commit 371c1699be963f2e5c1036782344ee5c587be00f Author: Tsuki Date: Wed Jul 10 15:49:05 2024 +0800 sync diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ea8c4bf --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/target diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..7abb13d --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,7 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Editor-based HTTP Client requests +/httpRequests/ +# GitHub Copilot persisted chat sessions +/copilot/chatSessions diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..aeb7613 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/untitled.iml b/.idea/untitled.iml new file mode 100644 index 0000000..e70e9ce --- /dev/null +++ b/.idea/untitled.iml @@ -0,0 +1,12 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..35eb1dd --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..80097bf --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,2172 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "ab_glyph" +version = "0.2.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e53b0a3d5760cd2ba9b787ae0c6440ad18ee294ff71b05e3381c900a7d16cfd" +dependencies = [ + "ab_glyph_rasterizer", + "owned_ttf_parser", +] + +[[package]] +name = "ab_glyph_rasterizer" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c71b1793ee61086797f5c80b6efa2b8ffa6d5dd703f118545808a7f2e27f7046" + +[[package]] +name = "ahash" +version = "0.8.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" +dependencies = [ + "cfg-if", + "getrandom", + "once_cell", + "version_check", + "zerocopy", +] + +[[package]] +name = "aho-corasick" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +dependencies = [ + "memchr", +] + +[[package]] +name = "android-activity" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee91c0c2905bae44f84bfa4e044536541df26b7703fd0888deeb9060fcc44289" +dependencies = [ + "android-properties", + "bitflags 2.5.0", + "cc", + "cesu8", + "jni", + "jni-sys", + "libc", + "log", + "ndk", + "ndk-context", + "ndk-sys", + "num_enum", + "thiserror", +] + +[[package]] +name = "android-properties" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc7eb209b1518d6bb87b283c20095f5228ecda460da70b44f0802523dea6da04" + +[[package]] +name = "anstream" +version = "0.6.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "418c75fa768af9c03be99d17643f93f79bbba589895012a80e3452a19ddda15b" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "is_terminal_polyfill", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "038dfcf04a5feb68e9c60b21c9625a54c2c0616e79b72b0fd87075a056ae1d1b" + +[[package]] +name = "anstyle-parse" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c03a11a9034d92058ceb6ee011ce58af4a9bf61491aa7e1e59ecd24bd40d22d4" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad186efb764318d35165f1758e7dcef3b10628e26d41a44bc5550652e6804391" +dependencies = [ + "windows-sys 0.52.0", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61a38449feb7068f52bb06c12759005cf459ee52bb4adc1d5a7c4322d716fb19" +dependencies = [ + "anstyle", + "windows-sys 0.52.0", +] + +[[package]] +name = "approx" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f2a05fd1bd10b2527e20a2cd32d8873d115b8b39fe219ee25f42a8aca6ba278" +dependencies = [ + "num-traits", +] + +[[package]] +name = "approx" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cab112f0a86d568ea0e627cc1d6be74a1e9cd55214684db5561995f6dad897c6" +dependencies = [ + "num-traits", +] + +[[package]] +name = "arrayref" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b4930d2cb77ce62f89ee5d5289b4ac049559b1c45539271f5ed4fdc7db34545" + +[[package]] +name = "arrayvec" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" + +[[package]] +name = "as-raw-xcb-connection" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "175571dd1d178ced59193a6fc02dde1b972eb0bc56c892cde9beeceac5bf0f6b" + +[[package]] +name = "atomic-waker" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" + +[[package]] +name = "autocfg" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bitflags" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1" + +[[package]] +name = "block" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a" + +[[package]] +name = "block-sys" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae85a0696e7ea3b835a453750bf002770776609115e6d25c6d2ff28a8200f7e7" +dependencies = [ + "objc-sys", +] + +[[package]] +name = "block2" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "15b55663a85f33501257357e6421bb33e769d5c9ffb5ba0921c975a123e35e68" +dependencies = [ + "block-sys", + "objc2", +] + +[[package]] +name = "bumpalo" +version = "3.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" + +[[package]] +name = "bytemuck" +version = "1.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b236fc92302c97ed75b38da1f4917b5cdda4984745740f153a5d3059e48d725e" +dependencies = [ + "bytemuck_derive", +] + +[[package]] +name = "bytemuck_derive" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "965ab7eb5f8f97d2a083c799f3a1b994fc397b2fe2da5d1da1626ce15a39f2b1" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "bytes" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "514de17de45fdb8dc022b1a7975556c53c86f9f0aa5f534b98977b171857c2c9" + +[[package]] +name = "calloop" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fba7adb4dd5aa98e5553510223000e7148f621165ec5f9acd7113f6ca4995298" +dependencies = [ + "bitflags 2.5.0", + "log", + "polling", + "rustix", + "slab", + "thiserror", +] + +[[package]] +name = "calloop-wayland-source" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f0ea9b9476c7fad82841a8dbb380e2eae480c21910feba80725b46931ed8f02" +dependencies = [ + "calloop", + "rustix", + "wayland-backend", + "wayland-client", +] + +[[package]] +name = "cc" +version = "1.0.98" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41c270e7540d725e65ac7f1b212ac8ce349719624d7bcff99f8e2e488e8cf03f" +dependencies = [ + "jobserver", + "libc", + "once_cell", +] + +[[package]] +name = "cesu8" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "cfg_aliases" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd16c4719339c4530435d38e511904438d07cce7950afa3718a84ac36c10e89e" + +[[package]] +name = "cgl" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ced0551234e87afee12411d535648dd89d2e7f34c78b753395567aff3d447ff" +dependencies = [ + "libc", +] + +[[package]] +name = "cgmath" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a98d30140e3296250832bbaaff83b27dcd6fa3cc70fb6f1f3e5c9c0023b5317" +dependencies = [ + "approx 0.4.0", + "num-traits", +] + +[[package]] +name = "chlorine" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d1d389c4b5c60ebf7955904cd19f5a225f53f42e03d4459a2d57463ed62c6a8" + +[[package]] +name = "clipboard-win" +version = "3.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fdf5e01086b6be750428ba4a40619f847eb2e95756eee84b18e06e5f0b50342" +dependencies = [ + "lazy-bytes-cast", + "winapi", +] + +[[package]] +name = "colorchoice" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b6a852b24ab71dffc585bcb46eaf7959d175cb865a7152e35b348d1b2960422" + +[[package]] +name = "combine" +version = "4.6.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba5a308b75df32fe02788e748662718f03fde005016435c444eea572398219fd" +dependencies = [ + "bytes", + "memchr", +] + +[[package]] +name = "concurrent-queue" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "copypasta" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "deb85422867ca93da58b7f95fb5c0c10f6183ed6e1ef8841568968a896d3a858" +dependencies = [ + "clipboard-win", + "objc", + "objc-foundation", + "objc_id", + "smithay-clipboard", + "x11-clipboard", +] + +[[package]] +name = "core-foundation" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" + +[[package]] +name = "core-graphics" +version = "0.23.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c07782be35f9e1140080c6b96f0d44b739e2278479f64e02fdab4e32dfd8b081" +dependencies = [ + "bitflags 1.3.2", + "core-foundation", + "core-graphics-types", + "foreign-types", + "libc", +] + +[[package]] +name = "core-graphics-types" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45390e6114f68f718cc7a830514a96f903cccd70d02a8f6d9f643ac4ba45afaf" +dependencies = [ + "bitflags 1.3.2", + "core-foundation", + "libc", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" + +[[package]] +name = "cursor-icon" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96a6ac251f4a2aca6b3f91340350eab87ae57c3f127ffeb585e92bd336717991" + +[[package]] +name = "dispatch" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd0c93bb4b0c6d9b77f4435b0ae98c24d17f1c45b2ff844c6151a07256ca923b" + +[[package]] +name = "dlib" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "330c60081dcc4c72131f8eb70510f1ac07223e5d4163db481a04a0befcffa412" +dependencies = [ + "libloading", +] + +[[package]] +name = "downcast-rs" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75b325c5dbd37f80359721ad39aca5a29fb04c89279657cffdda8736d0c0b9d2" + +[[package]] +name = "env_filter" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a009aa4810eb158359dda09d0c87378e4bbb89b5a801f016885a4707ba24f7ea" +dependencies = [ + "log", + "regex", +] + +[[package]] +name = "env_logger" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38b35839ba51819680ba087cd351788c9a3c476841207e0b8cee0b04722343b9" +dependencies = [ + "anstream", + "anstyle", + "env_filter", + "humantime", + "log", +] + +[[package]] +name = "equivalent" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + +[[package]] +name = "errno" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" +dependencies = [ + "libc", + "windows-sys 0.52.0", +] + +[[package]] +name = "foreign-types" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d737d9aa519fb7b749cbc3b962edcf310a8dd1f4b67c91c4f83975dbdd17d965" +dependencies = [ + "foreign-types-macros", + "foreign-types-shared", +] + +[[package]] +name = "foreign-types-macros" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a5c6c585bc94aaf2c7b51dd4c2ba22680844aba4c687be581871a6f518c5742" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "foreign-types-shared" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa9a19cbb55df58761df49b23516a86d432839add4af60fc256da840f66ed35b" + +[[package]] +name = "gethostname" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0176e0459c2e4a1fe232f984bca6890e681076abb9934f6cea7c326f3fc47818" +dependencies = [ + "libc", + "windows-targets 0.48.5", +] + +[[package]] +name = "getrandom" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "gl_generator" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a95dfc23a2b4a9a2f5ab41d194f8bfda3cabec42af4e39f08c339eb2a0c124d" +dependencies = [ + "khronos_api", + "log", + "xml-rs", +] + +[[package]] +name = "glow" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd348e04c43b32574f2de31c8bb397d96c9fcfa1371bd4ca6d8bdc464ab121b1" +dependencies = [ + "js-sys", + "slotmap", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "glutin" +version = "0.31.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18fcd4ae4e86d991ad1300b8f57166e5be0c95ef1f63f3f5b827f8a164548746" +dependencies = [ + "bitflags 2.5.0", + "cfg_aliases", + "cgl", + "core-foundation", + "dispatch", + "glutin_egl_sys", + "glutin_glx_sys", + "glutin_wgl_sys", + "icrate", + "libloading", + "objc2", + "once_cell", + "raw-window-handle 0.5.2", + "wayland-sys", + "windows-sys 0.48.0", + "x11-dl", +] + +[[package]] +name = "glutin-winit" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ebcdfba24f73b8412c5181e56f092b5eff16671c514ce896b258a0a64bd7735" +dependencies = [ + "cfg_aliases", + "glutin", + "raw-window-handle 0.5.2", + "winit", +] + +[[package]] +name = "glutin_egl_sys" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77cc5623f5309ef433c3dd4ca1223195347fe62c413da8e2fdd0eb76db2d9bcd" +dependencies = [ + "gl_generator", + "windows-sys 0.48.0", +] + +[[package]] +name = "glutin_glx_sys" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a165fd686c10dcc2d45380b35796e577eacfd43d4660ee741ec8ebe2201b3b4f" +dependencies = [ + "gl_generator", + "x11-dl", +] + +[[package]] +name = "glutin_wgl_sys" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c8098adac955faa2d31079b65dc48841251f69efd3ac25477903fc424362ead" +dependencies = [ + "gl_generator", +] + +[[package]] +name = "hashbrown" +version = "0.14.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" + +[[package]] +name = "hermit-abi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" + +[[package]] +name = "humantime" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" + +[[package]] +name = "icrate" +version = "0.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "99d3aaff8a54577104bafdf686ff18565c3b6903ca5782a2026ef06e2c7aa319" +dependencies = [ + "block2", + "dispatch", + "objc2", +] + +[[package]] +name = "imgui" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8addafa5cecf0515812226e806913814e02ce38d10215778082af5174abe5669" +dependencies = [ + "bitflags 1.3.2", + "cfg-if", + "imgui-sys", + "mint", + "parking_lot", +] + +[[package]] +name = "imgui-glow-renderer" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b577341b903dafa5da85f512b922624297c2556ff5c63bca737e7a73660fec4" +dependencies = [ + "glow", + "imgui", + "memoffset", +] + +[[package]] +name = "imgui-sys" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ead193f9f4b60398e8b8f4ab1483e2321640d87aeebdaa3e5f44c55633ccd804" +dependencies = [ + "cc", + "cfg-if", + "chlorine", + "mint", +] + +[[package]] +name = "imgui-winit-support" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e3c00d50ebf207505ea6bc9a5cdafb33c1d14a8fe854fff1fa3542f013f3952" +dependencies = [ + "imgui", + "winit", +] + +[[package]] +name = "include_dir" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "923d117408f1e49d914f1a379a309cffe4f18c05cf4e3d12e613a15fc81bd0dd" +dependencies = [ + "include_dir_macros", +] + +[[package]] +name = "include_dir_macros" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7cab85a7ed0bd5f0e76d93846e0147172bed2e2d3f859bcc33a8d9699cad1a75" +dependencies = [ + "proc-macro2", + "quote", +] + +[[package]] +name = "indexmap" +version = "2.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26" +dependencies = [ + "equivalent", + "hashbrown", +] + +[[package]] +name = "is_terminal_polyfill" +version = "1.70.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8478577c03552c21db0e2724ffb8986a5ce7af88107e6be5d2ee6e158c12800" + +[[package]] +name = "jni" +version = "0.21.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a87aa2bb7d2af34197c04845522473242e1aa17c12f4935d5856491a7fb8c97" +dependencies = [ + "cesu8", + "cfg-if", + "combine", + "jni-sys", + "log", + "thiserror", + "walkdir", + "windows-sys 0.45.0", +] + +[[package]] +name = "jni-sys" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130" + +[[package]] +name = "jobserver" +version = "0.1.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2b099aaa34a9751c5bf0878add70444e1ed2dd73f347be99003d4577277de6e" +dependencies = [ + "libc", +] + +[[package]] +name = "js-sys" +version = "0.3.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d" +dependencies = [ + "wasm-bindgen", +] + +[[package]] +name = "khronos_api" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2db585e1d738fc771bf08a151420d3ed193d9d895a36df7f6f8a9456b911ddc" + +[[package]] +name = "lazy-bytes-cast" +version = "5.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10257499f089cd156ad82d0a9cd57d9501fa2c989068992a97eb3c27836f206b" + +[[package]] +name = "libc" +version = "0.2.155" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" + +[[package]] +name = "libloading" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c2a198fb6b0eada2a8df47933734e6d35d350665a33a3593d7164fa52c75c19" +dependencies = [ + "cfg-if", + "windows-targets 0.52.5", +] + +[[package]] +name = "libredox" +version = "0.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3af92c55d7d839293953fcd0fda5ecfe93297cfde6ffbdec13b41d99c0ba6607" +dependencies = [ + "bitflags 2.5.0", + "libc", + "redox_syscall 0.4.1", +] + +[[package]] +name = "linux-raw-sys" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" + +[[package]] +name = "lock_api" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" +dependencies = [ + "autocfg", + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" + +[[package]] +name = "malloc_buf" +version = "0.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62bb907fe88d54d8d9ce32a3cceab4218ed2f6b7d35617cafe9adf84e43919cb" +dependencies = [ + "libc", +] + +[[package]] +name = "matrixmultiply" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7574c1cf36da4798ab73da5b215bbf444f50718207754cb522201d78d1cd0ff2" +dependencies = [ + "autocfg", + "rawpointer", +] + +[[package]] +name = "memchr" +version = "2.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d" + +[[package]] +name = "memmap2" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe751422e4a8caa417e13c3ea66452215d7d63e19e604f4980461212f3ae1322" +dependencies = [ + "libc", +] + +[[package]] +name = "memoffset" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a" +dependencies = [ + "autocfg", +] + +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + +[[package]] +name = "mint" +version = "0.5.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e53debba6bda7a793e5f99b8dacf19e626084f525f7829104ba9898f367d85ff" + +[[package]] +name = "nalgebra" +version = "0.32.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ea4908d4f23254adda3daa60ffef0f1ac7b8c3e9a864cf3cc154b251908a2ef" +dependencies = [ + "approx 0.5.1", + "matrixmultiply", + "num-complex", + "num-rational", + "num-traits", + "simba", + "typenum", +] + +[[package]] +name = "nalgebra-glm" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e68879ff227a94627e63bbd518b4f82b8f0cc56bb01a498251507de6d1c412d6" +dependencies = [ + "approx 0.5.1", + "nalgebra", + "num-traits", + "simba", +] + +[[package]] +name = "ndk" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2076a31b7010b17a38c01907c45b945e8f11495ee4dd588309718901b1f7a5b7" +dependencies = [ + "bitflags 2.5.0", + "jni-sys", + "log", + "ndk-sys", + "num_enum", + "raw-window-handle 0.5.2", + "raw-window-handle 0.6.2", + "thiserror", +] + +[[package]] +name = "ndk-context" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "27b02d87554356db9e9a873add8782d4ea6e3e58ea071a9adb9a2e8ddb884a8b" + +[[package]] +name = "ndk-sys" +version = "0.5.0+25.2.9519653" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c196769dd60fd4f363e11d948139556a344e79d451aeb2fa2fd040738ef7691" +dependencies = [ + "jni-sys", +] + +[[package]] +name = "nom" +version = "7.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" +dependencies = [ + "memchr", + "minimal-lexical", +] + +[[package]] +name = "num-complex" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73f88a1307638156682bada9d7604135552957b7818057dcef22705b4d509495" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-integer" +version = "0.1.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-rational" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f83d14da390562dca69fc84082e73e548e1ad308d24accdedd2720017cb37824" +dependencies = [ + "num-integer", + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", +] + +[[package]] +name = "num_enum" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02339744ee7253741199f897151b38e72257d13802d4ee837285cc2990a90845" +dependencies = [ + "num_enum_derive", +] + +[[package]] +name = "num_enum_derive" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "681030a937600a36906c185595136d26abfebb4aa9c65701cefcaf8578bb982b" +dependencies = [ + "proc-macro-crate", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "objc" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "915b1b472bc21c53464d6c8461c9d3af805ba1ef837e1cac254428f4a77177b1" +dependencies = [ + "malloc_buf", +] + +[[package]] +name = "objc-foundation" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1add1b659e36c9607c7aab864a76c7a4c2760cd0cd2e120f3fb8b952c7e22bf9" +dependencies = [ + "block", + "objc", + "objc_id", +] + +[[package]] +name = "objc-sys" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdb91bdd390c7ce1a8607f35f3ca7151b65afc0ff5ff3b34fa350f7d7c7e4310" + +[[package]] +name = "objc2" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "559c5a40fdd30eb5e344fbceacf7595a81e242529fb4e21cf5f43fb4f11ff98d" +dependencies = [ + "objc-sys", + "objc2-encode", +] + +[[package]] +name = "objc2-encode" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d079845b37af429bfe5dfa76e6d087d788031045b25cfc6fd898486fd9847666" + +[[package]] +name = "objc_id" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c92d4ddb4bd7b50d730c215ff871754d0da6b2178849f8a2a2ab69712d0c073b" +dependencies = [ + "objc", +] + +[[package]] +name = "once_cell" +version = "1.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" + +[[package]] +name = "orbclient" +version = "0.3.47" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52f0d54bde9774d3a51dcf281a5def240c71996bc6ca05d2c847ec8b2b216166" +dependencies = [ + "libredox", +] + +[[package]] +name = "owned_ttf_parser" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b41438d2fc63c46c74a2203bf5ccd82c41ba04347b2fcf5754f230b167067d5" +dependencies = [ + "ttf-parser", +] + +[[package]] +name = "parking_lot" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall 0.5.1", + "smallvec", + "windows-targets 0.52.5", +] + +[[package]] +name = "paste" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" + +[[package]] +name = "percent-encoding" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" + +[[package]] +name = "pin-project-lite" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" + +[[package]] +name = "pkg-config" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" + +[[package]] +name = "polling" +version = "3.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e6a007746f34ed64099e88783b0ae369eaa3da6392868ba262e2af9b8fbaea1" +dependencies = [ + "cfg-if", + "concurrent-queue", + "hermit-abi", + "pin-project-lite", + "rustix", + "tracing", + "windows-sys 0.52.0", +] + +[[package]] +name = "proc-macro-crate" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d37c51ca738a55da99dc0c4a34860fd675453b8b36209178c2249bb13651284" +dependencies = [ + "toml_edit", +] + +[[package]] +name = "proc-macro2" +version = "1.0.85" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22244ce15aa966053a896d1accb3a6e68469b97c7f33f284b99f0d576879fc23" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quick-xml" +version = "0.31.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1004a344b30a54e2ee58d66a71b32d2db2feb0a31f9a2d302bf0536f15de2a33" +dependencies = [ + "memchr", +] + +[[package]] +name = "quote" +version = "1.0.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "radar-g" +version = "0.1.0" +dependencies = [ + "bytemuck", + "cgmath", + "copypasta", + "env_logger", + "glow", + "glutin", + "glutin-winit", + "imgui", + "imgui-glow-renderer", + "imgui-winit-support", + "include_dir", + "log", + "nalgebra-glm", + "nom", + "once_cell", + "raw-window-handle 0.5.2", + "regex", + "thiserror", + "winit", +] + +[[package]] +name = "raw-window-handle" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2ff9a1f06a88b01621b7ae906ef0211290d1c8a168a15542486a8f61c0833b9" + +[[package]] +name = "raw-window-handle" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20675572f6f24e9e76ef639bc5552774ed45f1c30e2951e1e99c59888861c539" + +[[package]] +name = "rawpointer" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60a357793950651c4ed0f3f52338f53b2f809f32d83a07f72909fa13e4c6c1e3" + +[[package]] +name = "redox_syscall" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" +dependencies = [ + "bitflags 1.3.2", +] + +[[package]] +name = "redox_syscall" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" +dependencies = [ + "bitflags 1.3.2", +] + +[[package]] +name = "redox_syscall" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "469052894dcb553421e483e4209ee581a45100d31b4018de03e5a7ad86374a7e" +dependencies = [ + "bitflags 2.5.0", +] + +[[package]] +name = "regex" +version = "1.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b91213439dad192326a0d7c6ee3955910425f441d7038e0d6933b0aec5c4517f" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" + +[[package]] +name = "rustix" +version = "0.38.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f" +dependencies = [ + "bitflags 2.5.0", + "errno", + "libc", + "linux-raw-sys", + "windows-sys 0.52.0", +] + +[[package]] +name = "safe_arch" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f398075ce1e6a179b46f51bd88d0598b92b00d3551f1a2d4ac49e771b56ac354" +dependencies = [ + "bytemuck", +] + +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "scoped-tls" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294" + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "sctk-adwaita" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82b2eaf3a5b264a521b988b2e73042e742df700c4f962cde845d1541adb46550" +dependencies = [ + "ab_glyph", + "log", + "memmap2", + "smithay-client-toolkit", + "tiny-skia", +] + +[[package]] +name = "serde" +version = "1.0.203" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7253ab4de971e72fb7be983802300c30b5a7f0c2e56fab8abfc6a214307c0094" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.203" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "500cbc0ebeb6f46627f50f3f5811ccf6bf00643be300b4c3eabc0ef55dc5b5ba" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "simba" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "061507c94fc6ab4ba1c9a0305018408e312e17c041eb63bef8aa726fa33aceae" +dependencies = [ + "approx 0.5.1", + "num-complex", + "num-traits", + "paste", + "wide", +] + +[[package]] +name = "slab" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" +dependencies = [ + "autocfg", +] + +[[package]] +name = "slotmap" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbff4acf519f630b3a3ddcfaea6c06b42174d9a44bc70c620e9ed1649d58b82a" +dependencies = [ + "version_check", +] + +[[package]] +name = "smallvec" +version = "1.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" + +[[package]] +name = "smithay-client-toolkit" +version = "0.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "922fd3eeab3bd820d76537ce8f582b1cf951eceb5475c28500c7457d9d17f53a" +dependencies = [ + "bitflags 2.5.0", + "calloop", + "calloop-wayland-source", + "cursor-icon", + "libc", + "log", + "memmap2", + "rustix", + "thiserror", + "wayland-backend", + "wayland-client", + "wayland-csd-frame", + "wayland-cursor", + "wayland-protocols", + "wayland-protocols-wlr", + "wayland-scanner", + "xkeysym", +] + +[[package]] +name = "smithay-clipboard" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c091e7354ea8059d6ad99eace06dd13ddeedbb0ac72d40a9a6e7ff790525882d" +dependencies = [ + "libc", + "smithay-client-toolkit", + "wayland-backend", +] + +[[package]] +name = "smol_str" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd538fb6910ac1099850255cf94a94df6551fbdd602454387d0adb2d1ca6dead" +dependencies = [ + "serde", +] + +[[package]] +name = "strict-num" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6637bab7722d379c8b41ba849228d680cc12d0a45ba1fa2b48f2a30577a06731" + +[[package]] +name = "syn" +version = "2.0.66" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c42f3f41a2de00b01c0aaad383c5a45241efc8b2d1eda5661812fda5f3cdcff5" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "thiserror" +version = "1.0.61" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c546c80d6be4bc6a00c0f01730c08df82eaa7a7a61f11d656526506112cc1709" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.61" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46c3384250002a6d5af4d114f2845d37b57521033f30d5c3f46c4d70e1197533" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tiny-skia" +version = "0.11.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83d13394d44dae3207b52a326c0c85a8bf87f1541f23b0d143811088497b09ab" +dependencies = [ + "arrayref", + "arrayvec", + "bytemuck", + "cfg-if", + "log", + "tiny-skia-path", +] + +[[package]] +name = "tiny-skia-path" +version = "0.11.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c9e7fc0c2e86a30b117d0462aa261b72b7a99b7ebd7deb3a14ceda95c5bdc93" +dependencies = [ + "arrayref", + "bytemuck", + "strict-num", +] + +[[package]] +name = "toml_datetime" +version = "0.6.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4badfd56924ae69bcc9039335b2e017639ce3f9b001c393c1b2d1ef846ce2cbf" + +[[package]] +name = "toml_edit" +version = "0.21.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a8534fd7f78b5405e860340ad6575217ce99f38d4d5c8f2442cb5ecb50090e1" +dependencies = [ + "indexmap", + "toml_datetime", + "winnow", +] + +[[package]] +name = "tracing" +version = "0.1.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" +dependencies = [ + "pin-project-lite", + "tracing-core", +] + +[[package]] +name = "tracing-core" +version = "0.1.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" + +[[package]] +name = "ttf-parser" +version = "0.21.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c591d83f69777866b9126b24c6dd9a18351f177e49d625920d19f989fd31cf8" + +[[package]] +name = "typenum" +version = "1.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" + +[[package]] +name = "unicode-ident" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" + +[[package]] +name = "unicode-segmentation" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4c87d22b6e3f4a18d4d40ef354e97c90fcb14dd91d7dc0aa9d8a1172ebf7202" + +[[package]] +name = "utf8parse" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + +[[package]] +name = "walkdir" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" +dependencies = [ + "same-file", + "winapi-util", +] + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "wasm-bindgen" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8" +dependencies = [ + "cfg-if", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da" +dependencies = [ + "bumpalo", + "log", + "once_cell", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.42" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76bc14366121efc8dbb487ab05bcc9d346b3b5ec0eaa76e46594cabbe51762c0" +dependencies = [ + "cfg-if", + "js-sys", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" + +[[package]] +name = "wayland-backend" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34e9e6b6d4a2bb4e7e69433e0b35c7923b95d4dc8503a84d25ec917a4bbfdf07" +dependencies = [ + "cc", + "downcast-rs", + "rustix", + "scoped-tls", + "smallvec", + "wayland-sys", +] + +[[package]] +name = "wayland-client" +version = "0.31.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e63801c85358a431f986cffa74ba9599ff571fc5774ac113ed3b490c19a1133" +dependencies = [ + "bitflags 2.5.0", + "rustix", + "wayland-backend", + "wayland-scanner", +] + +[[package]] +name = "wayland-csd-frame" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "625c5029dbd43d25e6aa9615e88b829a5cad13b2819c4ae129fdbb7c31ab4c7e" +dependencies = [ + "bitflags 2.5.0", + "cursor-icon", + "wayland-backend", +] + +[[package]] +name = "wayland-cursor" +version = "0.31.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a206e8b2b53b1d3fcb9428fec72bc278ce539e2fa81fe2bfc1ab27703d5187b9" +dependencies = [ + "rustix", + "wayland-client", + "xcursor", +] + +[[package]] +name = "wayland-protocols" +version = "0.31.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f81f365b8b4a97f422ac0e8737c438024b5951734506b0e1d775c73030561f4" +dependencies = [ + "bitflags 2.5.0", + "wayland-backend", + "wayland-client", + "wayland-scanner", +] + +[[package]] +name = "wayland-protocols-plasma" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23803551115ff9ea9bce586860c5c5a971e360825a0309264102a9495a5ff479" +dependencies = [ + "bitflags 2.5.0", + "wayland-backend", + "wayland-client", + "wayland-protocols", + "wayland-scanner", +] + +[[package]] +name = "wayland-protocols-wlr" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad1f61b76b6c2d8742e10f9ba5c3737f6530b4c243132c2a2ccc8aa96fe25cd6" +dependencies = [ + "bitflags 2.5.0", + "wayland-backend", + "wayland-client", + "wayland-protocols", + "wayland-scanner", +] + +[[package]] +name = "wayland-scanner" +version = "0.31.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67da50b9f80159dec0ea4c11c13e24ef9e7574bd6ce24b01860a175010cea565" +dependencies = [ + "proc-macro2", + "quick-xml", + "quote", +] + +[[package]] +name = "wayland-sys" +version = "0.31.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "105b1842da6554f91526c14a2a2172897b7f745a805d62af4ce698706be79c12" +dependencies = [ + "dlib", + "log", + "once_cell", + "pkg-config", +] + +[[package]] +name = "web-sys" +version = "0.3.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77afa9a11836342370f4817622a2f0f418b134426d91a82dfb48f532d2ec13ef" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "web-time" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa30049b1c872b72c89866d458eae9f20380ab280ffd1b1e18df2d3e2d98cfe0" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "wide" +version = "0.7.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c5cb32c74fe55350a3272ba792f050613e692253ae0d89ad5d83eb0dcea15e1" +dependencies = [ + "bytemuck", + "safe_arch", +] + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-util" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d4cc384e1e73b93bafa6fb4f1df8c41695c8a91cf9c4c64358067d15a7b6c6b" +dependencies = [ + "windows-sys 0.52.0", +] + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows-sys" +version = "0.45.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" +dependencies = [ + "windows-targets 0.42.2", +] + +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets 0.48.5", +] + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets 0.52.5", +] + +[[package]] +name = "windows-targets" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" +dependencies = [ + "windows_aarch64_gnullvm 0.42.2", + "windows_aarch64_msvc 0.42.2", + "windows_i686_gnu 0.42.2", + "windows_i686_msvc 0.42.2", + "windows_x86_64_gnu 0.42.2", + "windows_x86_64_gnullvm 0.42.2", + "windows_x86_64_msvc 0.42.2", +] + +[[package]] +name = "windows-targets" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" +dependencies = [ + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", +] + +[[package]] +name = "windows-targets" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb" +dependencies = [ + "windows_aarch64_gnullvm 0.52.5", + "windows_aarch64_msvc 0.52.5", + "windows_i686_gnu 0.52.5", + "windows_i686_gnullvm", + "windows_i686_msvc 0.52.5", + "windows_x86_64_gnu 0.52.5", + "windows_x86_64_gnullvm 0.52.5", + "windows_x86_64_msvc 0.52.5", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6" + +[[package]] +name = "windows_i686_gnu" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" + +[[package]] +name = "windows_i686_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9" + +[[package]] +name = "windows_i686_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" + +[[package]] +name = "windows_i686_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0" + +[[package]] +name = "winit" +version = "0.29.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d59ad965a635657faf09c8f062badd885748428933dad8e8bdd64064d92e5ca" +dependencies = [ + "ahash", + "android-activity", + "atomic-waker", + "bitflags 2.5.0", + "bytemuck", + "calloop", + "cfg_aliases", + "core-foundation", + "core-graphics", + "cursor-icon", + "icrate", + "js-sys", + "libc", + "log", + "memmap2", + "ndk", + "ndk-sys", + "objc2", + "once_cell", + "orbclient", + "percent-encoding", + "raw-window-handle 0.5.2", + "raw-window-handle 0.6.2", + "redox_syscall 0.3.5", + "rustix", + "sctk-adwaita", + "smithay-client-toolkit", + "smol_str", + "unicode-segmentation", + "wasm-bindgen", + "wasm-bindgen-futures", + "wayland-backend", + "wayland-client", + "wayland-protocols", + "wayland-protocols-plasma", + "web-sys", + "web-time", + "windows-sys 0.48.0", + "x11-dl", + "x11rb", + "xkbcommon-dl", +] + +[[package]] +name = "winnow" +version = "0.5.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f593a95398737aeed53e489c785df13f3618e41dbcd6718c6addbf1395aa6876" +dependencies = [ + "memchr", +] + +[[package]] +name = "x11-clipboard" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b98785a09322d7446e28a13203d2cae1059a0dd3dfb32cb06d0a225f023d8286" +dependencies = [ + "libc", + "x11rb", +] + +[[package]] +name = "x11-dl" +version = "2.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38735924fedd5314a6e548792904ed8c6de6636285cb9fec04d5b1db85c1516f" +dependencies = [ + "libc", + "once_cell", + "pkg-config", +] + +[[package]] +name = "x11rb" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d91ffca73ee7f68ce055750bf9f6eca0780b8c85eff9bc046a3b0da41755e12" +dependencies = [ + "as-raw-xcb-connection", + "gethostname", + "libc", + "libloading", + "once_cell", + "rustix", + "x11rb-protocol", +] + +[[package]] +name = "x11rb-protocol" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec107c4503ea0b4a98ef47356329af139c0a4f7750e621cf2973cd3385ebcb3d" + +[[package]] +name = "xcursor" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a0ccd7b4a5345edfcd0c3535718a4e9ff7798ffc536bb5b5a0e26ff84732911" + +[[package]] +name = "xkbcommon-dl" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d039de8032a9a8856a6be89cea3e5d12fdd82306ab7c94d74e6deab2460651c5" +dependencies = [ + "bitflags 2.5.0", + "dlib", + "log", + "once_cell", + "xkeysym", +] + +[[package]] +name = "xkeysym" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "054a8e68b76250b253f671d1268cb7f1ae089ec35e195b2efb2a4e9a836d0621" + +[[package]] +name = "xml-rs" +version = "0.8.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "791978798f0597cfc70478424c2b4fdc2b7a8024aaff78497ef00f24ef674193" + +[[package]] +name = "zerocopy" +version = "0.7.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae87e3fcd617500e5d106f0380cf7b77f3c6092aae37191433159dda23cfb087" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.7.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "15e934569e47891f7d9411f1a451d947a60e000ab3bd24fbb970f000387d1b3b" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..dc84542 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,26 @@ +[package] +name = "radar-g" +version = "0.1.0" +edition = "2021" + +[dependencies] + +imgui = "0.12.0" +glow = "0.13.1" +imgui-glow-renderer = "0.12.0" +imgui-winit-support = "0.12.0" +glutin = "0.31.3" +glutin-winit = "0.4.2" +copypasta = "0.10.1" +raw-window-handle = "0.5.2" +winit = "0.29.15" +cgmath = "0.18.0" +nalgebra-glm = "0.18.0" +regex = "1.10.5" +once_cell = "1.19.0" +include_dir = "0.7.4" +nom = "7.1.3" +thiserror = "1.0.61" +log = "0.4.22" +env_logger = "0.11.3" +bytemuck = { version = "1.16.1", features = ["derive"] } diff --git a/resources/Dokdo-Regular.ttf b/resources/Dokdo-Regular.ttf new file mode 100644 index 0000000..ac4ac8d Binary files /dev/null and b/resources/Dokdo-Regular.ttf differ diff --git a/resources/LICENSE-Dokdo.txt b/resources/LICENSE-Dokdo.txt new file mode 100644 index 0000000..501e63a --- /dev/null +++ b/resources/LICENSE-Dokdo.txt @@ -0,0 +1,93 @@ +Copyright (c) 2005-2017 FONTRIX. All Rights Reserved. + +This Font Software is licensed under the SIL Open Font License, Version 1.1. +This license is copied below, and is also available with a FAQ at: +http://scripts.sil.org/OFL + + +----------------------------------------------------------- +SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 +----------------------------------------------------------- + +PREAMBLE +The goals of the Open Font License (OFL) are to stimulate worldwide +development of collaborative font projects, to support the font creation +efforts of academic and linguistic communities, and to provide a free and +open framework in which fonts may be shared and improved in partnership +with others. + +The OFL allows the licensed fonts to be used, studied, modified and +redistributed freely as long as they are not sold by themselves. The +fonts, including any derivative works, can be bundled, embedded, +redistributed and/or sold with any software provided that any reserved +names are not used by derivative works. The fonts and derivatives, +however, cannot be released under any other type of license. The +requirement for fonts to remain under this license does not apply +to any document created using the fonts or their derivatives. + +DEFINITIONS +"Font Software" refers to the set of files released by the Copyright +Holder(s) under this license and clearly marked as such. This may +include source files, build scripts and documentation. + +"Reserved Font Name" refers to any names specified as such after the +copyright statement(s). + +"Original Version" refers to the collection of Font Software components as +distributed by the Copyright Holder(s). + +"Modified Version" refers to any derivative made by adding to, deleting, +or substituting -- in part or in whole -- any of the components of the +Original Version, by changing formats or by porting the Font Software to a +new environment. + +"Author" refers to any designer, engineer, programmer, technical +writer or other person who contributed to the Font Software. + +PERMISSION & CONDITIONS +Permission is hereby granted, free of charge, to any person obtaining +a copy of the Font Software, to use, study, copy, merge, embed, modify, +redistribute, and sell modified and unmodified copies of the Font +Software, subject to the following conditions: + +1) Neither the Font Software nor any of its individual components, +in Original or Modified Versions, may be sold by itself. + +2) Original or Modified Versions of the Font Software may be bundled, +redistributed and/or sold with any software, provided that each copy +contains the above copyright notice and this license. These can be +included either as stand-alone text files, human-readable headers or +in the appropriate machine-readable metadata fields within text or +binary files as long as those fields can be easily viewed by the user. + +3) No Modified Version of the Font Software may use the Reserved Font +Name(s) unless explicit written permission is granted by the corresponding +Copyright Holder. This restriction only applies to the primary font name as +presented to the users. + +4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font +Software shall not be used to promote, endorse or advertise any +Modified Version, except to acknowledge the contribution(s) of the +Copyright Holder(s) and the Author(s) or with their explicit written +permission. + +5) The Font Software, modified or unmodified, in part or in whole, +must be distributed entirely under this license, and must not be +distributed under any other license. The requirement for fonts to +remain under this license does not apply to any document created +using the Font Software. + +TERMINATION +This license becomes null and void if any of the above conditions are +not met. + +DISCLAIMER +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE +COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL +DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM +OTHER DEALINGS IN THE FONT SOFTWARE. diff --git a/resources/LICENSE-Roboto.txt b/resources/LICENSE-Roboto.txt new file mode 100644 index 0000000..261eeb9 --- /dev/null +++ b/resources/LICENSE-Roboto.txt @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/resources/Lenna.jpg b/resources/Lenna.jpg new file mode 100644 index 0000000..9e1df85 Binary files /dev/null and b/resources/Lenna.jpg differ diff --git a/resources/Roboto-Regular.ttf b/resources/Roboto-Regular.ttf new file mode 100644 index 0000000..2c97eea Binary files /dev/null and b/resources/Roboto-Regular.ttf differ diff --git a/resources/mplus-1p-regular.ttf b/resources/mplus-1p-regular.ttf new file mode 100644 index 0000000..4775e3a Binary files /dev/null and b/resources/mplus-1p-regular.ttf differ diff --git a/shaders/agg-fast-path.frag b/shaders/agg-fast-path.frag new file mode 100644 index 0000000..4386958 --- /dev/null +++ b/shaders/agg-fast-path.frag @@ -0,0 +1,22 @@ +// ----------------------------------------------------------------------------- +// Copyright (c) 2009-2016 Nicolas P. Rougier. All rights reserved. +// Distributed under the (new) BSD License. +// ----------------------------------------------------------------------------- +#include "antialias/antialias.glsl" + +// Varyings +// ------------------------------------ +in vec4 v_color; +in float v_distance; +in float v_linewidth; +in float v_antialias; + +// Main +// ------------------------------------ +void main() +{ + ; + + if (v_color.a == 0) { discard; } + gl_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 new file mode 100644 index 0000000..dd703aa --- /dev/null +++ b/shaders/agg-fast-path.vert @@ -0,0 +1,77 @@ +// ----------------------------------------------------------------------------- +// Copyright (c) 2009-2016 Nicolas P. Rougier. All rights reserved. +// Distributed under the (new) BSD License. +// ----------------------------------------------------------------------------- +// Hooks: +// : vec4 function(position, ...) +// +// ---------------------------------------------------------------------------- +#include "misc/viewport-NDC.glsl" + +// Externs +// ------------------------------------ +// extern vec3 prev; +// extern vec3 curr; +// extern vec3 next; +// extern float id; +// extern vec4 color; +// extern float antialias; +// extern float linewidth; + +// Varyings +// ------------------------------------ +out float v_antialias; +out float v_linewidth; +out float v_distance; +out vec4 v_color; + + +// Main +// ------------------------------------ +void main () +{ + // This function is externally generated + fetch_uniforms(); + v_linewidth = linewidth; + v_antialias = antialias; + v_color = color; + + // transform prev/curr/next + vec4 prev_ = ; + vec4 curr_ = ; + vec4 next_ = ; + + // prev/curr/next in viewport coordinates + vec2 _prev = NDC_to_viewport(prev_, .zw); + vec2 _curr = NDC_to_viewport(curr_, .zw); + vec2 _next = NDC_to_viewport(next_, .zw); + + // Compute vertex final position (in viewport coordinates) + 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); + } + + if( abs(id) > 1.5 ) v_color.a = 0.0; + + v_distance = w*id; + gl_Position = viewport_to_NDC(P, .zw, curr_.z / curr_.w); + + ; +} \ No newline at end of file diff --git a/shaders/antialias/antialias.glsl b/shaders/antialias/antialias.glsl new file mode 100644 index 0000000..c27bc8b --- /dev/null +++ b/shaders/antialias/antialias.glsl @@ -0,0 +1,7 @@ +// ----------------------------------------------------------------------------- +// Copyright (c) 2009-2016 Nicolas P. Rougier. All rights reserved. +// Distributed under the (new) BSD License. +// ----------------------------------------------------------------------------- +#include "antialias/stroke.glsl" +#include "antialias/filled.glsl" +#include "antialias/outline.glsl" \ No newline at end of file diff --git a/shaders/antialias/filled.glsl b/shaders/antialias/filled.glsl new file mode 100644 index 0000000..69208b1 --- /dev/null +++ b/shaders/antialias/filled.glsl @@ -0,0 +1,45 @@ +// ----------------------------------------------------------------------------- +// Copyright (c) 2009-2016 Nicolas P. Rougier. All rights reserved. +// Distributed under the (new) BSD License. +// ----------------------------------------------------------------------------- + +/* --------------------------------------------------------- + Compute antialiased fragment color for a filled shape. + + Parameters: + ----------- + + distance : signed distance to border (in pixels) + linewidth: Stroke line width (in pixels) + antialias: Stroke antialiased area (in pixels) + fill: Fill color + + Return: + ------- + Fragment color (vec4) + + --------------------------------------------------------- */ + +vec4 filled(float distance, float linewidth, float antialias, vec4 bg_color) +{ + vec4 frag_color; + float t = linewidth/2.0 - antialias; + float signed_distance = distance; + float border_distance = abs(signed_distance) - t; + float alpha = border_distance/antialias; + alpha = exp(-alpha*alpha); + + if( border_distance < 0.0 ) + frag_color = bg_color; + else if( signed_distance < 0.0 ) + frag_color = bg_color; + else + frag_color = vec4(bg_color.rgb, alpha * bg_color.a); + + return frag_color; +} + +vec4 filled(float distance, float linewidth, float antialias, vec4 fg_color, vec4 bg_color) +{ + return filled(distance, linewidth, antialias, fg_color); +} \ No newline at end of file diff --git a/shaders/antialias/outline.glsl b/shaders/antialias/outline.glsl new file mode 100644 index 0000000..d886dee --- /dev/null +++ b/shaders/antialias/outline.glsl @@ -0,0 +1,45 @@ +// ----------------------------------------------------------------------------- +// Copyright (c) 2009-2016 Nicolas P. Rougier. All rights reserved. +// Distributed under the (new) BSD License. +// ----------------------------------------------------------------------------- + +/* --------------------------------------------------------- + Compute antialiased fragment color for an outlined shape. + + Parameters: + ----------- + + distance : signed distance to border (in pixels) + linewidth: Stroke line width (in pixels) + antialias: Stroke antialiased area (in pixels) + stroke: Stroke color + fill: Fill color + + Return: + ------- + Fragment color (vec4) + + --------------------------------------------------------- */ + +vec4 outline(float distance, float linewidth, float antialias, vec4 fg_color, vec4 bg_color) +{ + vec4 frag_color; + float t = linewidth/2.0 - antialias; + float signed_distance = distance; + float border_distance = abs(signed_distance) - t; + float alpha = border_distance/antialias; + alpha = exp(-alpha*alpha); + + if( border_distance < 0.0 ) + frag_color = fg_color; + else if( signed_distance < 0.0 ) + frag_color = mix(bg_color, fg_color, sqrt(alpha)); + else { + if( abs(signed_distance) < (linewidth/2.0 + antialias) ) { + frag_color = vec4(fg_color.rgb, fg_color.a * alpha); + } else { + discard; + } + } + return frag_color; +} \ No newline at end of file diff --git a/shaders/antialias/stroke.glsl b/shaders/antialias/stroke.glsl new file mode 100644 index 0000000..be982ee --- /dev/null +++ b/shaders/antialias/stroke.glsl @@ -0,0 +1,43 @@ +// ----------------------------------------------------------------------------- +// Copyright (c) 2009-2016 Nicolas P. Rougier. All rights reserved. +// Distributed under the (new) BSD License. +// ----------------------------------------------------------------------------- + +/* --------------------------------------------------------- + Compute antialiased fragment color for a stroke line. + + Parameters: + ----------- + + distance : signed distance to border (in pixels) + linewidth: Stroke line width (in pixels) + antialias: Stroke antialiased area (in pixels) + stroke: Stroke color + + Return: + ------- + Fragment color (vec4) + + --------------------------------------------------------- */ + +vec4 stroke(float distance, float linewidth, float antialias, vec4 fg_color) +{ + vec4 frag_color; + float t = linewidth/2.0 - antialias; + float signed_distance = distance; + float border_distance = abs(signed_distance) - t; + float alpha = border_distance/antialias; + alpha = exp(-alpha*alpha); + + if( border_distance < 0.0 ) + frag_color = fg_color; + else + frag_color = vec4(fg_color.rgb, fg_color.a * alpha); + + return frag_color; +} + +vec4 stroke(float distance, float linewidth, float antialias, vec4 fg_color, vec4 bg_color) +{ + return stroke(distance, linewidth, antialias, fg_color); +} \ No newline at end of file diff --git a/shaders/geo-position-struct.glsl b/shaders/geo-position-struct.glsl new file mode 100644 index 0000000..a003d21 --- /dev/null +++ b/shaders/geo-position-struct.glsl @@ -0,0 +1,14 @@ +// ----------------------------------------------------------------------------- +// Copyright (c) 2009-2016 Nicolas P. Rougier. All rights reserved. +// Distributed under the (new) BSD License. +// ----------------------------------------------------------------------------- + +#ifndef _GLUMPY__GEO_POSITION_STRUCT__ +#define _GLUMPY__GEO_POSITION_STRUCT__ +struct GeoPosition +{ + float longitude; + float latitude; + bool frozen; // Prevent further transformation if true +}; +#endif \ No newline at end of file diff --git a/shaders/line.vert b/shaders/line.vert new file mode 100644 index 0000000..3e3055c --- /dev/null +++ b/shaders/line.vert @@ -0,0 +1,39 @@ +uniform vec2 resolution; +uniform float antialias; + +layout() float thickness; +attribute vec2 p0, p1, uv; + +varying float v_alpha, v_thickness; +varying vec2 v_p0, v_p1, v_p; + +void main() { + + if( abs(thickness) < 1.0 ) { + v_thickness = 1.0; + v_alpha = abs(thickness); + } else { + v_thickness = abs(thickness); + v_alpha = 1.0; + } + + float t = v_thickness/2.0 + antialias; + float l = length(p1-p0); + float u = 2.0*uv.x - 1.0; + float v = 2.0*uv.y - 1.0; + + // Screen space + vec2 T = normalize(p1-p0); + vec2 O = vec2(-T.y , T.x); + vec2 p = p0 + vec2(0.5,0.5) + uv.x*T*l + u*T*t + v*O*t; + gl_Position = vec4(2.0*p/resolution-1.0, 0.0, 1.0); + + // Local space + T = vec2(1.0, 0.0); + O = vec2(0.0, 1.0); + p = uv.x*T*l + u*T*t + v*O*t; + + v_p0 = vec2(0.0, 0.0); + v_p1 = vec2( l, 0.0); + v_p = p; +} \ No newline at end of file diff --git a/shaders/math/constants.glsl b/shaders/math/constants.glsl new file mode 100644 index 0000000..fa535e9 --- /dev/null +++ b/shaders/math/constants.glsl @@ -0,0 +1,54 @@ +// ----------------------------------------------------------------------------- +// Copyright (c) 2009-2016 Nicolas P. Rougier. All rights reserved. +// Distributed under the (new) BSD License. +// ----------------------------------------------------------------------------- + +#ifndef _GLUMPY__CONSTANTS__ +#define _GLUMPY__CONSTANTS__ + +// The base of natural logarithms (e) +const float M_E = 2.71828182845904523536028747135266250; + +// The logarithm to base 2 of M_E (log2(e)) +const float M_LOG2E = 1.44269504088896340735992468100189214; + +// The logarithm to base 10 of M_E (log10(e)) +const float M_LOG10E = 0.434294481903251827651128918916605082; + +// The natural logarithm of 2 (loge(2)) +const float M_LN2 = 0.693147180559945309417232121458176568; + +// The natural logarithm of 10 (loge(10)) +const float M_LN10 = 2.30258509299404568401799145468436421; + +// Pi, the ratio of a circle's circumference to its diameter. +const float M_PI = 3.14159265358979323846264338327950288; + +// Pi divided by two (pi/2) +const float M_PI_2 = 1.57079632679489661923132169163975144; + +// Pi divided by four (pi/4) +const float M_PI_4 = 0.785398163397448309615660845819875721; + +// The reciprocal of pi (1/pi) +const float M_1_PI = 0.318309886183790671537767526745028724; + +// Two times the reciprocal of pi (2/pi) +const float M_2_PI = 0.636619772367581343075535053490057448; + +// Two times the reciprocal of the square root of pi (2/sqrt(pi)) +const float M_2_SQRTPI = 1.12837916709551257389615890312154517; + +// The square root of two (sqrt(2)) +const float M_SQRT2 = 1.41421356237309504880168872420969808; + +// The reciprocal of the square root of two (1/sqrt(2)) +const float M_SQRT1_2 = 0.707106781186547524400844362104849039; + +// 1 degree in radians +const float degree = 180.0/M_PI; + +// 1 radian in degrees +const float radian = M_PI/180.0; + +#endif \ No newline at end of file diff --git a/shaders/misc/viewport-NDC.glsl b/shaders/misc/viewport-NDC.glsl new file mode 100644 index 0000000..9593ad0 --- /dev/null +++ b/shaders/misc/viewport-NDC.glsl @@ -0,0 +1,20 @@ +// ----------------------------------------------------------------------------- +// Copyright (c) 2009-2016 Nicolas P. Rougier. All rights reserved. +// Distributed under the (new) BSD License. +// ----------------------------------------------------------------------------- + +vec2 NDC_to_viewport(vec4 position, vec2 viewport) +{ + vec2 p = position.xy/position.w; + return (p+1.0)/2.0 * viewport; +} + +vec4 viewport_to_NDC(vec2 position, vec2 viewport) +{ + return vec4(2.0*(position/viewport) - 1.0, 0.0, 1.0); +} + +vec4 viewport_to_NDC(vec2 position, vec2 viewport, float z) +{ + return vec4(2.0*(position/viewport) - 1.0, z, 1.0); +} \ No newline at end of file diff --git a/shaders/pcolormesh.frag b/shaders/pcolormesh.frag new file mode 100644 index 0000000..f5968d5 --- /dev/null +++ b/shaders/pcolormesh.frag @@ -0,0 +1,10 @@ +#version 330 core + +in vec2 location; +void main() { + + vec4 position = inverse(location); + + fragColor = vec4(position.x, position.y, 0.0, 1.0); + +} \ No newline at end of file diff --git a/shaders/pcolormesh.geom b/shaders/pcolormesh.geom new file mode 100644 index 0000000..10266ae --- /dev/null +++ b/shaders/pcolormesh.geom @@ -0,0 +1,54 @@ +#version 330 core +layout (points) in; +layout (triangle_strip, max_vertices = 4) out; + +uniform vec2 dpi; +uniform vec2 origin; +in vec4 near_coord[1]; + +out vec2 location; + + +void max_bound(vec4 near_coord, out vec2 _a0, out vec2 _a1, out vec2 _b0, out vec2 _b1) { + + vec2 a0 = vec2(near_coord.x, near_coord.z); + vec2 a1 = vec2(near_coord.x, near_coord.w); + + vec2 b0 = vec2(near_coord.y, near_coord.z); + vec2 b1 = vec2(near_coord.y, near_coord.w); + + vec2 a_c = (a1 + b1) / 2; + + float l1 = length(a_c - origin); + + float rate = near_coord.w / l1; + + vec2 r1 = a1 - origin; + vec2 r2 = b1 - origin; + + vec2 r1_ = r1 * rate; + vec2 r2_ = r2 * rate; + + _a0 = a0; + _a1 = a1; + _b0 = r2_ + origin; + _b1 = r1_ + origin; +} + +void main() { + vec4 position = vec4(0,0,0,0); + + vec2 a0, a1, b0, b1; + + max_bound(near_coord[0], a0, a1, b0, b1); + + gl_Position = vec4(a0, 0.0, 1.0); + EmitVertex(); + gl_Position = vec4(a1, 0.0, 1.0); + EmitVertex(); + gl_Position = vec4(b0, 0.0, 1.0); + EmitVertex(); + gl_Position = vec4(b1, 0.0, 1.0); + EmitVertex(); + EndPrimitive(); +} \ No newline at end of file diff --git a/shaders/pcolormesh.vert b/shaders/pcolormesh.vert new file mode 100644 index 0000000..16bd829 --- /dev/null +++ b/shaders/pcolormesh.vert @@ -0,0 +1,17 @@ +#version 330 core + +layout (location = 0) in vec2 in_position; +layout (location = 1) in vec3 value; +layout (location = 2) in vec4 coord; + +out vec4 near_coord; + +uniform vec2 dpi; + +void main() { + near_coord = coord; + + vec2 cart = forward(in_position); + + gl_Position = cart; +} \ No newline at end of file diff --git a/shaders/polar.frag b/shaders/polar.frag new file mode 100644 index 0000000..5563ff6 --- /dev/null +++ b/shaders/polar.frag @@ -0,0 +1,3 @@ +#version 330 core + +void main(){} \ No newline at end of file diff --git a/shaders/polar.vert b/shaders/polar.vert new file mode 100644 index 0000000..1d352bd --- /dev/null +++ b/shaders/polar.vert @@ -0,0 +1 @@ +#version 330 core \ No newline at end of file diff --git a/shaders/transform/polar.glsl b/shaders/transform/polar.glsl new file mode 100644 index 0000000..d0d55c3 --- /dev/null +++ b/shaders/transform/polar.glsl @@ -0,0 +1,33 @@ +#include "math/constants.glsl" + +uniform float polar_origin; + + +vec4 forward(float rho, float theta, float z, float w) +{ + return vec4(rho * cos(theta + polar_origin), + rho * sin(theta + polar_origin), + z, w); +} + +vec4 forward(float x, float y) {return forward(x, y, 0.0, 1.0);} +vec4 forward(float x, float y, float z) {return forward(x, y, z, 1.0);} +vec4 forward(vec2 P) { return forward(P.x, P.y); } +vec4 forward(vec3 P) { return forward(P.x, P.y, P.z, 1.0); } +vec4 forward(vec4 P) { return forward(P.x, P.y, P.z, P.w); } + +vec4 inverse(float x, float y, float z, float w) +{ + float rho = length(vec2(x,y)); + float theta = atan(y,x); + if( theta < 0.0 ) + theta = 2.0*M_PI+theta; + return vec4(rho, theta-polar_origin, z, w); +} + + +vec4 inverse(float x, float y) {return inverse(x,y,0.0,1.0); } +vec4 inverse(float x, float y, float z) {return inverse(x,y,z,1.0); } +vec4 inverse(vec2 P) { return inverse(P.x, P.y, 0.0, 1.0); } +vec4 inverse(vec3 P) { return inverse(P.x, P.y, P.z, 1.0); } +vec4 inverse(vec4 P) { return inverse(P.x, P.y, P.z, P.w); } \ No newline at end of file diff --git a/shaders/transform/position.glsl b/shaders/transform/position.glsl new file mode 100644 index 0000000..3ed6361 --- /dev/null +++ b/shaders/transform/position.glsl @@ -0,0 +1,50 @@ +// ----------------------------------------------------------------------------- +// Copyright (c) 2009-2016 Nicolas P. Rougier. All rights reserved. +// Distributed under the (new) BSD License. +// ----------------------------------------------------------------------------- +#include "geo-position-struct.glsl" + +vec4 position(float x) +{ + return vec4(x, 0.0, 0.0, 1.0); +} + +vec4 position(float x, float y) +{ + return vec4(x, y, 0.0, 1.0); +} + +vec4 position(vec2 xy) +{ + return vec4(xy, 0.0, 1.0); +} + +vec4 position(float x, float y, float z) +{ + return vec4(x, y, z, 1.0); +} + +vec4 position(vec3 xyz) +{ + return vec4(xyz, 1.0); +} + +vec4 position(vec4 xyzw) +{ + return xyzw; +} + +vec4 position(vec2 xy, float z) +{ + return vec4(xy, z, 1.0); +} + +vec4 position(float x, vec2 yz) +{ + return vec4(x, yz, 1.0); +} + +vec4 position(GeoPosition P) +{ + return vec4(P.longitude, P.latitude, 0.0, 1.0); +} diff --git a/shaders/transform/trackball.glsl b/shaders/transform/trackball.glsl new file mode 100644 index 0000000..bb4d1ec --- /dev/null +++ b/shaders/transform/trackball.glsl @@ -0,0 +1,15 @@ +// ----------------------------------------------------------------------------- +// Copyright (c) 2009-2016 Nicolas P. Rougier. All rights reserved. +// Distributed under the (new) BSD License. +// ----------------------------------------------------------------------------- +uniform mat4 trackball_view; +uniform mat4 trackball_model; +uniform mat4 trackball_projection; + +vec4 transform(vec4 position) +{ + return trackball_projection + * trackball_view + * trackball_model + * position; +} diff --git a/shaders/transform/viewport.glsl b/shaders/transform/viewport.glsl new file mode 100644 index 0000000..afabdc1 --- /dev/null +++ b/shaders/transform/viewport.glsl @@ -0,0 +1,50 @@ +// ----------------------------------------------------------------------------- +// 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; + +#ifdef _GLUMPY__VERTEX_SHADER__ +void transform() +{ + if (viewport_transform == 0) return; + + vec4 position = gl_Position; + + 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; + + gl_Position = vec4((x + w*position.x/position.w)*position.w, + (y + h*position.y/position.w)*position.w, + position.z, position.w); +} +#endif + +#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; + + /* + 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 \ No newline at end of file diff --git a/src/camera.rs b/src/camera.rs new file mode 100644 index 0000000..8305e73 --- /dev/null +++ b/src/camera.rs @@ -0,0 +1,55 @@ +use std::num::NonZeroU32; +use cgmath::Euler; +use glow::NativeProgram; +use nalgebra_glm::{ + Vec3, Mat4x4, look_at +}; + +pub(crate) struct Camera { + pos: Vec3, + upward: Vec3, + front: Vec3 +} + +pub type CameraPositon = Vec3; + +impl Camera { + pub(crate) fn new(world_loc: CameraPositon, upward: Vec3, front: Vec3) -> Self { + + Self { + pos: world_loc, + upward, + front + } + } + + pub fn get_position(&self) -> CameraPositon { + self.pos + } + + pub fn set_position(&mut self, pos: CameraPositon) { + self.pos = pos; + } + + pub fn get_front(&self) -> Vec3 { + self.front + } + + pub fn set_front(&mut self, front: Vec3) { + self.front = front; + } + + pub fn get_upward(&self) -> Vec3 { + self.upward + } + + pub fn set_upward(&mut self, upward: Vec3) { + self.upward = upward; + } + + pub fn get_view_matrix(&self) -> Mat4x4 { + let l = self.pos + self.front; + look_at(&self.pos, &l, &self.upward) + } + +} \ No newline at end of file diff --git a/src/components/mod.rs b/src/components/mod.rs new file mode 100644 index 0000000..96e1fba --- /dev/null +++ b/src/components/mod.rs @@ -0,0 +1,13 @@ +mod program; +mod shader; +mod snippets; + +pub use program::Program; +pub use shader::{fetchcode, Shader}; +pub use snippets::*; + +pub trait CodeComponent: Sized { + fn add_snippet_before(self, snippet: Snippet) -> Self; + + fn add_snippet_after(self, snippet: Snippet) -> Self; +} diff --git a/src/components/program.rs b/src/components/program.rs new file mode 100644 index 0000000..992581b --- /dev/null +++ b/src/components/program.rs @@ -0,0 +1,137 @@ +use glow::HasContext; + +use super::shader::Shader; +use super::snippets::{CodeType, Snippet}; +use crate::graphics::transforms::{viewport::Viewport, Transform}; + +#[derive(Debug)] +pub struct Program { + version: &'static str, + vertex: Shader, + fragment: Shader, + + geometry: Option, + pub native_program: Option<::Program>, +} + +impl Program { + pub fn new( + vertex: Shader, + fragment: Shader, + geometry: Option, + version: &'static str, + ) -> Self { + let res = Self { + version, + vertex, + fragment, + geometry, + native_program: None, + }; + + res + } + + pub fn vertex(&self) -> &Shader { + &self.vertex + } + + pub fn fragment(&self) -> &Shader { + &self.fragment + } + + pub fn set_hook(&mut self, hook: &str, code: &Snippet) { + self.vertex.set_hook(hook, code); + self.fragment.set_hook(hook, code); + } + + pub fn set_transform(&mut self, value: &T) { + self.set_hook("transform", value.snippet()); + } + + pub fn set_viewport(&mut self, viewport: &Viewport) { + self.set_hook("viewport", viewport.snippet()); + } + + pub fn compile(&mut self, gl: &glow::Context) { + unsafe { + let vertex_array = gl + .create_vertex_array() + .expect("Cannot create vertex array"); + + let program = gl.create_program().expect("Cannot create program"); + + let vertex_shader = + self.create_shader(gl, &self.vertex.to_string(), glow::VERTEX_SHADER); + let fragment_shader = + self.create_shader(gl, &self.fragment.to_string(), glow::FRAGMENT_SHADER); + + gl.link_program(program); + if !gl.get_program_link_status(program) { + panic!("{}", gl.get_program_info_log(program)); + } + gl.detach_shader(program, vertex_shader); + gl.detach_shader(program, fragment_shader); + + self.native_program = Some(program); + } + } + + fn create_shader( + &self, + gl: &glow::Context, + code: &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); + } + } +} + +mod test { + use super::*; + + #[test] + fn test_program() { + 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 program = Program::new(vertex, fragment, None, "330 core"); + } +} diff --git a/src/components/shader.rs b/src/components/shader.rs new file mode 100644 index 0000000..fb0c72d --- /dev/null +++ b/src/components/shader.rs @@ -0,0 +1,220 @@ +use std::borrow::Borrow; + +use super::{ + snippets::{merge_includes, CodeType, Snippet, Variable}, + CodeComponent, +}; +use crate::{ + errors::{Error, Result}, + utils::{find_file, CodeBlock}, +}; +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, +} + +impl std::fmt::Display for Shader { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", self.parsed) + } +} + +impl Shader { + pub fn new>(target: ShaderType, code: CodeType) -> Result { + let code = match code { + CodeType::Code(code) => code.borrow().to_string(), + CodeType::Path(path) => { + let code = find_file(path).expect("Failed to find file"); + code + } + }; + + let code = merge_includes(code).map_err(|e| Error::InvalidSnippet(e.to_string()))?; + let parsed = CodeBlock::new(&code)?; + + let hooks = parsed.all_hooks().iter().map(|h| h.name.clone()).collect(); + info!("Shader:{} Hooks: {:?}", target, hooks); + + Ok(Self { + target, + code, + parsed, + hooks, + }) + } + + pub fn compile(&self) {} + + pub fn set_hook(&mut self, hook: &str, code: &Snippet) { + self.parsed.set_hook(hook, code); + } +} + +impl CodeComponent for Shader { + fn add_snippet_after(self, snippet: Snippet) -> Self { + let new_code = self.to_string() + &snippet.to_string(); + let result = Self::new(self.target, CodeType::Code(new_code)).unwrap(); + result + } + + fn add_snippet_before(self, snippet: Snippet) -> Self { + let new_code = snippet.to_string() + &self.to_string(); + let result = Self::new(self.target, CodeType::Code(new_code)).unwrap(); + result + } +} + +mod utils { + use once_cell::sync::Lazy; + use std::collections::HashMap; + + use crate::{ + components::{CodeType, Snippet}, + utils::CodeBlock, + }; + + static TYPES: Lazy> = Lazy::new(|| { + [ + (1, "float"), + (2, "vec2 "), + (3, "vec3 "), + (4, "vec4 "), + (9, "mat3 "), + (16, "mat4 "), + ] + .iter() + .cloned() + .collect::>() + }); + + pub fn fetchcode<'a, V: AsRef<[(&'a str, usize)]>>(data_types: V, prefix: &str) -> Snippet { + let mut header = String::from( + " + uniform sampler2D uniforms; + uniform vec3 uniforms_shape; + layout(location = 0) in float collection_index;\n + ", + ); + + for data_type in data_types.as_ref().iter() { + if data_type.0 != "__unused__" { + if let Some(type_name) = TYPES.get(&data_type.1) { + header.push_str(&format!("out {} {}{};\n", type_name, prefix, data_type.0)); + } + } + } + + let mut body = String::from( + " + void fetch_uniforms() { + float rows = uniforms_shape.x; + float cols = uniforms_shape.y; + float count = uniforms_shape.z; + float index = collection_index; + int index_x = int(mod(index, (floor(cols/(count/4.0))))) * int(count/4.0); + int index_y = int(floor(index / (floor(cols/(count/4.0))))); + float size_x = cols - 1.0; + float size_y = rows - 1.0; + float ty = 0.0; + if (size_y > 0.0) + ty = float(index_y)/size_y; + int i = index_x; + vec4 _uniform; + ", + ); + + for data_type in data_types.as_ref().iter() { + if data_type.0 != "__unused__" { + let component_count = data_type.1; + let mut store = 0; + let mut shift = 0; + let mut count = component_count; + while count > 0 { + if store == 0 { + body.push_str(&format!( + "\n _uniform = texture2D(uniforms, vec2(float(i++)/size_x,ty));\n" + )); + store = 4; + } + let (a, b) = match store { + 4 => ( + "xyzw", + match shift { + 0 => "xyzw", + 1 => "yzw", + 2 => "zw", + 3 => "w", + _ => "", + }, + ), + 3 => ( + "yzw", + match shift { + 0 => "yzw", + 1 => "zw", + 2 => "w", + _ => "", + }, + ), + 2 => ( + "zw", + match shift { + 0 => "zw", + 1 => "w", + _ => "", + }, + ), + 1 => ("w", "w"), + _ => ("", ""), + }; + let min_length = std::cmp::min(b.len(), count); + body.push_str(&format!( + " {}{}{} = _uniform.{};\n", + prefix, + data_type.0, + &b[0..min_length], + &a[0..min_length] + )); + count -= min_length; + shift += min_length; + store -= min_length; + } + } + } + + body.push_str("}\n\n"); + let input = header + &body; + + let result = Snippet::new("fetch_uniform", CodeType::Code(input), None).unwrap(); + + result + } +} + +mod test { + use super::utils::fetchcode; + use super::*; + + #[test] + fn test_shader() { + let shader = Shader::new( + glow::VERTEX_SHADER, + CodeType::<&'static str>::Path("agg-fast-path.vert".into()), + ) + .unwrap(); + + println!("{}", shader.parsed); + } + + #[test] + fn test_fetchcode() { + let code = fetchcode([("position", 3), ("color", 4)], "a_"); + println!("{}", code); + } +} diff --git a/src/components/snippets/mod.rs b/src/components/snippets/mod.rs new file mode 100644 index 0000000..5f36fa2 --- /dev/null +++ b/src/components/snippets/mod.rs @@ -0,0 +1,192 @@ +use regex::{Captures, Regex}; +use std::{ + cell::{Ref, RefCell}, + collections::{HashMap, HashSet}, + ops::Add, + rc::Rc, + sync::atomic::{AtomicUsize, Ordering}, +}; +pub use util::Variable; + +use crate::{ + errors::{Error, Result}, + utils::{find_file, Code, CodeBlock, Function, Hook, ShareVariable, SnippetCode}, +}; +mod util; +pub use util::merge_includes; +use util::*; + +use super::CodeComponent; + +static SNIP_ID: AtomicUsize = AtomicUsize::new(0); + +#[derive(Debug, Clone)] +pub enum InputType { + Vertex(usize, Variable), + Other(Variable), +} + +pub enum CodeType> { + Code(S), + Path(std::path::PathBuf), +} + +#[derive(Debug, Clone)] +pub struct Snippet { + id: usize, + name: &'static str, + parsed: CodeBlock, + link: Option>, + alias: HashMap, + chained: String, + main: String, +} + +impl Snippet { + pub fn new>( + name: &'static str, + code: CodeType, + main: Option, + ) -> Result { + let code = match code { + CodeType::Code(code) => code.borrow().to_string(), + CodeType::Path(path) => { + let code = find_file(path).expect("Failed to find file"); + code + } + }; + + let merged_code = merge_includes(code) + .map(|code| { + let clean_code = remove_comments(&code); + let clean_code = remove_version(&clean_code); + clean_code + }) + .map_err(|v| { + let err_msg = format!("Failed to merge includes cause of {:?}", v); + Error::InvalidSnippet(err_msg) + })?; + + let id = SNIP_ID.fetch_add(1, Ordering::SeqCst); + + let mut parsed_code = CodeBlock::new(&merged_code)?; + let call = if let Some(main) = main { + main + } else { + parsed_code + .all_functions() + .first() + .map(|f| f.borrow().name.clone()) + .unwrap() + }; + let alias = parsed_code.mangling(id.to_string()); + + let chained = format!( + "// START {} //\n{}\n// END {} //\n", + name, parsed_code, name + ); + + Ok(Self { + id, + name, + parsed: parsed_code, + chained, + alias, + link: None, + main: call, + }) + } + + pub fn all_hooks(&self) -> HashSet { + self.parsed.all_hooks() + } + + pub fn chain(mut self, snippet: Snippet) -> Self { + self.chained = format!( + "// START {} //\n{}\n// END {} //\n{}\n\n", + snippet.name, snippet.chained, snippet.name, self.chained, + ); + + self.link = Some(Box::new(snippet)); + self + } + + pub fn call(&self, paras: &Vec) -> String { + if let Some(link) = &self.link { + let call_name = self.alias.get(&self.main).unwrap(); + let c = link.call(paras); + format!("{}({})", call_name, c) + } else { + let call_name = self.alias.get(&self.main).unwrap(); + format!("{}({})", call_name, paras.join(", ")) + } + } + + pub fn prepare_code(&self) -> &str { + &self.chained + } + + pub fn find_symbol(&self, name: &str) -> Option<&String> { + self.alias.get(name) + } + + pub fn find_variable(&self, name: &str) -> Option<&Rc>> { + self.find_symbol(name) + .map(|v| self.parsed.find_variable(v)) + .flatten() + } +} + +impl std::fmt::Display for Snippet { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", self.parsed) + } +} + +impl Add for Snippet { + type Output = Self; + + fn add(self, rhs: Self) -> Self::Output { + let mut raw_code = self.parsed.to_string(); + let code = rhs.parsed.to_string(); + + raw_code.push_str(&code); + Snippet::new(self.name, CodeType::Code(raw_code), None).unwrap() + } +} + +impl CodeComponent for Snippet { + fn add_snippet_after(self, snippet: Snippet) -> Self { + self + snippet + } + + fn add_snippet_before(self, snippet: Snippet) -> Self { + snippet + self + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_snippet_new() { + let code = r#" + #version 450 + #include "math/constants.glsl" + void main() { + gl_Position = vec4(0.0); + } + "#; + + let snippet = Snippet::new("polar", CodeType::Code(code), None).unwrap(); + + let snippet2 = Snippet::new("polar2", CodeType::Code(code), None).unwrap(); + + let snippet3 = snippet.clone() + snippet2.clone(); + + let snippet = snippet.chain(snippet2.chain(snippet3)); + + println!("{}", snippet.prepare_code()); + } +} diff --git a/src/components/snippets/util.rs b/src/components/snippets/util.rs new file mode 100644 index 0000000..e0785d7 --- /dev/null +++ b/src/components/snippets/util.rs @@ -0,0 +1,278 @@ +use include_dir::{include_dir, Dir}; +use nom::{ + branch::alt, + bytes::{ + complete::{tag, take_while1}, + streaming::take_while, + }, + character::{ + complete::{alpha1, char, multispace0, multispace1, space0, space1}, + streaming::none_of, + }, + combinator::{map, opt, recognize}, + multi::{fold_many0, many0, separated_list0}, + sequence::{delimited, pair, preceded, tuple}, + IResult, +}; +use once_cell::sync::Lazy; +use regex::Regex; +use std::path::Path; +use std::{collections::HashMap, io}; +use std::{collections::HashSet, env::var}; + +use crate::utils::find_file; + +static COMMENT_RE: Lazy = + Lazy::new(|| Regex::new(r#"(\".*?\"|\'.*?\')|(/\*.*?\*/|//[^\r\n]*\n)"#).unwrap()); +static VERSION_RE: Lazy = Lazy::new(|| Regex::new(r#"\#\s*version[^\r\n]*\n"#).unwrap()); +static INCLUDE_RE: Lazy = + Lazy::new(|| Regex::new(r#"\#\s*include\s*\"(?P[a-zA-Z0-9\-\.\/_]+)\""#).unwrap()); + +static VARIABLE_TYPE_PAT: Lazy = + Lazy::new(|| Regex::new(r#"(\w+)\s+([\w\[\] ]+);"#).unwrap()); + +static VARIABLE_NAME_PAT: Lazy = + Lazy::new(|| Regex::new(r#"(\w+)\s*(\[(\d+)\])?(\s*[^,]+)?"#).unwrap()); + +static TYPE_MAP: Lazy> = Lazy::new(|| { + let mut gtypes: HashMap<&str, u32> = HashMap::new(); + gtypes.insert("float", glow::FLOAT); + gtypes.insert("vec2", glow::FLOAT_VEC2); + gtypes.insert("vec3", glow::FLOAT_VEC3); + gtypes.insert("vec4", glow::FLOAT_VEC4); + gtypes.insert("int", glow::INT); + gtypes.insert("ivec2", glow::INT_VEC2); + gtypes.insert("ivec3", glow::INT_VEC3); + gtypes.insert("ivec4", glow::INT_VEC4); + gtypes.insert("bool", glow::BOOL); + gtypes.insert("bvec2", glow::BOOL_VEC2); + gtypes.insert("bvec3", glow::BOOL_VEC3); + gtypes.insert("bvec4", glow::BOOL_VEC4); + gtypes.insert("mat2", glow::FLOAT_MAT2); + gtypes.insert("mat3", glow::FLOAT_MAT3); + gtypes.insert("mat4", glow::FLOAT_MAT4); + gtypes.insert("sampler1D", glow::SAMPLER_1D); + gtypes.insert("sampler2D", glow::SAMPLER_2D); + gtypes.insert("sampler3D", glow::SAMPLER_3D); + gtypes.insert("samplerCube", glow::SAMPLER_CUBE); + gtypes +}); + +#[derive(Debug, Clone)] +pub struct Variable { + pub name: String, + pub vtype: String, + pub type_code: u32, +} + +fn get_declarations(code: &str, qualifier: Option<&[&str]>) -> Option> { + if code.is_empty() { + return None; + } + + let qualifier_pattern = if let Some(quals) = qualifier { + quals.join("|") + } else { + String::new() + }; + + let type_pattern = if !qualifier_pattern.is_empty() { + format!(r"{}\s+(\w+)\s+([\w,\[\]\n =\.]+);", qualifier_pattern) + } else { + String::from(r"(\w+)\s+([\w\[\] ]+);") + }; + + let re_type = Regex::new(&type_pattern).unwrap(); + let mut variables = Vec::new(); + + for caps in re_type.captures_iter(code) { + let vtype = caps.get(1).unwrap().as_str().to_string(); + let names = caps.get(2).unwrap().as_str(); + + for cap in VARIABLE_NAME_PAT.captures_iter(names) { + let name = cap.get(1).unwrap().as_str().to_string(); + if let Some(size_match) = cap.get(3) { + let size: usize = size_match.as_str().parse().unwrap(); + if size == 0 { + return None; + } + for i in 0..size { + let iname = format!("{}[{}]", name, i); + variables.push(Variable { + name: iname, + vtype: vtype.clone(), + type_code: *TYPE_MAP.get(vtype.as_str()).unwrap(), + }); + } + } else { + variables.push(Variable { + name, + vtype: vtype.clone(), + type_code: *TYPE_MAP.get(vtype.as_str()).unwrap(), + }); + } + } + } + + Some(variables) +} + +pub(super) fn get_uniform(code: &str) -> Vec { + let uniforms = get_declarations(code, Some(&["uniform"])); + uniforms.unwrap_or_default() +} + +pub(super) fn get_const(code: &str) -> Vec { + let consts = get_declarations(code, Some(&["const"])); + consts.unwrap_or_default() +} + +pub(super) fn get_in(code: &str) -> Vec<(Option, Variable)> { + let ins = get_declarations(code, Some(&[r#"(layout\s?\(location\s?=(\d+)\)\s+)?in"#])); + + if ins.is_none() { + return vec![]; + } + + let mut variables: Vec = Vec::new(); + + let type_pattern = r#"layout\s?\(location\s?=(\d+)\)"#; + let re_type = Regex::new(&type_pattern).unwrap(); + + for cap in re_type.captures_iter(code) { + if let Some(matched) = cap.get(1) { + variables.push(matched.as_str().parse().unwrap()); + } + } + + let ins = ins.unwrap(); + + if ins.len() != variables.len() && !variables.is_empty() { + return vec![]; + } else { + ins.into_iter() + .enumerate() + .map(|(i, v)| (variables.get(i).copied(), v)) + .collect() + } +} + +pub(super) fn get_out(code: &str) -> Vec { + let outs = get_declarations(code, Some(&[r#"(layout\(.+\)\w+)?out"#])); + outs.unwrap_or_default() +} + +pub(super) fn get_hooks(code: &str) -> Vec<(String, Option)> { + if code.is_empty() { + return vec![]; + } + + let re_hooks = Regex::new(r#"\<(?P\w+)(\.(?P.+))?(?:\([^<>]+\))?\>"#).unwrap(); + let mut hooks = HashSet::new(); + + for cap in re_hooks.captures_iter(code) { + let hook = cap.name("hook").unwrap().as_str().to_string(); + let subhook = cap.name("subhook").map(|m| m.as_str().to_string()); + hooks.insert((hook, subhook)); + } + + hooks.into_iter().collect() +} + +// 移除 GLSL 代码中的注释 +pub(super) fn remove_comments(code: &str) -> String { + COMMENT_RE + .replace_all(code, |caps: ®ex::Captures| { + if caps.get(2).is_some() { + "".to_string() + } else { + caps.get(1).unwrap().as_str().to_string() + } + }) + .to_string() +} + +// 移除 GLSL 代码中的版本指令 +pub(super) fn remove_version(code: &str) -> String { + VERSION_RE.replace_all(code, "\n").to_string() +} + +// 递归合并包含的文件内容 +pub fn merge_includes(mut code: String) -> io::Result { + let mut includes: Vec = vec![]; + + for _ in 0..10 { + if INCLUDE_RE.is_match(&code) { + let c = INCLUDE_RE.replace_all(&code, |caps: ®ex::Captures| { + let filename = caps.name("filename").unwrap().as_str().to_string(); + + if !includes.contains(&filename) { + let file_data = + find_file(&filename).expect(&format!("File {} not found", filename)); + + let cleaned_contents = remove_comments(&file_data); + let new_code = format!( + "\n// --- start of \"{}\" ---\n{}\n// --- end of \"{}\" ---\n", + filename, cleaned_contents, filename + ); + includes.push(filename); + new_code + } else { + "".to_string() + } + }); + + code = c.to_string(); + } else { + break; + } + } + Ok(code) +} + +mod test { + + use super::{get_declarations, get_hooks, get_in, merge_includes}; + use std::{fs::read_to_string, io::Write}; + + #[test] + fn test_include() { + let file = + std::fs::read_to_string("/Users/tsuki/projects/untitled/shaders/transform/polar.glsl") + .unwrap(); + + let mut merged = std::fs::File::create( + "/Users/tsuki/projects/untitled/shaders/transform/polar_merged.glsl", + ) + .unwrap(); + + merged + .write_all(merge_includes(file).unwrap().as_bytes()) + .unwrap(); + } + + #[test] + fn test_declare() { + let code = " + uniform float u_time; + attribute vec3 position; + uniform vec4 colors[3]; + layout(location = 0) in vec3 position; + "; + + let variables = get_in(code); + println!("{:?}", variables); + } + + #[test] + fn test_hook() { + let code = r" + + + + "; + + let hooks = get_hooks(code); + println!("{:?}", hooks); + } +} diff --git a/src/errors.rs b/src/errors.rs new file mode 100644 index 0000000..99104f7 --- /dev/null +++ b/src/errors.rs @@ -0,0 +1,9 @@ +use thiserror::Error; + +pub type Result = std::result::Result; + +#[derive(Error, Debug)] +pub enum Error { + #[error("Invalid Snippet {0}")] + InvalidSnippet(String), +} diff --git a/src/final_pg.rs b/src/final_pg.rs new file mode 100644 index 0000000..8f0d9ff --- /dev/null +++ b/src/final_pg.rs @@ -0,0 +1,68 @@ +use glow::HasContext; + +use crate::{ + components::{CodeType, Program, Shader}, + graphics::transforms::{ + polar::Polar, position::Position, trackball::Trackball, viewport::Viewport, Transform, + }, +}; + +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(); + + 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 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 viewport = Viewport::new().unwrap(); + + program.set_transform(&transform); + + program.set_viewport(&viewport); + + Self { transform, program } + } + + pub fn compile(&mut self, gl: &glow::Context) { + self.program.compile(gl); + } + + pub fn program(&self) -> &Program { + &self.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"); + + println!("{}", ppi.program.vertex()); + } +} diff --git a/src/graphics/collections/agg_fast_path.rs b/src/graphics/collections/agg_fast_path.rs new file mode 100644 index 0000000..8d62212 --- /dev/null +++ b/src/graphics/collections/agg_fast_path.rs @@ -0,0 +1,139 @@ +use std::ops::{Deref, DerefMut}; + +use bytemuck::{Pod, Zeroable}; + +use crate::components::{fetchcode, CodeComponent, CodeType, Program, Shader}; +use crate::errors::*; +use crate::graphics::transforms::viewport::Viewport; +use crate::graphics::transforms::Transform; +use crate::graphics::ty::Ty; +use crate::graphics::Graphics; + +use super::Colletion; + +struct AggFastPath { + program: Program, + buffer: Vec, +} + +impl AggFastPath { + pub fn new(transform: &T, viewport: &Viewport) -> Result { + let vertex = Shader::new( + glow::VERTEX_SHADER, + CodeType::::Path("agg-fast-path.vert".into()), + )?; + + let fragment = Shader::new( + glow::FRAGMENT_SHADER, + CodeType::::Path("agg-fast-path.frag".into()), + )?; + + let vertex = vertex.add_snippet_after(fetchcode([], "agg_fast")); + + let mut program = Program::new(vertex, fragment, None, ""); + + program.set_transform(transform); + program.set_viewport(viewport); + + Ok(Self { + program, + buffer: Vec::with_capacity(500), + }) + } +} + +impl Colletion for AggFastPath { + type Item = Path; + + fn append(&mut self, item: Self::Item) { + self.buffer.push(item); + } +} + +impl Graphics for AggFastPath { + fn draw(&self) -> Result<()> { + for path in self.buffer.iter() { + let p: &[u8] = &path; + } + 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 Path { + pub fn new(is_closed: bool) -> Self { + Self { + points: Vec::with_capacity(500), + is_closed, + is_empty: true, + } + } + + pub fn push(&mut self, point: [f32; 3]) { + if self.is_empty { + self.points.push(Point { + prev: point, + curr: point, + next: point, + }); + + 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; + } + } + + pub fn finish(&mut self) { + if self.is_closed { + let len = self.points.len(); + let prev = self.points[len - 1].curr; + let curr = self.points[0].curr; + let next = self.points[1].curr; + self.points.push(Point { prev, curr, next }); + self.points[len - 1].next = curr; + } + } +} + +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) + } +} diff --git a/src/graphics/collections/mod.rs b/src/graphics/collections/mod.rs new file mode 100644 index 0000000..c31d625 --- /dev/null +++ b/src/graphics/collections/mod.rs @@ -0,0 +1,7 @@ +pub mod agg_fast_path; + +pub trait Colletion { + type Item; + + fn append(&mut self, item: Self::Item); +} diff --git a/src/graphics/colormesh.rs b/src/graphics/colormesh.rs new file mode 100644 index 0000000..b81ba1a --- /dev/null +++ b/src/graphics/colormesh.rs @@ -0,0 +1 @@ +pub struct ColorMesh {} diff --git a/src/graphics/mod.rs b/src/graphics/mod.rs new file mode 100644 index 0000000..9921da9 --- /dev/null +++ b/src/graphics/mod.rs @@ -0,0 +1,12 @@ +pub mod collections; +mod colormesh; +pub mod tools; +pub mod transforms; +pub mod ty; +use crate::errors::*; + +pub use colormesh::ColorMesh; + +pub trait Graphics { + fn draw(&self) -> Result<()>; +} diff --git a/src/graphics/tools/mod.rs b/src/graphics/tools/mod.rs new file mode 100644 index 0000000..e69de29 diff --git a/src/graphics/transforms/mod.rs b/src/graphics/transforms/mod.rs new file mode 100644 index 0000000..bbfe261 --- /dev/null +++ b/src/graphics/transforms/mod.rs @@ -0,0 +1,26 @@ +pub mod polar; +pub mod position; +pub mod trackball; +pub mod viewport; +use crate::components::Snippet; + +pub trait Transform { + fn snippet(&self) -> &Snippet; + + fn chain(self, other: impl Transform) -> Self; +} + +mod test { + use super::*; + + #[test] + fn test_transform() { + let polar = polar::Polar::new().unwrap(); + let trackball = trackball::Trackball::new().unwrap(); + let polar_trackball = polar.chain(trackball); + + println!("{}", polar_trackball.snippet().prepare_code()); + + // println!("{}", polar_trackball.snippet().call(vec![])); + } +} diff --git a/src/graphics/transforms/polar.rs b/src/graphics/transforms/polar.rs new file mode 100644 index 0000000..fd63bfa --- /dev/null +++ b/src/graphics/transforms/polar.rs @@ -0,0 +1,49 @@ +use crate::{ + components::{CodeType, Snippet}, + errors::*, +}; + +use super::Transform; + +pub struct Polar { + snippet: Snippet, + origin: f32, +} + +impl Polar { + pub fn new() -> Result { + let snippets = Snippet::new( + "polar", + CodeType::<&'static str>::Path("transform/polar.glsl".into()), + Some("forward".to_string()), + )?; + + Ok(Self { + snippet: snippets, + origin: 0.0, + }) + } +} + +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 + } +} + +mod test { + use super::*; + + #[test] + fn test_polar() { + let polar = Polar::new().unwrap(); + + println!("{}", polar.snippet); + } +} diff --git a/src/graphics/transforms/position.rs b/src/graphics/transforms/position.rs new file mode 100644 index 0000000..b1971ea --- /dev/null +++ b/src/graphics/transforms/position.rs @@ -0,0 +1,41 @@ +use super::Transform; +use crate::{ + components::{CodeType, Snippet}, + errors::*, +}; +pub struct Position { + snippet: Snippet, +} + +impl Position { + pub fn new() -> Result { + let snippets = Snippet::new( + "position", + CodeType::<&'static str>::Path("transform/position.glsl".into()), + None, + )?; + + Ok(Self { snippet: snippets }) + } +} + +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 + } +} + +mod test { + use super::*; + + #[test] + fn test_position() { + let position = Position::new().unwrap(); + } +} diff --git a/src/graphics/transforms/trackball.rs b/src/graphics/transforms/trackball.rs new file mode 100644 index 0000000..36cb8a5 --- /dev/null +++ b/src/graphics/transforms/trackball.rs @@ -0,0 +1,43 @@ +use crate::components::{CodeType, Snippet}; +use crate::errors::Result; + +use super::Transform; + +pub struct Trackball { + snippet: Snippet, +} + +impl Trackball { + pub fn new() -> Result { + let snippets = Snippet::new( + "trackball", + CodeType::<&'static str>::Path("transform/trackball.glsl".into()), + None, + )?; + + Ok(Self { snippet: snippets }) + } +} + +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 + } +} + +mod test { + use super::*; + + #[test] + fn test_trackball() { + let trackball = Trackball::new().unwrap(); + + println!("{}", trackball.snippet); + } +} diff --git a/src/graphics/transforms/viewport.rs b/src/graphics/transforms/viewport.rs new file mode 100644 index 0000000..26f5b7b --- /dev/null +++ b/src/graphics/transforms/viewport.rs @@ -0,0 +1,23 @@ +use crate::{ + components::{self, CodeType, Snippet}, + errors::*, +}; +pub struct Viewport { + snippet: Snippet, +} + +impl Viewport { + pub fn new() -> Result { + let snippets = Snippet::new( + "viewport", + CodeType::<&'static str>::Path("transform/viewport.glsl".into()), + None, + )?; + + Ok(Self { snippet: snippets }) + } + + pub fn snippet(&self) -> &Snippet { + &self.snippet + } +} diff --git a/src/graphics/ty/mod.rs b/src/graphics/ty/mod.rs new file mode 100644 index 0000000..f4967aa --- /dev/null +++ b/src/graphics/ty/mod.rs @@ -0,0 +1,3 @@ +use bytemuck::{Pod, Zeroable}; + +pub trait Ty: Pod {} diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..9de5286 --- /dev/null +++ b/src/main.rs @@ -0,0 +1,55 @@ +use imgui::Condition; + +mod camera; +mod components; +mod errors; +mod graphics; +mod support; +mod utils; + +mod final_pg; + +fn main() { + env_logger::init(); + let choices = ["test test this is 1", "test test this is 2"]; + let mut value = 0; + support::supporter::init(move |_, ui| { + 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; + } + + 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] + )); + }); + + 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; + } + + 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] + )); + }); + }); +} diff --git a/src/support/clipboard.rs b/src/support/clipboard.rs new file mode 100644 index 0000000..dd74d06 --- /dev/null +++ b/src/support/clipboard.rs @@ -0,0 +1,18 @@ +use copypasta::{ClipboardContext, ClipboardProvider}; +use imgui::ClipboardBackend; + +pub struct ClipboardSupport(pub ClipboardContext); + +pub fn init() -> Option { + ClipboardContext::new().ok().map(ClipboardSupport) +} + +impl ClipboardBackend for ClipboardSupport { + fn get(&mut self) -> Option { + self.0.get_contents().ok() + } + fn set(&mut self, text: &str) { + // ignore errors? + let _ = self.0.set_contents(text.to_owned()); + } +} diff --git a/src/support/mod.rs b/src/support/mod.rs new file mode 100644 index 0000000..5bbbbdb --- /dev/null +++ b/src/support/mod.rs @@ -0,0 +1,2 @@ +mod clipboard; +pub mod supporter; diff --git a/src/support/supporter.rs b/src/support/supporter.rs new file mode 100644 index 0000000..c72cd15 --- /dev/null +++ b/src/support/supporter.rs @@ -0,0 +1,284 @@ +use crate::utils::Triangler; +use nalgebra_glm::perspective; +use glutin::{ + config::ConfigTemplateBuilder, + context::{ContextAttributesBuilder, NotCurrentGlContext, PossiblyCurrentContext}, + display::{GetGlDisplay, GlDisplay}, + surface::{GlSurface, Surface, SurfaceAttributesBuilder, WindowSurface}, +}; +use imgui::Ui; +use imgui_winit_support::{HiDpiMode, winit::{ + dpi::{LogicalSize, PhysicalPosition}, + event_loop::EventLoop, + window::{Window, WindowBuilder}, +}, WinitPlatform}; +use raw_window_handle::HasRawWindowHandle; +use std::num::NonZeroU32; +use std::time::Instant; +use cgmath::InnerSpace; +use glow::HasContext; +use nalgebra_glm::Vec3; +use crate::camera::Camera; + +pub fn init(mut run_ui: FUi) +where + FUi: FnMut(&mut bool, &mut Ui) + '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 + }; + + // OpenGL renderer from this crate + let mut ig_renderer = imgui_glow_renderer::AutoRenderer::initialize(gl, &mut imgui_context) + .expect("failed to create renderer"); + + let mut last_frame = Instant::now(); + let tri_renderer = Triangler::new(ig_renderer.gl_context(), "#version 330"); + + 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; + + event_loop + .run(move |event, window_target| { + match event { + winit::event::Event::NewEvents(_) => { + let now = Instant::now(); + imgui_context + .io_mut() + .update_delta_time(now.duration_since(last_frame)); + last_frame = now; + } + winit::event::Event::AboutToWait => { + winit_platform + .prepare_frame(imgui_context.io_mut(), &window) + .unwrap(); + + window.request_redraw(); + } + winit::event::Event::WindowEvent { + event: winit::event::WindowEvent::RedrawRequested, + .. + } => { + // Render your custom scene, note we need to borrow the OpenGL + // context from the `AutoRenderer`, which takes ownership of it. + + 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()); + } + + tri_renderer.render(ig_renderer.gl_context()); + + 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); + } + } + + let mut run = true; + run_ui(&mut run, ui); + + if !run { + window_target.exit(); + } + + let draw_data = imgui_context.render(); + + // Render imgui on top of it + ig_renderer + .render(draw_data) + .expect("error rendering imgui"); + + surface + .swap_buffers(&context) + .expect("Failed to swap buffers"); + } + winit::event::Event::WindowEvent { + event: winit::event::WindowEvent::CloseRequested, + .. + } => { + window_target.exit(); + } + + winit::event::Event::WindowEvent { + event: winit::event::WindowEvent::Resized(new_size), + .. + } => { + if new_size.width > 0 && new_size.height > 0 { + surface.resize( + &context, + NonZeroU32::new(new_size.width).unwrap(), + NonZeroU32::new(new_size.height).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); + } + event => { + winit_platform.handle_event(imgui_context.io_mut(), &window, &event); + } + } + }) + .unwrap() +} + +fn mouse_callback(last_position: &mut Option>, current_position:PhysicalPosition, sensitivity: f64, pitch: &mut f64, yaw: &mut f64, camera: &mut Camera) { + use cgmath::{Euler, Deg, Quaternion}; + + let xpos = current_position.x; + let ypos = current_position.y; + + if last_position.is_none() { + *last_position = Some(PhysicalPosition::new(xpos, ypos)); + } + + let _last_position = last_position.unwrap(); + + let mut xoffset = xpos - _last_position.x; + let mut yoffset = _last_position.y - ypos; // reversed since y-coordinates go from bottom to top + + *last_position = Some(PhysicalPosition::new(xpos, ypos)); + + xoffset *= sensitivity; + yoffset *= sensitivity; + + *yaw += xoffset; + *pitch += yoffset; + + if *pitch > 89.0 { + *pitch = 89.0; + } + + if *pitch < -89.0 { + *pitch = -89.0; + } + + let euler_deg = Euler::new( + Deg(*pitch), + Deg(*yaw), + Deg(0.0), + ); + + let c = Quaternion::from(euler_deg).normalize(); + + camera.set_front(Vec3::new(c.v.x as f32, c.v.y as f32, c.v.z as f32)); +} + +fn create_window() -> ( + EventLoop<()>, + Window, + Surface, + PossiblyCurrentContext, +) { + let event_loop = EventLoop::new().unwrap(); + + let window_builder = WindowBuilder::new() + .with_title("TEST") + .with_inner_size(LogicalSize::new(1024, 768)); + + let (window, cfg) = glutin_winit::DisplayBuilder::new() + .with_window_builder(Some(window_builder)) + .build(&event_loop, ConfigTemplateBuilder::new(), |mut cfgs| { + cfgs.next().unwrap() + }) + .expect("Failed to create window"); + + let window = window.unwrap(); + + let context_attributes = + ContextAttributesBuilder::new().build(Some(window.raw_window_handle())); + + let context = unsafe { + cfg.display() + .create_context(&cfg, &context_attributes) + .unwrap() + }; + + let surface_attributes = SurfaceAttributesBuilder::::new() + .with_srgb(Some(true)) + .build( + window.raw_window_handle(), + NonZeroU32::new(1024).unwrap(), + NonZeroU32::new(768).unwrap(), + ); + + let surface = unsafe { + cfg.display() + .create_window_surface(&cfg, &surface_attributes) + .unwrap() + }; + + let context = context.make_current(&surface).unwrap(); + + (event_loop, window, surface, context) +} + +fn glow_context(context: &PossiblyCurrentContext) -> glow::Context { + unsafe { + glow::Context::from_loader_function_cstr(|s| context.display().get_proc_address(s).cast()) + } +} + +fn imgui_init(window: &Window) -> (WinitPlatform, imgui::Context) { + let mut imgui_context = imgui::Context::create(); + 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, + ); + + imgui_context + .fonts() + .add_font(&[imgui::FontSource::DefaultFontData { config: None }]); + + imgui_context.io_mut().font_global_scale = (1.0 / winit_platform.hidpi_factor()) as f32; + + (winit_platform, imgui_context) +} diff --git a/src/utils/mod.rs b/src/utils/mod.rs new file mode 100644 index 0000000..c15fa30 --- /dev/null +++ b/src/utils/mod.rs @@ -0,0 +1,239 @@ +mod parser; +use include_dir::{include_dir, Dir}; +pub use parser::*; +use std::{num::NonZeroU32, path::Path}; + +use glow::HasContext; +use glutin::{ + config::ConfigTemplateBuilder, + context::{ContextApi, ContextAttributesBuilder, NotCurrentGlContext, PossiblyCurrentContext}, + display::{GetGlDisplay, GlDisplay}, + surface::{GlSurface, Surface, SurfaceAttributesBuilder, SwapInterval, WindowSurface}, +}; +use imgui_winit_support::WinitPlatform; +use raw_window_handle::HasRawWindowHandle; + +use winit::{ + dpi::LogicalSize, + event_loop::EventLoop, + window::{Window, WindowBuilder}, +}; + +static SHADERS: Dir = include_dir!("$CARGO_MANIFEST_DIR/shaders"); + +pub fn create_window( + title: &str, + context_api: Option, +) -> ( + EventLoop<()>, + Window, + Surface, + PossiblyCurrentContext, +) { + let event_loop = EventLoop::new().unwrap(); + + let window_builder = WindowBuilder::new() + .with_title(title) + .with_inner_size(LogicalSize::new(1024, 768)); + let (window, cfg) = glutin_winit::DisplayBuilder::new() + .with_window_builder(Some(window_builder)) + .build(&event_loop, ConfigTemplateBuilder::new(), |mut configs| { + configs.next().unwrap() + }) + .expect("Failed to create OpenGL window"); + + let window = window.unwrap(); + + let mut context_attribs = ContextAttributesBuilder::new(); + if let Some(context_api) = context_api { + context_attribs = context_attribs.with_context_api(context_api); + } + let context_attribs = context_attribs.build(Some(window.raw_window_handle())); + let context = unsafe { + cfg.display() + .create_context(&cfg, &context_attribs) + .expect("Failed to create OpenGL context") + }; + + let surface_attribs = SurfaceAttributesBuilder::::new() + .with_srgb(Some(true)) + .build( + window.raw_window_handle(), + NonZeroU32::new(1024).unwrap(), + NonZeroU32::new(768).unwrap(), + ); + let surface = unsafe { + cfg.display() + .create_window_surface(&cfg, &surface_attribs) + .expect("Failed to create OpenGL surface") + }; + + let context = context + .make_current(&surface) + .expect("Failed to make OpenGL context current"); + + surface + .set_swap_interval(&context, SwapInterval::Wait(NonZeroU32::new(1).unwrap())) + .expect("Failed to set swap interval"); + + (event_loop, window, surface, context) +} + +pub fn glow_context(context: &PossiblyCurrentContext) -> glow::Context { + unsafe { + glow::Context::from_loader_function_cstr(|s| context.display().get_proc_address(s).cast()) + } +} + +pub fn imgui_init(window: &Window) -> (WinitPlatform, imgui::Context) { + let mut imgui_context = imgui::Context::create(); + 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, + ); + + imgui_context + .fonts() + .add_font(&[imgui::FontSource::DefaultFontData { config: None }]); + + imgui_context.io_mut().font_global_scale = (1.0 / winit_platform.hidpi_factor()) as f32; + + (winit_platform, imgui_context) +} + +pub fn find_file>(filename: P) -> Option { + let path = SHADERS.get_file(filename.as_ref()); + + path.map(|p| p.contents_utf8()) + .flatten() + .map(|s| s.to_string()) +} + +pub struct Triangler { + pub program: ::Program, + pub vertex_array: ::VertexArray, +} + +impl Triangler { + pub fn new(gl: &glow::Context, shader_header: &str) -> Self { + const VERTEX_SHADER_SOURCE: &str = r#" + + 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 = projection * view * vec4(vert - 0.5, 0.0, 1.0); + } + "#; + const FRAGMENT_SHADER_SOURCE: &str = r#" + 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); + } + "#; + + let mut shaders = [ + (glow::VERTEX_SHADER, VERTEX_SHADER_SOURCE, None), + (glow::FRAGMENT_SHADER, FRAGMENT_SHADER_SOURCE, None), + ]; + + unsafe { + let vertex_array = gl + .create_vertex_array() + .expect("Cannot create vertex array"); + + let program = gl.create_program().expect("Cannot create program"); + + for (kind, source, handle) in &mut shaders { + let shader = gl.create_shader(*kind).expect("Cannot create shader"); + gl.shader_source(shader, &format!("{}\n{}", shader_header, *source)); + gl.compile_shader(shader); + if !gl.get_shader_compile_status(shader) { + panic!("{}", gl.get_shader_info_log(shader)); + } + gl.attach_shader(program, shader); + *handle = Some(shader); + } + + gl.link_program(program); + if !gl.get_program_link_status(program) { + panic!("{}", gl.get_program_info_log(program)); + } + + gl.get_uniform_location(program, "u_resolution"); + + for &(_, _, shader) in &shaders { + gl.detach_shader(program, shader.unwrap()); + gl.delete_shader(shader.unwrap()); + } + + Self { + program, + vertex_array, + } + } + } + + 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(Some(self.program)); + gl.bind_vertex_array(Some(self.vertex_array)); + gl.draw_arrays(glow::TRIANGLES, 0, 3); + } + } + + pub fn destroy(&self, gl: &glow::Context) { + unsafe { + gl.delete_program(self.program); + gl.delete_vertex_array(self.vertex_array); + } + } + + pub fn program(&self) -> ::Program { + self.program + } +} diff --git a/src/utils/parser.rs b/src/utils/parser.rs new file mode 100644 index 0000000..5b35f35 --- /dev/null +++ b/src/utils/parser.rs @@ -0,0 +1,1803 @@ +use nalgebra_glm::exp; +use once_cell::sync::Lazy; +use regex::Regex; +use std::{ + cell::RefCell, + collections::{HashMap, HashSet}, + env::var_os, + fmt::{write, Display}, + hash::{Hash, Hasher}, + rc::Rc, +}; + +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, + }, + 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, +}; + +use crate::{components::Snippet, errors::*}; + +static SINGLE_COMMENT_RE: Lazy = Lazy::new(|| Regex::new(r#"//.*"#).unwrap()); +static MULTI_COMMENT_RE: Lazy = Lazy::new(|| Regex::new(r#"/\*[\s\S]*?\*/"#).unwrap()); + +static VERSION_RE: Lazy = Lazy::new(|| Regex::new(r#"#version\s+\d+(\s+.+)?"#).unwrap()); + +type RFC = Rc>; + +const KEEP_WORDS: [&str; 80] = [ + "#version", + "#define", + "#include", + "layout", + "in", + "out", + "uniform", + "const", + "static", + "extern", + "if", + "else", + "while", + "do", + "for", + "+", + "-", + "*", + "/", + "!", + "<", + ">", + "=", + "(", + ")", + "{", + "}", + "[", + "]", + "void", + "return", + "vec4", + "float", + "int", + "bool", + "true", + "false", + "struct", + "main", + "vec3", + "vec2", + "mat4", + "mat3", + "mat2", + "sampler2D", + "samplerCube", + "sampler2DShadow", + "samplerCubeShadow", + "sampler2DArray", + "sampler2DArrayShadow", + "sampler3D", + "sampler2DMS", + "sampler2DMSArray", + "samplerBuffer", + "sampler2DRect", + "sampler1D", + "sampler1DShadow", + "sampler1DArray", + "sampler1DArrayShadow", + "sampler2DRectShadow", + "sampler1DArray", + "sampler1DArrayShadow", + "sampler2DRectShadow", + "sampler1DArray", + "sampler1DArrayShadow", + "sampler2DRectShadow", + "sampler1DArray", + "sampler1DArrayShadow", + "sampler2DRectShadow", + "sampler1DArray", + "sampler1DArrayShadow", + "sampler2DRectShadow", + "sampler1DArray", + "sampler1DArrayShadow", + "sampler2DRectShadow", + "sampler1DArray", + "sampler1DArrayShadow", + "sampler2DRectShadow", + "sampler1DArray", + "sampler1DArrayShadow", +]; + +#[derive(Debug, Clone)] +pub struct Include { + pub path: String, +} + +impl Display for Include { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "#include \"{}\"", self.path) + } +} + +fn include(input: &str) -> IResult<&str, Include> { + let (input, _) = tag("#include")(input)?; + let (input, _) = space1(input)?; + let (input, path) = delimited(char('"'), take_while(|c| c != '"'), char('"'))(input)?; + Ok(( + input, + Include { + path: path.to_string(), + }, + )) +} + +#[derive(Debug, Clone)] +pub enum Modifier { + Const, + Static, + Extern, + Uniform, + In(Option), + Out, +} + +impl Display for Modifier { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Modifier::Const => write!(f, "const"), + 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::Out => write!(f, "out"), + } + } +} + +fn modifier(input: &str) -> IResult<&str, Modifier> { + alt(( + map_res(tag("const"), |_| { + Ok::>(Modifier::Const) + }), + map_res(tag("static"), |_| { + Ok::>(Modifier::Static) + }), + map_res(tag("extern"), |_| { + Ok::>(Modifier::Extern) + }), + map_res(tag("uniform"), |_| { + 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)) + }, + ), + map_res(tag("out"), |_| { + Ok::>(Modifier::Out) + }), + ))(input) +} + +#[derive(Debug, Clone)] +pub struct ShareVariable { + pub modif: Vec, + pub typ: String, + pub name: String, + + pub value: Option, +} + +impl Display for ShareVariable { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!( + f, + "{} {} {}{}", + self.modif + .iter() + .map(|v| format!("{}", v)) + .collect::(), + self.typ, + self.name, + self.value + .as_ref() + .map(|v| format!(" = {}", v)) + .unwrap_or("".to_string()) + ) + } +} + +fn _share_variable(input: &str) -> IResult<&str, ShareVariable> { + let (input, modifier) = many0(modifier)(input)?; + let (input, _) = multispace1(input)?; + let (input, typ) = type_name(input)?; + let (input, _) = multispace1(input)?; + let (input, name) = identifier(input)?; + + let (input, value) = opt(preceded( + ws(char('=')), + ws(take_till(|c| c == ';' || c == '\n')), + ))(input)?; + Ok(( + input, + ShareVariable { + modif: modifier, + typ: typ.to_string(), + name: name.to_string(), + value: value.map(|v| v.to_string()), + }, + )) +} + +#[derive(Debug, PartialEq, Clone, Eq, Hash)] +pub enum PreprocessorDirective { + IfDef { condition: String }, + IfNDef { condition: String }, + EndIf, + Macro { name: String, value: Option }, +} + +impl Display for PreprocessorDirective { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + PreprocessorDirective::IfDef { condition } => write!(f, "#ifdef {}", condition), + PreprocessorDirective::IfNDef { condition } => write!(f, "#ifndef {}", condition), + PreprocessorDirective::EndIf => write!(f, "#endif"), + PreprocessorDirective::Macro { name, value } => { + if let Some(v) = value { + write!(f, "#define {} {}", name, v) + } else { + write!(f, "#define {}", name) + } + } + } + } +} + +fn parse_ifdef(input: &str) -> IResult<&str, PreprocessorDirective> { + let (input, v) = map( + preceded(pair(tag("#ifdef"), multispace1), identifier), + |condition| PreprocessorDirective::IfDef { + condition: condition.to_string(), + }, + )(input)?; + Ok((input, v)) +} + +fn parse_ifndef(input: &str) -> IResult<&str, PreprocessorDirective> { + map( + preceded(tuple((tag("#ifndef"), space1)), identifier), + |condition| PreprocessorDirective::IfNDef { + condition: condition.to_string(), + }, + )(input) +} + +fn parse_endif(input: &str) -> IResult<&str, PreprocessorDirective> { + map(ws(tag("#endif")), |_| PreprocessorDirective::EndIf)(input) +} + +fn parse_multiline_macro(input: &str) -> IResult<&str, &str> { + alt(( + recognize(pair( + terminated(take_till(|c| c == '\\'), tag("\\\n")), + parse_multiline_macro, + )), + terminated(take_till(|c: char| c == '\n'), char('\n')), + ))(input) +} + +fn parse_macro(input: &str) -> IResult<&str, PreprocessorDirective> { + let (input, (name, value)) = tuple(( + preceded(pair(tag("#define"), space1), identifier), + opt(preceded(space1, parse_multiline_macro)), + ))(input)?; + + Ok(( + input, + PreprocessorDirective::Macro { + name: name.to_string(), + value: value.map(|v| v.to_string()), + }, + )) +} + +#[derive(Debug, Clone)] +pub struct Function { + pub return_type: String, + pub name: String, + pub parameters: Vec<(String, String)>, + pub body: Statement, +} + +impl Display for Function { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{} {}(", self.return_type, self.name)?; + for (i, (typ, name)) in self.parameters.iter().enumerate() { + if i > 0 { + write!(f, ", ")?; + } + write!(f, "{} {}", typ, name)?; + } + write!(f, ") ")?; + + self.body.fmt_with_indent(f, 4)?; + + write!(f, "\n") + + // write!(f, ") {} \n ", self.body) + } +} + +// Helper function to parse identifiers (function names, variable names, etc.) +fn identifier(input: &str) -> IResult<&str, &str> { + recognize(pair( + take_while1(|c: char| c.is_alphabetic() || c == '_'), + many0_count(take_while1(|c: char| c.is_alphanumeric() || c == '_')), + ))(input) +} + +// Helper function to parse types (e.g., "int", "float") +fn type_name(input: &str) -> IResult<&str, &str> { + identifier(input) +} + +// Parse a single function parameter (e.g., "int a") +fn parameter(input: &str) -> IResult<&str, (String, String)> { + let (input, (typ, _, name)) = tuple((type_name, multispace0, identifier))(input)?; + Ok((input, (typ.to_string(), name.to_string()))) +} + +// Parse the parameter list of a function +fn parameters(input: &str) -> IResult<&str, Vec<(String, String)>> { + delimited( + char('('), + separated_list0(delimited(multispace0, char(','), multispace0), parameter), + char(')'), + )(input) +} + +// Parse the body of a function +fn function_body(input: &str) -> IResult<&str, Statement> { + let (input, body) = + delimited(char('{'), many0(_statement), pair(multispace0, char('}')))(input)?; + + Ok(( + input, + Statement::Block(body.into_iter().map(|v| Box::new(v)).collect()), + )) +} + +// Parse the entire function +pub fn function(input: &str) -> IResult<&str, Function> { + let (input, (return_type, _, name, _, params, _, body)) = tuple(( + type_name, + multispace0, + identifier, + multispace0, + parameters, + multispace0, + function_body, + ))(input)?; + + // println!("{}", body); + + Ok(( + input, + Function { + return_type: return_type.to_string(), + name: name.to_string(), + parameters: params, + body, + }, + )) +} + +fn skip(input: &str) -> IResult<&str, &str> { + let (input, a) = multispace0(input)?; + Ok((input, a)) +} + +pub fn ws<'a, F: 'a, O>(inner: F) -> impl FnMut(&'a str) -> IResult<&'a str, O> +where + F: FnMut(&'a str) -> IResult<&'a str, O>, +{ + preceded(skip, inner) +} + +#[derive(Debug, Clone, Hash, PartialEq, Eq)] +pub struct Hook { + pub name: String, + pub subhooks: Vec, + pub parameters: Option>, +} + +fn hook(input: &str) -> IResult<&str, Hook> { + map( + delimited( + char('<'), + pair( + separated_list1(char('.'), identifier), + opt(delimited( + char('('), + separated_list0(ws(char(',')), ws(identifier)), + char(')'), + )), + ), + char('>'), + ), + |(names, paras)| Hook { + name: names[0].to_string(), + subhooks: names[1..].iter().map(|v| v.to_string()).collect(), + parameters: paras.map(|v| v.iter().map(|v| v.to_string()).collect()), + }, + )(input) +} + +impl Display for Hook { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "<{}", self.name)?; + for sub in self.subhooks.iter() { + write!(f, ".{}", sub)?; + } + + if !self.parameters.is_none() { + write!(f, "(")?; + let para = self.parameters.as_ref().unwrap().join(","); + write!(f, "{}", para)?; + write!(f, ")")?; + } + + write!(f, ">") + } +} + +#[derive(Debug, Clone)] +pub enum Code { + Struct(Rc>), + Include(Rc>), + Function(Rc>), + PreprocessorDirective(Rc>, Box>), + Macro(Rc>), + ShareVariable(Rc>), +} + +#[derive(Debug, Clone)] +pub enum Statement { + Declaration { + name: String, + typ: String, + value: Option, + }, + Block(Vec>), + If { + condition: Expression, + block: Box, + }, + + Else { + block: Box, + }, + + While { + condition: Expression, + block: Box, + }, + + For { + condition: Expression, + block: Box, + }, + DoWhile { + block: Box, + condition: Expression, + }, + + Break, + Continue, + + // Hook(Hook), + Expression(Expression), + + Discard, + + Return(Option), +} + +impl Statement { + fn fmt_with_indent(&self, f: &mut std::fmt::Formatter<'_>, indent: usize) -> std::fmt::Result { + let indent_str = " ".repeat(indent); + match self { + Statement::Block(statements) => { + writeln!(f, "{{")?; + for statement in statements { + statement.fmt_with_indent(f, indent + 4)?; + } + writeln!(f, "}}") + } + Statement::While { condition, block } => { + writeln!(f, "{}while ({})", indent_str, condition)?; + block.fmt_with_indent(f, indent + 4) + } + Statement::DoWhile { block, condition } => { + writeln!(f, "{}do", indent_str)?; + block.fmt_with_indent(f, indent + 4)?; + writeln!(f, "{}while ({});", indent_str, condition) + } + Statement::If { condition, block } => { + writeln!(f, "{}if ({})", indent_str, condition)?; + block.fmt_with_indent(f, indent + 4) + } + Statement::Else { block } => { + if let Statement::If { condition, block } = &(**block) { + writeln!(f, "{}else if ({}) ", indent_str, condition)?; + + block.fmt_with_indent(f, indent + 4) + } else { + writeln!(f, "{}else ", indent_str)?; + + block.fmt_with_indent(f, indent + 4) + } + } + Statement::For { condition, block } => { + writeln!(f, "{}for ({})", indent_str, condition)?; + block.fmt_with_indent(f, indent + 4) + } + Statement::Expression(expr) => { + writeln!(f, "{}{};", indent_str, expr) + } + + Statement::Discard => { + writeln!(f, "{}discard;", indent_str) + } + + Statement::Declaration { name, typ, value } => { + writeln!( + f, + "{}{} {}{};", + indent_str, + typ, + name, + value + .as_ref() + .map_or("".to_string(), |v| format!(" = {}", v)) + ) + } + Statement::Return(expr) => { + if let Some(exp) = expr { + writeln!(f, "{}return {};", indent_str, exp) + } else { + writeln!(f, "{}return;", indent_str) + } + } + + Statement::Break => { + writeln!(f, "{}break;", indent_str) + } + + Statement::Continue => { + writeln!(f, "{}continue;", indent_str) + } + } + } +} + +impl Display for Statement { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Statement::Declaration { name, typ, value } => { + write!( + f, + "{} {}{};", + typ, + name, + value + .as_ref() + .map_or("".to_string(), |v| format!(" = {}", v)) + ) + } + Statement::Block(v) => { + write!(f, "{{\n")?; + for statement in v.iter() { + write!(f, "{}\n", statement)?; + } + write!(f, "}}")?; + Ok(()) + } + Statement::If { condition, block } => { + write!(f, "if ({}) {}", condition, block) + } + Statement::Else { block } => { + if let Statement::If { condition, block } = &(**block) { + write!(f, "else if ({}) {}", condition, block) + } else { + write!(f, "else {}", block) + } + } + Statement::While { condition, block } => { + write!(f, "while ({}) {}", condition, block) + } + Statement::For { condition, block } => { + write!(f, "for ({}) {}", condition, block) + } + Statement::DoWhile { block, condition } => { + write!(f, "do {}\n while ({})", block, condition) + } + + // Statement::Hook(hook) => write!(f, "{}", hook), + Statement::Expression(v) => write!(f, "{};", v), + + Statement::Return(v) => { + if let Some(exp) = v { + write!(f, "return {};", exp) + } else { + write!(f, "return;",) + } + } + + Statement::Discard => write!(f, "discard;"), + + Statement::Break => write!(f, "break;"), + Statement::Continue => write!(f, "continue;"), + } + } +} + +#[derive(Debug, Clone)] +pub enum Expression { + Binary { + left: Box, + right: Box, + operator: String, + }, + Unary { + right: Box, + operator: String, + left_or_right: bool, + }, + Variable(String), + Literal(Literal), + FunctionCall { + name: String, + parameters: Vec, + }, + Assignment { + left: Box, + right: Box, + }, + StructMemberAccess { + base: Box, + member: String, + }, + StructPointerAccess { + base: Box, + member: String, + }, + + Hook(Hook), +} + +impl Display for Expression { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Expression::Binary { + left, + right, + operator, + } => { + if operator == "+" { + write!(f, "({} {} {})", left, operator, right) + } else { + write!(f, "{} {} {}", left, operator, right) + } + } + Expression::Unary { + right, + operator, + left_or_right, + } => { + if *left_or_right { + write!(f, "{}{}", operator, right) + } else { + write!(f, "{}{}", right, operator) + } + } + Expression::Variable(v) => write!(f, "{}", v), + Expression::Literal(v) => write!(f, "{}", v), + Expression::FunctionCall { name, parameters } => { + write!(f, "{}(", name)?; + for (i, param) in parameters.iter().enumerate() { + if i > 0 { + write!(f, ", ")?; + } + write!(f, "{}", param)?; + } + write!(f, ")") + } + + Expression::Assignment { left, right } => write!(f, "{} = {}", left, right), + Expression::Hook(hook) => write!(f, "{}", hook), + Expression::StructMemberAccess { base, member } => write!(f, "{}.{}", base, member), + Expression::StructPointerAccess { base, member } => write!(f, "{}->{}", base, member), + } + } +} + +#[derive(Debug, PartialEq, Clone)] +pub enum Literal { + Integer(i64), + Float(f64, usize), + String(String), + Char(char), +} + +impl Display for Literal { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Literal::Integer(v) => write!(f, "{}", v), + Literal::Float(v, presicion) => { + let r = format!("{:.*}", presicion, v); + write!(f, "{}", r) + } + Literal::String(v) => write!(f, "\"{}\"", v), + Literal::Char(v) => write!(f, "'{}'", v), + } + } +} + +fn parse_integer(input: &str) -> IResult<&str, Literal> { + map_res(recognize(digit1), |s: &str| { + s.parse::().map(Literal::Integer) + })(input) +} + +fn parse_float(input: &str) -> IResult<&str, Literal> { + map_res( + recognize(tuple(( + digit1, + char('.'), + digit1, + opt(pair(alt((char('e'), char('E'))), opt(char('-')))), + opt(digit1), + ))), + |s: &str| { + s.parse::() + .map(|v| Literal::Float(v, s.split('.').last().unwrap().len())) + }, + )(input) +} + +fn parse_string(input: &str) -> IResult<&str, Literal> { + map( + delimited(char('"'), take_until("\""), char('"')), + |s: &str| Literal::String(s.to_string()), + )(input) +} + +fn parse_char(input: &str) -> IResult<&str, Literal> { + map( + delimited(char('\''), none_of("'"), char('\'')), + |c: char| Literal::Char(c), + )(input) +} + +fn parse_literal(input: &str) -> IResult<&str, Literal> { + alt((parse_float, parse_integer, parse_string, parse_char))(input) +} + +fn parse_assignment(input: &str) -> IResult<&str, Expression> { + let (input, left) = alt(( + parse_struct_member_access, + parse_struct_pointer_access, + parse_variable, + ))(input)?; + let (input, _) = space0(input)?; + let (input, _) = char('=')(input)?; + let (input, _) = space0(input)?; + let (input, right) = expression(input)?; + Ok(( + input, + Expression::Assignment { + left: Box::new(left), + right: Box::new(right), + }, + )) +} + +fn parse_unary(input: &str) -> IResult<&str, Expression> { + let left = alt((char('-'), char('+'), char('!'))); + + alt(( + map(pair(left, parse_factor), |(left, fac)| Expression::Unary { + right: Box::new(fac), + operator: left.to_string(), + left_or_right: true, + }), + map( + pair(alt((tag("++"), tag("--"))), parse_variable), + |(t, fac)| Expression::Unary { + right: Box::new(fac), + operator: t.to_string(), + left_or_right: true, + }, + ), + map( + pair(parse_variable, alt((tag("++"), tag("--")))), + |(fac, right)| Expression::Unary { + right: Box::new(fac), + operator: right.to_string(), + left_or_right: false, + }, + ), + ))(input) +} + +fn parse_term(input: &str) -> IResult<&str, Expression> { + let (input, init) = parse_factor(input)?; + fold_many0( + pair(alt((tag("*"), tag("/"))), parse_factor), + move || init.clone(), + |acc, (op, val): (&str, Expression)| Expression::Binary { + left: Box::new(acc), + operator: op.to_string(), + right: Box::new(val), + }, + )(input) +} + +fn parse_arith(input: &str) -> IResult<&str, Expression> { + let (input, init) = parse_term(input)?; + fold_many0( + pair(alt((tag("+"), tag("-"))), parse_term), + move || init.clone(), + |acc, (op, val): (&str, Expression)| Expression::Binary { + left: Box::new(acc), + operator: op.to_string(), + right: Box::new(val), + }, + )(input) +} + +fn parse_factor(input: &str) -> IResult<&str, Expression> { + delimited( + multispace0, + alt(( + delimited(char('('), expression, char(')')), + parse_struct_pointer_access, + parse_struct_member_access, + parse_unary, + parse_function_call, + parse_assignment, + map(parse_literal, |l| Expression::Literal(l)), + map(identifier, |i| Expression::Variable(i.to_string())), + map(hook, |hook| Expression::Hook(hook)), + )), + multispace0, + )(input) +} + +fn parse_comparison(input: &str) -> IResult<&str, Expression> { + let (input, init) = parse_arith(input)?; + fold_many0( + pair( + alt(( + tag("=="), + tag("!="), + tag("<="), + tag(">="), + tag("<"), + tag(">"), + )), + parse_arith, + ), + move || init.clone(), + |acc, (op, val): (&str, Expression)| Expression::Binary { + left: Box::new(acc), + operator: op.to_string(), + right: Box::new(val), + }, + )(input) +} + +fn parse_logical(input: &str) -> IResult<&str, Expression> { + let (input, init) = parse_comparison(input)?; + fold_many0( + pair(alt((tag("&&"), tag("||"))), parse_comparison), + move || init.clone(), + |acc, (op, val): (&str, Expression)| Expression::Binary { + left: Box::new(acc), + operator: op.to_string(), + right: Box::new(val), + }, + )(input) +} + +fn parse_variable(input: &str) -> IResult<&str, Expression> { + map(identifier, |v: &str| Expression::Variable(v.to_owned()))(input) +} + +fn parse_function_call(input: &str) -> IResult<&str, Expression> { + let (input, name) = identifier(input)?; + let (input, args) = delimited( + char('('), + separated_list0(delimited(multispace0, char(','), multispace0), expression), + cut(char(')')), + )(input)?; + Ok(( + input, + Expression::FunctionCall { + name: name.to_string(), + parameters: args, + }, + )) +} + +fn parse_struct_member_access(input: &str) -> IResult<&str, Expression> { + map( + separated_pair( + alt(( + map(hook, Expression::Hook), + map(identifier, |v| Expression::Variable(v.to_string())), + )), + char('.'), + identifier, + ), + |(base, member)| Expression::StructMemberAccess { + base: Box::new(base), + member: member.to_string(), + }, + )(input) +} + +fn parse_struct_pointer_access(input: &str) -> IResult<&str, Expression> { + map( + separated_pair( + alt(( + map(hook, Expression::Hook), + map(identifier, |v| Expression::Variable(v.to_string())), + )), + tag("->"), + identifier, + ), + |(base, member)| Expression::StructPointerAccess { + base: Box::new(base), + member: member.to_string(), + }, + )(input) +} + +fn expression(input: &str) -> IResult<&str, Expression> { + parse_logical(input) +} + +fn _condition(input: &str) -> IResult<&str, Expression> { + let (input, exp) = expression(input)?; + Ok((input, exp)) +} + +fn _statement(input: &str) -> IResult<&str, Statement> { + ws(alt(( + map( + delimited(char('{'), many0(_statement), pair(multispace0, char('}'))), + |statements| Statement::Block(statements.into_iter().map(|v| Box::new(v)).collect()), + ), + map( + preceded(tag("while"), pair(_condition, _statement)), + |(cond, statement)| Statement::While { + condition: cond, + block: Box::new(statement), + }, + ), + map( + preceded( + pair(tag("do"), space0), + tuple(( + _statement, + preceded(space0, tag("while")), + space0, + _condition, + )), + ), + |(block, _, _, condition)| Statement::DoWhile { + block: Box::new(block), + condition: condition, + }, + ), + map( + preceded(tag("if"), pair(_condition, _statement)), + |(cond, state)| Statement::If { + condition: cond, + block: Box::new(state), + }, + ), + map(preceded(tag("else"), _statement), |state| Statement::Else { + block: Box::new(state), + }), + map( + preceded(tag("for"), pair(_condition, _statement)), + |(cond, state)| Statement::For { + condition: cond, + block: Box::new(state), + }, + ), + map( + delimited(pair(tag("return"), multispace0), opt(expression), char(';')), + |e| Statement::Return(e), + ), + map(terminated(tag("discard"), pair(space0, char(';'))), |_| { + Statement::Discard + }), + map(terminated(tag("break"), pair(space0, char(';'))), |_| { + Statement::Break + }), + map(terminated(tag("continue"), pair(space0, char(';'))), |_| { + Statement::Continue + }), + map(terminated(hook, pair(multispace0, char(';'))), |hook| { + Statement::Expression(Expression::Hook(hook)) + }), + map(terminated(parse_assignment, char(';')), |v| { + Statement::Expression(v) + }), + map(terminated(parse_function_call, char(';')), |v| { + Statement::Expression(v) + }), + map( + terminated( + tuple(( + type_name, + space1, + identifier, + space0, + opt(tuple((char('='), space0, expression))), + )), + char(';'), + ), + |(typ, _, name, _, v)| Statement::Declaration { + name: name.to_string(), + typ: typ.to_string(), + value: v.map(|v| v.2), + }, + ), + )))(input) +} + +#[derive(Debug, Clone)] +struct Struct { + name: String, + members: Vec<(String, String)>, +} + +impl Display for Struct { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "struct {} {{\n", self.name)?; + for (typ, name) in self.members.iter() { + write!(f, " {} {};\n", typ, name)?; + } + write!(f, "}};") + } +} + +fn parse_struct(input: &str) -> IResult<&str, Struct> { + let (input, _) = tag("struct")(input)?; + let (input, _) = space1(input)?; + let (input, name) = identifier(input)?; + let (input, body) = delimited( + pair(multispace0, char('{')), + many0(ws(tuple(( + type_name, + space1, + identifier, + space0, + char(';'), + )))), + pair(multispace0, char('}')), + )(input)?; + Ok(( + input, + Struct { + name: name.to_string(), + members: body + .into_iter() + .map(|(typ, _, name, _, _)| (typ.to_string(), name.to_string())) + .collect(), + }, + )) +} + +impl Display for Code { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Code::Struct(v) => write!(f, "{}", *v.borrow()), + Code::Include(v) => write!(f, "{}", *v.borrow()), + Code::Function(v) => write!(f, "{}", *v.borrow()), + Code::PreprocessorDirective(v, c) => { + write!(f, "{}\n", *v.borrow())?; + for code in c.iter() { + write!(f, "{}\n", code)?; + } + write!(f, "\n{}", PreprocessorDirective::EndIf)?; + Ok(()) + } + Code::Macro(v) => write!(f, "{}", *v.borrow()), + Code::ShareVariable(v) => write!(f, "{};", *v.borrow()), + } + } +} + +#[derive(Debug, Clone)] +pub struct SnippetCode { + pub includes: Vec>, + pub variables: Vec>, + pub functions: Vec>, + pub preprocessor_directives: HashMap>, +} + +#[derive(Debug, Clone)] +pub struct SnippetPreprocessorKey(pub RFC); + +impl PartialEq for SnippetPreprocessorKey { + fn eq(&self, other: &Self) -> bool { + self.0.borrow().eq(&*other.0.borrow()) + } +} + +impl Eq for SnippetPreprocessorKey {} + +impl Hash for SnippetPreprocessorKey { + fn hash(&self, state: &mut H) { + self.0.borrow().hash(state) + } +} + +impl From> for SnippetPreprocessorKey { + fn from(v: RFC) -> Self { + SnippetPreprocessorKey(v) + } +} + +#[derive(Debug, Clone)] +pub struct CodeBlock { + pub codes: Vec, + pub snippet: SnippetCode, +} + +impl Display for CodeBlock { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + for code in self.codes.iter() { + write!(f, "{}\n\n", code)?; + } + Ok(()) + } +} + +impl CodeBlock { + pub fn new(input: &str) -> Result { + let clean = SINGLE_COMMENT_RE.replace_all(input, ""); + let clean = MULTI_COMMENT_RE.replace_all(&clean, ""); + let clean = VERSION_RE.replace_all(&clean, ""); + + let (_, codes) = Self::_parse(&clean) + .map_err(|e| crate::errors::Error::InvalidSnippet(format!("{:?}", e)))?; + + let snippets = SnippetCode::new(&codes)?; + + Ok(CodeBlock { + codes: codes, + snippet: snippets, + }) + } + + 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) + } + + pub fn public_variables(&self) -> Vec<&RFC> { + self.snippet.variables.iter().collect() + } + + pub fn public_functions(&self) -> Vec<&RFC> { + self.snippet.functions.iter().collect() + } + + pub fn public_includes(&self) -> Vec<&RFC> { + self.snippet.includes.iter().collect() + } + + pub fn preprocessor_directives(&self) -> Vec<&SnippetPreprocessorKey> { + self.snippet.preprocessor_directives.keys().collect() + } + + pub fn all_variables(&self) -> Vec<&RFC> { + self.snippet.all_variables() + } + + pub fn all_functions(&self) -> Vec<&RFC> { + self.snippet.all_functions() + } + + pub fn all_includes(&self) -> Vec<&RFC> { + self.snippet.all_includes() + } + + pub fn rename(&mut self, old: &str, new: &str) { + for code in self.codes.iter_mut() { + match code { + Code::ShareVariable(v) => { + if v.borrow().name == old { + v.borrow_mut().name = new.to_string(); + } + } + + Code::Function(v) => { + if v.borrow().name == old { + v.borrow_mut().name = new.to_string(); + } + } + _ => {} + } + } + } + + pub fn mangling>(&mut self, suffix: S) -> HashMap { + let mut map = HashMap::new(); + fn _mangling(codes: &mut Vec, suffix: &str, map: &mut HashMap) { + for code in codes.iter_mut() { + match code { + Code::Function(v) => { + let raw_name = v.borrow().name.clone(); + let new_name = format!("{}_{}", raw_name, suffix); + + v.borrow_mut().name = new_name.clone(); + map.insert(raw_name, new_name); + } + Code::ShareVariable(v) => { + let raw_name = v.borrow().name.clone(); + let new_name = format!("{}_{}", raw_name, suffix); + + v.borrow_mut().name = new_name.clone(); + map.insert(raw_name, new_name); + } + + Code::PreprocessorDirective(_, c) => { + _mangling(&mut (*c), suffix, map); + } + _ => {} + } + } + } + + _mangling(&mut self.codes, suffix.as_ref(), &mut map); + + map + } + + pub fn all_hooks(&self) -> HashSet { + self.snippet.all_hooks() + } + + pub fn set_hook(&mut self, old: &str, code: &Snippet) { + if self.snippet.set_hook(old, code) { + let prepare_code = code.prepare_code(); + + let clean = SINGLE_COMMENT_RE.replace_all(prepare_code, ""); + let clean = MULTI_COMMENT_RE.replace_all(&clean, ""); + let clean = VERSION_RE.replace_all(&clean, ""); + + let (_, mut prepare_code) = Self::_parse(&clean).unwrap(); + + let old = std::mem::replace(&mut self.codes, vec![]); + prepare_code.extend(old); + + self.codes = prepare_code; + } + } + + pub fn find_variable(&self, name: &str) -> Option<&RFC> { + self.snippet.find_variable(name) + } +} + +impl SnippetCode { + pub fn new(codes: &Vec) -> Result { + Self::check(codes) + } + + pub fn update(&mut self, codes: &Vec) -> Result<()> { + let new = Self::check(codes)?; + self.includes.extend(new.includes); + self.variables.extend(new.variables); + self.functions.extend(new.functions); + + Ok(()) + } + + fn check(codes: &Vec) -> Result { + let includes = codes + .iter() + .filter_map(|v| match v { + Code::Include(v) => Some(v.clone()), + _ => None, + }) + .collect(); + + let variables = codes + .iter() + .filter_map(|v| match v { + Code::ShareVariable(v) => Some(v.clone()), + _ => None, + }) + .collect(); + + let functions = codes + .iter() + .filter_map(|v| match v { + Code::Function(v) => Some(v.clone()), + _ => None, + }) + .collect(); + + let mut preprocessor_directives = vec![]; + + for code in codes.into_iter() { + match code { + Code::PreprocessorDirective(p, v) => { + let c = Self::check(v)?; + + preprocessor_directives.push((p.clone().into(), Box::new(c))); + } + _ => {} + } + } + + Ok(SnippetCode { + includes: includes, + variables: variables, + functions: functions, + preprocessor_directives: preprocessor_directives.into_iter().collect(), + }) + } + + fn all_variables(&self) -> Vec<&RFC> { + let mut result = vec![]; + + for v in self.variables.iter() { + result.push(v); + } + + for (_, v) in self.preprocessor_directives.iter() { + result.extend(v.all_variables()); + } + + result + } + + fn all_functions(&self) -> Vec<&RFC> { + let mut result = vec![]; + + for v in self.functions.iter() { + result.push(v); + } + + for (_, v) in self.preprocessor_directives.iter() { + result.extend(v.all_functions()); + } + + result + } + + fn all_includes(&self) -> Vec<&RFC> { + let mut result = vec![]; + + for v in self.includes.iter() { + result.push(v); + } + + for (_, v) in self.preprocessor_directives.iter() { + result.extend(v.all_includes()); + } + + result + } + + fn _hook<'b, 'a: 'b>(stat: &'a Box, res: &'b mut HashSet) { + match stat.as_ref() { + Statement::Block(body) => { + for statement in body.iter() { + Self::_hook(statement, res); + } + } + + Statement::Else { block } => { + Self::_hook(block, res); + } + + Statement::If { block, .. } => { + Self::_hook(block, res); + } + + Statement::While { block, .. } => { + Self::_hook(block, res); + } + + Statement::For { block, .. } => { + Self::_hook(block, res); + } + + Statement::DoWhile { block, .. } => { + Self::_hook(block, res); + } + + Statement::Declaration { value, .. } => { + if let Some(v) = value { + if let Expression::Hook(hook) = v { + res.insert(hook.to_owned()); + } + } + } + Statement::Expression(Expression::Hook(hook)) => { + res.insert(hook.to_owned()); + } + + _ => {} + } + } + + fn all_hooks(&self) -> HashSet { + let mut result = HashSet::new(); + + for v in self.functions.iter() { + if let Statement::Block(body) = &v.borrow().body { + for statement in body.iter() { + Self::_hook(statement, &mut result); + } + } + } + + result + } + + fn find_variable(&self, name: &str) -> Option<&RFC> { + for v in self.variables.iter() { + if v.borrow().name == name { + return Some(v); + } + } + + for (_, v) in self.preprocessor_directives.iter() { + if let Some(v) = v.find_variable(name) { + return Some(v); + } + } + + None + } + + fn _replace_hook(snippet: &Snippet, hook: &Hook) -> Expression { + let ow_subhooks = !hook.subhooks.is_empty(); + + let txt = if let Some(paras) = hook.parameters.as_ref() { + if ow_subhooks { + let call_name = snippet + .find_symbol(hook.subhooks.first().unwrap()) + .expect(format!("{} not found", hook.subhooks.first().unwrap()).as_str()); + let paras = paras.join(", "); + format!("{}({})", call_name, paras) + } else { + snippet.call(paras) + } + } else { + if ow_subhooks { + let var = snippet + .find_variable(hook.subhooks.first().unwrap()) + .unwrap(); + if let Some(v) = var.borrow().value.as_ref() { + v.to_owned() + } else { + var.borrow().name.to_owned() + } + } else { + snippet.call(&vec![]) + } + }; + + expression(&txt).unwrap().1 + } + + fn _check_hook_exp(old: &str, code: &Snippet, exp: &mut Expression, valid: &mut bool) { + match exp { + Expression::Assignment { right, .. } => { + Self::_check_hook_exp(old, code, right, valid); + } + Expression::Binary { left, right, .. } => { + Self::_check_hook_exp(old, code, left, valid); + Self::_check_hook_exp(old, code, right, valid); + } + Expression::FunctionCall { + parameters, name, .. + } => { + for v in parameters.iter_mut() { + Self::_check_hook_exp(old, code, v, valid); + } + } + Expression::StructMemberAccess { base, .. } => { + Self::_check_hook_exp(old, code, base, valid); + } + + Expression::StructPointerAccess { base, .. } => { + Self::_check_hook_exp(old, code, base, valid); + } + + Expression::Unary { right, .. } => { + Self::_check_hook_exp(old, code, right, valid); + } + + Expression::Hook(hook) => { + if hook.name == old { + let new_exp = Self::_replace_hook(code, hook); + *exp = new_exp; + *valid = true; + } + } + + _ => {} + } + } + + fn _set_hook<'b, 'a: 'b>( + stat: &'a mut Box, + old: &str, + code: &Snippet, + valid: &mut bool, + ) { + match stat.as_mut() { + Statement::Block(body) => { + for statement in body.iter_mut() { + Self::_set_hook(statement, old, code, valid); + } + } + + Statement::Else { block } => { + Self::_set_hook(block, old, code, valid); + } + + Statement::If { block, .. } => { + Self::_set_hook(block, old, code, valid); + } + + Statement::While { block, .. } => { + Self::_set_hook(block, old, code, valid); + } + + Statement::For { block, .. } => { + Self::_set_hook(block, old, code, valid); + } + + Statement::DoWhile { block, .. } => { + Self::_set_hook(block, old, code, valid); + } + + Statement::Declaration { value, .. } => { + if let Some(v) = value { + Self::_check_hook_exp(old, code, v, valid); + } + } + Statement::Expression(v) => { + Self::_check_hook_exp(old, code, v, valid); + } + + _ => {} + } + } + + fn set_hook(&mut self, old: &str, code: &Snippet) -> bool { + let mut valid = false; + for v in self.functions.iter_mut() { + if let Statement::Block(body) = &mut v.borrow_mut().body { + for statement in body.iter_mut() { + Self::_set_hook(statement, old, code, &mut valid); + } + } + } + + valid + } +} + +#[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; + +#ifdef _GLUMPY__VERTEX_SHADER__ +void transform() +{ + if (viewport_transform == 0) return; + + vec4 position = gl_Position; + + 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; + + gl_Position = vec4((x + w*position.x/position.w)*position.w, + (y + h*position.y/position.w)*position.w, + position.z, position.w); +} +#endif + +#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; + + /* + 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 + + + "#; + + let result = CodeBlock::new(input).unwrap(); + + print!("{}", result); +} + +#[test] +fn test_expression() { + let input = " + + void main () + { + fetch_uniforms(); + v_linewidth = linewidth; + v_antialias = antialias; + v_color = color; + + 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)))); + + vec2 _prev = NDC_to_viewport(prev_, .zw); + vec2 _curr = NDC_to_viewport(curr_, .zw); + vec2 _next = NDC_to_viewport(next_, .zw); + + 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); + } + + if( abs(id) > 1.5 ) v_color.a = 0.0; + + v_distance = w*id; + gl_Position = viewport_to_NDC(P, .zw, curr_.z / curr_.w); + + ; + } + + "; + let result = ws(function)(input).unwrap(); + println!("{:?}", result.1); +} + +#[test] +fn test_expression_2() { + let input = r#" + + "#; + + let result = ws(expression)(input).unwrap(); + + println!("{}", result.1); +} + +#[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); + } + "#; + + let result = ws(function)(input).unwrap(); + + println!("{}", result.1); +} + +#[test] +fn test_struct() { + let input = r#" + struct vertex { + vec4 position; + vec4 color; + } + +}"#; + + let stru = ws(parse_struct)(input).unwrap(); + + println!("{}", stru.1); +}