├── .gitignore ├── Cargo.lock ├── Cargo.toml ├── LICENSE ├── Makefile ├── README.md ├── envmaps ├── coltest │ ├── env_cos_0_x+.hdr │ ├── env_cos_0_x-.hdr │ ├── env_cos_0_y+.hdr │ ├── env_cos_0_y-.hdr │ ├── env_cos_0_z+.hdr │ ├── env_cos_0_z-.hdr │ ├── env_cos_1_x+.hdr │ ├── env_cos_1_x-.hdr │ ├── env_cos_1_y+.hdr │ ├── env_cos_1_y-.hdr │ ├── env_cos_1_z+.hdr │ ├── env_cos_1_z-.hdr │ ├── env_cos_512_x+.hdr │ ├── env_cos_512_x-.hdr │ ├── env_cos_512_y+.hdr │ ├── env_cos_512_y-.hdr │ ├── env_cos_512_z+.hdr │ ├── env_cos_512_z-.hdr │ ├── env_cos_64_x+.hdr │ ├── env_cos_64_x-.hdr │ ├── env_cos_64_y+.hdr │ ├── env_cos_64_y-.hdr │ ├── env_cos_64_z+.hdr │ ├── env_cos_64_z-.hdr │ ├── env_cos_8_x+.hdr │ ├── env_cos_8_x-.hdr │ ├── env_cos_8_y+.hdr │ ├── env_cos_8_y-.hdr │ ├── env_cos_8_z+.hdr │ └── env_cos_8_z-.hdr ├── doge │ ├── env_cos_0_x+.hdr │ ├── env_cos_0_x-.hdr │ ├── env_cos_0_y+.hdr │ ├── env_cos_0_y-.hdr │ ├── env_cos_0_z+.hdr │ ├── env_cos_0_z-.hdr │ ├── env_cos_1_x+.hdr │ ├── env_cos_1_x-.hdr │ ├── env_cos_1_y+.hdr │ ├── env_cos_1_y-.hdr │ ├── env_cos_1_z+.hdr │ ├── env_cos_1_z-.hdr │ ├── env_cos_512_x+.hdr │ ├── env_cos_512_x-.hdr │ ├── env_cos_512_y+.hdr │ ├── env_cos_512_y-.hdr │ ├── env_cos_512_z+.hdr │ ├── env_cos_512_z-.hdr │ ├── env_cos_64_x+.hdr │ ├── env_cos_64_x-.hdr │ ├── env_cos_64_y+.hdr │ ├── env_cos_64_y-.hdr │ ├── env_cos_64_z+.hdr │ ├── env_cos_64_z-.hdr │ ├── env_cos_8_x+.hdr │ ├── env_cos_8_x-.hdr │ ├── env_cos_8_y+.hdr │ ├── env_cos_8_y-.hdr │ ├── env_cos_8_z+.hdr │ └── env_cos_8_z-.hdr ├── enis │ ├── env_cos_0_x+.hdr │ ├── env_cos_0_x-.hdr │ ├── env_cos_0_y+.hdr │ ├── env_cos_0_y-.hdr │ ├── env_cos_0_z+.hdr │ ├── env_cos_0_z-.hdr │ ├── env_cos_1_x+.hdr │ ├── env_cos_1_x-.hdr │ ├── env_cos_1_y+.hdr │ ├── env_cos_1_y-.hdr │ ├── env_cos_1_z+.hdr │ ├── env_cos_1_z-.hdr │ ├── env_cos_512_x+.hdr │ ├── env_cos_512_x-.hdr │ ├── env_cos_512_y+.hdr │ ├── env_cos_512_y-.hdr │ ├── env_cos_512_z+.hdr │ ├── env_cos_512_z-.hdr │ ├── env_cos_64_x+.hdr │ ├── env_cos_64_x-.hdr │ ├── env_cos_64_y+.hdr │ ├── env_cos_64_y-.hdr │ ├── env_cos_64_z+.hdr │ ├── env_cos_64_z-.hdr │ ├── env_cos_8_x+.hdr │ ├── env_cos_8_x-.hdr │ ├── env_cos_8_y+.hdr │ ├── env_cos_8_y-.hdr │ ├── env_cos_8_z+.hdr │ └── env_cos_8_z-.hdr ├── envmap_copyright.txt ├── glacier │ ├── env_cos_0_x+.hdr │ ├── env_cos_0_x-.hdr │ ├── env_cos_0_y+.hdr │ ├── env_cos_0_y-.hdr │ ├── env_cos_0_z+.hdr │ ├── env_cos_0_z-.hdr │ ├── env_cos_1_x+.hdr │ ├── env_cos_1_x-.hdr │ ├── env_cos_1_y+.hdr │ ├── env_cos_1_y-.hdr │ ├── env_cos_1_z+.hdr │ ├── env_cos_1_z-.hdr │ ├── env_cos_512_x+.hdr │ ├── env_cos_512_x-.hdr │ ├── env_cos_512_y+.hdr │ ├── env_cos_512_y-.hdr │ ├── env_cos_512_z+.hdr │ ├── env_cos_512_z-.hdr │ ├── env_cos_64_x+.hdr │ ├── env_cos_64_x-.hdr │ ├── env_cos_64_y+.hdr │ ├── env_cos_64_y-.hdr │ ├── env_cos_64_z+.hdr │ ├── env_cos_64_z-.hdr │ ├── env_cos_8_x+.hdr │ ├── env_cos_8_x-.hdr │ ├── env_cos_8_y+.hdr │ ├── env_cos_8_y-.hdr │ ├── env_cos_8_z+.hdr │ └── env_cos_8_z-.hdr ├── grace │ ├── env_cos_0_x+.hdr │ ├── env_cos_0_x-.hdr │ ├── env_cos_0_y+.hdr │ ├── env_cos_0_y-.hdr │ ├── env_cos_0_z+.hdr │ ├── env_cos_0_z-.hdr │ ├── env_cos_1_x+.hdr │ ├── env_cos_1_x-.hdr │ ├── env_cos_1_y+.hdr │ ├── env_cos_1_y-.hdr │ ├── env_cos_1_z+.hdr │ ├── env_cos_1_z-.hdr │ ├── env_cos_512_x+.hdr │ ├── env_cos_512_x-.hdr │ ├── env_cos_512_y+.hdr │ ├── env_cos_512_y-.hdr │ ├── env_cos_512_z+.hdr │ ├── env_cos_512_z-.hdr │ ├── env_cos_64_x+.hdr │ ├── env_cos_64_x-.hdr │ ├── env_cos_64_y+.hdr │ ├── env_cos_64_y-.hdr │ ├── env_cos_64_z+.hdr │ ├── env_cos_64_z-.hdr │ ├── env_cos_8_x+.hdr │ ├── env_cos_8_x-.hdr │ ├── env_cos_8_y+.hdr │ ├── env_cos_8_y-.hdr │ ├── env_cos_8_z+.hdr │ └── env_cos_8_z-.hdr ├── parking_lot │ ├── env_cos_0_x+.hdr │ ├── env_cos_0_x-.hdr │ ├── env_cos_0_y+.hdr │ ├── env_cos_0_y-.hdr │ ├── env_cos_0_z+.hdr │ ├── env_cos_0_z-.hdr │ ├── env_cos_1_x+.hdr │ ├── env_cos_1_x-.hdr │ ├── env_cos_1_y+.hdr │ ├── env_cos_1_y-.hdr │ ├── env_cos_1_z+.hdr │ ├── env_cos_1_z-.hdr │ ├── env_cos_512_x+.hdr │ ├── env_cos_512_x-.hdr │ ├── env_cos_512_y+.hdr │ ├── env_cos_512_y-.hdr │ ├── env_cos_512_z+.hdr │ ├── env_cos_512_z-.hdr │ ├── env_cos_64_x+.hdr │ ├── env_cos_64_x-.hdr │ ├── env_cos_64_y+.hdr │ ├── env_cos_64_y-.hdr │ ├── env_cos_64_z+.hdr │ ├── env_cos_64_z-.hdr │ ├── env_cos_8_x+.hdr │ ├── env_cos_8_x-.hdr │ ├── env_cos_8_y+.hdr │ ├── env_cos_8_y-.hdr │ ├── env_cos_8_z+.hdr │ └── env_cos_8_z-.hdr ├── pine_tree │ ├── env_cos_0_x+.hdr │ ├── env_cos_0_x-.hdr │ ├── env_cos_0_y+.hdr │ ├── env_cos_0_y-.hdr │ ├── env_cos_0_z+.hdr │ ├── env_cos_0_z-.hdr │ ├── env_cos_1_x+.hdr │ ├── env_cos_1_x-.hdr │ ├── env_cos_1_y+.hdr │ ├── env_cos_1_y-.hdr │ ├── env_cos_1_z+.hdr │ ├── env_cos_1_z-.hdr │ ├── env_cos_512_x+.hdr │ ├── env_cos_512_x-.hdr │ ├── env_cos_512_y+.hdr │ ├── env_cos_512_y-.hdr │ ├── env_cos_512_z+.hdr │ ├── env_cos_512_z-.hdr │ ├── env_cos_64_x+.hdr │ ├── env_cos_64_x-.hdr │ ├── env_cos_64_y+.hdr │ ├── env_cos_64_y-.hdr │ ├── env_cos_64_z+.hdr │ ├── env_cos_64_z-.hdr │ ├── env_cos_8_x+.hdr │ ├── env_cos_8_x-.hdr │ ├── env_cos_8_y+.hdr │ ├── env_cos_8_y-.hdr │ ├── env_cos_8_z+.hdr │ └── env_cos_8_z-.hdr ├── pisa │ ├── env_cos_0_x+.hdr │ ├── env_cos_0_x-.hdr │ ├── env_cos_0_y+.hdr │ ├── env_cos_0_y-.hdr │ ├── env_cos_0_z+.hdr │ ├── env_cos_0_z-.hdr │ ├── env_cos_1_x+.hdr │ ├── env_cos_1_x-.hdr │ ├── env_cos_1_y+.hdr │ ├── env_cos_1_y-.hdr │ ├── env_cos_1_z+.hdr │ ├── env_cos_1_z-.hdr │ ├── env_cos_512_x+.hdr │ ├── env_cos_512_x-.hdr │ ├── env_cos_512_y+.hdr │ ├── env_cos_512_y-.hdr │ ├── env_cos_512_z+.hdr │ ├── env_cos_512_z-.hdr │ ├── env_cos_64_x+.hdr │ ├── env_cos_64_x-.hdr │ ├── env_cos_64_y+.hdr │ ├── env_cos_64_y-.hdr │ ├── env_cos_64_z+.hdr │ ├── env_cos_64_z-.hdr │ ├── env_cos_8_x+.hdr │ ├── env_cos_8_x-.hdr │ ├── env_cos_8_y+.hdr │ ├── env_cos_8_y-.hdr │ ├── env_cos_8_z+.hdr │ └── env_cos_8_z-.hdr └── uffizi │ ├── env_cos_0_x+.hdr │ ├── env_cos_0_x-.hdr │ ├── env_cos_0_y+.hdr │ ├── env_cos_0_y-.hdr │ ├── env_cos_0_z+.hdr │ ├── env_cos_0_z-.hdr │ ├── env_cos_1_x+.hdr │ ├── env_cos_1_x-.hdr │ ├── env_cos_1_y+.hdr │ ├── env_cos_1_y-.hdr │ ├── env_cos_1_z+.hdr │ ├── env_cos_1_z-.hdr │ ├── env_cos_512_x+.hdr │ ├── env_cos_512_x-.hdr │ ├── env_cos_512_y+.hdr │ ├── env_cos_512_y-.hdr │ ├── env_cos_512_z+.hdr │ ├── env_cos_512_z-.hdr │ ├── env_cos_64_x+.hdr │ ├── env_cos_64_x-.hdr │ ├── env_cos_64_y+.hdr │ ├── env_cos_64_y-.hdr │ ├── env_cos_64_z+.hdr │ ├── env_cos_64_z-.hdr │ ├── env_cos_8_x+.hdr │ ├── env_cos_8_x-.hdr │ ├── env_cos_8_y+.hdr │ ├── env_cos_8_y-.hdr │ ├── env_cos_8_z+.hdr │ └── env_cos_8_z-.hdr ├── hs-src ├── App.hs ├── AppDefs.hs ├── BoundedSequence.hs ├── Experiment.hs ├── Font.hs ├── FrameBuffer.hs ├── GLFWHelpers.hs ├── GLHelpers.hs ├── GLSLHelpers.hs ├── GoLPatterns.hs ├── Main.hs ├── Median.hs ├── QQPlainText.hs ├── QuadRendering.hs ├── QuadShaderSource.hs ├── QuadTypes.hs ├── RustGoLExperiment.hs ├── RustNBodyExperiment.hs ├── RustRasterizerExperiment.hs ├── RustSineExperiment.hs ├── Setup.hs ├── Timing.hs ├── Trace.hs └── WrapEnum.hs ├── meshes ├── blob.dat ├── cat_ao.dat ├── cornell_radiosity.dat ├── cube.dat ├── dwarf.dat ├── hand_ao.dat ├── head_ao.dat ├── killeroo_ao.dat ├── mitsuba_ao.dat ├── sphere.dat ├── teapot.dat └── torus_knot.dat ├── rs-src ├── gol.rs ├── lib.rs ├── nbody.rs ├── rasterizer.rs └── sine_scroller.rs ├── rust-exp.cabal ├── screenshot.png └── stack.yaml /.gitignore: -------------------------------------------------------------------------------- 1 | .cabal-sandbox/ 2 | cabal.sandbox.config 3 | dist/ 4 | rust-exp.prof 5 | .stack-work/ 6 | target/ 7 | -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | [root] 2 | name = "rust_exp" 3 | version = "0.1.0" 4 | dependencies = [ 5 | "ansi_term 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", 6 | "lazy_static 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", 7 | "nalgebra 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)", 8 | "num_cpus 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)", 9 | "rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", 10 | "scoped_threadpool 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", 11 | "stb_image 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", 12 | "time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)", 13 | ] 14 | 15 | [[package]] 16 | name = "ansi_term" 17 | version = "0.7.2" 18 | source = "registry+https://github.com/rust-lang/crates.io-index" 19 | 20 | [[package]] 21 | name = "kernel32-sys" 22 | version = "0.2.2" 23 | source = "registry+https://github.com/rust-lang/crates.io-index" 24 | dependencies = [ 25 | "winapi 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", 26 | "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", 27 | ] 28 | 29 | [[package]] 30 | name = "lazy_static" 31 | version = "0.2.1" 32 | source = "registry+https://github.com/rust-lang/crates.io-index" 33 | 34 | [[package]] 35 | name = "libc" 36 | version = "0.2.11" 37 | source = "registry+https://github.com/rust-lang/crates.io-index" 38 | 39 | [[package]] 40 | name = "nalgebra" 41 | version = "0.8.2" 42 | source = "registry+https://github.com/rust-lang/crates.io-index" 43 | dependencies = [ 44 | "num 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)", 45 | "rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", 46 | "rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)", 47 | ] 48 | 49 | [[package]] 50 | name = "num" 51 | version = "0.1.32" 52 | source = "registry+https://github.com/rust-lang/crates.io-index" 53 | dependencies = [ 54 | "num-bigint 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)", 55 | "num-complex 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)", 56 | "num-integer 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)", 57 | "num-iter 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)", 58 | "num-rational 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)", 59 | "num-traits 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)", 60 | ] 61 | 62 | [[package]] 63 | name = "num-bigint" 64 | version = "0.1.32" 65 | source = "registry+https://github.com/rust-lang/crates.io-index" 66 | dependencies = [ 67 | "num-integer 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)", 68 | "num-traits 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)", 69 | "rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", 70 | "rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)", 71 | ] 72 | 73 | [[package]] 74 | name = "num-complex" 75 | version = "0.1.32" 76 | source = "registry+https://github.com/rust-lang/crates.io-index" 77 | dependencies = [ 78 | "num-traits 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)", 79 | "rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)", 80 | ] 81 | 82 | [[package]] 83 | name = "num-integer" 84 | version = "0.1.32" 85 | source = "registry+https://github.com/rust-lang/crates.io-index" 86 | dependencies = [ 87 | "num-traits 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)", 88 | ] 89 | 90 | [[package]] 91 | name = "num-iter" 92 | version = "0.1.32" 93 | source = "registry+https://github.com/rust-lang/crates.io-index" 94 | dependencies = [ 95 | "num-integer 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)", 96 | "num-traits 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)", 97 | ] 98 | 99 | [[package]] 100 | name = "num-rational" 101 | version = "0.1.32" 102 | source = "registry+https://github.com/rust-lang/crates.io-index" 103 | dependencies = [ 104 | "num-bigint 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)", 105 | "num-integer 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)", 106 | "num-traits 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)", 107 | "rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)", 108 | ] 109 | 110 | [[package]] 111 | name = "num-traits" 112 | version = "0.1.32" 113 | source = "registry+https://github.com/rust-lang/crates.io-index" 114 | 115 | [[package]] 116 | name = "num_cpus" 117 | version = "0.2.12" 118 | source = "registry+https://github.com/rust-lang/crates.io-index" 119 | dependencies = [ 120 | "libc 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", 121 | ] 122 | 123 | [[package]] 124 | name = "rand" 125 | version = "0.3.14" 126 | source = "registry+https://github.com/rust-lang/crates.io-index" 127 | dependencies = [ 128 | "libc 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", 129 | ] 130 | 131 | [[package]] 132 | name = "rustc-serialize" 133 | version = "0.3.19" 134 | source = "registry+https://github.com/rust-lang/crates.io-index" 135 | 136 | [[package]] 137 | name = "scoped_threadpool" 138 | version = "0.1.7" 139 | source = "registry+https://github.com/rust-lang/crates.io-index" 140 | 141 | [[package]] 142 | name = "stb_image" 143 | version = "0.2.1" 144 | source = "registry+https://github.com/rust-lang/crates.io-index" 145 | dependencies = [ 146 | "libc 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", 147 | ] 148 | 149 | [[package]] 150 | name = "time" 151 | version = "0.1.35" 152 | source = "registry+https://github.com/rust-lang/crates.io-index" 153 | dependencies = [ 154 | "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", 155 | "libc 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", 156 | "winapi 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", 157 | ] 158 | 159 | [[package]] 160 | name = "winapi" 161 | version = "0.2.7" 162 | source = "registry+https://github.com/rust-lang/crates.io-index" 163 | 164 | [[package]] 165 | name = "winapi-build" 166 | version = "0.1.1" 167 | source = "registry+https://github.com/rust-lang/crates.io-index" 168 | 169 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "rust_exp" 3 | version = "0.1.0" 4 | 5 | [lib] 6 | path = "rs-src/lib.rs" 7 | crate-type = ["staticlib"] 8 | 9 | [dependencies] 10 | lazy_static = ">= 0.1.15" 11 | rand = ">= 0.3" 12 | nalgebra = ">= 0.5.1" 13 | stb_image = ">= 0.2.1" 14 | time = ">= 0.1" 15 | ansi_term = ">= 0.7" 16 | scoped_threadpool = ">= 0.1.7" 17 | num_cpus = ">= 0.2.11" 18 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2016 Tim C. Schroeder 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining 4 | a copy of this software and associated documentation files (the 5 | "Software"), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included 12 | in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 17 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 18 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 19 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 20 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | 2 | # Build project by invoking Haskell's Stack and Rust's Cargo build tools 3 | 4 | ifeq (, $(shell which stack)) 5 | $(error "Can't find Haskell 'stack' tool, please install from http://haskellstack.org/") 6 | endif 7 | 8 | ifeq (, $(shell which cargo)) 9 | $(error "Can't find Rust 'cargo' tool, please install from https://www.rust-lang.org/") 10 | endif 11 | 12 | .PHONY: all 13 | all: 14 | cargo build --release 15 | stack build 16 | 17 | .PHONY: clean 18 | clean: 19 | cargo clean 20 | stack clean 21 | $(RM) -rf .stack-work 22 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | # Rust Experiments 3 | 4 | This project contains a number of experiments in the simulation / graphics category. I frequently write Haskell projects where I delegate the performance critical, numerical code to C/C++ or offload it to the GPU. I wanted to try using Rust as a safer and more functional alternative. The application itself is written in Haskell, doing the display, user interaction and non-inner-loop parts with the actual computations done in a Rust library. 5 | 6 | ![rust-exp](https://raw.github.com/blitzcode/rust-exp/master/screenshot.png) 7 | 8 | Experiments include... 9 | 10 | - **Software rasterizer** using half-space functions, doing perspective and sub-pixel correct, gap-less rasterization, depth buffering, switchable between vertex and pixel shading, many different shaders implemented, does IBL based on pre-filtered irradiance cubemaps, different environments included, a selection of scenes, many with baked ambient occlusion or radiosity, build-in benchmarking, gamma corrected output, selectable backgrounds, parallelized 11 | - Gravitational **N-Body simulation**, both a brute force O(N^2) and the O(n log n) Barnes-Hut algorithm are implemented, adjustable time step and cutoff criteria, rendering of alpha blended particles with tails, parallelized, multiple interesting initial configurations to choose from 12 | - The famous **'Game of Life' cellular automata**, optimized and parallelized implementation, library of recallable patterns 13 | 14 | **If you want to read actual algorithm descriptions and references for these experiments, including more, higher quality images visit the following link to my website** 15 | 16 | [Rust projects on Blitzcode.net](http://www.blitzcode.net/rust.shtml) 17 | 18 | The Haskell application itself might also be of interests. It features a pluggable experiment framework, modern OpenGL 3/4.x style rendering, text, quad rendering, screenshots, framebuffer system, FPS counter, GLSL, logging etc. A good starting point for your own Haskell + OpenGL adventures. Also see my other [Haskell and GLSL program containing my distance field / ray marching related experiments](https://github.com/blitzcode/ray-marching-distance-fields/). 19 | 20 | # Building 21 | 22 | This project uses the Stack / Cabal tools (`stack build`) for building the Haskell code and Cargo (`cargo build --release`) for building the Rust code. There's a top-level Makefile invoking both, simply do 23 | 24 | make 25 | 26 | once you have Stack and Cargo / Rust installed. 27 | 28 | # Legal 29 | 30 | This program is published under the [MIT License](http://en.wikipedia.org/wiki/MIT_License). 31 | 32 | # Author 33 | 34 | Developed by Tim C. Schroeder, visit my [website](http://www.blitzcode.net) to learn more. 35 | 36 | -------------------------------------------------------------------------------- /envmaps/coltest/env_cos_0_x+.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/coltest/env_cos_0_x+.hdr -------------------------------------------------------------------------------- /envmaps/coltest/env_cos_0_x-.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/coltest/env_cos_0_x-.hdr -------------------------------------------------------------------------------- /envmaps/coltest/env_cos_0_y+.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/coltest/env_cos_0_y+.hdr -------------------------------------------------------------------------------- /envmaps/coltest/env_cos_0_y-.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/coltest/env_cos_0_y-.hdr -------------------------------------------------------------------------------- /envmaps/coltest/env_cos_0_z+.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/coltest/env_cos_0_z+.hdr -------------------------------------------------------------------------------- /envmaps/coltest/env_cos_0_z-.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/coltest/env_cos_0_z-.hdr -------------------------------------------------------------------------------- /envmaps/coltest/env_cos_1_x+.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/coltest/env_cos_1_x+.hdr -------------------------------------------------------------------------------- /envmaps/coltest/env_cos_1_x-.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/coltest/env_cos_1_x-.hdr -------------------------------------------------------------------------------- /envmaps/coltest/env_cos_1_y+.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/coltest/env_cos_1_y+.hdr -------------------------------------------------------------------------------- /envmaps/coltest/env_cos_1_y-.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/coltest/env_cos_1_y-.hdr -------------------------------------------------------------------------------- /envmaps/coltest/env_cos_1_z+.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/coltest/env_cos_1_z+.hdr -------------------------------------------------------------------------------- /envmaps/coltest/env_cos_1_z-.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/coltest/env_cos_1_z-.hdr -------------------------------------------------------------------------------- /envmaps/coltest/env_cos_512_x+.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/coltest/env_cos_512_x+.hdr -------------------------------------------------------------------------------- /envmaps/coltest/env_cos_512_x-.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/coltest/env_cos_512_x-.hdr -------------------------------------------------------------------------------- /envmaps/coltest/env_cos_512_y+.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/coltest/env_cos_512_y+.hdr -------------------------------------------------------------------------------- /envmaps/coltest/env_cos_512_y-.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/coltest/env_cos_512_y-.hdr -------------------------------------------------------------------------------- /envmaps/coltest/env_cos_512_z+.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/coltest/env_cos_512_z+.hdr -------------------------------------------------------------------------------- /envmaps/coltest/env_cos_512_z-.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/coltest/env_cos_512_z-.hdr -------------------------------------------------------------------------------- /envmaps/coltest/env_cos_64_x+.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/coltest/env_cos_64_x+.hdr -------------------------------------------------------------------------------- /envmaps/coltest/env_cos_64_x-.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/coltest/env_cos_64_x-.hdr -------------------------------------------------------------------------------- /envmaps/coltest/env_cos_64_y+.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/coltest/env_cos_64_y+.hdr -------------------------------------------------------------------------------- /envmaps/coltest/env_cos_64_y-.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/coltest/env_cos_64_y-.hdr -------------------------------------------------------------------------------- /envmaps/coltest/env_cos_64_z+.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/coltest/env_cos_64_z+.hdr -------------------------------------------------------------------------------- /envmaps/coltest/env_cos_64_z-.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/coltest/env_cos_64_z-.hdr -------------------------------------------------------------------------------- /envmaps/coltest/env_cos_8_x+.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/coltest/env_cos_8_x+.hdr -------------------------------------------------------------------------------- /envmaps/coltest/env_cos_8_x-.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/coltest/env_cos_8_x-.hdr -------------------------------------------------------------------------------- /envmaps/coltest/env_cos_8_y+.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/coltest/env_cos_8_y+.hdr -------------------------------------------------------------------------------- /envmaps/coltest/env_cos_8_y-.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/coltest/env_cos_8_y-.hdr -------------------------------------------------------------------------------- /envmaps/coltest/env_cos_8_z+.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/coltest/env_cos_8_z+.hdr -------------------------------------------------------------------------------- /envmaps/coltest/env_cos_8_z-.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/coltest/env_cos_8_z-.hdr -------------------------------------------------------------------------------- /envmaps/doge/env_cos_0_x+.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/doge/env_cos_0_x+.hdr -------------------------------------------------------------------------------- /envmaps/doge/env_cos_0_x-.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/doge/env_cos_0_x-.hdr -------------------------------------------------------------------------------- /envmaps/doge/env_cos_0_y+.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/doge/env_cos_0_y+.hdr -------------------------------------------------------------------------------- /envmaps/doge/env_cos_0_y-.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/doge/env_cos_0_y-.hdr -------------------------------------------------------------------------------- /envmaps/doge/env_cos_0_z+.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/doge/env_cos_0_z+.hdr -------------------------------------------------------------------------------- /envmaps/doge/env_cos_0_z-.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/doge/env_cos_0_z-.hdr -------------------------------------------------------------------------------- /envmaps/doge/env_cos_1_x+.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/doge/env_cos_1_x+.hdr -------------------------------------------------------------------------------- /envmaps/doge/env_cos_1_x-.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/doge/env_cos_1_x-.hdr -------------------------------------------------------------------------------- /envmaps/doge/env_cos_1_y+.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/doge/env_cos_1_y+.hdr -------------------------------------------------------------------------------- /envmaps/doge/env_cos_1_y-.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/doge/env_cos_1_y-.hdr -------------------------------------------------------------------------------- /envmaps/doge/env_cos_1_z+.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/doge/env_cos_1_z+.hdr -------------------------------------------------------------------------------- /envmaps/doge/env_cos_1_z-.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/doge/env_cos_1_z-.hdr -------------------------------------------------------------------------------- /envmaps/doge/env_cos_512_x+.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/doge/env_cos_512_x+.hdr -------------------------------------------------------------------------------- /envmaps/doge/env_cos_512_x-.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/doge/env_cos_512_x-.hdr -------------------------------------------------------------------------------- /envmaps/doge/env_cos_512_y+.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/doge/env_cos_512_y+.hdr -------------------------------------------------------------------------------- /envmaps/doge/env_cos_512_y-.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/doge/env_cos_512_y-.hdr -------------------------------------------------------------------------------- /envmaps/doge/env_cos_512_z+.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/doge/env_cos_512_z+.hdr -------------------------------------------------------------------------------- /envmaps/doge/env_cos_512_z-.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/doge/env_cos_512_z-.hdr -------------------------------------------------------------------------------- /envmaps/doge/env_cos_64_x+.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/doge/env_cos_64_x+.hdr -------------------------------------------------------------------------------- /envmaps/doge/env_cos_64_x-.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/doge/env_cos_64_x-.hdr -------------------------------------------------------------------------------- /envmaps/doge/env_cos_64_y+.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/doge/env_cos_64_y+.hdr -------------------------------------------------------------------------------- /envmaps/doge/env_cos_64_y-.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/doge/env_cos_64_y-.hdr -------------------------------------------------------------------------------- /envmaps/doge/env_cos_64_z+.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/doge/env_cos_64_z+.hdr -------------------------------------------------------------------------------- /envmaps/doge/env_cos_64_z-.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/doge/env_cos_64_z-.hdr -------------------------------------------------------------------------------- /envmaps/doge/env_cos_8_x+.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/doge/env_cos_8_x+.hdr -------------------------------------------------------------------------------- /envmaps/doge/env_cos_8_x-.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/doge/env_cos_8_x-.hdr -------------------------------------------------------------------------------- /envmaps/doge/env_cos_8_y+.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/doge/env_cos_8_y+.hdr -------------------------------------------------------------------------------- /envmaps/doge/env_cos_8_y-.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/doge/env_cos_8_y-.hdr -------------------------------------------------------------------------------- /envmaps/doge/env_cos_8_z+.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/doge/env_cos_8_z+.hdr -------------------------------------------------------------------------------- /envmaps/doge/env_cos_8_z-.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/doge/env_cos_8_z-.hdr -------------------------------------------------------------------------------- /envmaps/enis/env_cos_0_x+.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/enis/env_cos_0_x+.hdr -------------------------------------------------------------------------------- /envmaps/enis/env_cos_0_x-.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/enis/env_cos_0_x-.hdr -------------------------------------------------------------------------------- /envmaps/enis/env_cos_0_y+.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/enis/env_cos_0_y+.hdr -------------------------------------------------------------------------------- /envmaps/enis/env_cos_0_y-.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/enis/env_cos_0_y-.hdr -------------------------------------------------------------------------------- /envmaps/enis/env_cos_0_z+.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/enis/env_cos_0_z+.hdr -------------------------------------------------------------------------------- /envmaps/enis/env_cos_0_z-.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/enis/env_cos_0_z-.hdr -------------------------------------------------------------------------------- /envmaps/enis/env_cos_1_x+.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/enis/env_cos_1_x+.hdr -------------------------------------------------------------------------------- /envmaps/enis/env_cos_1_x-.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/enis/env_cos_1_x-.hdr -------------------------------------------------------------------------------- /envmaps/enis/env_cos_1_y+.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/enis/env_cos_1_y+.hdr -------------------------------------------------------------------------------- /envmaps/enis/env_cos_1_y-.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/enis/env_cos_1_y-.hdr -------------------------------------------------------------------------------- /envmaps/enis/env_cos_1_z+.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/enis/env_cos_1_z+.hdr -------------------------------------------------------------------------------- /envmaps/enis/env_cos_1_z-.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/enis/env_cos_1_z-.hdr -------------------------------------------------------------------------------- /envmaps/enis/env_cos_512_x+.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/enis/env_cos_512_x+.hdr -------------------------------------------------------------------------------- /envmaps/enis/env_cos_512_x-.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/enis/env_cos_512_x-.hdr -------------------------------------------------------------------------------- /envmaps/enis/env_cos_512_y+.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/enis/env_cos_512_y+.hdr -------------------------------------------------------------------------------- /envmaps/enis/env_cos_512_y-.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/enis/env_cos_512_y-.hdr -------------------------------------------------------------------------------- /envmaps/enis/env_cos_512_z+.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/enis/env_cos_512_z+.hdr -------------------------------------------------------------------------------- /envmaps/enis/env_cos_512_z-.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/enis/env_cos_512_z-.hdr -------------------------------------------------------------------------------- /envmaps/enis/env_cos_64_x+.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/enis/env_cos_64_x+.hdr -------------------------------------------------------------------------------- /envmaps/enis/env_cos_64_x-.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/enis/env_cos_64_x-.hdr -------------------------------------------------------------------------------- /envmaps/enis/env_cos_64_y+.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/enis/env_cos_64_y+.hdr -------------------------------------------------------------------------------- /envmaps/enis/env_cos_64_y-.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/enis/env_cos_64_y-.hdr -------------------------------------------------------------------------------- /envmaps/enis/env_cos_64_z+.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/enis/env_cos_64_z+.hdr -------------------------------------------------------------------------------- /envmaps/enis/env_cos_64_z-.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/enis/env_cos_64_z-.hdr -------------------------------------------------------------------------------- /envmaps/enis/env_cos_8_x+.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/enis/env_cos_8_x+.hdr -------------------------------------------------------------------------------- /envmaps/enis/env_cos_8_x-.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/enis/env_cos_8_x-.hdr -------------------------------------------------------------------------------- /envmaps/enis/env_cos_8_y+.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/enis/env_cos_8_y+.hdr -------------------------------------------------------------------------------- /envmaps/enis/env_cos_8_y-.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/enis/env_cos_8_y-.hdr -------------------------------------------------------------------------------- /envmaps/enis/env_cos_8_z+.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/enis/env_cos_8_z+.hdr -------------------------------------------------------------------------------- /envmaps/enis/env_cos_8_z-.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/enis/env_cos_8_z-.hdr -------------------------------------------------------------------------------- /envmaps/envmap_copyright.txt: -------------------------------------------------------------------------------- 1 | 2 | The environment map convolutions in the sub-directories here are derived from files 3 | downloaded from the following sources: 4 | 5 | http://gl.ict.usc.edu/Data/HighResProbes/ 6 | http://www.hdrlabs.com/sibl/archive.html 7 | http://www.hdri-hub.com/free-hdri-environments-for-download 8 | 9 | (C) original authors 10 | 11 | -------------------------------------------------------------------------------- /envmaps/glacier/env_cos_0_x+.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/glacier/env_cos_0_x+.hdr -------------------------------------------------------------------------------- /envmaps/glacier/env_cos_0_x-.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/glacier/env_cos_0_x-.hdr -------------------------------------------------------------------------------- /envmaps/glacier/env_cos_0_y+.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/glacier/env_cos_0_y+.hdr -------------------------------------------------------------------------------- /envmaps/glacier/env_cos_0_y-.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/glacier/env_cos_0_y-.hdr -------------------------------------------------------------------------------- /envmaps/glacier/env_cos_0_z+.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/glacier/env_cos_0_z+.hdr -------------------------------------------------------------------------------- /envmaps/glacier/env_cos_0_z-.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/glacier/env_cos_0_z-.hdr -------------------------------------------------------------------------------- /envmaps/glacier/env_cos_1_x+.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/glacier/env_cos_1_x+.hdr -------------------------------------------------------------------------------- /envmaps/glacier/env_cos_1_x-.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/glacier/env_cos_1_x-.hdr -------------------------------------------------------------------------------- /envmaps/glacier/env_cos_1_y+.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/glacier/env_cos_1_y+.hdr -------------------------------------------------------------------------------- /envmaps/glacier/env_cos_1_y-.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/glacier/env_cos_1_y-.hdr -------------------------------------------------------------------------------- /envmaps/glacier/env_cos_1_z+.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/glacier/env_cos_1_z+.hdr -------------------------------------------------------------------------------- /envmaps/glacier/env_cos_1_z-.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/glacier/env_cos_1_z-.hdr -------------------------------------------------------------------------------- /envmaps/glacier/env_cos_512_x+.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/glacier/env_cos_512_x+.hdr -------------------------------------------------------------------------------- /envmaps/glacier/env_cos_512_x-.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/glacier/env_cos_512_x-.hdr -------------------------------------------------------------------------------- /envmaps/glacier/env_cos_512_y+.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/glacier/env_cos_512_y+.hdr -------------------------------------------------------------------------------- /envmaps/glacier/env_cos_512_y-.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/glacier/env_cos_512_y-.hdr -------------------------------------------------------------------------------- /envmaps/glacier/env_cos_512_z+.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/glacier/env_cos_512_z+.hdr -------------------------------------------------------------------------------- /envmaps/glacier/env_cos_512_z-.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/glacier/env_cos_512_z-.hdr -------------------------------------------------------------------------------- /envmaps/glacier/env_cos_64_x+.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/glacier/env_cos_64_x+.hdr -------------------------------------------------------------------------------- /envmaps/glacier/env_cos_64_x-.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/glacier/env_cos_64_x-.hdr -------------------------------------------------------------------------------- /envmaps/glacier/env_cos_64_y+.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/glacier/env_cos_64_y+.hdr -------------------------------------------------------------------------------- /envmaps/glacier/env_cos_64_y-.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/glacier/env_cos_64_y-.hdr -------------------------------------------------------------------------------- /envmaps/glacier/env_cos_64_z+.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/glacier/env_cos_64_z+.hdr -------------------------------------------------------------------------------- /envmaps/glacier/env_cos_64_z-.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/glacier/env_cos_64_z-.hdr -------------------------------------------------------------------------------- /envmaps/glacier/env_cos_8_x+.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/glacier/env_cos_8_x+.hdr -------------------------------------------------------------------------------- /envmaps/glacier/env_cos_8_x-.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/glacier/env_cos_8_x-.hdr -------------------------------------------------------------------------------- /envmaps/glacier/env_cos_8_y+.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/glacier/env_cos_8_y+.hdr -------------------------------------------------------------------------------- /envmaps/glacier/env_cos_8_y-.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/glacier/env_cos_8_y-.hdr -------------------------------------------------------------------------------- /envmaps/glacier/env_cos_8_z+.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/glacier/env_cos_8_z+.hdr -------------------------------------------------------------------------------- /envmaps/glacier/env_cos_8_z-.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/glacier/env_cos_8_z-.hdr -------------------------------------------------------------------------------- /envmaps/grace/env_cos_0_x+.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/grace/env_cos_0_x+.hdr -------------------------------------------------------------------------------- /envmaps/grace/env_cos_0_x-.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/grace/env_cos_0_x-.hdr -------------------------------------------------------------------------------- /envmaps/grace/env_cos_0_y+.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/grace/env_cos_0_y+.hdr -------------------------------------------------------------------------------- /envmaps/grace/env_cos_0_y-.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/grace/env_cos_0_y-.hdr -------------------------------------------------------------------------------- /envmaps/grace/env_cos_0_z+.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/grace/env_cos_0_z+.hdr -------------------------------------------------------------------------------- /envmaps/grace/env_cos_0_z-.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/grace/env_cos_0_z-.hdr -------------------------------------------------------------------------------- /envmaps/grace/env_cos_1_x+.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/grace/env_cos_1_x+.hdr -------------------------------------------------------------------------------- /envmaps/grace/env_cos_1_x-.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/grace/env_cos_1_x-.hdr -------------------------------------------------------------------------------- /envmaps/grace/env_cos_1_y+.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/grace/env_cos_1_y+.hdr -------------------------------------------------------------------------------- /envmaps/grace/env_cos_1_y-.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/grace/env_cos_1_y-.hdr -------------------------------------------------------------------------------- /envmaps/grace/env_cos_1_z+.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/grace/env_cos_1_z+.hdr -------------------------------------------------------------------------------- /envmaps/grace/env_cos_1_z-.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/grace/env_cos_1_z-.hdr -------------------------------------------------------------------------------- /envmaps/grace/env_cos_512_x+.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/grace/env_cos_512_x+.hdr -------------------------------------------------------------------------------- /envmaps/grace/env_cos_512_x-.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/grace/env_cos_512_x-.hdr -------------------------------------------------------------------------------- /envmaps/grace/env_cos_512_y+.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/grace/env_cos_512_y+.hdr -------------------------------------------------------------------------------- /envmaps/grace/env_cos_512_y-.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/grace/env_cos_512_y-.hdr -------------------------------------------------------------------------------- /envmaps/grace/env_cos_512_z+.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/grace/env_cos_512_z+.hdr -------------------------------------------------------------------------------- /envmaps/grace/env_cos_512_z-.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/grace/env_cos_512_z-.hdr -------------------------------------------------------------------------------- /envmaps/grace/env_cos_64_x+.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/grace/env_cos_64_x+.hdr -------------------------------------------------------------------------------- /envmaps/grace/env_cos_64_x-.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/grace/env_cos_64_x-.hdr -------------------------------------------------------------------------------- /envmaps/grace/env_cos_64_y+.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/grace/env_cos_64_y+.hdr -------------------------------------------------------------------------------- /envmaps/grace/env_cos_64_y-.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/grace/env_cos_64_y-.hdr -------------------------------------------------------------------------------- /envmaps/grace/env_cos_64_z+.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/grace/env_cos_64_z+.hdr -------------------------------------------------------------------------------- /envmaps/grace/env_cos_64_z-.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/grace/env_cos_64_z-.hdr -------------------------------------------------------------------------------- /envmaps/grace/env_cos_8_x+.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/grace/env_cos_8_x+.hdr -------------------------------------------------------------------------------- /envmaps/grace/env_cos_8_x-.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/grace/env_cos_8_x-.hdr -------------------------------------------------------------------------------- /envmaps/grace/env_cos_8_y+.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/grace/env_cos_8_y+.hdr -------------------------------------------------------------------------------- /envmaps/grace/env_cos_8_y-.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/grace/env_cos_8_y-.hdr -------------------------------------------------------------------------------- /envmaps/grace/env_cos_8_z+.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/grace/env_cos_8_z+.hdr -------------------------------------------------------------------------------- /envmaps/grace/env_cos_8_z-.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/grace/env_cos_8_z-.hdr -------------------------------------------------------------------------------- /envmaps/parking_lot/env_cos_0_x+.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/parking_lot/env_cos_0_x+.hdr -------------------------------------------------------------------------------- /envmaps/parking_lot/env_cos_0_x-.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/parking_lot/env_cos_0_x-.hdr -------------------------------------------------------------------------------- /envmaps/parking_lot/env_cos_0_y+.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/parking_lot/env_cos_0_y+.hdr -------------------------------------------------------------------------------- /envmaps/parking_lot/env_cos_0_y-.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/parking_lot/env_cos_0_y-.hdr -------------------------------------------------------------------------------- /envmaps/parking_lot/env_cos_0_z+.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/parking_lot/env_cos_0_z+.hdr -------------------------------------------------------------------------------- /envmaps/parking_lot/env_cos_0_z-.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/parking_lot/env_cos_0_z-.hdr -------------------------------------------------------------------------------- /envmaps/parking_lot/env_cos_1_x+.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/parking_lot/env_cos_1_x+.hdr -------------------------------------------------------------------------------- /envmaps/parking_lot/env_cos_1_x-.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/parking_lot/env_cos_1_x-.hdr -------------------------------------------------------------------------------- /envmaps/parking_lot/env_cos_1_y+.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/parking_lot/env_cos_1_y+.hdr -------------------------------------------------------------------------------- /envmaps/parking_lot/env_cos_1_y-.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/parking_lot/env_cos_1_y-.hdr -------------------------------------------------------------------------------- /envmaps/parking_lot/env_cos_1_z+.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/parking_lot/env_cos_1_z+.hdr -------------------------------------------------------------------------------- /envmaps/parking_lot/env_cos_1_z-.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/parking_lot/env_cos_1_z-.hdr -------------------------------------------------------------------------------- /envmaps/parking_lot/env_cos_512_x+.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/parking_lot/env_cos_512_x+.hdr -------------------------------------------------------------------------------- /envmaps/parking_lot/env_cos_512_x-.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/parking_lot/env_cos_512_x-.hdr -------------------------------------------------------------------------------- /envmaps/parking_lot/env_cos_512_y+.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/parking_lot/env_cos_512_y+.hdr -------------------------------------------------------------------------------- /envmaps/parking_lot/env_cos_512_y-.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/parking_lot/env_cos_512_y-.hdr -------------------------------------------------------------------------------- /envmaps/parking_lot/env_cos_512_z+.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/parking_lot/env_cos_512_z+.hdr -------------------------------------------------------------------------------- /envmaps/parking_lot/env_cos_512_z-.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/parking_lot/env_cos_512_z-.hdr -------------------------------------------------------------------------------- /envmaps/parking_lot/env_cos_64_x+.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/parking_lot/env_cos_64_x+.hdr -------------------------------------------------------------------------------- /envmaps/parking_lot/env_cos_64_x-.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/parking_lot/env_cos_64_x-.hdr -------------------------------------------------------------------------------- /envmaps/parking_lot/env_cos_64_y+.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/parking_lot/env_cos_64_y+.hdr -------------------------------------------------------------------------------- /envmaps/parking_lot/env_cos_64_y-.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/parking_lot/env_cos_64_y-.hdr -------------------------------------------------------------------------------- /envmaps/parking_lot/env_cos_64_z+.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/parking_lot/env_cos_64_z+.hdr -------------------------------------------------------------------------------- /envmaps/parking_lot/env_cos_64_z-.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/parking_lot/env_cos_64_z-.hdr -------------------------------------------------------------------------------- /envmaps/parking_lot/env_cos_8_x+.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/parking_lot/env_cos_8_x+.hdr -------------------------------------------------------------------------------- /envmaps/parking_lot/env_cos_8_x-.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/parking_lot/env_cos_8_x-.hdr -------------------------------------------------------------------------------- /envmaps/parking_lot/env_cos_8_y+.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/parking_lot/env_cos_8_y+.hdr -------------------------------------------------------------------------------- /envmaps/parking_lot/env_cos_8_y-.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/parking_lot/env_cos_8_y-.hdr -------------------------------------------------------------------------------- /envmaps/parking_lot/env_cos_8_z+.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/parking_lot/env_cos_8_z+.hdr -------------------------------------------------------------------------------- /envmaps/parking_lot/env_cos_8_z-.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/parking_lot/env_cos_8_z-.hdr -------------------------------------------------------------------------------- /envmaps/pine_tree/env_cos_0_x+.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/pine_tree/env_cos_0_x+.hdr -------------------------------------------------------------------------------- /envmaps/pine_tree/env_cos_0_x-.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/pine_tree/env_cos_0_x-.hdr -------------------------------------------------------------------------------- /envmaps/pine_tree/env_cos_0_y+.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/pine_tree/env_cos_0_y+.hdr -------------------------------------------------------------------------------- /envmaps/pine_tree/env_cos_0_y-.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/pine_tree/env_cos_0_y-.hdr -------------------------------------------------------------------------------- /envmaps/pine_tree/env_cos_0_z+.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/pine_tree/env_cos_0_z+.hdr -------------------------------------------------------------------------------- /envmaps/pine_tree/env_cos_0_z-.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/pine_tree/env_cos_0_z-.hdr -------------------------------------------------------------------------------- /envmaps/pine_tree/env_cos_1_x+.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/pine_tree/env_cos_1_x+.hdr -------------------------------------------------------------------------------- /envmaps/pine_tree/env_cos_1_x-.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/pine_tree/env_cos_1_x-.hdr -------------------------------------------------------------------------------- /envmaps/pine_tree/env_cos_1_y+.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/pine_tree/env_cos_1_y+.hdr -------------------------------------------------------------------------------- /envmaps/pine_tree/env_cos_1_y-.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/pine_tree/env_cos_1_y-.hdr -------------------------------------------------------------------------------- /envmaps/pine_tree/env_cos_1_z+.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/pine_tree/env_cos_1_z+.hdr -------------------------------------------------------------------------------- /envmaps/pine_tree/env_cos_1_z-.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/pine_tree/env_cos_1_z-.hdr -------------------------------------------------------------------------------- /envmaps/pine_tree/env_cos_512_x+.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/pine_tree/env_cos_512_x+.hdr -------------------------------------------------------------------------------- /envmaps/pine_tree/env_cos_512_x-.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/pine_tree/env_cos_512_x-.hdr -------------------------------------------------------------------------------- /envmaps/pine_tree/env_cos_512_y+.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/pine_tree/env_cos_512_y+.hdr -------------------------------------------------------------------------------- /envmaps/pine_tree/env_cos_512_y-.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/pine_tree/env_cos_512_y-.hdr -------------------------------------------------------------------------------- /envmaps/pine_tree/env_cos_512_z+.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/pine_tree/env_cos_512_z+.hdr -------------------------------------------------------------------------------- /envmaps/pine_tree/env_cos_512_z-.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/pine_tree/env_cos_512_z-.hdr -------------------------------------------------------------------------------- /envmaps/pine_tree/env_cos_64_x+.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/pine_tree/env_cos_64_x+.hdr -------------------------------------------------------------------------------- /envmaps/pine_tree/env_cos_64_x-.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/pine_tree/env_cos_64_x-.hdr -------------------------------------------------------------------------------- /envmaps/pine_tree/env_cos_64_y+.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/pine_tree/env_cos_64_y+.hdr -------------------------------------------------------------------------------- /envmaps/pine_tree/env_cos_64_y-.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/pine_tree/env_cos_64_y-.hdr -------------------------------------------------------------------------------- /envmaps/pine_tree/env_cos_64_z+.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/pine_tree/env_cos_64_z+.hdr -------------------------------------------------------------------------------- /envmaps/pine_tree/env_cos_64_z-.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/pine_tree/env_cos_64_z-.hdr -------------------------------------------------------------------------------- /envmaps/pine_tree/env_cos_8_x+.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/pine_tree/env_cos_8_x+.hdr -------------------------------------------------------------------------------- /envmaps/pine_tree/env_cos_8_x-.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/pine_tree/env_cos_8_x-.hdr -------------------------------------------------------------------------------- /envmaps/pine_tree/env_cos_8_y+.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/pine_tree/env_cos_8_y+.hdr -------------------------------------------------------------------------------- /envmaps/pine_tree/env_cos_8_y-.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/pine_tree/env_cos_8_y-.hdr -------------------------------------------------------------------------------- /envmaps/pine_tree/env_cos_8_z+.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/pine_tree/env_cos_8_z+.hdr -------------------------------------------------------------------------------- /envmaps/pine_tree/env_cos_8_z-.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/pine_tree/env_cos_8_z-.hdr -------------------------------------------------------------------------------- /envmaps/pisa/env_cos_0_x+.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/pisa/env_cos_0_x+.hdr -------------------------------------------------------------------------------- /envmaps/pisa/env_cos_0_x-.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/pisa/env_cos_0_x-.hdr -------------------------------------------------------------------------------- /envmaps/pisa/env_cos_0_y+.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/pisa/env_cos_0_y+.hdr -------------------------------------------------------------------------------- /envmaps/pisa/env_cos_0_y-.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/pisa/env_cos_0_y-.hdr -------------------------------------------------------------------------------- /envmaps/pisa/env_cos_0_z+.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/pisa/env_cos_0_z+.hdr -------------------------------------------------------------------------------- /envmaps/pisa/env_cos_0_z-.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/pisa/env_cos_0_z-.hdr -------------------------------------------------------------------------------- /envmaps/pisa/env_cos_1_x+.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/pisa/env_cos_1_x+.hdr -------------------------------------------------------------------------------- /envmaps/pisa/env_cos_1_x-.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/pisa/env_cos_1_x-.hdr -------------------------------------------------------------------------------- /envmaps/pisa/env_cos_1_y+.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/pisa/env_cos_1_y+.hdr -------------------------------------------------------------------------------- /envmaps/pisa/env_cos_1_y-.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/pisa/env_cos_1_y-.hdr -------------------------------------------------------------------------------- /envmaps/pisa/env_cos_1_z+.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/pisa/env_cos_1_z+.hdr -------------------------------------------------------------------------------- /envmaps/pisa/env_cos_1_z-.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/pisa/env_cos_1_z-.hdr -------------------------------------------------------------------------------- /envmaps/pisa/env_cos_512_x+.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/pisa/env_cos_512_x+.hdr -------------------------------------------------------------------------------- /envmaps/pisa/env_cos_512_x-.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/pisa/env_cos_512_x-.hdr -------------------------------------------------------------------------------- /envmaps/pisa/env_cos_512_y+.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/pisa/env_cos_512_y+.hdr -------------------------------------------------------------------------------- /envmaps/pisa/env_cos_512_y-.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/pisa/env_cos_512_y-.hdr -------------------------------------------------------------------------------- /envmaps/pisa/env_cos_512_z+.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/pisa/env_cos_512_z+.hdr -------------------------------------------------------------------------------- /envmaps/pisa/env_cos_512_z-.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/pisa/env_cos_512_z-.hdr -------------------------------------------------------------------------------- /envmaps/pisa/env_cos_64_x+.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/pisa/env_cos_64_x+.hdr -------------------------------------------------------------------------------- /envmaps/pisa/env_cos_64_x-.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/pisa/env_cos_64_x-.hdr -------------------------------------------------------------------------------- /envmaps/pisa/env_cos_64_y+.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/pisa/env_cos_64_y+.hdr -------------------------------------------------------------------------------- /envmaps/pisa/env_cos_64_y-.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/pisa/env_cos_64_y-.hdr -------------------------------------------------------------------------------- /envmaps/pisa/env_cos_64_z+.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/pisa/env_cos_64_z+.hdr -------------------------------------------------------------------------------- /envmaps/pisa/env_cos_64_z-.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/pisa/env_cos_64_z-.hdr -------------------------------------------------------------------------------- /envmaps/pisa/env_cos_8_x+.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/pisa/env_cos_8_x+.hdr -------------------------------------------------------------------------------- /envmaps/pisa/env_cos_8_x-.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/pisa/env_cos_8_x-.hdr -------------------------------------------------------------------------------- /envmaps/pisa/env_cos_8_y+.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/pisa/env_cos_8_y+.hdr -------------------------------------------------------------------------------- /envmaps/pisa/env_cos_8_y-.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/pisa/env_cos_8_y-.hdr -------------------------------------------------------------------------------- /envmaps/pisa/env_cos_8_z+.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/pisa/env_cos_8_z+.hdr -------------------------------------------------------------------------------- /envmaps/pisa/env_cos_8_z-.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/pisa/env_cos_8_z-.hdr -------------------------------------------------------------------------------- /envmaps/uffizi/env_cos_0_x+.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/uffizi/env_cos_0_x+.hdr -------------------------------------------------------------------------------- /envmaps/uffizi/env_cos_0_x-.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/uffizi/env_cos_0_x-.hdr -------------------------------------------------------------------------------- /envmaps/uffizi/env_cos_0_y+.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/uffizi/env_cos_0_y+.hdr -------------------------------------------------------------------------------- /envmaps/uffizi/env_cos_0_y-.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/uffizi/env_cos_0_y-.hdr -------------------------------------------------------------------------------- /envmaps/uffizi/env_cos_0_z+.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/uffizi/env_cos_0_z+.hdr -------------------------------------------------------------------------------- /envmaps/uffizi/env_cos_0_z-.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/uffizi/env_cos_0_z-.hdr -------------------------------------------------------------------------------- /envmaps/uffizi/env_cos_1_x+.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/uffizi/env_cos_1_x+.hdr -------------------------------------------------------------------------------- /envmaps/uffizi/env_cos_1_x-.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/uffizi/env_cos_1_x-.hdr -------------------------------------------------------------------------------- /envmaps/uffizi/env_cos_1_y+.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/uffizi/env_cos_1_y+.hdr -------------------------------------------------------------------------------- /envmaps/uffizi/env_cos_1_y-.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/uffizi/env_cos_1_y-.hdr -------------------------------------------------------------------------------- /envmaps/uffizi/env_cos_1_z+.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/uffizi/env_cos_1_z+.hdr -------------------------------------------------------------------------------- /envmaps/uffizi/env_cos_1_z-.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/uffizi/env_cos_1_z-.hdr -------------------------------------------------------------------------------- /envmaps/uffizi/env_cos_512_x+.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/uffizi/env_cos_512_x+.hdr -------------------------------------------------------------------------------- /envmaps/uffizi/env_cos_512_x-.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/uffizi/env_cos_512_x-.hdr -------------------------------------------------------------------------------- /envmaps/uffizi/env_cos_512_y+.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/uffizi/env_cos_512_y+.hdr -------------------------------------------------------------------------------- /envmaps/uffizi/env_cos_512_y-.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/uffizi/env_cos_512_y-.hdr -------------------------------------------------------------------------------- /envmaps/uffizi/env_cos_512_z+.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/uffizi/env_cos_512_z+.hdr -------------------------------------------------------------------------------- /envmaps/uffizi/env_cos_512_z-.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/uffizi/env_cos_512_z-.hdr -------------------------------------------------------------------------------- /envmaps/uffizi/env_cos_64_x+.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/uffizi/env_cos_64_x+.hdr -------------------------------------------------------------------------------- /envmaps/uffizi/env_cos_64_x-.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/uffizi/env_cos_64_x-.hdr -------------------------------------------------------------------------------- /envmaps/uffizi/env_cos_64_y+.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/uffizi/env_cos_64_y+.hdr -------------------------------------------------------------------------------- /envmaps/uffizi/env_cos_64_y-.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/uffizi/env_cos_64_y-.hdr -------------------------------------------------------------------------------- /envmaps/uffizi/env_cos_64_z+.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/uffizi/env_cos_64_z+.hdr -------------------------------------------------------------------------------- /envmaps/uffizi/env_cos_64_z-.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/uffizi/env_cos_64_z-.hdr -------------------------------------------------------------------------------- /envmaps/uffizi/env_cos_8_x+.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/uffizi/env_cos_8_x+.hdr -------------------------------------------------------------------------------- /envmaps/uffizi/env_cos_8_x-.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/uffizi/env_cos_8_x-.hdr -------------------------------------------------------------------------------- /envmaps/uffizi/env_cos_8_y+.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/uffizi/env_cos_8_y+.hdr -------------------------------------------------------------------------------- /envmaps/uffizi/env_cos_8_y-.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/uffizi/env_cos_8_y-.hdr -------------------------------------------------------------------------------- /envmaps/uffizi/env_cos_8_z+.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/uffizi/env_cos_8_z+.hdr -------------------------------------------------------------------------------- /envmaps/uffizi/env_cos_8_z-.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/envmaps/uffizi/env_cos_8_z-.hdr -------------------------------------------------------------------------------- /hs-src/App.hs: -------------------------------------------------------------------------------- 1 | 2 | {-# LANGUAGE RecordWildCards 3 | , LambdaCase 4 | , FlexibleContexts 5 | , RankNTypes 6 | , TypeFamilies #-} 7 | 8 | module App ( run 9 | , module AppDefs 10 | ) where 11 | 12 | import Control.Lens 13 | import Control.Monad.Reader 14 | import Control.Monad.State 15 | import Control.Monad.Trans.Either 16 | import Control.Monad.STM 17 | import Control.Monad.Trans.Control 18 | import Control.Concurrent.STM.TQueue 19 | import qualified Graphics.Rendering.OpenGL as GL 20 | import qualified Graphics.UI.GLFW as GLFW 21 | import Text.Printf 22 | import Data.Time 23 | import Data.Maybe 24 | 25 | import AppDefs 26 | import GLFWHelpers 27 | import GLHelpers 28 | import Timing 29 | import Trace 30 | import Font 31 | import FrameBuffer 32 | import QuadRendering 33 | import qualified BoundedSequence as BS 34 | import Experiment 35 | import Median 36 | 37 | processAllEvents :: MonadIO m => TQueue a -> (a -> m ()) -> m () 38 | processAllEvents tq processEvent = 39 | (liftIO . atomically $ tryReadTQueue tq) >>= \case 40 | Just e -> processEvent e >> processAllEvents tq processEvent 41 | _ -> return () 42 | 43 | processGLFWEvent :: GLFWEvent -> AppIO () 44 | processGLFWEvent ev = do 45 | case ev of 46 | GLFWEventError e s -> do 47 | window <- view aeWindow 48 | liftIO $ do 49 | traceS TLError $ "GLFW Error " ++ show e ++ " " ++ show s 50 | GLFW.setWindowShouldClose window True 51 | GLFWEventKey win k _sc ks _mk | ks == GLFW.KeyState'Pressed -> 52 | case k of 53 | GLFW.Key'Escape -> do 54 | lastPress <- use asLastEscPress 55 | tick <- use asCurTick 56 | -- Only close when ESC has been pressed twice quickly 57 | when (tick - lastPress < 0.5) . 58 | liftIO $ GLFW.setWindowShouldClose win True 59 | asLastEscPress .= tick 60 | GLFW.Key'T -> view aeFB >>= \fb -> liftIO $ saveFrameBufferToPNG fb . 61 | map (\c -> if c `elem` ['/', '\\', ':', ' '] then '-' else c) 62 | . printf "Screenshot-%s.png" =<< show <$> getZonedTime 63 | GLFW.Key'V -> asVSync %= not >> setVSync 64 | -- Exit and switch to a different experiment 65 | GLFW.Key'Minus -> onRenderSettingsChage >> left ExpPrev 66 | GLFW.Key'Equal -> onRenderSettingsChage >> left ExpNext 67 | _ -> return () 68 | GLFWEventFramebufferSize _win _w _h -> resize 69 | _ -> return () 70 | runExperimentState $ experimentGLFWEvent ev -- Pass on event to the experiment 71 | 72 | -- Handle changes in window and frame buffer size 73 | resize :: (MonadReader AppEnv m, MonadState AppState m, MonadIO m) => m () 74 | resize = do 75 | window <- view aeWindow 76 | fb <- view aeFB 77 | liftIO $ do (w, h) <- GLFW.getFramebufferSize window 78 | setupViewport w h 79 | resizeFrameBuffer fb w h 80 | onRenderSettingsChage 81 | 82 | onRenderSettingsChage :: MonadState AppState m => m () 83 | onRenderSettingsChage = do 84 | -- Reset frame time measurements and frame index when the rendering settings have changed 85 | asFrameTimes %= BS.clear 86 | asFrameIdx .= 0 87 | 88 | draw :: AppIO () 89 | draw = do 90 | AppEnv { .. } <- ask 91 | AppState { .. } <- get 92 | -- Clear 93 | liftIO $ do 94 | GL.clearColor GL.$= (GL.Color4 1 0 1 1 :: GL.Color4 GL.GLclampf) 95 | GL.clear [GL.ColorBuffer, GL.DepthBuffer] 96 | GL.depthFunc GL.$= Just GL.Lequal 97 | -- Allow the experiment to draw into the framebuffer 98 | runExperimentState $ experimentDraw _aeFB _asCurTick 99 | -- Render everything quad based 100 | (liftIO $ GLFW.getFramebufferSize _aeWindow) >>= \(w, h) -> 101 | void . withQuadRenderBuffer _aeQR w h $ \qb -> do 102 | ftStr <- updateAndReturnFrameTimes 103 | (fbWdh, fbHgt) <- liftIO $ getFrameBufferDim _aeFB 104 | expDesc <- use asExperimentDesc 105 | vsync <- use asVSync 106 | statusString <- (++) ( "2x[ESC] Exit | Screensho[T] | %ix%i | %s\n" ++ 107 | "[V]Sync: %s | Exp. [-][=] %s | " 108 | ) 109 | <$> runExperimentState experimentStatusString 110 | liftIO $ do 111 | -- Draw frame buffer contents 112 | drawFrameBuffer _aeFB qb 0 0 (fromIntegral w) (fromIntegral h) 113 | -- FPS counter and mode / statistics / key bindings display 114 | let statusStringHgt = (succ . length $ filter (== '\n') statusString) * 12 115 | drawQuad qb 116 | 0 (fromIntegral h - fromIntegral statusStringHgt) 117 | (fromIntegral w) (fromIntegral h) 118 | 2 119 | FCBlack 120 | (TRBlend 0.5) 121 | Nothing 122 | QuadUVDefault 123 | drawTextWithShadow _aeFontTexture qb 3 (h - 12) $ printf 124 | statusString 125 | fbWdh 126 | fbHgt 127 | ftStr 128 | (if vsync then "On" else "Off") 129 | expDesc 130 | where drawTextWithShadow :: GL.TextureObject -> QuadRenderBuffer -> Int -> Int -> String -> IO () 131 | drawTextWithShadow tex qb x y str = do 132 | drawText tex qb (x + 1) (y - 1) 0x00000000 str 133 | drawText tex qb x y 0x0000FF00 str 134 | 135 | updateAndReturnFrameTimes :: MonadState AppState m => m String 136 | updateAndReturnFrameTimes = do 137 | frameTimes <- use $ asFrameTimes.to BS.toList 138 | curTick <- use asCurTick 139 | asFrameTimes %= BS.push_ curTick 140 | let frameDeltas = case frameTimes of (x:xs) -> goFD x xs; _ -> [] 141 | goFD prev (x:xs) = (prev - x) : goFD x xs 142 | goFD _ [] = [] 143 | fdMedian = fromMaybe 1 $ median frameDeltas 144 | fdWorst = case frameDeltas of [] -> 0; xs -> maximum xs 145 | fdBest = case frameDeltas of [] -> 0; xs -> minimum xs 146 | in return $ printf "%.2fFPS/%.1fms (L: %.2fms, H: %.2fms)" 147 | (1.0 / fdMedian) 148 | (fdMedian * 1000) 149 | (fdBest * 1000) 150 | (fdWorst * 1000) 151 | 152 | setVSync :: (MonadIO m, MonadState AppState m) => m () 153 | setVSync = use asVSync >>= \vsync -> liftIO . GLFW.swapInterval $ if vsync then 1 else 0 154 | 155 | run :: AppEnv -> AppState -> IO () 156 | run env st = 157 | -- Setup state, reader, OpenGL / GLFW and enter loop 158 | flip runReaderT env . flip evalStateT st $ do 159 | resize 160 | setVSync 161 | experimentLoop 2 162 | where -- Initialize / shutdown / switch experiment 163 | experimentLoop :: Int -> StateT AppState (ReaderT AppEnv IO) () 164 | experimentLoop expIdx = do 165 | -- We use the either to break out of the current experiment, and either exit 166 | -- or switch to a different one 167 | r <- runEitherT $ do 168 | -- Because of the existential type we have to call withExperiment from 169 | -- inside the lambda where we pattern match it out of the AnyWithExperiment. 170 | -- Also use monad-control to bring our stack across the IO of withExperiment 171 | curExp <- (!! expIdx) <$> view aeExperiments 172 | control $ \runMonad -> 173 | (\(AnyWithExperiment withExperiment') -> 174 | liftIO $ withExperiment' (runMonad . withExperimentInner expIdx) 175 | ) curExp 176 | numExp <- length <$> view aeExperiments 177 | -- Exit or keep running with a different experiment? 178 | case r of 179 | Left ExpNext -> experimentLoop $ wrapExpIdx (expIdx + 1) numExp 180 | Left ExpPrev -> experimentLoop $ wrapExpIdx (expIdx - 1) numExp 181 | Left ExpExit -> return () 182 | Right () -> return () 183 | where wrapExpIdx idx numExp | idx < 0 = numExp - 1 184 | | idx >= numExp = 0 185 | | otherwise = idx 186 | -- Experiment setup complete, store state and enter main loop 187 | withExperimentInner :: Experiment e => Int -> e -> AppIO () 188 | withExperimentInner expIdx expState = do 189 | let name = experimentName expState 190 | liftIO . traceS TLInfo $ "Switching to experiment: " ++ name 191 | numExp <- length <$> view aeExperiments 192 | asExperimentDesc .= printf "%i/%i: %s" (expIdx + 1) numExp name 193 | asExperiment .= AnyExperiment expState 194 | mainLoop 195 | -- Main loop 196 | mainLoop :: AppIO () 197 | mainLoop = do 198 | window <- view aeWindow 199 | asCurTick <~ liftIO getTick 200 | tqGLFW <- view aeGLFWEventsQueue 201 | processAllEvents tqGLFW processGLFWEvent 202 | -- GLFW / OpenGL 203 | draw 204 | liftIO $ {-# SCC swapAndPoll #-} do 205 | -- GL.flush 206 | -- GL.finish 207 | GLFW.swapBuffers window 208 | GLFW.pollEvents 209 | traceOnGLError $ Just "main loop" 210 | -- Drop the first three frame deltas, they are often outliers 211 | use asFrameIdx >>= \idx -> when (idx < 3) (asFrameTimes %= BS.clear) 212 | asFrameIdx += 1 213 | -- Done? 214 | flip unless mainLoop =<< liftIO (GLFW.windowShouldClose window) 215 | 216 | -------------------------------------------------------------------------------- /hs-src/AppDefs.hs: -------------------------------------------------------------------------------- 1 | 2 | {-# LANGUAGE TemplateHaskell 3 | , LambdaCase 4 | , RankNTypes #-} 5 | 6 | module AppDefs where 7 | 8 | import Control.Lens 9 | import Control.Monad.Reader 10 | import Control.Monad.State 11 | import Control.Monad.Trans.Either 12 | import Control.Concurrent.STM.TQueue 13 | import qualified Graphics.UI.GLFW as GLFW 14 | import qualified Graphics.Rendering.OpenGL as GL 15 | 16 | import GLFWHelpers 17 | import FrameBuffer 18 | import QuadRendering 19 | import qualified BoundedSequence as BS 20 | import Experiment 21 | 22 | -- Some definitions and utilities split out from the App module 23 | 24 | data AppState = AppState { _asCurTick :: !Double 25 | , _asLastEscPress :: !Double 26 | , _asFrameTimes :: !(BS.BoundedSequence Double) 27 | , _asFrameIdx :: !Int 28 | , _asVSync :: !Bool 29 | , _asExperiment :: !AnyExperiment 30 | , _asExperimentDesc :: !String 31 | } 32 | 33 | data AppEnv = AppEnv { _aeWindow :: !GLFW.Window 34 | , _aeGLFWEventsQueue :: !(TQueue GLFWEvent) 35 | , _aeFontTexture :: !GL.TextureObject 36 | , _aeFB :: !FrameBuffer 37 | , _aeQR :: !QuadRenderer 38 | , _aeExperiments :: ![AnyWithExperiment] 39 | } 40 | 41 | makeLenses ''AppState 42 | makeLenses ''AppEnv 43 | 44 | -- Our application runs in a reader / state / either / IO transformer stack 45 | data ExpResult = ExpNext | ExpPrev | ExpExit 46 | deriving (Show, Eq, Enum) 47 | type AppT m = EitherT ExpResult (StateT AppState (ReaderT AppEnv m)) 48 | type AppIO = AppT IO 49 | 50 | -- Run a computation in the State monad with the current experiment as its state. Store the 51 | -- final state back into ours. Note that we can't write this with the 'zoom' combinator 52 | -- from lens as we can't define a lens for an existential type 53 | runExperimentState :: (forall e m. (Experiment e, MonadIO m, MonadState e m) => m a) -> AppIO a 54 | runExperimentState f = 55 | use asExperiment >>= \case 56 | (AnyExperiment e) -> do 57 | (r, e') <- liftIO . flip runStateT e $ f 58 | asExperiment .= AnyExperiment e' 59 | return r 60 | 61 | -------------------------------------------------------------------------------- /hs-src/BoundedSequence.hs: -------------------------------------------------------------------------------- 1 | 2 | module BoundedSequence ( BoundedSequence 3 | , empty 4 | , push 5 | , push_ 6 | , pop 7 | , toList 8 | , clear 9 | ) where 10 | 11 | import qualified Data.Sequence as S 12 | import qualified Data.Foldable 13 | 14 | -- Sequence with a stack interface which drops elements pushed over a specified depth 15 | 16 | data BoundedSequence a = BoundedSequence !(S.Seq a) !Int 17 | deriving (Show) 18 | 19 | empty :: Int -> BoundedSequence a 20 | empty limit | limit >= 1 = BoundedSequence S.empty limit 21 | | otherwise = error "limit for BoundedSequence needs to be >= 1" 22 | 23 | -- Push element on the stack, truncate at the other end if we reached the limit, 24 | -- return new stack and truncated element (if over the limit) 25 | push :: a -> BoundedSequence a -> (BoundedSequence a, Maybe a) 26 | push x (BoundedSequence s limit) = 27 | let seqDropR sd = case S.viewr sd of (s' S.:> e) -> (s', Just e) 28 | S.EmptyR -> (sd, Nothing) 29 | boundedS | S.length s >= limit = seqDropR s 30 | | otherwise = (s, Nothing) 31 | in case boundedS of (s', e) -> (BoundedSequence (x S.<| s') limit, e) 32 | 33 | push_ :: a -> BoundedSequence a -> BoundedSequence a 34 | push_ x s = fst $ push x s 35 | 36 | -- LIFO pop 37 | pop :: BoundedSequence a -> (Maybe a, BoundedSequence a) 38 | pop bs@(BoundedSequence s limit) = 39 | case S.viewl s of (x S.:< s') -> (Just x , BoundedSequence s' limit) 40 | S.EmptyL -> (Nothing, bs) 41 | 42 | toList :: BoundedSequence a -> [a] 43 | toList (BoundedSequence s _) = Data.Foldable.toList s 44 | 45 | clear :: BoundedSequence a -> BoundedSequence a 46 | clear (BoundedSequence _ limit) = BoundedSequence S.empty limit 47 | 48 | -------------------------------------------------------------------------------- /hs-src/Experiment.hs: -------------------------------------------------------------------------------- 1 | 2 | {-# LANGUAGE ExistentialQuantification, RankNTypes, FlexibleContexts #-} 3 | 4 | module Experiment ( Experiment(..) 5 | , AnyExperiment(..) 6 | , AnyWithExperiment(..) 7 | , WithExperiment 8 | , EmptyExperiment 9 | ) where 10 | 11 | import Control.Monad.IO.Class 12 | import Control.Monad.State.Class 13 | 14 | import GLFWHelpers (GLFWEvent) 15 | import FrameBuffer (FrameBuffer) 16 | 17 | -- Existential wrappers for creating / using arbitrary experiments 18 | type WithExperiment e = forall a. Experiment e => (e -> IO a) -> IO a 19 | data AnyExperiment = forall e. Experiment e => AnyExperiment e 20 | data AnyWithExperiment = forall e. Experiment e => AnyWithExperiment (WithExperiment e) 21 | 22 | class Experiment e where 23 | -- Create experiment state and allow experiment to perform initialization and cleanup 24 | withExperiment :: WithExperiment e 25 | -- UI name of the experiment 26 | experimentName :: e -> String 27 | experimentName _ = "" 28 | -- UI status string, displaying current state, statistics, keybindings etc. 29 | experimentStatusString :: (MonadState e m, MonadIO m) => m String 30 | experimentStatusString = return "" 31 | -- Allow the experiment to draw into the framebuffer 32 | experimentDraw :: (MonadState e m, MonadIO m) => FrameBuffer -> Double -> m () 33 | experimentDraw _fb _tick = return () 34 | -- Allow the experiment to respond to keyboard / mouse events 35 | experimentGLFWEvent :: (MonadIO m, MonadState e m) => GLFWEvent -> m () 36 | experimentGLFWEvent _ = return () 37 | 38 | -- Dummy experiment for initialization etc. 39 | data EmptyExperiment = EmptyExperiment 40 | instance Experiment EmptyExperiment where 41 | withExperiment f = f EmptyExperiment 42 | experimentName _ = "EmptyExperiment" 43 | 44 | -------------------------------------------------------------------------------- /hs-src/Font.hs: -------------------------------------------------------------------------------- 1 | 2 | module Font (withFontTexture, drawText) where 3 | 4 | import Data.Word (Word8, Word32) 5 | import Data.Bits (shiftL, shiftR, (.&.)) 6 | import Data.Char (ord) 7 | import qualified Foreign.Marshal.Array (withArray) 8 | import qualified Data.Vector.Unboxed as VU 9 | import qualified Graphics.Rendering.OpenGL as GL 10 | import qualified Graphics.Rendering.OpenGL.GLU as GLU (build2DMipmaps) 11 | import Control.Exception 12 | import Control.Monad 13 | 14 | import GLHelpers 15 | import QuadRendering 16 | 17 | withFontTexture :: (GL.TextureObject -> IO a) -> IO a 18 | withFontTexture f = do 19 | traceOnGLError $ Just "withFontTexture begin" 20 | r <- bracket 21 | GL.genObjectName 22 | GL.deleteObjectName 23 | $ \tex -> do 24 | -- Font texture 25 | GL.textureBinding GL.Texture2D GL.$= Just tex 26 | setTextureFiltering GL.Texture2D TFMinOnly 27 | -- Convert font grid bitmap image from Word32 list into byte array 28 | let fontImgArray = 29 | VU.fromListN (fontGridWdh * fontGridHgt * fontCharWdh * fontCharHgt `div` 8) . 30 | concatMap (\x -> map (extractByte x) [0..3]) $ miscFixed6x12Data 31 | :: VU.Vector Word8 32 | -- Extract bits (reversed in byte), store transparent / opaque pixels in square texture 33 | let fontTex = [toRGBA $ texel x y | y <- [0..fontTexWdh - 1], x <- [0..fontTexWdh - 1]] 34 | where texel x y = (srcLookup x y .&. (1 `shiftL` (7 - (srcIdx x y `mod` 8)))) 35 | srcLookup x y | (x < fontImgWdh && y < fontImgHgt) = 36 | fontImgArray VU.! (srcIdx x y `div` 8) 37 | | otherwise = 0 38 | srcIdx x y = x + y * fontImgWdh 39 | toRGBA a = case a of 0 -> 0x0FFFFFF; _ -> 0xFFFFFFFF :: Word32 40 | Foreign.Marshal.Array.withArray fontTex $ \ptr -> 41 | -- TODO: Just use GPU MIP-map generation 42 | GLU.build2DMipmaps GL.Texture2D GL.RGBA' 43 | (fromIntegral fontTexWdh) 44 | (fromIntegral fontTexWdh) 45 | (GL.PixelData GL.RGBA GL.UnsignedByte ptr) 46 | traceOnGLError $ Just "withFontTexture begin inner" 47 | f tex 48 | traceOnGLError $ Just "withFontTexture after cleanup" 49 | return r 50 | 51 | drawText :: GL.TextureObject -> QuadRenderBuffer -> Int -> Int -> Word32 -> String -> IO () 52 | drawText tex qb x y color str = do 53 | let charAndPos = filter (\(_, _, c) -> c /= '\n') . 54 | scanl (\(x', y', _) a -> if a == '\n' 55 | then ((-1) , y' - 1, a) 56 | else (x' + 1, y' , a) 57 | ) ((-1), 0, '\n') $ str 58 | forM_ charAndPos $ \(xc, yc, chr) -> 59 | let xoffs = xc * fontCharWdh 60 | yoffs = yc * (fontCharHgt - 1) 61 | idx = ord chr 62 | tx = (idx `mod` fontGridWdh); 63 | ty = fontGridHgt - ((idx - (idx `mod` fontGridWdh)) `div` fontGridWdh + 1); 64 | ftx = fromIntegral (tx * fontCharWdh) / fromIntegral fontTexWdh; 65 | fty = fromIntegral (ty * fontCharHgt) / fromIntegral fontTexWdh; 66 | fontCharWdhTex = fromIntegral fontCharWdh / fromIntegral fontTexWdh 67 | fontCharHgtTex = fromIntegral fontCharHgt / fromIntegral fontTexWdh 68 | channel i = fromIntegral (extractByte color i) / 255.0 69 | in drawQuad qb 70 | (fromIntegral $ x + xoffs) 71 | (fromIntegral $ y + yoffs) 72 | (fromIntegral $ x + xoffs + fontCharWdh) 73 | (fromIntegral $ y + yoffs + fontCharHgt) 74 | 1 75 | (FCSolid $ RGBA (channel 0) (channel 1) (channel 2) 1) 76 | TRSrcAlpha 77 | (Just tex) 78 | $ QuadUV ftx fty (ftx + fontCharWdhTex) (fty + fontCharHgtTex) 79 | 80 | extractByte :: Word32 -> Int -> Word8 81 | extractByte x i = fromIntegral $ (x .&. (0xFF `shiftL` (i * 8))) `shiftR` (i * 8) 82 | 83 | -- Bit packed font data for a 16 x 16 character grid of 6 x 12 pixel characters 84 | fontGridWdh, fontGridHgt, fontImgWdh, fontImgHgt, fontCharWdh, fontCharHgt, fontTexWdh :: Int 85 | fontGridWdh = 16 86 | fontGridHgt = 16 87 | fontImgWdh = 96 88 | fontImgHgt = 192 89 | fontCharWdh = 6 90 | fontCharHgt = 12 91 | fontTexWdh = 256 92 | {-# NOINLINE miscFixed6x12Data #-} 93 | miscFixed6x12Data :: [Word32] 94 | miscFixed6x12Data = 95 | [ 0x00000000, 0x00000000, 0x20080200, 0x00000000, 0x00000000, 0x10080100, 0x711c2772, 0xc7f100c7 96 | , 0x088f701c, 0x8aa2288a, 0x28ca8828, 0x944889a2, 0x8aa2288a, 0x28aa8028, 0xa2288aa2, 0x8aa2288b 97 | , 0x289abe28, 0xa2288aa2, 0x711cc77a, 0x287a00c7, 0x222f8aa2, 0x00000008, 0x00000800, 0x00080000 98 | , 0x5208c252, 0x820000c5, 0x14885014, 0x2104a421, 0x010100a0, 0x00400008, 0x00000050, 0x00000000 99 | , 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00001800, 0x00000000, 0x00000000 100 | , 0x00000400, 0x00000000, 0x799ee779, 0xc7719ce7, 0x1cc7711c, 0x8aa2288a, 0x0882222a, 0x08822020 101 | , 0x799ee779, 0xcff320e7, 0x0882203c, 0x08822008, 0x288aa222, 0x088220a2, 0x711cc771, 0xc7711cc7 102 | , 0x1886611c, 0x00000000, 0x00000080, 0x00000000, 0x512c8520, 0x85200040, 0x14852014, 0x001a4240 103 | , 0x42400080, 0x00424000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 104 | , 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00800000, 0x00000000, 0x711c2772, 0xc77100c7 105 | , 0x2c84701c, 0x8aa2284a, 0x28caa228, 0x228788a2, 0x8aa2684a, 0x28aa9428, 0xa48488a2, 0x8aa2a8ea 106 | , 0x28aa8828, 0xa88488a2, 0x8aa2284b, 0x28aa9428, 0xa44489a2, 0x8aa2284a, 0x289aa228, 0x22278aa2 107 | , 0x711c2772, 0x287200c7, 0x1c248aa2, 0x00000000, 0x00080000, 0x00000000, 0x5208c202, 0x820000c5 108 | , 0x00805014, 0x2104a401, 0x010100a0, 0x00400008, 0x00000000, 0x00001800, 0x00000000, 0x00000000 109 | , 0x00000400, 0x00000000, 0x8aa2288a, 0xeffb9c2b, 0x1cc771be, 0x8aa2288a, 0x0882222a, 0x08822020 110 | , 0x8aa2288a, 0x0882202a, 0x08822020, 0xfbbeeffb, 0xcff320ef, 0x0882203c, 0x8aa2288a, 0x0882202a 111 | , 0x08822020, 0x8aa2288a, 0x0882222a, 0x08822020, 0x711cc771, 0xeffb9cc7, 0x1cc771be, 0x00000000 112 | , 0x00000080, 0x00000000, 0x512c8520, 0x85200040, 0x14852014, 0x001a4240, 0x42400080, 0x00424000 113 | , 0x02000000, 0x00600000, 0x00000000, 0x02000000, 0x00100000, 0x00000000, 0x0300e003, 0x000080a2 114 | , 0x1ce11028, 0x02000000, 0x00008062, 0x22811014, 0x02008000, 0x00008022, 0x9047780a, 0x02008000 115 | , 0x00008c26, 0x08255014, 0x0200e003, 0x00008c2e, 0x08a33028, 0x40188730, 0xc701800e, 0x004d5100 116 | , 0x20048248, 0x8000800e, 0x08024100, 0x10080148, 0x82008007, 0x00044100, 0x00040530, 0x85010000 117 | , 0x0002c300, 0x00180200, 0x82000000, 0x000c4100, 0x00000000, 0x00000000, 0x00000000, 0x00000200 118 | , 0x00000000, 0x00000000, 0xa82c8700, 0xe0011c82, 0x8007000a, 0x50928a00, 0x10020282, 0x40080814 119 | , 0x8b108a00, 0x50020ce2, 0x400a0828, 0x50b88a00, 0x90021280, 0x40caf914, 0xab108700, 0x570212e2 120 | , 0x400b000a, 0x01120200, 0x10020c42, 0x40080000, 0x020c8000, 0xe3011022, 0x80070000, 0x00000000 121 | , 0x05500e00, 0x3e000000, 0x00000000, 0x03000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 122 | , 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 123 | , 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 124 | , 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 125 | , 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 126 | , 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 127 | , 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 128 | , 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 129 | , 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 130 | , 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 131 | , 0x00002080, 0x00020000, 0x00000000, 0x00002080, 0x00010000, 0x00002104, 0x193ce8f1, 0x8f8814a2 132 | , 0x00802088, 0x2202288a, 0x44512a65, 0x00802008, 0x221c288a, 0x2222aa28, 0x00892008, 0x22a02c8a 133 | , 0x2152a228, 0x804a2010, 0xfa1eebf1, 0x2f8aa228, 0x80842088, 0x20000000, 0x00000000, 0x00802008 134 | , 0x20000000, 0x00000000, 0x00802008, 0x00000000, 0x00000000, 0x00002104, 0x00000000, 0x00000000 135 | , 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x03001c00, 0x00000000, 0x00000000 136 | , 0x04000200, 0x00000080, 0x791cef01, 0xc0891ec4, 0x9ca872a2, 0x8aa22802, 0x80882204, 0xa2a822a4 137 | , 0x8ba0e801, 0x808822c4, 0xa2a822b8, 0x8aa22800, 0x8088222e, 0xa2ac22a4, 0x791ccf01, 0x81f11cc4 138 | , 0x1c4b23a2, 0x08000810, 0x00808004, 0x00002020, 0x08000820, 0x80800003, 0x000060a0, 0x00000040 139 | , 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 140 | , 0x00000000, 0x00000000, 0x3e000000, 0x00000000, 0x00000000, 0x00c0011c, 0x219ca881, 0x8f8814c2 141 | , 0x00400890, 0x22224982, 0x88882a25, 0x00401010, 0x2202aa82, 0x84502a25, 0x00401010, 0x221c2ff2 142 | , 0x8220a228, 0x00402010, 0x22a0288a, 0x4151a228, 0x00404010, 0x22a2288a, 0x208aa228, 0x80484090 143 | , 0xfa1ccff1, 0x2f8aa228, 0x00458090, 0x00000000, 0x00000000, 0x00c2011c, 0x00000000, 0x00000000 144 | , 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 145 | , 0x00000000, 0x00000000, 0xf31c2f72, 0xc6891ce8, 0x9c28fa22, 0x4aa22482, 0x89882208, 0xa2288224 146 | , 0x4aa024ba, 0x81882608, 0xa2298228, 0x4b20e7ab, 0x81f820cf, 0xa22a8230, 0x4aa024ba, 0x81882008 147 | , 0xa2ac8228, 0x4aa2248a, 0x81882208, 0xa2688324, 0xf31ccf71, 0xc3899cef, 0x9c2882a2, 0x00000000 148 | , 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 149 | , 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000030, 0x119ccf31, 0x867108c7 150 | , 0x08000018, 0x12228448, 0x46888828, 0x00041018, 0xf8028248, 0x20888828, 0x08e22300, 0x900c8148 151 | , 0xe671042f, 0x08014018, 0x53848048, 0x268a04c8, 0x04e22318, 0x32828849, 0x208a0204, 0x22041000 152 | , 0x133e8730, 0xc0713ee3, 0x1c000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 153 | , 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x20000000 154 | , 0x00110000, 0x0000c000, 0x72148000, 0x82208066, 0x20066000, 0xaa3e0000, 0x8a200069, 0x10066088 155 | , 0x29148000, 0x4740800a, 0x10000008, 0x70148000, 0x42400084, 0x08e0033e, 0xa03e8000, 0x4740004a 156 | , 0x04000008, 0xab148500, 0x8a20082a, 0x04000088, 0x73008500, 0x82200824, 0x02000000, 0x20000500 157 | , 0x00110800, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 158 | , 0xfc000000, 0x80200082, 0x00000000, 0x00000000, 0x80200082, 0x00000000, 0x00000000, 0x8f200082 159 | , 0x000b51be, 0x003f0000, 0x80200082, 0x80045100, 0x00000000, 0x81200082, 0x00e453b0, 0x00c00f00 160 | , 0x86fc3ffe, 0x0c8e500c, 0x00000000, 0x88000882, 0x0ce4fb02, 0x00000000, 0x86000882, 0x8044000c 161 | , 0x0000f003, 0x81000882, 0x004300b0, 0x00000000, 0x80000882, 0x00000000, 0x00000000, 0x80000882 162 | , 0x00000000, 0x000000fc, 0x80000882, 0x00000000, 0x00400500, 0x00000000, 0x08002000, 0x00800a00 163 | , 0x00000000, 0x08002000, 0x204405a8, 0x00f800a2, 0x08002000, 0x20848a00, 0x000000a3, 0x08002000 164 | , 0x3044c589, 0x002000c2, 0x08002000, 0xa084ea03, 0x002080a3, 0xff03e038, 0xb96ec589, 0x00f800c0 165 | , 0x08020008, 0xc2a88a00, 0x00200c0e, 0x08020008, 0x827805a8, 0x00201208, 0x08020008, 0xe2a80a00 166 | , 0x00001208, 0x08020008, 0x01680500, 0x00000c88, 0x08020008, 0x00800a00, 0x00000000, 0x08020008 167 | ] 168 | 169 | -------------------------------------------------------------------------------- /hs-src/FrameBuffer.hs: -------------------------------------------------------------------------------- 1 | 2 | {-# LANGUAGE RecordWildCards, FlexibleContexts, LambdaCase, ScopedTypeVariables #-} 3 | 4 | module FrameBuffer ( withFrameBuffer 5 | , fillFrameBuffer 6 | , drawFrameBuffer 7 | , saveFrameBufferToPNG 8 | , resizeFrameBuffer 9 | , getFrameBufferDim 10 | , drawIntoFrameBuffer 11 | , FrameBuffer 12 | , Downscaling(..) 13 | ) where 14 | 15 | import Control.Monad 16 | import Control.Exception 17 | import Control.Monad.Trans 18 | import Control.Monad.Trans.Control 19 | import qualified Graphics.Rendering.OpenGL as GL 20 | import qualified Graphics.GL as GLR 21 | import Data.Word 22 | import Data.IORef 23 | import qualified Data.Vector.Storable.Mutable as VSM 24 | import qualified Data.Vector.Storable as VS 25 | import Text.Printf 26 | import Foreign.Storable 27 | import Foreign.Ptr 28 | import Foreign.ForeignPtr 29 | import qualified Codec.Picture as JP 30 | 31 | import GLHelpers 32 | import QuadRendering 33 | import Trace 34 | 35 | -- Simple 'frame buffer' interface where we can either directly write into an RGBA8 vector CPU 36 | -- side or render into a texture with the GPU and have it appear on screen, optionally with 37 | -- super sampling 38 | 39 | data FrameBuffer = FrameBuffer { fbTex :: !GL.TextureObject 40 | -- Ping-pong with two PBOs doesn't seem to help upload 41 | -- speed as long as we orphan our buffers anyway 42 | , fbPBO :: !GL.BufferObject 43 | , fbDim :: IORef (Int, Int) 44 | , fbFBO :: !GL.FramebufferObject 45 | , fbDownscaling :: !Downscaling 46 | } 47 | 48 | data Downscaling = HighQualityDownscaling | LowQualityDownscaling 49 | deriving (Show, Eq) 50 | 51 | withFrameBuffer :: Int -> Int -> Downscaling -> (FrameBuffer -> IO a) -> IO a 52 | withFrameBuffer w h fbDownscaling f = do 53 | traceOnGLError $ Just "withFrameBuffer begin" 54 | r <- bracket GL.genObjectName GL.deleteObjectName $ \fbTex -> 55 | bracket GL.genObjectName GL.deleteObjectName $ \fbPBO -> 56 | bracket GL.genObjectName GL.deleteObjectName $ \fbFBO -> do 57 | -- Setup texture 58 | GL.textureBinding GL.Texture2D GL.$= Just fbTex 59 | setTextureFiltering GL.Texture2D $ 60 | if fbDownscaling == HighQualityDownscaling 61 | then TFMinMag -- Need to generate MIP-maps after every change 62 | else TFMagOnly 63 | setTextureClampST GL.Texture2D -- No wrap-around artifacts at the FB borders 64 | -- Setup FBO 65 | GL.bindFramebuffer GL.Framebuffer GL.$= fbFBO 66 | GL.framebufferTexture2D GL.Framebuffer (GL.ColorAttachment 0) GL.Texture2D fbTex 0 67 | GL.drawBuffer GL.$= GL.FBOColorAttachment 0 68 | GL.bindFramebuffer GL.Framebuffer GL.$= GL.defaultFramebufferObject 69 | -- Setup texture, dimensions 70 | fbDim <- newIORef (0, 0) 71 | let fb = FrameBuffer { .. } 72 | resizeFrameBuffer fb w h 73 | -- Inner 74 | traceOnGLError $ Just "withFrameBuffer begin inner" 75 | f fb 76 | traceOnGLError $ Just "withFrameBuffer after cleanup" 77 | return r 78 | 79 | resizeFrameBuffer :: FrameBuffer -> Int -> Int -> IO () 80 | resizeFrameBuffer fb w h = do 81 | -- Limit requested size by maximum available and store. This can lead to some 82 | -- blurriness when drawing with high quality downscaling. For instance, a 640^2 83 | -- window size with a maximum render size of 1024^2 and 2x super sampling will 84 | -- not get the requested 1280^2, and there won't be a clean 1:4 pixel ratio, 85 | -- leading to some blurriness from the MIP-mapping filter. This is of course 86 | -- preferable to failing to allocate the FB altogether, but is the reason why 87 | -- sometimes higher levels of super sampling will reduce sharpness in the preview 88 | (maxWdh, maxHgt) <- maxRenderSize 89 | let aspect = fromIntegral w / fromIntegral h :: Double 90 | wdiff = max 0 $ w - maxWdh 91 | (clampWW, clampWH) = ( w - wdiff 92 | , truncate $ fromIntegral h - fromIntegral wdiff / aspect 93 | ) 94 | hdiff = max 0 $ clampWH - maxHgt 95 | (clampHW, clampHH) = ( truncate $ fromIntegral clampWW - fromIntegral hdiff * aspect 96 | , clampWH - hdiff 97 | ) 98 | writeIORef (fbDim fb) (clampHW, clampHH) 99 | -- Allocate texture and clear contents to black 100 | GL.textureBinding GL.Texture2D GL.$= Just (fbTex fb) 101 | GL.texImage2D GL.Texture2D 102 | GL.NoProxy 103 | 0 104 | GL.RGBA8 105 | (GL.TextureSize2D (fromIntegral clampHW) (fromIntegral clampHH)) 106 | 0 107 | (GL.PixelData GL.RGBA GL.UnsignedByte nullPtr) 108 | GL.textureBinding GL.Texture2D GL.$= Nothing 109 | void . drawIntoFrameBuffer fb $ \_ _ -> do 110 | GL.clearColor GL.$= (GL.Color4 0 0 0 1 :: GL.Color4 GL.GLclampf) 111 | GL.clear [GL.ColorBuffer] 112 | 113 | getFrameBufferDim :: FrameBuffer -> IO (Int, Int) 114 | getFrameBufferDim fb = readIORef $ fbDim fb 115 | 116 | -- Specify the frame buffer contents by filling a mutable vector 117 | fillFrameBuffer :: forall a m s. (MonadBaseControl IO m, MonadIO m) 118 | => FrameBuffer 119 | -> (Int -> Int -> VSM.MVector s Word32 -> m a) -- Run inner inside the base monad 120 | -> m (Maybe a) -- Return Nothing if mapping fails 121 | fillFrameBuffer fb@(FrameBuffer { .. }) f = do 122 | -- Map. If this function is nested inside another fillFrameBuffer with the same FrameBuffer, 123 | -- the mapping operation will fail as OpenGL does not allow two concurrent mappings. Hence, 124 | -- no need to check for this explicitly 125 | (w, h) <- liftIO $ readIORef fbDim 126 | r <- control $ \run -> liftIO $ do 127 | let bindPBO = GL.bindBuffer GL.PixelUnpackBuffer GL.$= Just fbPBO 128 | -- Prevent stalls by just allocating new PBO storage every time 129 | in bindPBO >> allocPBO fb >> GL.withMappedBuffer 130 | GL.PixelUnpackBuffer 131 | GL.WriteOnly 132 | ( \ptrPBO -> newForeignPtr_ ptrPBO >>= \fpPBO -> 133 | finally 134 | -- Run in outer base monad 135 | ( run $ Just <$> f w h (VSM.unsafeFromForeignPtr0 fpPBO $ fbSizeB w h) ) 136 | bindPBO -- Make sure we rebind our PBO, otherwise 137 | -- unmapping might fail if the inner 138 | -- modified the bound buffer objects 139 | ) 140 | ( \mf -> do traceS TLError $ "fillFrameBuffer - PBO mapping failure: " ++ show mf 141 | -- Looks like since the 1.0.0.0 change in monad-control we need 142 | -- some type annotations for this to work 143 | run $ (return Nothing :: m (Maybe a)) 144 | ) 145 | liftIO $ do 146 | -- Update frame buffer texture from the PBO data 147 | GL.textureBinding GL.Texture2D GL.$= Just fbTex 148 | GL.texSubImage2D GL.Texture2D 149 | 0 150 | (GL.TexturePosition2D 0 0) 151 | (GL.TextureSize2D (fromIntegral w) (fromIntegral h)) 152 | (GL.PixelData GL.RGBA GL.UnsignedByte nullPtr) 153 | when (fbDownscaling == HighQualityDownscaling) $ 154 | GLR.glGenerateMipmap GLR.GL_TEXTURE_2D 155 | -- Done 156 | GL.bindBuffer GL.PixelUnpackBuffer GL.$= Nothing 157 | GL.textureBinding GL.Texture2D GL.$= Nothing 158 | return r 159 | 160 | -- Specify the frame buffer contents by rendering into it 161 | -- http://www.opengl-tutorial.org/intermediate-tutorials/tutorial-14-render-to-texture/ 162 | drawIntoFrameBuffer :: forall a m. (MonadBaseControl IO m, MonadIO m) 163 | => FrameBuffer 164 | -> (Int -> Int -> m a) 165 | -> m (Maybe a) 166 | drawIntoFrameBuffer FrameBuffer { .. } f = do 167 | oldVP <- liftIO $ GL.get GL.viewport 168 | control $ \run -> finally 169 | ( do GL.bindFramebuffer GL.Framebuffer GL.$= fbFBO 170 | (w, h) <- readIORef fbDim 171 | setupViewport w h 172 | -- GL.framebufferStatus is unfortunately broken in OpenGL 2.9.2.0 173 | -- (see https://github.com/haskell-opengl/OpenGL/issues/51), so 174 | -- we're using the raw APIs as a backup 175 | GLR.glCheckFramebufferStatus GLR.GL_FRAMEBUFFER >>= \case 176 | r | r == GLR.GL_FRAMEBUFFER_COMPLETE -> run $ Just <$> f w h 177 | | otherwise -> do 178 | traceS TLError $ printf 179 | "drawIntoFrameBuffer, glCheckFramebufferStatus: 0x%x" 180 | (fromIntegral r :: Int) 181 | -- Looks like since the 1.0.0.0 change in monad-control we need 182 | -- some type annotations for this to work 183 | run $ (return Nothing :: m (Maybe a)) 184 | ) 185 | ( do GL.bindFramebuffer GL.Framebuffer GL.$= GL.defaultFramebufferObject 186 | GL.viewport GL.$= oldVP 187 | when (fbDownscaling == HighQualityDownscaling) $ do 188 | -- TODO: When rendering tiles we're computing the MIP-chain for the 189 | -- full frame buffer texture after rendering each individual tile. 190 | -- We would need to make the frame buffer tiling aware and render 191 | -- into a tile sized texture (later copied into the full frame 192 | -- buffer) to address this 193 | GL.textureBinding GL.Texture2D GL.$= Just fbTex 194 | GLR.glGenerateMipmap GLR.GL_TEXTURE_2D 195 | GL.textureBinding GL.Texture2D GL.$= Nothing 196 | ) 197 | 198 | -- Draw quad with frame buffer texture 199 | drawFrameBuffer :: FrameBuffer -> QuadRenderBuffer -> Float -> Float -> Float -> Float -> IO () 200 | drawFrameBuffer FrameBuffer { .. } qb x1 y1 x2 y2 = 201 | drawQuad qb x1 y1 x2 y2 10 FCWhite TRNone (Just fbTex) QuadUVDefault 202 | 203 | fbSizeB :: Integral a => Int -> Int -> a 204 | fbSizeB w h = fromIntegral $ w * h * sizeOf (0 :: Word32) 205 | 206 | -- Allocate new frame buffer sized backing storage for the bound PBO 207 | allocPBO :: FrameBuffer -> IO () 208 | allocPBO FrameBuffer { .. } = do 209 | (w, h) <- readIORef fbDim 210 | GL.bufferData GL.PixelUnpackBuffer GL.$= ( fbSizeB w h -- In bytes 211 | , nullPtr -- Just allocate 212 | , GL.StreamDraw -- Dynamic 213 | ) 214 | 215 | saveFrameBufferToPNG :: FrameBuffer -> FilePath -> IO () 216 | saveFrameBufferToPNG FrameBuffer { .. } fn = do 217 | GL.textureBinding GL.Texture2D GL.$= Just fbTex 218 | (w, h) <- getCurTex2DSize 219 | img <- VSM.new $ fbSizeB w h :: IO (VSM.IOVector JP.Pixel8) 220 | VSM.unsafeWith img $ GL.getTexImage GL.Texture2D 0 . GL.PixelData GL.RGBA GL.UnsignedByte 221 | GL.textureBinding GL.Texture2D GL.$= Nothing 222 | let flipAndFixA img' = 223 | JP.generateImage 224 | ( \x y -> case JP.pixelAt img' x (h - 1 - y) of 225 | JP.PixelRGBA8 r g b _ -> JP.PixelRGBA8 r g b 0xFF 226 | ) w h 227 | in JP.savePngImage fn . JP.ImageRGBA8 . flipAndFixA . JP.Image w h =<< VS.freeze img 228 | traceS TLInfo $ "Saved screenshot of framebuffer to " ++ fn 229 | 230 | -------------------------------------------------------------------------------- /hs-src/GLFWHelpers.hs: -------------------------------------------------------------------------------- 1 | 2 | module GLFWHelpers ( withWindow 3 | , GLFWEvent(..) 4 | , highDPIScaleFactor 5 | ) where 6 | 7 | import Control.Exception 8 | import Control.Monad 9 | import Control.Concurrent.STM 10 | import qualified Graphics.UI.GLFW as GLFW 11 | import qualified Graphics.GL as GLR 12 | 13 | -- Various utility functions related to GLFW 14 | 15 | withWindow :: Int -> Int -> Bool -> String -> TQueue GLFWEvent -> (GLFW.Window -> IO ()) -> IO () 16 | withWindow w h srgb title tq = 17 | bracket 18 | ( do GLFW.setErrorCallback . Just $ errorCallback tq 19 | True <- GLFW.init 20 | -- GLFW.windowHint $ GLFW.WindowHint'Samples 4 21 | -- GLFW.windowHint $ GLFW.WindowHint'Decorated False 22 | GLFW.windowHint $ GLFW.WindowHint'Resizable True 23 | when srgb . GLFW.windowHint $ GLFW.WindowHint'sRGBCapable True 24 | modernOpenGL 25 | Just window <- GLFW.createWindow w h title Nothing Nothing 26 | registerCallbacks window tq 27 | GLFW.makeContextCurrent $ Just window 28 | when srgb $ GLR.glEnable GLR.GL_FRAMEBUFFER_SRGB 29 | return window 30 | ) 31 | ( \window -> do GLFW.destroyWindow window 32 | GLFW.terminate 33 | ) 34 | 35 | -- >2.1, no backwards compatibility on OS X 36 | -- http://www.glfw.org/faq.html#how-do-i-create-an-opengl-30-context 37 | modernOpenGL :: IO () 38 | modernOpenGL = do 39 | GLFW.windowHint $ GLFW.WindowHint'OpenGLProfile GLFW.OpenGLProfile'Core 40 | GLFW.windowHint $ GLFW.WindowHint'OpenGLForwardCompat True 41 | GLFW.windowHint $ GLFW.WindowHint'ContextVersionMajor 3 42 | GLFW.windowHint $ GLFW.WindowHint'ContextVersionMinor 3 43 | 44 | highDPIScaleFactor :: GLFW.Window -> IO Double 45 | highDPIScaleFactor win = do 46 | (scWdh, _) <- GLFW.getWindowSize win 47 | (pxWdh, _) <- GLFW.getFramebufferSize win 48 | return $ fromIntegral pxWdh / fromIntegral scWdh 49 | 50 | -- Convert GLFW callbacks into events delivered to a queue 51 | 52 | data GLFWEvent = GLFWEventError 53 | !GLFW.Error 54 | !String 55 | | GLFWEventKey 56 | !GLFW.Window 57 | !GLFW.Key 58 | !Int 59 | !GLFW.KeyState 60 | !GLFW.ModifierKeys 61 | | GLFWEventWindowSize 62 | !GLFW.Window 63 | !Int 64 | !Int 65 | | GLFWEventFramebufferSize 66 | !GLFW.Window 67 | !Int 68 | !Int 69 | | GLFWEventMouseButton 70 | !GLFW.Window 71 | !GLFW.MouseButton 72 | !GLFW.MouseButtonState 73 | !GLFW.ModifierKeys 74 | | GLFWEventCursorPos 75 | !GLFW.Window 76 | !Double 77 | !Double 78 | | GLFWEventScroll 79 | !GLFW.Window 80 | !Double 81 | !Double 82 | 83 | errorCallback :: TQueue GLFWEvent -> GLFW.Error -> String -> IO () 84 | errorCallback tq e s = atomically . writeTQueue tq $ GLFWEventError e s 85 | 86 | keyCallback :: TQueue GLFWEvent 87 | -> GLFW.Window 88 | -> GLFW.Key 89 | -> Int 90 | -> GLFW.KeyState 91 | -> GLFW.ModifierKeys -> IO () 92 | keyCallback tq win k sc ka mk = atomically . writeTQueue tq $ GLFWEventKey win k sc ka mk 93 | 94 | windowSizeCallback :: TQueue GLFWEvent -> GLFW.Window -> Int -> Int -> IO () 95 | windowSizeCallback tq win w h = atomically . writeTQueue tq $ GLFWEventWindowSize win w h 96 | 97 | framebufferSizeCallback :: TQueue GLFWEvent -> GLFW.Window -> Int -> Int -> IO () 98 | framebufferSizeCallback tq win w h = 99 | atomically . writeTQueue tq $ GLFWEventFramebufferSize win w h 100 | 101 | mouseButtonCallback :: TQueue GLFWEvent 102 | -> GLFW.Window 103 | -> GLFW.MouseButton 104 | -> GLFW.MouseButtonState 105 | -> GLFW.ModifierKeys 106 | -> IO () 107 | mouseButtonCallback tq win bttn st mk = 108 | atomically . writeTQueue tq $ GLFWEventMouseButton win bttn st mk 109 | 110 | cursorPosCallback :: TQueue GLFWEvent -> GLFW.Window -> Double -> Double -> IO () 111 | cursorPosCallback tq win x y = atomically . writeTQueue tq $ GLFWEventCursorPos win x y 112 | 113 | scrollCallback :: TQueue GLFWEvent -> GLFW.Window -> Double -> Double -> IO () 114 | scrollCallback tq win x y = atomically . writeTQueue tq $ GLFWEventScroll win x y 115 | 116 | registerCallbacks :: GLFW.Window -> TQueue GLFWEvent -> IO () 117 | registerCallbacks window tq = do 118 | GLFW.setKeyCallback window . Just $ keyCallback tq 119 | GLFW.setWindowSizeCallback window . Just $ windowSizeCallback tq 120 | GLFW.setFramebufferSizeCallback window . Just $ framebufferSizeCallback tq 121 | GLFW.setMouseButtonCallback window . Just $ mouseButtonCallback tq 122 | GLFW.setCursorPosCallback window . Just $ cursorPosCallback tq 123 | GLFW.setScrollCallback window . Just $ scrollCallback tq 124 | 125 | -------------------------------------------------------------------------------- /hs-src/GLHelpers.hs: -------------------------------------------------------------------------------- 1 | 2 | {-# LANGUAGE LambdaCase, ScopedTypeVariables #-} 3 | 4 | module GLHelpers ( getGLStrings 5 | , getGLExtensionList 6 | , traceOnGLError 7 | , throwOnGLError 8 | , getCurTex2DSize 9 | , disableVAOAndShaders 10 | , Transparency(..) 11 | , setTransparency 12 | , setTextureFiltering 13 | , setTextureClampST 14 | , TextureFiltering(..) 15 | , setupViewport 16 | , maxRenderSize 17 | , genObjectNameResource 18 | ) where 19 | 20 | import qualified Graphics.Rendering.OpenGL as GL 21 | import qualified Graphics.GL as GLR 22 | import qualified Graphics.UI.GLFW as GLFW 23 | import Control.Monad 24 | import Control.Exception 25 | import Control.Monad.Trans.Resource 26 | import Text.Printf 27 | import Data.Maybe 28 | import Foreign.Marshal.Alloc 29 | import Foreign.Marshal.Array 30 | import Foreign.Storable 31 | import Foreign.Ptr 32 | import Foreign.C.String 33 | 34 | import Trace 35 | 36 | -- Various utility functions related to OpenGL 37 | 38 | getErrors :: Maybe String -> IO (Maybe String) 39 | getErrors context = 40 | GL.get GL.errors >>= \case 41 | [] -> return Nothing 42 | err -> return . Just $ 43 | "OpenGL Error" ++ maybe ": " (\c -> " (" ++ c ++ "): ") context ++ show err 44 | 45 | traceOnGLError :: Maybe String -> IO () 46 | traceOnGLError context = getErrors context >>= maybe (return ()) (traceS TLError) 47 | 48 | throwOnGLError :: Maybe String -> IO () 49 | throwOnGLError context = getErrors context >>= maybe (return ()) (throwIO . ErrorCall) 50 | 51 | -- No wrapper around the OpenGL 3 extension APIs yet, have to use the raw ones 52 | getNumExtensions :: IO Int 53 | getNumExtensions = 54 | alloca $ \(ptr :: Ptr GLR.GLint) -> 55 | GLR.glGetIntegerv GLR.GL_NUM_EXTENSIONS ptr >> fromIntegral <$> peek ptr 56 | getExtensionStr :: Int -> IO String 57 | getExtensionStr i = 58 | peekCString =<< castPtr <$> GLR.glGetStringi GLR.GL_EXTENSIONS (fromIntegral i) 59 | 60 | getGLExtensionList :: IO [String] 61 | getGLExtensionList = 62 | getNumExtensions >>= \numExt -> forM [0..numExt - 1] $ \i -> getExtensionStr i 63 | 64 | -- Take the minimum of the maximum viewport and texture size to figure out 65 | -- how large of a frame buffer we can allocate and render into 66 | maxRenderSize :: IO (Int, Int) 67 | maxRenderSize = 68 | withArray [0, 0] $ \ptr -> do 69 | GLR.glGetIntegerv GLR.GL_MAX_VIEWPORT_DIMS ptr 70 | [vpWdh, vpHgt] <- peekArray 2 ptr 71 | GLR.glGetIntegerv GLR.GL_MAX_TEXTURE_SIZE ptr 72 | texDim <- peek ptr 73 | return (fromIntegral $ min vpWdh texDim, fromIntegral $ max vpHgt texDim) 74 | 75 | getGLStrings :: IO String 76 | getGLStrings = do 77 | numExt <- getNumExtensions 78 | (w, h) <- maxRenderSize 79 | printf 80 | ( "OpenGL - Vendor: %s · Renderer: %s · Version: %s · GLSL: %s · Num Extensions: %i" ++ 81 | " · Max FB Res: %ix%i\nGLFW - Version: %s" 82 | ) 83 | <$> GL.get GL.vendor 84 | <*> GL.get GL.renderer 85 | <*> GL.get GL.glVersion 86 | <*> GL.get GL.shadingLanguageVersion 87 | <*> pure numExt 88 | <*> pure w 89 | <*> pure h 90 | <*> (fromJust <$> GLFW.getVersionString) 91 | 92 | getCurTex2DSize :: IO (Int, Int) 93 | getCurTex2DSize = (\(GL.TextureSize2D w h) -> (fromIntegral w, fromIntegral h)) 94 | <$> (GL.get $ GL.textureSize2D GL.Texture2D 0) 95 | 96 | data TextureFiltering = TFNone | TFMinMag | TFMinOnly | TFMagOnly 97 | 98 | setTextureFiltering :: GL.ParameterizedTextureTarget t => t -> TextureFiltering -> IO () 99 | setTextureFiltering target TFNone = 100 | GL.textureFilter target GL.$= ((GL.Nearest, Nothing ), GL.Nearest) 101 | setTextureFiltering target TFMinMag = 102 | GL.textureFilter target GL.$= ((GL.Linear', Just GL.Linear'), GL.Linear') 103 | setTextureFiltering target TFMinOnly = 104 | GL.textureFilter target GL.$= ((GL.Linear', Just GL.Linear'), GL.Nearest) 105 | setTextureFiltering target TFMagOnly = 106 | GL.textureFilter target GL.$= ((GL.Nearest, Nothing ), GL.Linear') 107 | 108 | setTextureClampST :: GL.ParameterizedTextureTarget t => t -> IO () 109 | setTextureClampST target = 110 | forM_ [GL.S, GL.T] $ 111 | \x -> GL.textureWrapMode target x GL.$= (GL.Repeated, GL.ClampToEdge) 112 | 113 | data Transparency = TRNone 114 | | TRBlend !Float 115 | | TRSrcAlpha 116 | deriving (Eq, Ord, Show) 117 | 118 | setTransparency :: Transparency -> IO () 119 | setTransparency trans = 120 | case trans of TRNone -> GL.blend GL.$= GL.Disabled 121 | TRBlend weight -> do 122 | GL.blend GL.$= GL.Enabled 123 | GL.blendFunc GL.$= (GL.ConstantAlpha, GL.OneMinusConstantAlpha) 124 | GL.blendColor GL.$= GL.Color4 0 0 0 (realToFrac weight :: GL.GLfloat) 125 | TRSrcAlpha -> do 126 | GL.blend GL.$= GL.Enabled 127 | GL.blendFunc GL.$= (GL.SrcAlpha, GL.OneMinusSrcAlpha) 128 | 129 | -- Disable vertex attribute arrays and shaders 130 | disableVAOAndShaders :: IO () 131 | disableVAOAndShaders = do 132 | GL.bindVertexArrayObject GL.$= Nothing 133 | GL.currentProgram GL.$= Nothing 134 | 135 | setupViewport :: Int -> Int -> IO () 136 | setupViewport w h = GL.viewport GL.$= (GL.Position 0 0, GL.Size (fromIntegral w) (fromIntegral h)) 137 | 138 | -- Allocate OpenGL object name in ResourceT 139 | genObjectNameResource :: (GL.GeneratableObjectName a, MonadResource m) => m a 140 | genObjectNameResource = snd <$> allocate GL.genObjectName GL.deleteObjectName 141 | 142 | -------------------------------------------------------------------------------- /hs-src/GLSLHelpers.hs: -------------------------------------------------------------------------------- 1 | 2 | {-# LANGUAGE FlexibleContexts, LambdaCase #-} 3 | 4 | module GLSLHelpers ( mkShaderProgram 5 | , compileShaderProgram 6 | , tryMkShaderResource 7 | , setTextureShader 8 | , setOrtho2DProjMatrix 9 | ) where 10 | 11 | import qualified Graphics.Rendering.OpenGL as GL 12 | import qualified Graphics.GL as GLR 13 | import qualified Data.ByteString as B 14 | import Data.Either 15 | import Control.Exception 16 | import Control.Monad 17 | import Control.Monad.Except 18 | import Control.Monad.Trans.Resource 19 | import Foreign.Marshal.Array 20 | 21 | import GLHelpers 22 | 23 | -- GLSL shaders and support functions 24 | 25 | mkShaderProgram :: B.ByteString 26 | -> B.ByteString 27 | -> [(String, GL.AttribLocation)] 28 | -> IO (Either String GL.Program) 29 | mkShaderProgram vsSrc fsSrc attribLocations = 30 | -- Only delete the program on error 31 | bracketOnError GL.createProgram GL.deleteObjectName $ \shdProg -> do 32 | compileShaderProgram vsSrc fsSrc attribLocations shdProg >>= 33 | \case Left err -> do -- The bracket only deletes in case of an exception, 34 | -- still need to delete manually in case of a monadic error 35 | GL.deleteObjectName shdProg 36 | return $ Left err 37 | Right () -> return $ Right shdProg 38 | 39 | compileShaderProgram :: B.ByteString 40 | -> B.ByteString 41 | -> [(String, GL.AttribLocation)] 42 | -> GL.Program 43 | -> IO (Either String ()) 44 | compileShaderProgram vsSrc fsSrc attribLocations shdProg = 45 | -- Delete the shaders (don't need them after linking) 46 | bracket (GL.createShader GL.VertexShader ) (GL.deleteObjectName) $ \shdVtx -> 47 | bracket (GL.createShader GL.FragmentShader) (GL.deleteObjectName) $ \shdFrag -> 48 | runExceptT $ do 49 | compile shdVtx vsSrc 50 | compile shdFrag fsSrc 51 | liftIO $ GL.attachShader shdProg shdVtx >> GL.attachShader shdProg shdFrag 52 | -- Need to specify attribute locations before we link 53 | liftIO . forM_ attribLocations $ 54 | \(name, loc) -> GL.attribLocation shdProg name GL.$= loc 55 | link shdProg 56 | liftIO $ GL.detachShader shdProg shdVtx >> GL.detachShader shdProg shdFrag 57 | liftIO . traceOnGLError $ Just "compileShaderProgram end" 58 | -- Compile and link helpers 59 | where compile shd src = do 60 | liftIO $ do GL.shaderSourceBS shd GL.$= src 61 | GL.compileShader shd 62 | success <- liftIO $ GL.get $ GL.compileStatus shd 63 | unless success $ do 64 | errLog <- liftIO . GL.get $ GL.shaderInfoLog shd 65 | throwError errLog 66 | link prog = do 67 | liftIO $ GL.linkProgram prog 68 | success <- liftIO . GL.get $ GL.linkStatus prog 69 | unless success $ do 70 | errLog <- liftIO $ GL.get $ GL.programInfoLog prog 71 | throwError errLog 72 | 73 | -- Helper for mkShaderProgam, guaranteeing deallocation through ResourceT and 74 | -- reports errors through MonadError 75 | tryMkShaderResource :: (MonadError String m, MonadIO m, MonadResource m) 76 | => IO (Either String GL.Program) 77 | -> m GL.Program 78 | tryMkShaderResource f = 79 | allocate f (GL.deleteObjectNames . rights . (: [])) >>= (either throwError return . snd) 80 | 81 | setTextureShader :: GL.BindableTextureTarget t 82 | => GL.TextureObject 83 | -> t 84 | -> Int 85 | -> GL.Program 86 | -> String 87 | -> IO () 88 | setTextureShader tex target tu prog uname = do 89 | (GL.get $ GL.uniformLocation prog uname) >>= \loc -> 90 | GL.uniform loc GL.$= GL.Index1 (fromIntegral tu :: GL.GLint) 91 | GL.activeTexture GL.$= GL.TextureUnit (fromIntegral tu) 92 | GL.textureBinding target GL.$= Just tex 93 | 94 | setOrtho2DProjMatrix :: GL.Program -> String -> Int -> Int -> IO () 95 | setOrtho2DProjMatrix prog uniform w h = do 96 | GL.UniformLocation loc <- GL.get $ GL.uniformLocation prog uniform 97 | let ortho2D = [ 2 / fromIntegral w, 0, 0, -1, 98 | 0, 2 / fromIntegral h, 0, -1, 99 | 0, 0, (-2) / 1000, -1, 100 | 0, 0, 0, 1 101 | ] :: [GL.GLfloat] 102 | withArray ortho2D $ \ptr -> GLR.glUniformMatrix4fv loc 1 1 {- transpose -} ptr 103 | 104 | -------------------------------------------------------------------------------- /hs-src/GoLPatterns.hs: -------------------------------------------------------------------------------- 1 | 2 | module GoLPatterns ( acorn 3 | , gun 4 | , spacefill 5 | , ark 6 | ) where 7 | 8 | acorn, gun, spacefill, ark :: [String] 9 | 10 | acorn = [ ".O....." 11 | , "...O..." 12 | , "OO..OOO" 13 | ] 14 | 15 | gun = [ "........................O..........." 16 | , "......................O.O..........." 17 | , "............OO......OO............OO" 18 | , "...........O...O....OO............OO" 19 | , "OO........O.....O...OO.............." 20 | , "OO........O...O.OO....O.O..........." 21 | , "..........O.....O.......O..........." 22 | , "...........O...O...................." 23 | , "............OO......................" 24 | ] 25 | 26 | -- http://www.radicaleye.com/lifepage/patterns/max.html 27 | spacefill = [ ".....O.O....................." 28 | , "....O..O....................." 29 | , "...OO........................" 30 | , "..O.........................." 31 | , ".OOOO........................" 32 | , "O....O......................." 33 | , "O..O........................." 34 | , "O..O........................." 35 | , ".O.........OOO...OOO........." 36 | , "..OOOO.O..O..O...O..O........" 37 | , "...O...O.....O...O..........." 38 | , "....O........O...O..........." 39 | , "....O.O......O...O..........." 40 | , "............................." 41 | , "...OOO.....OOO...OOO........." 42 | , "...OO.......O.....O.........." 43 | , "...OOO......OOOOOOO.........." 44 | , "...........O.......O........." 45 | , "....O.O...OOOOOOOOOOO........" 46 | , "...O..O..O............OO....." 47 | , "...O.....OOOOOOOOOOOO...O...." 48 | , "...O...O.............O...O..." 49 | , "....O...OOOOOOOOOOOO.....O..." 50 | , ".....OO............O..O..O..." 51 | , "........OOOOOOOOOOO...O.O...." 52 | , ".........O.......O..........." 53 | , "..........OOOOOOO......OOO..." 54 | , "..........O.....O.......OO..." 55 | , ".........OOO...OOO.....OOO..." 56 | , "............................." 57 | , "...........O...O......O.O...." 58 | , "...........O...O........O...." 59 | , "...........O...O.....O...O..." 60 | , "........O..O...O..O..O.OOOO.." 61 | , ".........OOO...OOO.........O." 62 | , ".........................O..O" 63 | , ".........................O..O" 64 | , ".......................O....O" 65 | , "........................OOOO." 66 | , "..........................O.." 67 | , "........................OO..." 68 | , ".....................O..O...." 69 | , ".....................O.O....." 70 | ] 71 | 72 | -- http://www.argentum.freeserve.co.uk/lex_a.htm#ark 73 | ark = 74 | [ "...........................O...." 75 | , "............................O..." 76 | , ".............................O.." 77 | , "............................O..." 78 | , "...........................O...." 79 | , ".............................OOO" 80 | , "................................" 81 | , "................................" 82 | , "................................" 83 | , "................................" 84 | , "................................" 85 | , "................................" 86 | , "................................" 87 | , "................................" 88 | , "................................" 89 | , "................................" 90 | , "................................" 91 | , "................................" 92 | , "................................" 93 | , "................................" 94 | , "................................" 95 | , "................................" 96 | , "................................" 97 | , "................................" 98 | , "................................" 99 | , "OO.............................." 100 | , "..O............................." 101 | , "..O............................." 102 | , "...OOOO........................." 103 | ] 104 | 105 | -------------------------------------------------------------------------------- /hs-src/Main.hs: -------------------------------------------------------------------------------- 1 | 2 | {-# LANGUAGE RecordWildCards, FlexibleContexts #-} 3 | 4 | module Main (main) where 5 | 6 | import GHC.Conc (getNumProcessors) 7 | import Control.Concurrent (setNumCapabilities) 8 | import Control.Concurrent.STM.TQueue 9 | import Data.List 10 | import qualified System.Info as SI 11 | 12 | import App 13 | import Trace 14 | import GLFWHelpers 15 | import GLHelpers 16 | import Timing 17 | import Font 18 | import FrameBuffer 19 | import QuadRendering 20 | import qualified BoundedSequence as BS 21 | import Experiment 22 | import RustSineExperiment() -- Disabled, just for testing 23 | import RustGoLExperiment 24 | import RustNBodyExperiment 25 | import RustRasterizerExperiment 26 | 27 | runOnAllCores :: IO () 28 | runOnAllCores = GHC.Conc.getNumProcessors >>= setNumCapabilities 29 | 30 | traceSystemInfo :: IO () 31 | traceSystemInfo = do 32 | cpus <- GHC.Conc.getNumProcessors 33 | traceS TLInfo =<< 34 | ( (++) . concat . intersperse " · " $ 35 | [ "System - OS: " ++ SI.os 36 | , "Arch: " ++ SI.arch 37 | , "CPUs: " ++ show cpus 38 | , concat [ "Compiler: " 39 | , SI.compilerName 40 | , " / " 41 | , show SI.compilerVersion 42 | ] 43 | ] 44 | ) 45 | <$> (("\n" ++) <$> getGLStrings) 46 | -- mapM_ (traceS TLInfo) =<< getGLExtensionList 47 | 48 | main :: IO () 49 | main = do 50 | runOnAllCores 51 | withTrace Nothing True False True TLInfo $ do 52 | _aeGLFWEventsQueue <- newTQueueIO 53 | let w = 512 54 | h = 512 55 | in withWindow w h False "Viewer" _aeGLFWEventsQueue $ \_aeWindow -> 56 | withFontTexture $ \_aeFontTexture -> 57 | withFrameBuffer w h LowQualityDownscaling $ \_aeFB -> 58 | withQuadRenderer 4096 $ \_aeQR -> 59 | (withExperiment :: WithExperiment EmptyExperiment) $ \emptyExperiment -> do 60 | traceSystemInfo 61 | _asCurTick <- getTick 62 | let _aeExperiments = 63 | [ AnyWithExperiment (withExperiment :: WithExperiment RustGoLExperiment ) 64 | , AnyWithExperiment (withExperiment :: WithExperiment RustNBodyExperiment) 65 | , AnyWithExperiment (withExperiment :: WithExperiment RustRasterizerExperiment) 66 | ] 67 | ae = AppEnv { .. } 68 | as = AppState { _asLastEscPress = -1 69 | , _asFrameTimes = BS.empty 60 -- Average over last N FPS 70 | , _asFrameIdx = 0 71 | , _asVSync = False 72 | , _asExperiment = AnyExperiment emptyExperiment 73 | , _asExperimentDesc = "" 74 | , .. 75 | } 76 | in run ae as 77 | 78 | -------------------------------------------------------------------------------- /hs-src/Median.hs: -------------------------------------------------------------------------------- 1 | 2 | module Median ( median 3 | ) where 4 | 5 | import Data.List 6 | 7 | median :: (Fractional a, Ord a) => [a] -> Maybe a 8 | median xs | null xs = Nothing 9 | | odd len = Just $ sorted !! mid 10 | | even len = Just meanMedian 11 | | otherwise = Nothing 12 | where len = length sorted 13 | mid = len `div` 2 14 | meanMedian = (sorted !! (mid - 1) + sorted !! mid) / 2 15 | sorted = sort xs 16 | 17 | -------------------------------------------------------------------------------- /hs-src/QQPlainText.hs: -------------------------------------------------------------------------------- 1 | 2 | module QQPlainText ( plaintext 3 | ) where 4 | 5 | import Language.Haskell.TH 6 | import Language.Haskell.TH.Quote 7 | 8 | -- Simple Quasi Quoter inserting its contents as a String where it is called 9 | 10 | plaintext :: QuasiQuoter 11 | plaintext = QuasiQuoter { quoteExp = quotePlainTextExp 12 | , quotePat = undefined 13 | , quoteDec = undefined 14 | , quoteType = undefined 15 | } 16 | 17 | quotePlainTextExp :: String -> Q Exp 18 | quotePlainTextExp = dataToExpQ (const Nothing) 19 | 20 | -------------------------------------------------------------------------------- /hs-src/QuadShaderSource.hs: -------------------------------------------------------------------------------- 1 | 2 | {-# LANGUAGE QuasiQuotes #-} 3 | 4 | module QuadShaderSource ( vsSrcBasic 5 | , fsSrcBasic 6 | , fsColOnlySrcBasic 7 | ) where 8 | 9 | import qualified Data.Text as T 10 | import qualified Data.Text.Encoding as TE 11 | import qualified Data.ByteString as B 12 | 13 | import QQPlainText 14 | 15 | -- Shader source for basic vertex and fragment shaders 16 | vsSrcBasic, fsSrcBasic, fsColOnlySrcBasic :: B.ByteString 17 | 18 | vsSrcBasic = TE.encodeUtf8 . T.pack $ 19 | [plaintext| #version 330 core 20 | uniform mat4 in_mvp; 21 | in vec3 in_pos; 22 | in vec4 in_col; 23 | in vec2 in_uv; 24 | out vec4 fs_col; 25 | out vec2 fs_uv; 26 | void main() 27 | { 28 | gl_Position = in_mvp * vec4(in_pos, 1.0); 29 | fs_col = in_col; 30 | fs_uv = in_uv; 31 | } 32 | |] 33 | 34 | fsSrcBasic = TE.encodeUtf8 . T.pack $ 35 | [plaintext| #version 330 core 36 | in vec4 fs_col; 37 | in vec2 fs_uv; 38 | uniform sampler2D tex; 39 | out vec4 frag_color; 40 | void main() 41 | { 42 | frag_color = fs_col * texture(tex, fs_uv); 43 | } 44 | |] 45 | 46 | fsColOnlySrcBasic = TE.encodeUtf8 . T.pack $ 47 | [plaintext| #version 330 core 48 | in vec4 fs_col; 49 | out vec4 frag_color; 50 | void main() 51 | { 52 | frag_color = fs_col; 53 | } 54 | |] 55 | 56 | -------------------------------------------------------------------------------- /hs-src/QuadTypes.hs: -------------------------------------------------------------------------------- 1 | 2 | module QuadTypes ( RGBA(..) 3 | , FillColor(..) 4 | , QuadUV(..) 5 | ) where 6 | 7 | -- Types shared between different modules generating / processing / storing quads for 8 | -- OpenGL rendering. Put in their own module to reduce logical and compile time dependency 9 | -- between them 10 | 11 | data RGBA = RGBA {-# UNPACK #-} !Float 12 | {-# UNPACK #-} !Float 13 | {-# UNPACK #-} !Float 14 | {-# UNPACK #-} !Float 15 | deriving (Eq, Show) 16 | 17 | data FillColor = FCWhite 18 | | FCBlack 19 | | FCSolid !RGBA 20 | | FCBottomTopGradient !RGBA !RGBA 21 | | FCLeftRightGradient !RGBA !RGBA 22 | deriving (Eq, Show) 23 | 24 | data QuadUV = QuadUVDefault 25 | | QuadUV {-# UNPACK #-} !Float -- UV Bottom Left 26 | {-# UNPACK #-} !Float 27 | {-# UNPACK #-} !Float -- UV Top Right 28 | {-# UNPACK #-} !Float 29 | deriving (Eq, Show) 30 | 31 | -------------------------------------------------------------------------------- /hs-src/RustGoLExperiment.hs: -------------------------------------------------------------------------------- 1 | 2 | {-# LANGUAGE RecordWildCards 3 | , ForeignFunctionInterface 4 | , TemplateHaskell 5 | , BangPatterns 6 | , LambdaCase 7 | , FlexibleContexts #-} 8 | 9 | module RustGoLExperiment ( RustGoLExperiment 10 | ) where 11 | 12 | import Control.Monad.IO.Class 13 | import Control.Lens 14 | import Control.Monad 15 | import Control.Monad.State.Class 16 | import Control.Concurrent.MVar 17 | import Control.Concurrent.Async 18 | import Control.Exception 19 | import Foreign.C.Types 20 | import Foreign.Ptr 21 | import Data.Word 22 | import Data.Maybe 23 | import Text.Printf 24 | import qualified Data.Vector.Storable.Mutable as VSM 25 | import qualified Data.Vector.Storable as VS 26 | import qualified Graphics.UI.GLFW as GLFW 27 | 28 | import Experiment 29 | import FrameBuffer 30 | import Timing 31 | import qualified BoundedSequence as BS 32 | import Median 33 | import qualified GoLPatterns as GP 34 | import GLFWHelpers 35 | 36 | -- Game of Life 37 | 38 | data GoLStats = GoLStats !Int !Double 39 | deriving (Show, Eq) 40 | 41 | newtype NumWorkers = NumWorkers { getNumWorkers :: Int } 42 | 43 | data RustGoLExperiment = RustGoLExperiment { -- Serialize main / worker thread access to Rust code. 44 | -- Also contains the number of worker threads the 45 | -- Rust code should use 46 | rgolLock :: MVar NumWorkers 47 | -- Statistics from the worker thread 48 | , rgolStats :: MVar GoLStats 49 | } 50 | 51 | makeLenses ''RustGoLExperiment 52 | 53 | instance Experiment RustGoLExperiment where 54 | withExperiment f = do setPatternNoLock GP.ark 55 | rgolLock <- newMVar $ NumWorkers 1 56 | rgolStats <- newMVar $ GoLStats 0 1 57 | withAsync (golWorker rgolLock rgolStats) $ \_ -> 58 | f $ RustGoLExperiment { .. } 59 | experimentName _ = "RustGoL" 60 | experimentDraw fb _tick = 61 | gets rgolLock >>= \lock -> 62 | liftIO . void $ withMVar lock $ \_ -> 63 | fillFrameBuffer fb $ \w h vec -> 64 | VSM.unsafeWith vec $ \pvec -> 65 | golDraw (fromIntegral w) (fromIntegral h) pvec 66 | experimentStatusString = do 67 | GoLStats ngen avgtime <- liftIO . readMVar =<< gets rgolStats 68 | nt <- liftIO . readMVar =<< gets rgolLock 69 | return $ printf ( "256^2 Grid, %iGs, %.2fms, %iGPS\n[RGAFK] Pattern | Threads [T][t]: %i " 70 | ++ "(Simulation and Rendering is decoupled)" 71 | ) 72 | ngen 73 | (avgtime * 1000) 74 | (round $ 1 / avgtime :: Int) 75 | (getNumWorkers nt) 76 | experimentGLFWEvent ev = do 77 | case ev of 78 | GLFWEventKey _win k _sc ks mk | ks == GLFW.KeyState'Pressed -> 79 | case k of 80 | GLFW.Key'R -> randomizePattern 81 | GLFW.Key'G -> setPattern GP.gun 82 | GLFW.Key'A -> setPattern GP.acorn 83 | GLFW.Key'F -> setPattern GP.spacefill 84 | GLFW.Key'K -> setPattern GP.ark 85 | GLFW.Key'T | GLFW.modifierKeysShift mk -> modifyNumWorkers pred 86 | | otherwise -> modifyNumWorkers succ 87 | _ -> return () 88 | where modifyNumWorkers action = 89 | (liftIO . flip modifyMVar_ 90 | (return . NumWorkers . min 16 . max 1 . action . getNumWorkers)) 91 | =<< gets rgolLock 92 | 93 | _ -> return () 94 | 95 | -- Worker thread does computation, gets stalled when we draw / modify the grid 96 | golWorker :: MVar NumWorkers -> MVar GoLStats -> IO () 97 | golWorker lock stats = go (BS.empty 30) (0 :: Int) 98 | where go !bs !ngen = do 99 | -- Timed GoL step 100 | time <- withMVar lock $ \nt -> 101 | fst <$> timeIt (golStep . fromIntegral $ getNumWorkers nt) 102 | -- Update stats and keep going 103 | let bs' = BS.push_ time bs 104 | modifyMVar stats $ \_ -> 105 | return ( GoLStats ngen (fromMaybe 1 . median . BS.toList $ bs') 106 | , () 107 | ) 108 | go bs' (ngen + 1) 109 | 110 | setPattern :: (MonadState RustGoLExperiment m, MonadIO m) => [String] -> m () 111 | setPattern asciiPat = 112 | gets rgolLock >>= \lock -> 113 | liftIO . withMVar lock $ \_ -> 114 | setPatternNoLock asciiPat 115 | 116 | -- Set the grid from an ASCII drawing of a GoL pattern 117 | setPatternNoLock :: [String] -> IO () 118 | setPatternNoLock asciiPat = 119 | let w = case asciiPat of 120 | (x:_) -> length x 121 | _ -> 0 122 | h = length asciiPat 123 | v = VS.fromList $ concatMap (map (\case { 'O' -> 1; _ -> 0 })) asciiPat 124 | in (VS.length v == w * h) `assert` VS.unsafeWith v $ \pvec -> 125 | golSetPattern (fromIntegral w) (fromIntegral h) pvec 126 | 127 | randomizePattern :: (MonadState RustGoLExperiment m, MonadIO m) => m () 128 | randomizePattern = 129 | gets rgolLock >>= \lock -> 130 | liftIO . withMVar lock $ \_ -> 131 | golRandomize 132 | 133 | foreign import ccall "gol_draw" golDraw :: CInt -> CInt -> Ptr Word32 -> IO () 134 | foreign import ccall "gol_step" golStep :: CInt -> IO () 135 | foreign import ccall "gol_randomize" golRandomize :: IO () 136 | foreign import ccall "gol_set_pattern" golSetPattern :: CInt -> CInt -> Ptr Word8 -> IO () 137 | 138 | -------------------------------------------------------------------------------- /hs-src/RustNBodyExperiment.hs: -------------------------------------------------------------------------------- 1 | 2 | {-# LANGUAGE RecordWildCards 3 | , ForeignFunctionInterface 4 | , TemplateHaskell 5 | , BangPatterns 6 | , FlexibleContexts #-} 7 | 8 | module RustNBodyExperiment ( RustNBodyExperiment 9 | ) where 10 | 11 | import Control.Monad.IO.Class 12 | import Control.Lens 13 | import Control.Monad 14 | import Control.Monad.State.Class 15 | import Foreign.C.Types 16 | import Foreign.Ptr 17 | import Data.Word 18 | import Data.Maybe 19 | import Text.Printf 20 | import qualified Data.Vector.Storable.Mutable as VSM 21 | import qualified Graphics.UI.GLFW as GLFW 22 | 23 | import Experiment 24 | import FrameBuffer 25 | import Timing 26 | import qualified BoundedSequence as BS 27 | import Median 28 | import GLFWHelpers 29 | 30 | -- N-Body Simulation 31 | 32 | data RustNBodyExperiment = RustNBodyExperiment 33 | { _rnbNumSteps :: !Int 34 | , _rnbTimes :: !(BS.BoundedSequence Double) 35 | , _rnbTimeStep :: !Double 36 | , _rnbTheta :: !Double 37 | , _rnbNumThreads :: !Int 38 | } 39 | 40 | makeLenses ''RustNBodyExperiment 41 | instance Experiment RustNBodyExperiment where 42 | withExperiment f = do liftIO $ nbStableOrbits 10000 0.5 30.0 43 | f $ RustNBodyExperiment { _rnbNumSteps = 0 44 | , _rnbTimes = BS.empty 30 45 | , _rnbTimeStep = 0.01 46 | , _rnbTheta = 0.85 47 | , _rnbNumThreads = 1 48 | } 49 | experimentName _ = "RustNBody" 50 | experimentDraw fb _tick = do 51 | dt <- use rnbTimeStep 52 | theta <- use rnbTheta 53 | nthreads <- use rnbNumThreads 54 | -- Simulate first 55 | time <- fst <$> liftIO (timeIt $ nbStepBarnesHut (realToFrac theta) 56 | (realToFrac dt) 57 | (fromIntegral nthreads)) 58 | void . liftIO . fillFrameBuffer fb $ \w h vec -> 59 | VSM.unsafeWith vec $ \pvec -> 60 | nbDraw (fromIntegral w) (fromIntegral h) pvec 61 | rnbNumSteps += 1 62 | rnbTimes %= BS.push_ time 63 | experimentStatusString = do 64 | RustNBodyExperiment { .. } <- get 65 | let avgtime = fromMaybe 1 . median . BS.toList $ _rnbTimes 66 | np <- liftIO (fromIntegral <$> nbNumParticles :: IO Int) 67 | return $ printf ( "%i Steps, %.1fSPS/%.2fms | %s Bodies\n" ++ 68 | "[QWE] Scene | Time Step [X][x]: %.4f | Theta [A][a]: %.2f | " ++ 69 | "Threads [P][p]: %i" 70 | ) 71 | _rnbNumSteps 72 | (1 / avgtime) 73 | (avgtime * 1000) 74 | ( if np > 999 75 | then show (np `div` 1000) ++ "K" 76 | else show np 77 | ) 78 | _rnbTimeStep 79 | _rnbTheta 80 | _rnbNumThreads 81 | experimentGLFWEvent ev = do 82 | case ev of 83 | GLFWEventKey _win k _sc ks mk | ks == GLFW.KeyState'Pressed -> 84 | case k of 85 | GLFW.Key'Q -> liftIO $ nbStableOrbits 10000 0.5 30.0 86 | GLFW.Key'W -> liftIO $ nbRandomDisk 10000 87 | GLFW.Key'E -> liftIO $ nbStableOrbits 5 5.0 40.0 88 | GLFW.Key'X | GLFW.modifierKeysShift mk -> rnbTimeStep //= 2 89 | | otherwise -> rnbTimeStep *= 2 90 | GLFW.Key'A | GLFW.modifierKeysShift mk -> 91 | rnbTheta %= max 0.0 . min 0.95 . (\x -> x - 0.05) 92 | | otherwise -> 93 | rnbTheta %= max 0.0 . min 0.95 . (\x -> x + 0.05) 94 | GLFW.Key'P | GLFW.modifierKeysShift mk -> 95 | rnbNumThreads %= max 1 . min 16 . pred 96 | | otherwise -> 97 | rnbNumThreads %= max 1 . min 16 . succ 98 | _ -> return () 99 | _ -> return () 100 | 101 | foreign import ccall "nb_draw" nbDraw :: CInt -> CInt -> Ptr Word32 -> IO () 102 | foreign import ccall "nb_step_brute_force" _nbStepBruteForce :: CFloat -> IO () 103 | foreign import ccall "nb_step_barnes_hut" nbStepBarnesHut :: CFloat -> CFloat -> CInt -> IO () 104 | foreign import ccall "nb_random_disk" nbRandomDisk :: CInt -> IO () 105 | foreign import ccall "nb_stable_orbits" nbStableOrbits :: CInt -> CFloat -> CFloat -> IO () 106 | foreign import ccall "nb_num_particles" nbNumParticles :: IO CInt 107 | 108 | -------------------------------------------------------------------------------- /hs-src/RustRasterizerExperiment.hs: -------------------------------------------------------------------------------- 1 | 2 | {-# LANGUAGE RecordWildCards 3 | , ForeignFunctionInterface 4 | , TemplateHaskell 5 | , FlexibleContexts #-} 6 | 7 | module RustRasterizerExperiment ( RustRasterizerExperiment 8 | ) where 9 | 10 | import Control.Monad.IO.Class 11 | import Control.Lens hiding (Index) 12 | import Control.Monad.State.Class 13 | import Foreign.C.Types 14 | import Foreign.C.String 15 | import Foreign.Ptr 16 | import Data.Word 17 | import Data.Maybe 18 | import Text.Printf 19 | import qualified Data.Vector.Storable.Mutable as VSM 20 | import qualified Graphics.UI.GLFW as GLFW 21 | 22 | import Experiment 23 | import FrameBuffer 24 | import Timing 25 | import qualified BoundedSequence as BS 26 | import Median 27 | import GLFWHelpers 28 | import WrapEnum 29 | 30 | -- Software Rasterization 31 | 32 | data Mode = Point | Line | Fill 33 | deriving (Eq, Show, Enum, Bounded) 34 | 35 | data Index = Index { idxVal :: !Int 36 | , idxMax :: !Int 37 | } 38 | 39 | idxSucc :: Index -> Index 40 | idxSucc Index { .. } | idxVal >= idxMax = Index 0 idxMax 41 | | otherwise = Index (idxVal + 1) idxMax 42 | 43 | idxPred :: Index -> Index 44 | idxPred Index { .. } | idxVal <= 0 = Index idxMax idxMax 45 | | otherwise = Index (idxVal - 1) idxMax 46 | 47 | instance Show Index where 48 | show Index { .. } = printf "%i/%i" (idxVal + 1) (idxMax + 1) 49 | 50 | data RustRasterizerExperiment = RustRasterizerExperiment 51 | { _rrTimes :: !(BS.BoundedSequence Double) 52 | , _rrShadePerPixel :: !Bool 53 | , _rrMode :: !Mode 54 | , _rrMeshIdx :: !Index 55 | , _rrShaderIdx :: !Index 56 | , _rrCMIdx :: !Index 57 | , _rrBgIdx :: !Index 58 | } 59 | 60 | makeLenses ''RustRasterizerExperiment 61 | 62 | instance Experiment RustRasterizerExperiment where 63 | withExperiment f = do 64 | num_mesh <- fromIntegral <$> rastGetNumMeshes 65 | num_shader <- fromIntegral <$> rastGetNumShaders 66 | num_cm <- fromIntegral <$> rastGetNumCMSets 67 | num_bg <- fromIntegral <$> rastGetNumBackgrounds 68 | f $ RustRasterizerExperiment { _rrTimes = BS.empty 60 69 | , _rrShadePerPixel = False 70 | , _rrMode = Fill 71 | , _rrMeshIdx = Index 0 (num_mesh - 1) 72 | , _rrShaderIdx = Index 5 (num_shader - 1) 73 | , _rrCMIdx = Index 0 (num_cm - 1) 74 | , _rrBgIdx = Index 0 (num_bg - 1) 75 | } 76 | experimentName _ = "RustRasterizer" 77 | experimentDraw fb tick = do 78 | RustRasterizerExperiment { .. } <- get 79 | mbtime <- liftIO . fillFrameBuffer fb $ \w h vec -> 80 | VSM.unsafeWith vec $ \pvec -> 81 | fst <$> timeIt (rastDraw (fromIntegral $ fromEnum _rrShadePerPixel) 82 | (fromIntegral $ fromEnum _rrMode ) 83 | (fromIntegral $ idxVal _rrMeshIdx ) 84 | (fromIntegral $ idxVal _rrShaderIdx ) 85 | (fromIntegral $ idxVal _rrCMIdx ) 86 | (fromIntegral $ idxVal _rrBgIdx ) 87 | (realToFrac tick) 88 | (fromIntegral w) 89 | (fromIntegral h) 90 | pvec) 91 | case mbtime of 92 | Just time -> rrTimes %= BS.push_ time 93 | Nothing -> return () 94 | experimentStatusString = do 95 | RustRasterizerExperiment { .. } <- get 96 | let avgtime = fromMaybe 1 . median . BS.toList $ _rrTimes 97 | mesh_idx = fromIntegral $ idxVal _rrMeshIdx 98 | shader_idx = fromIntegral $ idxVal _rrShaderIdx 99 | cm_idx = fromIntegral $ idxVal _rrCMIdx 100 | num_tri <- liftIO $ rastGetMeshTriCnt mesh_idx 101 | mesh_name <- liftIO $ rastGetMeshName mesh_idx >>= peekCString 102 | shader_name <- liftIO $ rastGetShaderName shader_idx >>= peekCString 103 | cm_name <- liftIO $ rastGetCMSetName cm_idx >>= peekCString 104 | return $ printf ( "%.1fFPS/%.2fms | [M]ode: %s\n" ++ 105 | "%s | Background [1][2] %s | Mesh [Q][W] %s: %s (%s)\n" ++ 106 | "Shader [A][S] %s: %s | Env [Z][X] %s: %s | [B]enchmark" 107 | ) 108 | (1 / avgtime) 109 | (avgtime * 1000) 110 | (show _rrMode) 111 | ( if _rrShadePerPixel 112 | then "[P]erPixel" 113 | else "[P]erVertex" 114 | ) 115 | (show _rrBgIdx) 116 | (show _rrMeshIdx) 117 | mesh_name 118 | ( if num_tri > 1000 119 | then printf "%.1fK Tri" (fromIntegral num_tri / 1000 :: Float) 120 | else printf "%i Tri" (fromIntegral num_tri :: Int ) 121 | :: String 122 | ) 123 | (show _rrShaderIdx) 124 | shader_name 125 | (show _rrCMIdx) 126 | cm_name 127 | experimentGLFWEvent ev = do 128 | case ev of 129 | GLFWEventKey _win k _sc ks _mk | ks == GLFW.KeyState'Pressed -> 130 | case k of 131 | GLFW.Key'B -> liftIO rastBenchmark 132 | GLFW.Key'M -> rrMode %= wrapSucc 133 | GLFW.Key'P -> rrShadePerPixel %= not 134 | GLFW.Key'Q -> rrMeshIdx %= idxPred 135 | GLFW.Key'W -> rrMeshIdx %= idxSucc 136 | GLFW.Key'A -> rrShaderIdx %= idxPred 137 | GLFW.Key'S -> rrShaderIdx %= idxSucc 138 | GLFW.Key'Z -> rrCMIdx %= idxPred 139 | GLFW.Key'X -> rrCMIdx %= idxSucc 140 | GLFW.Key'1 -> rrBgIdx %= idxPred 141 | GLFW.Key'2 -> rrBgIdx %= idxSucc 142 | _ -> return () 143 | _ -> return () 144 | 145 | foreign import ccall "rast_draw" rastDraw :: CInt -- Shader per-pixel (bool)? 146 | -> CInt -- Render mode enum 147 | -> CInt -- Mesh index 148 | -> CInt -- Shader index 149 | -> CInt -- Environment map index 150 | -> CInt -- Background index 151 | -> CDouble -- Tick 152 | -> CInt -- Framebuffer width 153 | -> CInt -- Framebuffer height 154 | -> Ptr Word32 -- Framebuffer pointer 155 | -> IO () 156 | 157 | foreign import ccall "rast_get_num_meshes" rastGetNumMeshes :: IO CInt -- Number of meshes 158 | 159 | foreign import ccall "rast_get_mesh_name" rastGetMeshName :: CInt -- Mesh index 160 | -> IO CString -- Mesh name 161 | 162 | foreign import ccall "rast_get_mesh_tri_cnt" rastGetMeshTriCnt :: CInt -- Mesh index 163 | -> IO CInt -- Triangle count 164 | 165 | foreign import ccall "rast_get_num_shaders" rastGetNumShaders :: IO CInt -- Number of shaders 166 | 167 | foreign import ccall "rast_get_shader_name" rastGetShaderName :: CInt -- Shader index 168 | -> IO CString -- Shader name 169 | 170 | foreign import ccall "rast_get_num_cm_sets" rastGetNumCMSets :: IO CInt -- Number of CM sets 171 | 172 | foreign import ccall "rast_get_cm_set_name" rastGetCMSetName :: CInt -- CM index 173 | -> IO CString -- CM set name 174 | 175 | foreign import ccall "rast_get_num_backgrounds" rastGetNumBackgrounds :: IO CInt -- Number of BGs 176 | 177 | foreign import ccall "rast_benchmark" rastBenchmark :: IO () 178 | 179 | -------------------------------------------------------------------------------- /hs-src/RustSineExperiment.hs: -------------------------------------------------------------------------------- 1 | 2 | {-# LANGUAGE ForeignFunctionInterface 3 | , TemplateHaskell 4 | , FlexibleContexts #-} 5 | 6 | module RustSineExperiment ( RustSineExperiment 7 | ) where 8 | 9 | import Control.Monad.IO.Class 10 | import Control.Lens 11 | import Foreign.C.Types 12 | import Foreign.Ptr 13 | import Data.Word 14 | import Data.Maybe 15 | import Text.Printf 16 | import qualified Data.Vector.Storable.Mutable as VSM 17 | 18 | import Experiment 19 | import FrameBuffer 20 | import Timing 21 | import qualified BoundedSequence as BS 22 | import Median 23 | 24 | -- Simple 2D scrolling sine waves 25 | 26 | data RustSineExperiment = RustSineExperiment { _rseTime :: !(BS.BoundedSequence Double) } 27 | 28 | makeLenses ''RustSineExperiment 29 | 30 | instance Experiment RustSineExperiment where 31 | withExperiment f = f $ RustSineExperiment (BS.empty 30) 32 | experimentName _ = "RustSine" 33 | experimentDraw fb tick = do 34 | mbtime <- liftIO . fillFrameBuffer fb $ \w h vec -> 35 | VSM.unsafeWith vec $ \pvec -> 36 | fst <$> timeIt (sineScroller (fromIntegral w) (fromIntegral h) pvec tick) 37 | case mbtime of 38 | Just time -> rseTime %= BS.push_ time 39 | Nothing -> return () 40 | experimentStatusString = do 41 | times <- use $ rseTime.to BS.toList 42 | return . printf "%.2fms" . (* 1000) . fromMaybe 1 $ median times 43 | 44 | foreign import ccall "sine_scroller" sineScroller :: CInt -> CInt -> Ptr Word32 -> Double -> IO () 45 | 46 | -------------------------------------------------------------------------------- /hs-src/Setup.hs: -------------------------------------------------------------------------------- 1 | import Distribution.Simple 2 | main = defaultMain 3 | -------------------------------------------------------------------------------- /hs-src/Timing.hs: -------------------------------------------------------------------------------- 1 | 2 | module Timing ( getTick 3 | , timeIt 4 | ) where 5 | 6 | import Control.Exception 7 | import Data.Time.Clock 8 | import Control.Monad.IO.Class 9 | import System.IO.Unsafe 10 | 11 | -- Timing functions 12 | 13 | -- TODO: Consider just using the criterion package for all performance measurements 14 | -- http://hackage.haskell.org/package/criterion 15 | 16 | {-# NOINLINE startTime #-} 17 | startTime :: UTCTime 18 | startTime = unsafePerformIO getCurrentTime 19 | 20 | -- In seconds 21 | getTick :: IO Double 22 | getTick = do 23 | -- Make sure startTime has been evaluated, otherwise the getCurrentTime in the 24 | -- unsafePerformIO might be evaluated after the getCurrentTime here, returning a 25 | -- negative tick on the first call to getTick 26 | st <- evaluate startTime 27 | (realToFrac . flip diffUTCTime st) <$> getCurrentTime 28 | 29 | timeIt :: MonadIO m => m a -> m (Double, a) 30 | timeIt f = do 31 | start <- liftIO getCurrentTime 32 | r <- f 33 | end <- liftIO getCurrentTime 34 | return (realToFrac $ diffUTCTime end start, r) 35 | 36 | -------------------------------------------------------------------------------- /hs-src/Trace.hs: -------------------------------------------------------------------------------- 1 | 2 | {-# LANGUAGE OverloadedStrings #-} 3 | 4 | module Trace ( withTrace 5 | , TraceLevel(..) 6 | , traceT 7 | , traceS 8 | , traceB 9 | , traceAndThrow 10 | ) where 11 | 12 | -- Execution tracing for multiple threads into file / stdout 13 | 14 | import System.IO 15 | import System.IO.Unsafe (unsafePerformIO) 16 | import qualified System.Console.ANSI as A 17 | import Control.Concurrent.MVar 18 | import Control.Exception 19 | import Control.Monad 20 | import Control.Concurrent 21 | import qualified Data.Text as T 22 | import qualified Data.Text.IO as TI 23 | import qualified Data.Text.Encoding as E 24 | import qualified Data.ByteString as B 25 | import Data.Time 26 | import Data.List 27 | import Data.Monoid 28 | import Text.Printf 29 | 30 | data TraceLevel = TLNone | TLError | TLWarn | TLInfo 31 | deriving (Eq, Enum) 32 | 33 | data TraceSettings = TraceSettings { tsFile :: Maybe Handle 34 | , tsEchoOn :: Bool 35 | , tsColorOn :: Bool 36 | , tsLevel :: TraceLevel 37 | } 38 | 39 | -- The well-known unsafePerformIO hack. It would be a bit cumbersome to always pass the trace 40 | -- record around or always be in a reader or special trace monad 41 | {-# NOINLINE traceSettings #-} 42 | traceSettings :: MVar TraceSettings 43 | traceSettings = unsafePerformIO newEmptyMVar 44 | 45 | withTrace :: Maybe FilePath -> Bool -> Bool -> Bool -> TraceLevel -> IO () -> IO () 46 | withTrace traceFn echoOn appendOn colorOn level f = 47 | bracket 48 | ( do h <- case traceFn of Just fn -> if level /= TLNone 49 | then Just <$> openFile fn (if appendOn 50 | then AppendMode 51 | else WriteMode) 52 | else return Nothing 53 | _ -> return Nothing 54 | let ts = TraceSettings { tsFile = h 55 | , tsEchoOn = echoOn 56 | , tsColorOn = colorOn 57 | , tsLevel = level 58 | } 59 | r <- tryPutMVar traceSettings ts 60 | unless r $ error "Double initialization of Trace module" 61 | return ts 62 | ) 63 | ( \ts -> do traceT TLInfo "Shutting down trace system" 64 | void . takeMVar $ traceSettings 65 | case tsFile ts of Just h -> hClose h 66 | _ -> return () 67 | when (tsEchoOn ts) $ hFlush stdout 68 | ) 69 | $ \_ -> f 70 | 71 | trace :: TraceLevel -> T.Text -> IO () 72 | trace lvl msg = void $ withMVar traceSettings $ \ts -> -- TODO: Have to take an MVar even if 73 | -- tracing is off, speed this up 74 | when (lvl /= TLNone && fromEnum lvl <= fromEnum (tsLevel ts)) $ do 75 | tid <- printf "%-12s" . show <$> myThreadId 76 | time <- printf "%-26s" . show . zonedTimeToLocalTime <$> getZonedTime 77 | let lvlDesc color = (if color then concat else (!! 1)) $ case lvl of 78 | TLError -> [ mkANSICol A.Red , "ERROR", reset ] 79 | TLWarn -> [ mkANSICol A.Yellow, "WARN ", reset ] 80 | TLInfo -> [ mkANSICol A.White , "INFO ", reset ] 81 | _ -> replicate 3 "" 82 | reset = A.setSGRCode [] 83 | mkANSICol c = A.setSGRCode [ A.SetColor A.Foreground A.Vivid c ] 84 | header color = intercalate " | " [ lvlDesc color, tid, time ] 85 | handles = case tsFile ts of Just h -> [h]; _ -> []; ++ [stdout | tsEchoOn ts] 86 | oneLine = not (T.any (== '\n') msg) && T.length msg < 80 87 | forM_ handles $ \h -> do 88 | closed <- hIsClosed h 89 | hs <- hShow h 90 | -- Use ANSI colors when outputting to the terminal 91 | color <- (&&) (tsColorOn ts) <$> hIsTerminalDevice h 92 | if closed 93 | then TI.putStrLn $ "ERROR: Trace message lost, called trace after shutdown: " <> msg 94 | <> "\n" <> T.pack hs <> "\n" <> T.pack (show h) 95 | else -- Display short, unbroken messages in a single line without padding newline 96 | if oneLine 97 | then TI.hPutStrLn h $ T.pack (header color) <> " - " <> msg 98 | else do hPutStrLn h $ header color 99 | TI.hPutStrLn h msg 100 | hPutStrLn h "" 101 | 102 | traceT :: TraceLevel -> T.Text -> IO () 103 | traceT = trace 104 | 105 | traceS :: TraceLevel -> String -> IO () 106 | traceS lvl msg = trace lvl (T.pack msg) 107 | 108 | traceB :: TraceLevel -> B.ByteString -> IO () 109 | traceB lvl msg = trace lvl (E.decodeUtf8 msg) 110 | 111 | traceAndThrow :: String -> IO a 112 | traceAndThrow err = traceS TLError err >> (throwIO $ ErrorCall err) 113 | 114 | -------------------------------------------------------------------------------- /hs-src/WrapEnum.hs: -------------------------------------------------------------------------------- 1 | 2 | module WrapEnum where 3 | 4 | -- Move through an enumeration, but wrap around when hitting the end 5 | wrapSucc, wrapPred :: (Enum a, Bounded a, Eq a) => a -> a 6 | wrapSucc a | a == maxBound = minBound 7 | | otherwise = succ a 8 | wrapPred a | a == minBound = maxBound 9 | | otherwise = pred a 10 | 11 | -------------------------------------------------------------------------------- /meshes/cube.dat: -------------------------------------------------------------------------------- 1 | # Simple ASCII Mesh File Format 2 | # 3 | # 4 | # 5 | # Px Py Pz Nx Ny Nz ColR ColB ColG 6 | # 7 | # 8 | # 9 | # 10 | 11 | 24 12 | 13 | -38.007374 -43.911434 0.000000 0.000000 0.000000 -1.000000 1.0 0.0 0.0 14 | 48.339481 -43.911434 0.000000 0.000000 0.000000 -1.000000 0.0 1.0 0.0 15 | -38.007374 36.531361 0.000000 0.000000 0.000000 -1.000000 0.0 0.0 1.0 16 | 48.339481 36.531361 0.000000 0.000000 0.000000 -1.000000 1.0 0.0 1.0 17 | 18 | -38.007374 -43.911434 73.800728 0.000000 0.000000 1.000000 1.0 0.0 0.0 19 | 48.339481 -43.911434 73.800728 0.000000 0.000000 1.000000 0.0 1.0 0.0 20 | -38.007374 36.531361 73.800728 0.000000 0.000000 1.000000 0.0 0.0 1.0 21 | 48.339481 36.531361 73.800728 0.000000 0.000000 1.000000 1.0 0.0 1.0 22 | 23 | -38.007374 -43.911434 0.000000 0.000000 -1.000000 0.000000 1.0 0.0 0.0 24 | 48.339481 -43.911434 0.000000 0.000000 -1.000000 0.000000 0.0 1.0 0.0 25 | 48.339481 -43.911434 73.800728 0.000000 -1.000000 0.000000 0.0 0.0 1.0 26 | -38.007374 -43.911434 73.800728 0.000000 -1.000000 0.000000 1.0 0.0 1.0 27 | 28 | 48.339481 -43.911434 0.000000 1.000000 0.000000 0.000000 1.0 0.0 0.0 29 | 48.339481 36.531361 0.000000 1.000000 0.000000 0.000000 0.0 1.0 0.0 30 | 48.339481 36.531361 73.800728 1.000000 0.000000 0.000000 0.0 0.0 1.0 31 | 48.339481 -43.911434 73.800728 1.000000 0.000000 0.000000 1.0 0.0 1.0 32 | 33 | 48.339481 36.531361 0.000000 0.000000 1.000000 0.000000 1.0 0.0 0.0 34 | -38.007374 36.531361 0.000000 0.000000 1.000000 0.000000 0.0 1.0 0.0 35 | -38.007374 36.531361 73.800728 0.000000 1.000000 0.000000 0.0 0.0 1.0 36 | 48.339481 36.531361 73.800728 0.000000 1.000000 0.000000 1.0 0.0 1.0 37 | 38 | -38.007374 36.531361 0.000000 -1.000000 0.000000 0.000000 1.0 0.0 0.0 39 | -38.007374 -43.911434 0.000000 -1.000000 0.000000 0.000000 0.0 1.0 0.0 40 | -38.007374 -43.911434 73.800728 -1.000000 0.000000 0.000000 0.0 0.0 1.0 41 | -38.007374 36.531361 73.800728 -1.000000 0.000000 0.000000 1.0 0.0 1.0 42 | 43 | 36 44 | 45 | 0 2 3 46 | 3 1 0 47 | 4 5 7 48 | 7 6 4 49 | 8 9 10 50 | 10 11 8 51 | 12 13 14 52 | 14 15 12 53 | 16 17 18 54 | 18 19 16 55 | 20 21 22 56 | 22 23 20 57 | -------------------------------------------------------------------------------- /meshes/sphere.dat: -------------------------------------------------------------------------------- 1 | # Simple ASCII Mesh File Format 2 | # 3 | # 4 | # 5 | # Px Py Pz Nx Ny Nz 6 | # 7 | # 8 | # 9 | # 10 | 11 | 56 12 | 13 | -37.023926 37.031246 -37.023926 -0.577350 0.577350 -0.577350 14 | -44.523926 11.835930 -44.523926 -0.700799 0.133273 -0.700799 15 | -59.992676 16.054678 -16.047358 -0.942250 0.236817 -0.236817 16 | -44.523926 44.531246 -11.828609 -0.700799 0.700799 -0.133273 17 | -44.523926 -11.828609 -44.523926 -0.675002 -0.297900 -0.675002 18 | -59.992676 -16.047358 -16.047358 -0.933483 -0.253583 -0.253583 19 | -37.023926 -37.023926 -37.023926 -0.557140 -0.615784 -0.557140 20 | -44.523926 -44.523926 -11.828609 -0.695548 -0.685284 -0.215865 21 | -59.992676 16.054678 16.054678 -0.933483 0.253583 0.253583 22 | -44.523926 44.531246 11.835930 -0.675002 0.675002 0.297900 23 | -59.992676 -16.047358 16.054678 -0.942250 -0.236817 0.236817 24 | -44.523926 -44.523926 11.835930 -0.685285 -0.695548 0.215865 25 | -44.523926 11.835930 44.531246 -0.695548 0.215865 0.685284 26 | -37.023926 37.031246 37.031246 -0.557140 0.557140 0.615784 27 | -44.523926 -11.828609 44.531246 -0.685285 -0.215865 0.695548 28 | -37.023926 -37.023926 37.031246 -0.615784 -0.557140 0.557140 29 | -11.828609 -44.523926 -44.523926 -0.215865 -0.685284 -0.695548 30 | -16.047358 -59.992676 -16.047358 -0.236817 -0.942250 -0.236817 31 | 11.835930 -44.523926 -44.523926 0.215865 -0.695548 -0.685285 32 | 16.054678 -59.992676 -16.047358 0.253583 -0.933483 -0.253583 33 | 37.031246 -37.023926 -37.023926 0.557140 -0.557140 -0.615784 34 | 44.531246 -44.523926 -11.828609 0.675002 -0.675002 -0.297900 35 | -16.047358 -59.992676 16.054678 -0.253583 -0.933483 0.253583 36 | 16.054678 -59.992676 16.054678 0.236817 -0.942250 0.236817 37 | 44.531246 -44.523926 11.835930 0.700799 -0.700799 0.133273 38 | -11.828609 -44.523926 44.531246 -0.297900 -0.675002 0.675002 39 | 11.835930 -44.523926 44.531246 0.133273 -0.700799 0.700799 40 | 37.031246 -37.023926 37.031246 0.577350 -0.577350 0.577350 41 | -11.828609 44.531246 -44.523926 -0.133273 0.700799 -0.700799 42 | -16.047358 16.054678 -59.992676 -0.236817 0.236817 -0.942250 43 | 11.835930 44.531246 -44.523926 0.297900 0.675002 -0.675002 44 | 16.054678 16.054678 -59.992676 0.253583 0.253583 -0.933483 45 | 37.031246 37.031246 -37.023926 0.615784 0.557140 -0.557140 46 | 44.531246 11.835930 -44.523926 0.685284 0.215865 -0.695548 47 | -16.047358 -16.047358 -59.992676 -0.253583 -0.253583 -0.933483 48 | 16.054678 -16.047358 -59.992676 0.236817 -0.236817 -0.942250 49 | 44.531246 -11.828609 -44.523926 0.695548 -0.215865 -0.685285 50 | 44.531246 44.531246 -11.828609 0.685284 0.695548 -0.215865 51 | 59.999996 16.054678 -16.047358 0.942250 0.236817 -0.236817 52 | 44.531246 44.531246 11.835930 0.695548 0.685285 0.215865 53 | 59.999996 16.054678 16.054678 0.933483 0.253583 0.253583 54 | 37.031246 37.031246 37.031246 0.557140 0.615784 0.557140 55 | 44.531246 11.835930 44.531246 0.675002 0.297900 0.675002 56 | 59.999996 -16.047358 -16.047358 0.933483 -0.253583 -0.253583 57 | 59.999996 -16.047358 16.054678 0.942250 -0.236817 0.236817 58 | 44.531246 -11.828609 44.531246 0.700799 -0.133273 0.700799 59 | -16.047358 59.999996 -16.047358 -0.236817 0.942250 -0.236817 60 | -16.047358 59.999996 16.054678 -0.253583 0.933483 0.253583 61 | -11.828609 44.531246 44.531246 -0.215865 0.695548 0.685284 62 | 16.054678 59.999996 -16.047358 0.253583 0.933483 -0.253583 63 | 16.054678 59.999996 16.054678 0.236817 0.942250 0.236817 64 | 11.835930 44.531246 44.531246 0.215865 0.685285 0.695548 65 | -16.047358 16.054678 59.999996 -0.236817 0.236817 0.942250 66 | -16.047358 -16.047358 59.999996 -0.253583 -0.253583 0.933483 67 | 16.054678 16.054678 59.999996 0.253583 0.253583 0.933483 68 | 16.054678 -16.047358 59.999996 0.236817 -0.236817 0.942250 69 | 70 | 324 71 | 72 | 0 1 2 73 | 2 3 0 74 | 1 4 5 75 | 5 2 1 76 | 4 6 7 77 | 7 5 4 78 | 3 2 8 79 | 8 9 3 80 | 2 5 10 81 | 10 8 2 82 | 5 7 11 83 | 11 10 5 84 | 9 8 12 85 | 12 13 9 86 | 8 10 14 87 | 14 12 8 88 | 10 11 15 89 | 15 14 10 90 | 6 16 17 91 | 17 7 6 92 | 16 18 19 93 | 19 17 16 94 | 18 20 21 95 | 21 19 18 96 | 7 17 22 97 | 22 11 7 98 | 17 19 23 99 | 23 22 17 100 | 19 21 24 101 | 24 23 19 102 | 11 22 25 103 | 25 15 11 104 | 22 23 26 105 | 26 25 22 106 | 23 24 27 107 | 27 26 23 108 | 0 28 29 109 | 29 1 0 110 | 28 30 31 111 | 31 29 28 112 | 30 32 33 113 | 33 31 30 114 | 1 29 34 115 | 34 4 1 116 | 29 31 35 117 | 35 34 29 118 | 31 33 36 119 | 36 35 31 120 | 4 34 16 121 | 16 6 4 122 | 34 35 18 123 | 18 16 34 124 | 35 36 20 125 | 20 18 35 126 | 32 37 38 127 | 38 33 32 128 | 37 39 40 129 | 40 38 37 130 | 39 41 42 131 | 42 40 39 132 | 33 38 43 133 | 43 36 33 134 | 38 40 44 135 | 44 43 38 136 | 40 42 45 137 | 45 44 40 138 | 36 43 21 139 | 21 20 36 140 | 43 44 24 141 | 24 21 43 142 | 44 45 27 143 | 27 24 44 144 | 0 3 46 145 | 46 28 0 146 | 3 9 47 147 | 47 46 3 148 | 9 13 48 149 | 48 47 9 150 | 28 46 49 151 | 49 30 28 152 | 46 47 50 153 | 50 49 46 154 | 47 48 51 155 | 51 50 47 156 | 30 49 37 157 | 37 32 30 158 | 49 50 39 159 | 39 37 49 160 | 50 51 41 161 | 41 39 50 162 | 13 12 52 163 | 52 48 13 164 | 12 14 53 165 | 53 52 12 166 | 14 15 25 167 | 25 53 14 168 | 48 52 54 169 | 54 51 48 170 | 52 53 55 171 | 55 54 52 172 | 53 25 26 173 | 26 55 53 174 | 51 54 42 175 | 42 41 51 176 | 54 55 45 177 | 45 42 54 178 | 55 26 27 179 | 27 45 55 180 | -------------------------------------------------------------------------------- /rs-src/gol.rs: -------------------------------------------------------------------------------- 1 | 2 | use std::sync::Mutex; 3 | use rand; 4 | use rand::Rng; 5 | use std::ptr; 6 | use std::thread; 7 | 8 | static GRID_WDH : i32 = 256; 9 | 10 | lazy_static! { 11 | static ref GRID: Mutex> = { 12 | let mut v = Vec::new(); 13 | v.resize((GRID_WDH * GRID_WDH) as usize, 0); 14 | Mutex::new(v) 15 | }; 16 | } 17 | 18 | #[no_mangle] 19 | pub extern fn gol_randomize() -> () { 20 | let mut grid = GRID.lock().unwrap(); 21 | let mut rng = rand::thread_rng(); 22 | 23 | for y in 0..GRID_WDH { 24 | for x in 0..GRID_WDH { 25 | let idx = (x + y * GRID_WDH) as usize; 26 | grid[idx] = if rng.gen() { 1 } else { 0 }; 27 | } 28 | } 29 | } 30 | 31 | #[no_mangle] 32 | pub extern fn gol_step(nthreads : i32) -> () { 33 | // Allocate new grid without wasting time setting it to any value 34 | let grid_size = (GRID_WDH * GRID_WDH) as usize; 35 | let mut new_grid = Vec::with_capacity(grid_size); 36 | unsafe { new_grid.set_len(grid_size); } 37 | let new_grid_ptr = new_grid.as_mut_ptr(); 38 | 39 | let mut grid = GRID.lock().unwrap(); 40 | let grid_ptr = grid.as_mut_ptr(); 41 | 42 | // Compute the four borders 43 | for side in 0..4 { 44 | let mut x; 45 | let mut y; 46 | let xincr; 47 | let yincr; 48 | match side { 49 | 0 => { x = 0 ; y = 0 ; xincr = 1; yincr = 0; }, 50 | 1 => { x = 0 ; y = GRID_WDH - 1; xincr = 1; yincr = 0; }, 51 | 2 => { x = 0 ; y = 0 ; xincr = 0; yincr = 1; }, 52 | 3 => { x = GRID_WDH - 1; y = 0 ; xincr = 0; yincr = 1; }, 53 | _ => panic!("invalid side") 54 | } 55 | 56 | while x < GRID_WDH && y < GRID_WDH { 57 | // We're at the boundary, wrap 58 | let torus_idx = |x: i32, y: i32| -> u8 { 59 | let wrapx = if x < 0 { GRID_WDH - 1 } else { if x > GRID_WDH - 1 { 0 } else { x } }; 60 | let wrapy = if y < 0 { GRID_WDH - 1 } else { if y > GRID_WDH - 1 { 0 } else { y } }; 61 | let idx = wrapx + wrapy * GRID_WDH; 62 | unsafe { * grid_ptr.offset(idx as isize) } 63 | }; 64 | 65 | // 2D indexing, faster to wrap 66 | let idx = (x + y * GRID_WDH) as isize; 67 | let alive = unsafe { * grid_ptr.offset(idx as isize) }; 68 | let alive_nb = torus_idx(x + 1, y ) + 69 | torus_idx(x , y + 1) + 70 | torus_idx(x - 1, y ) + 71 | torus_idx(x , y - 1) + 72 | torus_idx(x + 1, y + 1) + 73 | torus_idx(x - 1, y - 1) + 74 | torus_idx(x + 1, y - 1) + 75 | torus_idx(x - 1, y + 1); 76 | 77 | unsafe { 78 | * new_grid_ptr.offset(idx as isize) = 79 | if alive_nb == 3 || (alive == 1 && alive_nb == 2) { 1 } else { 0 }; 80 | } 81 | 82 | x += xincr; 83 | y += yincr; 84 | } 85 | } 86 | 87 | // Compute interior 88 | if nthreads == 1 { 89 | // Single-threaded version. There's quite a bit of overhead for the threads, make 90 | // sure no performance is lost 91 | 92 | // TODO: Duplicate code between serial / parallel version 93 | for y in 1..GRID_WDH - 1 { 94 | for x in 1..GRID_WDH - 1 { 95 | // 1D indexing, no wrapping needed 96 | let idx = x + y * GRID_WDH; 97 | let alive = unsafe { * grid_ptr.offset(idx as isize) }; 98 | let alive_nb = unsafe { 99 | * grid_ptr.offset((idx + 1 ) as isize) + 100 | * grid_ptr.offset((idx - 1 ) as isize) + 101 | * grid_ptr.offset((idx + GRID_WDH) as isize) + 102 | * grid_ptr.offset((idx - GRID_WDH) as isize) + 103 | * grid_ptr.offset((idx + 1 + GRID_WDH) as isize) + 104 | * grid_ptr.offset((idx + 1 - GRID_WDH) as isize) + 105 | * grid_ptr.offset((idx - 1 + GRID_WDH) as isize) + 106 | * grid_ptr.offset((idx - 1 - GRID_WDH) as isize) 107 | }; 108 | 109 | unsafe { 110 | * new_grid_ptr.offset(idx as isize) = 111 | if alive_nb == 3 || (alive == 1 && alive_nb == 2) { 1 } else { 0 }; 112 | } 113 | } 114 | } 115 | } else { 116 | // Multi-threaded version 117 | 118 | let threads: Vec<_> = (0..nthreads).map(|i| { 119 | // Vertical slice to be processed by the current thread 120 | let range = (GRID_WDH - 2) / nthreads; 121 | let seg_low = 1 + range * i; 122 | let seg_high = if i == nthreads - 1 { GRID_WDH - 1 } else { 1 + range * (i + 1) }; 123 | 124 | // Allow sharing of pointers with our threads 125 | struct SendPtr { 126 | ptr : *mut u8 127 | } 128 | unsafe impl Send for SendPtr { } 129 | let grid_ptr_send = SendPtr { ptr: grid_ptr }; 130 | let new_grid_ptr_send = SendPtr { ptr: new_grid_ptr }; 131 | 132 | // TODO: Thread creation seems expensive compared to our computation, need to 133 | // re-use threads between steps for more scalability 134 | thread::spawn(move || { 135 | // Unwrap 136 | let grid_ptr = grid_ptr_send.ptr; 137 | let new_grid_ptr = new_grid_ptr_send.ptr; 138 | 139 | for y in seg_low..seg_high { 140 | for x in 1..GRID_WDH - 1 { 141 | // 1D indexing, no wrapping needed 142 | let idx = x + y * GRID_WDH; 143 | let alive = unsafe { * grid_ptr.offset(idx as isize) }; 144 | let alive_nb = unsafe { 145 | * grid_ptr.offset((idx + 1 ) as isize) + 146 | * grid_ptr.offset((idx - 1 ) as isize) + 147 | * grid_ptr.offset((idx + GRID_WDH) as isize) + 148 | * grid_ptr.offset((idx - GRID_WDH) as isize) + 149 | * grid_ptr.offset((idx + 1 + GRID_WDH) as isize) + 150 | * grid_ptr.offset((idx + 1 - GRID_WDH) as isize) + 151 | * grid_ptr.offset((idx - 1 + GRID_WDH) as isize) + 152 | * grid_ptr.offset((idx - 1 - GRID_WDH) as isize) 153 | }; 154 | 155 | unsafe { 156 | * new_grid_ptr.offset(idx as isize) = 157 | if alive_nb == 3 || (alive == 1 && alive_nb == 2) { 1 } else { 0 }; 158 | } 159 | } 160 | } 161 | }) 162 | }).collect(); 163 | 164 | for thread in threads { 165 | thread.join().unwrap(); 166 | } 167 | } 168 | 169 | * grid = new_grid; 170 | } 171 | 172 | #[no_mangle] 173 | pub extern fn gol_draw(w: i32, h: i32, fb: *mut u32) -> () { 174 | // Clear background 175 | unsafe { ptr::write_bytes(fb, 64, (w * h) as usize); } 176 | 177 | let grid = GRID.lock().unwrap(); 178 | 179 | // Center 180 | let xoffs = w / 2 - GRID_WDH / 2; 181 | let yoffs = h / 2 - GRID_WDH / 2; 182 | 183 | for y in 0..GRID_WDH { 184 | for x in 0..GRID_WDH { 185 | let idx_fb = (xoffs + x) + (yoffs + y) * w; 186 | 187 | // Out of bounds check for the FB 188 | if idx_fb < 0 || idx_fb > w * h - 1 { continue; } 189 | 190 | let idx_grid = x + y * GRID_WDH; 191 | 192 | unsafe { 193 | * fb.offset(idx_fb as isize) = 194 | if grid[idx_grid as usize] == 1 { 0x00FFFFFF } else { 0 }; 195 | } 196 | } 197 | } 198 | } 199 | 200 | #[no_mangle] 201 | pub extern fn gol_set_pattern(w: i32, h: i32, pat: *mut u8) -> () { 202 | // Place specified pattern in the center of an empty grid 203 | let mut grid = GRID.lock().unwrap(); 204 | 205 | // Clear grid 206 | let grid_size = GRID_WDH * GRID_WDH; 207 | grid.clear(); 208 | grid.resize(grid_size as usize, 0); 209 | 210 | // Center 211 | let xoffs = GRID_WDH / 2 - w / 2; 212 | let yoffs = GRID_WDH / 2 - h / 2; 213 | 214 | for y in 0..h { 215 | for x in 0..w { 216 | let idx_grid = (xoffs + x) + (yoffs + y) * GRID_WDH; 217 | 218 | // Out of bounds check for the grid 219 | if idx_grid < 0 || idx_grid > grid_size - 1 { continue; } 220 | 221 | let idx_pat = x + y * w; 222 | unsafe { grid[idx_grid as usize] = * pat.offset(idx_pat as isize); } 223 | } 224 | } 225 | } 226 | 227 | -------------------------------------------------------------------------------- /rs-src/lib.rs: -------------------------------------------------------------------------------- 1 | 2 | #[macro_use] 3 | extern crate lazy_static; 4 | extern crate rand; 5 | extern crate nalgebra as na; 6 | extern crate stb_image; 7 | extern crate time; 8 | extern crate ansi_term; 9 | extern crate scoped_threadpool; 10 | extern crate num_cpus; 11 | 12 | pub mod sine_scroller; 13 | pub mod gol; 14 | pub mod nbody; 15 | pub mod rasterizer; 16 | 17 | -------------------------------------------------------------------------------- /rs-src/sine_scroller.rs: -------------------------------------------------------------------------------- 1 | 2 | use std::f32::consts; 3 | 4 | #[no_mangle] 5 | pub extern fn sine_scroller(w: i32, h: i32, fb: *mut u32, tick: f64) -> () { 6 | for y in 0..h { 7 | let sy = (((y as f32) / 64.0 + tick as f32) * 2.0 * consts::PI).sin(); 8 | for x in 0..w { 9 | let sx = (((x as f32) / 64.0 + tick as f32) * 2.0 * consts::PI).sin(); 10 | let gray = (((sx + 1.0) * 0.5) * ((sy + 1.0) * 0.5) * 255.0) as u32; 11 | let idx = x + y * w; 12 | unsafe { 13 | *fb.offset(idx as isize) = gray | gray << 8 | gray << 16; 14 | } 15 | } 16 | } 17 | } 18 | 19 | -------------------------------------------------------------------------------- /rust-exp.cabal: -------------------------------------------------------------------------------- 1 | name: rust-exp 2 | version: 0.1.0.0 3 | synopsis: Haskell OpenGL / GLFW application wrapping around a few Rust experiments 4 | -- description: 5 | license: MIT 6 | license-file: LICENSE 7 | author: Tim C. Schroeder 8 | maintainer: www.blitzcode.net 9 | -- copyright: 10 | category: Graphics 11 | build-type: Simple 12 | -- extra-source-files: 13 | cabal-version: >=1.10 14 | 15 | executable rust-exp 16 | main-is: Main.hs 17 | hs-source-dirs: hs-src 18 | build-depends: base >=4.8 && <5, 19 | mtl >= 2.2.1, 20 | transformers, 21 | monad-control, 22 | linear, 23 | GLFW-b, 24 | OpenGL, 25 | OpenGLRaw >= 3.0.0.0, 26 | stm, 27 | vector, 28 | lens, 29 | time, 30 | ansi-terminal, 31 | text, 32 | bytestring, 33 | containers, 34 | async, 35 | template-haskell, 36 | resourcet, 37 | directory, 38 | filepath, 39 | deepseq, 40 | JuicyPixels, 41 | either 42 | default-language: Haskell2010 43 | ghc-options: -Wall -rtsopts -O2 -threaded -dynamic 44 | ghc-prof-options: -fprof-auto -caf-all 45 | -- Link against our rust library 46 | extra-libraries: rust_exp 47 | extra-lib-dirs: target/release/ 48 | -------------------------------------------------------------------------------- /screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blitzcode/rust-exp/2d380104ebbc1c0c1167f07f93dd9e9b3ed32472/screenshot.png -------------------------------------------------------------------------------- /stack.yaml: -------------------------------------------------------------------------------- 1 | # For more information, see: https://github.com/commercialhaskell/stack/blob/release/doc/yaml_configuration.md 2 | 3 | # Specifies the GHC version and set of packages available (e.g., lts-3.5, nightly-2015-09-21, ghc-7.10.2) 4 | resolver: lts-6.0 5 | 6 | # Local packages, usually specified by relative directory name 7 | packages: 8 | - '.' 9 | 10 | # Packages to be pulled from upstream that are not in the resolver (e.g., acme-missiles-0.3) 11 | extra-deps: [] 12 | 13 | # Override default flag values for local packages and extra-deps 14 | flags: {} 15 | 16 | # Extra package databases containing global packages 17 | extra-package-dbs: [] 18 | 19 | # Control whether we use the GHC we find on the path 20 | # system-ghc: true 21 | 22 | # Require a specific version of stack, using version ranges 23 | # require-stack-version: -any # Default 24 | # require-stack-version: >= 1.0.0 25 | 26 | # Override the architecture used by stack, especially useful on Windows 27 | # arch: i386 28 | # arch: x86_64 29 | 30 | # Extra directories used by stack for building 31 | # extra-include-dirs: [/path/to/dir] 32 | # extra-lib-dirs: [/path/to/dir] 33 | --------------------------------------------------------------------------------