From 39ee0fefb7f41fde8b2bd5a11c1bc4267b1799f0 Mon Sep 17 00:00:00 2001 From: asrael Date: Wed, 21 Jan 2026 23:19:50 -0600 Subject: [PATCH] improve sw renderer --- demo/main.fnl | 21 +- demo/mod/blendtable.fnl | 4103 ++++++++++++++++++++++ demo/mod/colormap.fnl | 1031 ++++++ demo/mod/first_person3d.fnl | 287 +- demo/mod/menu.fnl | 14 +- demo/mod/palette.fnl | 263 ++ demo/mod/sky.fnl | 287 +- demo/mod/textures.fnl | 168 + demo/profile_3d.fnl | 5 + pxl8.sh | 43 +- server/build.rs | 10 +- src/asset/pxl8_ase.c | 83 +- src/asset/pxl8_cart.c | 93 +- src/asset/pxl8_cart.h | 2 +- src/asset/pxl8_save.c | 21 +- src/core/pxl8.c | 22 +- src/core/pxl8_bytes.c | 72 +- src/core/pxl8_bytes.h | 72 +- src/{game => core}/pxl8_game.h | 0 src/core/pxl8_io.c | 23 +- src/core/pxl8_io.h | 8 +- src/core/pxl8_log.c | 2 +- src/{game => core}/pxl8_replay.c | 49 +- src/{game => core}/pxl8_replay.h | 0 src/core/pxl8_types.h | 3 + src/gfx/pxl8_3d_camera.c | 48 +- src/gfx/pxl8_3d_camera.h | 1 + src/gfx/pxl8_anim.c | 47 +- src/gfx/pxl8_atlas.c | 102 +- src/gfx/pxl8_atlas.h | 26 +- src/gfx/pxl8_blend.c | 194 - src/gfx/pxl8_blend.h | 39 - src/gfx/pxl8_colormap.c | 133 +- src/gfx/pxl8_colormap.h | 62 +- src/gfx/pxl8_cpu.c | 238 +- src/gfx/pxl8_cpu.h | 23 +- src/gfx/pxl8_font.c | 3 +- src/gfx/pxl8_gfx.c | 173 +- src/gfx/pxl8_gfx.h | 59 +- src/gfx/pxl8_gfx3d.h | 37 +- src/gfx/pxl8_glows.c | 62 + src/gfx/pxl8_glows.h | 42 + src/gfx/pxl8_lightmap.c | 114 + src/gfx/pxl8_lightmap.h | 48 + src/gfx/pxl8_lights.c | 64 + src/gfx/pxl8_lights.h | 33 + src/gfx/pxl8_mesh.c | 19 +- src/gfx/pxl8_mesh.h | 69 +- src/gfx/pxl8_palette.c | 115 +- src/gfx/pxl8_palette.h | 12 +- src/gfx/pxl8_particles.c | 11 +- src/gfx/pxl8_tilemap.c | 33 +- src/gfx/pxl8_tilesheet.c | 51 +- src/gfx/pxl8_transition.c | 5 +- src/{game => gui}/pxl8_gui.c | 40 +- src/{game => gui}/pxl8_gui.h | 4 +- src/gui/pxl8_gui_palette.h | 41 + src/hal/{pxl8_sdl3.c => pxl8_hal_sdl3.c} | 8 +- src/hal/pxl8_mem.h | 8 + src/hal/pxl8_mem_sdl3.c | 19 + src/hal/pxl8_sdl3.h | 5 - src/lua/pxl8.lua | 55 +- src/lua/pxl8/core.lua | 21 +- src/lua/pxl8/effects.lua | 81 +- src/lua/pxl8/gfx3d.lua | 52 +- src/lua/pxl8/gui.lua | 4 +- src/lua/pxl8/math.lua | 42 +- src/lua/pxl8/particles.lua | 2 +- src/lua/pxl8/procgen.lua | 99 + src/lua/pxl8/world.lua | 30 +- src/math/pxl8_math.c | 59 +- src/math/pxl8_math.h | 52 +- src/math/pxl8_simd.h | 291 -- src/net/pxl8_net.c | 19 +- src/net/pxl8_net.h | 4 +- src/net/pxl8_protocol.c | 24 +- src/net/pxl8_protocol.h | 24 +- src/procgen/pxl8_graph.c | 332 ++ src/procgen/pxl8_graph.h | 90 + src/script/pxl8_repl.c | 33 +- src/script/pxl8_script.c | 43 +- src/script/pxl8_script_ffi.h | 217 +- src/sfx/pxl8_sfx.c | 78 +- src/world/pxl8_bsp.c | 542 +-- src/world/pxl8_bsp.h | 44 +- src/world/pxl8_gen.c | 684 +++- src/world/pxl8_gen.h | 13 - src/world/pxl8_world.c | 81 +- src/world/pxl8_world.h | 1 + 89 files changed, 9380 insertions(+), 2307 deletions(-) create mode 100644 demo/mod/blendtable.fnl create mode 100644 demo/mod/colormap.fnl create mode 100644 demo/mod/palette.fnl create mode 100644 demo/mod/textures.fnl create mode 100644 demo/profile_3d.fnl rename src/{game => core}/pxl8_game.h (100%) rename src/{game => core}/pxl8_replay.c (93%) rename src/{game => core}/pxl8_replay.h (100%) delete mode 100644 src/gfx/pxl8_blend.c delete mode 100644 src/gfx/pxl8_blend.h create mode 100644 src/gfx/pxl8_glows.c create mode 100644 src/gfx/pxl8_glows.h create mode 100644 src/gfx/pxl8_lightmap.c create mode 100644 src/gfx/pxl8_lightmap.h create mode 100644 src/gfx/pxl8_lights.c create mode 100644 src/gfx/pxl8_lights.h rename src/{game => gui}/pxl8_gui.c (69%) rename src/{game => gui}/pxl8_gui.h (88%) create mode 100644 src/gui/pxl8_gui_palette.h rename src/hal/{pxl8_sdl3.c => pxl8_hal_sdl3.c} (99%) create mode 100644 src/hal/pxl8_mem.h create mode 100644 src/hal/pxl8_mem_sdl3.c delete mode 100644 src/hal/pxl8_sdl3.h create mode 100644 src/lua/pxl8/procgen.lua delete mode 100644 src/math/pxl8_simd.h create mode 100644 src/procgen/pxl8_graph.c create mode 100644 src/procgen/pxl8_graph.h diff --git a/demo/main.fnl b/demo/main.fnl index 8a63553..6b9367d 100644 --- a/demo/main.fnl +++ b/demo/main.fnl @@ -6,11 +6,10 @@ (var time 0) (var active-demo :logo) (var particles nil) -(var particles2 nil) (var fire-init? false) (var rain-init? false) (var snow-init? false) -(var snow-init2? false) +(var first_person3d-init? false) (var use-famicube-palette? false) (var logo-x 256) @@ -32,9 +31,7 @@ (pxl8.load_palette "res/sprites/pxl8_logo.ase") (set logo-sprite (pxl8.load_sprite "res/sprites/pxl8_logo.ase")) (set particles (pxl8.create_particles 1000)) - (set particles2 (pxl8.create_particles 500)) - (music.init) - (first_person3d.init))) + (music.init))) (global update (fn [dt] (when (pxl8.key_pressed "escape") @@ -57,7 +54,8 @@ (set transition-pending nil) (when (= active-demo :fire) (set fire-init? false)) (when (= active-demo :rain) (set rain-init? false)) - (when (= active-demo :snow) (set snow-init? false) (set snow-init2? false))) + (when (= active-demo :snow) (set snow-init? false)) + (when (= active-demo :first_person3d) (set first_person3d-init? false))) (transition:destroy) (set transition nil))) @@ -92,12 +90,14 @@ (when (> logo-y 296) (set logo-y 296) (set logo-dy (- (math.abs logo-dy))))) - :first_person3d (first_person3d.update dt)) + :first_person3d (do + (when (not first_person3d-init?) + (first_person3d.init) + (set first_person3d-init? true)) + (first_person3d.update dt))) (when particles - (particles:update dt)) - (when particles2 - (particles2:update dt))) + (particles:update dt))) (when (menu.is-paused) (menu.update)))) @@ -174,6 +174,7 @@ :first_person3d (first_person3d.frame) + _ (pxl8.clear 0)) (when transition diff --git a/demo/mod/blendtable.fnl b/demo/mod/blendtable.fnl new file mode 100644 index 0000000..b210921 --- /dev/null +++ b/demo/mod/blendtable.fnl @@ -0,0 +1,4103 @@ +(require :pxl8) +(local ffi (require :ffi)) + +(local data (ffi.new "u8[65536]" [ + 143 175 141 47 158 95 2 2 43 43 3 4 4 4 5 5 + 158 158 158 158 1 47 141 141 47 141 141 142 142 142 175 143 + 31 31 94 94 94 45 158 46 46 47 47 47 141 174 142 142 + 26 245 245 172 41 26 246 245 99 23 62 246 245 172 173 174 + 246 171 172 172 172 172 173 78 79 79 79 174 174 142 175 175 + 30 157 157 45 103 158 46 1 1 47 141 141 141 142 142 142 + 63 77 1 47 190 127 142 175 24 91 39 4 5 38 4 244 + 244 187 124 125 126 126 125 126 190 190 127 190 191 191 143 143 + 27 246 139 139 139 172 140 158 140 47 141 141 142 142 175 143 + 41 155 43 93 44 44 44 30 103 45 102 1 159 141 142 175 + 138 171 139 172 172 173 173 173 173 79 174 174 175 175 143 175 + 186 186 186 187 187 188 188 188 189 126 127 127 127 141 191 175 + 41 42 43 43 93 44 31 45 158 158 1 47 159 141 142 175 + 156 206 206 206 156 101 44 6 6 5 152 201 19 19 17 61 + 17 61 62 62 239 239 171 76 76 77 77 77 78 79 174 174 + 171 137 139 189 127 175 141 39 25 26 172 5 3 244 169 129 + 159 47 158 95 94 2 43 3 3 4 4 4 5 5 5 6 + 101 101 245 63 102 103 103 103 103 158 158 1 47 47 159 159 + 43 43 43 93 44 2 31 94 94 45 103 103 158 1 1 1 + 155 24 26 245 40 22 62 62 17 19 21 62 246 245 63 173 + 137 169 170 170 171 171 171 172 172 172 172 173 140 47 141 141 + 42 25 93 101 101 101 30 157 45 45 103 158 46 1 47 173 + 246 245 102 95 189 158 47 79 90 88 4 5 35 5 5 4 + 244 244 187 187 124 124 124 125 126 126 126 127 127 47 159 141 + 42 24 138 138 138 138 94 94 103 103 46 46 1 47 141 141 + 39 41 41 155 155 42 43 43 44 44 30 45 103 158 1 141 + 137 137 170 246 171 171 171 63 172 172 140 140 47 141 141 190 + 185 185 185 186 186 186 187 187 188 188 189 189 158 46 1 141 + 39 41 41 155 42 43 93 44 157 157 45 102 158 1 159 159 + 205 205 204 204 20 155 156 6 33 200 200 200 16 16 60 61 + 61 61 61 61 238 238 169 239 239 239 75 76 77 173 173 173 + 170 136 137 138 95 159 140 38 136 91 245 36 4 39 168 128 + 95 95 2 2 43 3 3 3 4 4 5 5 35 6 33 33 + 42 24 25 26 101 28 44 44 44 31 31 45 45 45 95 95 + 244 3 3 3 3 3 43 43 43 2 2 2 2 94 45 157 + 40 41 155 24 153 20 21 62 83 17 98 19 23 26 101 139 + 136 168 168 169 170 170 170 246 246 246 246 139 94 103 103 103 + 39 41 42 92 42 42 43 43 43 93 2 2 94 94 45 103 + 62 62 101 2 2 2 102 172 86 134 5 35 34 34 35 5 + 4 4 186 186 121 122 124 124 124 124 188 94 45 95 95 46 + 39 41 42 92 92 92 93 93 93 29 94 94 94 45 95 158 + 4 4 4 4 39 39 41 3 3 3 43 44 2 31 45 103 + 89 136 90 137 137 24 246 246 246 246 94 94 45 103 95 189 + 185 184 185 185 185 186 186 187 187 187 2 2 2 94 45 158 + 5 4 39 39 41 155 155 155 43 43 44 30 157 45 102 158 + 202 203 203 203 154 155 41 7 7 199 200 200 55 55 55 60 + 60 60 97 61 61 168 168 168 169 169 170 170 171 139 139 139 + 168 135 136 244 2 102 94 37 134 88 24 6 5 4 88 128 + 31 2 43 3 3 4 4 4 5 5 35 33 6 33 7 7 + 155 41 41 41 155 42 43 43 43 43 43 43 2 2 2 2 + 4 4 4 4 4 39 244 3 3 3 3 3 3 43 43 93 + 37 40 154 21 152 153 18 19 51 83 84 17 99 22 42 26 + 135 135 88 87 90 90 137 137 137 24 25 27 93 93 44 29 + 38 39 41 41 41 39 41 3 3 3 3 43 43 93 2 28 + 87 21 42 3 3 43 44 101 153 37 36 33 32 33 34 35 + 35 5 4 186 185 186 187 186 186 244 244 43 2 2 2 45 + 38 39 39 39 39 41 41 3 3 3 43 43 43 44 2 31 + 5 5 5 5 4 4 4 4 39 39 3 3 43 43 43 93 + 134 85 86 88 89 90 90 91 92 92 25 93 93 29 2 188 + 183 183 184 184 185 185 185 186 244 244 244 244 3 43 2 2 + 36 5 5 5 40 40 40 40 41 155 42 43 43 44 44 157 + 202 203 201 201 152 154 154 7 8 199 199 214 150 55 55 55 + 55 60 96 96 97 98 166 167 167 168 169 169 170 26 27 138 + 135 133 134 4 3 2 27 36 37 40 41 7 6 5 135 128 + 43 3 3 4 4 4 5 5 35 33 34 33 7 7 7 8 + 39 40 40 40 39 39 41 3 3 3 3 3 3 3 3 3 + 5 5 5 5 38 4 4 4 4 4 4 4 4 3 3 3 + 36 153 153 40 150 152 152 17 150 50 82 83 85 154 41 91 + 84 84 85 85 85 86 88 89 89 41 41 42 42 3 3 43 + 5 38 38 4 4 4 4 39 4 39 39 244 3 3 244 42 + 85 18 154 39 244 3 3 42 151 131 33 7 7 32 32 33 + 34 34 5 184 184 185 186 185 186 186 244 244 244 3 3 43 + 5 38 38 38 38 38 4 39 4 39 244 3 244 244 244 43 + 6 6 6 37 5 5 5 5 38 4 4 39 244 3 3 42 + 37 133 84 85 85 85 40 40 41 41 155 3 3 3 43 187 + 33 182 183 183 183 183 5 5 4 4 4 4 4 244 3 43 + 6 36 36 36 152 153 153 153 153 154 154 41 41 3 3 156 + 201 202 201 200 200 152 5 8 8 147 196 214 214 214 49 54 + 54 55 55 51 83 83 84 166 166 167 167 88 136 136 42 137 + 133 132 132 5 4 3 42 149 151 153 40 8 7 6 132 128 + 3 3 4 4 38 5 5 35 34 7 7 7 8 8 8 9 + 5 153 153 153 40 39 39 39 4 39 39 39 4 4 4 3 + 35 35 37 5 5 5 5 38 4 4 4 4 4 4 244 3 + 6 152 152 153 149 151 151 83 49 50 50 152 153 153 40 41 + 132 83 84 84 84 84 85 86 40 40 40 39 39 39 39 244 + 37 37 37 5 5 5 38 4 38 38 4 4 4 4 4 41 + 153 153 4 4 4 4 41 41 150 130 7 8 8 8 7 7 + 33 34 35 35 183 184 185 184 185 4 4 4 4 39 244 3 + 37 37 37 5 5 5 38 4 38 4 4 4 4 244 244 3 + 33 33 33 6 6 36 37 5 5 5 38 4 4 4 39 41 + 151 82 152 152 84 153 153 153 40 39 39 39 39 244 244 244 + 32 33 33 33 33 34 35 35 5 5 5 4 4 4 4 3 + 7 6 6 150 151 152 152 152 153 153 40 4 39 39 3 155 + 196 200 200 201 200 152 6 10 9 145 146 146 147 214 49 49 + 49 54 54 50 81 51 82 84 165 85 85 85 135 40 41 136 + 132 131 131 35 4 3 41 148 150 152 153 8 7 7 131 128 + 4 4 5 5 5 35 6 33 7 7 8 8 8 9 10 9 + 36 151 152 37 5 5 38 38 38 38 4 4 4 4 4 4 + 33 34 6 35 35 35 35 35 35 5 5 5 5 38 4 4 + 149 150 150 152 148 150 150 151 48 49 49 150 151 152 5 40 + 131 82 82 82 82 132 133 153 153 38 39 38 38 38 4 4 + 34 6 6 6 36 37 37 37 35 5 5 5 5 38 4 4 + 152 152 5 5 5 4 4 40 149 129 8 8 9 9 8 7 + 7 33 33 33 34 35 183 35 35 35 5 5 38 4 4 4 + 6 33 6 35 36 35 37 5 5 5 5 38 38 4 4 4 + 7 7 7 7 33 33 6 6 6 35 37 5 5 5 4 38 + 150 50 151 151 151 152 152 37 37 38 38 4 38 4 4 4 + 32 32 32 33 32 33 34 34 35 35 35 5 5 4 4 4 + 8 7 7 149 150 150 151 152 152 152 153 5 5 4 4 39 + 196 197 197 197 199 150 6 9 9 144 145 145 146 147 147 48 + 49 49 49 49 80 80 81 82 83 83 84 133 133 38 38 135 + 131 130 130 34 5 4 40 146 149 151 151 146 8 8 130 128 + 5 5 35 6 34 33 7 7 7 8 8 8 9 10 10 10 + 150 150 150 150 6 36 37 37 5 5 5 5 5 5 5 5 + 7 32 33 33 33 33 33 33 33 34 35 35 35 5 5 5 + 148 148 148 150 146 148 148 149 146 48 148 149 149 150 6 37 + 254 49 49 80 50 50 151 151 152 37 37 5 5 5 5 5 + 7 7 7 33 33 6 34 33 34 6 35 35 5 5 5 5 + 150 150 6 6 35 5 5 5 128 128 9 9 10 9 9 8 + 9 7 32 32 33 33 32 33 35 35 35 5 5 5 5 5 + 7 7 7 33 34 6 34 34 35 35 37 5 5 5 5 5 + 8 8 8 7 7 7 7 7 33 33 34 34 34 35 5 37 + 149 254 254 150 150 150 151 36 36 37 37 5 5 5 5 5 + 9 8 32 32 32 33 32 32 33 33 34 35 35 5 5 5 + 8 8 8 147 147 148 149 150 150 151 151 6 36 5 5 5 + 196 214 196 214 196 199 7 10 10 10 144 144 144 146 146 146 + 48 48 48 48 49 49 49 80 81 81 82 132 132 37 37 37 + 129 129 128 32 35 5 38 253 148 149 149 9 9 8 129 128 + 35 6 34 33 7 7 7 8 8 9 9 10 10 10 11 11 + 7 148 7 7 7 6 6 6 6 33 33 34 34 34 34 6 + 7 7 7 7 7 7 7 7 33 6 33 33 33 33 6 6 + 8 147 147 148 145 146 147 148 146 48 48 147 148 149 6 150 + 128 48 254 49 254 254 254 150 150 150 6 33 6 6 35 5 + 7 7 8 7 7 7 7 8 34 34 34 33 33 33 34 36 + 149 149 7 33 33 34 6 36 128 146 9 10 10 10 10 9 + 8 8 8 8 32 32 32 32 33 34 33 34 34 35 5 35 + 7 7 7 7 7 7 7 8 33 34 34 34 34 6 35 5 + 9 8 9 9 8 8 7 7 8 7 7 33 6 33 34 34 + 147 48 48 148 149 149 149 7 36 6 6 6 35 35 35 35 + 9 8 8 9 8 8 7 8 33 32 33 33 33 33 6 5 + 9 8 8 8 146 146 148 149 149 148 148 6 6 6 6 5 + 195 196 196 195 196 147 147 12 10 11 11 144 144 144 144 147 + 146 48 48 48 48 48 254 49 254 254 130 130 131 36 36 36 + 129 128 128 8 33 6 150 106 253 148 148 10 9 8 253 128 + 33 6 7 8 7 8 9 8 9 10 10 10 11 11 11 11 + 8 8 148 7 7 7 7 8 7 7 7 7 33 33 33 34 + 8 8 9 9 9 8 8 7 7 7 7 7 7 7 33 33 + 9 146 146 146 144 145 145 253 253 144 144 146 147 8 7 36 + 129 48 48 48 48 48 148 149 149 149 7 33 33 34 34 34 + 9 8 8 8 8 8 7 32 8 8 8 7 32 33 33 34 + 147 147 7 7 7 7 33 37 106 106 10 10 11 11 10 10 + 10 10 9 9 8 8 32 32 32 33 7 7 33 33 34 33 + 9 8 8 8 8 8 7 7 7 7 8 7 33 6 34 33 + 9 10 10 9 8 8 9 8 8 7 7 8 8 7 34 34 + 147 48 48 147 148 148 148 148 8 7 7 33 34 6 34 33 + 9 10 10 9 9 9 9 8 9 8 7 7 8 32 34 33 + 10 9 9 9 146 146 146 146 146 148 7 7 7 7 33 6 + 194 195 195 194 194 145 146 11 12 11 11 252 144 144 144 144 + 144 144 253 48 48 253 48 254 48 48 254 254 129 7 33 34 + 128 128 128 8 32 7 149 144 144 253 147 10 11 10 128 128 + 7 7 8 8 8 9 9 10 10 10 11 11 11 12 12 12 + 9 9 9 9 8 8 8 7 7 8 8 7 7 7 7 7 + 10 10 9 8 8 8 8 8 9 8 8 8 7 7 7 7 + 9 9 9 9 10 144 144 253 106 144 144 144 145 9 8 7 + 106 106 253 253 128 128 128 147 148 148 7 8 8 7 7 7 + 10 9 9 8 9 9 9 9 8 8 8 8 8 7 7 8 + 146 145 9 8 8 7 7 8 106 106 11 11 12 12 11 10 + 10 10 10 9 9 9 9 9 8 8 7 7 7 7 32 8 + 10 9 9 8 8 8 9 9 9 8 8 7 7 7 7 7 + 11 10 9 9 10 10 9 8 9 8 9 8 8 8 7 7 + 106 144 253 253 146 146 146 8 7 7 7 7 7 7 7 32 + 10 110 10 10 10 10 9 9 8 9 9 8 7 7 7 8 + 10 10 10 10 9 9 9 9 8 8 8 8 7 7 7 7 + 194 194 193 193 194 145 9 13 13 107 107 107 252 106 106 106 + 144 106 144 253 106 106 106 253 48 48 128 128 128 8 8 7 + 106 253 11 9 8 7 7 252 106 144 144 11 11 10 106 128 + 7 8 8 8 9 10 9 10 11 11 11 12 12 12 12 13 + 10 9 9 9 9 8 8 8 8 9 9 8 8 8 8 8 + 9 9 9 9 9 10 10 9 9 9 9 8 8 9 8 9 + 10 10 10 10 11 106 106 144 252 106 144 144 144 9 8 8 + 144 106 106 106 144 253 253 146 146 8 8 8 8 8 8 8 + 9 10 10 10 10 9 9 10 8 8 9 9 8 8 8 8 + 144 145 9 8 8 9 8 8 106 106 11 12 12 12 12 11 + 11 11 10 10 112 112 9 9 9 8 9 8 8 8 7 7 + 9 9 9 10 10 10 9 9 8 8 8 9 9 9 8 7 + 11 10 11 11 10 10 9 10 10 10 10 8 8 8 8 8 + 144 144 144 144 144 253 9 8 9 8 8 8 8 8 8 32 + 11 110 110 11 10 10 10 10 9 9 9 8 8 9 9 8 + 11 11 11 11 10 10 9 9 9 9 9 8 8 9 8 7 + 193 193 192 192 192 144 10 14 13 107 107 252 107 251 107 252 + 252 106 106 144 253 253 253 106 106 253 253 253 253 8 8 8 + 106 253 10 8 8 9 9 107 106 144 144 13 11 11 106 128 + 9 8 9 10 10 10 11 11 11 12 12 12 12 13 13 13 + 10 10 10 9 9 9 10 10 9 10 9 9 9 9 9 8 + 10 11 11 11 11 10 10 9 10 9 10 10 9 9 9 9 + 11 10 10 11 107 107 252 106 252 252 252 106 144 10 9 8 + 253 106 106 106 106 106 106 144 10 9 9 8 8 8 9 9 + 11 11 11 10 10 10 9 10 10 10 9 9 9 9 9 8 + 10 10 10 10 10 9 9 8 107 107 12 13 13 13 108 108 + 12 109 110 110 110 111 111 112 10 9 9 9 9 9 8 8 + 11 11 11 11 10 10 10 9 10 10 9 9 9 8 8 9 + 11 12 12 11 10 11 11 10 11 9 9 10 10 9 8 9 + 106 106 106 144 144 10 10 9 10 9 9 9 9 9 8 8 + 12 109 109 109 11 11 10 11 11 10 9 10 10 9 9 9 + 12 11 11 11 11 11 10 10 11 10 9 10 9 9 9 8 + 11 192 192 192 11 11 11 14 14 14 251 107 252 252 107 107 + 252 252 252 252 252 106 253 253 106 106 106 144 253 9 9 8 + 106 253 11 9 9 10 9 107 107 252 144 12 13 12 106 128 + 9 9 10 10 11 11 11 11 12 12 12 13 13 13 14 14 + 10 10 11 11 11 10 10 10 10 10 10 9 9 9 9 9 + 12 12 11 11 10 11 11 10 11 10 10 10 10 10 9 9 + 12 11 11 11 12 107 107 252 251 251 107 252 11 10 10 9 + 107 252 106 106 144 106 106 106 10 10 10 10 10 10 9 9 + 12 11 11 10 10 11 11 11 10 10 10 10 10 10 9 9 + 10 10 11 10 10 9 9 10 107 251 13 13 14 14 13 108 + 109 109 109 110 110 110 110 110 10 10 10 9 9 9 9 10 + 12 11 11 11 10 10 11 11 11 10 10 9 9 9 9 10 + 13 12 11 11 12 12 11 10 11 10 10 10 10 10 9 9 + 107 252 252 106 106 11 11 11 10 10 9 9 9 10 10 10 + 108 108 108 109 109 12 12 11 11 11 11 11 10 9 9 10 + 13 12 12 12 11 12 11 11 11 10 11 10 10 9 9 10 + 11 10 10 11 11 11 11 15 215 215 215 251 251 252 252 251 + 251 251 107 252 252 252 252 252 253 106 106 106 10 10 10 9 + 252 107 13 10 9 9 9 251 251 107 106 14 13 12 252 128 + 10 11 10 11 12 12 11 12 13 13 13 14 14 14 15 15 + 12 12 11 11 11 11 11 11 11 11 11 11 11 11 11 11 + 11 11 12 12 12 12 12 12 11 10 11 10 10 11 11 11 + 13 12 12 12 13 107 107 252 251 251 107 107 107 11 10 10 + 107 252 252 252 252 252 252 106 10 10 10 11 11 11 10 10 + 12 12 12 12 12 12 11 11 11 11 11 10 10 10 10 10 + 107 11 10 110 11 11 11 10 107 251 13 14 15 15 14 108 + 108 108 108 109 109 110 110 110 10 10 11 11 11 11 10 9 + 12 12 12 12 12 12 11 11 11 11 11 11 11 11 10 9 + 13 13 13 13 13 12 11 12 11 12 12 11 10 11 10 10 + 107 107 107 107 107 107 11 10 11 11 11 11 10 10 10 9 + 108 108 108 108 12 12 12 12 12 12 11 10 11 11 11 9 + 13 13 13 13 13 12 12 12 12 11 11 10 11 11 11 9 + 11 11 11 12 11 12 12 15 15 215 216 216 216 216 251 251 + 251 251 251 251 107 252 252 252 252 252 252 252 252 11 10 10 + 107 251 107 10 11 11 10 14 251 107 107 215 13 13 251 128 + 11 10 11 12 12 12 13 12 13 13 14 14 15 15 15 215 + 12 12 12 12 12 12 11 11 12 12 11 11 11 11 11 10 + 13 13 13 13 13 12 12 11 11 11 12 12 12 12 11 10 + 13 13 13 13 14 251 251 251 251 251 251 107 107 107 107 11 + 107 252 252 252 107 251 107 252 107 252 11 10 10 11 11 11 + 13 13 13 12 12 12 12 12 11 12 12 12 11 11 11 10 + 107 107 12 12 12 11 11 10 251 251 215 215 15 15 15 14 + 14 108 108 108 109 109 109 12 12 12 11 11 10 11 10 11 + 13 13 13 13 12 107 107 107 12 12 12 11 11 10 10 11 + 14 14 14 13 13 13 13 13 13 107 11 107 107 11 11 11 + 251 251 251 107 107 107 107 107 107 107 11 11 11 10 11 11 + 14 108 108 14 13 13 13 13 13 12 11 12 12 11 11 11 + 14 14 14 13 13 13 13 13 12 11 12 12 11 11 10 11 + 13 12 12 13 12 12 12 215 215 215 216 216 216 216 216 216 + 216 251 251 251 251 252 252 251 252 252 252 252 252 106 11 106 + 252 251 251 12 12 11 11 215 251 251 107 215 215 14 251 128 + 21 99 154 40 153 153 152 152 151 150 150 149 148 148 146 145 + 152 153 16 16 153 17 18 18 19 19 154 20 20 20 20 20 + 151 152 152 152 153 153 153 153 85 18 40 18 40 154 154 20 + 151 51 83 83 49 50 51 96 49 54 55 96 97 16 17 98 + 96 96 96 96 96 97 97 97 98 98 98 19 88 88 88 20 + 152 152 152 152 152 153 16 17 17 17 18 18 18 19 20 20 + 84 16 16 18 18 19 20 20 82 49 149 147 146 147 148 7 + 7 6 36 5 5 5 4 4 4 39 41 41 41 41 155 23 + 151 152 152 152 152 152 16 16 16 17 18 19 20 99 21 21 + 149 150 150 150 151 151 152 152 152 152 16 18 19 19 20 20 + 51 51 83 97 97 97 97 17 98 98 86 19 20 99 21 155 + 6 6 6 6 6 36 37 5 37 153 153 40 86 86 20 99 + 149 149 150 151 151 83 83 83 16 16 18 19 19 20 20 21 + 196 197 198 200 200 200 152 145 147 146 48 53 53 53 58 54 + 54 54 54 54 55 96 96 96 96 165 165 97 98 87 87 87 + 164 163 132 134 39 154 21 49 50 50 97 48 254 254 81 48 + 23 21 20 19 18 16 84 83 82 151 150 150 149 148 147 146 + 16 17 17 17 17 19 19 19 19 20 20 21 21 21 23 23 + 152 84 84 84 84 85 85 18 18 19 19 20 20 20 21 21 + 51 96 97 97 54 55 96 60 54 59 55 96 97 17 19 61 + 96 60 60 60 61 61 61 61 61 61 61 90 90 21 21 21 + 83 83 16 16 16 16 17 17 19 19 19 19 20 21 21 62 + 16 17 17 19 20 21 21 62 51 80 49 148 147 148 148 199 + 150 36 152 153 153 4 39 39 39 154 155 22 22 21 23 62 + 152 83 83 16 16 16 17 17 17 19 19 20 21 21 23 62 + 150 50 50 51 51 83 83 83 16 16 17 19 19 20 21 62 + 55 96 16 97 97 61 61 61 61 61 168 21 21 21 62 100 + 6 35 37 37 37 5 38 38 153 40 86 19 20 99 21 21 + 150 50 50 51 51 96 96 97 17 17 98 19 20 20 21 23 + 201 201 201 201 201 201 153 145 147 48 53 54 58 58 59 58 + 58 59 59 59 60 60 60 96 165 165 166 166 61 61 90 168 + 165 164 133 135 40 99 21 49 55 55 97 48 49 80 82 104 + 62 23 21 20 19 18 84 84 152 151 150 150 149 148 148 146 + 17 17 17 19 19 19 19 20 21 21 21 21 21 23 23 23 + 153 153 84 84 84 85 18 19 19 19 20 20 21 21 21 23 + 51 96 16 16 55 55 60 60 54 55 55 96 97 61 19 61 + 60 60 60 61 61 61 61 61 61 61 168 21 21 23 23 62 + 16 16 16 17 17 17 17 17 19 19 20 21 21 21 23 62 + 17 17 98 19 20 21 21 62 83 80 50 49 148 148 149 199 + 36 152 5 38 39 39 39 154 41 41 155 23 23 23 23 62 + 152 16 16 17 17 17 17 17 19 20 21 21 21 23 62 62 + 50 151 151 83 83 83 16 16 16 17 18 19 20 20 21 62 + 96 96 97 61 61 61 61 61 61 61 21 21 21 23 62 24 + 36 35 5 5 5 5 38 38 40 40 88 99 99 22 23 62 + 150 151 83 83 83 83 16 16 17 61 98 19 20 21 23 23 + 202 202 202 202 202 201 153 146 147 48 48 54 59 59 59 59 + 58 59 59 60 60 60 60 96 165 166 61 61 168 168 168 168 + 165 164 134 135 88 99 62 49 55 96 17 48 49 80 82 48 + 62 23 22 99 88 18 85 153 152 151 150 150 149 148 148 146 + 17 17 19 19 19 19 20 20 21 21 21 21 22 23 23 22 + 153 153 153 153 85 85 86 19 19 20 99 21 21 22 23 62 + 83 16 16 17 55 55 97 97 55 55 55 96 97 61 21 62 + 97 60 97 61 61 61 61 61 61 21 21 21 62 23 23 62 + 16 16 17 17 17 17 18 19 19 19 20 21 21 23 23 62 + 17 17 19 19 20 21 21 62 83 50 50 149 148 149 149 6 + 36 37 5 38 39 39 41 41 155 155 155 42 100 24 24 62 + 84 16 17 17 17 17 18 19 20 20 21 21 23 23 62 62 + 151 151 152 83 84 84 84 17 17 18 19 20 20 21 23 62 + 97 97 97 61 61 61 61 61 61 21 21 21 23 23 62 26 + 36 35 37 5 5 5 38 39 40 40 41 99 22 23 23 23 + 150 151 83 83 16 16 16 17 61 98 19 20 21 23 23 24 + 201 201 201 201 202 202 202 146 146 48 48 54 58 58 59 59 + 59 59 59 60 60 60 60 165 165 166 237 168 168 168 62 169 + 165 164 133 135 41 22 62 50 55 96 17 48 49 50 83 48 + 246 246 23 21 99 19 85 153 153 152 151 150 149 149 148 147 + 19 19 20 20 20 21 21 21 21 21 23 23 23 62 62 246 + 153 153 40 40 86 86 20 20 99 21 22 23 23 23 62 62 + 16 16 17 17 51 96 97 61 55 60 96 97 17 19 21 62 + 61 61 61 61 61 61 61 168 169 62 62 62 62 62 246 62 + 17 17 17 17 17 19 19 20 20 21 21 23 62 62 62 62 + 98 19 20 21 21 23 62 62 84 50 50 149 148 149 150 6 + 36 37 5 39 39 41 3 3 3 155 42 100 26 26 246 246 + 85 17 17 17 18 19 19 20 20 21 21 23 23 23 246 246 + 151 152 152 152 153 84 85 85 85 86 87 99 21 22 23 62 + 97 97 61 61 61 61 61 21 21 21 62 62 62 62 246 246 + 37 35 5 5 5 38 4 39 39 41 41 91 23 100 24 246 + 150 151 152 16 16 16 17 19 19 19 20 21 62 62 24 246 + 202 202 202 201 201 202 202 147 146 48 54 54 54 58 58 59 + 59 59 60 60 60 60 165 166 166 237 237 238 169 169 62 169 + 166 165 134 135 136 23 62 50 96 97 61 254 50 82 83 48 + 245 246 24 23 22 99 40 85 153 152 151 151 150 149 148 148 + 20 20 21 21 21 21 23 23 62 23 62 62 62 246 246 246 + 153 40 40 154 41 99 99 21 21 22 23 23 23 24 246 62 + 16 17 18 19 55 16 17 61 55 60 97 97 61 21 23 62 + 98 61 61 61 61 168 62 62 62 62 62 62 62 246 246 246 + 18 18 19 19 19 19 21 21 21 21 23 62 62 62 246 62 + 20 20 21 21 23 62 62 62 85 82 50 150 149 150 6 37 + 5 5 38 39 41 3 3 3 3 43 43 156 101 246 245 246 + 85 18 18 18 19 20 21 62 21 23 62 62 62 246 246 246 + 152 152 153 153 153 85 85 85 86 99 90 22 23 100 26 62 + 98 61 61 61 61 61 21 21 62 62 62 62 246 246 246 246 + 35 5 5 38 38 4 39 39 39 41 155 42 92 24 26 246 + 152 152 153 17 17 17 19 19 19 20 21 62 62 62 246 246 + 203 203 202 202 202 202 154 147 147 49 54 54 54 59 59 59 + 60 60 60 60 60 60 166 237 237 237 72 238 238 62 62 169 + 166 166 135 136 91 24 62 50 96 97 61 254 50 83 97 254 + 245 246 26 24 91 22 154 40 153 152 151 151 150 149 149 148 + 20 21 21 21 23 23 62 62 62 246 246 246 246 246 246 246 + 40 40 154 41 41 99 22 22 22 23 23 24 24 246 246 246 + 17 18 19 19 83 16 17 61 55 60 97 98 61 21 23 62 + 98 61 61 168 168 169 169 62 62 62 62 246 246 246 245 245 + 86 19 19 99 99 21 21 23 23 23 62 62 246 246 246 246 + 21 21 22 23 23 246 246 246 86 83 82 150 149 6 36 5 + 5 38 39 39 3 3 3 3 43 43 43 93 28 157 245 63 + 85 86 86 20 99 21 62 62 23 62 62 246 246 246 245 245 + 153 153 153 153 40 86 86 86 88 90 91 23 24 246 246 245 + 98 167 61 168 168 168 62 62 23 62 246 246 246 245 245 245 + 37 5 5 4 4 4 39 41 41 41 42 92 25 26 101 246 + 152 153 153 18 18 19 19 19 20 21 23 62 23 246 246 245 + 202 202 203 203 203 203 154 147 148 150 49 54 54 59 59 60 + 60 60 60 60 60 165 166 237 71 72 238 238 239 170 170 170 + 167 166 135 136 92 26 245 50 16 17 21 254 50 84 97 48 + 245 245 246 24 92 41 154 40 40 153 152 152 151 150 199 148 + 21 21 23 62 62 62 62 246 246 246 246 246 245 245 245 245 + 41 41 41 41 41 155 23 23 24 26 246 246 246 246 246 245 + 18 19 20 20 16 16 19 61 55 60 97 98 19 21 24 246 + 167 167 168 168 238 238 62 169 62 62 246 246 246 245 245 245 + 86 88 87 21 21 23 23 23 62 62 246 246 246 246 245 245 + 22 62 62 24 246 246 245 171 86 83 132 131 150 36 36 5 + 5 38 4 3 3 3 43 43 43 43 44 44 28 157 245 63 + 40 86 89 99 90 90 22 23 23 62 246 246 246 245 245 63 + 152 153 153 40 40 86 89 99 99 22 23 24 24 246 245 171 + 167 167 168 168 168 90 62 62 62 246 246 245 245 245 63 139 + 5 5 38 38 4 4 3 3 3 42 43 26 101 101 157 245 + 152 153 153 40 19 20 20 20 21 62 62 62 246 246 245 207 + 203 203 203 203 203 202 20 148 148 149 49 54 55 60 60 60 + 55 60 60 61 61 165 166 237 71 168 238 238 239 239 171 171 + 167 166 135 136 27 246 63 152 16 98 21 49 82 84 97 48 + 172 245 28 26 92 155 41 40 40 40 38 37 6 6 7 149 + 23 23 23 23 62 246 246 246 246 246 246 245 245 245 63 63 + 41 41 41 41 155 155 92 24 24 246 246 246 246 245 245 245 + 18 20 20 21 16 18 19 62 55 16 17 19 21 62 246 171 + 98 168 238 238 238 238 239 170 171 171 246 246 245 245 245 245 + 99 99 22 22 22 23 23 62 24 246 246 246 246 245 245 63 + 23 62 24 26 246 246 245 63 86 84 132 131 150 6 5 5 + 4 4 39 3 3 3 43 43 43 2 2 31 94 139 172 172 + 40 88 99 22 22 23 23 23 24 26 246 246 246 245 63 63 + 152 153 40 40 40 20 99 99 22 91 100 26 246 246 245 245 + 88 167 168 168 168 169 62 246 24 26 246 246 245 63 63 103 + 5 5 38 4 4 39 3 3 3 42 43 93 101 157 245 102 + 152 153 153 40 40 20 20 20 22 23 62 246 246 245 245 207 + 203 202 202 203 203 203 20 148 149 149 50 55 60 60 60 60 + 55 60 60 60 97 167 237 168 238 238 238 239 239 239 171 171 + 167 166 136 136 25 101 63 152 16 61 21 150 132 84 167 48 + 140 172 157 101 25 42 41 41 39 39 38 5 36 6 33 7 + 23 23 23 24 246 246 246 246 246 246 245 245 245 63 63 103 + 41 3 3 3 155 42 92 25 26 246 246 101 246 245 245 63 + 19 21 99 23 16 19 20 62 16 16 98 19 21 62 246 171 + 167 168 238 238 238 239 239 239 171 171 171 171 171 245 245 245 + 99 90 22 22 23 23 24 24 246 246 246 246 246 245 245 63 + 23 23 24 26 246 246 245 63 89 134 132 36 6 6 37 5 + 4 4 39 3 3 3 43 43 2 2 94 45 45 103 172 172 + 40 88 90 91 23 23 24 24 246 246 246 245 245 63 172 140 + 153 153 40 154 154 41 99 22 22 23 24 26 246 245 245 63 + 87 168 168 168 169 169 62 246 246 246 246 245 245 63 172 158 + 5 5 4 4 4 39 3 3 3 43 93 101 101 157 102 102 + 153 153 40 154 41 21 22 21 23 24 246 246 246 245 63 63 + 203 203 203 203 203 203 20 148 149 150 50 55 60 60 55 55 + 55 60 60 97 61 61 168 238 238 238 238 239 239 171 171 171 + 168 166 136 136 138 245 63 152 16 61 21 150 132 84 167 48 + 140 103 157 28 93 43 3 41 39 39 38 5 5 36 6 6 + 100 23 24 246 246 246 245 245 245 245 245 63 63 172 172 158 + 3 3 3 3 3 43 25 26 26 101 157 157 245 63 139 63 + 20 21 21 23 16 19 20 62 16 61 19 87 21 62 245 245 + 168 168 238 238 238 239 239 239 75 171 171 171 171 63 172 172 + 90 22 91 23 23 100 26 26 246 246 246 245 245 63 172 172 + 23 24 26 246 246 245 172 172 88 134 132 36 36 36 5 5 + 4 4 244 244 244 43 2 2 2 2 94 45 103 103 158 172 + 41 90 91 23 24 24 26 26 246 246 245 139 139 139 158 1 + 40 153 153 154 21 41 41 23 23 100 26 246 245 245 63 63 + 90 168 169 169 169 169 170 246 246 245 245 245 63 172 140 46 + 4 4 4 4 4 244 3 3 43 43 44 30 157 102 102 158 + 38 40 154 154 41 22 23 23 24 246 246 246 245 63 172 207 + 203 203 203 203 203 203 155 148 149 150 51 55 60 55 55 55 + 60 60 61 61 61 168 168 238 238 238 238 239 239 171 171 171 + 168 166 136 136 29 103 63 152 17 21 23 150 132 84 167 128 + 1 158 45 30 93 43 3 3 41 39 4 5 5 5 6 6 + 24 246 246 246 246 245 245 245 245 63 63 172 172 158 140 1 + 3 3 3 43 43 43 93 101 27 101 157 157 139 103 158 172 + 99 23 23 62 16 20 21 62 16 61 61 21 62 246 245 171 + 168 168 238 238 239 239 239 239 171 171 172 172 172 172 172 172 + 91 91 91 24 24 26 246 246 246 245 245 245 63 63 172 172 + 24 246 246 246 245 63 172 172 88 134 132 36 36 36 5 4 + 4 4 244 3 43 2 188 188 188 188 45 95 103 158 140 140 + 41 91 23 24 26 26 246 246 246 246 139 139 139 158 1 1 + 40 40 154 41 155 155 155 42 24 26 26 101 245 63 63 172 + 90 169 169 169 169 170 170 246 171 245 63 63 158 1 1 1 + 4 185 185 186 244 244 244 3 43 43 44 31 45 102 158 1 + 38 39 154 154 41 155 23 23 246 246 245 245 245 63 173 173 + 204 204 204 204 204 204 155 149 149 150 151 55 55 55 55 60 + 60 60 61 61 168 168 168 238 238 238 239 239 239 171 172 77 + 168 167 136 137 94 103 173 153 19 62 62 151 133 85 87 128 + 141 1 102 157 2 44 43 3 3 39 4 38 5 5 35 6 + 26 246 246 245 245 245 63 63 63 139 172 158 140 140 140 1 + 3 3 3 43 43 93 44 30 28 157 157 45 103 158 46 140 + 22 23 23 246 17 21 21 62 17 61 87 90 62 245 63 172 + 169 238 238 239 239 239 239 76 76 77 77 172 172 172 172 173 + 91 92 24 26 26 246 246 246 245 245 245 63 139 172 140 173 + 26 246 246 245 63 172 140 173 91 135 134 37 36 37 5 4 + 4 39 244 43 2 188 188 188 125 95 95 158 46 47 141 141 + 91 91 24 26 246 246 246 246 139 139 139 140 140 1 141 141 + 40 154 41 41 41 155 100 42 25 26 101 157 63 63 140 173 + 23 169 170 170 170 170 171 171 171 171 172 172 140 1 159 159 + 186 186 186 186 186 244 244 187 43 2 2 94 45 102 46 159 + 4 154 41 41 155 23 100 24 246 245 245 245 63 63 173 173 + 204 204 204 204 204 204 156 150 150 150 151 55 55 55 60 60 + 61 61 61 61 238 238 238 238 238 238 239 75 76 77 173 77 + 169 167 137 137 94 103 173 153 99 62 62 132 133 135 87 128 + 141 47 158 45 31 44 43 3 3 39 4 38 5 5 35 6 + 26 246 245 245 245 245 63 172 172 172 158 140 140 140 1 47 + 3 3 43 43 44 44 29 31 30 45 103 103 103 158 1 1 + 22 24 24 246 18 21 23 62 61 61 62 62 62 245 63 172 + 169 238 239 239 239 239 171 76 77 77 173 173 173 173 173 173 + 92 24 26 26 246 246 246 245 245 63 63 172 172 140 140 173 + 246 246 245 63 172 140 173 173 91 135 134 37 37 5 4 4 + 4 3 3 2 188 188 188 188 189 189 189 46 47 159 141 79 + 92 24 26 246 246 246 246 171 139 139 172 140 140 47 159 174 + 39 41 155 41 41 42 24 24 93 101 30 157 103 158 1 173 + 23 62 170 170 170 171 171 171 171 172 172 140 1 159 159 159 + 185 186 186 186 186 187 187 187 188 188 94 45 103 158 1 47 + 39 154 155 155 155 42 24 26 246 245 63 63 63 173 173 159 + 205 204 204 204 204 204 156 6 150 151 151 55 60 60 60 61 + 61 61 97 61 238 238 238 238 74 74 75 75 76 77 173 78 + 169 168 137 137 103 1 173 153 19 22 23 131 133 135 87 128 + 174 159 158 45 31 44 43 3 3 244 4 4 5 5 35 36 + 101 245 245 63 63 63 172 140 140 140 140 140 1 47 47 47 + 43 43 43 2 2 2 31 31 157 103 102 102 158 1 47 159 + 22 24 24 245 18 21 62 62 61 61 62 62 62 245 172 173 + 170 238 239 239 239 239 171 77 77 77 173 173 173 173 173 173 + 24 26 26 246 246 246 245 245 63 63 172 140 140 1 141 79 + 246 245 63 172 140 140 173 173 91 135 134 37 37 5 4 4 + 4 3 3 2 188 188 189 189 189 126 126 46 47 141 141 79 + 92 24 26 246 246 246 246 139 139 139 172 140 140 159 159 174 + 154 41 155 155 155 42 43 43 93 28 94 103 103 46 1 173 + 100 23 170 170 170 171 171 171 172 172 172 173 173 159 159 127 + 185 185 186 186 187 187 187 188 188 188 188 189 95 46 47 141 + 4 41 155 155 155 100 26 101 101 245 63 63 1 159 159 159 + 205 204 204 204 204 204 101 6 151 151 151 55 60 60 61 61 + 61 61 97 61 238 238 238 74 75 75 75 76 76 77 78 78 + 170 168 170 138 103 1 79 153 20 23 23 36 134 135 90 128 + 142 159 1 102 45 2 2 43 244 244 4 4 38 5 35 35 + 28 245 139 139 139 103 140 140 140 1 1 1 47 47 141 141 + 43 43 2 2 2 2 2 94 45 103 158 158 158 1 47 47 + 155 24 26 245 19 23 62 62 17 61 62 62 246 245 140 173 + 170 238 239 239 75 75 76 78 173 173 173 173 141 141 141 141 + 25 26 27 28 28 28 157 139 172 172 140 140 140 47 141 141 + 245 245 139 158 140 140 173 173 137 41 134 38 37 5 4 4 + 4 244 244 187 188 188 125 189 126 126 126 127 159 141 174 174 + 92 25 27 138 138 138 138 139 139 172 140 140 47 141 141 142 + 3 39 41 3 43 3 43 43 44 29 94 45 103 46 1 141 + 24 246 246 246 171 171 172 172 172 172 140 173 141 159 141 190 + 185 185 186 186 186 187 187 187 188 188 189 189 189 1 47 141 + 4 41 3 42 42 43 101 101 101 245 158 1 1 159 159 159 + 204 204 205 205 205 205 101 6 6 151 151 16 16 16 97 61 + 61 61 61 61 238 238 238 75 239 75 75 76 77 77 78 78 + 170 168 170 137 189 1 79 85 23 62 246 37 40 136 169 129 + 38 5 5 35 35 34 33 33 32 32 8 9 8 9 10 9 + 34 34 35 35 37 37 37 5 37 5 5 5 5 5 38 38 + 32 32 33 33 33 34 34 35 35 35 5 5 5 5 5 5 + 7 7 6 36 147 148 149 50 48 48 149 149 150 36 37 37 + 130 130 131 131 132 132 132 37 37 37 5 5 5 5 5 38 + 34 34 33 33 34 34 35 35 37 37 37 37 37 5 5 5 + 34 36 37 37 37 5 5 38 7 7 9 8 10 8 9 9 + 32 32 32 32 182 183 183 183 184 184 5 5 5 5 38 4 + 33 33 33 34 34 34 34 34 35 37 37 37 5 5 38 4 + 8 7 7 8 7 7 33 33 33 34 35 35 35 5 5 38 + 129 131 131 131 36 37 37 37 37 37 5 5 5 38 4 4 + 181 181 181 181 181 32 32 32 34 34 35 35 35 5 5 5 + 7 7 7 8 7 33 6 6 33 6 37 5 5 5 5 4 + 196 196 198 197 198 199 6 10 9 9 144 144 145 48 48 48 + 48 48 48 49 80 254 130 131 131 132 132 132 132 37 38 38 + 131 129 130 34 35 5 37 146 147 150 150 10 8 7 129 128 + 4 38 5 35 35 34 33 33 32 32 8 8 9 9 9 10 + 35 35 35 35 35 37 5 5 5 5 5 5 38 38 38 38 + 33 33 33 34 34 34 35 35 35 35 5 5 5 5 5 38 + 7 33 6 36 8 148 149 151 147 149 149 150 131 37 37 38 + 130 162 131 132 132 132 133 37 38 38 38 38 5 38 4 4 + 33 33 33 34 34 35 35 35 35 35 37 5 5 5 5 38 + 36 36 37 37 5 5 38 38 7 7 8 9 9 9 8 8 + 32 32 32 182 182 183 183 183 183 183 5 38 38 4 4 4 + 33 33 33 34 34 35 35 35 35 37 5 5 5 38 4 4 + 7 7 32 32 33 33 33 33 34 34 35 35 5 5 5 38 + 7 131 131 131 36 37 37 37 37 5 5 5 38 4 4 4 + 181 181 181 181 32 32 33 33 35 35 35 35 5 5 38 4 + 32 8 8 32 33 6 34 33 35 35 5 5 5 5 38 39 + 197 214 198 197 198 199 6 10 10 10 144 145 146 147 48 48 + 48 48 49 49 254 130 131 131 132 132 132 133 133 38 38 38 + 131 129 130 34 35 5 38 128 148 150 131 9 8 7 129 128 + 4 4 5 5 35 35 34 33 33 8 8 8 9 8 8 10 + 5 37 37 37 5 5 5 5 5 5 38 4 4 4 4 4 + 34 34 34 34 35 35 35 35 5 5 5 5 5 5 38 4 + 33 6 6 36 148 149 150 151 148 149 150 150 151 37 38 38 + 131 163 132 132 132 133 133 37 38 38 38 38 38 4 4 4 + 33 33 34 35 35 5 5 5 37 5 5 5 38 38 4 4 + 36 37 5 5 5 38 4 39 33 7 8 9 9 9 8 8 + 32 32 32 182 183 183 183 184 183 183 5 4 4 4 4 4 + 34 34 34 34 35 35 35 37 37 5 5 38 38 4 4 4 + 7 8 7 33 34 33 33 34 35 35 5 5 5 5 38 4 + 131 132 132 131 36 37 37 37 38 38 38 38 38 4 4 4 + 32 181 181 32 32 32 33 34 35 35 37 5 5 5 4 4 + 7 8 7 33 6 6 33 33 5 5 5 5 38 4 4 154 + 197 213 200 197 200 199 6 9 10 9 145 146 146 48 48 48 + 48 49 49 49 49 131 131 131 132 132 133 133 134 38 38 38 + 131 130 131 35 5 4 40 128 254 150 36 9 8 7 130 128 + 39 4 38 5 5 35 34 34 33 32 32 8 8 8 8 9 + 5 37 37 5 5 5 38 38 4 4 4 4 4 4 39 4 + 34 34 35 35 35 35 35 5 5 5 5 38 4 4 4 4 + 6 6 36 37 149 149 151 152 149 49 150 151 152 37 38 134 + 131 163 132 132 133 133 133 133 38 38 38 4 4 4 4 4 + 34 35 35 35 5 5 5 5 5 5 5 38 4 4 4 4 + 37 37 38 38 38 4 39 39 33 7 7 8 9 8 8 32 + 32 33 33 182 183 183 183 184 184 184 38 4 4 4 4 4 + 34 34 35 35 35 35 35 37 5 5 38 4 4 4 4 4 + 8 7 33 6 34 33 34 35 35 5 5 5 5 38 4 39 + 131 132 132 132 132 37 37 37 38 38 38 4 4 4 39 4 + 32 32 32 32 32 33 34 35 35 35 5 5 5 38 4 4 + 8 7 33 6 6 33 6 6 5 5 5 38 4 4 4 154 + 196 198 200 198 200 150 6 9 9 9 145 146 147 48 48 48 + 49 49 49 49 80 81 82 131 132 133 133 134 134 40 39 39 + 131 130 131 35 5 4 40 128 254 150 36 8 8 7 130 128 + 39 4 4 5 5 5 35 34 33 33 32 8 7 8 9 8 + 37 37 5 5 38 38 4 4 4 4 4 4 4 4 39 4 + 35 35 35 35 35 37 5 5 5 5 38 4 4 4 4 39 + 6 36 37 37 149 150 151 83 49 49 150 151 152 153 38 135 + 132 132 132 133 133 134 134 134 40 40 39 39 39 39 39 41 + 35 35 37 5 5 5 5 5 5 38 38 4 4 4 4 39 + 37 38 38 38 38 39 39 39 34 7 8 8 9 8 8 32 + 32 33 33 182 183 184 184 184 185 185 4 4 4 4 4 244 + 35 35 35 37 5 5 37 5 38 38 4 4 4 4 39 3 + 7 33 6 6 33 6 35 5 35 5 5 38 38 4 4 39 + 132 132 132 132 132 133 37 38 38 38 39 39 39 39 39 244 + 32 32 33 33 34 34 35 35 37 5 5 38 38 4 4 4 + 7 6 6 6 6 6 37 5 37 5 5 4 4 4 39 41 + 196 200 200 200 200 151 6 9 9 9 146 147 48 48 48 49 + 54 49 49 80 81 82 82 164 165 133 134 134 135 40 39 41 + 132 130 131 35 5 4 40 128 150 151 37 8 8 7 130 128 + 3 244 4 4 5 5 35 35 33 33 32 8 7 8 9 8 + 5 38 38 38 4 4 4 4 4 4 4 4 39 3 41 39 + 35 35 35 37 5 5 5 5 38 4 4 4 4 4 39 3 + 6 36 37 37 149 150 152 84 49 49 50 152 153 153 39 136 + 132 164 133 133 134 135 135 135 88 40 154 41 41 41 41 3 + 37 37 5 5 5 5 5 38 38 4 4 4 4 39 39 41 + 38 153 38 38 39 39 41 41 36 33 7 8 8 8 32 33 + 33 33 34 183 184 184 184 184 184 184 4 4 39 3 3 3 + 5 35 37 37 37 5 38 38 4 4 4 39 39 3 3 3 + 33 6 6 33 6 5 5 5 5 5 38 4 4 4 4 41 + 132 132 132 132 133 133 133 38 40 39 39 39 41 41 3 244 + 32 33 33 34 34 35 35 5 5 5 38 38 4 4 4 3 + 33 6 6 6 6 37 5 37 5 38 38 4 4 39 3 156 + 198 201 200 200 200 151 36 9 9 145 146 147 48 49 49 54 + 54 49 49 54 51 82 83 165 165 165 85 135 135 40 41 136 + 132 131 132 35 4 244 41 128 150 151 37 8 7 33 131 128 + 3 3 244 4 4 5 5 35 35 34 32 7 7 8 8 8 + 38 38 40 40 39 39 39 39 39 39 244 3 3 3 3 3 + 5 5 5 5 5 38 38 4 4 4 4 39 39 3 3 3 + 36 37 37 153 150 151 83 16 50 50 82 84 153 40 40 136 + 133 133 134 134 135 135 86 86 89 41 41 41 155 155 42 3 + 37 5 5 38 38 38 4 4 4 39 39 39 3 3 3 3 + 40 40 40 40 39 41 42 155 37 34 7 7 8 8 33 33 + 33 34 35 183 184 184 184 184 185 185 4 3 3 3 3 3 + 5 37 37 5 5 38 38 38 4 39 41 3 3 3 3 3 + 6 6 6 6 37 5 5 5 5 38 4 4 39 41 3 42 + 132 133 133 84 85 85 85 40 40 41 41 41 3 3 3 244 + 33 33 34 34 35 35 5 5 5 38 4 4 39 244 3 3 + 6 6 6 36 36 37 5 153 153 39 39 39 39 41 3 156 + 201 201 201 201 200 152 37 9 9 146 147 147 49 54 54 54 + 54 54 54 55 51 83 165 166 165 166 135 86 88 41 41 136 + 133 132 132 37 4 3 91 129 150 152 38 8 7 6 132 128 + 43 3 3 39 4 4 5 5 5 6 6 33 7 7 7 8 + 38 40 40 40 154 41 41 3 3 3 3 3 3 3 3 3 + 5 5 38 38 38 4 4 4 4 4 41 3 3 3 3 3 + 37 37 153 153 151 152 84 16 50 51 83 84 85 40 41 91 + 134 165 134 135 135 86 86 88 91 91 91 42 92 92 43 43 + 5 38 38 4 4 4 4 39 39 39 41 41 3 3 3 43 + 40 154 154 41 41 42 92 42 37 34 34 8 7 8 33 33 + 34 35 5 184 185 185 185 185 186 244 244 3 3 43 43 43 + 5 5 38 38 4 39 39 4 39 39 3 3 43 43 43 43 + 6 6 36 5 5 5 5 4 38 4 39 41 3 3 3 92 + 133 84 84 85 86 88 86 99 41 41 155 42 42 43 43 43 + 35 183 183 183 35 5 5 4 4 4 39 41 3 3 43 43 + 6 151 152 153 153 152 153 154 40 154 154 155 3 3 3 156 + 202 202 201 202 152 153 38 8 8 147 147 147 214 54 54 54 + 54 55 60 96 51 96 165 166 166 167 167 136 136 91 42 137 + 133 132 133 38 4 3 92 254 151 152 40 7 7 36 133 128 + 44 43 3 3 4 4 5 5 35 5 6 33 33 7 8 7 + 154 41 41 41 41 41 3 3 3 3 3 3 3 3 43 43 + 38 38 38 38 4 4 39 39 39 41 3 3 3 3 3 43 + 37 153 40 40 151 152 17 17 50 51 83 84 18 89 91 137 + 134 134 135 135 88 89 90 90 90 91 91 92 92 25 25 43 + 38 4 4 39 4 39 39 41 3 3 3 3 3 43 43 93 + 40 154 41 41 41 42 25 25 37 36 36 8 7 32 33 33 + 35 35 5 184 185 185 185 186 186 244 244 3 43 43 2 2 + 5 38 38 38 39 39 39 39 41 3 3 3 43 43 44 44 + 36 36 37 37 5 38 4 4 4 4 39 3 3 3 43 43 + 153 84 85 86 86 86 99 41 41 41 155 3 3 43 43 2 + 183 182 183 184 183 184 184 5 4 4 4 3 3 3 43 44 + 36 151 152 152 153 153 40 40 154 154 41 155 3 43 43 101 + 201 201 202 201 201 153 38 8 8 147 148 214 214 54 54 54 + 60 55 55 55 96 97 166 167 166 167 168 168 90 137 92 137 + 134 132 133 38 244 3 25 130 132 153 40 7 6 36 133 128 + 2 43 3 3 244 4 4 5 5 5 35 34 34 33 7 7 + 41 99 155 155 155 155 42 3 43 43 43 43 43 43 43 2 + 4 4 4 4 4 39 41 3 3 3 3 3 43 43 43 43 + 5 40 154 40 151 84 18 98 51 83 16 17 19 21 92 26 + 135 135 167 136 168 90 169 137 91 100 24 25 26 26 27 101 + 38 4 39 39 39 39 41 41 3 3 3 43 43 43 44 28 + 41 99 91 42 92 25 27 28 38 37 34 33 7 33 33 35 + 35 5 184 185 186 186 186 186 186 244 43 43 44 2 2 2 + 38 38 39 39 39 39 41 41 3 3 43 43 43 44 2 2 + 37 37 5 5 38 4 4 4 4 39 3 3 3 43 43 44 + 40 86 86 20 99 99 22 23 23 100 156 93 44 2 2 188 + 183 183 184 184 184 184 185 185 185 4 244 3 3 43 44 157 + 152 152 152 153 153 40 154 154 154 41 155 155 43 43 44 157 + 202 202 202 201 201 154 4 8 8 148 199 214 214 54 55 55 + 60 60 60 60 97 97 166 167 167 167 168 168 137 26 27 138 + 135 133 134 38 244 43 27 150 84 85 40 7 6 37 133 128 + 31 2 43 3 3 244 4 4 38 5 35 35 34 33 32 7 + 41 22 23 23 42 42 43 43 43 43 43 2 2 2 2 2 + 4 4 39 39 39 3 3 3 3 3 43 43 43 43 2 44 + 38 40 154 20 152 84 18 19 83 83 16 19 99 23 26 246 + 135 167 168 168 169 169 169 24 26 26 26 101 28 101 28 30 + 39 39 154 41 41 41 3 3 3 3 43 43 43 2 2 30 + 155 22 91 92 92 43 27 28 38 37 36 36 7 33 33 5 + 35 5 184 185 186 186 186 187 187 187 2 2 2 31 31 31 + 38 39 39 39 41 41 155 155 42 43 43 93 2 2 31 31 + 5 5 38 38 4 39 4 4 39 3 3 43 43 93 2 30 + 40 86 88 99 90 22 23 23 24 25 101 44 2 31 31 188 + 184 183 184 184 184 185 185 185 186 244 244 3 43 44 30 157 + 5 153 153 153 40 154 154 154 41 155 155 156 43 44 30 157 + 202 202 203 202 201 154 154 7 8 199 199 214 214 55 55 55 + 55 60 60 61 61 61 166 167 167 168 168 169 137 138 138 138 + 135 133 135 39 187 2 28 131 84 85 41 7 6 37 134 128 + 45 2 44 43 3 3 4 4 4 5 5 35 34 33 33 7 + 155 22 23 100 92 156 43 43 44 44 2 2 2 31 31 31 + 4 39 39 41 3 3 3 3 43 43 43 43 43 2 2 31 + 40 40 41 41 152 84 19 87 83 16 17 20 21 23 26 246 + 135 136 168 169 169 169 169 170 246 246 246 101 28 157 157 157 + 39 154 41 155 3 3 3 3 3 43 43 44 2 2 2 31 + 42 91 92 92 43 93 28 28 38 37 37 34 34 33 34 5 + 5 5 185 185 186 186 186 187 187 2 2 31 31 31 94 45 + 39 40 41 41 41 42 42 42 92 43 93 2 2 31 45 45 + 5 5 38 39 39 39 39 39 41 3 3 43 43 44 2 94 + 40 86 88 99 22 23 23 24 26 26 101 30 31 31 31 188 + 184 183 184 184 184 185 185 186 186 244 244 43 43 44 31 102 + 5 5 153 153 40 154 41 41 155 155 156 156 44 44 31 102 + 202 203 204 202 202 154 154 7 7 199 199 214 50 55 55 55 + 55 60 60 61 61 61 167 167 168 168 169 169 170 138 138 138 + 135 134 136 244 187 2 28 36 84 86 41 33 37 5 134 128 + 95 45 2 43 43 3 39 4 4 5 5 5 6 34 33 7 + 42 23 100 24 25 156 101 44 2 2 2 31 94 45 45 45 + 39 41 3 3 3 3 3 3 43 43 43 2 2 2 2 45 + 40 154 41 22 153 85 87 21 83 16 18 20 22 24 101 246 + 136 136 169 169 169 170 170 171 246 246 246 157 94 157 45 45 + 41 41 155 155 3 3 43 43 43 43 44 2 2 31 45 102 + 24 24 26 27 28 29 94 139 38 38 38 34 34 34 35 5 + 5 4 185 186 186 187 186 187 188 188 2 31 45 95 95 158 + 39 41 41 41 42 92 92 25 93 93 44 31 94 45 95 158 + 5 38 39 39 39 41 41 3 3 3 43 43 2 2 31 45 + 41 89 90 91 91 24 246 246 246 101 157 157 45 95 158 126 + 184 184 184 184 185 185 185 186 187 187 187 43 2 2 45 102 + 5 153 153 40 154 41 155 155 156 156 156 44 30 31 45 102 + 203 202 202 202 203 155 41 7 7 199 200 200 55 55 96 55 + 55 60 60 61 61 167 167 168 169 169 169 170 170 138 139 139 + 136 135 136 244 188 2 94 132 85 89 91 6 5 38 135 128 + 47 158 45 2 43 3 3 3 4 4 38 5 35 35 34 33 + 24 24 26 26 101 101 30 157 94 45 45 95 95 95 158 158 + 3 3 3 3 3 43 43 43 2 2 2 2 2 94 45 95 + 41 41 23 23 153 86 21 62 84 17 19 21 23 246 245 139 + 90 169 169 169 170 170 171 171 171 245 139 139 103 103 158 158 + 3 155 155 155 3 43 43 44 44 2 31 31 45 95 95 158 + 26 26 28 28 31 45 103 140 39 39 38 36 33 5 35 5 + 4 185 186 186 187 187 187 187 125 189 45 95 95 158 46 47 + 41 41 91 91 92 25 27 27 28 29 94 45 95 158 158 1 + 38 39 154 41 41 41 3 3 3 43 93 2 2 94 95 103 + 136 136 91 137 137 246 246 246 246 245 245 157 45 158 46 190 + 184 185 185 185 186 186 186 187 187 187 188 188 188 45 95 158 + 38 4 39 154 155 155 155 42 156 101 30 157 45 45 102 1 + 203 203 203 203 20 155 155 7 7 199 200 200 55 16 96 96 + 60 60 61 61 61 168 168 169 238 239 239 170 171 139 139 172 + 136 135 137 244 188 95 172 37 86 90 92 6 5 4 135 128 + 159 1 95 31 2 43 3 3 39 4 4 5 5 35 34 34 + 27 246 246 101 157 157 45 103 45 95 95 95 158 46 46 1 + 3 3 3 43 43 43 2 2 2 2 31 95 95 95 95 158 + 41 155 100 24 40 88 22 62 16 17 20 21 24 246 245 172 + 137 169 169 169 170 170 171 171 172 172 172 172 140 1 1 1 + 3 42 42 43 43 93 2 31 2 31 94 95 95 95 158 1 + 27 27 28 30 94 103 140 140 41 39 38 37 6 5 5 5 + 4 186 186 122 123 123 123 124 125 189 95 95 46 46 127 47 + 41 91 137 137 24 138 138 28 94 94 45 158 158 46 127 159 + 39 154 41 41 41 155 3 3 43 43 2 31 45 95 95 46 + 136 137 137 137 170 170 246 171 171 245 63 103 103 46 46 126 + 185 185 185 185 186 186 186 187 187 188 188 188 188 189 189 46 + 4 39 39 41 155 42 156 156 44 30 157 45 102 158 46 159 + 204 203 204 204 20 155 42 6 7 199 200 201 16 16 96 96 + 61 61 61 61 61 168 238 238 239 239 239 171 171 172 140 140 + 169 135 137 244 125 126 140 153 86 22 92 6 5 39 135 128 + 141 140 103 157 28 93 43 42 39 41 39 5 38 37 6 36 + 246 246 246 245 245 245 63 172 139 103 103 158 158 140 140 140 + 42 92 25 93 93 93 28 29 29 94 45 103 103 103 158 1 + 155 22 23 24 18 19 62 62 97 17 61 62 62 245 63 63 + 169 169 169 170 239 76 76 76 63 63 172 172 173 173 173 173 + 91 100 24 26 26 101 101 157 30 157 45 103 103 158 1 173 + 246 246 245 245 139 172 173 173 91 40 40 37 5 5 5 4 + 4 3 3 187 124 124 124 125 188 95 102 158 1 1 47 173 + 91 91 137 24 26 246 246 246 245 139 172 140 140 1 47 141 + 40 154 41 41 41 155 42 24 25 26 157 45 103 103 46 140 + 137 137 170 170 170 171 171 171 171 63 172 173 173 140 140 47 + 185 185 185 185 187 187 244 187 188 188 188 94 45 103 46 140 + 40 40 154 41 155 23 100 24 101 101 245 63 63 140 140 159 + 205 204 204 204 204 23 156 6 6 150 150 55 60 60 60 60 + 61 61 61 61 61 72 73 238 238 74 239 239 171 172 173 173 + 169 167 136 244 45 158 173 84 86 22 246 36 40 41 88 128 + 152 152 151 150 149 149 148 148 146 146 253 145 144 10 10 144 + 254 254 49 49 150 150 150 150 131 131 131 151 151 132 36 151 + 128 128 148 254 149 254 149 149 130 150 150 150 36 36 36 151 + 147 48 254 254 253 146 48 49 48 48 48 48 49 49 149 82 + 254 104 104 104 49 80 80 80 50 50 150 150 151 151 132 151 + 48 254 254 254 254 254 254 254 254 150 150 150 131 151 132 151 + 254 149 149 150 150 151 151 151 146 146 144 144 10 10 10 9 + 9 146 8 7 7 7 7 7 6 6 36 36 151 151 152 152 + 48 128 254 254 254 49 49 149 150 150 150 151 151 151 152 153 + 147 147 146 146 147 148 148 147 254 149 149 149 150 131 36 151 + 128 48 254 254 254 254 49 50 49 50 151 151 151 151 132 37 + 9 9 9 8 8 7 8 8 7 7 7 130 36 36 36 151 + 253 146 147 146 146 147 148 149 149 150 150 150 150 151 151 152 + 195 196 214 214 196 147 147 11 10 144 144 106 52 52 53 53 + 53 53 53 52 53 104 104 104 104 161 162 80 80 130 151 133 + 255 129 129 33 34 36 132 144 48 48 49 106 144 146 128 128 + 84 84 84 82 50 50 49 49 147 148 147 146 144 253 144 144 + 50 50 50 51 51 51 82 82 83 83 83 84 84 84 84 84 + 49 49 49 50 50 50 50 82 82 151 82 152 152 153 153 85 + 49 49 49 80 48 49 54 54 53 53 49 49 54 51 83 83 + 80 162 162 54 81 96 96 55 51 51 83 83 84 84 84 84 + 254 49 49 80 50 50 82 82 50 82 83 83 83 84 84 84 + 50 51 82 82 83 84 84 97 49 48 146 145 145 145 145 147 + 147 148 149 150 151 151 151 152 5 152 153 153 153 153 85 18 + 49 49 80 80 50 50 50 50 82 82 83 84 84 84 84 84 + 146 48 49 49 49 49 50 50 50 50 50 151 82 152 84 84 + 49 49 80 50 50 50 51 51 51 83 83 16 84 84 85 40 + 7 7 8 8 7 33 6 36 150 150 151 152 152 84 84 84 + 48 48 49 49 49 49 50 50 50 51 82 83 83 84 17 19 + 196 213 214 214 214 149 149 10 144 144 53 52 53 53 53 53 + 52 53 59 59 58 249 249 249 249 250 250 165 96 83 83 84 + 162 255 130 131 132 152 85 253 48 49 50 253 48 48 254 128 + 98 98 16 83 83 82 151 150 149 149 148 148 146 146 144 144 + 83 83 83 83 83 16 16 16 16 16 16 17 17 18 18 17 + 51 51 82 82 51 50 82 83 16 16 16 16 16 17 18 18 + 49 50 50 50 49 54 55 54 53 54 54 54 55 96 16 97 + 250 250 250 250 55 55 96 96 97 16 16 16 17 17 17 17 + 50 50 50 50 51 83 83 83 83 16 17 17 16 17 17 17 + 51 83 83 83 16 16 16 16 49 49 48 146 146 146 146 147 + 148 149 150 151 152 152 5 5 5 37 153 153 40 40 40 18 + 50 50 50 50 82 82 83 83 84 84 84 85 85 85 85 19 + 49 49 49 49 48 49 49 50 51 83 83 83 16 17 18 17 + 50 50 50 51 55 96 96 16 16 16 16 17 17 19 19 20 + 7 7 7 6 6 36 150 150 151 152 153 153 16 16 17 18 + 48 49 49 49 49 50 50 50 51 83 16 16 16 17 17 203 + 214 213 213 213 200 150 151 144 144 253 53 53 53 57 58 53 + 58 58 58 58 58 59 59 68 68 68 250 250 96 97 17 98 + 163 162 131 132 37 153 17 48 54 55 50 253 48 48 80 48 + 61 61 17 16 16 83 83 51 50 49 148 149 147 146 253 146 + 96 96 96 16 16 16 16 16 61 17 17 17 19 19 19 19 + 50 50 51 83 83 16 16 17 16 16 17 17 17 19 19 61 + 51 55 96 55 53 54 55 60 54 59 54 55 60 60 16 61 + 250 250 250 250 60 61 61 61 61 61 61 61 61 61 61 61 + 55 96 96 55 55 96 96 16 16 16 17 17 17 19 19 61 + 16 16 16 16 17 61 61 61 54 49 48 48 146 147 148 148 + 149 150 151 152 153 153 153 153 40 40 40 20 21 21 21 21 + 51 51 82 83 83 83 16 16 16 16 17 18 19 19 19 21 + 49 49 49 50 51 96 96 55 96 96 16 16 16 17 19 61 + 55 55 55 55 60 60 60 60 60 16 61 61 61 61 61 20 + 150 6 6 36 151 152 152 153 152 153 16 17 17 17 19 61 + 49 54 54 51 55 55 96 96 96 16 16 16 17 61 61 203 + 214 213 213 213 55 55 50 144 253 48 53 53 57 57 58 58 + 59 58 59 59 59 60 60 236 250 250 60 60 61 61 61 61 + 96 163 132 133 85 19 61 48 54 55 96 48 49 49 80 104 + 49 49 48 48 48 48 253 253 144 253 253 106 252 252 252 252 + 48 53 53 53 48 48 48 48 49 49 49 49 49 49 49 49 + 48 48 48 48 48 253 253 253 253 48 48 48 49 49 49 49 + 52 52 53 53 52 52 52 53 52 52 52 52 53 53 48 54 + 52 248 248 52 52 53 53 53 54 54 49 49 49 49 49 49 + 48 53 53 48 48 48 48 48 48 48 48 48 49 49 49 49 + 52 52 53 53 48 48 49 54 105 105 106 252 252 252 144 144 + 144 144 145 146 146 147 147 147 147 146 147 48 49 49 49 49 + 253 105 48 48 48 48 48 48 48 48 48 49 80 49 49 49 + 106 106 106 144 105 48 48 253 48 48 48 48 48 48 49 49 + 53 53 53 53 53 53 53 53 53 53 49 49 49 49 49 49 + 144 144 144 106 106 144 253 146 146 48 48 48 48 49 49 49 + 106 106 106 144 52 52 53 53 53 53 48 48 49 54 49 214 + 195 212 214 214 53 53 48 252 252 252 247 247 247 247 247 56 + 56 56 56 52 52 52 52 52 53 53 53 53 54 54 54 54 + 105 105 105 253 146 48 49 247 52 52 53 252 252 247 105 160 + 51 51 81 49 49 48 48 48 48 48 48 105 105 106 106 106 + 54 54 54 54 54 54 49 49 55 55 55 55 55 55 55 55 + 48 48 48 48 49 49 49 49 49 49 80 54 51 51 51 55 + 53 53 53 54 53 53 53 58 52 52 53 53 53 54 54 54 + 249 249 249 249 249 54 54 54 54 54 54 55 55 55 51 55 + 53 53 54 54 54 54 54 54 54 49 49 54 55 55 55 55 + 54 54 54 54 54 55 55 55 53 52 105 105 106 144 253 253 + 146 146 48 148 49 149 149 149 50 50 50 51 51 55 55 55 + 53 53 53 54 54 54 54 54 54 54 54 55 55 55 55 55 + 48 48 48 48 53 53 53 49 49 54 49 49 54 54 55 55 + 53 53 54 54 54 54 54 54 54 54 55 55 55 55 55 51 + 253 253 128 48 254 48 48 48 49 49 49 80 50 51 55 55 + 48 53 53 53 53 53 54 54 54 54 53 54 55 55 55 55 + 195 212 214 214 53 53 48 252 106 247 247 52 56 56 56 56 + 56 56 57 57 57 57 58 58 58 59 59 54 54 55 55 55 + 249 160 255 130 50 96 55 53 52 52 54 105 52 53 105 160 + 97 97 96 51 50 50 49 49 49 48 48 253 253 106 106 105 + 55 55 55 55 55 55 55 55 96 96 96 97 97 97 97 97 + 49 49 49 50 50 50 50 50 83 96 96 96 96 96 96 96 + 53 54 54 54 53 53 54 59 53 58 58 54 59 55 55 60 + 249 249 249 249 250 250 250 60 55 55 60 60 97 96 96 96 + 49 54 54 54 54 55 55 55 55 55 55 96 96 97 97 60 + 55 55 55 55 55 96 96 96 53 48 48 48 253 253 146 146 + 148 148 149 150 151 151 151 151 152 152 83 16 97 97 97 60 + 53 54 54 54 55 55 55 55 55 55 55 60 60 60 16 61 + 48 48 49 54 49 49 49 54 54 55 55 55 55 96 97 97 + 49 54 54 54 55 55 55 55 55 55 60 60 97 97 97 97 + 48 128 148 254 254 254 49 49 50 51 51 83 83 97 97 97 + 48 48 48 49 49 54 54 54 55 55 55 55 96 96 96 16 + 196 213 213 214 54 54 54 144 144 144 52 52 57 57 57 57 + 57 57 58 58 58 58 58 59 59 59 250 60 60 60 60 96 + 250 104 131 131 82 97 96 53 54 54 49 105 53 53 160 160 + 61 61 61 60 60 55 55 54 54 54 80 48 49 48 48 105 + 60 60 60 60 60 60 60 61 60 60 61 61 61 61 61 61 + 51 51 51 55 55 55 55 96 61 60 60 60 60 61 61 61 + 59 59 60 59 58 59 59 60 58 58 59 59 60 60 60 61 + 60 67 250 60 68 60 60 60 61 61 61 61 61 61 61 61 + 59 55 60 60 60 60 60 60 60 60 60 61 61 61 61 61 + 60 60 60 60 60 61 61 61 55 53 53 53 105 48 49 49 + 49 49 50 51 16 16 16 16 61 61 61 61 61 61 61 61 + 55 55 60 60 60 60 60 60 60 60 60 61 61 61 61 61 + 54 54 54 54 54 54 55 60 55 60 60 60 60 61 61 61 + 60 59 59 59 60 60 60 60 60 60 60 61 61 61 61 61 + 49 49 50 50 50 51 51 83 96 97 97 97 97 61 61 61 + 54 54 54 54 55 55 60 60 60 60 60 60 61 61 61 204 + 213 213 213 54 59 59 55 52 52 53 53 58 57 58 57 57 + 229 58 58 58 59 59 59 60 60 60 236 60 60 60 61 70 + 68 249 164 164 97 61 61 54 59 59 55 53 53 54 54 104 + 59 58 53 53 53 53 52 52 247 52 52 247 247 247 247 247 + 53 58 58 57 58 58 58 53 53 53 53 53 53 53 58 59 + 53 53 53 53 53 53 53 53 53 53 53 53 53 53 53 53 + 52 52 52 52 56 56 56 56 56 56 56 56 56 57 58 53 + 52 52 52 52 57 58 58 53 53 53 53 53 53 53 53 58 + 52 52 52 52 53 58 53 58 53 53 53 53 53 53 58 58 + 58 57 57 53 53 53 58 58 52 52 52 52 52 247 247 247 + 106 144 52 53 48 48 53 53 53 53 53 53 54 59 59 58 + 52 52 52 52 53 53 53 53 53 53 53 53 53 58 59 59 + 247 52 52 52 52 52 52 52 52 53 53 53 53 53 58 58 + 52 52 52 52 57 58 57 58 58 58 53 53 53 58 59 54 + 247 247 52 52 53 53 53 53 53 53 53 53 53 53 53 58 + 52 52 52 52 52 52 52 52 58 58 53 53 53 53 53 59 + 212 212 52 52 52 52 52 247 247 52 56 56 219 225 225 225 + 225 56 56 56 56 56 56 56 56 57 58 58 53 53 58 58 + 248 248 248 53 53 53 53 52 56 52 52 247 52 52 52 58 + 59 59 59 58 58 53 53 53 53 52 52 247 52 247 247 52 + 57 57 58 58 58 58 59 59 59 59 58 58 58 58 59 59 + 53 53 53 53 53 53 58 58 58 59 59 59 59 59 58 58 + 57 58 58 58 56 57 57 57 56 56 56 57 58 58 58 59 + 58 58 58 57 57 58 58 58 58 58 59 59 58 58 58 59 + 57 58 58 58 58 57 58 58 59 58 59 59 59 58 58 58 + 57 58 58 59 59 58 58 58 52 52 52 247 247 247 52 52 + 52 53 53 53 48 49 49 54 54 54 54 54 59 59 59 58 + 53 58 58 57 57 53 58 58 58 58 58 59 59 59 59 59 + 53 53 53 52 52 52 53 53 53 58 58 59 59 59 59 58 + 57 58 58 58 58 58 58 58 58 58 59 59 59 59 59 59 + 52 52 52 52 53 53 53 53 53 53 58 58 59 59 59 59 + 52 52 57 57 57 58 58 57 57 58 59 59 58 58 59 59 + 212 212 58 58 58 57 57 247 52 52 56 225 225 225 225 225 + 56 56 56 56 56 57 58 58 58 57 57 58 58 59 59 58 + 227 227 53 249 59 59 59 52 56 57 58 52 52 52 52 58 + 60 60 55 54 54 54 54 54 53 53 53 53 53 52 247 52 + 59 59 59 59 59 59 59 59 60 60 59 60 60 60 60 55 + 54 49 54 54 54 54 54 54 54 54 54 55 55 60 60 60 + 53 58 58 58 53 57 58 58 57 57 57 58 58 59 59 59 + 53 58 58 58 58 58 59 59 59 59 59 60 60 60 250 60 + 58 58 58 58 59 59 59 59 59 54 59 59 60 60 60 60 + 59 59 59 59 59 59 60 60 53 53 52 52 52 52 48 48 + 48 48 48 49 49 50 50 50 51 51 55 55 55 55 55 55 + 53 58 59 59 59 58 58 59 59 59 59 55 60 60 55 55 + 53 53 53 53 53 53 54 59 54 54 54 54 59 55 60 60 + 53 58 58 58 58 58 58 59 59 59 59 60 60 55 55 60 + 48 48 48 48 48 48 48 49 49 54 54 54 55 55 55 60 + 53 53 53 53 53 58 59 59 59 59 59 59 55 60 60 55 + 214 213 213 58 58 58 58 52 247 52 52 56 56 56 56 56 + 56 56 57 58 58 58 58 58 58 58 58 59 59 59 60 59 + 249 64 161 162 55 55 60 52 53 58 58 52 52 53 53 53 + 61 16 55 55 55 55 54 49 54 48 48 48 48 48 253 144 + 55 60 55 55 55 55 55 55 60 55 55 60 60 60 60 60 + 49 49 50 51 55 55 55 55 55 55 55 55 96 96 96 60 + 54 54 54 54 53 58 59 59 53 58 58 59 54 55 60 55 + 54 59 59 59 250 60 60 250 55 250 250 60 60 60 60 60 + 54 54 54 54 55 60 55 55 55 55 55 55 60 60 60 60 + 55 60 55 55 55 60 60 60 54 53 53 53 48 48 48 48 + 48 148 149 150 151 151 152 152 152 83 16 16 16 97 61 61 + 54 54 54 54 59 60 60 60 55 55 60 60 60 61 61 61 + 49 54 49 49 49 49 49 49 54 55 55 55 55 55 60 60 + 54 59 59 59 59 60 55 60 55 55 60 60 60 60 61 61 + 48 48 49 49 49 49 50 50 50 51 51 51 96 16 16 61 + 48 53 54 54 54 54 54 54 60 55 55 55 60 55 60 61 + 214 213 214 214 54 54 54 144 144 52 52 52 56 56 57 57 + 58 57 57 58 58 58 58 59 249 250 250 250 250 96 60 60 + 249 249 162 162 51 96 60 53 58 59 54 52 53 54 54 48 + 61 61 17 97 97 96 51 50 80 50 49 48 48 48 48 48 + 55 55 60 60 60 60 61 61 97 61 61 61 61 61 61 61 + 82 82 82 82 83 83 97 97 97 97 97 97 97 17 98 61 + 55 55 55 55 54 59 59 59 59 58 59 60 60 60 61 61 + 60 60 250 250 60 60 60 60 97 97 97 61 61 61 61 61 + 55 55 55 55 96 60 96 97 61 97 97 97 97 61 61 61 + 96 60 61 61 61 61 61 61 54 49 48 48 48 48 48 148 + 149 150 151 152 153 153 16 17 17 17 18 98 61 61 61 61 + 55 55 54 55 60 60 60 60 61 61 61 61 61 61 61 61 + 49 49 80 51 51 55 96 96 51 96 61 61 97 97 17 61 + 55 60 250 60 60 60 60 60 61 97 61 61 61 61 61 61 + 254 130 131 50 50 82 82 82 83 84 97 97 16 17 61 61 + 49 49 54 55 55 55 55 55 96 60 97 61 61 97 17 204 + 214 198 200 55 55 55 55 144 48 53 53 53 58 57 58 53 + 59 59 58 58 59 60 60 250 250 250 165 165 165 61 61 166 + 250 250 163 132 84 97 61 53 54 55 60 48 48 49 81 104 + 169 62 90 19 98 17 84 83 82 82 80 49 50 80 48 146 + 97 61 61 61 61 61 61 61 168 168 169 62 169 169 62 62 + 85 85 85 85 84 16 17 17 98 98 98 19 87 21 62 62 + 51 97 97 97 55 60 60 60 59 60 250 96 61 61 61 238 + 60 60 60 60 165 166 61 61 168 61 168 169 62 62 62 62 + 83 97 17 97 97 97 17 61 17 61 61 61 168 168 62 62 + 61 61 61 61 61 168 238 238 96 51 80 49 48 148 149 150 + 151 152 153 153 40 154 41 21 99 21 22 23 21 62 62 62 + 96 97 97 61 61 61 61 61 61 61 61 62 62 62 62 62 + 50 51 82 83 83 83 97 97 97 17 98 98 98 21 62 62 + 97 61 61 61 61 61 61 61 168 61 168 168 169 169 169 169 + 132 132 132 152 133 153 84 84 85 19 87 20 99 21 21 62 + 51 51 51 83 96 96 97 61 97 61 61 61 62 62 62 21 + 201 201 202 201 16 16 16 146 48 48 54 59 59 58 59 58 + 58 59 59 60 60 60 60 60 165 166 166 167 168 169 169 168 + 165 164 133 134 88 21 62 54 55 60 61 48 49 81 164 128 + 63 245 246 23 23 23 99 18 85 85 153 151 151 149 149 150 + 20 21 62 62 62 62 62 62 62 62 62 62 246 246 245 245 + 40 40 99 22 23 23 62 62 62 62 62 62 62 246 246 62 + 16 19 61 61 16 16 61 61 55 61 61 97 61 62 62 62 + 166 237 72 72 238 238 238 238 239 62 239 239 63 63 63 207 + 19 20 19 19 21 62 21 21 23 62 62 62 62 62 246 62 + 61 61 62 62 62 62 239 75 98 97 82 150 149 150 151 152 + 5 38 39 39 3 3 43 43 43 43 101 101 245 245 63 63 + 18 20 19 98 19 87 168 62 168 62 62 62 246 245 63 63 + 153 84 85 18 17 18 19 19 19 20 21 23 62 246 245 239 + 97 61 61 61 61 168 168 62 168 169 169 62 171 63 63 63 + 38 38 38 39 39 41 41 41 41 23 24 24 246 246 246 63 + 151 83 16 17 19 19 19 19 19 62 62 62 62 62 245 207 + 203 203 203 202 202 17 20 148 49 49 54 54 58 59 59 60 + 60 55 60 60 60 60 61 237 237 71 238 238 238 239 239 75 + 167 166 135 136 24 246 62 51 97 61 61 49 51 97 166 128 + 77 77 171 170 170 169 169 90 87 98 84 84 84 82 50 50 + 62 62 239 239 239 239 75 75 76 76 76 76 76 77 77 77 + 90 90 90 90 169 62 62 239 239 239 239 75 76 76 77 76 + 61 62 62 62 97 61 61 73 61 60 237 73 73 238 75 74 + 71 71 72 72 72 73 74 74 75 75 75 75 75 76 76 77 + 21 62 62 21 62 62 62 62 239 239 75 75 76 76 77 77 + 238 238 74 75 75 75 75 76 167 98 84 83 82 152 153 40 + 40 39 41 92 27 29 29 29 138 139 139 172 172 77 77 77 + 87 169 169 62 239 239 169 169 75 75 171 171 76 77 77 77 + 84 98 88 87 168 168 168 168 169 62 239 239 239 171 76 76 + 237 71 71 71 73 73 74 75 75 75 75 75 75 76 77 77 + 40 39 41 41 136 91 91 91 246 246 246 246 171 76 77 77 + 97 98 61 98 61 168 62 62 239 62 62 239 76 76 76 77 + 204 204 204 204 204 61 20 49 80 54 54 60 59 60 59 59 + 60 236 70 236 70 71 71 71 73 72 73 74 75 75 76 76 + 238 167 136 137 171 63 76 96 61 237 238 81 96 165 167 160 + 166 165 165 164 163 163 162 162 161 104 160 160 160 160 105 247 + 163 163 163 164 164 164 164 164 165 165 165 165 165 165 165 165 + 162 162 162 163 163 163 163 163 164 164 164 164 165 165 165 165 + 161 162 163 163 160 161 162 250 104 64 64 249 250 250 250 250 + 249 65 65 66 66 66 67 67 68 68 68 165 165 165 165 165 + 162 162 162 163 163 163 163 163 164 164 164 164 165 165 165 165 + 163 250 250 163 164 164 165 165 162 161 160 105 105 105 128 129 + 129 129 130 131 132 132 132 133 133 133 84 165 165 166 166 166 + 162 162 162 162 162 163 163 163 164 164 164 165 165 165 166 166 + 161 104 104 104 161 162 162 162 162 163 163 164 164 165 165 165 + 64 64 65 65 66 66 66 67 250 250 165 165 165 165 166 167 + 129 129 129 130 130 130 131 81 81 163 164 164 165 165 165 166 + 104 104 104 104 161 162 163 163 250 96 96 96 165 165 165 61 + 214 55 214 54 54 54 162 105 105 248 52 52 52 57 57 57 + 227 231 229 230 232 65 65 65 65 66 66 67 67 68 165 68 + 66 64 163 133 83 165 165 248 64 64 65 105 160 160 161 160 + 166 166 165 164 164 163 162 162 64 64 160 160 160 248 248 248 + 250 250 250 250 164 164 164 164 165 165 165 166 166 166 166 166 + 162 162 162 163 250 250 250 250 250 250 164 165 165 166 166 69 + 249 249 250 250 104 249 65 66 64 64 65 66 67 68 68 69 + 65 65 66 66 66 235 234 234 68 69 69 69 69 69 69 69 + 162 162 163 250 250 250 250 164 165 164 164 165 165 166 166 236 + 66 67 67 67 164 69 69 69 64 64 160 160 105 160 160 255 + 255 255 162 163 164 164 164 165 165 165 165 166 166 166 70 70 + 162 162 163 163 163 250 250 250 164 165 165 165 166 166 70 70 + 161 64 64 64 64 64 162 163 163 250 164 164 165 165 166 69 + 65 65 66 66 66 235 235 235 235 68 69 69 69 69 70 166 + 255 255 255 255 162 162 162 163 164 164 164 165 165 69 236 70 + 104 64 64 64 249 250 250 250 250 250 165 165 165 236 236 61 + 54 60 54 54 54 249 250 247 247 248 248 57 57 58 57 57 + 228 229 229 230 232 232 233 66 66 66 235 235 68 69 69 69 + 66 64 163 165 165 166 236 160 64 65 66 248 160 104 249 160 + 237 166 166 165 164 164 163 162 162 162 161 160 160 160 160 248 + 250 164 164 165 165 165 165 165 165 166 166 166 70 70 237 70 + 163 163 250 250 250 250 68 68 68 68 165 165 166 70 166 70 + 162 250 250 250 161 249 66 66 64 249 65 67 68 68 69 69 + 66 66 66 235 235 234 234 69 69 236 236 70 70 70 70 70 + 250 250 250 250 250 250 164 164 165 165 165 166 166 166 70 70 + 67 68 68 68 69 69 70 70 64 64 160 160 160 160 160 255 + 162 162 163 164 164 133 165 165 165 166 166 166 167 237 237 70 + 162 163 250 250 250 250 164 164 165 165 166 70 70 70 237 70 + 161 64 162 65 162 162 250 250 250 164 164 165 165 166 166 236 + 66 66 66 235 235 235 234 68 69 236 236 70 70 70 70 237 + 255 130 130 162 162 163 163 164 164 164 165 165 166 166 70 70 + 104 64 249 249 250 250 250 250 250 250 165 166 166 70 70 237 + 49 60 60 60 60 250 250 247 248 248 52 57 57 57 57 57 + 229 229 229 232 232 233 233 233 66 235 235 234 69 236 70 70 + 66 64 163 165 166 167 70 64 64 65 235 248 104 161 162 160 + 237 237 166 166 165 164 164 163 162 162 162 161 160 160 160 160 + 165 165 165 165 165 166 166 166 166 70 237 237 237 237 237 237 + 164 164 164 164 164 165 69 69 69 69 236 70 70 70 237 70 + 250 250 250 250 162 250 250 67 249 65 66 67 68 69 69 236 + 66 235 235 234 234 234 69 236 236 70 70 70 70 237 237 237 + 250 250 250 164 165 165 165 165 165 166 70 70 70 70 237 237 + 68 69 69 69 69 70 70 70 163 249 161 160 160 104 255 255 + 130 131 132 133 165 165 166 166 166 166 167 167 237 237 237 237 + 163 250 250 250 164 165 69 165 165 166 70 237 237 237 237 237 + 162 162 162 163 250 250 250 250 164 165 165 166 166 166 166 70 + 66 66 235 235 235 68 69 236 236 236 70 70 237 237 237 237 + 255 130 162 163 163 163 164 164 164 165 165 166 166 70 70 237 + 162 249 250 250 250 250 250 250 250 165 166 166 70 237 237 237 + 55 16 55 55 55 60 250 105 248 248 53 53 57 58 58 58 + 229 229 230 232 233 233 234 235 235 234 234 69 236 70 70 70 + 235 65 164 165 166 167 70 64 65 66 68 160 104 162 250 160 + 72 71 237 237 166 165 165 164 163 163 162 162 161 160 160 160 + 165 166 166 166 237 237 237 237 237 237 237 237 237 237 168 71 + 164 164 165 165 165 165 166 236 70 70 237 237 237 237 237 237 + 250 250 68 69 162 250 67 68 66 66 67 68 69 236 70 237 + 68 234 234 69 69 236 236 70 70 70 70 70 237 71 71 71 + 165 165 165 69 69 166 166 70 70 70 237 237 237 237 237 71 + 236 236 70 70 237 237 237 71 250 163 162 104 104 255 255 80 + 131 132 133 134 135 135 167 167 167 167 168 168 168 238 72 72 + 164 164 164 165 165 69 166 166 70 237 237 237 237 71 72 73 + 250 250 250 250 250 250 165 165 165 166 70 70 166 237 237 237 + 68 68 68 69 69 236 236 70 70 70 70 237 71 72 72 73 + 163 132 163 164 164 164 165 165 165 166 166 167 237 237 237 71 + 163 250 250 250 250 250 250 165 166 166 237 237 237 237 237 238 + 16 16 55 55 55 60 96 160 160 53 53 53 58 58 58 59 + 230 230 230 233 233 234 234 235 234 69 69 236 70 70 71 71 + 68 66 165 166 167 168 237 64 66 66 69 160 161 162 250 160 + 73 73 71 237 237 166 165 165 164 163 162 162 255 255 255 160 + 166 166 237 237 237 237 237 237 237 237 72 238 238 238 238 238 + 165 165 165 165 166 166 166 237 237 237 237 237 237 71 72 72 + 164 165 69 236 250 250 68 69 250 67 67 69 236 70 237 71 + 69 69 69 236 236 70 70 70 71 71 71 71 71 72 72 72 + 165 165 165 236 70 70 70 237 237 237 237 237 237 71 72 73 + 70 70 237 237 237 71 72 72 164 163 162 104 255 255 81 81 + 132 133 134 135 86 88 87 88 168 168 169 169 238 238 238 73 + 165 165 165 69 166 70 70 166 237 237 237 237 72 73 73 74 + 164 250 250 164 165 165 166 166 165 166 237 237 237 237 71 71 + 68 68 69 236 236 70 70 70 70 70 237 71 72 73 73 74 + 163 132 164 164 165 165 165 166 166 167 167 168 168 71 238 73 + 163 250 250 96 96 165 165 166 237 237 237 237 237 237 238 74 + 16 16 16 61 60 97 96 160 160 53 59 58 58 59 58 58 + 230 230 233 234 234 234 234 68 69 236 236 70 70 71 71 72 + 69 67 165 166 168 169 71 249 66 67 236 160 161 163 165 160 + 74 73 238 168 168 167 166 165 165 164 163 162 162 255 255 255 + 167 237 237 237 237 168 168 168 168 238 238 238 238 238 74 74 + 166 166 166 166 166 167 167 237 237 237 71 238 238 238 238 73 + 165 166 70 70 250 250 69 70 250 250 250 69 70 71 71 72 + 236 236 236 70 70 70 70 71 71 71 72 72 73 73 73 73 + 166 166 166 70 237 237 237 237 237 237 71 72 72 238 73 74 + 237 237 237 71 72 238 73 73 165 163 163 161 255 255 131 132 + 132 134 135 88 136 90 137 90 169 169 169 239 238 238 74 74 + 165 166 166 166 70 237 237 167 237 237 72 238 238 73 74 74 + 96 96 96 165 165 166 166 166 166 237 237 168 168 238 238 73 + 69 69 236 70 70 70 237 71 71 71 71 73 73 73 74 74 + 164 133 133 165 165 166 166 167 167 167 168 168 168 238 238 74 + 163 96 96 96 165 166 61 61 167 237 72 238 238 238 238 75 + 19 202 16 16 60 61 165 255 104 104 59 59 59 59 58 58 + 230 233 234 234 234 234 69 69 236 70 70 70 71 71 73 73 + 69 69 166 167 169 239 72 250 67 68 237 161 162 164 165 160 + 75 74 74 238 168 168 167 166 165 165 164 164 82 130 254 129 + 168 168 168 238 238 238 238 238 238 74 74 74 74 74 75 75 + 167 166 166 167 167 168 168 168 238 238 238 238 238 238 74 74 + 166 237 237 237 164 96 236 237 250 250 68 70 71 73 73 73 + 70 70 70 70 71 71 71 71 72 73 73 73 74 74 74 74 + 237 237 237 237 237 237 72 238 238 238 238 238 238 74 74 75 + 71 71 71 238 238 238 74 75 166 165 164 162 81 130 132 132 + 132 134 135 88 136 137 137 137 137 170 239 239 239 75 75 75 + 166 166 237 237 237 237 237 237 238 238 238 74 74 74 75 75 + 96 96 97 166 166 166 61 61 61 168 238 238 238 238 74 74 + 166 70 70 237 237 71 71 72 72 73 73 74 74 74 74 75 + 84 133 134 135 135 166 167 167 168 168 169 169 169 238 239 74 + 96 96 97 97 61 61 61 61 61 168 238 238 74 74 74 75 + 153 202 203 61 17 61 97 49 80 53 54 59 59 59 59 59 + 67 234 234 234 234 69 236 236 70 70 71 71 72 73 74 74 + 70 69 166 167 170 239 238 250 68 69 71 162 163 165 166 160 + 76 75 75 239 169 168 168 167 166 166 84 83 82 81 80 254 + 238 238 238 238 238 74 238 238 238 74 75 75 75 75 75 75 + 167 167 168 168 168 168 168 169 238 239 239 239 239 239 75 75 + 166 167 237 238 165 165 237 72 250 250 250 237 71 71 74 74 + 237 70 70 71 71 71 72 73 73 73 74 74 74 75 75 75 + 167 168 72 238 238 238 238 238 238 238 238 74 74 75 75 75 + 72 72 238 238 239 75 75 75 166 166 164 163 80 131 132 132 + 134 134 88 136 91 24 138 246 246 246 170 171 75 76 76 75 + 167 167 237 237 237 238 238 238 238 238 74 75 75 75 75 75 + 97 97 97 61 61 61 61 61 168 168 238 239 239 239 239 75 + 167 237 237 237 71 72 73 73 73 74 74 74 75 75 75 75 + 134 135 135 135 135 136 168 168 168 169 169 170 239 239 75 75 + 96 97 97 61 61 61 61 61 238 238 169 239 75 75 75 76 + 20 202 203 61 61 17 61 49 49 49 54 54 59 59 60 250 + 67 68 67 236 69 236 70 70 70 71 72 73 73 74 74 74 + 237 70 167 169 170 239 75 163 69 237 71 80 164 166 166 160 + 76 75 75 239 169 168 168 167 86 85 84 83 82 82 50 80 + 169 238 238 238 238 239 239 238 239 239 75 75 75 75 76 76 + 168 136 168 168 168 168 169 169 169 239 239 239 239 239 75 75 + 166 167 168 238 97 97 61 72 96 60 165 71 73 238 75 75 + 237 237 71 71 72 72 73 73 74 74 74 75 75 75 75 75 + 167 168 168 168 238 238 238 238 239 239 239 239 75 75 75 75 + 238 238 238 238 239 75 75 75 166 166 164 81 131 131 132 37 + 134 40 41 91 92 25 138 246 246 246 171 171 76 76 76 76 + 167 167 168 168 168 238 238 238 238 239 239 75 75 76 76 76 + 97 97 97 98 61 61 61 61 168 168 169 239 239 239 75 75 + 167 237 237 237 71 72 73 73 74 74 75 75 75 75 75 76 + 134 134 135 135 88 136 136 136 137 169 170 170 170 171 76 76 + 97 97 97 61 61 61 168 168 62 169 169 239 75 75 76 77 + 20 203 203 204 61 61 61 49 49 49 54 54 59 60 60 250 + 250 68 68 70 236 70 70 70 71 71 72 73 74 74 75 75 + 237 167 167 137 170 171 75 164 165 237 238 80 84 166 166 160 + 77 76 76 171 169 169 169 87 86 85 84 83 83 82 50 50 + 169 169 239 239 239 239 239 239 75 75 76 76 76 76 76 76 + 136 136 137 137 169 169 169 170 170 239 239 171 171 76 76 76 + 98 61 168 238 97 61 61 73 60 60 166 72 238 238 75 75 + 237 71 71 73 73 73 74 74 74 75 75 75 75 76 76 76 + 167 168 168 169 169 169 239 239 239 239 239 239 75 76 76 76 + 238 238 238 239 239 75 76 76 167 166 84 82 131 132 37 38 + 40 39 41 42 92 93 28 29 29 94 245 63 172 77 77 77 + 167 168 168 169 169 238 238 169 239 239 239 75 76 76 76 77 + 84 17 17 98 19 21 21 90 90 169 62 239 239 171 76 76 + 168 237 237 238 238 238 74 74 75 75 75 75 76 76 76 77 + 134 38 135 135 136 136 137 137 137 170 170 170 171 171 76 77 + 84 17 98 19 19 21 21 62 62 62 62 239 76 76 76 77 + 21 203 203 203 20 20 21 49 49 80 55 60 60 60 55 250 + 250 68 68 70 70 70 70 71 71 72 73 74 74 75 75 75 + 237 167 168 137 171 171 76 164 166 237 238 80 83 98 167 160 + 77 77 172 171 170 169 23 90 87 86 85 84 152 152 151 50 + 169 169 239 239 239 239 75 75 76 76 76 76 76 77 77 77 + 137 137 137 137 137 170 170 170 170 170 171 171 171 172 172 77 + 87 168 169 62 98 61 168 238 97 97 61 238 238 239 75 76 + 168 71 73 73 74 74 74 75 75 75 75 76 76 76 77 77 + 90 169 169 169 62 170 239 171 239 171 171 171 76 77 77 77 + 239 239 239 239 171 76 76 77 168 167 84 132 132 37 38 38 + 39 39 155 92 43 44 29 29 94 139 139 172 172 173 77 77 + 168 168 169 169 169 239 239 170 239 239 75 76 76 77 77 77 + 85 18 19 20 99 21 22 23 62 62 170 171 171 63 77 77 + 168 168 238 238 238 238 239 239 75 75 76 76 76 77 77 77 + 38 38 39 41 136 136 137 138 138 246 246 171 171 172 172 77 + 85 18 19 19 20 21 62 62 62 62 170 171 76 77 77 77 + 23 204 204 204 204 21 62 149 50 50 55 60 60 55 55 60 + 60 60 68 71 237 71 71 71 73 73 74 74 75 75 76 76 + 168 167 136 137 139 171 76 165 166 168 169 50 84 98 167 104 + 78 172 172 63 246 26 100 22 99 88 40 153 153 152 151 150 + 169 170 171 171 171 171 76 171 76 76 77 77 77 77 77 77 + 137 137 137 26 26 246 246 246 246 171 171 171 172 172 172 173 + 87 90 169 62 98 19 62 62 97 97 61 238 169 239 76 76 + 168 238 238 74 74 74 75 75 76 76 76 76 77 77 77 77 + 22 62 62 62 62 170 246 171 171 171 171 172 172 77 77 77 + 239 239 239 171 171 77 77 77 87 88 134 132 132 37 38 4 + 39 41 3 43 44 2 2 31 45 103 103 140 173 173 173 78 + 90 169 169 169 169 170 239 239 171 171 76 76 77 77 77 77 + 86 86 20 99 21 22 23 23 24 246 246 245 63 172 77 77 + 169 169 238 238 238 239 239 239 75 76 76 77 77 77 77 78 + 4 4 4 244 244 244 92 138 138 138 139 139 139 172 173 78 + 85 19 20 21 21 21 62 62 62 246 245 63 172 77 77 173 + 204 204 204 204 204 23 62 149 150 150 51 55 60 55 60 60 + 60 61 165 71 71 71 71 73 73 74 74 75 75 76 76 76 + 238 167 137 137 139 139 76 165 167 168 239 82 84 86 168 48 + 78 173 172 172 246 26 24 91 41 41 40 40 38 37 36 150 + 246 171 171 171 171 171 63 63 63 172 77 173 173 173 78 173 + 92 25 26 27 138 246 246 246 246 171 172 172 172 140 173 173 + 90 62 62 62 19 21 62 62 97 97 168 62 62 171 63 77 + 169 238 238 74 75 75 75 76 76 76 77 77 77 173 78 78 + 23 62 62 62 246 246 246 245 245 63 63 172 173 173 173 78 + 239 239 171 171 77 77 77 78 136 88 134 132 37 37 38 4 + 39 3 3 43 2 2 31 94 95 95 158 140 173 173 79 78 + 169 169 169 169 170 170 171 171 171 171 172 77 77 77 78 78 + 88 99 99 21 22 23 23 100 26 246 246 245 63 172 173 77 + 169 169 238 238 239 239 239 239 76 76 77 77 77 78 78 173 + 4 4 244 244 244 244 43 93 29 94 139 139 172 172 173 78 + 86 20 99 21 22 23 24 246 246 245 63 63 172 173 173 173 + 205 205 204 204 204 23 23 149 150 50 51 55 55 55 60 61 + 61 61 166 72 71 71 72 73 74 74 75 75 76 76 77 76 + 238 167 170 137 139 172 77 165 167 169 239 152 84 88 168 48 + 79 173 173 172 245 101 27 92 42 41 39 39 38 37 37 36 + 246 245 171 171 171 63 63 63 172 173 173 173 78 78 79 79 + 25 27 27 28 246 246 246 139 139 172 172 172 172 140 173 173 + 23 62 62 62 20 21 62 62 17 17 62 62 62 171 172 77 + 170 238 238 239 75 76 76 76 76 77 77 77 78 78 79 79 + 23 246 246 246 246 246 245 245 245 63 172 172 173 173 173 78 + 171 239 171 172 77 173 78 78 90 88 134 133 37 38 4 4 + 3 3 43 2 2 95 95 95 95 158 1 47 141 79 79 79 + 137 169 170 170 170 171 171 171 172 172 172 173 78 78 78 79 + 41 41 22 22 91 23 24 26 246 246 245 63 63 172 173 78 + 169 169 239 239 239 239 75 76 76 77 77 173 173 78 78 174 + 244 186 186 244 244 187 2 93 29 94 139 140 173 173 78 79 + 20 99 22 23 23 26 246 246 245 63 63 63 172 173 78 79 + 205 205 205 204 204 23 24 150 151 152 83 96 60 60 60 61 + 61 61 61 73 72 72 73 73 74 74 75 76 77 77 77 77 + 239 167 170 137 139 172 77 166 167 169 171 152 153 87 169 48 + 174 78 173 172 63 245 246 26 92 155 41 40 38 38 37 37 + 245 63 63 63 63 63 63 63 172 173 78 79 79 79 79 79 + 26 26 246 246 245 245 245 63 63 172 172 172 173 173 173 79 + 22 62 62 62 19 21 62 62 61 61 62 239 239 77 77 78 + 170 169 169 239 75 76 76 76 76 77 77 78 78 78 79 79 + 24 246 246 245 245 245 63 63 245 63 172 172 173 78 78 78 + 171 76 76 77 77 173 78 78 90 87 85 153 38 38 4 4 + 3 3 43 2 95 95 126 95 158 46 1 141 141 79 174 79 + 170 170 170 170 171 171 171 171 77 77 173 173 78 78 79 79 + 99 22 22 23 23 24 246 246 246 245 63 63 63 173 173 78 + 170 239 239 75 75 76 76 77 77 77 77 78 78 78 79 174 + 244 187 187 187 187 188 2 93 29 94 103 140 173 78 79 79 + 99 21 22 23 246 246 246 246 245 63 63 63 63 173 79 79 + 205 205 205 205 205 205 246 151 151 152 16 60 60 60 61 61 + 61 61 61 73 73 73 73 73 74 74 75 76 77 77 78 77 + 75 167 171 137 140 173 78 98 167 169 76 153 153 90 169 48 + 85 153 152 152 151 150 149 149 148 147 147 146 145 144 144 144 + 150 50 50 151 82 152 151 152 153 152 152 153 153 153 153 153 + 149 149 150 150 150 150 150 150 151 151 152 152 152 153 153 153 + 149 80 150 50 48 49 49 50 48 49 49 49 50 50 151 133 + 130 130 131 131 81 82 82 82 83 83 83 84 152 153 153 153 + 149 150 150 150 150 151 151 151 151 152 152 152 152 133 153 84 + 50 50 151 152 152 133 84 84 254 128 146 253 144 9 8 8 + 8 7 7 7 34 6 35 37 5 37 37 37 37 38 153 153 + 254 49 130 130 131 50 50 151 151 152 152 153 153 153 153 153 + 147 148 254 254 254 254 49 49 131 131 131 151 152 152 153 84 + 254 80 80 80 50 50 82 82 151 152 152 153 153 153 134 38 + 7 8 8 8 32 32 33 6 34 6 36 36 152 153 153 85 + 147 148 148 148 149 149 150 150 151 151 151 151 152 153 153 153 + 196 214 200 198 214 149 150 144 144 144 253 53 53 53 53 53 + 53 53 54 249 104 104 162 162 163 163 164 164 164 133 133 133 + 130 255 130 131 37 37 84 253 48 49 49 106 146 128 254 48 + 86 85 153 152 152 151 150 150 149 148 148 147 146 145 145 144 + 82 83 83 83 83 83 83 84 84 84 84 84 85 85 85 85 + 150 50 50 50 50 82 82 83 83 84 84 84 153 153 153 85 + 49 50 50 82 48 49 80 51 49 54 49 80 51 51 83 85 + 130 131 131 132 164 84 84 84 97 85 85 85 85 153 153 85 + 130 50 50 50 50 82 82 82 152 83 84 84 84 84 85 85 + 82 83 83 152 153 153 84 85 80 254 48 146 146 8 8 8 + 7 7 33 6 35 35 37 5 5 5 38 38 38 40 40 86 + 150 50 50 50 50 82 83 82 152 84 153 153 153 85 86 86 + 147 254 254 49 49 80 50 50 50 82 83 83 84 153 85 85 + 81 81 81 82 82 83 83 84 152 153 153 85 85 85 86 40 + 7 32 32 33 33 34 34 35 37 37 37 37 153 85 85 18 + 148 148 149 149 149 150 150 50 82 82 152 84 153 85 85 18 + 214 213 213 213 198 200 151 144 144 253 253 53 53 53 53 53 + 53 58 249 249 104 249 250 250 250 250 164 164 164 84 134 134 + 131 130 131 132 37 134 85 48 49 50 50 144 48 48 49 48 + 88 86 85 153 152 152 151 150 149 148 148 148 146 146 145 144 + 152 83 83 83 84 84 84 84 84 84 153 85 85 86 86 86 + 150 150 151 151 151 83 83 83 84 84 84 84 153 153 85 85 + 49 50 50 83 48 80 50 51 54 54 49 51 51 83 84 85 + 131 131 132 132 164 84 84 84 84 85 85 85 85 85 40 86 + 131 50 82 82 82 83 83 83 152 84 84 84 85 85 85 86 + 83 83 83 153 153 153 85 85 50 254 48 147 146 8 8 7 + 7 33 6 35 5 5 5 5 38 38 38 38 40 154 41 99 + 150 50 50 50 82 83 83 83 84 84 153 85 85 86 86 20 + 148 149 254 149 80 50 50 50 50 82 84 84 153 153 85 86 + 82 81 82 82 82 83 83 84 84 84 85 85 86 86 86 41 + 7 32 33 34 34 35 35 35 37 37 37 153 153 85 85 18 + 148 148 149 149 150 150 151 151 82 83 84 84 153 85 86 20 + 197 214 213 200 200 200 151 144 144 253 48 53 53 53 53 53 + 58 59 59 53 249 250 250 250 250 164 164 165 165 85 135 134 + 131 131 131 132 133 134 86 48 49 50 50 253 48 254 80 104 + 99 88 85 153 153 152 151 151 150 149 148 148 147 146 146 145 + 152 83 83 83 84 84 84 85 85 134 134 85 86 86 86 86 + 151 151 151 151 152 152 83 84 84 84 84 85 85 85 85 86 + 150 82 82 83 49 50 50 51 54 54 54 51 51 83 17 85 + 132 132 132 164 133 84 97 84 84 85 85 85 86 86 86 88 + 151 82 82 82 83 83 84 84 84 84 85 85 85 85 86 86 + 83 83 84 153 153 85 86 86 50 254 254 147 146 8 8 7 + 7 33 6 35 5 5 5 5 38 38 4 39 40 154 41 99 + 150 50 82 82 82 83 84 84 84 153 85 85 85 86 20 99 + 149 149 150 150 150 50 50 50 82 83 84 153 153 85 86 86 + 132 131 132 132 132 83 133 84 85 85 85 86 86 88 89 41 + 7 32 33 34 34 34 35 5 37 37 38 38 153 40 86 20 + 148 149 149 150 150 151 151 152 83 84 85 85 85 85 86 20 + 196 198 200 200 200 200 151 144 253 253 48 53 53 53 53 58 + 58 59 58 53 250 250 250 250 250 164 165 165 166 86 135 135 + 163 162 132 132 133 134 19 254 49 50 82 253 254 254 80 104 + 22 99 86 85 153 153 152 151 150 149 149 148 147 147 146 145 + 152 84 84 84 85 85 85 86 86 40 40 40 88 89 89 89 + 37 37 37 152 133 133 84 84 84 85 85 85 86 86 88 87 + 50 82 82 84 49 50 51 96 54 54 55 96 55 16 20 86 + 132 164 164 165 165 166 98 98 87 19 88 19 89 99 99 99 + 151 83 83 83 83 84 84 84 85 85 85 86 86 88 89 99 + 83 84 84 85 86 88 89 87 82 49 254 147 146 148 7 7 + 33 6 6 35 5 38 5 4 4 39 39 154 41 41 22 22 + 151 82 83 83 83 84 84 84 85 85 86 86 88 99 99 99 + 149 150 150 151 151 151 151 152 84 153 153 153 40 154 99 89 + 132 132 133 133 133 84 85 85 85 86 86 88 89 90 90 41 + 34 33 33 34 35 35 35 5 5 5 38 38 40 40 88 99 + 149 149 150 151 151 152 152 152 84 84 85 85 86 89 99 21 + 197 200 201 201 200 200 152 145 253 146 48 53 53 53 59 59 + 58 59 58 59 250 250 250 250 164 165 166 166 167 87 89 88 + 164 163 132 133 134 40 90 49 50 51 84 146 254 49 81 48 + 22 99 88 86 153 153 152 152 151 150 149 149 148 147 147 146 + 153 85 85 85 86 85 135 88 88 88 88 41 89 90 90 41 + 37 37 37 133 133 153 153 134 85 85 86 86 86 88 89 87 + 151 83 152 84 49 51 82 96 49 54 96 96 16 17 20 88 + 83 164 165 165 166 167 167 98 87 19 88 20 99 21 99 90 + 152 83 84 84 84 84 85 85 85 85 86 86 88 89 99 90 + 84 17 18 86 88 88 89 90 82 80 49 147 146 7 7 33 + 6 6 35 5 38 4 4 4 4 39 41 41 41 41 155 23 + 151 83 83 84 84 84 85 85 86 86 88 99 99 99 22 22 + 149 150 150 151 151 152 152 152 153 153 153 85 86 99 21 90 + 132 133 133 133 134 135 86 86 86 86 86 88 99 90 91 91 + 34 34 34 35 35 35 35 5 38 38 39 39 40 41 41 22 + 149 150 150 151 151 152 153 84 84 85 85 86 88 90 90 21 + 201 201 201 200 200 201 152 145 253 146 48 53 53 59 59 58 + 58 59 59 59 60 250 250 250 165 165 166 166 167 90 90 136 + 164 164 133 134 135 88 90 49 50 83 16 48 254 80 82 48 + 23 22 99 154 40 153 153 152 151 150 150 149 148 148 147 146 + 153 85 85 85 86 86 86 89 89 89 89 41 91 91 91 91 + 37 38 38 38 38 153 153 134 86 86 88 88 89 89 90 90 + 152 84 133 84 49 51 83 97 54 55 96 96 16 61 20 90 + 133 165 165 165 166 167 167 87 19 19 88 99 21 22 91 23 + 152 84 84 84 84 85 85 85 86 86 88 88 89 99 91 22 + 17 17 18 88 88 99 90 90 83 80 254 148 128 7 7 33 + 6 35 35 5 4 4 4 4 4 39 3 155 155 155 42 100 + 152 83 84 84 84 85 85 85 86 88 89 99 99 91 23 100 + 150 150 151 152 152 152 153 153 153 85 85 86 88 99 22 90 + 133 133 133 134 135 135 86 86 88 88 88 99 22 91 91 92 + 34 34 35 35 35 37 5 5 38 4 39 39 41 41 41 42 + 150 150 151 151 152 152 153 153 85 85 85 86 99 22 91 23 + 202 201 201 201 201 201 153 145 146 146 48 54 54 59 54 59 + 59 59 59 60 60 60 60 165 166 166 166 167 167 90 90 136 + 165 164 133 134 135 136 22 49 50 51 16 48 254 50 83 104 + 26 100 91 99 154 40 153 153 152 151 150 150 149 7 148 147 + 18 86 86 86 87 99 89 90 90 91 91 91 91 24 24 24 + 38 38 38 38 40 40 40 40 88 88 89 90 90 22 91 23 + 152 84 84 85 50 83 84 97 55 60 96 97 61 61 20 23 + 84 165 166 166 166 167 167 87 62 169 22 23 23 23 100 23 + 153 84 85 85 85 86 86 86 88 88 99 22 91 91 91 23 + 85 18 19 99 90 91 91 23 84 131 130 254 148 7 7 6 + 6 35 5 38 4 4 4 4 4 3 3 42 42 24 26 246 + 153 84 85 85 85 86 86 86 99 99 99 22 91 100 26 246 + 151 151 152 152 152 153 153 153 153 85 88 99 99 22 91 137 + 134 165 134 135 135 88 88 87 90 90 90 22 23 24 26 26 + 35 35 35 37 35 5 38 4 38 4 41 41 155 42 92 26 + 150 151 152 152 153 153 153 85 85 86 88 99 90 23 23 24 + 201 201 202 202 201 201 153 146 146 146 48 54 54 54 54 59 + 59 59 60 60 250 60 70 165 70 70 167 167 168 90 137 137 + 166 164 133 134 136 91 62 49 51 83 17 48 254 50 83 104 + 26 24 23 22 41 40 40 153 152 152 36 6 7 7 7 148 + 20 20 20 99 99 90 22 91 22 91 100 100 24 24 24 26 + 38 38 39 39 40 154 41 99 99 99 22 22 22 23 23 24 + 84 85 85 88 151 16 84 17 55 55 96 97 17 20 21 62 + 84 166 167 167 166 167 168 168 169 23 23 23 23 24 26 26 + 153 85 85 86 86 86 88 88 89 99 90 91 92 24 26 246 + 86 19 99 90 91 92 24 170 84 132 131 254 148 33 34 34 + 35 5 5 38 4 4 244 3 244 3 3 43 43 156 26 246 + 153 84 85 85 85 86 88 88 90 91 91 100 24 24 26 246 + 151 151 152 152 153 153 153 85 85 86 88 99 90 91 100 137 + 135 166 166 135 167 87 90 90 90 22 23 23 24 246 246 26 + 36 35 35 37 5 38 4 4 4 39 41 41 42 92 26 26 + 36 152 152 152 153 153 40 40 20 99 99 22 91 23 24 246 + 202 202 202 201 201 201 153 146 146 148 50 54 54 54 53 59 + 60 59 59 60 60 60 96 70 70 237 237 168 168 169 137 137 + 166 164 135 135 136 137 62 50 83 16 18 254 49 82 97 48 + 246 246 24 42 41 154 40 40 38 5 37 6 6 7 7 148 + 20 20 99 21 21 22 23 23 100 24 24 26 26 26 246 246 + 39 39 39 39 154 41 41 22 22 22 23 23 100 24 26 246 + 153 85 85 88 151 16 16 98 55 55 96 16 19 20 23 62 + 166 166 167 167 167 168 168 168 169 23 62 246 246 246 246 246 + 85 85 86 86 88 89 99 99 91 91 91 100 24 26 26 246 + 87 99 90 22 92 24 26 246 85 132 131 254 7 34 34 6 + 5 5 38 4 4 4 244 244 3 3 43 43 43 93 101 246 + 153 85 85 86 86 88 99 99 91 23 100 24 26 26 246 245 + 152 152 152 153 153 153 40 40 86 88 89 90 91 100 24 170 + 135 166 166 167 167 87 90 90 23 23 23 246 246 246 245 101 + 37 37 5 5 5 5 4 4 39 41 3 3 42 25 101 101 + 36 37 153 153 153 40 40 154 99 99 22 23 23 24 246 246 + 202 202 202 201 201 201 153 147 147 148 49 49 54 54 54 59 + 60 60 60 60 60 60 165 237 237 237 237 168 169 169 170 170 + 166 165 135 135 137 92 62 50 83 16 19 254 150 82 97 48 + 245 101 26 24 42 41 154 39 38 38 5 36 6 33 7 7 + 99 21 21 23 23 23 100 24 26 26 246 246 246 245 245 245 + 39 39 39 41 41 41 155 42 23 23 24 26 246 246 246 246 + 153 86 86 99 152 16 17 61 96 60 97 98 61 21 24 246 + 167 166 167 167 168 169 169 90 169 62 246 246 246 246 246 246 + 40 86 88 99 99 22 91 91 100 24 24 26 26 246 246 246 + 21 21 23 24 26 27 246 171 85 132 132 150 7 6 35 35 + 5 38 4 4 244 244 244 244 3 43 44 2 2 30 157 245 + 40 86 88 89 89 90 91 91 92 24 26 26 246 157 245 245 + 152 153 153 153 40 40 86 88 89 90 91 91 24 26 246 246 + 88 167 167 167 168 168 169 23 62 62 246 246 245 245 245 245 + 37 5 5 38 38 4 4 3 3 3 3 43 43 101 157 157 + 37 5 153 153 40 154 99 99 21 22 23 24 26 246 246 245 + 202 203 203 203 202 202 41 148 148 149 49 49 54 55 55 60 + 59 60 60 60 60 165 166 237 237 71 238 169 169 170 246 170 + 167 165 136 136 137 26 246 151 16 18 99 149 151 83 97 48 + 172 245 28 26 92 42 41 39 38 38 5 37 36 6 33 7 + 22 23 23 23 100 24 246 246 246 246 245 245 245 245 63 245 + 41 3 3 3 155 155 42 92 24 26 26 101 101 245 245 245 + 86 89 99 22 152 17 19 61 96 16 17 19 21 62 246 246 + 167 167 167 168 169 239 170 170 170 170 246 246 245 245 245 245 + 88 99 90 22 22 23 100 24 26 26 26 246 246 245 245 245 + 23 23 24 26 101 28 245 63 88 153 152 131 34 36 35 5 + 5 38 4 244 244 244 244 244 43 2 2 31 45 45 103 172 + 88 88 89 22 91 91 100 26 24 26 246 246 245 245 63 63 + 153 153 153 40 40 154 41 41 90 91 91 24 26 246 245 171 + 87 168 168 168 168 169 169 62 62 246 246 245 245 63 63 103 + 5 5 4 4 4 4 244 3 3 43 43 93 44 157 157 102 + 37 5 153 40 154 41 22 22 23 23 24 246 246 245 245 63 + 202 203 203 203 202 202 155 7 148 149 150 55 55 60 55 60 + 55 60 60 60 166 166 237 71 71 72 238 238 239 171 171 171 + 168 166 136 136 138 138 245 152 18 19 23 150 132 84 98 48 + 140 102 30 28 43 43 3 41 39 4 38 5 37 35 6 6 + 23 23 24 26 246 246 246 245 246 245 245 245 63 63 63 103 + 3 3 3 3 3 42 43 25 26 101 101 157 157 157 103 63 + 154 21 22 23 16 19 20 62 96 16 98 19 21 62 246 246 + 167 168 168 169 239 239 239 171 171 171 171 63 63 63 172 172 + 99 22 22 91 91 100 24 26 26 26 246 157 245 63 172 172 + 23 62 246 101 101 157 139 172 99 153 133 36 36 37 5 5 + 5 4 4 3 244 43 187 2 2 2 2 45 102 158 158 140 + 41 90 91 91 91 24 26 246 26 246 246 139 139 172 140 140 + 153 153 40 154 154 41 41 91 91 91 24 26 101 245 139 63 + 90 168 168 169 169 169 170 170 246 246 246 245 63 63 140 140 + 4 185 185 185 4 4 244 244 3 43 43 2 31 157 103 158 + 5 38 39 154 41 155 23 23 100 24 246 246 245 63 63 207 + 203 203 203 203 203 203 155 7 148 150 150 55 60 60 55 55 + 60 60 60 61 61 237 72 238 238 238 238 239 239 171 172 171 + 168 166 136 136 138 94 63 152 19 21 23 150 152 85 98 48 + 159 158 45 30 44 43 3 3 41 4 38 5 5 35 34 34 + 26 246 246 246 246 245 245 245 139 139 139 172 172 140 140 1 + 3 3 3 43 43 43 93 44 28 30 157 45 45 103 102 140 + 20 22 22 24 16 20 21 62 16 61 87 90 62 246 245 171 + 168 169 169 239 239 239 239 171 76 63 63 172 172 172 140 173 + 91 91 23 100 24 26 246 246 246 246 245 245 63 172 140 173 + 246 246 246 157 157 103 172 172 91 85 153 37 36 5 5 5 + 4 39 3 43 2 2 188 188 188 94 45 95 46 1 1 173 + 91 91 91 24 24 26 246 246 246 245 139 139 172 140 173 173 + 40 154 154 154 41 155 155 42 92 24 26 101 157 102 158 140 + 90 90 169 169 170 170 170 246 171 245 245 63 172 140 140 47 + 185 185 186 186 186 244 244 244 43 2 2 31 45 103 158 1 + 38 39 154 41 41 42 100 23 26 246 245 245 63 63 140 173 + 205 204 204 204 204 204 156 199 149 151 150 55 60 55 55 55 + 60 61 61 61 168 238 238 238 238 238 239 239 171 172 172 172 + 169 167 137 136 138 139 172 153 19 21 23 151 152 85 88 48 + 141 1 102 45 94 44 43 3 244 4 4 38 5 35 35 34 + 246 246 245 245 245 245 139 172 172 172 140 140 1 1 173 47 + 43 43 43 43 2 2 2 94 94 45 103 158 158 158 1 47 + 99 23 24 246 17 21 62 62 17 61 169 169 62 63 172 172 + 169 169 239 239 239 239 239 76 77 172 172 172 173 173 173 173 + 24 24 26 26 246 246 246 245 245 63 63 172 140 173 173 173 + 246 245 245 63 103 158 140 173 24 40 153 37 37 5 5 4 + 4 3 3 2 2 188 188 189 189 95 95 46 47 159 141 141 + 92 24 24 26 246 246 246 245 245 63 172 140 140 173 141 141 + 154 154 155 155 155 42 156 25 26 101 157 102 102 158 1 173 + 91 169 170 170 170 171 171 171 172 172 172 172 140 140 141 190 + 185 185 186 186 187 187 187 188 188 188 94 95 95 158 46 159 + 4 154 41 155 42 24 26 26 246 245 63 63 172 173 173 159 + 205 204 204 204 204 204 156 6 150 151 151 55 60 60 60 60 + 61 61 61 61 168 238 238 238 74 75 75 75 76 173 173 173 + 169 168 137 137 139 103 173 153 99 23 246 151 153 88 168 254 + 174 79 140 63 63 245 27 25 42 41 39 39 38 38 37 37 + 246 171 171 63 63 63 77 172 172 173 173 173 173 173 79 79 + 43 43 93 44 28 157 157 63 139 63 172 140 140 173 173 79 + 21 62 62 245 19 62 62 239 61 61 62 62 62 76 77 77 + 239 74 74 75 75 75 76 76 76 77 77 78 78 78 78 78 + 62 246 246 246 246 245 63 63 63 63 172 173 173 173 78 78 + 171 171 63 63 172 173 173 78 62 86 85 133 37 38 38 4 + 41 3 43 44 94 45 95 158 46 46 46 1 141 79 79 79 + 24 170 170 170 246 171 171 171 63 77 77 173 78 78 79 79 + 41 155 155 23 23 24 246 246 245 245 63 63 63 173 173 173 + 62 169 239 239 75 76 76 76 77 77 77 173 173 78 79 174 + 186 186 186 244 187 187 188 2 94 94 103 103 140 140 141 79 + 40 154 155 23 100 246 246 246 245 245 63 173 173 173 173 79 + 204 204 205 205 204 204 205 151 150 152 51 60 60 60 61 61 + 61 61 61 61 238 238 238 74 74 75 75 75 76 77 78 78 + 239 169 170 138 139 140 78 85 168 62 239 132 85 87 168 254 + 23 21 20 19 17 84 83 82 151 150 254 254 254 147 146 48 + 97 97 97 97 98 98 98 98 87 87 87 87 87 87 87 99 + 152 152 152 153 153 153 153 16 85 18 18 19 20 87 99 21 + 51 51 96 97 54 55 96 60 54 54 55 96 97 97 98 167 + 164 250 164 164 165 166 166 166 167 167 167 167 87 87 87 88 + 83 83 83 84 84 97 97 98 85 98 98 86 86 88 87 168 + 97 97 97 98 98 86 88 167 82 80 254 48 128 128 254 149 + 150 151 152 37 153 38 40 40 40 40 88 99 21 22 23 169 + 83 83 83 84 97 97 97 97 98 98 98 98 87 87 90 21 + 150 150 151 151 82 82 83 83 16 16 16 17 19 20 21 21 + 96 96 96 96 165 165 166 166 166 98 167 88 88 87 169 137 + 34 34 35 35 36 37 37 37 134 134 86 88 88 88 88 87 + 150 150 151 151 82 83 83 83 16 17 18 18 18 20 99 21 + 201 201 201 201 200 152 16 146 48 253 53 53 53 53 58 59 + 59 54 54 54 250 250 164 163 166 166 166 166 166 168 168 168 + 164 163 133 134 135 87 167 104 163 250 165 48 254 80 81 48 + 62 62 21 19 19 17 84 83 83 50 80 49 49 48 48 48 + 61 61 61 61 61 61 61 61 61 61 61 168 168 169 62 62 + 84 84 16 17 17 17 17 18 18 19 19 87 168 168 168 168 + 96 96 97 97 55 55 60 61 54 59 60 60 61 61 61 168 + 165 165 165 165 166 237 237 237 166 167 167 168 168 169 62 62 + 83 97 97 97 97 97 61 61 61 61 167 168 168 168 168 169 + 97 61 61 61 61 168 168 169 83 81 49 254 48 254 150 150 + 151 151 152 153 153 40 40 41 89 99 99 21 23 62 62 62 + 83 164 165 165 165 97 166 61 167 61 61 168 168 168 62 62 + 50 50 51 83 83 83 83 16 17 17 98 19 61 21 62 62 + 96 96 165 165 165 166 61 61 167 167 167 168 168 168 169 169 + 36 36 37 37 37 37 133 134 85 85 88 87 90 90 169 62 + 50 50 51 83 83 16 16 16 17 17 19 19 21 21 62 62 + 201 201 202 202 16 16 16 146 48 48 53 59 59 59 58 58 + 58 59 250 60 250 250 250 250 236 70 70 237 237 168 168 168 + 165 164 134 135 88 90 168 104 250 250 165 48 49 81 81 104 + 62 62 23 21 20 19 17 84 84 83 50 150 150 149 148 148 + 19 61 61 61 61 61 168 21 21 21 21 23 62 62 62 246 + 153 85 85 18 18 19 19 19 99 99 21 90 169 169 169 62 + 97 97 97 61 55 96 60 61 55 55 60 61 61 61 168 169 + 166 166 166 237 237 237 168 168 238 169 169 169 169 169 23 62 + 16 16 17 17 17 61 61 61 61 61 168 62 62 62 62 62 + 61 61 61 61 62 62 62 62 97 82 50 49 149 149 150 151 + 36 37 5 40 39 41 41 155 155 42 92 24 24 246 246 62 + 84 97 98 98 98 167 167 87 168 87 90 169 62 62 62 62 + 82 82 83 83 84 84 84 17 98 18 19 20 21 22 62 62 + 97 61 61 61 61 61 61 61 61 62 62 62 62 62 62 246 + 37 37 37 5 38 38 40 40 40 86 99 21 23 62 62 62 + 50 51 83 97 97 97 17 61 17 61 61 61 62 62 62 62 + 202 202 202 202 16 16 17 48 48 48 54 59 59 59 58 59 + 59 59 250 60 60 250 68 236 70 70 237 237 72 238 238 238 + 165 164 134 135 41 24 62 81 96 97 61 48 50 82 83 48 + 245 246 62 23 22 87 86 18 153 152 151 151 150 149 148 148 + 20 20 21 21 21 62 62 62 62 62 24 246 246 246 246 246 + 40 40 40 86 86 99 99 21 22 23 23 23 62 62 170 62 + 84 16 98 61 83 96 61 61 55 60 60 61 61 168 169 169 + 166 167 167 168 168 168 238 238 169 169 170 62 62 246 246 246 + 18 19 19 19 19 20 21 21 21 62 62 62 62 62 246 62 + 61 61 62 62 62 62 62 62 18 83 50 150 150 150 151 36 + 5 5 4 39 3 3 3 43 3 43 43 27 101 101 246 246 + 85 86 88 87 168 90 90 90 90 22 23 23 62 246 246 245 + 152 84 84 85 85 85 18 86 86 88 87 90 22 62 62 62 + 97 61 61 61 61 61 62 62 62 62 62 62 62 246 245 245 + 37 37 5 38 38 39 154 41 41 41 22 23 23 24 246 246 + 83 83 16 16 17 17 61 61 61 61 62 62 62 62 62 62 + 203 202 202 202 16 16 18 148 48 49 54 54 54 59 59 60 + 60 60 60 60 60 60 236 237 70 237 71 72 238 238 238 238 + 166 165 135 41 42 101 62 51 97 61 19 149 151 84 97 254 + 63 245 246 24 91 90 88 86 40 153 152 152 151 150 149 149 + 21 21 22 23 62 62 62 246 246 246 246 246 246 245 245 245 + 41 41 41 99 90 91 91 100 23 24 26 246 246 246 246 246 + 85 19 19 20 83 97 61 61 96 97 61 61 168 169 62 170 + 167 167 168 168 168 238 238 238 169 170 239 171 171 245 63 63 + 20 20 20 21 21 21 23 23 23 24 246 246 101 245 157 245 + 22 62 62 62 246 246 245 245 86 152 151 151 150 36 5 5 + 5 4 4 3 3 3 3 43 43 2 44 29 157 45 139 245 + 85 86 88 90 90 90 90 90 62 246 246 246 245 245 63 63 + 153 153 85 86 86 86 88 99 99 90 91 24 246 246 246 171 + 88 168 168 168 168 168 169 62 62 246 246 245 245 245 245 245 + 5 5 38 4 4 39 41 155 92 24 24 26 26 246 245 63 + 152 153 85 18 18 19 20 21 23 62 62 62 246 246 245 63 + 203 202 203 203 203 203 20 148 148 49 49 54 55 60 55 55 + 55 60 60 60 165 166 237 237 237 238 238 238 239 239 239 170 + 167 166 136 136 93 157 245 82 16 61 21 150 152 84 98 48 + 172 139 246 138 25 92 41 41 41 39 38 5 37 36 6 6 + 23 62 62 62 246 246 246 245 245 245 245 245 63 63 172 172 + 155 42 42 42 92 24 25 26 26 26 246 245 245 139 139 172 + 20 21 23 62 16 17 61 61 97 97 61 61 169 62 245 171 + 168 168 238 238 238 239 239 239 76 76 76 63 63 63 245 245 + 21 22 22 23 23 100 24 26 26 246 246 157 157 45 103 172 + 23 23 246 246 246 245 172 172 89 134 37 36 36 36 5 5 + 4 4 3 3 3 43 2 2 2 2 94 45 103 158 140 172 + 88 87 90 169 169 169 169 170 246 246 245 245 63 172 140 140 + 153 40 40 154 41 41 22 23 91 24 26 101 246 245 139 172 + 90 168 169 168 90 169 170 246 246 245 245 63 139 103 158 158 + 4 4 4 4 39 3 3 3 43 43 93 28 30 45 103 140 + 153 153 40 154 41 21 23 23 24 246 246 246 246 63 172 173 + 203 203 203 203 203 203 155 149 149 149 50 55 60 60 55 60 + 60 60 61 61 61 168 238 168 238 238 239 170 170 171 171 171 + 167 166 136 137 29 102 63 16 17 21 23 151 152 85 168 48 + 190 46 189 94 2 43 244 244 244 4 4 5 5 5 35 6 + 246 246 246 245 245 245 63 63 63 63 63 172 173 173 173 173 + 156 156 156 156 156 101 101 157 157 157 45 102 102 158 46 1 + 21 23 62 62 18 20 62 62 17 61 61 62 62 245 63 77 + 169 238 238 74 239 75 75 76 76 76 77 77 77 173 173 173 + 91 91 137 137 170 170 246 246 246 171 171 139 139 172 140 140 + 26 246 246 245 139 172 173 173 137 86 134 37 37 5 5 5 + 4 3 3 43 2 2 31 95 95 95 95 158 1 159 141 79 + 90 169 169 170 170 170 246 171 245 63 63 172 140 1 47 159 + 154 154 154 155 155 155 156 156 156 101 157 157 45 102 158 173 + 90 169 169 169 170 170 171 171 172 172 172 140 140 1 141 141 + 185 185 186 186 244 244 187 187 187 188 188 94 94 95 46 140 + 38 40 154 41 155 100 24 26 246 246 245 245 63 172 140 173 + 204 204 204 204 203 204 156 150 150 150 51 60 55 55 60 61 + 61 61 97 61 168 238 238 238 238 239 239 239 171 76 77 76 + 168 167 137 27 45 1 173 17 61 62 62 152 153 86 168 48 + 141 141 140 139 94 29 93 92 3 41 39 39 38 38 37 37 + 171 171 75 171 76 76 77 77 77 77 77 77 77 78 78 78 + 26 101 101 101 101 245 245 63 63 63 172 140 140 140 173 173 + 90 62 62 62 98 168 62 74 61 61 238 238 239 76 77 77 + 238 73 74 74 74 75 75 76 76 76 76 77 78 78 78 77 + 169 169 169 170 170 239 239 171 76 76 77 77 77 173 78 78 + 239 239 171 76 77 77 77 78 169 86 134 133 133 38 4 4 + 39 155 43 44 94 45 103 158 140 140 140 140 173 78 79 78 + 169 169 169 239 239 239 239 239 76 77 77 77 173 78 79 79 + 41 21 21 23 23 100 24 26 246 245 63 63 172 173 173 78 + 169 169 238 239 239 75 76 76 77 77 77 77 78 78 78 79 + 244 244 244 244 244 93 93 138 29 94 139 139 140 140 140 173 + 40 154 22 23 23 24 246 246 245 63 63 77 77 173 78 173 + 204 204 205 205 205 205 205 151 152 50 55 60 60 60 61 61 + 61 61 61 72 72 72 73 74 74 75 75 75 76 77 77 77 + 238 169 170 138 139 173 77 97 168 74 239 83 85 167 238 160 + 84 82 50 50 80 254 254 254 49 48 253 105 106 106 105 105 + 255 255 255 162 162 162 255 162 162 162 81 81 163 82 132 132 + 129 129 129 129 129 254 254 130 130 131 131 131 131 131 131 131 + 128 255 255 255 105 160 104 161 105 160 160 160 104 162 81 163 + 161 160 104 161 161 161 162 162 162 162 163 163 163 163 163 164 + 255 255 80 80 255 255 80 81 81 81 80 80 81 82 132 82 + 104 162 162 162 162 163 163 163 160 105 105 105 106 106 106 106 + 128 128 128 129 130 130 130 130 131 131 131 131 131 132 133 164 + 105 160 104 104 255 255 255 255 162 162 81 81 131 131 132 133 + 253 253 253 128 129 254 254 254 254 129 129 131 131 131 131 132 + 160 104 161 104 104 162 162 161 162 162 162 163 163 164 164 83 + 129 129 129 129 129 129 129 129 129 130 131 131 131 81 81 82 + 253 146 146 146 146 254 49 254 50 50 50 50 50 82 83 83 + 147 214 214 214 214 148 148 252 253 144 247 247 247 52 52 52 + 52 52 53 53 64 104 104 64 249 162 162 162 162 163 163 163 + 162 105 130 131 131 130 163 105 160 160 255 106 105 105 160 160 + 81 80 80 254 253 48 48 105 105 106 106 106 252 252 252 252 + 105 105 48 160 255 255 255 255 160 255 255 255 255 255 255 130 + 128 128 128 128 128 128 128 128 128 128 129 129 129 129 130 130 + 105 105 105 105 106 105 105 105 105 105 105 105 160 104 255 104 + 160 160 160 160 105 160 104 161 160 104 255 255 255 255 255 80 + 48 105 105 105 105 48 48 255 255 255 254 254 254 254 254 80 + 160 104 255 255 255 255 255 104 105 247 106 106 252 252 106 106 + 106 106 253 253 128 128 128 128 128 128 128 129 254 130 130 255 + 105 105 160 160 160 160 104 255 255 160 129 129 130 130 130 130 + 106 106 105 106 106 106 253 253 253 128 128 128 129 129 130 130 + 160 160 160 160 105 160 160 161 104 104 255 255 255 161 80 80 + 106 106 106 106 106 253 128 129 128 128 128 254 254 80 80 80 + 106 253 144 144 144 253 48 48 253 48 254 254 254 49 49 49 + 146 145 145 145 147 147 147 107 252 252 247 247 247 247 247 247 + 247 247 248 248 248 248 248 248 160 160 104 104 104 255 255 255 + 105 105 128 128 129 129 160 247 105 105 105 252 106 106 247 160 + 128 129 128 253 253 253 106 106 106 252 252 252 251 107 107 251 + 106 106 106 106 253 253 253 128 128 128 128 129 128 128 128 128 + 10 10 10 10 106 106 106 106 253 253 253 128 128 128 128 128 + 106 106 106 105 252 106 105 105 252 247 105 105 106 106 253 254 + 106 106 105 105 106 105 253 253 128 128 128 128 128 128 128 128 + 106 106 106 253 253 106 106 106 253 253 253 128 128 128 129 128 + 106 106 253 253 128 128 254 254 106 252 252 251 107 107 107 107 + 11 10 10 9 9 9 9 8 8 8 8 8 8 128 148 128 + 106 106 106 106 106 106 106 106 253 253 128 254 129 128 128 128 + 252 106 106 144 106 106 106 144 106 253 253 253 253 128 128 128 + 106 106 106 105 105 106 105 253 128 128 128 128 128 128 128 128 + 11 10 10 11 11 10 10 10 10 9 9 8 8 128 128 128 + 252 106 106 106 144 144 144 106 144 253 146 146 128 48 48 147 + 144 144 144 144 144 144 144 251 251 251 252 252 247 247 247 247 + 247 247 247 247 247 247 248 248 105 105 105 160 160 160 160 128 + 253 253 10 9 8 128 128 252 106 106 253 107 252 252 106 160 + 8 10 9 9 11 11 11 107 11 107 13 13 14 13 251 14 + 10 144 144 10 10 144 144 144 10 10 10 10 10 10 9 10 + 10 10 11 11 11 11 10 10 106 10 144 144 9 10 10 144 + 107 252 252 106 251 252 252 106 252 252 252 252 106 253 106 106 + 252 252 106 253 106 106 253 144 144 144 144 144 144 144 144 144 + 252 252 106 106 144 144 144 106 106 144 144 144 10 10 10 10 + 253 106 106 10 10 10 106 106 106 107 251 251 13 13 13 108 + 12 11 11 11 110 10 10 10 9 10 9 9 9 9 8 8 + 252 252 252 252 106 144 144 144 106 144 10 10 10 10 9 148 + 107 107 107 107 107 107 11 106 252 106 106 10 10 144 253 253 + 252 252 252 106 253 106 106 106 106 106 144 144 144 253 253 9 + 12 109 109 109 109 110 110 110 11 11 10 10 10 10 9 8 + 107 107 107 107 107 252 106 106 106 106 10 10 10 144 253 145 + 11 10 192 11 11 11 11 15 215 251 251 251 251 252 252 252 + 247 252 252 252 252 252 247 247 105 105 105 105 106 106 106 106 + 106 11 12 9 10 10 253 251 252 106 106 14 251 251 252 128 + 9 9 10 11 11 11 12 12 13 13 13 13 14 15 14 15 + 11 11 10 10 10 10 11 11 10 10 10 10 10 9 9 9 + 12 12 12 12 12 11 11 11 10 10 10 10 11 10 10 10 + 107 107 107 252 251 107 107 252 251 251 252 252 252 252 11 10 + 107 107 252 106 11 11 10 11 11 11 11 10 10 10 10 9 + 12 12 12 12 12 11 11 11 11 11 11 11 11 10 10 9 + 11 11 11 10 10 10 10 9 13 13 14 14 15 14 14 108 + 108 108 109 109 110 110 110 110 110 110 110 111 10 10 9 9 + 12 107 107 107 11 11 10 11 11 11 10 10 10 10 9 9 + 13 13 13 12 12 107 107 107 107 11 10 10 10 11 10 10 + 107 107 107 107 11 11 11 11 11 11 11 11 10 10 9 9 + 108 108 109 109 109 109 109 109 110 110 110 110 11 11 10 9 + 13 13 12 12 12 11 12 12 11 10 10 11 11 10 10 10 + 11 11 11 12 11 11 12 15 15 15 215 215 216 251 251 251 + 252 251 251 251 251 251 252 252 252 252 106 106 106 10 10 10 + 107 107 13 9 110 11 10 251 251 107 11 15 14 251 252 128 + 9 10 9 10 11 11 10 109 109 109 109 108 108 108 14 14 + 11 11 10 10 10 9 9 9 9 10 10 10 9 9 9 9 + 11 110 110 110 11 11 10 10 10 10 10 10 10 10 9 9 + 11 11 11 10 12 11 11 10 251 107 252 252 11 10 10 9 + 11 11 10 10 10 10 9 9 9 9 9 9 9 9 9 9 + 10 10 10 10 11 11 11 11 9 9 9 9 10 10 10 10 + 11 10 10 10 10 10 10 9 12 12 13 13 14 108 108 109 + 109 109 109 110 111 111 111 111 111 111 111 111 111 112 112 9 + 11 11 10 10 11 11 11 11 9 9 9 10 10 9 9 9 + 12 11 12 12 12 11 11 10 11 11 10 10 10 10 10 9 + 11 10 10 11 11 10 10 10 9 9 10 10 9 9 9 9 + 109 109 109 110 110 109 109 109 110 110 110 111 10 10 10 10 + 11 12 12 12 12 11 11 10 11 10 10 9 9 9 9 9 + 10 192 192 192 10 10 110 14 14 14 14 14 251 107 107 251 + 251 252 252 252 252 252 106 106 106 106 9 9 10 10 10 10 + 107 10 11 10 112 10 10 12 107 11 11 14 12 12 252 128 + 8 8 9 9 112 112 111 110 110 110 109 109 109 109 108 108 + 9 9 10 10 10 10 9 9 9 8 8 8 8 8 9 9 + 111 111 111 111 111 10 10 10 10 9 9 8 8 8 8 8 + 11 10 10 10 12 11 10 9 107 11 11 10 9 9 9 8 + 10 10 10 9 10 9 9 9 9 8 8 8 8 9 9 9 + 11 10 10 10 9 9 9 10 10 9 9 9 8 8 8 8 + 10 10 9 9 9 8 8 8 11 11 12 13 108 108 109 109 + 110 110 110 111 111 111 111 111 113 112 112 112 112 112 113 8 + 11 10 10 10 10 10 9 9 10 9 8 8 8 9 9 8 + 12 11 11 11 11 11 11 11 9 10 10 9 9 8 8 8 + 11 10 9 10 10 10 10 10 9 9 9 9 9 8 8 8 + 110 110 109 110 110 111 111 111 111 111 111 112 112 8 8 8 + 12 12 11 11 10 10 10 10 10 10 9 9 8 8 8 8 + 11 192 192 192 192 11 10 14 14 13 13 107 107 107 107 107 + 252 252 252 106 106 106 106 253 144 144 9 9 9 8 8 8 + 106 9 10 10 112 9 9 12 11 10 9 108 12 12 252 128 + 32 8 8 8 112 112 112 111 111 111 110 110 110 109 108 109 + 9 9 9 8 8 9 9 8 9 8 8 32 8 8 32 32 + 111 111 111 111 112 112 8 9 9 9 9 9 9 8 8 32 + 10 9 10 9 11 9 9 10 11 11 10 10 9 8 8 8 + 10 9 9 8 9 9 8 8 9 8 8 32 32 8 8 32 + 9 9 9 9 9 8 8 9 8 8 8 8 8 8 32 32 + 8 8 9 9 8 8 7 8 10 11 11 109 109 109 110 110 + 110 110 111 111 111 113 113 112 113 113 113 114 113 114 114 32 + 10 10 10 9 9 8 8 9 8 8 9 8 8 32 32 32 + 110 110 111 111 111 112 10 10 9 9 8 9 9 8 8 32 + 10 9 9 9 8 8 8 9 9 8 8 8 32 32 32 32 + 110 111 111 111 111 111 111 111 113 112 112 112 112 113 8 32 + 11 11 10 10 10 10 10 10 8 8 9 8 8 8 7 7 + 144 193 193 193 193 9 9 108 108 12 11 11 11 252 11 252 + 106 144 144 144 144 144 106 253 146 9 8 8 8 8 32 8 + 10 106 10 9 112 113 32 11 11 9 8 108 109 11 106 128 + 32 32 181 114 113 113 113 113 111 111 111 111 110 110 110 109 + 112 8 8 32 8 8 32 32 32 32 32 32 32 32 32 33 + 113 113 113 113 113 112 113 8 32 32 32 32 32 32 32 32 + 10 9 8 8 10 9 9 8 10 144 9 8 8 8 8 32 + 8 9 9 8 8 32 32 32 32 32 32 32 32 32 32 32 + 8 8 9 9 9 9 8 8 32 8 8 32 32 32 32 33 + 8 8 7 8 32 32 32 33 10 10 10 110 110 110 110 110 + 111 111 112 113 113 113 114 114 114 114 114 114 114 114 114 182 + 9 8 9 9 9 8 8 32 32 32 32 32 32 32 32 32 + 111 111 111 111 111 112 113 8 9 9 8 8 32 32 32 33 + 9 8 8 9 8 8 32 8 8 32 32 32 32 32 32 32 + 111 111 111 112 113 113 113 113 113 113 114 114 181 180 181 32 + 111 112 112 112 9 8 8 9 8 8 7 7 32 32 32 33 + 9 195 194 193 8 113 113 108 109 12 11 11 192 192 192 144 + 144 144 144 145 145 145 9 8 8 8 7 7 32 32 32 32 + 128 9 8 8 181 114 32 11 9 9 8 109 110 10 253 128 + 183 182 182 114 114 114 113 113 112 113 111 111 111 110 110 110 + 32 32 32 32 32 32 32 33 32 33 182 182 182 182 182 182 + 114 114 114 114 114 113 114 181 32 32 32 32 32 182 182 183 + 8 8 32 32 9 8 8 7 9 145 8 8 7 32 32 34 + 32 7 7 7 32 33 33 33 32 32 33 33 33 33 182 182 + 8 8 32 32 32 33 32 32 32 32 32 33 182 182 182 182 + 32 32 32 32 32 33 33 35 8 9 112 111 110 111 111 111 + 113 113 113 113 114 113 114 114 114 115 115 115 115 115 115 183 + 9 8 8 32 32 32 32 32 32 32 33 182 182 182 183 183 + 112 113 113 113 113 113 113 113 32 113 32 32 32 33 33 35 + 8 8 32 32 32 32 32 32 32 33 33 33 32 182 182 183 + 113 113 113 113 113 113 113 114 114 114 114 114 182 182 182 182 + 112 113 112 112 113 113 32 32 33 33 32 32 33 33 34 5 + 112 7 114 114 114 114 114 110 110 11 11 10 144 144 144 144 + 145 145 145 146 147 8 8 7 7 7 33 33 32 33 182 182 + 8 8 32 180 114 114 182 10 9 8 32 110 111 9 128 128 + 184 184 183 115 114 114 114 114 113 113 113 113 111 111 111 111 + 32 33 33 33 33 33 182 183 183 183 183 183 183 183 184 116 + 114 114 114 114 114 114 114 182 182 182 182 183 183 183 183 184 + 32 32 32 32 8 7 7 33 8 8 7 7 33 33 183 183 + 33 33 33 33 34 34 34 34 35 35 183 183 183 183 183 184 + 32 32 32 32 32 33 33 32 182 182 182 183 183 183 183 184 + 32 33 33 33 183 183 184 184 8 8 112 111 111 111 112 111 + 113 113 114 114 114 115 115 115 115 115 115 116 116 116 116 184 + 32 32 32 32 33 33 32 32 182 183 183 183 183 184 184 116 + 113 113 114 114 113 114 114 114 114 114 114 115 115 183 184 184 + 32 32 32 33 33 33 33 34 182 183 183 183 183 183 184 117 + 113 113 113 113 114 114 114 114 115 114 114 115 115 116 116 116 + 113 113 113 113 114 114 114 114 114 114 182 182 183 183 183 184 + 112 114 114 114 114 113 114 110 111 10 10 144 144 194 195 195 + 147 146 147 148 7 7 7 33 33 34 34 34 35 183 183 183 + 32 8 32 181 115 116 183 9 8 7 6 10 112 8 129 128 + 117 117 117 116 115 115 115 115 114 113 114 114 113 113 113 111 + 183 183 183 183 183 183 184 184 185 185 120 118 117 117 117 118 + 115 115 115 115 115 115 115 116 116 116 116 117 117 117 117 117 + 32 33 33 34 32 7 33 6 8 7 34 33 6 35 184 184 + 34 34 35 35 35 35 183 183 185 185 185 185 184 185 117 120 + 182 33 33 33 182 183 183 184 183 183 184 184 117 117 117 120 + 183 183 183 183 184 185 185 185 33 32 113 113 113 113 113 113 + 113 114 115 114 115 116 116 116 116 116 116 117 117 117 117 120 + 182 33 33 182 183 183 184 184 184 184 184 117 117 117 117 118 + 113 114 114 114 114 114 115 115 115 115 116 116 116 117 117 118 + 182 34 35 35 35 35 183 183 183 184 185 185 185 117 117 118 + 113 114 114 114 115 115 115 115 115 115 116 116 116 116 117 117 + 113 114 114 114 115 115 115 114 115 115 116 116 117 117 117 118 + 115 115 115 115 115 115 115 111 111 10 10 145 145 195 195 195 + 148 148 148 199 6 6 6 35 35 35 5 5 184 184 184 185 + 35 32 33 182 116 117 185 113 32 33 5 112 113 8 33 128 + 119 118 117 117 116 116 116 115 114 115 114 114 114 113 113 112 + 184 184 185 185 185 185 185 120 117 118 118 118 118 118 118 118 + 116 116 116 116 116 116 116 117 117 117 117 118 118 118 118 118 + 183 184 184 184 33 6 35 5 7 6 5 35 5 184 185 185 + 35 5 5 5 184 185 185 185 186 186 186 121 120 120 119 120 + 183 183 183 184 184 185 185 184 185 185 118 118 118 118 118 118 + 185 185 184 184 185 118 118 120 183 33 32 114 114 113 114 115 + 115 115 115 116 116 116 116 117 117 117 117 118 118 118 119 120 + 183 183 183 184 184 184 184 184 184 185 120 120 118 119 119 119 + 115 115 114 114 115 115 115 116 116 116 117 117 117 117 118 118 + 183 184 184 184 184 184 185 185 185 185 185 120 118 120 119 119 + 115 115 115 115 115 116 116 116 116 116 117 118 117 117 118 119 + 115 115 115 114 115 116 116 116 117 117 117 117 118 118 118 119 + 116 115 115 115 115 115 116 111 112 9 8 196 196 197 197 199 + 150 150 150 36 37 5 5 38 5 38 4 185 185 186 121 186 + 183 34 184 183 117 117 120 32 6 5 4 112 114 32 35 128 + 119 119 118 118 117 117 116 115 115 115 115 114 113 114 114 113 + 185 184 185 185 185 185 185 120 118 118 119 119 119 119 119 119 + 116 116 116 116 116 117 117 117 118 117 118 118 118 118 119 119 + 183 184 185 184 34 35 5 4 33 36 5 5 4 185 121 186 + 5 5 38 4 185 185 186 186 186 186 186 121 121 119 119 119 + 184 184 184 184 184 184 184 184 120 118 118 118 119 119 119 119 + 184 185 185 185 118 118 119 121 182 32 32 114 114 113 114 115 + 115 115 116 116 117 116 116 117 117 118 118 119 119 119 119 121 + 184 184 184 184 184 184 184 184 185 120 120 119 119 119 119 119 + 115 115 115 115 115 116 116 116 117 117 117 117 117 118 119 119 + 183 184 185 184 185 185 186 185 186 120 120 120 119 119 119 119 + 115 115 115 115 115 116 116 116 117 117 117 117 118 119 119 119 + 115 115 115 115 115 116 117 117 117 117 117 117 118 118 119 119 + 116 116 116 116 116 116 116 113 112 8 8 196 196 196 197 199 + 150 150 151 37 5 5 4 4 4 4 185 186 186 121 121 121 + 184 183 184 184 118 119 121 114 6 5 185 113 114 182 37 128 + 119 119 119 119 117 117 117 116 115 114 115 114 113 114 114 113 + 186 185 185 186 186 121 121 121 121 119 119 119 119 119 119 119 + 116 116 117 117 117 117 118 118 118 118 118 118 119 119 119 119 + 183 184 184 184 6 35 5 4 6 37 5 5 4 186 121 187 + 184 5 38 4 185 186 186 186 186 186 186 121 123 123 119 123 + 184 184 184 184 184 185 185 121 120 120 120 119 119 119 119 119 + 184 185 185 120 119 119 119 123 183 182 33 114 114 114 114 115 + 115 116 116 116 117 118 118 117 118 118 119 119 119 119 119 123 + 184 184 184 184 184 185 185 186 186 121 121 119 119 119 119 119 + 115 182 115 183 116 116 117 116 117 117 117 117 118 119 119 119 + 183 184 184 185 185 185 186 185 186 120 121 121 123 123 119 119 + 115 115 116 116 116 116 116 116 117 117 117 118 119 119 119 119 + 114 115 115 115 116 117 117 117 117 118 119 119 119 119 119 119 + 117 116 117 117 116 116 116 112 113 7 7 197 197 198 198 198 + 150 151 151 37 5 38 4 4 4 4 185 186 186 121 122 123 + 185 183 184 117 119 119 123 114 6 5 185 32 182 183 134 128 + 123 119 119 119 118 118 118 116 116 116 115 115 114 114 113 113 + 186 186 185 186 186 122 122 123 123 123 119 119 119 119 119 119 + 116 117 117 117 117 118 118 118 119 119 119 119 119 119 119 119 + 183 184 185 185 5 5 5 4 36 5 5 4 4 186 122 123 + 4 4 4 4 244 244 244 187 186 186 187 123 123 123 123 123 + 184 185 185 185 185 185 185 185 121 121 122 123 119 119 119 123 + 185 186 186 121 123 123 119 123 183 183 33 32 114 114 115 115 + 115 116 116 117 117 117 117 118 118 119 119 119 119 119 123 123 + 184 184 184 185 185 185 185 185 186 121 121 123 123 119 119 123 + 183 183 184 184 184 184 184 184 120 120 120 119 119 119 119 119 + 184 184 184 185 186 186 186 187 122 122 121 121 121 123 123 123 + 115 115 116 116 116 116 117 117 117 118 119 119 119 119 119 123 + 6 5 5 183 183 184 185 120 120 120 120 119 123 123 123 123 + 119 117 118 118 116 116 184 112 32 7 199 199 197 198 198 198 + 151 152 152 153 38 39 39 39 39 39 244 244 187 122 123 124 + 185 184 185 120 119 119 123 33 5 4 185 32 182 184 134 128 + 123 123 119 119 119 120 118 117 184 184 183 183 182 114 114 113 + 186 186 186 186 122 122 123 123 123 123 123 123 123 123 124 124 + 117 117 118 118 118 120 119 119 119 119 119 119 119 119 119 123 + 184 4 185 244 5 4 4 244 37 153 38 4 3 3 122 124 + 4 4 3 244 244 244 244 187 188 187 187 124 124 124 124 124 + 185 185 186 186 186 186 186 186 121 122 123 123 123 123 123 124 + 186 244 187 122 123 123 124 124 184 35 35 32 114 114 115 115 + 116 116 117 117 117 118 119 119 119 119 119 119 119 123 124 124 + 185 185 185 185 186 186 186 186 186 186 122 123 123 124 124 124 + 182 183 184 185 185 185 185 185 185 120 121 121 121 123 123 123 + 184 4 185 186 186 186 187 187 122 123 124 123 124 124 124 123 + 116 116 116 116 116 117 117 117 118 119 119 119 119 123 123 124 + 5 5 5 4 4 185 185 186 121 122 123 124 124 124 124 124 + 119 120 120 120 185 185 185 8 8 7 199 199 200 200 200 200 + 151 152 153 153 40 40 41 39 3 3 244 244 187 124 124 124 + 185 184 185 120 119 119 124 34 5 4 185 32 182 183 134 128 + 124 124 123 123 121 121 120 185 184 184 184 183 182 114 114 114 + 186 244 244 186 187 123 124 124 124 124 124 124 124 124 124 124 + 185 185 185 120 120 121 121 121 123 123 123 124 124 124 124 124 + 4 4 4 244 5 4 4 3 153 40 4 39 3 3 123 125 + 3 3 3 3 3 43 43 2 188 187 188 188 125 124 124 125 + 186 186 186 186 186 186 186 187 122 122 123 124 124 124 125 125 + 3 3 187 187 124 124 125 125 4 35 35 33 114 115 115 115 + 116 116 117 118 119 119 119 119 119 119 123 123 124 124 125 125 + 185 185 186 186 186 186 187 187 187 187 124 124 124 124 125 125 + 5 5 184 184 185 185 186 186 186 186 122 123 123 123 123 124 + 185 4 244 244 244 244 187 187 124 124 124 124 124 125 125 125 + 116 116 116 117 117 117 118 118 119 119 123 123 123 124 124 125 + 5 5 38 4 4 4 186 186 186 122 123 124 124 124 125 125 + 121 121 4 4 4 4 185 32 7 7 199 198 200 200 200 201 + 152 16 17 18 40 41 41 91 92 92 43 43 188 125 125 125 + 244 4 185 121 123 123 124 35 4 39 244 33 182 35 135 128 + 125 125 124 123 123 122 186 186 185 185 184 183 183 182 32 32 + 244 3 187 187 124 124 124 125 125 125 125 125 125 125 125 125 + 186 186 186 186 186 122 122 123 124 124 124 124 124 124 125 125 + 4 3 244 3 5 39 41 92 153 40 154 41 43 43 124 125 + 3 3 43 43 43 44 2 2 2 2 188 188 125 125 125 126 + 186 186 186 186 186 187 187 187 187 187 124 125 125 125 125 126 + 43 43 93 2 125 125 126 126 4 5 37 34 182 183 183 116 + 117 117 118 119 119 119 119 119 123 123 124 124 124 125 125 125 + 186 186 186 186 186 187 187 187 188 188 188 125 125 125 125 126 + 4 38 38 38 4 244 244 244 186 122 124 124 124 124 124 125 + 3 3 3 3 3 43 43 187 188 188 125 125 125 126 126 126 + 184 184 184 185 120 120 120 120 121 123 123 124 124 124 125 126 + 5 38 4 4 4 244 244 244 186 122 124 124 125 125 125 126 + 4 4 4 4 154 3 3 33 33 198 200 200 200 201 201 201 + 16 16 18 19 19 99 91 91 24 26 138 29 2 125 125 126 + 244 4 244 121 124 124 125 5 4 41 244 34 35 5 135 128 + 126 125 125 124 124 187 187 186 186 185 184 184 35 34 33 33 + 43 2 2 2 2 2 125 125 125 126 126 126 126 126 126 126 + 186 186 187 187 187 187 187 124 124 124 125 125 125 125 126 126 + 3 3 3 43 38 41 155 26 153 19 41 155 156 157 31 126 + 42 25 93 101 44 30 157 45 94 45 45 189 189 126 126 127 + 244 244 244 244 244 187 187 2 188 188 125 125 126 126 126 127 + 44 101 29 94 126 126 127 127 3 38 38 35 35 184 184 184 + 118 118 119 119 119 123 123 123 124 124 125 125 125 125 126 126 + 186 244 244 244 244 187 188 188 188 188 189 126 126 126 126 127 + 4 4 4 39 3 3 3 3 3 187 124 125 125 125 125 126 + 3 3 3 43 93 44 2 94 2 2 189 126 126 126 127 126 + 184 184 185 185 186 186 121 121 123 123 124 124 124 125 125 126 + 4 4 4 244 244 244 244 187 187 187 124 125 125 126 126 127 + 154 203 154 154 155 156 43 33 6 200 200 200 201 201 201 16 + 16 17 19 19 20 21 22 23 170 246 245 139 45 95 126 127 + 244 39 244 186 124 125 126 5 39 41 92 34 5 38 136 128 + 190 127 126 125 125 124 187 187 244 244 4 5 5 35 35 34 + 2 157 31 31 45 95 95 95 126 126 126 127 127 190 190 190 + 187 187 187 187 187 188 188 188 125 125 126 126 126 126 127 127 + 3 43 43 28 40 155 92 246 18 20 22 92 101 157 95 47 + 25 26 246 157 157 157 103 103 103 140 140 46 158 46 127 127 + 3 43 43 2 2 2 2 94 94 95 95 126 126 127 127 127 + 157 157 94 103 95 126 127 159 3 39 38 5 35 184 184 184 + 185 121 121 123 123 123 124 124 125 125 125 126 126 126 127 127 + 244 3 3 43 2 2 2 2 45 189 189 126 126 127 127 127 + 4 39 3 3 3 3 43 3 43 2 125 125 125 126 126 127 + 3 43 93 28 28 94 94 103 94 95 46 46 127 127 127 190 + 185 185 185 186 186 186 186 187 124 124 125 125 126 126 126 127 + 4 4 3 3 3 3 43 2 2 188 125 126 126 126 127 127 + 155 204 204 204 156 156 43 33 6 6 200 201 201 202 16 17 + 17 61 61 21 21 62 62 170 239 171 172 172 140 1 127 190 + 137 136 244 244 125 125 126 38 41 24 28 37 5 4 136 128 + 191 127 126 126 125 188 187 187 244 244 4 38 5 5 5 35 + 44 45 45 31 95 158 158 1 158 46 127 127 127 127 190 190 + 187 187 187 188 188 188 188 95 189 95 126 126 127 127 127 127 + 3 43 93 157 154 23 92 246 19 21 22 24 245 102 158 47 + 138 170 171 171 139 172 140 140 140 140 47 1 1 47 159 142 + 43 44 2 29 31 94 45 45 45 45 158 158 46 127 127 159 + 157 157 139 103 158 127 127 159 42 39 39 5 5 5 184 185 + 186 122 123 124 124 124 125 125 125 125 126 126 127 127 127 191 + 3 43 93 44 2 94 45 94 95 158 46 127 127 127 127 191 + 39 3 3 3 3 43 43 2 2 31 95 126 126 126 127 127 + 43 27 246 246 138 94 139 139 140 140 1 1 127 127 191 191 + 185 185 186 186 186 187 187 187 188 125 125 126 127 127 127 127 + 4 4 3 3 43 43 44 44 31 45 95 126 126 126 127 142 + 205 205 204 204 23 156 43 6 6 6 200 201 202 16 16 17 + 61 61 61 62 62 62 239 239 239 76 77 172 140 47 127 141 + 138 136 138 2 126 126 190 38 22 26 157 5 4 41 169 128 + 191 127 127 126 126 125 2 187 244 244 4 4 4 5 5 5 + 157 172 103 103 158 1 1 47 47 47 127 127 190 190 191 191 + 187 187 188 188 188 2 94 45 95 158 46 46 127 127 127 191 + 43 101 29 103 41 100 26 246 20 21 23 246 245 63 46 141 + 170 170 171 171 172 172 140 173 173 141 141 141 141 142 142 142 + 44 44 30 94 94 94 103 103 158 158 1 47 47 159 191 191 + 102 102 172 140 46 127 191 142 43 154 154 4 5 5 4 186 + 186 187 124 124 125 125 125 126 126 126 127 127 127 127 191 191 + 93 138 29 29 94 103 95 95 1 127 127 127 127 191 191 175 + 3 3 3 43 43 43 44 29 94 45 95 126 126 127 127 191 + 28 246 171 172 139 139 172 172 140 141 47 47 159 191 175 191 + 186 186 186 186 187 187 188 188 188 189 189 126 127 127 190 191 + 244 3 3 43 43 101 157 157 102 102 1 1 1 159 142 142 + 205 205 205 204 156 156 2 6 6 6 152 201 16 17 17 61 + 61 61 61 62 62 239 239 239 75 75 76 77 173 141 141 174 + 139 137 138 2 126 127 141 39 22 26 245 5 4 3 169 48 + 175 142 174 47 46 103 94 44 43 92 41 39 39 38 5 37 + 172 173 172 172 173 140 140 173 141 141 141 141 141 174 174 142 + 29 29 29 94 139 139 139 172 140 140 140 141 141 141 142 142 + 26 245 246 172 99 24 246 171 61 62 62 170 63 63 140 78 + 170 239 75 76 76 77 77 173 78 79 79 79 79 174 142 174 + 246 245 139 139 139 172 172 172 172 173 173 141 141 174 142 175 + 103 172 172 140 173 174 174 175 26 90 41 40 5 38 4 244 + 244 187 187 125 125 126 126 126 127 127 127 191 191 175 143 175 + 138 246 246 246 139 172 140 140 173 47 141 141 174 142 175 175 + 41 42 92 25 26 28 138 138 139 139 172 140 140 141 174 142 + 246 171 171 172 77 77 77 173 173 78 79 174 142 175 175 175 + 244 186 187 187 187 188 188 189 94 189 140 140 140 140 174 175 + 155 155 42 25 101 245 245 245 63 173 173 173 79 79 174 175 + 206 206 206 206 206 101 44 6 36 152 152 16 61 61 61 61 + 61 61 72 73 74 74 74 75 75 75 76 77 78 79 174 79 + 171 169 171 94 127 190 174 135 62 171 63 38 41 92 169 48 + 133 133 132 131 131 130 129 129 128 128 128 253 253 106 10 10 + 130 131 131 131 131 132 132 132 132 132 133 133 133 132 132 133 + 129 129 130 130 130 130 131 131 132 132 132 132 132 133 133 133 + 254 130 129 130 253 129 254 80 105 53 80 80 80 81 132 132 + 161 161 161 162 162 81 163 132 133 133 133 133 133 133 133 133 + 129 130 130 130 130 131 131 131 132 132 132 132 132 133 133 133 + 131 131 131 132 132 132 132 132 254 254 128 106 10 9 8 8 + 8 8 32 33 33 6 6 35 35 5 5 37 37 37 38 134 + 129 130 130 130 130 131 131 131 131 132 132 133 133 133 133 134 + 128 128 128 128 148 254 254 254 254 130 131 132 132 132 132 133 + 129 130 130 130 130 131 131 131 132 132 132 133 133 133 134 134 + 8 8 8 8 8 32 33 33 34 131 131 132 132 132 132 133 + 128 147 147 148 254 254 149 149 150 151 151 151 151 37 37 153 + 196 197 214 196 149 149 149 106 106 144 144 48 53 53 53 53 + 52 53 53 104 104 104 161 161 162 162 163 163 163 132 133 133 + 255 255 130 131 35 37 132 128 254 80 130 106 128 128 255 160 + 135 134 133 132 132 132 130 254 254 128 128 128 253 144 106 106 + 131 163 132 132 132 164 133 133 132 133 133 133 134 134 134 165 + 255 255 162 162 162 81 163 132 131 132 132 132 133 133 134 84 + 254 80 130 130 128 254 80 81 53 54 54 54 81 82 133 165 + 162 162 162 163 163 163 164 164 164 133 133 133 133 133 133 134 + 130 130 130 131 131 131 163 163 132 132 132 133 133 133 134 134 + 131 131 163 132 133 133 84 84 160 160 128 253 10 9 8 8 + 8 32 32 34 35 35 35 35 5 5 5 37 38 134 135 135 + 130 130 130 130 131 131 163 163 132 164 133 165 84 165 165 85 + 48 254 254 254 254 49 49 80 50 82 82 83 83 133 84 134 + 130 130 130 131 131 163 163 132 164 133 133 133 133 134 134 135 + 8 7 32 32 32 33 34 34 132 131 132 133 133 133 133 165 + 48 48 254 254 254 130 150 150 50 82 83 152 152 133 134 153 + 196 198 214 214 150 150 49 106 106 253 105 53 53 53 53 53 + 53 58 249 249 64 249 249 162 162 163 163 164 164 164 133 165 + 162 255 131 131 132 133 133 160 104 162 131 106 128 129 255 160 + 135 135 133 133 133 83 131 130 254 254 128 129 128 253 144 106 + 132 164 164 164 132 133 133 133 134 134 134 134 135 135 135 166 + 130 81 163 81 81 82 132 132 132 133 133 134 134 135 135 135 + 80 81 131 132 129 130 81 164 104 54 104 80 96 83 133 166 + 162 162 163 163 164 164 164 165 165 165 134 134 135 135 135 166 + 131 131 163 163 163 163 132 164 164 164 133 133 134 135 135 135 + 132 132 164 164 133 134 135 166 255 255 129 128 8 8 8 8 + 7 32 33 34 35 35 5 5 5 5 38 38 38 135 135 88 + 130 130 131 131 163 132 164 164 164 133 133 165 135 135 135 86 + 254 254 254 49 80 50 50 50 50 83 83 83 133 84 135 85 + 130 131 131 163 163 164 164 164 133 133 134 134 134 135 135 135 + 7 32 33 33 33 34 34 35 132 132 132 133 84 134 165 166 + 254 254 254 49 130 130 50 50 82 83 84 84 84 85 134 40 + 197 200 200 214 151 150 150 106 106 253 48 53 53 53 53 52 + 58 249 249 64 249 249 65 162 250 250 164 164 165 165 166 166 + 162 162 131 132 133 133 134 255 255 162 82 253 128 129 255 160 + 88 86 84 84 133 83 82 80 254 49 254 48 48 148 146 144 + 83 164 164 164 133 133 165 134 166 166 166 135 135 166 166 166 + 131 163 82 82 82 132 132 133 133 133 133 133 134 134 135 85 + 80 81 131 132 129 130 131 163 49 54 54 80 96 84 133 166 + 162 250 250 250 164 164 165 165 165 165 135 135 135 135 167 167 + 131 163 132 132 164 164 164 133 133 133 165 134 135 135 135 135 + 133 133 164 164 134 135 86 167 255 255 129 128 8 8 8 7 + 7 33 34 35 35 37 5 5 5 38 4 39 40 135 135 88 + 131 131 163 163 132 164 164 164 133 133 165 135 135 167 167 88 + 254 254 49 150 50 50 50 151 82 83 83 133 84 85 86 135 + 131 131 163 132 164 164 164 165 133 134 165 135 135 135 135 135 + 7 33 34 34 34 34 35 35 37 132 133 84 84 166 135 167 + 254 49 49 80 131 131 82 82 83 83 84 84 84 85 135 20 + 199 200 200 200 151 151 150 106 106 253 48 53 53 53 53 53 + 59 249 249 249 249 250 250 163 250 250 165 165 165 166 166 166 + 163 162 132 132 133 134 166 255 255 163 83 253 128 254 162 160 + 90 87 88 85 84 84 83 82 49 80 49 48 48 254 48 253 + 84 165 165 165 165 135 166 166 166 135 135 135 167 167 167 168 + 132 132 132 133 133 133 133 133 134 134 135 135 135 135 86 86 + 131 132 132 133 254 131 81 164 104 54 81 81 96 166 135 166 + 163 250 67 164 165 165 165 166 166 166 167 167 167 88 167 167 + 132 132 164 164 133 133 165 165 165 165 166 135 135 135 167 167 + 134 134 165 165 135 135 167 167 162 255 129 128 8 8 8 7 + 33 34 35 37 5 38 38 38 4 4 39 41 41 89 136 168 + 132 163 164 164 164 164 165 165 165 166 135 167 167 136 168 168 + 254 149 150 150 50 151 151 152 83 83 84 85 85 86 88 87 + 132 132 164 164 133 133 165 165 165 166 135 167 167 136 136 136 + 33 33 34 34 34 35 35 37 37 134 134 85 135 167 167 167 + 49 80 50 50 50 82 83 83 83 84 84 85 85 86 89 99 + 198 200 200 200 151 151 151 253 253 253 48 52 53 53 58 58 + 59 58 249 249 250 250 250 250 67 68 165 166 166 166 167 167 + 164 163 132 132 134 135 166 255 162 163 84 128 129 130 163 160 + 169 169 90 86 85 84 84 83 82 50 49 49 254 148 147 254 + 84 165 166 166 166 167 167 167 167 167 167 168 136 168 168 169 + 132 132 133 133 84 134 85 85 135 86 86 86 88 90 90 169 + 82 133 133 134 130 82 133 165 104 54 96 96 165 167 136 167 + 164 67 68 165 165 166 166 166 167 167 167 167 136 136 136 168 + 132 133 133 165 165 165 166 166 166 166 135 167 167 136 168 168 + 134 166 166 166 167 136 168 168 163 162 130 129 128 8 7 33 + 34 35 37 5 38 38 4 4 4 39 41 41 136 90 137 169 + 164 164 164 164 165 165 165 165 166 135 167 167 168 168 169 169 + 130 150 50 151 151 152 83 84 84 84 85 86 88 88 87 169 + 133 164 164 165 165 165 166 166 166 167 167 167 136 168 169 137 + 34 34 34 35 35 35 37 38 38 134 135 86 88 87 168 168 + 80 50 50 82 82 83 83 84 84 85 18 86 88 90 90 23 + 200 201 201 201 152 152 84 253 253 146 48 53 53 58 59 59 + 58 249 249 250 250 250 250 68 69 69 166 166 167 167 167 168 + 164 163 132 133 135 136 167 255 163 164 85 128 254 131 163 160 + 169 169 90 88 85 84 84 83 83 50 150 150 149 147 147 254 + 85 166 135 135 166 167 167 167 168 168 168 168 168 168 168 169 + 132 132 133 134 134 135 135 135 134 135 135 88 88 136 136 90 + 82 83 133 134 254 82 83 165 54 55 96 96 165 167 136 168 + 164 68 69 69 166 166 167 167 168 168 168 168 136 136 137 169 + 133 133 134 134 135 166 166 167 135 167 167 136 136 168 169 169 + 135 135 166 167 136 136 169 169 163 162 130 129 128 8 7 33 + 34 35 37 38 38 4 4 4 4 39 41 42 91 91 137 169 + 133 133 165 165 165 166 166 166 135 167 136 136 136 136 137 137 + 131 50 151 83 152 84 84 84 84 85 85 86 88 87 90 169 + 133 133 165 165 166 166 166 167 167 167 136 136 136 137 137 137 + 35 34 35 35 35 35 5 38 38 135 135 135 88 90 169 169 + 50 50 50 82 83 84 84 84 85 18 19 87 87 91 137 24 + 201 201 201 201 152 16 85 146 253 48 48 54 54 59 58 58 + 58 59 250 250 250 250 68 69 69 70 70 237 168 168 168 168 + 164 163 133 133 135 137 168 130 163 164 166 128 130 81 164 160 + 170 137 90 88 86 85 84 152 152 151 150 150 149 148 148 147 + 86 167 167 135 167 167 168 169 136 136 136 136 169 170 169 169 + 133 134 134 134 135 86 135 86 135 88 136 90 137 137 137 169 + 133 85 134 85 50 83 84 166 55 55 96 96 98 167 136 169 + 165 69 69 70 70 237 167 168 168 168 168 136 136 137 137 169 + 134 84 134 135 135 135 135 135 167 136 136 136 136 136 169 169 + 135 135 167 167 136 136 137 169 164 163 130 129 128 7 33 34 + 35 37 5 38 4 4 4 4 244 3 3 42 137 137 137 170 + 133 133 165 165 165 166 167 167 135 136 136 136 136 137 137 170 + 131 50 152 83 84 84 84 84 84 86 86 86 88 90 169 169 + 134 134 135 166 166 166 167 167 167 136 168 169 137 137 137 137 + 35 34 35 5 5 5 5 38 38 39 40 88 136 137 170 170 + 50 50 82 152 84 84 84 84 85 18 19 87 87 91 137 24 + 201 201 202 202 201 153 85 146 147 48 48 54 54 59 58 59 + 59 250 60 250 250 165 69 165 69 70 237 168 168 168 169 169 + 165 164 133 134 136 137 168 130 164 165 86 128 130 132 164 160 + 138 137 137 136 89 86 85 153 153 152 151 151 150 149 148 128 + 88 88 89 136 136 90 169 169 137 137 137 137 137 170 170 170 + 134 40 40 40 40 40 88 89 136 136 137 137 137 137 170 170 + 84 85 86 87 50 83 97 61 55 60 97 166 61 168 90 169 + 166 236 70 237 237 237 168 168 169 169 169 169 137 137 170 170 + 135 135 135 86 88 88 136 168 136 136 136 137 137 137 170 170 + 88 168 168 168 137 137 137 170 134 133 131 130 7 33 34 35 + 35 5 38 4 4 4 244 244 244 3 43 43 27 138 246 170 + 134 135 135 135 135 167 167 136 136 136 137 137 137 137 138 246 + 132 83 83 84 84 84 85 85 86 86 87 90 91 137 170 170 + 134 135 135 167 167 167 167 136 168 136 137 137 170 170 138 138 + 35 35 5 5 5 5 38 4 39 41 42 137 137 170 170 246 + 152 83 84 84 84 85 86 87 19 20 21 23 23 24 26 246 + 202 202 201 201 16 17 18 147 147 149 49 54 54 59 59 59 + 59 60 60 250 166 236 165 70 70 237 237 168 169 169 169 170 + 166 164 135 135 137 137 170 81 164 166 88 129 131 132 165 160 + 139 138 138 137 91 41 40 40 38 153 37 36 36 150 7 129 + 90 90 90 169 169 169 169 170 170 170 170 170 170 246 246 171 + 40 40 40 40 41 41 41 91 91 137 137 246 138 246 246 246 + 84 86 86 90 82 97 97 61 60 60 61 61 61 169 169 170 + 166 70 237 237 237 238 238 169 239 170 170 170 170 170 171 171 + 135 86 86 88 88 89 136 137 137 137 137 170 170 170 246 171 + 136 169 169 169 170 246 246 171 134 133 131 130 33 6 35 35 + 5 38 4 4 244 244 244 244 244 43 44 44 29 139 171 171 + 135 135 135 167 167 168 136 136 169 137 137 138 138 246 171 171 + 132 133 84 84 85 85 86 86 88 89 91 91 137 170 246 170 + 135 167 167 136 168 168 168 169 169 170 170 246 246 171 171 139 + 35 183 5 5 5 4 4 244 39 41 42 92 25 26 246 171 + 152 152 153 85 85 40 88 99 21 21 23 62 246 246 246 245 + 202 202 203 203 202 17 20 148 148 149 49 54 54 59 59 60 + 55 60 60 250 166 166 166 237 237 237 238 238 169 170 170 170 + 167 165 135 135 137 137 170 81 165 166 88 129 131 132 165 160 + 139 139 138 27 92 42 41 39 39 38 38 37 36 34 33 7 + 90 91 137 137 137 137 170 246 246 246 138 246 246 171 139 139 + 41 41 41 41 41 155 42 92 25 27 138 246 138 246 246 171 + 85 87 88 21 83 98 61 61 60 61 61 61 168 62 246 171 + 167 237 237 168 238 238 238 239 239 239 171 171 171 171 139 139 + 86 88 89 90 90 90 137 137 137 137 137 138 138 246 139 172 + 91 137 169 169 246 246 246 171 135 134 132 131 6 36 37 5 + 38 38 4 4 244 244 187 43 2 2 2 31 45 139 172 172 + 88 88 136 136 136 169 137 137 137 137 138 138 138 139 139 172 + 133 84 85 85 86 86 89 99 90 91 91 24 246 246 246 171 + 88 88 168 168 168 169 169 169 170 170 246 171 139 139 172 103 + 184 184 184 185 4 4 244 244 244 3 43 93 138 138 245 63 + 152 153 40 40 88 41 99 99 23 23 24 246 246 246 139 63 + 154 202 203 203 203 20 21 148 148 149 49 54 55 55 55 60 + 60 60 60 96 166 237 167 237 237 238 238 238 239 171 171 171 + 167 166 136 136 138 138 171 132 85 86 90 130 131 133 166 160 + 140 139 94 138 93 42 3 41 39 4 38 5 37 35 34 33 + 137 24 24 246 246 246 246 246 246 171 139 139 139 139 172 172 + 3 3 3 3 42 43 93 28 27 28 29 94 139 139 139 172 + 88 21 22 62 16 61 21 62 97 61 61 87 21 62 246 171 + 168 168 168 238 238 239 239 239 171 171 171 172 172 172 172 172 + 90 90 91 100 137 137 137 246 138 138 138 139 139 139 139 172 + 92 170 137 170 171 139 139 172 88 135 133 132 36 5 5 5 + 4 4 4 244 187 2 2 188 188 188 31 95 103 140 140 172 + 136 136 137 137 137 170 170 137 138 138 138 139 139 172 140 140 + 134 40 40 88 88 41 22 91 91 92 24 27 246 246 139 172 + 136 136 136 169 169 169 170 170 170 171 171 139 172 172 172 140 + 185 185 185 185 244 244 244 244 3 43 2 29 94 139 172 172 + 153 40 40 41 41 41 91 23 24 26 246 245 245 245 172 63 + 204 203 203 203 204 21 155 148 149 150 50 55 55 60 55 60 + 60 60 60 166 237 237 237 72 238 238 238 239 239 171 171 171 + 168 166 136 136 29 139 172 133 98 88 91 131 37 134 167 160 + 173 140 103 94 44 43 43 3 41 4 4 38 5 37 35 34 + 26 246 246 246 245 245 245 63 139 172 140 140 140 140 140 47 + 43 3 3 43 43 43 28 94 29 94 94 139 103 103 140 140 + 41 23 23 246 17 20 62 62 61 61 61 169 62 246 63 172 + 169 169 169 239 239 239 75 76 76 77 77 172 172 173 140 140 + 91 23 24 26 246 246 246 246 171 139 139 172 140 140 140 173 + 26 246 246 246 172 140 140 173 136 135 133 37 37 5 5 5 + 4 4 244 2 188 188 188 125 125 125 126 126 47 47 141 173 + 91 137 137 137 170 170 170 246 171 139 139 172 140 140 140 141 + 40 40 41 41 41 155 42 24 25 26 28 30 139 103 140 140 + 137 169 169 170 170 170 171 171 171 139 172 172 140 140 173 47 + 185 185 185 186 244 244 43 2 2 188 188 94 45 103 140 173 + 40 40 154 41 41 42 92 24 101 245 245 63 63 140 140 159 + 204 204 204 204 204 21 100 150 149 151 151 51 55 60 60 60 + 61 61 61 61 168 238 238 238 238 74 75 75 76 172 172 77 + 169 167 137 137 45 140 78 85 88 87 24 36 37 86 167 128 + 141 141 140 103 94 2 43 3 3 39 4 38 5 5 35 35 + 28 245 245 245 245 63 63 172 172 140 140 1 140 47 47 141 + 43 43 43 93 44 44 2 45 94 45 103 103 140 140 47 173 + 155 24 26 245 18 21 62 239 61 61 168 169 62 245 172 173 + 170 170 239 239 239 75 76 76 77 77 173 173 173 173 173 141 + 24 26 26 246 246 246 246 245 139 139 139 140 140 140 140 141 + 101 245 245 245 140 1 1 141 136 88 134 37 37 5 5 4 + 4 244 187 188 188 188 125 125 126 126 126 127 127 159 141 79 + 92 24 246 246 246 246 171 171 139 172 140 140 140 141 141 141 + 39 41 41 155 42 42 156 101 101 101 157 45 103 46 1 141 + 137 169 170 170 171 171 171 172 172 172 140 173 141 141 141 190 + 185 185 186 186 187 187 2 2 188 188 189 189 95 46 141 79 + 40 154 41 41 155 42 43 101 245 63 63 1 173 159 141 159 + 205 205 205 204 204 23 156 6 150 151 152 55 60 60 60 61 + 61 61 61 168 168 238 238 238 74 75 75 76 77 173 173 78 + 239 168 137 93 45 140 78 85 90 90 246 37 38 88 168 128 + 174 174 47 46 102 31 2 43 3 3 4 4 38 5 35 35 + 157 245 63 63 63 63 140 173 173 159 159 47 159 141 141 142 + 2 2 2 2 94 94 45 95 95 158 158 46 47 141 141 141 + 92 101 101 245 20 62 62 239 61 61 169 170 246 63 140 173 + 170 239 239 239 76 76 77 77 77 77 78 78 173 79 79 174 + 101 101 101 245 245 245 63 172 172 103 158 1 47 47 141 174 + 245 63 63 172 173 159 159 174 137 136 135 38 5 5 4 4 + 244 244 187 188 125 125 125 126 126 126 127 127 127 142 142 174 + 26 246 246 246 246 139 139 139 172 140 140 140 141 141 141 142 + 41 155 42 156 156 156 101 157 157 157 102 102 158 47 159 174 + 137 170 170 171 171 171 172 172 173 173 173 141 141 174 174 191 + 186 186 186 187 187 2 2 188 188 189 189 189 46 47 141 142 + 41 41 155 42 43 43 101 157 102 63 1 1 173 159 141 142 + 206 205 204 205 205 206 101 6 36 152 152 16 16 61 61 61 + 61 61 61 238 238 238 239 239 75 75 76 77 77 78 79 78 + 239 168 138 138 46 1 78 85 169 23 245 38 40 90 169 128 + 175 142 174 159 1 102 157 157 43 43 3 39 4 38 5 37 + 63 63 1 173 173 173 79 79 174 174 174 174 174 142 175 143 + 31 31 157 102 102 102 158 1 1 1 47 159 141 174 174 174 + 101 245 245 63 21 62 62 239 61 62 62 246 245 63 173 79 + 171 75 76 76 76 77 77 78 78 78 79 79 174 142 142 175 + 245 245 245 63 63 63 63 173 173 173 141 174 174 174 142 142 + 63 173 173 173 79 174 142 175 24 91 88 40 38 5 4 244 + 187 187 188 188 189 126 126 127 127 127 127 191 142 175 175 175 + 246 245 245 245 245 172 140 173 173 173 141 174 174 142 175 143 + 155 42 156 156 156 101 157 157 102 102 158 1 159 159 142 142 + 246 171 171 76 77 77 77 78 78 79 79 174 142 142 175 143 + 186 186 187 187 187 188 94 95 189 189 127 47 159 174 142 175 + 155 155 156 101 101 101 157 63 1 173 173 173 159 174 142 175 + 206 206 206 206 206 205 206 152 152 152 152 16 61 61 61 61 + 61 61 72 73 74 74 75 75 75 76 77 77 78 79 174 79 + 239 169 171 94 141 174 79 86 62 62 63 40 154 23 170 129 + 7 148 148 147 146 146 145 9 10 10 10 10 10 11 11 12 + 145 146 147 147 147 147 148 148 148 148 148 148 148 149 149 149 + 9 9 9 145 146 146 146 147 147 147 147 148 148 148 148 148 + 144 145 145 146 144 144 145 146 144 144 145 146 147 148 148 148 + 146 146 146 146 48 48 48 48 148 148 147 148 148 149 199 199 + 145 145 146 146 146 146 146 147 147 147 148 148 148 148 148 149 + 146 147 147 147 148 148 148 149 144 144 106 11 11 11 11 11 + 10 10 9 9 8 8 32 32 7 7 7 7 7 7 7 149 + 145 145 145 145 146 146 147 147 147 148 148 148 148 149 149 149 + 10 144 144 144 144 145 145 145 146 146 146 147 147 148 148 148 + 146 146 146 146 146 147 147 147 148 148 148 148 148 149 149 7 + 9 10 10 10 9 9 8 8 9 8 8 8 8 148 149 199 + 144 144 144 144 145 145 145 146 146 146 147 148 148 148 148 199 + 196 195 194 194 144 145 145 11 107 11 192 144 106 247 52 52 + 247 247 52 52 53 48 48 48 253 48 48 48 254 149 149 254 + 128 128 128 8 8 7 149 144 144 145 146 252 10 144 253 48 + 150 149 148 148 147 147 146 146 145 144 10 10 10 10 11 11 + 147 147 148 148 148 148 148 148 199 149 149 149 149 149 149 150 + 146 146 146 146 147 147 147 147 148 148 148 148 148 149 149 199 + 145 146 146 146 144 145 146 147 144 145 146 147 147 147 148 150 + 146 48 48 48 48 48 254 149 149 149 149 149 149 150 199 199 + 146 146 146 147 147 147 147 147 148 148 148 149 149 149 150 150 + 147 148 148 148 148 149 150 150 145 145 144 10 11 10 10 10 + 10 9 9 8 8 8 8 8 7 7 7 7 33 150 150 150 + 146 146 146 146 147 147 148 148 148 148 149 199 199 199 150 150 + 144 145 145 145 145 146 146 146 146 147 147 148 148 149 149 149 + 146 48 48 48 48 48 148 148 149 149 149 149 150 150 150 150 + 10 10 10 9 8 8 8 9 8 7 7 148 148 149 150 150 + 144 144 145 145 145 146 146 146 147 147 148 149 149 149 150 200 + 212 212 194 194 145 146 145 252 11 192 192 144 106 247 52 52 + 52 52 52 53 53 53 48 48 48 48 254 254 49 149 150 149 + 128 128 128 128 8 7 149 144 145 146 147 252 10 144 253 48 + 151 150 150 149 148 148 147 146 146 145 144 144 10 10 10 10 + 148 148 148 148 149 149 199 199 150 150 150 150 150 150 150 150 + 147 147 147 147 148 148 148 148 148 149 149 150 150 150 150 150 + 146 147 147 148 145 146 146 147 146 146 48 147 147 148 149 151 + 147 48 48 254 254 49 49 49 150 150 150 150 150 150 151 151 + 147 147 147 147 148 148 148 148 149 149 149 149 150 150 150 150 + 148 148 149 149 149 150 150 151 146 145 144 10 10 10 10 10 + 9 9 8 8 7 7 7 7 33 33 33 6 6 151 151 151 + 147 147 147 147 148 148 148 148 149 149 199 150 150 150 151 151 + 145 145 145 146 146 146 147 147 148 148 148 149 149 149 150 150 + 147 48 48 48 48 149 149 149 149 149 150 150 150 151 151 151 + 9 9 8 8 9 9 8 7 7 7 7 7 149 150 151 151 + 145 145 145 146 146 147 147 147 148 148 149 199 150 150 150 201 + 212 212 195 195 194 195 146 11 192 192 192 144 144 247 52 52 + 52 53 53 53 53 53 48 48 49 49 49 49 150 150 150 150 + 128 128 128 32 7 33 150 144 146 48 148 144 144 145 253 48 + 152 151 150 150 149 148 148 147 146 146 145 144 10 10 10 10 + 149 149 149 149 150 150 150 150 150 150 151 151 151 151 151 151 + 147 147 147 148 148 148 149 149 199 150 150 151 151 151 151 151 + 147 148 148 148 146 147 147 148 48 48 48 48 149 150 150 151 + 148 254 49 49 49 49 49 150 50 151 151 151 151 151 151 152 + 148 148 148 148 149 149 149 149 149 149 149 150 150 151 151 151 + 149 149 150 150 150 150 151 152 147 146 144 10 10 10 10 9 + 8 8 8 7 7 32 33 33 6 6 6 6 36 36 151 151 + 147 148 148 148 148 149 149 149 149 150 150 150 151 151 152 152 + 145 146 146 146 147 147 147 148 148 148 149 149 150 150 151 151 + 147 254 49 254 49 49 150 150 150 150 150 151 151 151 152 152 + 8 8 9 8 8 7 7 7 7 7 33 6 150 151 152 152 + 145 146 146 146 147 147 148 148 149 199 150 150 150 151 151 201 + 212 212 196 196 195 196 147 144 192 192 192 144 144 52 52 57 + 53 53 53 53 53 53 49 49 49 49 49 150 50 151 151 151 + 129 129 129 33 33 6 150 144 48 148 149 144 144 145 48 48 + 152 152 151 150 150 149 148 148 147 146 146 145 144 10 10 10 + 149 150 150 150 150 150 151 151 151 151 151 152 152 151 152 152 + 148 148 148 148 149 149 149 199 150 150 151 151 151 151 152 152 + 147 148 148 149 146 147 48 49 146 48 48 49 149 150 151 151 + 149 49 49 49 80 50 50 50 50 151 151 152 152 152 152 152 + 148 148 149 149 149 149 149 150 150 150 151 151 151 151 152 152 + 150 150 150 151 151 151 152 152 148 146 145 144 10 9 9 9 + 9 8 8 7 33 33 33 33 6 6 6 36 36 152 152 153 + 148 148 149 149 149 149 150 150 150 150 151 151 151 152 152 152 + 146 146 147 147 147 148 148 148 149 149 149 150 150 151 151 152 + 148 254 49 49 49 150 50 151 151 151 151 152 152 152 152 5 + 8 9 8 8 7 7 7 8 33 6 6 6 36 151 152 152 + 145 146 146 147 148 148 148 149 150 150 150 151 151 152 152 201 + 195 213 214 196 195 196 148 144 192 192 192 144 145 52 53 58 + 53 53 53 53 53 54 54 54 80 80 80 50 50 151 152 132 + 129 129 129 33 6 36 151 145 48 148 149 144 145 146 48 48 + 153 152 152 151 150 150 149 148 147 147 146 145 145 144 10 10 + 150 150 151 150 150 150 151 152 152 152 152 152 152 152 152 152 + 148 149 149 149 149 150 150 150 150 151 151 151 152 152 152 152 + 148 149 149 149 146 148 49 49 146 48 49 49 49 150 151 152 + 49 49 49 80 50 50 82 82 82 152 152 152 152 152 152 152 + 148 149 149 149 149 149 150 150 150 151 152 152 152 152 152 153 + 150 150 151 151 151 151 152 153 148 147 146 144 9 9 9 8 + 8 8 7 7 33 33 6 6 6 36 37 5 5 5 153 153 + 148 149 149 149 150 150 150 150 151 151 151 152 152 152 153 153 + 146 147 147 148 148 148 148 149 199 150 150 151 151 152 152 152 + 149 49 49 49 80 50 50 151 151 152 152 152 152 153 153 153 + 9 8 7 7 8 8 7 33 6 6 6 36 36 36 152 153 + 146 146 147 148 148 149 149 150 150 150 151 151 152 152 153 201 + 196 213 214 214 196 197 148 144 144 192 144 145 48 53 53 53 + 53 53 53 54 54 54 49 49 50 50 50 50 151 152 152 133 + 129 129 129 34 6 5 152 146 48 149 150 144 145 147 48 48 + 153 153 152 152 151 150 199 149 148 148 147 146 146 145 144 144 + 151 151 151 151 151 151 152 152 152 152 152 153 153 153 153 153 + 7 149 149 150 150 151 151 151 152 152 152 152 152 153 153 153 + 148 150 150 150 147 149 49 50 48 49 49 50 150 151 152 85 + 49 49 80 50 82 82 82 83 84 152 153 153 153 153 153 153 + 149 149 150 150 150 150 151 151 151 152 152 152 152 153 153 153 + 150 151 151 152 152 152 153 153 149 148 146 145 9 9 8 8 + 7 7 7 33 34 6 35 5 5 5 5 38 38 153 153 153 + 149 150 150 150 150 151 151 151 152 152 152 153 153 153 153 40 + 147 147 148 148 149 149 149 199 150 151 151 152 152 152 153 153 + 149 49 50 50 50 151 82 152 152 152 152 153 153 153 153 40 + 7 7 7 7 7 33 34 6 6 6 6 37 37 37 153 40 + 147 148 148 148 149 199 150 150 150 151 151 152 152 153 153 202 + 214 213 214 214 197 198 199 144 144 144 194 145 48 53 53 52 + 53 53 53 54 54 54 54 54 51 51 51 82 83 84 153 134 + 130 130 130 34 35 5 153 48 48 150 151 144 145 148 254 48 + 154 40 153 152 152 151 150 199 149 148 148 147 146 145 145 144 + 151 151 151 152 152 153 153 153 153 5 153 153 40 40 40 40 + 6 6 6 6 151 151 152 152 153 153 153 153 153 153 153 154 + 149 150 151 150 147 149 50 51 49 49 49 49 50 83 84 85 + 80 50 50 82 83 83 83 83 84 84 153 153 40 40 40 40 + 150 150 150 151 151 151 151 151 152 153 153 153 153 40 40 153 + 151 152 152 152 37 153 153 40 149 148 147 145 9 9 8 8 + 8 7 33 35 5 5 5 5 5 5 5 38 38 40 40 154 + 150 50 151 151 151 151 152 152 153 153 153 153 153 40 40 154 + 148 148 149 199 150 150 150 150 151 151 152 152 153 153 153 40 + 150 50 50 50 82 83 152 152 152 153 153 153 153 40 40 39 + 7 7 32 33 33 33 6 6 5 5 5 5 5 5 153 154 + 148 148 149 149 199 150 150 150 151 152 152 153 153 40 40 202 + 197 213 214 198 198 200 199 144 144 145 194 145 53 53 53 53 + 53 53 54 54 54 54 55 55 55 51 83 83 84 84 153 134 + 131 131 130 35 35 5 153 48 49 151 152 145 146 148 254 254 + 154 154 153 5 37 36 36 150 149 148 148 147 8 8 9 9 + 152 152 152 152 153 153 153 153 154 40 40 40 39 39 39 39 + 6 6 36 36 6 36 37 153 153 153 153 153 40 40 154 154 + 150 150 151 152 148 49 50 51 49 49 50 50 51 83 84 85 + 82 82 82 82 83 84 84 85 85 85 85 40 40 40 40 40 + 150 151 151 151 152 152 152 153 153 153 153 153 40 40 40 40 + 152 152 153 153 153 38 40 40 150 149 148 146 9 8 8 7 + 7 33 34 6 35 5 5 5 5 4 4 39 39 39 40 154 + 151 50 82 82 152 152 152 152 153 153 153 40 154 154 154 41 + 148 149 149 149 150 150 150 151 151 152 152 153 153 153 40 154 + 150 50 82 82 83 83 84 153 153 153 40 40 40 154 154 154 + 33 33 33 33 33 6 35 5 5 5 5 38 4 39 39 154 + 148 149 199 150 150 150 151 152 152 152 153 153 153 40 154 203 + 196 214 214 198 200 200 200 145 144 145 194 146 48 53 53 58 + 53 54 54 54 54 55 55 55 55 83 83 84 85 85 40 135 + 131 131 131 37 5 4 40 148 49 150 152 145 147 149 80 48 + 155 41 39 4 5 5 37 36 6 33 7 7 7 8 8 8 + 153 153 153 153 153 40 40 40 40 39 39 154 41 41 155 41 + 37 5 5 5 5 5 153 40 40 40 40 154 154 154 154 154 + 151 151 152 153 149 150 51 97 49 50 51 51 83 85 86 87 + 82 83 83 83 84 84 84 85 86 86 88 88 41 41 41 41 + 151 152 152 152 153 153 153 153 153 40 40 39 154 41 41 41 + 153 84 85 40 40 40 154 41 151 150 148 146 8 8 7 7 + 33 6 6 35 5 4 5 4 4 4 39 41 39 41 41 155 + 151 83 83 83 84 153 153 153 40 40 40 154 41 41 155 155 + 149 150 150 150 151 151 151 152 152 153 153 40 39 154 41 41 + 151 82 83 84 84 84 85 85 85 40 154 41 41 41 155 155 + 33 33 34 34 35 35 5 5 5 5 4 4 39 154 41 41 + 149 150 150 151 151 152 152 153 153 153 40 40 154 154 41 155 + 197 198 200 201 200 200 200 144 145 145 195 214 49 54 54 54 + 54 54 54 55 60 55 55 96 96 97 97 98 86 86 41 88 + 133 132 132 38 5 3 41 149 50 152 153 146 148 150 50 254 + 43 3 3 39 4 4 5 5 36 6 6 33 7 7 8 8 + 40 40 40 154 154 41 41 155 41 41 41 155 155 42 42 3 + 5 38 4 4 38 38 39 39 154 154 41 41 155 155 155 155 + 152 152 153 153 151 82 16 17 50 51 83 16 16 18 99 90 + 84 85 85 85 86 86 86 87 90 90 22 91 91 91 91 23 + 152 153 153 153 40 40 40 154 154 154 41 41 155 155 3 42 + 85 86 88 41 41 41 91 91 152 151 149 148 7 7 7 32 + 6 37 5 5 4 4 4 4 4 244 3 3 3 3 43 25 + 152 84 84 84 85 86 86 40 41 41 41 155 155 155 156 156 + 150 151 151 152 152 152 153 153 153 153 39 154 41 155 155 42 + 153 84 84 85 85 86 86 88 89 41 22 42 42 42 156 43 + 34 34 35 35 35 5 5 5 4 4 39 3 3 3 3 156 + 150 151 151 152 152 153 153 153 40 154 154 41 155 155 156 156 + 201 201 202 202 201 201 201 146 147 146 196 214 49 54 54 54 + 54 55 60 55 55 55 97 61 61 98 98 87 90 90 91 137 + 134 133 133 38 4 3 22 150 152 84 18 147 199 150 82 254 + 44 43 3 3 41 39 4 38 5 36 6 6 33 7 7 8 + 40 88 41 41 41 155 155 42 156 42 43 43 43 43 43 43 + 38 4 4 39 4 39 39 41 41 155 3 3 43 43 43 93 + 153 153 40 18 151 83 17 61 51 83 16 17 18 20 22 91 + 85 88 88 88 87 90 90 90 91 23 100 24 24 26 26 26 + 153 154 154 154 154 41 41 155 41 155 155 42 43 43 43 26 + 20 99 22 91 42 92 92 26 153 152 150 7 7 33 33 34 + 35 5 5 5 4 244 4 244 244 244 3 43 43 43 44 101 + 153 85 85 86 86 99 99 99 91 155 42 24 43 43 44 157 + 151 152 152 152 153 153 153 40 39 39 154 41 3 3 43 156 + 153 85 86 86 88 89 90 90 91 91 92 25 26 93 101 2 + 35 35 35 5 5 5 5 4 4 4 3 3 3 43 43 44 + 36 152 152 5 153 153 40 40 154 41 155 155 42 43 93 101 + 202 202 202 201 201 201 153 147 147 147 196 214 49 54 54 54 + 55 60 55 55 60 61 61 61 167 167 168 168 91 91 24 26 + 135 133 134 38 3 43 24 150 83 17 19 148 199 151 83 48 + 157 2 43 3 3 3 39 4 4 5 37 6 6 33 7 7 + 41 22 91 91 91 42 92 24 43 43 43 93 44 2 2 44 + 4 4 4 3 3 3 3 3 3 3 43 43 43 44 44 157 + 153 40 154 99 152 84 98 61 51 83 16 17 20 23 26 246 + 88 167 88 88 90 169 90 91 24 24 26 26 101 101 157 245 + 40 41 41 154 41 155 155 42 42 156 43 43 44 44 30 157 + 21 22 91 92 25 93 27 101 153 152 151 150 33 33 6 35 + 5 5 4 4 244 244 244 244 244 187 2 2 2 2 31 103 + 40 86 86 88 99 22 91 91 24 24 25 101 44 44 157 102 + 152 153 153 153 153 40 40 154 41 41 3 3 43 43 2 30 + 40 86 88 89 90 90 91 91 92 24 26 28 101 30 157 94 + 35 183 184 184 184 184 4 4 244 244 3 43 43 44 2 157 + 5 5 153 153 40 154 154 154 41 155 3 43 43 44 30 157 + 203 203 203 203 203 203 154 7 148 148 199 214 54 55 55 60 + 55 55 55 60 61 61 97 166 167 167 168 169 169 26 26 246 + 88 134 135 39 3 2 246 151 84 19 99 149 6 152 85 48 + 158 102 2 44 43 3 3 39 4 4 5 5 35 6 33 33 + 92 23 24 26 26 26 101 101 101 101 30 157 45 45 45 45 + 4 4 244 3 3 3 43 43 43 44 2 2 2 31 31 45 + 40 41 22 22 153 85 19 61 83 16 19 20 22 26 246 245 + 90 168 168 87 169 170 170 170 246 246 246 245 245 63 63 63 + 41 155 155 155 100 24 24 25 156 93 101 101 157 157 45 103 + 23 23 24 26 28 94 94 139 40 153 152 36 6 6 35 5 + 5 4 4 244 187 187 187 187 187 188 188 188 94 95 95 158 + 154 99 99 22 91 100 24 24 246 27 28 157 45 45 102 158 + 153 40 40 40 154 154 154 155 3 3 43 43 44 2 31 45 + 41 89 90 91 91 24 26 246 26 246 28 157 45 102 102 95 + 184 184 185 185 185 185 186 244 244 244 43 2 2 31 45 102 + 5 153 40 39 154 41 155 155 3 43 44 44 30 45 102 102 + 202 202 203 202 202 202 154 7 7 149 199 200 55 60 96 55 + 55 60 61 61 61 61 61 238 168 169 169 170 170 171 245 172 + 168 135 136 244 2 95 63 152 84 87 22 150 152 153 86 48 + 159 1 102 157 2 43 3 3 244 4 4 5 5 35 34 6 + 26 246 246 245 245 245 245 63 158 103 103 158 158 46 158 158 + 244 244 244 3 3 43 44 44 31 31 45 45 45 102 158 158 + 41 42 24 100 85 19 62 62 17 19 21 62 62 245 63 63 + 169 169 169 169 239 171 171 171 63 63 172 172 172 140 140 173 + 42 24 24 100 26 101 101 101 101 30 157 45 102 158 158 1 + 246 246 246 245 139 103 140 140 41 40 153 37 37 37 5 4 + 4 4 244 187 188 188 188 125 125 125 189 126 126 46 47 159 + 42 23 24 24 26 246 246 246 245 94 139 158 158 46 1 159 + 39 154 154 41 155 155 155 43 43 43 44 2 31 45 95 46 + 91 23 24 26 246 246 246 245 245 245 139 158 1 1 1 47 + 185 185 186 186 186 186 187 187 187 2 2 94 45 95 46 1 + 4 39 154 41 155 155 3 43 44 30 31 45 102 158 1 159 + 156 204 204 204 203 204 156 6 33 150 200 151 55 60 96 55 + 61 61 61 60 61 73 74 238 239 239 239 171 172 172 173 173 + 169 135 137 244 188 95 140 153 85 22 24 36 5 40 90 128 + 79 173 173 139 139 138 25 92 41 41 39 39 38 37 36 36 + 170 239 239 171 171 76 76 77 77 172 172 173 173 78 78 173 + 137 137 93 27 138 138 138 94 94 139 139 172 140 140 173 173 + 90 169 170 170 98 168 238 74 97 61 61 62 62 171 77 77 + 169 238 239 239 75 76 76 76 77 77 77 77 77 77 78 78 + 169 170 170 62 170 171 246 171 171 63 63 172 173 173 78 78 + 171 239 171 171 172 173 77 77 90 88 84 84 37 38 38 39 + 39 3 3 93 94 94 94 47 189 189 46 140 140 141 141 79 + 169 62 170 170 170 171 171 171 171 171 172 173 173 173 173 79 + 41 22 22 41 91 91 91 25 27 138 94 139 139 140 140 173 + 169 169 170 239 239 239 75 76 76 76 77 77 173 78 78 79 + 244 244 244 244 244 244 93 138 138 94 139 139 140 140 173 79 + 40 41 155 23 23 100 26 246 245 63 63 63 172 173 78 78 + 23 204 205 205 205 23 100 150 149 151 152 16 60 60 61 61 + 61 61 61 237 72 72 72 73 73 74 74 75 76 76 77 77 + 169 167 170 137 95 140 78 85 167 169 170 152 40 88 168 160 + 85 84 133 132 131 131 130 129 129 129 129 128 253 106 253 105 + 162 163 163 163 163 163 164 164 164 164 164 164 165 165 165 165 + 130 130 130 130 130 131 131 131 132 132 132 132 133 133 133 133 + 255 161 162 162 160 104 161 249 53 104 54 104 162 164 164 164 + 161 162 162 162 162 163 163 163 164 164 164 164 164 165 165 165 + 161 162 162 162 162 162 163 163 163 163 164 164 164 164 165 166 + 163 163 163 163 164 164 165 165 104 160 105 105 106 144 253 128 + 128 129 129 130 131 131 131 132 132 132 132 133 134 134 134 165 + 255 161 162 162 162 163 163 163 163 164 164 164 84 84 85 85 + 128 129 254 254 254 129 130 130 131 131 131 131 132 132 133 133 + 255 161 162 162 162 162 163 163 163 164 164 164 165 165 165 165 + 129 129 129 129 129 129 130 130 131 131 132 132 132 133 133 134 + 128 48 254 254 254 49 49 50 50 51 97 83 84 83 165 98 + 147 214 214 54 49 80 49 106 105 105 52 52 52 52 53 53 + 53 53 58 53 64 64 65 64 65 65 250 163 164 164 165 165 + 162 255 131 132 133 133 164 160 160 161 162 105 253 128 161 160 + 166 166 165 164 163 163 131 130 255 255 255 104 48 105 105 105 + 250 250 250 250 250 250 250 164 165 165 165 165 165 166 166 165 + 162 131 131 131 131 132 132 132 132 132 133 133 133 134 134 165 + 161 162 162 163 160 104 249 250 104 104 249 249 250 250 164 69 + 162 162 163 250 250 250 250 164 164 165 165 165 165 165 165 69 + 161 64 65 65 162 163 250 250 250 250 164 164 165 165 165 166 + 163 250 250 164 164 165 165 165 161 160 160 105 105 253 48 128 + 129 254 130 131 82 132 132 133 133 133 133 134 165 166 166 166 + 161 64 249 249 249 250 250 250 250 164 164 165 165 165 166 166 + 255 254 255 255 130 130 131 131 131 131 132 164 133 133 134 165 + 162 64 65 65 65 66 250 250 67 68 165 165 165 166 166 166 + 255 129 255 255 255 255 130 131 131 132 132 133 133 133 134 135 + 128 254 49 49 49 80 50 51 51 55 96 96 165 165 166 61 + 49 214 214 54 49 54 80 105 105 105 52 53 57 57 57 57 + 53 58 249 249 64 65 65 65 65 66 66 67 67 165 165 165 + 162 255 131 132 133 165 165 160 160 64 162 105 160 160 162 160 + 167 166 165 164 164 164 132 131 255 255 255 255 104 48 105 105 + 163 250 250 250 164 165 165 165 166 165 166 166 166 166 166 166 + 163 131 163 163 163 164 164 164 165 165 84 165 166 166 166 166 + 162 162 250 250 104 249 250 250 249 104 249 250 250 250 164 70 + 163 250 250 250 250 164 68 165 165 165 166 166 166 166 166 166 + 162 162 250 250 250 250 250 164 165 165 165 165 166 166 166 166 + 164 164 164 165 165 165 166 166 162 161 104 160 48 48 254 254 + 254 130 131 81 83 133 133 133 134 134 135 166 166 167 167 167 + 162 249 250 250 250 250 250 250 165 165 165 166 166 166 167 167 + 255 254 255 130 130 131 163 132 132 132 133 165 165 166 166 166 + 162 163 250 250 250 250 250 68 68 165 165 166 166 166 167 167 + 255 129 130 130 130 131 131 163 132 133 133 165 134 134 135 167 + 254 254 49 80 50 51 51 55 55 96 97 96 166 165 166 61 + 49 214 55 55 55 55 96 105 105 105 53 53 57 57 57 58 + 58 58 249 66 64 66 65 66 66 66 235 68 68 69 166 166 + 163 162 131 132 134 166 166 160 64 65 163 105 104 255 162 160 + 168 167 166 165 165 133 132 131 131 130 255 255 104 48 48 105 + 164 164 165 165 165 165 166 166 166 166 166 166 166 166 167 167 + 163 163 163 164 164 164 165 165 165 165 166 166 166 166 166 166 + 162 250 250 250 161 249 250 68 64 249 250 250 250 165 166 70 + 163 250 250 250 164 164 165 165 69 166 166 70 70 70 70 166 + 163 250 250 250 250 165 165 165 166 165 166 166 166 166 167 167 + 165 165 69 69 166 166 166 70 162 161 104 104 48 48 254 254 + 254 80 131 82 133 133 133 134 135 135 135 167 167 167 168 168 + 163 250 250 250 250 250 68 165 165 166 166 166 167 167 167 168 + 254 254 80 81 81 81 82 82 164 133 165 165 166 166 167 167 + 163 250 250 250 250 164 68 165 165 166 166 166 166 167 167 168 + 255 130 131 131 131 131 132 164 133 133 165 165 135 166 167 167 + 254 49 80 50 51 51 55 96 96 97 61 97 166 166 167 61 + 150 214 201 55 60 51 82 106 48 53 52 53 53 57 58 58 + 58 58 249 249 66 235 66 235 235 235 68 69 69 70 70 237 + 164 162 132 133 135 167 166 104 64 250 164 105 255 255 162 160 + 169 167 166 166 165 133 133 132 132 131 130 130 254 48 48 48 + 166 166 166 166 166 166 166 166 166 167 167 237 168 168 168 168 + 164 164 164 165 165 165 165 166 166 166 167 167 167 167 167 167 + 163 250 250 68 162 250 250 68 104 250 250 250 250 166 70 70 + 250 250 164 165 69 69 166 166 70 70 237 237 237 237 237 237 + 164 164 164 165 165 165 165 165 166 166 166 166 167 237 237 237 + 166 69 69 70 166 237 237 237 163 162 161 104 48 254 254 254 + 130 131 132 83 84 84 134 135 135 86 88 167 167 168 168 238 + 163 164 164 164 164 165 165 165 166 166 237 237 237 237 168 238 + 49 80 81 82 82 82 83 133 165 165 165 166 166 167 167 168 + 164 164 164 165 165 69 69 166 166 70 237 237 168 168 168 168 + 130 130 131 132 132 132 132 133 165 165 166 166 167 167 167 168 + 254 80 50 51 51 51 96 96 97 61 61 61 61 167 168 168 + 201 200 201 55 55 51 83 105 48 48 53 53 58 58 58 59 + 59 58 249 66 235 66 234 234 234 69 69 236 70 70 237 237 + 164 163 133 134 135 167 167 161 249 250 165 160 255 162 163 160 + 169 169 167 167 135 135 133 133 132 131 131 80 254 254 48 48 + 166 166 166 166 166 167 237 167 167 167 168 168 168 238 238 238 + 164 165 165 165 165 165 166 167 166 167 167 167 167 167 168 168 + 164 165 165 69 250 250 250 68 249 250 250 250 165 165 166 237 + 164 165 165 69 236 70 70 237 237 237 237 237 237 71 72 238 + 165 165 165 165 166 166 166 166 166 167 167 167 168 168 238 238 + 166 70 70 70 237 237 238 72 164 162 161 255 254 254 130 130 + 131 132 133 84 85 85 135 86 88 89 90 168 168 168 169 238 + 164 164 165 165 165 166 166 70 70 237 237 237 237 238 238 238 + 80 50 82 82 82 83 84 165 165 166 166 166 167 167 168 238 + 164 164 165 165 166 166 70 70 237 237 237 168 238 238 238 238 + 131 131 132 132 133 133 133 134 135 166 167 167 167 168 168 169 + 49 50 51 83 83 96 97 97 61 61 61 61 168 168 238 238 + 202 201 202 16 16 16 97 48 48 48 53 58 58 58 58 59 + 58 249 67 67 234 66 234 234 69 236 70 70 70 237 237 71 + 164 164 134 135 135 168 237 162 249 250 166 104 130 81 164 160 + 170 169 168 168 167 135 134 134 133 132 82 81 130 254 254 48 + 166 166 166 166 167 168 168 168 168 168 238 238 238 238 238 169 + 165 165 166 166 166 166 167 167 167 167 168 168 168 168 169 169 + 96 165 166 166 250 250 250 236 250 250 60 165 70 237 237 238 + 165 165 236 70 70 237 237 237 237 237 237 238 238 238 238 238 + 165 166 166 166 166 166 167 167 167 167 168 168 238 238 238 238 + 166 237 70 237 237 238 238 73 164 163 162 80 254 254 130 131 + 132 133 84 85 86 88 88 89 90 90 169 169 169 169 170 238 + 165 165 165 166 166 166 237 237 237 237 237 238 238 238 238 74 + 82 82 82 83 83 84 84 85 166 167 167 167 167 168 169 238 + 165 165 165 166 70 237 237 237 237 237 168 238 238 238 239 239 + 132 132 132 133 133 134 135 135 166 167 167 168 168 169 169 239 + 50 51 83 83 16 16 17 61 61 61 168 61 238 168 238 239 + 201 201 201 202 16 16 97 48 48 48 54 54 59 59 59 58 + 59 59 68 68 68 235 234 69 236 70 70 71 71 71 72 73 + 166 165 166 135 136 169 238 162 250 165 166 255 130 82 165 160 + 170 169 168 168 168 86 135 85 84 133 83 82 80 130 254 48 + 167 61 167 167 168 168 238 238 238 238 238 238 238 238 238 239 + 166 166 167 167 167 167 167 168 168 168 169 169 169 169 169 239 + 165 166 61 237 96 165 166 70 250 60 60 96 166 72 238 238 + 166 166 70 237 237 237 237 71 238 238 238 238 238 238 238 238 + 166 166 167 167 167 167 167 167 167 168 238 238 238 238 238 238 + 167 237 237 237 238 238 238 74 165 163 162 80 254 254 130 131 + 37 153 40 40 41 41 41 91 91 91 137 170 170 170 170 239 + 165 165 166 166 167 167 237 237 237 238 238 238 238 238 238 239 + 83 83 83 84 98 98 98 85 98 167 168 168 168 168 169 239 + 166 166 166 237 237 237 237 237 168 238 238 238 238 239 239 239 + 132 132 133 133 134 135 135 135 135 167 168 168 169 169 169 239 + 82 83 83 83 16 17 61 61 61 61 62 168 169 169 239 239 + 202 203 202 202 16 17 84 48 48 49 54 54 59 59 59 58 + 59 60 250 68 67 69 69 236 70 70 71 71 71 72 238 73 + 70 165 167 88 136 169 238 162 164 165 167 254 131 133 165 160 + 239 239 170 169 169 90 88 85 84 133 132 131 131 130 254 254 + 98 168 168 169 238 238 238 238 239 239 238 238 239 239 239 239 + 135 86 88 87 136 168 136 168 136 169 169 169 169 170 170 239 + 97 61 61 61 96 165 61 237 96 60 60 166 61 168 238 238 + 166 166 237 237 237 237 238 238 238 238 238 238 239 239 239 239 + 167 167 167 167 167 168 168 168 169 169 169 239 239 239 239 239 + 168 168 238 238 169 239 239 239 165 164 163 80 130 130 131 36 + 37 38 40 41 42 42 42 92 25 26 246 246 246 171 171 239 + 166 166 166 167 168 168 168 168 238 238 238 238 239 239 239 75 + 84 84 84 85 98 98 98 88 88 87 168 168 169 169 239 239 + 166 166 237 237 237 237 237 168 238 238 238 239 239 239 239 171 + 133 133 38 134 134 135 135 88 136 136 169 169 169 170 170 239 + 82 83 16 16 16 17 19 61 61 62 62 169 62 239 239 76 + 202 202 203 203 19 19 18 48 48 49 54 54 59 59 59 59 + 250 60 250 68 69 236 69 71 70 70 71 72 73 74 74 74 + 237 165 167 135 137 169 74 163 165 166 168 130 131 133 166 160 + 76 171 170 170 169 90 87 86 85 84 132 132 131 130 130 254 + 90 168 169 169 169 169 239 239 239 239 239 239 239 75 75 239 + 135 88 136 136 136 90 90 137 137 169 170 170 170 171 171 171 + 97 61 61 168 96 97 61 237 96 60 61 61 168 238 239 239 + 167 237 237 168 168 238 238 238 238 239 239 239 239 239 75 75 + 87 87 87 87 168 168 168 168 169 62 239 239 239 239 171 75 + 169 238 238 238 239 239 239 75 166 165 164 81 131 131 132 37 + 38 38 39 155 42 42 43 43 93 27 246 246 171 171 171 76 + 167 167 167 168 168 169 169 169 169 238 239 239 239 75 76 76 + 84 153 85 18 86 18 86 87 90 90 169 169 170 170 171 75 + 167 167 167 237 237 238 238 238 238 238 239 239 239 239 171 171 + 37 38 38 38 135 135 136 136 137 137 137 170 170 170 171 76 + 83 16 16 17 18 19 20 21 21 62 62 62 170 171 171 77 + 202 203 203 203 19 19 19 48 49 49 49 54 59 59 59 60 + 59 60 60 68 70 70 70 70 237 71 72 73 74 74 75 75 + 237 166 167 136 170 170 75 164 166 166 168 130 132 84 166 160 + 77 77 171 246 170 23 90 89 86 85 133 152 132 151 150 149 + 169 62 62 62 62 239 239 75 239 239 171 171 76 76 76 171 + 88 136 136 91 137 137 137 137 170 246 246 246 171 171 171 171 + 98 87 169 62 97 61 61 72 96 61 61 61 168 239 239 75 + 168 168 238 238 238 238 239 239 239 239 239 75 171 76 76 76 + 90 90 90 90 90 169 169 62 170 170 171 171 171 171 171 76 + 169 239 239 239 239 171 76 76 167 165 83 132 132 37 37 37 + 38 4 41 3 43 43 44 2 44 29 94 139 172 172 173 77 + 136 168 168 168 169 169 169 170 170 239 239 171 76 76 77 77 + 85 40 18 19 88 20 87 90 22 23 62 170 171 171 63 76 + 168 168 168 168 238 238 238 239 239 239 239 75 171 76 77 172 + 38 38 38 4 39 41 136 136 137 137 138 246 171 171 171 172 + 153 17 18 19 20 20 21 21 23 62 62 246 245 63 63 77 + 20 203 203 203 20 20 21 254 149 50 54 55 60 60 60 60 + 55 60 70 250 70 237 71 71 71 72 73 74 74 75 75 75 + 237 166 168 136 171 171 75 164 166 166 169 131 132 84 167 160 + 78 173 172 245 246 26 100 91 41 40 40 153 37 37 36 150 + 62 62 62 170 170 170 171 76 171 171 171 172 77 77 77 172 + 136 91 91 92 137 26 138 246 246 246 171 171 139 172 172 172 + 99 21 62 62 17 98 168 238 97 61 61 61 62 239 171 76 + 168 238 238 238 238 239 239 75 76 76 76 76 77 77 77 77 + 91 22 23 23 62 62 246 246 246 171 171 171 172 172 172 77 + 170 239 239 239 171 172 172 77 167 85 133 132 37 37 38 38 + 4 39 3 3 43 2 2 31 31 94 103 103 140 173 173 78 + 136 136 169 169 169 169 170 171 171 171 171 172 172 77 173 78 + 40 154 41 99 99 21 22 23 23 24 246 246 245 63 172 77 + 168 168 169 238 238 238 239 239 239 75 76 76 77 77 77 173 + 4 4 4 244 244 244 244 137 27 138 138 139 139 139 172 173 + 85 18 20 20 21 21 23 23 23 246 246 245 63 172 172 173 + 204 204 203 203 204 21 23 150 149 50 55 55 60 60 55 55 + 60 60 61 166 237 71 72 71 73 73 74 75 75 76 76 76 + 238 167 169 137 139 171 76 165 166 167 169 131 133 85 167 128 + 79 173 172 139 157 101 26 92 41 41 39 38 38 37 36 36 + 26 246 246 245 245 171 63 172 172 172 172 173 173 173 173 173 + 42 92 92 26 27 28 138 157 139 139 139 139 172 172 140 172 + 22 23 62 62 18 87 62 62 97 61 61 62 62 171 77 77 + 169 238 238 239 239 239 75 76 76 77 77 77 173 173 173 173 + 91 23 24 246 246 246 246 246 245 171 63 172 172 173 173 78 + 171 171 171 171 172 172 173 173 136 86 133 132 37 5 38 4 + 4 244 244 43 2 188 125 125 95 95 158 46 1 173 141 79 + 137 137 137 137 170 170 171 171 171 172 172 172 173 173 173 79 + 40 41 41 22 22 23 23 24 24 246 246 245 63 172 140 173 + 169 169 169 239 239 239 239 239 76 76 77 77 173 173 173 141 + 244 186 186 244 244 244 43 93 93 29 94 139 139 140 140 173 + 40 154 99 21 22 23 100 24 246 245 245 63 172 140 173 79 + 205 204 204 204 204 205 24 150 150 152 83 55 55 55 60 60 + 61 61 61 71 71 72 72 73 73 74 75 75 76 76 77 77 + 238 167 137 137 139 139 77 85 167 168 170 132 133 86 168 128 + 174 141 140 103 45 157 28 43 3 41 39 39 38 38 37 36 + 101 245 63 63 63 63 172 172 172 173 173 173 173 173 79 79 + 25 93 28 28 28 30 157 103 103 103 158 158 140 173 173 173 + 23 24 246 246 19 90 62 239 98 61 62 62 239 63 77 78 + 169 239 239 75 75 75 76 76 77 77 173 173 78 78 79 79 + 24 26 246 246 246 245 245 245 63 63 172 172 173 173 173 79 + 171 171 76 172 172 173 173 79 137 136 135 37 37 5 4 4 + 244 244 187 188 188 125 126 126 126 126 127 127 159 141 141 79 + 137 137 137 246 246 171 171 172 172 173 173 173 173 141 174 174 + 41 41 155 42 100 24 26 26 246 246 245 63 172 140 173 79 + 170 170 170 239 239 171 76 77 77 77 173 78 79 79 174 174 + 244 186 187 187 187 187 188 188 29 94 103 140 140 140 141 174 + 41 41 22 23 100 26 246 246 245 63 63 63 173 173 173 142 + 205 205 204 204 204 205 26 151 150 152 16 96 60 60 60 61 + 61 61 61 73 72 73 73 73 74 75 75 76 77 77 78 78 + 239 168 170 93 189 140 78 86 167 169 171 37 153 89 168 128 + 142 142 141 46 103 45 29 93 3 3 39 4 4 5 5 37 + 245 63 63 140 140 173 173 173 173 173 141 79 79 174 174 142 + 44 44 30 31 157 45 103 158 158 1 1 1 141 141 141 141 + 25 101 245 245 99 23 62 239 19 62 62 62 63 77 173 78 + 239 239 75 75 76 76 77 77 78 78 78 79 79 174 174 174 + 246 246 246 245 139 63 63 172 172 173 173 173 173 79 79 79 + 172 63 77 77 173 79 174 174 137 136 135 38 5 5 4 4 + 244 244 188 188 125 126 126 126 126 127 127 127 141 142 142 174 + 138 138 138 246 171 172 172 172 173 173 173 141 174 142 142 175 + 41 42 92 92 24 26 101 101 245 63 172 140 140 141 174 174 + 170 239 171 171 171 76 77 77 77 173 79 79 174 174 142 175 + 187 186 187 187 187 188 188 188 94 189 46 1 1 47 142 175 + 41 155 42 24 26 101 245 245 63 140 63 1 141 141 174 175 + 205 205 205 205 205 205 101 151 150 152 16 16 61 61 61 61 + 61 61 61 74 73 74 74 74 75 75 76 77 78 78 79 78 + 239 169 138 29 190 47 79 86 90 62 63 153 40 91 169 128 + 191 191 190 190 189 189 188 187 186 186 185 185 184 184 5 5 + 189 158 189 46 46 46 190 190 190 190 190 190 190 190 191 191 + 188 188 188 188 188 189 189 189 189 189 190 190 190 190 190 190 + 187 2 94 94 41 92 246 63 20 23 62 246 245 172 140 79 + 171 171 171 172 172 172 173 173 141 141 141 141 141 191 191 191 + 2 188 94 94 189 189 189 189 189 189 190 190 190 190 191 191 + 139 139 139 140 190 190 191 175 244 244 39 38 5 184 185 185 + 186 187 187 188 125 126 126 126 126 190 190 190 190 191 191 191 + 188 188 188 188 188 189 189 189 189 190 190 190 190 191 191 191 + 244 244 244 244 187 188 188 188 188 189 189 189 189 190 190 191 + 138 138 139 139 139 140 140 140 140 141 141 191 191 191 191 191 + 186 186 186 187 187 187 188 188 188 189 189 126 126 190 190 191 + 3 3 3 43 43 2 94 94 189 189 189 189 190 190 190 143 + 2 157 206 205 101 156 157 36 37 37 152 16 17 61 17 61 + 61 61 62 238 239 239 76 239 76 76 77 173 141 141 191 174 + 170 137 188 188 189 190 174 40 23 246 140 38 4 3 137 128 + 181 181 181 180 179 179 179 178 178 177 177 176 109 109 109 108 + 179 180 180 180 180 180 180 180 181 181 181 181 181 181 181 181 + 178 178 179 179 179 179 179 179 180 180 180 180 180 180 181 181 + 178 179 179 180 110 10 9 7 10 9 9 9 9 32 180 182 + 8 8 9 8 32 32 32 181 181 181 181 181 181 181 181 181 + 179 179 179 179 179 179 179 180 180 180 180 180 181 181 181 181 + 181 180 180 180 180 180 181 182 112 9 112 110 109 177 176 176 + 177 177 178 178 179 179 179 180 180 180 180 181 181 181 181 181 + 179 179 179 179 179 179 179 180 180 180 180 180 181 181 181 182 + 111 110 110 111 178 179 179 179 179 179 179 180 181 181 181 181 + 179 179 179 180 180 180 180 180 181 181 181 181 181 181 181 181 + 177 177 177 177 178 178 178 179 179 179 179 180 180 181 181 181 + 111 111 111 110 111 112 113 180 180 180 180 181 181 181 181 114 + 113 113 113 113 113 113 113 108 108 12 12 11 10 10 106 106 + 144 144 144 253 253 8 9 9 9 8 32 32 181 181 181 181 + 32 9 179 181 178 180 182 11 9 8 32 109 110 111 8 128 + 181 181 181 180 179 179 179 178 178 176 177 177 177 110 110 110 + 180 180 180 180 180 180 181 180 180 180 180 181 181 181 181 181 + 178 178 179 179 179 179 179 179 179 180 180 180 180 181 181 181 + 179 179 179 180 111 112 8 32 9 9 9 9 8 181 181 182 + 112 8 8 8 181 181 181 181 181 181 181 181 181 182 182 182 + 179 179 179 179 180 180 180 180 180 180 180 180 181 181 181 181 + 180 180 180 180 180 181 181 182 113 112 111 110 109 176 176 176 + 177 178 178 178 179 179 179 180 180 180 180 181 181 181 181 181 + 179 178 178 179 179 180 180 179 180 180 180 181 181 181 182 182 + 110 111 178 179 179 178 178 178 179 179 179 180 180 181 181 181 + 179 179 179 180 180 180 181 181 181 180 181 181 181 181 182 182 + 177 177 177 177 178 178 178 179 179 179 179 180 180 181 181 181 + 110 111 111 112 113 113 179 180 180 180 180 180 181 181 181 181 + 113 113 113 112 111 112 113 109 109 109 11 11 10 10 10 10 + 106 106 9 9 9 9 9 9 8 32 181 181 181 181 181 182 + 32 9 179 181 179 180 182 11 9 8 32 109 110 111 8 128 + 182 181 181 181 180 180 179 178 178 178 177 178 176 111 110 109 + 181 180 180 180 181 181 181 181 181 181 181 182 182 182 182 182 + 179 179 179 179 179 180 180 180 180 180 181 181 181 181 181 182 + 179 180 180 181 112 112 8 32 9 9 8 9 32 180 182 182 + 8 32 32 32 32 181 181 181 182 182 181 181 181 182 182 182 + 180 180 180 180 180 180 180 180 181 181 181 181 181 182 182 182 + 180 180 180 181 181 181 182 182 113 112 111 110 176 176 177 177 + 177 178 178 179 180 180 180 180 180 181 181 181 181 182 182 182 + 179 179 180 180 180 180 180 181 181 181 181 181 182 182 182 182 + 111 113 180 180 179 179 179 180 180 180 180 181 181 181 182 182 + 180 180 180 180 180 181 181 181 182 181 181 181 182 182 182 182 + 177 177 178 178 178 179 179 179 180 180 180 181 181 181 182 182 + 111 112 112 113 113 180 181 180 181 180 180 181 181 182 182 182 + 114 113 113 113 113 113 113 110 109 110 10 10 10 10 10 144 + 144 253 253 128 8 8 8 8 32 32 32 181 181 182 182 182 + 32 8 179 180 180 181 182 10 9 8 32 110 111 112 8 128 + 183 182 182 181 180 180 180 179 178 179 178 178 176 111 110 110 + 181 181 181 181 181 182 182 182 182 182 182 182 182 182 182 182 + 180 180 180 180 180 181 181 181 181 181 182 182 182 182 182 182 + 179 180 181 181 112 9 8 33 8 8 8 8 32 181 182 182 + 32 32 32 32 32 32 181 182 182 182 182 182 182 182 182 182 + 181 181 180 180 180 181 181 181 181 182 182 182 182 182 182 182 + 181 181 181 181 182 182 182 182 113 112 112 111 111 176 177 178 + 178 179 179 180 180 181 180 181 181 181 182 182 182 182 182 183 + 180 180 181 181 180 180 181 182 182 181 182 182 182 182 183 183 + 112 113 180 180 180 180 181 181 180 181 181 181 182 182 182 182 + 181 181 181 181 181 181 181 181 182 182 182 182 182 182 183 183 + 178 178 178 179 179 179 180 180 180 181 181 181 182 182 182 183 + 113 113 112 113 113 181 181 181 180 180 181 181 182 182 182 182 + 114 114 114 113 113 114 114 110 110 110 10 10 10 144 144 145 + 253 146 128 129 128 128 7 7 33 33 33 33 182 182 182 183 + 32 8 179 180 181 182 183 9 8 8 32 110 111 113 129 128 + 183 183 182 182 181 181 181 180 180 178 179 179 180 110 110 111 + 32 181 181 182 182 183 183 182 182 182 183 183 183 183 183 183 + 180 180 181 181 181 181 181 182 182 182 182 182 182 182 183 183 + 32 32 32 32 8 7 32 33 8 7 8 32 32 182 183 183 + 32 33 32 32 33 34 182 183 182 183 183 183 183 183 183 183 + 181 181 180 181 181 181 182 182 182 182 182 183 183 183 183 183 + 33 33 182 182 183 183 183 183 8 9 9 110 110 176 178 178 + 179 180 180 180 181 181 181 182 182 182 182 182 183 183 183 183 + 181 180 180 181 181 182 182 182 182 182 182 183 183 183 183 184 + 112 113 181 181 181 181 181 180 181 182 182 182 182 183 183 183 + 180 32 32 32 32 33 182 182 182 182 183 183 183 183 183 184 + 179 178 179 179 180 180 180 181 181 181 182 182 182 183 183 183 + 112 112 8 8 32 32 32 32 32 181 182 182 183 183 183 183 + 114 114 113 114 114 114 114 110 110 10 10 9 144 145 145 145 + 48 48 254 254 129 129 130 130 131 34 34 34 183 183 183 183 + 129 128 179 179 182 182 183 9 8 7 33 110 112 8 129 128 + 183 183 183 182 182 182 182 181 181 179 180 180 180 111 111 111 + 33 33 33 182 183 183 183 183 183 183 183 183 183 183 183 184 + 181 181 181 181 182 182 182 182 182 182 182 182 183 183 183 184 + 32 33 32 33 8 7 33 34 8 7 8 33 33 35 183 184 + 33 33 33 33 35 35 34 35 183 183 183 183 183 183 183 183 + 32 32 32 33 182 182 183 183 183 183 183 183 183 183 183 184 + 34 34 182 183 183 183 184 184 32 8 9 111 111 178 179 178 + 180 180 181 181 181 182 182 182 182 183 183 183 183 183 183 184 + 181 181 32 32 182 182 183 183 183 183 183 183 183 183 184 184 + 113 32 32 32 32 32 181 181 181 182 183 183 183 183 183 183 + 32 32 33 33 34 34 35 35 182 183 184 184 183 183 184 184 + 179 179 180 180 180 181 181 181 182 182 182 182 183 183 183 184 + 112 8 32 32 32 32 32 32 33 34 183 183 183 183 183 184 + 114 114 114 114 114 32 32 110 10 10 9 9 145 146 146 146 + 48 48 48 254 254 130 130 131 131 131 34 34 35 183 184 184 + 130 129 180 181 183 183 183 9 8 33 35 10 112 8 129 128 + 184 184 183 183 183 182 182 181 180 181 180 180 112 112 112 110 + 34 35 35 35 183 184 184 184 184 184 184 184 184 184 184 184 + 182 182 182 182 182 182 183 183 183 183 183 183 183 184 184 184 + 32 34 34 35 8 7 33 35 148 7 33 34 35 35 183 184 + 34 35 35 35 35 35 35 35 5 184 184 184 184 184 184 184 + 33 34 34 34 34 34 183 183 183 183 183 184 184 184 184 184 + 34 35 183 183 184 184 184 185 33 32 8 112 112 179 179 179 + 180 181 181 181 182 182 182 183 183 183 184 184 184 184 184 185 + 32 33 34 34 33 34 183 183 183 183 183 184 184 184 184 185 + 32 32 32 32 32 32 32 33 32 183 183 183 183 183 184 184 + 33 34 34 35 35 35 35 35 183 184 184 184 184 184 184 184 + 180 180 180 181 181 181 182 182 182 182 183 183 183 184 184 184 + 32 32 33 33 32 32 33 34 34 35 183 184 184 184 184 184 + 6 6 33 33 33 33 34 10 10 9 9 145 145 146 147 147 + 48 48 254 254 130 131 131 132 132 132 36 35 35 184 184 185 + 131 130 33 182 184 184 184 8 32 33 35 9 8 32 130 128 + 186 185 184 184 183 183 182 181 180 180 181 32 112 112 9 112 + 35 35 35 35 5 184 185 185 184 184 184 185 184 185 185 185 + 182 182 182 182 182 183 183 183 184 184 184 184 184 184 184 185 + 33 6 34 37 7 6 35 35 7 148 36 34 37 5 5 185 + 34 35 35 35 37 5 5 4 5 5 184 184 185 185 185 185 + 34 35 35 35 34 35 183 184 184 184 184 184 184 185 185 185 + 35 5 5 184 185 185 185 185 34 32 8 8 112 180 180 181 + 181 181 182 182 183 183 183 183 183 184 184 184 185 185 185 185 + 34 34 34 34 35 35 35 35 184 184 184 184 185 185 185 185 + 33 32 32 33 33 33 33 34 34 183 184 184 184 184 185 185 + 33 34 35 37 37 5 5 5 5 184 184 184 185 185 185 185 + 180 180 181 181 181 182 182 182 183 183 183 184 184 184 184 185 + 32 32 32 33 34 35 35 34 35 35 5 184 184 185 185 185 + 33 6 6 33 33 33 34 10 9 8 8 146 146 147 148 148 + 49 49 49 80 81 132 132 132 132 132 133 37 38 185 185 185 + 131 131 34 182 184 184 185 8 32 34 37 9 7 33 130 128 + 186 186 185 184 184 184 183 183 181 32 32 32 32 8 9 9 + 5 38 38 38 5 185 185 185 185 185 186 185 185 185 185 185 + 182 183 183 183 183 183 184 184 184 184 184 184 184 185 185 186 + 35 35 35 5 33 36 35 37 149 130 34 36 37 38 4 244 + 35 37 37 38 38 38 38 38 4 4 4 185 185 186 185 185 + 35 35 35 35 5 5 184 185 184 185 185 185 185 185 185 186 + 5 5 38 184 185 186 186 186 34 33 32 8 113 181 181 180 + 181 182 182 183 183 183 184 184 184 184 185 185 185 185 185 186 + 34 35 35 5 5 5 4 185 184 185 185 185 185 185 186 186 + 32 33 33 34 34 35 35 35 35 5 184 184 185 185 185 185 + 34 36 37 37 5 38 38 4 38 185 185 185 186 186 186 186 + 181 181 181 182 182 182 182 183 183 183 184 184 184 185 185 186 + 32 33 33 34 35 35 5 5 5 5 5 185 185 185 185 186 + 6 200 6 36 6 35 35 9 8 8 8 146 147 149 149 149 + 49 80 50 82 82 132 132 133 133 134 134 38 38 185 186 244 + 37 131 5 183 185 185 185 32 33 35 37 8 33 33 131 128 + 187 186 185 185 185 184 184 183 34 33 33 33 32 32 8 8 + 5 38 4 4 4 4 185 185 186 186 186 186 186 186 186 186 + 183 183 184 184 184 184 184 185 185 185 185 185 186 186 186 186 + 35 37 5 5 34 36 37 38 130 131 36 37 38 39 39 244 + 38 38 38 38 38 39 39 41 41 3 244 244 244 186 186 187 + 5 38 38 5 5 38 4 185 185 185 185 186 186 186 186 186 + 38 4 4 4 185 186 186 244 35 34 33 32 8 181 181 181 + 182 182 183 183 184 184 184 185 185 185 186 186 186 186 186 187 + 35 5 5 5 5 38 4 4 185 185 186 186 186 186 186 187 + 33 34 34 35 35 35 5 5 5 5 185 185 185 186 186 186 + 5 5 38 38 38 4 4 4 4 185 185 186 186 187 187 186 + 182 182 182 182 183 183 183 184 184 184 185 185 185 186 186 186 + 33 33 35 35 5 5 5 5 38 4 4 244 186 186 186 187 + 152 201 200 153 37 5 5 9 8 8 8 147 147 149 149 49 + 50 50 50 82 133 133 133 133 134 135 135 39 39 244 186 244 + 134 132 38 184 186 122 187 34 34 5 38 8 33 6 132 128 + 188 187 186 186 185 185 184 184 35 34 34 33 33 32 32 8 + 4 39 39 4 4 244 244 186 186 186 187 187 187 187 187 187 + 184 184 184 185 185 185 185 185 186 186 186 186 186 187 187 187 + 5 5 38 4 36 37 38 135 131 151 37 38 40 41 3 43 + 135 135 135 135 88 41 91 42 42 42 3 244 187 187 187 187 + 38 38 38 4 4 4 4 185 185 185 186 187 187 187 187 187 + 4 39 39 244 244 187 187 187 5 34 34 32 32 181 181 182 + 183 183 183 184 184 185 185 186 186 186 186 186 187 187 187 188 + 5 38 38 4 4 4 4 4 185 186 186 187 187 187 187 187 + 34 35 35 5 5 5 5 38 4 4 185 186 186 186 186 187 + 38 38 39 39 39 39 41 244 244 244 186 186 187 187 187 187 + 182 183 183 183 183 183 183 184 184 185 185 186 186 186 187 187 + 34 35 35 5 5 38 4 4 4 4 244 244 244 186 187 2 + 201 202 201 153 153 4 4 8 8 8 148 148 148 149 150 50 + 50 50 82 84 165 166 166 134 135 136 136 137 244 244 187 2 + 134 132 38 184 185 122 187 33 35 38 38 7 6 35 133 128 + 188 188 187 187 186 186 185 184 5 35 35 34 33 33 32 32 + 41 3 3 244 244 244 244 244 244 187 187 187 187 187 187 187 + 185 185 185 185 185 186 186 186 186 186 187 187 187 187 187 187 + 38 4 4 4 37 38 39 136 152 83 134 40 41 155 43 93 + 135 135 136 136 91 137 137 92 92 92 43 93 2 188 188 188 + 38 4 39 39 39 244 244 244 244 244 244 187 187 187 188 188 + 3 155 244 244 244 187 188 188 38 35 35 34 32 32 181 183 + 183 184 184 184 185 185 186 186 186 186 186 187 187 188 188 188 + 38 38 4 39 39 41 3 244 244 244 187 187 187 187 188 188 + 35 5 5 5 38 4 4 4 4 4 244 244 244 187 187 188 + 38 39 39 41 41 41 42 92 244 244 187 187 188 188 188 188 + 183 183 183 183 184 184 184 185 185 185 186 186 187 187 187 188 + 35 5 5 38 4 4 4 39 41 3 3 3 244 187 187 31 + 202 202 202 202 153 154 39 8 7 7 149 149 150 150 50 51 + 51 51 83 97 166 166 166 167 168 168 137 137 27 93 2 29 + 135 133 4 184 122 124 2 34 37 38 136 7 6 5 134 128 + 189 94 188 187 187 186 185 4 4 38 5 37 35 34 33 32 + 244 42 42 3 43 43 43 43 2 2 188 188 188 188 188 188 + 186 185 185 185 186 186 244 244 244 187 187 188 188 188 188 188 + 4 39 39 41 37 40 41 90 84 16 86 89 22 24 44 94 + 88 88 136 137 137 137 170 246 138 138 138 29 94 94 94 94 + 41 41 3 3 3 3 3 3 43 43 187 188 188 188 188 189 + 92 92 92 43 93 2 94 94 4 37 37 34 33 33 34 183 + 184 184 185 185 186 186 122 187 187 187 187 188 188 188 189 189 + 38 39 41 41 155 42 92 43 244 43 188 188 188 188 188 189 + 5 5 4 4 4 4 39 41 3 3 3 187 187 188 188 189 + 39 41 136 91 91 137 26 138 137 93 29 188 188 188 189 189 + 184 184 184 184 185 185 185 186 186 186 187 187 187 188 188 189 + 5 38 38 4 4 39 41 3 3 3 43 43 2 2 94 102 + 203 203 202 203 154 155 155 7 7 149 149 150 151 51 55 55 + 96 96 97 97 166 167 167 168 168 169 169 170 138 29 94 139 + 135 133 244 185 124 125 95 37 38 40 136 33 5 5 135 128 + 158 45 94 188 187 187 244 4 4 4 38 5 35 35 33 33 + 43 25 93 43 93 44 2 2 31 45 45 95 95 189 189 126 + 244 244 244 244 244 244 244 187 187 2 188 188 188 189 189 95 + 41 155 3 42 153 154 22 23 16 17 88 90 23 101 94 139 + 136 136 169 169 169 170 246 171 139 139 139 139 103 103 103 158 + 3 3 3 43 43 43 43 43 2 2 2 2 94 45 189 46 + 27 26 27 28 94 94 103 140 39 38 38 35 34 35 35 184 + 185 185 186 186 122 187 187 124 124 188 188 189 189 189 46 140 + 39 41 42 92 92 25 26 93 28 29 94 94 189 189 189 46 + 4 4 4 39 39 41 3 3 3 43 43 2 2 188 189 158 + 136 136 137 137 137 26 138 138 138 138 94 45 189 189 158 189 + 184 184 185 185 185 186 186 187 187 187 187 188 188 188 189 189 + 38 4 39 39 41 3 3 3 43 43 44 2 45 103 103 158 + 203 203 202 203 154 155 155 7 6 150 150 151 51 55 96 60 + 97 97 97 61 167 167 168 169 169 169 170 170 246 139 140 172 + 136 134 136 244 188 125 102 37 40 88 137 34 5 4 88 128 + 141 1 189 188 188 188 3 3 39 39 39 38 5 35 34 33 + 93 28 30 30 157 103 102 102 102 102 158 46 1 1 47 159 + 3 43 43 43 43 2 2 2 2 94 45 45 95 158 46 46 + 155 100 26 101 20 20 23 62 16 19 90 91 24 157 45 139 + 170 169 169 170 170 171 171 172 172 172 172 140 140 140 140 141 + 3 43 43 93 93 44 30 31 31 45 45 103 103 158 1 47 + 101 246 245 103 103 103 140 141 42 39 38 37 37 5 5 4 + 185 186 186 187 123 124 125 125 125 126 126 126 46 47 47 141 + 42 92 27 27 101 101 101 157 45 103 103 46 46 47 47 159 + 39 41 3 3 3 3 43 43 43 44 2 94 45 95 46 47 + 137 137 137 170 170 246 171 171 139 139 139 140 140 47 141 190 + 185 185 185 186 186 186 186 187 187 188 188 188 189 189 46 47 + 39 154 41 155 155 42 43 43 44 30 157 102 158 1 1 159 + 204 204 203 204 41 156 156 6 6 150 151 152 16 60 60 60 + 61 61 61 61 168 168 238 238 239 239 239 171 172 172 173 78 + 170 167 138 187 189 127 1 153 99 91 170 36 5 39 136 128 + 174 174 159 46 95 45 2 43 156 42 155 39 38 5 5 5 + 157 63 63 63 63 1 1 1 159 159 159 159 159 174 174 142 + 43 44 157 157 157 157 102 102 158 1 1 1 159 159 141 159 + 156 156 245 245 21 23 62 206 17 61 62 62 245 63 159 173 + 170 239 239 75 76 76 77 77 77 173 173 173 79 79 174 174 + 101 101 101 157 157 157 102 102 102 158 1 159 159 141 174 174 + 245 245 63 173 173 173 159 79 26 41 40 38 38 5 5 4 + 244 244 187 188 125 126 126 126 126 127 127 159 141 174 174 174 + 24 26 101 245 245 245 63 63 140 140 1 141 141 174 174 142 + 155 155 155 156 156 156 101 101 157 157 102 158 1 159 159 174 + 137 170 170 171 171 63 77 77 173 173 173 173 141 174 174 141 + 186 186 186 187 187 187 187 188 94 95 158 1 1 159 141 142 + 41 155 155 23 156 156 101 157 102 207 159 159 159 159 159 159 + 206 205 204 205 23 101 101 36 151 152 201 16 16 60 61 61 + 61 61 61 72 73 74 74 74 75 75 76 77 77 78 78 78 + 239 168 138 244 126 159 173 18 62 62 171 37 4 155 90 48 + 149 148 147 146 146 145 145 144 144 144 10 11 11 11 11 12 + 195 146 146 146 147 147 148 147 147 148 148 148 148 148 148 148 + 145 145 145 9 9 146 146 146 146 147 147 147 147 148 148 148 + 144 145 146 145 144 144 145 145 144 144 144 145 145 146 147 148 + 146 48 48 253 48 146 146 147 148 148 148 148 148 148 148 7 + 145 145 145 145 146 146 146 145 146 147 146 147 148 148 148 148 + 146 146 146 147 147 148 148 148 144 106 11 11 11 11 10 10 + 10 10 9 9 8 8 8 8 8 8 8 8 148 148 149 150 + 144 145 145 145 145 146 146 146 147 147 146 148 148 148 149 149 + 144 144 144 144 144 144 145 145 145 145 146 146 147 147 148 148 + 253 253 253 146 146 147 146 146 147 148 148 148 148 7 7 7 + 10 10 10 10 10 9 9 8 8 8 147 147 147 148 7 199 + 192 144 144 144 144 144 145 145 195 195 195 196 147 196 197 198 + 195 195 194 194 145 145 145 13 107 107 192 144 144 247 52 52 + 52 247 247 52 52 53 48 48 48 48 48 48 147 148 148 148 + 253 106 10 8 8 196 148 106 144 253 146 107 11 10 144 48 + 150 149 148 148 147 147 146 145 145 144 144 192 192 192 11 11 + 194 195 196 196 148 199 148 148 199 199 149 149 149 149 149 149 + 145 146 146 146 146 147 147 147 147 148 148 148 148 149 150 199 + 145 195 146 146 144 145 195 195 144 145 146 146 146 196 196 150 + 146 48 48 48 48 48 48 149 149 149 149 149 149 199 199 199 + 146 146 147 147 147 147 147 148 147 148 148 148 149 149 149 149 + 146 147 148 199 199 199 199 149 145 144 144 10 11 10 192 10 + 144 9 9 8 8 7 7 7 7 7 148 149 149 149 150 151 + 145 146 146 146 146 147 147 147 148 148 147 149 149 148 150 150 + 144 144 144 145 145 146 146 146 146 147 147 148 148 149 149 149 + 147 146 146 146 146 48 148 149 148 149 149 149 149 199 199 6 + 10 9 9 9 9 9 8 8 8 147 148 148 148 148 149 199 + 144 144 145 194 194 194 195 195 196 196 196 196 197 197 197 200 + 212 212 195 194 145 145 146 11 252 192 192 192 144 52 52 52 + 52 52 52 53 53 53 53 48 48 48 48 254 149 149 150 150 + 128 253 9 32 7 199 150 144 253 146 48 252 144 144 145 48 + 152 150 150 149 148 148 147 146 146 145 144 144 192 192 192 192 + 196 196 196 196 197 199 199 199 199 199 200 151 151 151 150 150 + 146 147 147 147 147 148 148 148 148 149 199 149 199 150 150 200 + 195 195 147 147 145 146 195 196 146 48 147 196 196 196 199 150 + 146 48 48 48 49 49 49 150 149 150 150 150 150 200 200 200 + 146 146 146 147 147 148 148 148 149 199 149 150 150 150 150 151 + 147 148 199 199 198 200 198 150 146 145 144 192 10 10 144 144 + 144 9 8 8 7 7 7 7 7 7 150 150 150 150 151 152 + 146 146 147 147 148 148 148 148 149 149 149 150 150 150 151 151 + 144 145 194 194 195 195 147 147 196 148 148 149 199 150 150 150 + 147 48 48 48 48 49 149 150 149 150 150 150 150 151 151 36 + 9 9 8 8 8 8 8 8 8 148 148 149 199 150 150 151 + 144 194 194 194 194 195 195 196 196 196 197 199 198 198 198 200 + 212 212 212 196 196 146 195 11 11 192 192 144 106 247 52 52 + 52 53 53 53 53 53 53 48 49 49 49 49 150 150 150 149 + 128 128 128 32 7 198 150 144 253 48 48 106 144 145 146 48 + 152 151 150 150 149 148 148 147 146 146 145 144 144 144 192 192 + 199 199 197 197 197 198 200 200 198 200 200 200 200 200 151 152 + 147 148 148 148 148 149 149 199 149 150 150 150 150 151 151 200 + 195 196 196 199 146 147 196 214 48 48 214 214 214 197 198 151 + 147 49 49 49 49 49 49 50 150 150 151 151 151 200 200 200 + 199 148 148 148 199 199 199 199 199 199 150 150 200 200 200 152 + 149 149 199 198 200 200 200 152 147 146 145 144 10 144 144 145 + 9 9 8 7 7 7 33 6 6 6 6 151 151 152 152 152 + 147 147 148 148 148 149 149 149 150 150 150 151 151 151 152 152 + 194 194 195 195 195 195 196 147 148 199 199 199 199 200 151 151 + 48 48 49 49 49 49 150 150 150 150 151 151 151 200 152 152 + 9 8 8 8 8 8 7 8 7 149 150 150 151 151 151 152 + 145 194 195 195 195 196 196 196 197 197 198 200 200 200 200 201 + 212 212 212 214 214 196 196 192 192 11 192 144 52 52 52 53 + 53 53 53 53 53 53 54 49 49 49 49 50 151 151 152 152 + 128 129 128 33 6 200 150 253 146 48 148 144 144 146 147 48 + 153 152 152 151 150 199 149 148 147 146 146 145 144 144 144 192 + 199 198 200 200 200 200 200 200 200 200 200 200 200 200 152 152 + 148 149 149 149 199 150 150 200 150 151 151 151 151 151 151 200 + 196 196 197 198 147 147 196 214 146 48 214 214 214 200 200 152 + 149 49 80 50 50 50 50 51 83 152 152 152 152 201 201 201 + 148 199 199 199 199 199 199 198 199 200 200 200 200 200 200 152 + 150 150 198 200 200 200 201 152 147 146 145 144 144 144 145 146 + 146 8 7 7 6 6 6 6 36 36 36 152 152 153 153 153 + 148 148 149 149 199 150 150 150 151 200 151 152 152 152 201 201 + 195 195 196 196 196 196 196 196 199 199 198 200 200 200 200 152 + 49 49 49 49 49 49 50 151 151 151 151 152 152 201 201 153 + 8 8 8 8 32 7 7 7 7 150 150 151 152 152 152 152 + 195 195 196 196 196 196 197 197 199 198 200 200 200 200 201 201 + 212 212 213 214 214 196 197 192 144 192 192 145 53 53 53 53 + 53 52 53 53 53 54 54 54 49 50 50 50 151 152 152 152 + 254 130 129 34 36 200 151 146 48 48 49 144 144 146 48 48 + 154 153 153 152 151 150 150 149 148 147 147 146 145 145 144 144 + 198 200 200 200 200 200 201 201 200 201 201 201 201 201 201 201 + 199 150 150 151 151 151 151 151 151 152 152 152 152 5 152 201 + 197 197 198 200 147 148 214 200 48 48 214 214 200 200 200 152 + 49 50 50 50 51 51 51 83 83 152 152 152 201 201 201 202 + 200 200 200 200 200 200 200 201 200 200 200 200 201 201 201 201 + 151 151 200 200 201 201 201 201 148 147 146 145 144 145 146 147 + 147 148 7 150 6 36 36 36 5 37 152 152 153 153 153 153 + 149 149 150 150 150 150 151 151 152 152 152 201 201 201 201 202 + 196 196 196 197 197 197 197 198 199 200 200 200 201 201 201 153 + 49 49 80 50 50 50 51 152 151 152 152 152 201 202 202 154 + 8 8 32 32 32 33 6 6 6 151 151 152 152 153 153 153 + 195 196 196 197 197 197 198 198 200 200 200 201 201 201 201 202 + 212 212 213 213 214 197 198 192 144 144 194 145 53 53 53 52 + 53 53 53 54 54 54 54 55 55 96 83 51 83 152 153 152 + 131 130 129 34 6 201 152 48 48 254 151 144 145 147 254 48 + 154 153 153 153 152 151 151 150 149 148 147 147 146 146 145 144 + 200 201 201 201 200 201 201 202 201 201 201 201 201 202 203 203 + 150 150 151 151 151 151 151 152 201 201 201 153 153 202 153 202 + 198 200 200 200 214 214 200 55 49 54 54 200 200 201 201 201 + 50 51 51 51 83 83 83 16 16 16 16 16 202 202 202 203 + 200 200 198 200 200 200 200 200 201 201 201 201 202 202 202 202 + 152 152 201 201 201 202 202 202 49 148 147 146 145 146 147 147 + 148 148 149 6 36 37 37 36 5 5 153 40 154 154 154 20 + 150 150 150 150 150 151 152 152 153 152 153 153 201 202 202 203 + 196 196 197 198 198 197 198 200 200 200 201 201 201 201 202 202 + 49 80 51 51 83 83 83 16 16 16 16 202 202 202 203 154 + 7 7 32 33 33 6 6 6 36 152 152 152 153 153 153 153 + 196 196 197 197 198 198 200 200 200 201 201 201 201 202 202 203 + 212 213 213 213 198 198 198 192 144 145 194 146 53 53 53 53 + 58 58 59 54 54 54 55 60 55 55 96 83 16 17 19 18 + 83 131 130 35 5 202 17 48 49 49 151 145 146 148 49 48 + 203 154 202 202 152 152 151 150 150 149 148 147 147 146 146 145 + 201 201 202 202 202 202 202 201 201 202 203 203 203 202 202 203 + 152 151 151 151 151 151 152 153 153 201 201 201 202 202 202 203 + 198 200 200 200 150 151 200 55 54 54 54 55 201 201 202 202 + 51 83 83 83 83 83 83 16 17 19 19 203 203 203 202 202 + 200 200 200 200 200 200 201 201 201 201 201 201 202 203 203 203 + 16 16 201 201 202 202 203 203 50 149 147 146 146 146 147 148 + 149 149 150 151 152 153 5 37 5 153 154 154 154 154 203 20 + 151 151 151 151 151 152 152 152 153 153 154 202 202 203 202 204 + 197 197 198 200 200 198 200 200 200 201 201 201 202 202 202 203 + 50 51 83 83 83 83 83 16 17 17 17 202 202 203 203 154 + 7 33 33 6 6 6 6 6 5 153 153 153 153 154 154 154 + 196 197 198 198 200 200 200 200 201 201 202 202 202 203 203 203 + 213 213 213 213 198 198 200 194 145 145 194 196 53 53 53 58 + 58 59 54 54 54 55 55 55 55 96 97 16 16 17 19 17 + 83 131 131 37 5 202 19 146 49 50 152 146 147 150 80 48 + 204 203 202 202 153 153 152 152 151 150 149 149 148 147 146 146 + 201 201 201 202 203 203 203 203 202 203 203 203 204 204 204 204 + 152 152 153 153 152 153 153 154 202 202 202 202 202 203 203 204 + 200 200 201 202 151 151 201 16 54 54 55 16 201 202 203 204 + 16 97 96 96 97 16 17 19 19 19 20 204 204 204 204 204 + 201 201 201 201 201 202 201 202 203 203 203 203 203 204 204 204 + 16 16 202 203 203 202 203 204 50 50 150 148 147 147 148 149 + 150 151 152 152 153 153 40 154 40 154 41 155 23 204 20 20 + 152 152 152 152 153 153 18 18 18 18 202 202 203 204 204 203 + 197 200 200 200 201 201 201 201 202 202 202 202 203 203 204 204 + 83 83 83 97 16 17 17 17 19 19 20 204 204 204 204 203 + 6 33 6 6 36 37 5 153 153 153 154 154 154 155 155 20 + 199 198 200 200 200 201 201 201 202 202 202 203 203 203 204 204 + 214 213 213 200 200 201 201 194 194 195 196 214 214 54 59 59 + 58 59 59 59 60 55 55 60 60 97 97 61 61 20 20 19 + 84 132 132 38 154 203 203 49 50 51 16 146 148 150 50 49 + 205 204 204 203 154 202 153 153 152 151 150 150 149 148 147 147 + 202 203 203 203 203 203 204 204 204 204 204 204 204 204 205 205 + 152 5 40 154 154 154 154 154 154 203 203 204 204 204 204 204 + 201 201 202 202 151 152 16 16 55 55 60 16 203 203 203 20 + 16 97 97 97 17 98 19 21 21 21 23 205 205 204 204 205 + 201 202 202 202 203 203 203 203 203 203 203 204 204 204 204 205 + 17 19 203 204 204 203 204 205 51 50 150 149 148 148 149 150 + 151 152 153 153 40 154 154 41 41 155 155 156 23 204 205 205 + 16 16 16 17 17 18 19 19 20 20 20 20 204 204 205 205 + 200 200 201 201 201 201 202 201 202 202 203 203 204 204 204 205 + 16 97 97 17 17 19 19 20 20 20 21 204 204 204 205 23 + 6 6 35 5 5 5 153 153 40 154 155 155 155 23 156 204 + 198 200 201 201 201 201 202 202 203 203 203 204 204 204 205 205 + 202 202 202 201 201 201 202 196 196 196 196 214 214 54 59 59 + 59 59 60 60 60 60 60 61 61 61 61 61 62 62 205 62 + 97 132 133 38 154 204 204 50 51 16 17 147 199 151 51 48 + 206 205 205 204 20 154 154 154 153 152 151 151 150 199 148 148 + 203 204 204 204 204 204 204 205 205 205 204 205 205 205 205 206 + 154 39 39 38 40 154 41 155 154 203 204 204 205 205 205 205 + 201 202 203 203 152 16 203 17 55 60 16 17 203 204 204 204 + 16 17 98 61 61 168 21 62 62 62 62 206 206 206 206 206 + 203 203 203 203 204 204 204 203 204 204 204 204 204 205 205 205 + 20 20 204 204 204 204 205 205 83 82 151 149 148 149 150 151 + 152 152 153 154 41 155 155 155 156 156 156 156 156 205 206 206 + 18 18 18 19 19 20 20 20 21 23 23 205 205 205 206 206 + 201 201 201 201 201 202 202 202 203 203 204 204 204 204 205 205 + 17 17 98 98 19 19 20 21 21 23 23 205 205 205 206 206 + 37 5 5 38 4 39 39 154 41 155 155 156 156 156 156 205 + 200 201 201 201 202 202 202 203 203 203 204 204 204 205 205 205 + 203 203 202 202 201 201 202 196 196 196 214 214 214 54 59 60 + 60 60 55 60 60 61 61 61 61 61 61 62 62 62 205 62 + 98 84 135 39 155 204 205 51 16 16 61 149 200 152 83 48 + 207 206 205 23 155 41 154 154 153 153 152 151 151 150 149 148 + 204 204 203 204 204 205 205 204 205 205 205 205 206 206 206 206 + 40 39 39 41 41 155 155 155 155 23 204 205 205 205 206 206 + 201 202 20 20 152 17 204 61 55 96 17 203 203 20 23 205 + 19 61 61 61 62 62 169 62 62 62 62 206 206 206 206 206 + 20 20 20 20 204 204 204 204 204 204 205 205 205 205 206 206 + 20 21 204 205 205 205 206 206 16 84 151 150 149 150 36 36 + 5 153 40 41 155 3 3 3 43 156 101 101 101 206 206 206 + 18 18 19 20 20 21 21 21 62 62 62 206 206 206 206 207 + 201 201 201 201 202 202 203 203 203 203 204 204 205 205 206 206 + 17 18 19 19 20 20 21 23 62 62 205 206 206 206 206 207 + 5 5 4 4 39 154 154 41 155 155 42 156 156 156 101 206 + 200 201 202 202 202 203 203 203 204 204 204 204 205 205 206 206 + 203 202 202 202 202 202 203 196 196 214 198 200 54 54 55 60 + 60 55 55 60 61 61 61 61 61 61 168 62 62 62 206 62 + 168 86 136 244 156 205 206 51 16 17 20 149 152 153 97 48 + 207 207 206 101 156 155 155 41 154 40 153 152 152 151 150 199 + 23 23 21 23 205 205 205 205 206 206 206 206 207 207 207 207 + 41 41 155 155 156 156 156 156 101 101 206 205 206 206 206 206 + 202 20 21 20 16 18 204 204 97 97 61 204 21 21 205 206 + 21 62 169 169 62 62 169 170 246 246 245 63 207 207 207 207 + 20 20 20 21 23 23 23 205 205 205 206 206 206 206 206 207 + 21 23 205 205 206 206 206 207 18 85 152 151 150 36 37 5 + 38 39 41 3 3 43 43 44 44 2 157 102 102 207 207 207 + 20 20 20 21 23 62 62 62 62 246 245 206 206 207 207 207 + 201 202 202 202 202 203 203 203 203 204 205 205 205 206 206 207 + 20 21 21 23 23 23 62 62 245 245 206 206 207 207 207 207 + 5 5 4 4 39 41 3 3 3 3 43 44 157 157 207 207 + 201 202 202 203 203 203 204 204 204 205 205 205 206 206 207 207 + 203 203 203 203 203 203 203 197 199 199 198 214 54 55 60 60 + 55 60 60 61 61 97 61 238 168 238 62 239 62 245 63 63 + 169 167 136 244 156 206 206 16 16 19 21 150 152 153 98 254 + 159 207 207 245 101 156 42 155 154 154 4 5 37 152 151 150 + 156 101 206 206 101 101 245 207 207 207 207 207 207 207 207 159 + 156 43 3 3 42 156 101 157 157 102 207 207 207 207 207 207 + 20 21 62 62 16 19 204 62 17 61 61 21 205 206 207 207 + 62 62 62 62 239 239 170 171 171 63 63 173 207 207 207 207 + 21 23 23 23 24 24 26 207 246 206 245 207 207 207 207 207 + 23 246 245 206 207 207 207 207 19 98 153 152 36 37 38 4 + 39 39 3 3 43 2 2 2 94 95 158 158 1 1 1 1 + 21 21 23 23 62 62 246 246 245 245 63 207 207 207 159 159 + 154 154 154 20 155 155 155 23 23 205 206 206 206 207 207 207 + 21 23 62 62 62 246 246 245 63 63 63 207 207 207 207 1 + 4 185 185 4 3 3 43 43 43 43 2 31 102 158 1 159 + 153 202 203 203 203 204 204 205 205 205 206 206 207 207 207 207 + 204 204 204 203 203 203 204 198 150 200 200 200 55 60 60 60 + 60 61 61 61 61 61 61 74 239 239 239 75 171 63 63 77 + 169 136 137 244 157 207 207 16 18 21 62 151 153 40 87 48 + 159 159 1 102 157 101 43 42 41 41 39 38 5 5 36 6 + 101 245 63 63 245 245 63 207 1 1 1 1 1 159 159 159 + 155 43 93 30 157 157 101 101 157 102 102 1 1 1 173 173 + 23 62 62 62 18 20 205 205 17 61 61 205 206 207 207 77 + 62 239 239 239 239 76 171 77 171 63 63 172 63 207 1 173 + 26 246 246 246 246 246 246 63 245 63 63 207 1 1 159 173 + 246 171 63 207 207 207 173 173 87 86 153 152 37 5 4 4 + 3 3 3 43 2 188 188 189 189 189 46 47 159 159 159 159 + 100 23 24 246 246 246 246 245 63 63 63 1 159 159 159 159 + 154 154 155 155 156 156 156 156 101 101 245 207 207 207 159 159 + 23 62 62 62 246 245 245 63 63 63 207 173 159 159 159 159 + 185 185 186 244 3 43 43 2 2 2 94 94 95 1 159 159 + 154 154 20 204 204 204 205 205 206 206 206 207 207 207 159 159 + 205 205 205 205 204 205 206 200 200 151 201 201 55 96 60 61 + 61 61 97 61 61 238 238 239 239 239 75 76 77 173 173 173 + 169 136 137 187 102 159 207 16 99 62 62 152 153 154 168 128 + 159 159 159 159 159 207 206 206 205 205 204 203 203 202 202 201 + 207 207 207 207 159 159 159 159 159 159 159 159 159 159 159 159 + 206 206 206 206 206 207 207 159 159 159 159 159 159 159 159 159 + 205 205 206 206 204 204 205 206 203 204 205 206 206 207 207 159 + 206 207 207 207 207 207 207 159 159 159 159 159 159 159 159 159 + 206 206 206 206 207 207 207 159 207 159 159 159 159 159 159 159 + 207 207 159 159 159 159 159 159 205 204 203 202 202 202 203 203 + 205 205 206 207 207 159 159 159 159 159 159 159 159 159 159 159 + 206 206 206 206 207 207 207 207 207 159 159 159 159 159 159 159 + 204 204 204 205 205 205 206 206 206 207 207 159 159 159 159 159 + 206 206 206 206 207 207 207 159 207 159 159 159 159 159 159 159 + 156 156 157 157 206 206 206 206 207 159 159 159 159 159 159 159 + 204 205 205 205 205 205 206 206 206 207 207 159 159 159 159 159 + 205 205 205 205 205 205 205 201 201 201 201 202 203 203 204 204 + 203 203 203 204 205 206 206 207 207 207 207 207 159 159 159 159 + 206 26 2 125 159 159 159 203 205 206 206 202 203 204 206 48 + 210 210 210 210 210 210 210 210 211 211 211 211 211 211 211 211 + 210 210 210 210 210 210 210 210 210 210 210 210 210 210 210 210 + 211 211 211 211 211 211 210 210 210 210 210 210 210 210 210 210 + 210 210 211 211 211 211 211 211 211 211 211 210 210 210 210 210 + 211 211 211 211 211 211 211 211 211 211 210 210 210 210 210 210 + 211 211 211 211 211 211 210 210 210 210 210 210 210 210 210 210 + 210 210 210 210 210 210 210 210 211 211 211 211 211 211 211 211 + 211 210 210 210 210 210 210 210 210 210 210 210 210 210 210 210 + 211 211 211 211 211 211 211 211 210 210 210 210 210 210 210 210 + 211 211 211 211 211 211 210 210 210 210 210 210 210 210 210 210 + 211 211 211 211 211 211 211 211 210 210 210 210 210 210 210 210 + 211 211 211 211 211 211 211 210 210 210 210 210 210 210 210 210 + 210 210 210 210 210 210 210 210 210 210 210 210 210 210 210 210 + 210 210 210 210 210 210 210 211 211 211 210 210 210 211 211 211 + 211 211 211 211 211 211 211 211 211 211 211 211 211 211 211 211 + 212 194 193 201 211 210 211 211 211 211 211 211 210 211 194 214 + 210 210 210 210 210 210 210 210 210 210 210 210 211 211 211 211 + 210 210 210 210 210 210 210 210 210 210 210 210 210 210 210 210 + 210 210 210 210 210 210 210 210 210 210 210 210 210 210 210 210 + 210 210 210 210 210 210 210 210 210 210 210 210 210 210 210 210 + 210 210 210 210 210 210 210 210 210 210 210 210 210 210 210 210 + 210 210 210 210 210 210 210 210 210 210 210 210 210 210 210 210 + 210 210 210 210 210 210 210 210 210 210 210 210 210 210 210 210 + 210 210 210 210 210 209 209 209 209 210 210 210 210 210 210 210 + 210 210 210 210 210 210 210 210 210 210 210 210 210 210 210 210 + 210 210 210 210 210 210 210 210 210 210 210 209 209 210 210 210 + 210 211 210 210 210 210 210 210 210 210 210 210 210 210 210 210 + 210 210 210 210 210 210 210 210 210 210 210 210 210 210 210 210 + 210 210 210 210 210 210 210 209 209 209 210 210 210 210 210 210 + 209 208 209 209 209 209 210 211 211 211 210 210 210 210 210 210 + 211 211 210 210 210 210 210 210 210 210 210 210 210 210 211 211 + 211 211 195 201 210 210 210 210 210 210 211 210 210 210 212 213 + 202 213 212 212 211 211 211 211 211 211 211 212 212 212 212 194 + 212 211 211 211 211 211 211 212 213 212 213 212 212 212 213 213 + 212 212 212 212 211 211 211 211 211 211 211 211 211 211 211 211 + 211 211 211 211 211 211 211 211 211 211 211 211 211 211 211 211 + 212 212 212 212 212 213 213 213 213 213 213 213 212 213 213 213 + 212 212 212 212 212 212 212 212 212 212 212 212 212 212 212 213 + 212 212 212 212 212 212 212 213 212 212 212 212 212 212 212 211 + 211 211 211 211 211 211 211 211 211 211 211 211 211 212 213 201 + 212 212 212 212 212 212 212 212 213 213 213 213 212 213 213 203 + 211 211 211 211 211 211 211 211 211 211 211 211 211 211 212 212 + 212 212 212 212 212 212 212 212 213 213 213 212 212 213 213 201 + 212 212 212 212 212 212 211 211 211 212 212 212 212 212 212 211 + 211 210 210 210 210 210 210 210 210 210 211 211 211 211 211 210 + 210 209 210 210 210 210 211 193 194 212 211 210 210 210 211 211 + 211 211 211 211 211 211 212 212 213 213 213 213 213 213 213 213 + 213 213 196 201 212 211 212 212 212 212 212 212 211 212 214 49 + 203 202 213 213 213 213 212 212 212 212 212 212 194 194 194 192 + 213 213 213 213 213 213 213 213 213 213 213 213 213 201 202 203 + 213 213 213 213 213 213 213 213 213 213 213 213 213 213 213 213 + 212 212 212 212 212 212 212 212 211 211 212 212 212 213 213 213 + 213 213 213 213 213 213 213 213 213 213 213 213 200 201 201 203 + 213 213 213 213 213 213 213 213 213 213 213 213 213 213 201 202 + 196 196 196 196 213 213 201 201 196 196 195 195 194 195 212 212 + 212 212 212 212 213 213 212 212 213 212 213 213 213 202 203 203 + 213 213 213 213 213 213 213 213 213 214 214 213 200 201 202 203 + 212 212 212 212 212 212 212 212 212 212 213 213 213 213 200 203 + 213 213 213 213 213 213 213 213 213 213 213 200 200 201 202 203 + 196 214 213 213 213 213 213 213 213 213 213 213 213 213 201 202 + 212 211 211 211 211 211 211 211 212 212 213 213 212 213 201 203 + 210 210 210 210 210 211 212 192 192 194 212 211 211 211 212 212 + 212 212 212 212 212 213 213 213 213 213 213 198 200 200 201 202 + 214 198 199 200 196 213 213 195 213 212 213 212 212 212 146 48 + 202 202 201 213 213 213 197 197 196 195 195 195 194 194 144 192 + 213 213 213 213 213 213 213 213 213 200 200 201 201 201 201 202 + 214 213 213 213 213 213 213 213 213 213 213 213 213 200 201 201 + 214 214 213 213 212 213 213 213 212 212 212 213 213 197 198 201 + 213 213 213 213 213 213 213 213 200 200 201 201 201 201 202 202 + 213 213 213 213 213 213 213 213 200 213 213 198 200 201 201 201 + 198 198 198 198 200 201 201 202 196 196 194 194 193 194 194 196 + 214 213 213 213 197 197 198 200 213 213 200 201 202 202 201 201 + 213 213 213 213 213 213 213 213 213 213 200 201 202 202 202 202 + 195 212 213 213 213 213 213 213 213 213 213 213 198 198 200 202 + 213 213 213 213 213 213 213 213 214 200 200 201 201 201 201 201 + 195 195 196 196 214 214 214 214 198 198 198 214 198 200 201 202 + 212 212 212 212 213 213 213 213 213 213 213 213 200 201 201 203 + 211 210 211 211 211 212 196 192 192 193 195 212 212 212 212 212 + 212 212 213 213 213 214 214 214 214 214 214 200 200 201 201 202 + 149 149 7 6 197 201 201 194 196 197 197 193 194 196 147 254 + 202 202 202 201 200 198 197 197 196 195 195 195 194 144 144 144 + 198 200 200 201 201 201 201 201 202 202 202 202 202 201 201 201 + 197 198 198 198 198 198 200 200 200 200 201 201 201 201 201 202 + 197 197 214 200 214 214 214 213 213 213 213 214 198 198 200 201 + 200 201 201 201 200 200 201 200 201 201 201 201 201 201 202 202 + 198 198 198 198 198 200 200 200 201 201 201 201 201 201 201 202 + 199 198 198 200 200 201 201 201 196 196 146 145 144 145 194 195 + 196 214 197 197 198 198 200 200 200 201 201 201 201 201 201 202 + 197 198 198 198 200 200 200 201 200 200 201 201 201 201 201 201 + 196 196 196 197 197 197 198 200 213 198 200 200 201 201 152 152 + 198 198 200 200 200 200 201 201 201 201 201 201 202 202 202 201 + 147 147 148 148 199 199 199 199 200 200 200 200 201 201 201 202 + 196 196 197 197 197 197 197 198 198 198 200 201 201 201 201 202 + 212 211 211 212 212 213 196 192 144 144 194 212 212 213 213 214 + 53 58 58 54 54 48 48 54 96 55 55 16 201 201 201 152 + 49 149 7 6 200 202 201 146 196 198 198 194 195 197 147 128 + 201 201 200 200 200 200 198 197 199 147 147 146 145 144 9 144 + 198 200 200 200 152 152 201 201 152 152 152 152 152 152 153 153 + 198 198 198 198 200 200 200 200 200 200 201 201 153 153 152 151 + 199 199 198 200 147 148 149 150 214 214 214 150 151 151 152 153 + 150 51 51 51 151 152 153 153 153 153 152 152 152 152 153 153 + 198 198 198 200 200 200 200 200 198 200 152 153 153 152 153 153 + 200 200 201 201 201 202 202 202 148 147 146 145 145 144 146 147 + 195 196 198 200 200 200 200 200 5 5 5 5 152 152 153 202 + 199 199 199 200 200 151 200 200 152 152 152 201 153 5 4 154 + 195 196 148 148 148 199 199 198 200 200 200 201 201 153 153 152 + 150 150 150 151 151 151 152 152 152 153 153 152 152 153 40 154 + 7 7 7 7 7 199 199 150 150 200 151 151 152 153 153 153 + 147 147 148 199 199 196 199 199 198 200 201 202 201 201 153 202 + 195 195 196 214 197 197 199 144 144 144 145 145 214 214 214 53 + 53 59 54 49 49 104 104 81 81 51 55 16 16 16 153 153 + 254 254 7 6 36 152 153 146 149 200 200 145 196 147 253 129 + 11 11 11 12 13 13 13 14 14 215 215 215 215 215 215 215 + 107 107 251 251 251 13 107 107 11 11 107 107 107 107 107 107 + 14 14 14 13 13 12 12 13 13 13 13 12 12 11 11 11 + 14 14 251 251 216 216 251 251 216 216 216 251 251 251 107 252 + 251 251 251 251 251 251 107 107 107 107 107 11 11 11 11 11 + 14 14 251 251 251 251 107 107 107 13 12 12 11 11 11 11 + 251 107 107 12 12 107 11 11 215 215 215 215 215 215 215 215 + 15 14 13 13 13 13 12 12 12 12 12 12 11 11 11 107 + 251 251 251 251 251 251 251 13 13 13 12 12 11 11 11 11 + 215 215 14 14 14 14 14 14 13 12 12 12 12 107 11 107 + 251 251 251 251 251 251 251 251 251 107 107 11 12 11 11 11 + 14 15 15 14 14 14 13 13 13 13 13 13 12 107 11 107 + 215 215 14 14 14 14 14 13 107 13 13 107 107 11 107 11 + 13 13 13 13 13 14 14 215 215 216 216 216 216 216 216 216 + 216 217 217 216 251 251 251 251 251 251 251 252 252 252 107 252 + 251 251 13 13 13 12 107 215 215 251 251 216 216 215 251 128 + 11 11 107 107 107 251 251 251 251 251 215 216 216 216 216 216 + 252 107 107 107 107 107 107 107 107 107 107 107 107 252 11 11 + 13 13 13 13 12 12 12 12 12 107 12 12 12 12 11 11 + 13 251 251 252 216 251 216 252 216 251 251 252 252 252 107 107 + 251 251 252 251 251 252 107 107 107 107 107 107 107 107 11 10 + 251 251 251 107 107 107 107 107 107 107 107 107 12 12 11 11 + 252 252 107 107 107 107 107 252 251 216 215 215 215 215 215 15 + 14 14 12 12 13 13 12 11 11 109 12 109 11 192 192 11 + 251 251 251 251 107 107 107 107 107 107 107 12 12 11 10 11 + 215 215 251 251 251 14 14 13 107 107 107 107 107 107 107 252 + 251 251 107 107 251 107 107 107 107 107 107 107 107 11 11 11 + 14 14 14 14 14 13 13 13 13 12 12 11 11 11 11 11 + 215 14 14 251 251 13 107 107 107 107 107 107 107 252 11 11 + 12 13 12 107 251 251 107 215 215 216 216 216 217 217 217 217 + 217 217 216 252 252 251 251 251 251 251 252 252 252 252 107 252 + 252 251 107 107 12 12 11 215 251 251 251 216 216 216 251 128 + 106 252 252 252 252 251 251 251 251 251 251 216 216 216 216 216 + 252 251 252 252 252 106 106 106 106 144 144 144 144 144 144 144 + 107 107 107 107 107 107 107 107 252 252 106 106 106 11 11 252 + 107 252 252 251 216 252 252 252 217 217 216 252 252 252 106 252 + 252 252 252 252 252 252 252 252 252 106 106 144 144 144 144 106 + 251 251 252 252 252 252 252 252 252 252 106 144 144 106 106 106 + 252 252 252 252 106 106 106 106 252 251 216 216 216 216 215 13 + 14 13 13 12 11 11 11 11 11 11 11 11 192 192 192 144 + 252 251 252 252 252 252 252 252 252 252 106 144 144 144 144 144 + 251 251 252 252 251 252 252 251 107 107 252 252 106 106 144 106 + 252 252 252 252 251 252 252 252 252 106 106 106 144 144 144 106 + 13 13 13 13 107 107 107 107 107 107 252 11 11 10 10 144 + 251 251 252 251 252 251 107 252 252 252 106 106 106 106 106 144 + 144 144 216 216 252 252 252 216 216 216 217 217 217 218 218 218 + 217 217 217 247 252 247 247 252 247 247 252 252 106 106 106 106 + 252 251 252 252 11 11 144 216 252 252 252 216 216 251 252 105 + 144 106 106 144 144 106 252 252 144 218 216 217 217 216 217 217 + 52 247 247 52 52 52 52 52 52 52 52 52 52 52 52 52 + 252 252 252 252 252 106 106 106 106 144 144 144 144 144 144 144 + 252 252 52 52 217 217 52 52 218 218 218 52 52 52 52 247 + 247 247 247 247 247 247 52 52 52 52 52 52 52 52 52 52 + 247 247 247 247 52 247 247 52 247 52 52 52 52 52 52 52 + 247 247 247 247 247 247 52 52 247 217 216 217 216 216 216 217 + 252 11 107 11 144 11 252 144 144 144 144 144 144 144 144 52 + 247 247 247 52 52 247 52 52 247 52 52 52 52 52 52 52 + 217 217 247 247 252 252 251 106 106 106 106 144 144 144 144 106 + 247 247 247 247 247 52 52 52 52 52 52 52 52 52 52 52 + 252 252 252 252 252 252 252 252 144 144 144 144 144 144 144 144 + 217 217 217 218 218 252 52 52 52 52 52 52 52 52 52 52 + 217 218 218 217 217 52 52 216 217 217 218 218 218 218 219 219 + 219 218 218 218 56 56 56 52 52 52 52 52 52 52 52 52 + 52 252 252 252 144 144 144 216 217 52 52 216 217 217 252 104 + 53 52 52 52 52 52 52 52 52 217 217 217 217 218 218 217 + 56 52 56 56 56 56 56 56 56 56 56 56 52 56 56 52 + 247 247 247 247 247 52 52 52 52 52 52 52 52 52 52 52 + 52 52 52 56 218 218 56 57 219 219 219 222 56 56 56 52 + 56 56 56 56 56 56 56 52 56 56 56 56 56 56 56 56 + 52 52 52 52 56 56 56 56 56 56 56 56 56 52 56 52 + 52 52 247 52 52 52 52 56 56 218 218 218 217 217 218 217 + 216 144 144 144 144 144 144 144 52 52 52 52 52 52 52 52 + 247 52 52 52 52 52 52 56 56 56 56 52 52 52 52 57 + 218 218 218 56 52 52 52 52 52 52 52 52 52 52 52 52 + 52 56 56 56 56 56 56 56 56 56 56 56 52 52 56 52 + 252 252 252 252 247 247 52 52 52 52 52 52 52 52 52 52 + 218 218 218 218 56 56 52 52 52 52 52 52 52 52 52 56 + 219 219 219 218 218 222 56 218 218 218 218 219 219 219 219 219 + 220 220 220 219 219 221 225 56 56 56 56 56 52 52 52 52 + 52 52 247 52 52 52 52 217 217 56 56 218 218 217 247 53 + 57 56 56 56 56 52 52 52 52 218 217 218 218 218 218 218 + 56 56 56 56 56 56 56 56 56 56 56 56 56 56 56 56 + 52 52 52 52 52 56 56 56 56 56 56 56 56 56 56 56 + 218 56 225 225 219 219 219 222 220 221 219 219 222 225 56 56 + 56 56 56 56 56 56 56 56 56 56 56 56 56 56 56 56 + 56 56 56 56 56 56 56 56 56 56 56 56 56 56 56 56 + 56 56 56 56 56 56 56 56 222 219 218 218 218 218 218 218 + 217 52 52 52 52 52 52 52 52 56 56 57 56 56 56 56 + 56 56 56 56 56 56 56 56 56 56 56 56 56 56 56 57 + 219 219 219 219 225 56 56 56 56 56 56 56 56 56 56 56 + 56 56 56 56 56 56 56 56 56 56 56 56 56 56 56 57 + 52 52 52 247 247 52 52 52 52 52 56 56 56 56 56 56 + 218 219 219 219 219 219 56 56 56 56 56 56 56 56 56 56 + 219 220 220 220 219 219 219 218 218 218 219 219 219 219 219 220 + 220 220 220 220 221 222 222 225 225 225 56 56 56 56 56 56 + 56 56 247 52 56 57 56 218 219 225 225 218 218 219 56 231 + 57 56 56 56 56 56 56 56 56 56 56 218 218 219 218 218 + 56 56 56 56 56 56 56 56 56 56 56 56 56 57 57 56 + 56 56 56 56 56 56 56 56 56 56 56 56 56 56 56 56 + 225 225 222 224 219 224 223 223 221 221 221 223 225 225 56 56 + 225 225 225 56 56 56 56 56 56 56 56 56 56 56 56 56 + 56 56 56 56 56 56 56 56 56 56 56 56 56 56 56 56 + 56 56 56 56 56 56 56 56 223 223 219 219 218 218 218 56 + 56 52 247 52 52 52 56 56 57 56 56 56 56 56 57 58 + 56 56 56 56 56 56 56 57 56 56 56 56 56 56 57 57 + 219 223 222 225 222 225 225 225 56 56 56 56 56 56 56 56 + 225 225 225 225 56 56 56 56 56 56 56 56 56 57 57 57 + 52 52 52 52 52 52 56 56 56 56 56 56 56 56 56 57 + 219 221 223 222 225 225 225 225 56 56 56 56 56 56 56 56 + 220 219 220 220 219 223 222 218 218 219 219 220 220 220 220 220 + 220 220 222 222 221 221 224 224 225 225 56 56 56 56 56 56 + 225 225 247 52 56 56 57 219 224 224 225 218 218 222 247 231 + 58 57 57 56 56 56 56 56 56 56 56 56 56 218 218 218 + 56 56 56 56 56 56 56 56 56 56 56 56 57 57 57 57 + 56 56 56 56 56 56 56 56 56 56 56 56 56 57 57 57 + 225 222 225 226 219 224 225 225 221 221 222 56 56 56 56 56 + 225 225 225 56 56 56 56 56 56 56 56 56 56 57 57 57 + 225 225 56 56 56 56 56 56 56 56 56 56 56 56 57 57 + 56 56 56 56 56 57 57 57 225 225 223 218 218 218 56 56 + 52 52 52 52 56 56 56 56 56 56 57 58 58 57 57 57 + 56 225 56 56 56 56 56 56 56 56 56 56 57 57 57 58 + 225 223 225 222 225 225 225 56 56 56 56 56 56 57 57 57 + 222 225 225 225 56 56 56 56 56 56 56 56 57 57 57 58 + 52 52 52 52 52 52 52 52 56 56 56 56 56 56 57 57 + 225 225 223 225 225 225 56 56 56 56 56 56 56 57 57 57 + 219 219 219 223 225 222 223 218 218 219 220 220 220 220 220 220 + 222 224 221 224 224 224 224 224 225 225 56 56 56 56 57 57 + 225 56 52 52 56 56 57 222 225 225 56 218 223 223 247 64 + 58 58 57 57 56 56 56 56 56 56 56 56 222 222 56 218 + 56 56 56 56 56 56 56 56 57 57 57 57 57 57 57 57 + 56 56 56 56 56 56 56 56 56 56 57 57 57 57 57 57 + 56 56 56 225 223 225 225 225 222 224 225 225 56 56 56 57 + 56 225 225 225 56 56 56 56 56 57 57 57 57 57 57 57 + 56 56 56 56 56 56 56 56 56 56 57 57 57 57 58 58 + 56 56 56 56 56 57 57 57 56 225 225 56 56 56 56 247 + 52 247 52 56 56 56 57 57 57 57 57 57 57 57 57 57 + 56 56 56 56 56 56 56 56 56 56 57 57 58 58 57 57 + 222 225 222 225 56 56 56 56 56 56 56 56 57 57 57 57 + 225 225 225 225 225 56 56 56 56 57 57 57 57 58 58 57 + 52 247 247 52 52 52 52 56 56 56 56 57 57 57 57 57 + 225 225 225 225 56 56 56 56 56 56 56 56 57 57 58 58 + 56 56 57 225 225 225 56 218 218 219 220 221 220 221 221 222 + 222 224 224 224 224 224 226 226 226 226 56 56 56 57 57 227 + 225 56 52 53 58 57 228 225 225 225 56 56 223 222 247 53 + 57 58 57 57 56 56 56 56 56 56 225 225 225 225 225 225 + 56 56 56 56 56 57 57 57 57 57 57 57 57 57 57 57 + 56 56 56 56 56 56 56 56 57 57 57 57 57 57 57 57 + 56 56 56 56 222 225 225 225 224 224 225 225 56 56 57 227 + 226 225 226 226 226 226 227 227 227 227 227 227 57 57 57 57 + 56 56 56 56 56 56 56 56 57 57 57 57 57 57 57 57 + 56 56 57 57 57 57 57 57 56 225 225 56 56 56 52 52 + 52 52 56 57 57 57 57 58 57 57 57 57 57 57 57 57 + 56 56 56 56 56 56 56 56 57 57 57 57 57 57 57 57 + 56 225 56 56 56 56 56 56 56 56 56 57 58 57 57 57 + 56 226 226 225 225 225 56 56 227 227 227 57 57 57 57 57 + 52 52 52 52 52 56 56 56 56 57 58 57 57 57 57 57 + 225 225 225 56 56 56 56 56 56 56 57 57 57 57 57 57 + 56 56 56 56 56 56 56 218 219 219 221 221 222 222 222 224 + 224 224 224 224 226 226 226 226 226 226 226 227 227 227 227 227 + 226 56 52 58 58 57 57 225 225 226 226 225 223 225 52 58 + 58 58 57 58 57 57 56 57 56 56 56 56 225 225 225 56 + 57 57 57 57 57 57 58 57 57 57 57 57 57 57 57 57 + 56 56 56 57 57 57 58 58 57 57 57 57 57 57 57 57 + 56 56 56 56 225 225 225 226 225 225 226 226 227 227 228 227 + 226 226 226 226 226 227 228 228 228 228 228 228 228 228 228 228 + 56 56 56 56 56 57 57 57 57 57 57 57 58 57 57 57 + 227 227 227 227 57 57 57 57 56 56 56 56 56 52 52 52 + 52 56 56 57 58 58 57 57 57 57 57 58 58 58 58 58 + 57 56 56 56 56 57 227 57 227 57 57 57 57 58 58 58 + 56 56 56 56 56 56 56 56 56 57 58 58 57 58 58 57 + 227 226 227 227 227 227 228 228 228 228 228 228 228 228 58 58 + 247 247 52 52 52 57 57 57 58 57 57 57 57 57 58 228 + 56 56 56 56 56 57 56 56 57 57 57 57 57 57 57 57 + 56 56 56 57 56 56 57 225 223 223 224 222 222 224 224 224 + 224 224 225 226 226 226 226 226 226 226 228 228 228 228 228 229 + 227 227 57 58 53 57 227 225 225 226 227 225 225 56 56 58 + 59 58 58 57 58 58 57 56 56 56 56 56 56 56 56 56 + 57 227 227 227 57 57 57 57 58 58 58 58 58 58 58 58 + 57 57 57 57 57 57 57 57 58 58 58 58 58 58 59 59 + 56 57 57 227 225 225 226 227 226 226 226 226 228 228 229 228 + 227 227 228 227 227 228 228 228 229 229 229 229 229 230 229 229 + 57 58 58 58 58 57 57 57 57 57 58 58 58 58 58 228 + 227 227 227 228 228 228 229 229 227 56 56 56 56 247 247 52 + 52 57 58 57 57 58 58 59 58 58 58 58 58 58 58 58 + 56 57 57 227 227 227 227 227 229 229 228 228 58 58 58 58 + 57 56 56 56 56 57 57 58 58 58 57 57 58 58 58 58 + 227 227 227 228 227 227 228 228 229 229 229 229 229 230 230 229 + 52 52 52 52 52 57 57 57 57 57 58 58 59 58 58 58 + 56 56 56 56 56 57 57 57 57 57 57 58 58 58 58 58 + 57 58 57 56 56 57 228 56 225 223 223 224 224 224 224 224 + 226 226 226 226 226 226 226 227 228 228 228 228 229 229 229 229 + 228 227 248 58 58 58 228 225 225 226 227 56 56 56 52 58 + 68 59 249 58 58 57 57 58 57 57 52 52 52 52 52 52 + 228 228 229 229 230 230 230 230 230 230 230 230 230 230 230 230 + 57 57 57 58 58 58 58 58 58 58 58 58 58 58 58 58 + 57 227 227 227 56 227 227 228 226 226 226 228 228 229 230 229 + 228 228 228 229 229 228 228 229 229 229 229 229 229 230 230 230 + 57 58 57 57 57 57 57 58 58 231 231 230 230 230 230 230 + 229 229 229 229 229 230 230 230 227 56 56 56 52 247 52 52 + 52 53 53 53 58 59 59 58 59 59 58 58 58 249 249 249 + 57 227 57 227 228 229 229 229 230 230 230 230 230 230 230 230 + 56 56 57 58 57 58 57 57 57 57 59 59 58 58 59 230 + 227 227 228 229 229 228 229 229 229 229 229 230 230 230 230 230 + 248 52 53 53 58 249 59 59 59 58 58 58 58 249 249 67 + 56 57 57 57 57 58 58 57 58 58 58 58 58 249 230 230 + 57 57 57 58 57 57 57 56 56 222 223 224 224 224 226 226 + 226 226 226 226 226 227 228 228 229 228 228 229 229 229 230 230 + 227 228 231 249 249 58 230 56 227 228 228 56 56 56 52 53 + 67 68 68 249 249 58 249 58 53 53 53 52 52 52 52 247 + 230 230 229 229 229 232 232 232 233 233 233 233 233 233 234 234 + 249 249 249 249 58 58 249 249 58 249 66 234 234 234 68 234 + 248 227 229 229 227 227 229 229 226 228 227 229 229 229 230 230 + 229 228 229 229 229 229 229 230 230 230 230 230 230 230 233 233 + 57 58 58 249 230 230 230 230 232 232 233 233 233 233 233 233 + 229 229 229 230 230 233 233 233 227 57 56 52 52 52 52 52 + 248 53 249 249 58 58 59 59 60 60 250 250 67 68 236 236 + 248 231 230 230 230 232 231 230 232 232 233 233 233 234 234 234 + 57 57 58 57 57 57 58 58 58 58 249 58 249 234 234 234 + 231 228 229 229 229 229 229 230 229 230 230 233 233 233 234 234 + 248 160 64 64 64 64 64 249 249 249 66 67 67 67 67 67 + 57 57 57 57 58 58 58 59 58 58 249 249 249 233 234 234 + 58 58 57 57 58 57 58 52 56 56 225 225 226 226 226 226 + 226 226 226 226 228 228 228 229 228 229 229 229 230 230 230 233 + 229 231 64 249 67 68 234 56 228 229 229 56 56 57 53 53 + 236 235 67 67 67 249 249 249 249 249 58 53 248 248 52 248 + 232 231 232 232 233 233 233 233 234 234 234 234 234 234 234 234 + 64 249 249 249 249 66 66 233 233 234 234 234 234 235 235 234 + 231 231 231 230 228 229 229 229 227 228 229 229 230 229 233 233 + 229 229 229 229 230 230 230 230 230 233 234 234 234 234 234 234 + 249 66 249 249 249 233 233 234 233 233 233 233 233 233 234 234 + 231 230 232 233 233 234 234 234 231 227 248 248 248 248 53 160 + 249 249 64 249 250 250 250 250 250 250 250 250 67 68 68 68 + 66 233 232 231 232 232 233 233 233 233 233 233 234 234 234 234 + 248 53 58 58 58 249 249 249 64 249 234 234 233 234 234 234 + 232 229 230 230 230 230 230 230 230 233 233 234 234 234 234 69 + 160 160 64 64 64 64 64 249 249 66 235 67 235 235 234 234 + 53 53 53 58 59 58 58 58 58 249 67 234 234 234 234 236 + 58 58 59 58 59 59 59 247 52 56 56 225 226 226 226 226 + 226 226 228 228 228 228 229 229 229 230 230 230 230 233 234 234 + 231 231 65 66 69 68 234 227 229 229 230 248 57 58 249 104 + 234 69 234 235 66 68 66 64 64 64 64 64 53 248 248 248 + 233 233 233 234 234 234 234 234 234 234 235 234 68 68 69 69 + 249 65 65 66 66 233 234 234 234 234 234 234 235 234 69 236 + 232 233 233 233 231 229 230 230 228 228 229 230 230 230 234 234 + 230 230 230 230 230 233 233 233 233 233 234 234 234 234 234 234 + 65 233 233 233 234 234 233 233 234 234 234 234 234 234 234 234 + 233 233 234 234 234 234 234 234 232 232 231 248 248 248 160 104 + 160 64 249 250 250 250 250 250 250 250 250 68 69 236 236 236 + 64 65 66 233 233 233 233 234 233 234 234 234 234 234 69 236 + 249 64 249 249 64 249 249 65 234 66 65 234 234 234 234 234 + 232 230 230 230 233 233 234 234 233 234 234 234 234 234 69 69 + 64 64 64 64 64 64 65 65 65 66 235 235 235 235 234 234 + 249 58 58 58 59 58 249 249 67 67 68 234 235 234 234 236 + 58 58 58 59 58 53 249 52 52 52 56 56 225 226 226 228 + 228 228 228 229 229 229 229 230 230 230 230 233 234 234 234 234 + 232 231 64 162 69 68 234 248 230 230 233 248 58 249 249 160 + 236 236 69 69 67 68 66 66 249 64 160 64 64 160 248 248 + 234 234 234 234 234 234 234 234 236 69 69 236 236 70 70 70 + 65 66 66 67 235 235 235 235 235 234 234 69 69 69 69 69 + 65 66 233 234 232 230 233 233 231 230 232 233 233 234 234 234 + 233 230 233 234 234 233 234 234 234 234 234 234 234 69 236 236 + 233 233 233 233 233 234 234 234 235 234 234 69 69 69 236 70 + 234 234 234 234 68 69 236 70 65 65 64 248 248 160 104 104 + 65 249 249 250 250 165 165 165 166 166 236 70 70 70 70 236 + 66 65 66 235 233 234 234 233 234 234 234 69 69 236 236 70 + 64 64 249 249 249 66 66 67 66 68 235 234 234 234 236 234 + 232 233 233 233 233 234 234 233 234 234 234 234 69 236 70 70 + 160 161 162 162 162 66 66 66 67 67 235 69 69 68 234 236 + 64 249 249 249 250 250 250 250 68 68 69 69 69 236 236 70 + 250 60 59 58 58 250 250 248 52 52 57 227 228 228 227 228 + 228 229 229 229 229 230 230 230 230 233 234 234 234 234 236 236 + 233 66 66 164 69 68 70 231 230 230 234 248 64 249 250 160 + 70 70 70 236 69 68 67 250 250 249 249 64 64 104 160 248 + 235 234 234 234 234 234 69 236 236 236 236 236 70 70 70 70 + 250 250 250 67 68 68 69 236 69 69 236 236 70 70 70 70 + 67 235 235 234 232 233 233 233 231 230 233 233 234 234 69 236 + 233 233 234 234 234 234 234 234 236 236 236 70 70 236 70 70 + 66 233 234 234 234 234 234 234 234 69 236 236 70 70 70 71 + 68 69 236 236 70 70 70 70 66 65 64 64 160 160 161 161 + 162 162 250 165 165 166 166 166 237 237 70 70 70 70 70 70 + 66 235 235 235 235 234 234 234 69 69 236 70 70 70 70 71 + 249 249 250 250 250 66 67 68 68 68 69 69 236 70 70 70 + 233 233 233 234 234 234 234 234 234 234 236 236 70 70 70 70 + 162 162 162 163 163 250 250 250 67 68 69 236 70 70 70 70 + 64 249 250 67 250 250 250 250 68 69 69 236 236 70 70 70 + 250 60 60 60 60 250 250 248 53 53 57 227 227 228 228 228 + 229 229 229 229 230 230 230 233 233 234 234 234 236 236 236 236 + 233 65 66 164 70 70 70 232 233 233 234 248 64 249 250 160 + 71 71 70 70 70 69 68 250 250 250 162 162 161 160 160 248 + 69 69 69 236 236 236 236 70 70 70 70 70 70 70 70 237 + 164 165 165 165 69 69 236 236 70 70 70 70 237 71 71 71 + 67 235 68 68 65 233 234 234 232 233 233 234 234 69 236 70 + 234 234 234 234 234 234 236 236 236 236 236 70 70 70 237 70 + 235 235 235 234 234 69 69 69 236 70 70 70 70 71 71 71 + 236 236 70 70 70 70 70 71 67 66 64 64 160 161 161 162 + 163 163 164 165 166 166 167 167 167 237 237 237 237 71 71 71 + 235 235 235 234 234 234 69 236 236 70 70 70 70 71 71 71 + 250 250 250 250 250 250 68 68 69 69 236 70 70 70 237 71 + 235 234 234 234 234 236 236 236 236 70 70 70 70 237 71 72 + 162 163 163 164 164 165 165 165 165 236 70 70 70 71 71 70 + 249 250 250 250 250 250 250 68 236 236 70 70 70 70 70 71 + 60 60 60 59 250 250 250 53 104 53 53 57 227 228 229 230 + 229 230 230 230 233 233 233 234 234 234 234 234 236 70 70 71 + 234 66 164 166 70 70 70 65 233 233 234 64 64 249 68 160 + 73 72 71 237 70 70 69 165 164 250 163 162 161 161 160 160 + 236 70 70 70 70 70 70 237 70 237 71 71 71 71 71 71 + 166 166 166 166 166 70 70 70 70 237 237 71 71 71 71 71 + 67 68 69 69 66 235 234 234 233 233 234 234 69 236 70 71 + 234 234 236 236 236 236 70 70 71 70 70 71 71 71 71 71 + 69 68 69 69 70 70 70 70 70 70 71 71 71 71 71 71 + 70 236 70 70 70 237 71 71 67 66 64 64 104 161 162 162 + 164 164 165 166 166 167 168 168 168 168 72 72 71 71 72 72 + 235 235 234 69 69 236 236 70 70 70 70 237 71 71 73 73 + 250 250 250 164 164 165 69 69 69 70 237 237 71 71 71 71 + 68 69 69 236 236 70 70 70 70 70 237 237 71 72 73 74 + 163 164 164 164 165 165 166 166 166 237 237 237 237 71 71 71 + 250 250 250 250 250 250 69 236 70 70 70 237 237 71 71 72 + 60 61 60 60 60 96 165 160 160 249 249 58 229 229 230 229 + 230 230 230 230 233 234 234 234 234 234 236 236 70 71 71 71 + 68 67 165 166 237 71 71 65 66 234 69 64 249 250 164 160 + 74 73 72 237 237 237 166 166 165 164 163 163 162 162 161 160 + 70 237 237 71 71 71 71 71 71 71 72 73 73 73 74 74 + 166 166 166 167 237 237 237 237 237 237 71 71 72 73 73 73 + 68 69 69 70 67 68 69 236 235 234 235 69 70 70 71 71 + 68 69 236 70 70 70 71 71 71 71 72 73 73 73 73 73 + 166 236 70 70 237 237 237 237 237 71 71 72 72 73 73 73 + 70 70 70 71 71 71 71 72 68 66 162 161 161 162 162 163 + 164 165 166 167 167 168 168 169 169 169 238 238 74 74 74 75 + 69 69 69 236 236 70 70 70 70 237 71 71 73 73 74 75 + 164 164 164 164 165 165 166 166 166 237 237 71 71 72 73 73 + 236 236 70 70 70 70 70 237 71 71 71 73 73 74 74 75 + 164 165 165 165 165 166 166 167 167 168 237 237 71 73 73 73 + 250 164 165 165 165 166 70 237 237 237 71 71 71 72 73 74 + 61 61 61 60 60 165 166 160 104 104 249 58 58 58 230 230 + 233 233 233 234 234 234 234 236 236 236 70 70 71 71 71 71 + 236 68 165 167 72 73 72 65 68 69 70 161 162 163 165 160 + 75 75 73 238 168 168 167 167 165 165 164 164 163 162 161 161 + 237 237 71 71 71 72 72 73 73 73 74 74 75 75 75 75 + 167 167 167 167 168 168 168 238 238 238 238 73 74 74 75 75 + 166 166 237 237 68 69 70 70 68 68 69 70 71 72 73 73 + 236 236 70 70 71 71 71 71 71 73 73 74 75 75 75 75 + 167 167 167 167 237 237 237 71 72 72 73 74 74 75 75 75 + 71 71 71 72 73 73 74 75 166 165 164 162 162 131 132 133 + 134 135 88 90 137 137 137 137 170 170 170 239 75 75 76 75 + 70 70 70 70 70 237 237 71 72 73 74 74 75 75 75 75 + 164 165 165 166 166 166 166 167 237 237 238 238 238 74 75 75 + 70 70 70 237 71 71 71 71 71 73 73 75 75 75 75 75 + 134 134 135 135 135 167 167 168 168 168 238 238 238 74 75 75 + 165 165 166 166 166 167 167 168 72 238 73 73 74 74 75 76 + 17 203 61 61 61 61 167 104 80 104 54 58 59 58 250 236 + 234 234 234 234 234 236 236 236 70 71 71 71 71 73 73 74 + 237 166 166 167 239 75 75 163 236 70 71 162 163 164 166 160 + 76 76 75 239 169 169 168 168 167 166 165 164 164 163 131 80 + 238 238 238 238 238 238 74 74 75 75 75 75 75 75 76 76 + 168 168 168 168 169 169 169 239 239 239 239 239 75 75 75 75 + 168 167 168 238 166 70 237 71 68 236 70 71 73 74 74 75 + 237 237 71 71 71 72 73 73 73 74 75 75 75 75 75 76 + 168 168 169 169 168 169 238 238 238 239 74 75 75 75 76 76 + 238 73 73 74 75 75 75 75 166 166 165 163 131 132 133 134 + 135 40 136 137 138 138 138 138 171 171 171 171 77 77 77 77 + 168 237 237 237 237 72 238 238 74 74 75 75 76 76 76 76 + 165 166 167 167 167 167 168 168 168 169 238 238 239 75 76 76 + 237 70 237 71 72 73 73 74 74 74 75 75 75 75 76 76 + 134 134 135 135 136 136 136 137 169 169 170 170 239 75 76 76 + 166 166 98 98 87 168 169 169 238 238 74 75 75 75 76 77 + 204 204 204 61 61 61 168 49 80 80 55 60 60 59 250 68 + 68 234 236 236 236 70 70 70 71 71 72 73 73 75 75 75 + 72 167 135 136 239 76 75 163 166 237 238 163 164 166 167 160 + 78 77 76 171 171 170 137 137 89 88 135 134 133 132 132 131 + 170 239 239 239 239 75 75 76 76 76 76 76 77 77 77 77 + 169 169 169 170 170 170 171 171 171 171 171 171 76 76 76 76 + 168 169 169 239 61 168 238 73 165 70 237 238 74 75 76 77 + 238 73 73 73 74 74 75 75 76 75 76 76 77 76 76 77 + 169 169 169 170 170 239 239 239 239 239 76 76 76 77 77 77 + 239 239 75 75 76 76 77 77 168 167 165 132 132 133 38 38 + 39 3 92 93 29 94 94 94 139 172 172 172 173 78 78 78 + 169 169 169 169 239 239 239 239 239 239 76 76 77 77 78 78 + 86 87 90 90 90 169 169 169 170 170 170 171 76 76 77 77 + 168 71 238 238 238 74 75 75 75 75 76 76 76 77 78 78 + 39 39 39 244 244 137 137 138 138 138 171 171 171 172 77 78 + 86 86 88 87 21 62 62 239 239 239 239 75 76 76 77 77 + 205 205 204 204 61 168 168 49 80 51 55 60 55 60 60 60 + 236 69 70 71 237 71 72 71 73 73 74 75 75 76 76 76 + 73 168 136 136 170 76 76 164 166 168 239 82 165 167 167 160 + 78 77 76 76 171 170 170 169 136 88 135 135 134 133 133 132 + 239 75 75 75 75 76 76 76 76 76 77 77 77 77 77 77 + 170 170 170 170 170 170 171 76 76 76 76 76 76 77 77 77 + 168 169 239 75 61 237 238 74 70 70 72 73 74 75 76 76 + 73 72 73 73 74 75 75 75 75 75 76 76 77 77 77 77 + 169 169 169 239 239 75 75 239 75 76 76 76 76 77 77 77 + 239 75 75 76 76 76 77 77 168 167 166 133 133 134 135 135 + 136 244 244 138 138 138 139 139 139 172 172 78 77 78 78 78 + 169 238 238 74 74 75 75 75 76 76 76 76 77 77 78 78 + 167 87 168 168 169 169 169 169 239 239 75 76 76 76 77 76 + 73 73 73 73 73 74 75 75 75 76 76 77 77 78 78 78 + 136 244 244 244 137 137 137 137 138 139 139 171 171 77 77 78 + 167 168 168 169 169 62 62 239 75 75 75 75 76 76 77 78 + 23 205 204 61 62 238 238 80 81 96 60 60 60 61 61 70 + 236 69 70 71 71 71 71 71 71 71 74 75 75 76 76 76 + 73 237 169 137 239 76 76 166 167 238 74 163 165 167 168 160 + 70 70 166 164 163 163 163 163 162 162 255 255 128 128 253 105 + 163 250 163 164 164 164 164 165 165 165 165 165 165 166 166 166 + 131 131 131 162 163 164 164 163 165 165 165 165 165 165 165 164 + 162 164 164 163 104 161 162 250 64 249 64 249 250 68 164 68 + 66 65 65 66 66 65 66 66 68 164 164 165 69 69 236 236 + 250 163 163 163 163 164 164 163 164 164 165 165 165 164 165 166 + 163 163 66 69 165 164 164 166 164 161 160 160 105 128 128 130 + 129 130 129 131 131 131 131 131 132 133 133 165 166 167 167 70 + 66 66 65 66 164 164 164 163 165 165 165 165 165 166 166 166 + 162 162 162 162 162 163 164 164 164 163 164 69 69 164 165 69 + 66 66 65 66 65 67 163 163 165 165 165 165 165 166 166 166 + 129 130 129 129 129 131 132 130 130 131 132 164 164 164 166 237 + 162 163 163 162 162 164 164 250 164 164 164 164 165 165 165 166 + 104 55 59 249 162 163 163 105 105 53 52 52 53 53 53 53 + 248 64 65 66 65 65 65 65 65 65 65 66 235 68 68 69 + 235 161 164 161 164 165 164 160 66 67 250 105 162 161 161 160 + 161 162 255 255 255 255 160 128 128 105 105 105 106 106 106 106 + 255 161 160 160 255 255 255 255 255 255 255 255 255 162 162 130 + 131 131 130 129 129 255 255 255 255 255 255 255 255 255 255 255 + 105 160 255 255 160 160 160 161 160 104 160 160 160 161 161 162 + 160 248 64 64 64 64 161 161 161 161 161 161 162 162 162 162 + 160 160 161 161 160 160 255 161 255 255 255 255 255 255 162 162 + 161 161 160 160 255 255 255 162 105 105 105 105 105 253 106 253 + 131 182 180 181 181 180 180 180 180 130 130 130 255 255 162 162 + 160 160 160 160 160 160 160 255 255 255 255 255 255 162 162 162 + 105 105 105 105 105 160 160 160 161 160 160 160 255 161 162 162 + 248 160 160 160 160 160 160 161 255 255 255 162 162 162 162 131 + 130 181 181 182 181 181 182 180 181 131 131 131 255 255 255 161 + 105 160 160 160 160 255 255 255 160 255 255 255 161 162 162 162 + 104 161 104 104 160 255 255 106 105 105 53 53 248 248 160 160 + 248 248 160 248 64 64 64 64 64 64 64 64 64 162 162 163 + 160 162 160 162 255 160 162 105 105 160 160 105 105 105 160 160 + 183 183 182 182 182 182 181 180 180 180 180 180 178 177 176 176 + 180 181 182 182 182 182 182 181 182 182 182 182 183 183 183 182 + 179 179 180 181 181 181 181 182 182 182 182 182 182 182 182 182 + 180 129 130 130 129 130 130 131 128 128 131 132 132 131 132 132 + 162 162 162 162 162 162 131 131 181 181 181 182 182 182 182 182 + 181 182 181 181 182 182 181 181 182 182 182 182 182 182 182 182 + 180 131 132 131 182 183 183 183 183 182 180 177 177 177 178 180 + 179 241 241 241 241 241 241 241 181 182 182 182 182 182 183 183 + 131 131 131 131 131 182 182 181 182 182 182 182 182 183 182 182 + 180 180 180 180 180 181 181 182 181 182 183 182 182 182 183 183 + 131 161 162 131 131 131 131 182 182 182 182 183 182 182 182 182 + 180 241 179 179 241 241 241 241 241 241 241 181 182 182 183 183 + 180 180 180 180 180 180 180 180 182 182 182 182 183 183 182 183 + 129 130 129 130 129 180 180 177 9 106 106 105 105 105 105 105 + 160 161 164 164 162 65 65 65 65 164 163 162 132 131 182 183 + 131 129 182 180 181 183 131 131 131 131 131 106 128 128 130 105 + 186 186 186 186 186 185 183 181 181 181 181 181 181 181 181 181 + 183 185 186 186 186 186 186 186 185 186 186 186 186 186 186 185 + 180 181 183 184 186 186 186 186 186 186 186 186 186 186 186 186 + 181 182 182 182 32 34 35 35 130 129 130 129 130 34 186 188 + 131 131 130 129 130 133 186 187 186 186 186 186 186 186 186 186 + 181 182 181 182 186 187 186 186 186 186 186 186 187 187 186 186 + 182 184 186 186 186 186 186 186 180 180 181 180 181 181 180 181 + 180 180 181 184 185 184 184 184 184 184 185 186 186 186 186 186 + 181 181 181 183 185 187 186 186 186 186 186 186 186 186 186 186 + 181 181 181 182 182 181 181 182 182 184 186 186 186 186 186 186 + 181 180 180 182 184 186 186 185 186 186 186 186 186 186 186 186 + 180 180 180 180 181 181 184 186 185 185 185 186 186 186 186 186 + 181 181 181 182 182 182 182 182 186 186 186 186 186 186 186 187 + 4 38 36 6 33 182 183 180 181 8 8 128 128 129 130 255 + 128 129 255 255 161 162 162 162 163 163 132 134 186 186 186 187 + 182 136 180 186 185 186 186 181 182 181 181 181 182 182 131 129 + 187 186 186 186 185 185 184 183 183 183 182 182 181 181 181 180 + 184 185 185 184 184 185 185 186 186 186 186 186 186 186 186 186 + 183 183 183 184 184 185 185 186 185 185 185 185 186 186 186 186 + 184 184 185 185 35 38 39 39 152 151 134 135 136 41 187 187 + 135 136 137 137 137 244 244 186 186 186 186 186 186 186 186 186 + 183 185 184 184 185 185 184 185 185 185 185 186 186 186 186 186 + 185 185 186 186 186 187 187 186 183 182 182 180 180 181 180 182 + 182 182 183 118 120 118 117 117 118 120 120 121 187 187 187 187 + 183 183 184 184 184 184 184 184 185 185 185 186 186 186 186 187 + 183 182 183 184 184 183 183 184 184 185 185 186 186 121 187 186 + 184 184 184 184 185 185 186 186 186 186 186 186 186 187 187 187 + 183 183 183 183 182 182 183 183 184 184 184 185 186 186 187 187 + 183 182 183 183 183 183 184 184 184 185 185 185 186 186 186 187 + 5 202 202 203 4 185 184 179 8 8 7 150 149 150 50 50 + 82 83 96 96 165 166 167 167 167 167 136 244 186 186 186 186 + 184 185 184 184 187 186 186 180 182 183 244 8 182 33 38 8 + 189 188 187 187 186 186 186 186 184 184 184 184 183 35 33 32 + 187 187 187 244 187 188 188 188 188 188 188 188 188 188 188 188 + 187 186 186 186 186 186 187 187 187 187 188 188 188 188 125 189 + 4 41 244 92 38 154 91 23 18 17 86 99 23 26 139 139 + 136 137 137 137 137 137 138 139 94 188 188 188 188 189 189 189 + 4 244 244 244 244 244 186 188 187 188 188 188 188 188 189 189 + 244 43 137 138 188 188 188 189 4 37 37 35 34 183 183 183 + 184 185 185 122 124 123 123 123 124 124 124 125 125 189 126 189 + 185 244 244 244 244 244 244 187 188 188 188 188 188 188 189 126 + 184 5 184 185 185 185 186 187 187 187 187 187 187 188 188 189 + 185 244 244 244 244 244 187 188 188 188 188 188 189 189 189 189 + 184 184 185 186 185 186 187 186 187 187 187 187 188 188 125 126 + 4 4 4 244 244 244 244 187 187 188 188 188 125 125 125 127 + 204 204 203 202 202 41 244 32 7 149 150 151 152 152 16 16 + 55 61 61 61 61 61 72 168 169 170 170 138 188 188 188 189 + 137 137 185 186 186 188 188 37 135 135 135 34 35 38 135 149 + 173 173 172 172 171 170 137 136 137 88 134 84 133 84 152 151 + 62 62 239 239 76 76 75 76 76 77 77 77 77 78 78 77 + 23 100 24 26 246 246 246 246 246 246 139 172 172 140 140 172 + 136 136 137 169 84 88 169 169 97 61 166 168 238 239 75 77 + 238 238 74 74 74 74 75 75 75 75 75 75 76 76 76 76 + 169 169 169 62 170 170 170 171 171 171 171 171 172 77 77 77 + 62 239 75 76 76 77 77 78 169 84 84 84 37 37 38 38 + 40 155 42 26 28 157 172 139 139 172 173 172 172 173 78 78 + 90 168 168 169 169 170 170 170 239 171 76 77 173 172 173 78 + 135 88 136 90 90 87 90 90 169 246 171 63 171 171 77 77 + 169 169 169 239 239 75 239 239 239 75 76 76 76 76 77 78 + 244 186 244 244 137 137 138 137 138 138 246 245 63 173 173 173 + 85 18 20 21 21 22 23 62 62 245 245 63 77 77 77 173 + 205 205 204 204 21 62 23 150 150 50 50 55 55 60 16 61 + 61 61 60 60 61 73 73 238 238 238 74 74 75 76 76 77 + 168 88 137 138 103 63 78 84 98 238 74 50 85 85 87 48 + 254 48 253 253 106 106 253 253 106 252 252 252 252 252 252 251 + 105 105 105 105 105 105 105 48 48 48 48 48 48 48 48 48 + 144 253 253 144 144 253 253 106 106 253 253 253 146 146 146 48 + 105 106 105 105 252 106 105 105 252 247 247 105 105 105 105 48 + 105 105 105 105 105 105 248 248 160 160 160 160 160 160 53 53 + 105 105 105 105 105 105 105 105 105 105 105 48 48 48 48 48 + 105 105 105 105 105 48 48 48 105 252 252 252 252 252 252 252 + 252 106 144 144 144 106 144 106 253 253 146 128 253 128 48 254 + 105 105 105 105 105 105 105 105 105 105 105 48 48 48 48 254 + 252 252 106 105 105 105 105 105 105 105 105 105 253 253 48 48 + 105 105 247 105 105 105 105 105 105 105 160 160 160 160 160 254 + 252 107 252 106 253 106 253 253 253 106 106 253 253 146 146 48 + 252 106 106 105 105 105 105 105 105 253 253 253 48 48 48 48 + 144 193 144 144 144 144 144 251 251 252 247 247 247 247 247 52 + 52 52 52 247 247 105 105 105 105 105 105 105 160 104 53 53 + 105 106 106 253 144 48 48 252 252 247 52 252 252 251 105 48 + 81 81 81 80 49 254 48 253 105 106 106 105 105 106 252 252 + 104 249 249 104 104 104 104 104 104 249 249 249 249 249 249 162 + 105 105 105 48 160 255 255 129 255 255 254 80 80 80 80 80 + 105 248 248 160 247 248 248 248 248 248 248 248 53 249 249 249 + 160 160 160 104 64 104 104 104 104 161 162 162 162 162 81 163 + 160 160 160 160 160 160 104 104 104 104 104 104 161 162 162 162 + 160 104 64 160 104 161 162 162 105 247 105 106 106 106 106 106 + 106 253 253 128 129 128 129 254 254 254 254 254 80 81 81 81 + 160 160 248 248 160 104 161 161 161 161 161 162 162 162 162 163 + 105 105 105 105 48 48 48 48 48 48 254 254 254 49 80 81 + 105 248 160 160 160 104 104 104 160 161 162 162 162 162 162 163 + 106 106 106 105 105 128 160 160 255 255 255 255 255 130 130 81 + 105 105 105 105 48 105 105 48 48 104 49 48 48 49 81 51 + 195 196 214 48 53 53 52 106 252 247 247 247 52 56 247 52 + 56 56 52 52 53 248 53 248 64 64 64 64 249 249 249 249 + 160 105 128 130 80 81 54 105 248 53 249 247 105 105 160 104 + 97 96 82 81 80 80 49 254 254 48 253 253 253 105 106 105 + 163 250 250 250 250 250 250 250 250 250 250 250 250 68 165 165 + 80 80 80 80 81 81 81 81 81 81 81 82 82 82 96 96 + 104 249 249 249 53 53 104 249 248 58 249 249 249 250 250 250 + 161 249 249 249 162 250 250 250 250 250 250 250 96 96 165 165 + 104 104 161 162 162 162 162 162 250 250 250 250 250 250 164 250 + 250 66 66 66 250 164 164 164 104 160 160 105 105 253 253 128 + 128 128 129 130 131 130 131 82 82 82 82 83 83 83 84 96 + 161 162 162 249 249 249 65 65 250 250 250 250 164 164 165 96 + 48 48 48 48 49 49 49 49 49 80 50 81 81 82 83 83 + 161 64 249 249 249 250 250 250 250 250 250 250 164 164 165 165 + 254 128 128 254 80 162 162 255 162 163 163 163 132 133 133 165 + 105 105 48 48 104 49 49 49 49 54 96 51 51 96 97 97 + 214 214 214 214 54 54 54 105 52 247 247 247 56 56 56 57 + 57 57 57 58 58 249 249 249 64 65 66 66 250 250 67 67 + 162 161 130 132 80 82 96 160 249 249 249 105 160 160 104 104 + 62 61 18 17 17 83 83 82 150 149 254 254 254 253 253 253 + 165 165 96 96 165 165 166 165 166 166 166 166 166 61 61 167 + 82 82 82 82 82 132 83 84 85 85 98 98 19 19 61 61 + 51 96 163 96 54 55 250 250 54 59 54 250 60 60 61 166 + 163 164 164 163 164 164 165 70 70 70 61 61 61 61 61 61 + 163 250 96 96 165 165 165 165 165 165 166 166 166 166 61 61 + 96 250 164 165 166 166 166 61 163 162 104 48 253 147 148 149 + 150 150 151 152 153 153 85 86 153 17 17 18 19 61 61 61 + 51 96 96 96 164 164 165 165 165 166 166 166 166 61 168 61 + 49 54 54 51 51 51 51 51 51 83 97 98 98 98 87 168 + 96 250 250 250 250 164 165 96 237 237 166 166 61 61 61 61 + 130 131 132 132 132 132 83 133 133 133 134 135 135 135 86 88 + 80 81 51 51 96 51 51 51 96 97 61 61 97 61 61 61 + 50 54 55 55 55 51 81 105 105 105 53 53 58 58 57 59 + 59 58 58 64 66 67 67 250 250 68 69 236 70 237 237 237 + 164 163 132 135 85 86 167 255 161 165 165 105 160 255 162 104 + 144 144 144 144 106 252 107 107 107 251 251 251 14 215 215 215 + 252 252 252 252 106 106 253 253 106 144 144 144 144 253 253 144 + 252 252 252 252 252 252 252 106 106 106 106 106 106 144 144 144 + 252 252 251 252 251 252 252 252 252 252 252 252 106 106 106 253 + 252 252 252 252 252 252 252 106 105 105 105 144 144 144 144 144 + 252 252 252 252 252 252 252 252 106 106 106 106 144 144 253 253 + 252 252 252 106 106 144 144 253 252 251 251 216 215 14 13 13 + 13 12 12 107 11 11 11 11 10 10 10 144 144 144 144 144 + 252 252 252 252 252 252 252 252 252 106 106 106 106 144 144 144 + 251 251 251 252 252 252 252 252 252 252 252 106 106 106 144 144 + 252 252 252 252 252 252 252 252 106 106 144 144 144 144 144 144 + 13 13 13 13 107 107 107 107 107 252 11 106 106 106 144 144 + 251 251 251 252 252 252 252 252 252 252 106 106 106 144 144 144 + 144 252 144 252 252 252 252 215 215 216 216 216 216 217 217 218 + 247 247 247 247 247 252 247 247 252 252 252 252 106 105 105 106 + 252 251 107 10 11 106 106 251 251 252 252 216 251 251 252 48 + 147 146 145 145 144 144 144 144 106 252 107 107 107 251 251 251 + 144 144 106 106 144 253 253 253 253 253 253 253 253 253 146 146 + 144 10 144 144 144 144 144 144 144 145 145 145 145 145 146 146 + 144 144 144 144 252 144 144 144 252 106 144 144 106 144 145 146 + 253 106 106 105 253 106 253 253 48 48 48 48 48 147 147 147 + 144 144 144 144 144 144 144 144 144 144 144 145 145 146 146 146 + 144 144 144 144 253 146 146 146 106 252 252 251 13 12 12 11 + 11 10 10 10 10 9 9 9 8 8 8 8 8 8 147 147 + 144 144 144 144 144 144 144 144 144 144 145 146 146 146 146 147 + 107 252 106 106 144 144 144 144 144 144 145 145 145 146 146 146 + 144 106 106 106 106 144 106 106 253 146 147 147 147 147 147 147 + 12 11 10 10 11 10 10 9 10 9 9 9 146 146 147 147 + 107 252 11 144 144 144 144 144 144 145 145 145 145 146 147 147 + 194 192 193 192 192 144 144 251 251 251 252 252 247 247 247 247 + 52 247 247 247 247 247 247 247 105 105 106 105 253 128 128 128 + 253 106 9 8 9 9 9 252 107 106 106 251 107 252 253 254 + 50 49 254 148 147 253 253 253 144 144 106 106 106 106 252 251 + 128 48 48 48 48 148 147 147 148 149 149 149 149 149 150 150 + 145 145 146 146 146 147 147 147 147 148 148 148 148 148 149 149 + 253 253 48 146 144 144 253 48 106 144 253 48 48 48 148 254 + 253 48 253 253 128 128 48 48 49 49 49 49 254 254 130 130 + 253 146 48 48 48 48 147 147 147 147 147 148 149 150 150 149 + 147 48 48 48 148 149 150 149 253 106 106 252 252 11 10 10 + 10 9 9 8 8 8 8 8 7 7 7 7 7 149 149 150 + 253 253 48 48 48 146 48 147 147 147 147 254 149 149 149 150 + 106 106 144 253 253 253 253 146 146 147 48 148 148 149 149 49 + 48 48 48 48 48 48 254 254 48 254 254 254 254 49 80 131 + 10 10 10 9 9 8 8 9 8 8 8 148 148 149 149 149 + 144 144 144 145 145 145 146 146 147 147 148 148 148 149 149 149 + 195 194 194 193 145 146 146 107 251 251 252 252 247 52 247 247 + 247 52 52 52 248 248 160 160 160 160 160 255 254 254 130 130 + 128 128 128 8 8 7 129 106 106 253 253 106 106 106 106 48 + 82 82 82 81 80 254 254 48 48 253 253 105 105 105 106 106 + 254 80 80 80 81 81 82 81 81 82 82 82 82 83 83 83 + 48 48 254 254 49 80 80 80 80 81 81 80 81 82 82 81 + 48 104 80 255 48 48 255 255 105 105 105 255 80 80 130 81 + 255 162 162 255 162 163 81 81 82 96 96 51 81 163 163 164 + 48 48 254 255 80 80 80 80 80 80 81 81 82 83 83 83 + 80 80 80 80 81 82 83 83 160 105 105 106 106 253 253 253 + 128 128 129 254 130 131 131 131 131 131 131 131 82 82 83 83 + 48 104 80 80 80 80 80 81 81 81 82 82 82 83 83 83 + 128 128 48 48 48 48 254 254 49 80 80 80 81 81 82 82 + 255 255 255 255 80 80 80 80 81 81 82 81 163 163 164 164 + 253 128 128 129 128 128 129 129 130 130 131 131 131 81 82 82 + 253 253 253 48 48 254 254 49 49 80 80 81 82 83 84 97 + 148 147 147 48 48 48 48 106 106 106 106 247 52 53 248 248 + 52 52 52 53 104 104 104 104 162 162 163 163 163 81 131 132 + 255 255 128 129 131 83 82 105 48 49 49 106 106 253 160 104 + 160 160 160 160 160 160 104 48 48 48 160 160 160 160 160 160 + 160 104 104 160 160 160 104 104 104 104 48 48 48 254 254 48 + 160 104 104 104 160 160 160 160 160 160 160 160 160 160 160 160 + 160 160 160 160 160 160 104 160 160 104 160 160 160 160 160 160 + 160 160 160 160 160 160 160 104 48 48 104 104 160 160 160 160 + 160 160 160 160 160 160 160 160 160 160 104 160 48 48 48 104 + 48 160 160 104 104 48 48 104 160 160 160 160 128 128 128 129 + 128 254 129 128 128 128 128 128 128 128 128 128 160 160 160 160 + 160 160 160 160 160 160 160 160 48 160 160 128 160 160 104 160 + 160 48 104 104 160 48 48 48 160 160 160 160 160 128 128 160 + 160 160 160 160 160 160 48 48 160 160 160 160 160 160 160 160 + 128 128 128 128 128 128 128 128 128 128 128 128 128 160 160 160 + 160 128 128 128 160 160 160 160 160 160 160 160 160 160 160 48 + 48 49 49 48 48 48 49 48 128 128 160 160 53 53 160 104 + 104 160 104 160 104 160 160 160 104 160 160 160 160 160 128 128 + 160 160 128 128 128 48 49 53 104 53 104 48 104 160 160 160 +])) + +data diff --git a/demo/mod/colormap.fnl b/demo/mod/colormap.fnl new file mode 100644 index 0000000..937abb9 --- /dev/null +++ b/demo/mod/colormap.fnl @@ -0,0 +1,1031 @@ +(require :pxl8) +(local ffi (require :ffi)) + +(local data (ffi.new "u8[16384]" [ + 254 254 48 48 48 253 253 253 253 144 106 106 106 252 252 252 + 253 253 48 48 48 48 48 48 48 48 48 48 48 254 254 254 + 253 253 253 253 253 253 253 128 128 48 48 48 48 48 48 254 + 253 105 253 253 105 105 105 105 105 105 105 105 48 48 48 48 + 105 105 105 105 128 105 48 48 48 49 49 48 48 254 254 254 + 253 253 253 253 253 253 253 48 48 48 48 48 48 48 254 254 + 253 48 48 48 48 48 254 254 105 105 106 252 252 106 106 10 + 10 9 9 9 8 8 8 8 128 128 128 147 148 148 254 49 + 253 253 253 253 253 253 48 48 48 48 48 48 48 254 254 254 + 106 106 253 253 253 253 253 253 253 253 48 48 48 48 48 254 + 105 105 105 105 253 48 48 48 48 48 48 254 254 254 254 254 + 106 10 9 9 9 9 253 253 253 253 128 128 128 128 254 254 + 106 106 144 253 253 253 253 253 253 48 48 48 48 48 254 49 + 145 145 145 145 145 145 253 252 252 252 252 247 247 52 247 52 + 52 52 52 52 248 248 248 248 248 105 160 160 160 104 254 129 + 105 105 253 128 128 128 129 106 105 105 105 252 106 106 105 160 + 84 84 82 151 150 254 254 254 128 146 253 253 253 253 106 106 + 80 81 81 81 81 81 51 82 82 83 83 83 83 83 83 83 + 254 254 254 254 130 130 130 131 131 131 131 151 152 152 152 83 + 254 104 255 80 105 48 104 104 53 53 53 104 54 54 51 96 + 161 161 162 162 162 162 162 163 163 164 164 96 96 83 83 84 + 49 49 49 80 80 80 80 80 81 81 81 82 83 83 83 96 + 80 81 162 163 82 83 83 83 160 105 105 253 144 253 253 253 + 146 147 148 149 150 150 150 150 151 151 152 152 152 84 84 84 + 254 255 255 255 255 162 162 162 162 81 163 83 83 83 84 84 + 253 48 48 48 254 49 254 254 254 49 50 50 151 151 152 84 + 49 255 255 161 162 162 162 162 163 163 164 83 83 83 84 84 + 128 8 128 128 129 254 130 130 130 130 131 131 132 132 133 133 + 253 48 48 49 49 49 49 49 49 50 51 51 82 83 83 16 + 214 214 214 214 214 49 254 106 106 106 52 52 52 52 52 53 + 58 53 53 53 53 104 249 161 162 162 162 163 164 164 164 164 + 80 129 129 36 131 152 83 253 48 104 80 105 105 105 104 104 + 186 186 185 184 184 184 183 182 182 182 182 181 180 180 180 179 + 183 184 184 184 184 184 184 185 185 185 185 185 185 185 185 185 + 183 183 183 184 184 184 184 184 185 185 185 185 185 185 185 185 + 35 132 132 133 130 131 132 133 130 80 132 132 133 133 135 136 + 164 164 164 164 164 134 135 135 135 185 185 185 185 185 185 185 + 35 132 132 35 184 184 184 184 184 184 184 185 185 185 185 186 + 133 134 135 135 185 185 186 185 131 131 129 180 180 180 180 181 + 182 182 182 183 184 183 184 184 184 184 185 185 185 185 186 186 + 132 132 132 133 133 134 184 184 185 185 185 185 185 185 185 186 + 34 34 34 34 35 35 35 183 184 184 184 184 185 185 185 185 + 132 132 132 133 133 134 135 135 184 185 185 185 185 186 186 185 + 182 182 182 182 182 182 183 183 184 184 184 184 185 185 185 186 + 34 34 34 35 35 35 35 35 184 185 184 185 185 185 185 244 + 37 153 151 152 36 35 183 8 128 128 128 254 254 254 80 255 + 255 162 163 163 163 164 164 164 164 164 165 134 135 135 185 186 + 132 133 183 184 184 185 135 130 131 132 133 128 130 130 132 128 + 239 239 169 168 168 167 167 166 165 133 133 132 131 130 130 129 + 167 237 168 168 168 168 168 238 238 238 238 238 238 238 239 239 + 166 167 167 167 167 167 168 168 168 168 169 169 169 169 169 238 + 165 166 167 167 164 165 166 70 250 68 69 70 237 71 238 238 + 69 69 69 70 70 70 237 237 71 71 238 238 238 238 238 239 + 166 166 167 167 167 167 168 168 168 168 238 238 238 238 238 238 + 237 237 237 71 238 238 238 238 165 164 163 162 130 131 131 132 + 133 134 135 135 136 136 136 136 137 137 137 170 170 239 239 239 + 166 166 166 237 237 237 237 168 168 238 238 238 238 239 239 239 + 164 165 165 165 165 166 166 166 167 167 168 168 169 238 238 238 + 69 69 69 70 70 237 237 237 71 238 238 238 238 239 239 170 + 133 133 134 134 134 135 135 135 135 136 136 168 169 169 239 239 + 164 165 165 165 166 166 167 167 168 168 168 238 238 238 238 239 + 17 19 17 97 97 166 166 104 255 80 54 54 59 59 250 250 + 66 66 234 69 69 69 69 69 236 70 70 237 71 71 238 73 + 70 165 166 135 168 238 238 163 165 70 237 255 163 164 165 160 + 71 71 237 70 70 236 69 68 250 250 162 162 162 161 160 160 + 236 236 236 70 70 70 70 70 70 70 71 71 71 71 71 71 + 165 165 69 69 236 236 70 70 70 70 70 71 71 71 71 71 + 67 68 69 69 66 234 234 234 232 233 233 234 234 236 70 70 + 234 234 234 234 236 236 236 70 70 70 70 71 71 71 71 71 + 68 68 69 69 69 236 236 236 70 70 70 71 71 71 71 71 + 236 236 70 70 70 71 71 71 67 66 65 64 160 161 162 162 + 163 164 165 166 166 167 168 168 168 237 71 71 72 72 71 71 + 68 235 68 69 69 69 236 236 70 70 70 71 71 71 72 72 + 250 250 250 250 250 68 68 69 69 236 70 70 70 71 71 71 + 68 234 69 236 236 236 70 70 70 70 70 70 71 71 72 73 + 163 163 164 164 164 165 165 166 236 70 70 70 70 71 71 71 + 250 250 250 250 250 250 69 69 70 70 70 71 71 71 71 72 + 60 60 60 60 60 60 165 53 53 53 58 58 228 228 229 229 + 230 230 230 230 233 234 234 234 234 234 236 236 70 71 71 71 + 68 67 164 166 237 71 71 65 233 234 69 64 249 250 165 160 + 67 67 66 249 249 58 58 58 53 57 57 52 52 52 52 52 + 229 229 229 229 230 230 230 230 233 233 233 233 233 233 233 233 + 58 58 58 58 58 249 249 249 249 249 249 249 66 66 66 233 + 227 227 231 228 227 227 228 229 226 227 228 228 229 229 230 230 + 228 228 229 229 229 229 229 230 230 230 230 230 230 233 233 233 + 58 58 58 58 249 231 231 232 232 232 232 233 233 233 233 233 + 229 229 229 230 230 230 233 230 227 227 56 248 52 248 248 248 + 53 53 58 58 249 59 59 59 59 59 250 250 250 250 67 67 + 58 231 231 231 231 231 231 232 230 230 233 233 233 233 233 234 + 57 57 58 58 58 58 58 58 58 58 249 249 249 66 66 233 + 231 228 229 229 229 229 229 230 230 230 230 230 233 233 233 233 + 248 248 53 53 53 64 249 249 249 249 249 249 66 66 66 67 + 57 57 57 58 58 58 58 58 58 58 249 249 249 66 233 67 + 58 58 58 58 58 58 58 52 56 56 225 225 225 226 226 226 + 226 226 226 227 228 228 228 228 229 229 229 229 230 230 230 230 + 231 231 64 249 250 250 233 56 227 228 229 56 56 57 53 53 + 58 57 57 57 56 56 56 56 56 56 56 221 221 219 219 219 + 56 56 56 56 56 57 57 57 57 57 57 57 57 57 57 57 + 56 56 56 56 56 56 56 56 57 57 57 57 57 57 57 57 + 56 225 225 225 222 224 225 225 222 224 224 225 225 56 57 227 + 225 225 225 225 226 226 226 227 227 227 227 227 227 227 227 227 + 56 56 56 56 56 56 56 56 57 56 57 57 57 57 57 57 + 56 56 56 56 57 57 57 57 225 223 222 219 219 219 219 56 + 52 56 56 56 56 56 57 57 57 57 57 57 57 57 57 57 + 56 56 56 56 56 56 56 56 57 57 57 57 57 57 57 57 + 222 223 223 225 225 225 225 56 56 56 57 57 57 57 57 57 + 225 225 225 225 225 225 226 226 227 227 227 57 57 57 57 57 + 52 52 52 52 52 56 56 56 56 56 57 57 57 57 57 57 + 222 222 223 225 225 225 56 56 56 56 56 57 57 57 57 57 + 222 222 222 223 223 225 223 219 219 220 220 220 221 221 221 222 + 224 224 224 224 224 224 225 225 226 226 226 227 227 227 227 227 + 225 56 56 57 57 57 57 222 224 225 225 219 221 222 56 58 + 144 106 106 106 106 252 252 252 252 217 217 217 217 217 217 216 + 247 247 247 247 247 247 247 247 247 247 52 52 52 52 52 144 + 252 252 252 252 252 252 252 252 106 106 106 106 106 106 144 106 + 252 247 247 247 217 218 247 52 218 218 218 247 247 247 247 247 + 247 247 247 247 247 247 247 247 247 247 247 247 247 247 52 52 + 252 247 247 247 247 247 247 247 247 247 247 52 247 247 247 52 + 247 247 247 247 247 247 52 52 247 217 217 217 216 216 216 217 + 251 252 252 252 252 252 252 106 106 106 144 144 144 144 144 52 + 252 247 247 247 247 247 247 247 247 247 247 247 247 52 144 52 + 217 217 218 252 252 252 252 252 252 252 106 106 106 106 106 247 + 247 247 247 247 247 247 247 247 247 247 247 247 247 52 52 144 + 251 251 251 251 252 252 252 252 252 252 252 106 106 144 144 144 + 217 217 217 218 252 252 247 247 247 247 247 247 247 247 52 52 + 218 218 218 218 218 247 252 216 216 217 217 218 218 218 218 218 + 218 218 218 219 219 247 247 247 247 247 247 247 247 247 247 247 + 247 252 252 252 106 144 144 217 217 247 247 216 217 217 252 160 + 198 197 196 195 195 195 194 194 194 193 193 193 192 192 192 192 + 195 195 195 195 195 195 195 195 196 196 196 196 196 197 197 197 + 194 194 194 194 195 195 195 195 195 195 195 195 196 196 197 196 + 194 194 194 195 193 194 194 195 194 194 194 194 195 195 195 196 + 195 196 196 195 195 196 196 196 196 196 196 196 196 197 197 197 + 194 194 194 195 195 195 195 195 195 195 195 196 196 196 197 197 + 195 195 195 195 196 196 197 197 193 193 192 192 192 192 192 193 + 193 193 194 194 194 195 195 195 195 196 196 196 197 197 197 198 + 194 194 194 195 195 195 195 195 195 195 196 196 197 197 197 198 + 193 193 194 194 194 194 194 194 195 195 195 195 195 196 196 197 + 194 195 195 195 195 195 195 196 196 196 196 196 197 197 197 198 + 193 193 193 193 194 194 194 194 195 195 195 195 196 196 197 197 + 193 194 194 194 194 194 194 194 195 195 195 196 196 196 197 198 + 194 211 212 194 194 194 194 12 12 192 192 192 193 194 194 144 + 144 145 145 146 146 146 145 146 147 147 214 214 214 196 197 199 + 146 146 9 8 195 196 197 192 194 194 195 192 192 193 144 129 + 203 203 202 201 201 201 201 201 213 213 213 213 213 213 213 213 + 201 201 201 201 201 201 201 201 202 202 202 202 202 203 203 203 + 201 201 201 201 201 201 201 202 202 202 202 202 202 202 203 203 + 213 201 201 201 213 213 201 201 213 213 213 201 201 201 202 203 + 201 201 201 201 202 202 202 202 202 202 202 202 202 203 203 203 + 201 201 201 201 201 201 201 202 202 202 202 202 202 202 202 203 + 201 201 202 202 202 202 203 203 201 213 213 213 213 213 213 213 + 213 201 201 201 201 201 201 201 201 201 202 202 202 203 203 203 + 201 201 201 201 201 201 201 201 202 202 202 202 202 202 203 203 + 213 213 213 213 201 201 201 201 201 201 201 202 202 202 203 203 + 201 201 201 201 201 201 202 202 202 202 202 202 202 203 203 203 + 201 201 201 201 201 201 201 201 201 201 201 202 202 202 203 203 + 213 213 213 213 213 213 201 201 201 201 202 202 201 201 202 203 + 210 210 210 211 210 211 201 212 213 213 213 213 213 213 213 213 + 213 213 213 213 213 201 201 201 202 202 202 202 202 202 202 202 + 201 201 200 3 201 203 203 213 201 201 201 213 213 201 200 49 + 207 207 206 101 156 42 155 41 40 153 153 152 152 151 150 149 + 23 205 205 205 205 205 206 206 206 206 206 206 207 207 207 207 + 41 41 3 3 3 42 156 156 156 101 101 206 206 206 206 207 + 154 20 21 21 16 18 21 61 96 97 61 21 21 205 206 245 + 87 168 168 169 169 169 169 239 170 171 63 63 207 207 207 207 + 20 21 21 21 23 23 23 205 205 206 206 206 206 206 207 207 + 23 62 206 206 206 206 207 207 98 84 152 151 150 36 37 37 + 38 39 41 3 43 43 93 44 2 31 45 102 102 102 207 207 + 99 99 90 90 22 62 62 62 246 246 245 245 207 207 207 207 + 153 202 202 202 203 203 20 204 204 204 205 205 206 206 207 207 + 20 87 90 169 169 62 62 246 246 245 245 207 207 207 207 102 + 38 184 4 4 39 41 3 3 3 43 44 44 157 157 63 207 + 152 202 202 202 203 203 204 204 205 205 205 206 206 206 207 207 + 203 203 203 203 203 203 204 197 199 199 198 200 54 59 60 60 + 60 60 60 60 61 61 61 72 168 238 238 239 239 245 63 63 + 168 167 136 244 101 206 206 83 17 19 62 150 152 153 98 48 + 202 201 201 152 200 150 150 149 148 147 147 146 145 145 144 144 + 200 200 200 200 200 201 201 201 201 201 201 201 201 201 201 202 + 199 150 150 150 150 150 200 200 200 200 200 201 201 201 201 201 + 197 197 197 200 214 214 214 214 48 53 214 214 200 200 201 201 + 49 50 50 50 51 51 51 83 16 16 16 201 201 201 201 202 + 199 198 198 198 200 200 200 200 200 200 200 201 201 201 201 202 + 151 151 200 201 201 201 201 202 149 147 146 145 144 145 146 146 + 147 148 149 150 36 36 36 36 152 152 152 153 153 153 202 202 + 149 149 150 150 150 151 151 151 152 151 152 201 201 201 201 202 + 196 196 196 197 197 197 197 198 198 200 200 200 201 201 201 202 + 49 49 50 50 50 51 51 152 152 152 201 201 201 202 202 202 + 8 8 7 7 7 33 33 6 150 151 151 152 152 153 153 153 + 195 196 196 197 197 197 198 198 200 200 201 201 201 201 201 202 + 212 212 213 213 214 197 197 192 144 144 194 194 53 53 53 53 + 53 53 53 58 54 54 54 55 54 51 51 51 83 16 16 16 + 50 130 129 35 200 201 16 146 48 49 50 144 146 147 148 48 + 153 152 152 151 150 150 149 148 147 147 146 145 145 144 10 10 + 199 199 198 198 200 200 200 200 152 152 152 152 152 152 152 152 + 148 149 199 149 149 150 150 150 150 151 151 151 151 152 152 152 + 148 199 199 149 146 147 197 199 48 48 149 149 199 198 200 152 + 149 49 49 80 50 50 50 82 152 152 152 152 152 152 152 153 + 149 149 149 199 150 150 150 150 150 151 151 151 152 152 152 152 + 150 150 151 200 152 152 152 152 148 146 145 144 144 145 145 8 + 8 8 7 7 33 6 6 6 6 6 36 37 152 152 153 153 + 148 148 149 149 150 150 150 150 151 151 151 152 152 152 153 153 + 146 195 196 196 148 148 148 149 199 199 150 151 151 152 152 152 + 149 49 49 49 150 50 151 151 151 151 152 152 152 152 153 5 + 8 8 8 8 32 32 7 7 7 150 151 151 151 152 37 153 + 146 195 196 196 196 196 199 199 198 198 200 200 200 201 201 201 + 213 213 213 214 196 148 199 10 144 144 144 145 145 52 52 53 + 53 53 53 53 54 54 54 54 80 50 50 50 151 152 152 152 + 254 129 129 34 6 152 152 146 48 254 150 144 145 146 148 48 + 189 189 188 187 187 187 186 4 4 38 5 37 35 35 33 33 + 3 43 43 43 43 44 2 2 2 2 94 189 188 189 189 189 + 186 186 186 186 186 244 187 187 187 187 188 188 188 188 189 94 + 39 41 244 3 38 40 41 91 84 85 86 89 91 26 29 94 + 136 136 136 137 137 170 246 246 246 138 94 94 45 189 189 189 + 41 3 3 3 3 3 43 43 43 43 188 188 188 188 189 189 + 43 25 93 93 29 94 94 103 39 38 37 35 34 34 34 184 + 184 185 185 186 186 187 187 187 187 124 188 188 188 189 189 189 + 39 39 41 42 42 42 43 43 43 2 188 188 188 189 189 189 + 38 38 4 4 39 39 3 3 3 3 43 2 188 188 188 189 + 39 136 91 137 92 24 27 138 138 29 188 188 189 189 189 189 + 184 184 184 184 185 185 185 186 186 187 187 187 188 188 188 189 + 5 38 4 4 39 41 3 3 43 43 44 2 2 94 95 158 + 203 203 202 203 154 155 155 7 7 150 150 150 151 51 96 96 + 97 97 97 98 167 167 168 168 169 169 170 170 246 139 45 139 + 136 134 244 186 124 125 95 37 38 136 137 34 5 4 135 128 + 185 184 184 184 183 183 182 181 181 180 180 180 8 112 112 112 + 35 35 35 35 183 184 184 184 184 184 184 184 184 184 184 184 + 182 182 182 182 182 183 183 183 183 183 184 184 184 184 184 185 + 33 34 34 35 7 33 34 35 7 7 33 34 35 5 184 185 + 34 35 35 35 37 37 5 5 5 184 185 185 185 185 184 185 + 33 34 34 34 35 35 183 183 184 184 184 184 184 184 184 185 + 35 35 5 184 184 185 185 185 33 32 8 9 112 179 179 180 + 181 181 182 182 182 183 183 183 183 184 184 184 184 184 185 185 + 33 33 34 34 35 35 183 183 184 184 184 184 184 184 185 185 + 32 32 32 33 33 33 33 34 34 183 184 184 184 184 184 185 + 33 34 35 35 35 37 5 5 5 184 184 184 184 185 185 185 + 180 180 181 181 181 182 182 182 182 183 183 183 184 184 184 185 + 32 32 33 33 33 34 6 34 35 35 5 184 184 184 185 185 + 6 6 33 33 33 34 34 10 9 9 9 145 146 147 148 147 + 49 49 49 80 131 131 132 132 132 132 37 37 5 184 185 185 + 131 130 34 182 184 184 185 8 32 34 35 9 8 32 130 128 + 183 182 182 181 181 181 180 179 179 178 178 178 177 111 110 110 + 181 181 181 181 182 182 182 182 182 182 182 182 182 182 182 182 + 180 180 180 180 180 181 181 181 181 181 181 182 182 182 182 182 + 180 180 180 181 112 8 8 33 9 8 8 8 32 182 182 183 + 32 32 32 32 33 182 182 182 182 182 182 182 182 182 182 182 + 180 181 180 181 181 181 181 181 181 182 182 182 182 182 182 183 + 181 181 181 182 182 182 182 183 113 112 112 111 110 177 177 178 + 178 179 179 180 180 181 181 181 181 182 182 182 182 182 182 183 + 180 180 180 180 181 181 181 181 182 181 182 182 182 182 183 183 + 112 113 113 180 180 180 180 180 180 181 181 181 182 182 182 182 + 180 181 181 181 181 181 181 182 182 182 182 182 182 182 183 183 + 178 178 178 179 179 179 180 180 180 181 181 181 182 182 182 183 + 112 112 113 113 113 181 181 181 181 181 181 182 182 182 182 183 + 114 114 114 113 113 113 114 110 110 110 10 10 10 144 144 145 + 253 253 128 128 128 128 7 7 32 33 33 182 182 182 182 183 + 32 8 179 181 181 182 183 10 8 7 33 110 111 113 32 128 + 141 1 103 94 29 93 43 3 39 4 38 5 5 35 35 6 + 93 28 28 28 28 94 139 139 139 139 139 140 140 140 140 140 + 3 3 3 43 43 93 44 29 29 94 94 94 45 103 140 103 + 41 42 24 24 85 88 22 62 16 98 20 21 62 171 171 172 + 169 169 169 170 170 171 171 171 172 172 172 172 172 140 140 140 + 42 92 92 25 27 138 138 138 28 94 139 139 139 140 140 140 + 246 171 171 171 139 103 140 140 136 135 133 37 35 5 5 184 + 185 185 186 187 187 124 125 125 125 125 189 126 46 46 47 47 + 137 137 137 137 137 138 138 138 139 139 139 139 140 140 47 141 + 39 39 39 41 41 42 42 92 25 93 27 29 139 103 158 140 + 137 169 169 170 170 170 171 171 171 139 172 140 140 140 140 47 + 185 185 185 186 186 186 187 187 187 188 94 94 94 103 46 47 + 39 40 154 41 41 42 24 25 28 30 30 157 103 103 158 159 + 155 204 204 203 204 23 100 150 150 151 151 51 55 60 60 60 + 97 97 61 61 237 72 238 238 238 239 239 171 171 172 172 172 + 169 167 137 244 188 45 173 84 86 87 246 36 37 40 87 128 + 76 239 170 169 169 90 88 86 85 84 83 82 50 80 130 254 + 168 168 168 168 169 238 238 238 239 239 239 239 239 239 239 239 + 86 88 88 168 168 168 168 169 169 169 169 169 170 170 170 239 + 97 61 61 61 96 165 61 237 96 60 60 61 61 238 238 74 + 167 237 237 237 237 72 238 238 238 238 238 239 239 239 239 75 + 167 167 167 168 168 168 168 168 169 169 238 239 239 239 239 75 + 168 238 238 238 238 239 239 75 166 164 163 81 131 131 132 132 + 153 153 40 41 42 42 42 24 24 26 246 246 171 171 171 76 + 166 166 167 167 168 168 168 238 238 238 238 239 239 75 75 75 + 84 84 84 17 98 98 98 19 168 168 169 169 169 170 239 75 + 166 237 237 237 237 71 72 238 238 238 238 239 239 239 75 76 + 133 133 134 134 135 135 136 136 136 169 169 169 170 170 170 75 + 83 16 16 16 17 19 61 61 61 62 62 62 239 239 239 76 + 203 203 203 203 17 19 19 254 254 49 54 54 59 59 59 59 + 250 60 68 69 236 236 70 70 70 71 71 72 73 73 74 74 + 237 166 167 136 169 170 74 163 165 166 168 80 132 84 166 160 + 167 167 165 165 164 164 132 131 130 255 255 255 160 48 105 105 + 164 165 165 165 165 165 165 165 166 166 166 166 166 166 167 167 + 163 163 163 163 164 164 164 165 165 165 165 166 166 166 166 166 + 162 250 250 250 161 249 250 250 64 249 249 250 250 164 165 70 + 163 250 250 250 250 164 165 165 69 166 166 166 166 166 70 70 + 163 250 250 250 250 250 164 165 165 165 165 166 166 166 166 237 + 164 164 68 165 165 166 166 70 162 161 104 160 48 48 254 254 + 254 80 131 82 133 133 133 134 134 135 135 166 167 167 167 167 + 163 163 250 250 250 250 250 165 165 165 166 166 166 167 167 168 + 254 80 80 80 81 81 163 132 164 164 165 165 165 166 166 167 + 163 250 250 250 250 250 68 165 69 166 166 166 166 167 167 167 + 255 130 130 131 131 131 163 132 164 133 165 165 165 166 167 167 + 254 49 80 50 50 51 55 55 96 96 61 97 166 166 167 61 + 150 200 55 55 55 51 51 105 105 105 53 53 53 58 58 58 + 58 58 249 249 66 66 66 66 66 235 68 69 69 236 70 70 + 163 162 132 133 134 166 166 160 64 250 164 105 255 255 162 160 + 139 28 27 92 42 41 39 39 38 37 37 36 34 33 7 129 + 87 168 90 169 90 91 169 24 246 26 26 246 246 246 246 138 + 39 39 39 39 41 41 41 155 42 92 92 25 93 27 28 138 + 134 85 88 88 83 84 98 61 51 96 97 98 87 22 170 170 + 167 167 167 167 168 169 169 169 169 170 170 170 246 246 246 171 + 85 88 88 88 87 90 90 90 91 23 100 24 26 246 246 246 + 90 90 90 91 137 138 246 246 84 133 82 150 149 150 36 37 + 37 38 38 39 244 244 244 43 244 43 93 93 29 29 94 139 + 85 86 86 88 87 90 90 90 169 137 137 246 246 138 30 139 + 37 153 153 153 40 40 40 40 41 41 41 42 92 93 28 138 + 85 86 88 87 168 90 169 169 169 169 170 246 246 246 171 139 + 5 5 184 38 38 4 4 39 244 244 244 92 43 93 28 94 + 37 153 153 153 40 40 154 154 41 23 24 24 26 246 246 245 + 202 203 203 202 202 202 154 148 148 148 149 54 54 55 55 55 + 55 60 60 60 166 70 70 237 237 167 168 169 169 170 170 171 + 167 133 135 39 43 93 170 82 83 98 88 254 151 152 166 160 + 3 3 41 39 4 38 5 37 6 6 33 7 7 8 8 8 + 153 153 40 40 40 154 154 154 154 154 41 41 155 3 3 3 + 5 5 5 5 5 38 4 39 154 154 154 154 41 41 155 155 + 151 152 153 153 150 151 83 16 49 51 51 83 84 18 99 90 + 83 84 84 84 85 85 86 86 89 99 99 22 91 155 155 155 + 152 153 153 153 153 153 40 40 154 154 154 154 41 155 155 155 + 153 85 40 154 154 41 41 155 152 150 149 148 8 7 32 32 + 33 6 35 5 4 4 4 4 4 4 3 3 3 3 3 24 + 152 152 84 84 153 85 40 40 154 154 41 41 155 155 42 156 + 150 151 151 151 152 152 152 5 153 153 39 154 154 41 155 155 + 152 152 84 84 85 85 86 40 154 41 41 155 155 155 42 3 + 34 34 35 35 35 5 5 5 4 4 4 39 41 3 3 155 + 150 150 151 151 152 152 153 153 153 39 154 154 154 155 155 156 + 200 200 201 201 201 201 201 146 146 195 195 214 214 54 54 54 + 54 54 54 55 55 60 96 97 97 97 98 86 87 99 41 91 + 133 132 133 38 4 3 22 149 151 152 153 146 199 150 82 48 + 151 151 150 149 148 148 147 146 146 145 145 144 144 10 11 11 + 148 148 149 149 149 149 150 150 150 150 150 150 150 150 150 151 + 147 147 147 147 148 148 148 148 149 149 199 150 150 150 150 151 + 146 147 147 147 145 146 48 48 145 146 48 48 148 149 150 150 + 48 48 48 254 254 49 49 49 150 150 150 150 150 151 151 151 + 147 147 147 148 148 148 148 148 149 149 149 150 150 150 151 151 + 148 149 149 149 149 150 150 151 146 145 144 10 10 10 10 9 + 9 9 8 8 7 7 7 7 33 33 6 6 6 151 151 151 + 146 147 148 148 148 148 149 149 149 149 150 150 150 151 151 151 + 145 145 146 146 146 146 147 147 148 148 148 149 149 150 150 151 + 147 48 48 48 254 49 49 149 150 150 150 150 151 151 151 151 + 9 9 9 8 8 8 8 7 7 7 7 7 150 150 151 151 + 145 145 146 146 146 147 147 148 148 149 149 150 150 150 151 200 + 195 212 196 195 195 196 146 11 192 192 192 144 144 52 52 52 + 52 52 52 53 53 53 48 48 49 49 49 49 150 150 151 131 + 128 128 128 32 7 6 150 144 146 48 148 106 144 145 146 48 + 43 42 155 41 39 4 5 5 36 6 33 33 7 7 8 8 + 40 40 154 154 154 154 41 41 155 155 155 155 155 42 42 43 + 5 5 5 38 38 4 39 39 154 154 41 41 155 155 155 42 + 152 153 153 153 151 152 152 17 50 51 83 153 17 154 41 22 + 84 84 85 85 98 86 88 87 90 21 22 22 42 42 156 156 + 153 153 153 153 40 40 40 154 154 154 41 155 155 155 155 156 + 40 154 154 154 41 155 155 156 152 151 149 7 7 7 32 33 + 6 35 5 5 4 4 185 185 244 3 3 3 3 43 43 156 + 152 153 153 153 153 40 154 154 154 41 41 155 155 42 43 156 + 6 36 152 152 152 152 153 153 153 40 40 154 154 155 155 42 + 84 84 85 85 85 86 88 89 99 41 41 155 42 156 156 43 + 34 34 35 35 5 5 5 5 4 4 4 39 41 155 42 156 + 150 151 151 152 152 153 153 153 154 154 154 155 155 155 42 156 + 202 202 201 201 201 201 153 146 146 147 148 148 49 54 54 54 + 59 54 55 96 96 96 97 97 166 98 98 87 90 22 91 91 + 134 133 134 38 4 3 91 150 83 152 153 148 149 151 83 128 + 140 140 139 94 27 92 42 155 41 39 38 38 37 36 36 34 + 26 170 170 246 246 171 171 171 171 171 139 172 172 172 140 140 + 42 3 3 92 43 25 27 138 138 138 139 139 139 172 172 172 + 89 22 91 62 16 61 168 62 61 61 61 168 62 62 171 171 + 168 72 238 238 74 74 75 75 76 76 76 172 172 172 172 172 + 91 91 137 137 170 170 170 170 246 246 171 139 139 172 172 173 + 26 170 170 170 139 172 172 173 136 135 133 132 36 37 5 38 + 4 4 244 244 187 188 188 188 188 125 95 158 46 140 173 173 + 136 169 169 169 169 170 170 170 170 171 171 139 172 140 140 173 + 134 86 88 89 99 22 91 23 100 24 246 246 171 139 172 172 + 136 169 169 169 170 170 170 170 171 171 171 172 172 140 173 140 + 185 185 185 185 244 244 244 3 43 93 29 94 139 172 172 173 + 153 40 154 41 41 91 92 24 246 246 245 245 63 172 172 173 + 23 204 204 204 204 21 100 149 149 150 50 55 60 60 60 60 + 60 61 61 166 237 71 237 72 238 73 74 75 75 76 172 77 + 169 167 136 137 94 139 77 133 167 168 169 131 132 135 167 160 + 89 88 86 84 84 83 82 50 80 49 254 254 48 48 146 253 + 83 164 165 165 165 165 166 166 166 166 135 135 167 167 167 167 + 131 132 132 132 132 133 133 133 133 84 134 134 85 135 86 167 + 80 82 132 133 129 80 81 164 104 54 54 81 96 165 134 166 + 163 250 250 250 164 165 165 165 166 166 166 135 135 135 135 167 + 132 132 132 164 164 164 164 165 165 165 165 166 135 135 167 167 + 133 133 165 165 135 135 167 167 162 255 129 128 8 8 8 7 + 7 33 34 35 37 5 5 5 38 38 39 40 40 88 88 167 + 131 163 163 163 164 164 164 164 165 165 135 135 167 167 88 87 + 254 49 49 50 50 50 82 82 82 83 84 84 85 85 86 167 + 131 163 132 164 164 164 165 165 165 134 135 135 135 167 167 136 + 7 33 33 34 34 34 35 37 37 133 133 84 85 86 167 167 + 254 49 80 50 50 82 82 82 83 84 84 84 85 86 88 99 + 200 200 200 200 151 151 82 253 253 253 48 53 53 53 58 58 + 58 249 249 249 249 250 250 250 250 250 165 165 166 166 167 167 + 163 162 132 132 134 135 166 255 161 163 133 253 128 255 162 160 + 137 137 136 136 135 135 134 133 132 131 131 130 149 148 147 128 + 135 135 86 135 88 88 89 136 136 136 136 136 136 137 137 137 + 133 133 134 134 134 134 135 135 135 88 136 136 136 91 137 137 + 133 84 133 135 131 132 133 85 81 55 96 96 98 86 136 136 + 165 165 165 166 166 167 167 87 136 136 136 136 137 137 137 137 + 133 134 134 134 135 135 135 135 88 88 88 136 136 137 137 137 + 135 135 135 135 136 136 137 137 132 132 131 129 8 7 33 34 + 34 35 5 4 185 185 185 185 244 244 3 3 3 92 25 138 + 133 133 134 134 134 135 135 135 88 136 136 136 137 137 137 26 + 151 151 152 152 152 152 153 153 153 40 40 88 89 136 137 137 + 133 84 134 135 135 135 135 88 136 136 136 136 137 137 137 138 + 35 35 35 35 35 5 38 38 39 135 135 136 136 136 137 137 + 131 151 151 152 152 153 153 153 18 19 99 99 41 91 92 24 + 201 201 201 201 16 153 153 8 253 147 48 49 54 54 54 54 + 54 59 250 250 164 165 165 165 166 166 167 167 168 168 137 169 + 165 133 134 134 244 244 136 131 82 84 85 128 150 132 83 160 + 126 126 125 125 124 124 187 187 186 186 185 184 183 183 34 34 + 2 31 2 2 125 125 125 126 126 126 126 126 126 126 127 190 + 187 187 187 187 187 124 124 124 125 125 125 125 125 126 126 126 + 3 43 43 2 39 155 42 101 154 20 41 42 44 157 125 127 + 43 93 28 30 157 45 45 95 95 158 46 126 126 126 127 127 + 187 187 187 188 188 188 188 188 188 125 126 126 126 126 127 127 + 2 157 45 95 126 126 127 127 3 4 38 5 183 184 184 184 + 120 120 119 119 123 123 124 124 124 125 125 125 126 126 126 127 + 122 187 187 187 187 188 188 188 189 189 126 126 126 126 127 127 + 4 39 3 244 244 244 187 187 187 124 125 125 125 125 126 126 + 3 43 43 44 2 94 94 94 95 126 126 126 126 127 127 127 + 185 185 185 121 121 121 122 122 124 124 125 125 125 125 126 127 + 4 39 41 3 3 3 43 2 188 188 125 126 126 126 127 127 + 156 156 155 155 155 156 43 33 6 6 200 201 201 202 202 202 + 17 19 20 21 21 23 24 246 246 171 139 103 158 126 127 127 + 93 244 244 122 125 125 126 5 41 92 93 35 5 4 136 128 + 119 119 119 119 118 117 117 116 115 115 115 114 114 114 114 113 + 185 185 185 186 186 121 121 121 121 119 119 119 119 119 119 119 + 116 116 117 117 117 117 118 118 118 118 119 119 119 119 119 119 + 183 184 184 185 35 5 5 4 6 37 5 5 4 185 186 187 + 5 4 4 4 185 186 186 186 186 186 186 122 122 123 119 123 + 184 184 184 185 185 185 185 185 120 120 120 119 119 119 119 119 + 185 185 185 186 120 119 119 123 183 182 33 114 114 114 114 115 + 115 115 116 116 117 117 117 118 118 118 119 119 119 119 119 123 + 184 184 184 184 185 185 185 185 185 121 121 121 119 119 119 119 + 115 115 115 183 183 116 116 117 117 117 118 118 119 119 119 119 + 184 184 184 185 185 185 186 186 186 121 121 121 121 119 119 119 + 115 115 115 116 116 116 116 116 117 117 118 119 119 119 119 123 + 115 115 115 115 116 116 117 117 117 118 119 119 119 119 119 119 + 117 116 117 116 116 116 116 113 113 8 196 196 197 197 198 198 + 151 151 152 37 5 38 4 4 4 4 185 186 186 122 122 123 + 184 183 184 117 119 119 122 33 35 5 185 32 114 182 134 128 + 183 182 182 114 114 113 113 113 113 112 111 111 111 111 110 110 + 32 32 32 32 32 32 32 33 182 182 182 182 182 182 182 115 + 113 113 113 113 113 113 114 114 114 114 182 182 182 182 182 182 + 8 8 8 8 9 8 8 7 9 9 8 8 7 32 33 182 + 8 8 32 32 32 32 32 32 33 33 33 182 182 182 182 183 + 8 8 8 8 32 32 32 32 32 32 32 182 182 182 182 182 + 32 32 32 32 32 182 182 183 8 9 112 111 110 110 111 111 + 111 113 113 113 114 114 114 114 114 115 115 115 115 115 115 183 + 8 8 8 8 32 32 32 32 32 32 182 182 182 182 183 183 + 112 113 113 113 113 113 113 113 113 114 114 114 114 182 182 183 + 8 8 32 32 32 32 32 32 32 33 182 182 182 182 183 183 + 112 112 113 113 113 113 113 113 114 114 114 114 114 115 182 115 + 112 112 112 113 113 113 113 113 114 114 32 32 182 182 182 183 + 113 113 113 113 113 113 113 109 109 11 11 10 144 144 144 144 + 145 145 145 146 8 8 8 7 7 7 33 33 33 33 182 182 + 8 8 8 180 114 182 182 10 9 8 32 110 111 9 8 128 + 9 9 9 10 11 11 11 12 12 12 12 13 13 14 14 14 + 11 10 10 10 10 10 10 10 10 10 10 9 9 9 9 9 + 11 11 11 11 11 11 11 10 10 10 10 10 10 10 9 9 + 107 252 252 106 251 252 252 106 251 252 252 252 106 106 10 9 + 252 252 106 106 106 106 144 144 10 10 10 9 9 9 9 9 + 11 11 11 11 106 106 106 106 10 10 10 10 10 9 9 9 + 106 106 106 10 10 10 9 253 107 107 251 13 14 14 108 108 + 109 109 109 110 110 110 110 111 111 111 10 9 10 9 9 9 + 107 252 252 252 106 106 106 106 10 10 10 9 9 9 9 9 + 107 107 107 107 107 107 11 11 11 11 10 10 10 10 9 9 + 252 252 252 106 106 106 106 10 10 10 10 10 9 9 253 9 + 12 109 109 109 109 109 110 110 110 10 10 10 10 10 9 9 + 107 107 107 107 107 11 11 11 10 10 10 10 10 9 9 145 + 11 192 11 11 11 11 11 15 15 14 251 251 251 251 251 251 + 252 252 252 252 252 252 106 106 106 106 106 253 106 144 9 9 + 252 106 11 10 10 10 9 251 107 252 11 14 13 251 252 128 + 137 91 136 86 134 134 133 132 132 131 130 254 129 128 128 128 + 84 84 85 85 98 86 88 88 88 87 87 90 90 90 90 91 + 153 153 153 153 153 153 85 85 135 86 88 89 136 136 136 90 + 82 83 84 84 80 82 96 96 80 51 96 96 165 166 88 168 + 164 165 165 165 165 166 167 167 167 167 168 168 168 90 90 169 + 84 84 84 84 84 84 85 98 86 86 88 88 89 90 90 90 + 84 85 98 86 88 87 168 168 82 80 254 129 128 129 7 7 + 6 36 37 38 38 39 39 39 39 39 41 136 90 91 137 169 + 82 83 84 84 165 84 85 85 86 86 88 87 90 91 91 137 + 150 151 151 151 132 152 133 153 133 153 85 40 88 89 136 90 + 164 164 165 165 165 165 166 167 167 88 87 90 90 90 91 137 + 36 36 36 36 36 37 38 38 38 38 40 41 89 136 90 91 + 149 150 151 151 152 153 153 84 85 18 86 88 88 90 90 23 + 201 201 201 201 201 201 153 146 146 48 48 53 53 58 58 59 + 54 54 250 250 250 250 165 165 165 166 166 166 167 167 168 167 + 164 163 133 134 39 136 168 49 81 96 97 48 254 80 163 160 + 63 245 246 23 23 21 20 86 85 153 152 152 151 150 149 149 + 21 21 62 62 62 62 62 62 62 62 62 246 246 245 245 245 + 154 154 99 99 99 21 22 23 23 23 62 62 246 246 246 246 + 17 17 61 61 16 16 61 61 60 60 61 61 61 169 62 239 + 167 237 237 237 238 238 238 238 239 239 239 239 239 246 171 245 + 19 19 20 20 21 21 62 62 62 62 62 62 246 246 246 171 + 168 62 62 62 62 62 245 171 98 83 82 50 150 151 152 37 + 5 38 39 41 155 3 43 43 43 93 27 101 245 245 245 245 + 86 86 167 168 168 168 168 169 62 62 62 62 246 246 245 63 + 153 153 153 18 18 18 19 20 99 21 22 23 62 246 246 239 + 61 61 61 61 168 168 62 62 62 62 62 246 246 245 245 63 + 5 38 38 4 4 39 41 41 91 91 100 24 246 246 245 245 + 152 84 16 17 18 19 19 20 21 62 62 62 62 246 245 245 + 203 203 203 203 202 17 20 148 148 49 54 54 59 59 59 59 + 60 60 60 60 166 70 70 237 237 71 238 238 238 239 239 239 + 166 166 135 136 25 246 239 51 97 61 61 49 82 84 97 48 + 1 63 157 101 25 92 155 41 39 38 38 5 37 36 34 33 + 23 23 62 62 246 246 246 246 245 245 245 245 63 63 63 63 + 41 3 3 3 42 43 156 25 26 26 101 157 157 157 103 63 + 19 99 21 23 16 19 19 62 97 97 61 87 62 62 246 171 + 168 168 168 169 169 239 239 239 239 171 171 171 63 63 63 63 + 99 90 22 22 23 23 24 246 246 246 246 246 245 63 63 63 + 62 62 246 246 246 245 139 63 89 84 133 151 36 36 37 5 + 38 4 39 3 3 43 2 2 2 2 31 94 103 158 140 172 + 89 90 90 90 91 23 24 246 246 246 246 245 245 172 172 172 + 153 40 40 154 154 41 41 22 91 23 24 26 246 245 63 63 + 87 168 168 169 169 169 170 170 170 246 171 245 245 172 172 140 + 4 185 185 185 185 244 244 244 3 43 93 44 29 94 103 103 + 5 153 40 154 41 21 22 22 23 24 246 246 245 245 63 63 + 20 203 203 203 203 203 155 149 149 150 150 55 55 55 60 60 + 60 60 60 97 61 237 237 72 238 238 238 239 239 171 172 171 + 168 166 136 136 138 246 171 83 98 87 23 150 132 85 98 48 + 246 26 100 91 41 154 40 153 153 37 36 6 33 7 7 148 + 154 20 99 99 90 22 22 23 91 92 92 24 24 26 26 26 + 39 39 39 39 40 40 41 41 99 90 22 91 23 23 24 24 + 153 85 85 86 151 16 16 17 55 60 97 97 61 20 23 62 + 85 166 166 167 167 168 168 168 169 23 23 23 24 26 26 26 + 153 85 85 86 86 88 88 99 99 22 91 91 92 24 26 246 + 19 20 99 22 91 24 26 246 84 132 131 254 148 33 34 6 + 35 5 5 4 4 4 4 244 244 3 43 43 43 43 101 246 + 153 85 85 86 86 86 88 99 22 91 91 100 24 26 246 246 + 151 152 152 153 153 153 153 40 40 86 88 90 91 91 24 137 + 135 135 135 135 88 87 90 90 22 23 23 23 26 246 246 101 + 36 35 37 5 5 38 38 4 4 39 3 3 42 92 26 101 + 36 152 152 153 153 153 40 86 20 99 90 22 23 24 26 246 + 202 202 202 202 201 201 40 147 147 148 49 54 54 59 54 59 + 59 59 60 60 60 60 165 70 237 237 237 168 168 169 170 169 + 166 165 135 135 136 92 62 50 83 16 19 254 150 82 97 48 + 88 86 85 153 152 152 151 150 149 148 148 148 146 146 146 145 + 152 83 83 83 84 84 84 85 85 134 85 85 40 86 86 86 + 151 151 151 151 151 152 152 83 84 84 84 84 85 85 85 86 + 150 50 50 83 48 50 50 51 49 54 54 51 51 83 16 85 + 131 132 132 164 83 84 84 84 97 17 85 85 85 86 40 86 + 151 82 82 82 82 83 83 83 133 84 84 85 85 85 86 86 + 83 83 84 153 153 85 85 86 50 254 254 147 146 8 8 7 + 7 33 34 6 5 5 5 5 38 38 38 39 40 40 154 99 + 150 50 82 82 82 83 83 152 84 84 85 85 85 86 86 20 + 148 149 149 150 150 50 50 151 82 83 152 84 153 153 86 86 + 131 131 132 132 132 133 84 84 84 84 85 85 86 86 88 41 + 7 32 33 33 34 35 35 35 37 37 37 38 153 85 86 19 + 148 149 149 150 150 151 151 151 83 83 84 84 85 86 86 20 + 197 198 200 200 200 200 151 144 144 253 48 53 53 53 53 53 + 58 58 58 54 249 250 250 250 250 164 165 165 165 85 135 135 + 163 162 131 132 133 134 86 48 49 50 82 253 48 254 80 48 + 172 245 246 246 92 91 22 154 40 153 153 152 151 151 150 149 + 90 23 62 62 62 170 246 246 246 246 171 171 171 63 63 63 + 41 41 91 91 91 91 91 100 24 246 246 246 246 245 139 245 + 86 20 21 21 16 17 61 61 96 96 61 61 168 62 170 171 + 167 167 168 169 169 238 239 239 239 239 171 171 171 171 63 63 + 88 99 21 22 22 23 23 24 24 246 246 246 246 245 245 171 + 169 169 169 170 246 171 171 171 86 84 133 131 36 36 37 5 + 38 4 39 3 3 43 43 2 2 2 29 94 139 172 172 172 + 88 87 90 90 90 169 169 169 170 170 246 171 171 171 172 172 + 153 153 85 86 86 20 99 99 22 22 100 26 246 246 245 171 + 167 168 168 168 169 169 169 62 170 170 171 171 171 171 172 172 + 5 5 4 4 4 244 244 244 3 43 25 138 246 245 63 63 + 153 153 18 18 20 20 21 21 23 23 246 246 246 245 63 63 + 203 203 203 203 203 20 21 148 149 149 50 55 55 55 55 60 + 60 60 60 237 70 70 237 71 71 72 238 238 239 171 171 239 + 168 166 136 136 138 138 171 83 97 167 169 150 152 85 98 48 + 77 76 76 239 170 169 169 168 88 86 84 84 83 82 131 80 + 169 238 239 239 239 239 75 239 75 75 76 76 76 76 76 76 + 169 169 169 169 169 169 169 170 239 239 239 239 75 76 76 76 + 167 168 238 238 97 166 237 73 165 60 166 72 73 238 75 75 + 71 71 71 72 73 73 73 74 74 75 75 75 75 76 76 76 + 168 168 238 238 238 238 239 239 239 239 239 75 75 76 76 76 + 238 238 238 239 75 75 76 76 167 166 165 82 132 132 133 38 + 40 40 41 92 25 138 138 246 246 245 171 172 77 77 77 77 + 168 168 168 238 238 238 238 238 239 239 75 75 76 76 76 77 + 17 17 98 61 61 168 168 168 169 62 239 239 239 75 76 76 + 168 237 71 72 73 73 74 74 75 75 75 75 76 76 76 76 + 135 135 135 136 136 136 137 137 169 170 170 171 171 171 76 76 + 97 17 98 61 61 168 62 62 62 62 239 239 76 76 76 77 + 21 203 204 204 61 61 21 49 80 80 54 55 60 60 60 60 + 250 69 68 70 70 70 70 71 71 72 73 74 74 75 75 75 + 237 167 168 137 171 171 75 165 166 237 238 81 83 166 167 160 + 71 237 237 166 166 165 164 164 163 162 162 161 104 160 160 160 + 165 165 165 166 166 166 166 166 237 237 237 237 237 237 237 237 + 164 164 164 164 165 165 165 69 236 70 70 70 70 237 237 237 + 250 250 68 68 162 250 250 67 249 65 66 67 69 236 70 70 + 235 235 234 234 234 69 69 236 70 70 70 70 70 237 237 237 + 164 250 164 68 165 165 165 69 166 166 70 70 70 237 237 71 + 69 69 69 70 70 70 237 237 250 162 161 160 160 104 255 255 + 131 132 132 133 165 166 166 166 167 167 167 168 168 237 237 71 + 250 250 164 164 164 165 69 165 166 166 70 237 237 237 71 71 + 162 250 250 250 250 250 250 250 164 165 166 166 166 237 237 70 + 66 67 235 68 68 69 69 236 236 70 70 70 237 71 71 71 + 162 162 163 163 163 164 164 164 165 165 166 166 166 237 237 237 + 162 249 250 250 250 250 250 250 165 166 70 237 237 237 237 72 + 55 16 55 60 55 60 250 248 160 53 53 53 58 58 58 58 + 229 230 230 233 233 233 234 235 234 234 69 69 236 70 70 71 + 235 66 164 165 167 168 237 64 65 66 69 160 104 162 250 160 + 169 169 168 167 166 166 165 83 83 82 80 80 80 49 48 48 + 97 166 166 166 167 167 167 167 168 168 168 168 168 169 169 168 + 84 84 84 97 97 166 166 166 61 61 167 167 168 168 168 168 + 96 96 165 97 81 96 96 165 250 250 250 165 166 237 167 237 + 68 69 69 69 236 70 70 237 237 237 237 168 238 238 238 238 + 97 97 97 97 166 166 166 166 167 167 167 168 168 168 169 238 + 166 166 167 167 167 168 168 238 164 163 80 254 48 254 130 131 + 131 132 133 134 135 135 88 136 89 136 90 90 169 169 169 238 + 96 165 165 165 166 166 166 166 167 167 168 168 168 169 169 169 + 81 81 82 164 164 164 165 165 165 166 166 167 167 168 168 168 + 165 68 69 69 236 70 70 237 237 237 168 168 168 169 169 169 + 131 132 132 132 133 133 133 134 85 86 86 167 168 168 169 238 + 81 81 51 96 96 96 97 97 97 61 61 61 168 168 168 62 + 201 202 201 16 60 96 97 253 48 53 53 53 58 58 58 58 + 59 249 250 250 67 68 68 69 69 69 70 70 237 237 238 71 + 165 164 133 135 88 168 238 80 250 250 166 160 80 163 164 160 + 60 60 60 55 54 54 54 54 53 53 53 53 53 52 105 52 + 59 59 59 59 59 59 59 59 60 60 60 60 60 60 60 60 + 54 49 54 54 54 54 54 55 55 55 55 55 55 55 55 60 + 58 59 59 59 53 58 58 59 57 57 58 58 59 59 59 60 + 58 58 59 59 59 59 59 59 59 59 60 60 60 60 60 60 + 54 59 54 54 59 59 59 59 59 59 55 60 60 60 60 60 + 59 59 59 59 55 60 60 60 53 53 53 52 52 52 48 48 + 48 48 49 49 50 50 51 51 51 55 55 96 60 60 60 60 + 53 59 59 59 59 59 59 59 59 59 55 60 60 60 60 60 + 53 53 53 53 53 53 54 54 54 54 55 55 55 60 60 60 + 58 59 59 59 59 59 59 59 59 55 55 60 60 60 60 60 + 48 48 48 49 49 49 49 54 54 55 55 55 55 55 60 60 + 53 53 53 53 54 54 54 54 59 59 59 55 60 60 60 60 + 214 213 213 214 58 58 54 52 52 52 52 56 56 56 57 57 + 57 57 57 58 58 58 58 59 59 59 59 59 59 60 60 60 + 249 249 162 162 55 55 60 53 58 58 54 52 52 53 53 53 + 55 55 54 54 49 49 48 48 48 48 253 253 105 106 106 106 + 54 54 54 54 54 54 54 54 55 55 55 55 55 55 55 55 + 48 48 48 49 49 49 49 49 54 54 54 54 54 55 55 55 + 53 53 53 53 52 53 53 58 52 57 53 53 58 54 54 55 + 53 58 58 58 58 59 59 59 54 54 55 55 55 55 55 55 + 53 53 54 54 54 54 54 54 54 54 54 54 55 55 55 55 + 54 54 54 54 54 54 55 55 53 52 52 105 144 144 253 145 + 146 146 48 148 49 149 49 150 150 150 50 51 55 55 55 55 + 53 53 53 54 54 54 54 54 54 54 54 55 55 55 55 55 + 48 53 53 53 53 53 53 53 54 54 54 54 54 54 55 55 + 53 53 53 53 54 54 54 54 54 54 54 55 55 55 55 51 + 146 146 146 48 48 48 48 49 49 49 80 54 54 55 55 55 + 52 53 53 53 53 53 53 54 54 54 54 54 54 55 55 55 + 212 212 214 214 53 53 53 106 106 52 52 52 56 56 56 56 + 56 56 57 57 57 58 58 58 58 58 59 59 59 59 55 55 + 249 160 255 130 80 51 55 52 53 53 53 247 52 52 53 160 + 91 91 99 40 153 153 152 152 151 151 149 149 148 148 8 146 + 84 84 85 85 18 18 86 86 99 99 41 41 41 22 91 22 + 152 152 152 153 153 153 153 153 40 40 40 154 41 41 41 22 + 151 152 152 84 50 51 83 97 54 54 51 83 16 17 18 87 + 84 165 165 165 97 98 98 98 19 19 20 99 21 22 22 22 + 152 152 152 153 153 153 85 153 153 40 154 41 41 41 91 22 + 153 85 85 18 86 99 21 22 151 150 149 148 147 148 7 7 + 33 6 5 5 5 4 4 4 4 39 154 41 155 155 42 100 + 152 83 133 84 84 85 85 85 86 40 41 41 41 91 42 23 + 150 151 151 151 151 152 152 152 153 153 40 40 40 41 41 22 + 132 83 84 84 84 84 17 18 18 19 20 99 99 22 91 42 + 34 34 34 34 35 5 5 5 38 38 39 39 41 41 41 91 + 150 150 151 151 152 152 153 153 153 18 18 19 20 99 22 23 + 200 201 201 201 201 152 152 9 146 146 48 48 53 53 54 54 + 59 59 59 59 250 250 250 165 165 166 166 166 167 88 90 90 + 133 132 133 38 4 41 22 254 50 83 84 147 149 150 81 128 + 158 95 2 2 43 3 3 4 4 4 5 5 35 6 33 7 + 92 24 26 26 26 101 44 44 2 31 31 94 45 95 95 95 + 244 244 3 3 3 3 43 43 43 2 2 2 2 2 94 45 + 39 41 155 22 153 85 99 21 84 16 18 21 23 26 246 245 + 136 136 169 169 169 170 170 171 246 246 245 139 139 103 103 103 + 41 3 3 3 3 3 43 43 43 44 2 2 31 31 95 102 + 24 24 26 27 28 30 139 103 39 38 37 36 34 35 35 5 + 5 4 185 186 187 187 187 187 188 188 94 45 95 95 158 158 + 39 41 41 42 42 92 25 25 93 28 29 94 45 95 158 158 + 38 38 39 39 39 41 41 3 3 3 43 2 2 31 45 103 + 41 89 90 91 23 24 246 246 246 101 157 94 45 95 95 126 + 184 184 184 185 185 185 186 186 187 187 187 2 2 31 95 158 + 38 153 40 154 154 155 155 155 156 156 101 30 157 157 45 158 + 204 203 203 203 202 155 155 7 7 199 198 200 55 55 96 96 + 60 60 61 61 61 61 168 168 169 169 170 170 170 139 139 139 + 136 135 136 244 188 31 139 132 85 89 42 6 5 38 135 128 + 3 244 4 4 38 5 35 35 34 33 32 7 8 8 8 8 + 38 38 38 38 4 4 4 4 4 4 4 39 3 3 3 3 + 35 35 37 37 5 5 5 38 38 38 4 4 4 39 39 41 + 6 36 37 153 150 150 83 83 49 50 50 152 153 153 40 136 + 132 133 133 133 134 135 135 135 88 40 40 41 41 41 41 3 + 37 37 5 5 5 5 5 38 4 4 4 4 39 39 3 41 + 38 153 40 40 39 39 41 41 36 7 7 8 8 8 32 32 + 33 34 34 183 184 184 184 184 185 185 4 39 3 3 3 3 + 35 37 37 37 5 5 38 38 38 4 39 39 41 3 3 3 + 33 33 6 6 36 37 5 5 5 5 38 4 4 4 39 41 + 132 132 132 133 84 153 153 40 40 40 39 41 41 41 3 244 + 33 33 33 34 34 35 35 5 5 5 38 4 4 4 3 3 + 7 6 6 36 36 36 37 5 5 38 4 39 39 39 3 155 + 200 201 200 200 200 152 36 9 9 146 146 147 48 48 49 49 + 54 54 54 51 51 82 83 165 165 165 85 135 135 41 41 136 + 132 131 132 35 4 3 41 148 150 151 153 8 7 33 131 128 + 3 39 4 38 5 5 35 35 34 33 32 7 8 8 8 9 + 5 38 38 38 38 4 4 4 4 4 4 39 39 39 41 244 + 35 35 35 5 5 5 5 5 5 4 4 4 4 4 4 39 + 6 36 37 38 149 150 151 83 49 50 151 152 152 153 39 135 + 132 164 133 133 134 134 135 40 40 40 39 39 39 39 244 244 + 35 35 37 5 5 5 38 38 38 38 4 4 4 4 39 39 + 37 38 38 4 4 39 39 41 36 33 7 8 8 8 32 32 + 33 34 34 183 184 184 184 185 185 185 4 4 39 244 244 244 + 35 35 35 37 5 5 5 38 38 4 4 4 4 39 3 3 + 33 33 34 6 6 35 35 37 5 5 5 38 4 4 4 41 + 36 133 133 133 133 38 38 38 39 39 39 39 39 3 3 244 + 182 182 182 182 182 34 35 35 5 5 5 38 4 4 4 244 + 33 33 33 6 6 36 37 37 5 38 4 4 39 39 3 155 + 198 200 201 200 201 200 37 9 9 9 146 146 147 48 49 49 + 49 49 80 50 82 82 132 133 133 165 134 135 135 40 41 136 + 133 131 132 37 4 4 41 254 150 152 37 8 7 33 131 128 + 141 1 102 157 2 93 43 3 3 39 4 38 5 5 35 6 + 26 246 246 245 245 245 63 63 63 172 172 158 140 140 1 47 + 3 3 43 43 43 93 44 30 30 157 103 103 103 158 1 1 + 22 23 23 246 17 21 21 62 17 61 21 169 62 245 63 172 + 169 238 238 239 239 239 75 76 76 77 172 172 173 173 173 173 + 91 100 24 26 26 246 246 245 245 245 63 63 172 140 140 173 + 246 246 245 245 103 172 140 173 90 135 133 37 36 37 5 4 + 4 39 244 43 2 188 188 188 189 189 95 158 1 47 141 141 + 91 91 24 246 246 246 246 246 139 139 139 172 140 1 159 141 + 40 154 41 41 155 155 100 24 25 26 101 157 103 172 1 173 + 91 169 169 170 170 170 171 171 171 172 172 172 140 47 159 159 + 185 185 186 186 186 244 187 187 2 2 2 45 103 158 1 159 + 4 154 41 41 155 100 24 24 246 245 63 63 63 173 173 173 + 204 204 204 204 204 204 156 150 150 150 151 55 60 60 60 60 + 60 61 61 61 168 238 238 238 238 239 239 75 76 77 77 77 + 169 167 137 137 45 158 173 153 19 62 62 151 133 135 168 128 + 63 245 246 26 24 91 41 154 40 153 153 152 151 150 199 149 + 21 23 62 62 62 62 62 62 246 246 246 245 245 245 245 245 + 41 41 41 155 155 91 23 100 24 26 246 246 246 245 245 245 + 18 20 20 21 16 17 61 61 60 60 17 19 20 62 246 171 + 167 168 168 238 238 238 239 62 239 239 246 246 245 245 245 63 + 20 99 90 21 22 23 23 62 62 62 246 246 246 245 245 63 + 22 62 62 62 246 246 245 171 86 84 132 131 150 36 37 5 + 38 4 39 3 3 3 43 43 44 44 44 30 157 139 63 63 + 86 88 99 21 22 23 23 62 62 62 246 246 245 245 63 63 + 153 153 153 40 40 88 99 99 90 22 23 24 246 246 245 63 + 167 168 168 168 168 169 62 62 62 246 246 245 245 245 63 172 + 5 5 38 4 4 39 41 3 3 42 25 26 101 157 245 245 + 152 153 40 154 20 20 20 21 21 62 62 62 246 245 245 207 + 203 203 203 203 203 203 20 148 148 150 54 54 55 59 59 60 + 60 60 60 60 61 61 237 237 72 238 238 238 239 239 171 171 + 167 166 136 136 27 246 63 152 16 61 62 150 82 84 98 48 + 21 20 18 85 153 153 152 152 151 150 149 148 147 147 146 145 + 16 16 16 16 16 16 17 17 18 18 18 19 19 20 20 20 + 151 152 152 152 152 152 153 84 85 85 85 18 18 18 20 20 + 50 51 83 83 49 54 55 96 54 54 54 55 96 16 17 98 + 96 96 96 96 96 97 97 97 97 98 98 19 19 20 20 20 + 151 83 83 83 83 16 16 16 16 16 17 18 19 19 20 20 + 83 16 16 17 18 18 19 20 50 49 254 147 146 147 148 7 + 7 6 36 37 5 5 38 4 4 39 40 154 41 41 99 21 + 151 152 152 83 83 16 16 16 16 17 18 18 19 20 99 21 + 149 149 150 150 151 151 82 152 83 84 16 17 17 18 19 20 + 51 51 96 96 97 97 97 97 17 98 98 19 20 20 21 22 + 33 33 34 6 35 36 37 37 37 153 153 40 40 86 20 99 + 149 150 150 50 50 51 83 83 16 16 16 17 18 19 20 20 + 200 200 201 200 200 200 152 145 146 145 48 53 53 53 58 58 + 58 58 54 54 55 250 250 250 96 96 165 166 166 98 88 88 + 164 163 132 133 38 40 20 48 50 51 97 146 254 49 81 48 + 9 9 10 10 10 11 11 11 12 12 12 13 13 13 14 14 + 10 10 10 10 10 10 10 10 10 10 10 9 9 9 9 9 + 11 11 11 11 11 11 10 10 10 10 10 10 9 10 9 9 + 11 11 11 11 107 107 252 106 252 252 252 252 106 10 10 9 + 106 106 106 106 106 106 106 144 144 9 9 9 9 9 9 9 + 11 11 11 11 10 10 10 10 10 10 10 10 9 9 9 9 + 106 10 10 10 10 10 9 9 107 107 13 13 14 13 13 108 + 12 109 109 110 110 110 10 10 10 9 10 9 9 9 9 9 + 11 11 11 11 11 10 10 10 10 10 10 9 9 9 9 9 + 12 12 12 11 11 11 11 11 11 10 10 10 10 10 9 9 + 252 252 106 106 106 10 10 10 10 10 9 9 9 9 9 9 + 109 109 109 109 11 11 11 11 11 10 10 10 10 10 9 9 + 12 12 12 11 11 11 11 11 10 10 10 10 9 9 9 9 + 11 192 192 11 11 11 11 15 14 14 251 251 251 251 251 107 + 107 252 252 252 252 106 106 106 106 106 106 106 144 9 9 9 + 106 106 11 9 10 10 9 251 107 252 106 13 13 12 252 128 + 35 6 33 7 7 7 8 8 9 9 9 10 10 10 11 11 + 7 148 7 7 7 33 33 33 6 33 33 34 34 6 6 6 + 8 8 8 8 7 7 7 7 7 33 32 33 33 33 6 6 + 8 147 147 148 145 146 146 147 253 146 146 147 148 148 33 36 + 128 48 254 254 254 254 254 150 150 6 6 6 6 6 6 35 + 8 8 8 8 7 7 7 7 32 32 33 33 33 34 34 6 + 148 149 7 33 33 34 6 36 253 253 9 10 10 10 10 9 + 9 9 8 8 32 32 32 32 33 33 33 34 34 34 35 35 + 8 8 8 7 7 7 7 7 33 33 33 34 34 6 35 35 + 9 9 9 8 8 8 8 8 8 7 7 32 32 33 6 6 + 147 48 48 148 148 149 149 149 33 6 6 6 6 6 35 35 + 9 9 9 8 8 8 8 8 7 7 32 33 33 33 6 6 + 9 9 9 8 8 147 148 148 148 149 199 7 6 6 6 37 + 195 196 195 195 195 147 8 11 11 11 10 144 144 144 144 145 + 253 253 253 48 48 48 48 254 254 254 130 130 130 34 36 36 + 128 128 8 32 33 6 36 144 253 147 148 10 10 9 128 128 + 94 2 43 3 3 3 4 4 5 5 35 6 6 33 7 7 + 155 155 155 155 42 43 43 43 43 93 2 2 2 2 2 2 + 4 4 39 39 3 3 3 3 3 3 43 3 43 2 2 44 + 153 154 154 21 152 153 18 20 82 84 16 18 99 91 92 246 + 86 167 87 90 90 90 137 170 26 26 27 138 28 28 29 94 + 39 39 41 41 41 155 3 3 3 3 43 43 93 44 2 30 + 90 21 156 43 43 43 2 157 153 133 36 33 33 33 34 35 + 5 5 4 185 185 186 122 122 187 187 187 2 2 2 2 45 + 39 39 39 41 41 41 3 3 3 43 43 93 2 2 94 94 + 5 5 5 38 4 4 39 39 41 3 3 3 43 93 2 29 + 40 86 88 89 90 90 91 91 24 26 27 28 29 29 94 188 + 183 183 184 184 184 185 185 186 244 244 244 244 43 43 2 31 + 37 5 153 153 40 154 154 154 155 155 156 156 43 44 2 157 + 202 203 202 202 153 154 39 8 8 199 199 214 150 55 55 55 + 55 60 60 97 97 98 167 167 168 168 169 169 170 138 138 138 + 135 133 135 185 3 2 28 36 133 40 22 7 6 5 134 128 + 143 143 143 175 191 191 141 141 141 47 47 46 46 158 95 95 + 142 142 142 142 175 175 175 175 175 175 143 143 143 143 143 143 + 141 141 141 142 141 142 142 142 142 175 175 175 175 143 143 143 + 141 174 174 142 46 141 141 174 173 173 173 79 174 142 175 143 + 141 174 174 174 174 174 142 142 175 175 175 143 175 143 143 143 + 141 141 174 142 142 142 142 142 142 175 175 175 143 143 143 143 + 174 174 142 175 191 175 143 143 141 47 1 158 95 158 46 127 + 127 127 127 191 191 191 191 191 191 191 175 175 143 143 143 143 + 141 174 174 174 174 142 142 142 175 175 143 143 143 143 143 143 + 47 159 159 159 141 141 141 141 142 142 142 175 175 175 143 143 + 141 174 174 174 174 142 142 142 175 175 175 175 143 143 143 143 + 190 190 190 190 190 190 190 191 191 191 191 175 175 143 143 143 + 1 159 159 141 141 141 141 142 142 142 142 175 143 143 143 143 + 159 142 159 159 159 141 141 45 95 95 102 158 173 173 172 173 + 173 173 173 78 79 79 79 79 174 174 174 142 175 175 143 175 + 174 141 174 190 191 143 142 47 159 141 174 103 127 1 78 128 + 143 175 191 191 159 47 1 46 95 95 94 2 2 2 43 43 + 141 141 141 141 141 141 174 174 142 142 142 142 175 175 143 143 + 46 1 47 47 47 47 159 141 141 141 142 142 142 142 175 175 + 158 1 1 141 157 46 140 173 245 63 63 173 173 141 174 142 + 173 173 173 78 79 79 79 79 174 174 142 175 175 175 175 175 + 1 1 1 47 47 141 141 141 141 141 141 142 142 175 175 143 + 141 141 141 141 142 191 175 143 158 45 29 28 43 2 2 188 + 189 189 126 127 127 127 127 127 191 191 191 191 175 143 143 143 + 1 140 140 47 141 141 141 141 141 142 142 142 175 175 143 143 + 45 102 102 158 158 46 1 1 47 159 159 141 142 142 175 175 + 140 140 140 173 173 79 79 174 174 174 142 175 143 175 143 143 + 45 189 189 189 189 47 47 46 47 159 141 142 142 142 175 143 + 45 102 102 158 158 46 1 47 159 159 159 142 142 142 143 143 + 158 1 207 207 207 159 1 43 43 156 101 205 205 206 245 245 + 245 171 76 77 77 77 77 78 78 78 79 79 174 174 142 142 + 173 172 141 189 191 191 142 245 63 173 140 93 2 102 171 128 + 143 191 47 46 95 45 2 43 3 3 39 4 4 5 5 36 + 139 172 172 140 140 140 140 141 47 141 141 141 141 142 191 191 + 2 2 2 31 94 45 95 158 158 1 47 159 159 141 141 174 + 24 246 246 63 20 23 62 75 19 21 62 62 245 63 173 79 + 239 239 75 75 76 77 77 77 78 78 78 79 79 174 142 142 + 246 246 245 245 139 139 172 140 140 1 47 141 141 141 142 142 + 172 172 140 140 173 141 174 174 25 41 39 38 5 5 4 4 + 186 186 187 124 125 125 126 126 126 127 127 127 191 191 143 143 + 27 246 246 171 139 139 172 140 140 47 141 141 142 142 143 143 + 3 155 42 156 43 93 44 30 31 45 158 1 47 159 141 174 + 138 170 171 171 171 172 77 77 173 78 79 174 174 142 175 175 + 186 186 186 187 187 187 188 188 188 189 46 46 47 141 174 143 + 41 155 155 43 43 44 30 157 102 1 1 159 159 159 142 143 + 206 205 205 205 205 205 101 36 36 151 152 16 16 60 61 61 + 61 61 61 73 74 74 75 75 75 75 76 78 78 79 174 79 + 171 136 138 2 127 142 78 86 90 169 171 37 4 155 169 160 + 143 191 47 95 2 2 3 244 4 5 37 6 33 7 8 8 + 26 246 245 245 63 63 172 140 140 1 47 141 141 141 141 142 + 3 3 3 43 43 43 2 31 94 95 158 158 46 47 141 141 + 40 22 23 62 83 17 20 62 55 60 61 61 62 245 172 78 + 168 238 238 238 74 75 76 76 77 77 78 78 79 79 174 142 + 41 91 23 100 26 246 246 245 245 139 140 140 1 141 141 79 + 246 245 245 172 140 140 141 79 135 133 36 33 7 32 33 35 + 183 185 186 122 123 124 124 125 125 126 126 126 127 191 191 175 + 41 136 91 137 246 246 246 139 139 140 140 47 141 142 142 143 + 5 153 153 40 154 41 155 155 43 43 2 45 158 1 159 174 + 136 168 169 169 170 239 171 76 77 77 173 78 79 142 175 191 + 183 183 184 185 185 186 186 187 187 188 188 189 126 127 141 142 + 152 153 153 154 41 155 156 156 101 101 207 207 159 159 159 142 + 202 204 204 203 203 203 204 146 146 147 147 214 54 59 59 59 + 59 60 60 236 70 71 71 72 73 74 75 76 77 78 78 79 + 169 134 137 244 158 159 78 131 165 167 245 148 6 153 166 160 + 143 141 158 2 3 3 4 5 35 33 7 8 9 9 10 11 + 21 23 23 24 246 245 245 63 172 172 46 1 159 141 141 141 + 38 4 4 4 39 3 3 43 44 2 94 45 95 46 47 47 + 37 85 18 20 49 51 16 61 58 59 60 97 61 62 63 77 + 166 70 237 71 72 73 74 75 76 76 77 78 78 79 79 174 + 153 86 86 88 22 22 23 26 246 246 157 103 140 140 141 79 + 90 62 246 245 139 140 141 79 132 131 128 8 10 9 8 32 + 181 182 116 118 119 119 119 123 124 125 126 126 127 191 191 142 + 134 135 135 88 136 169 169 137 170 139 172 140 141 141 142 143 + 149 150 151 152 152 153 153 40 154 155 43 44 31 158 47 79 + 84 166 167 168 168 238 238 239 75 76 77 173 79 174 142 191 + 181 181 182 183 183 184 185 185 186 187 187 188 189 126 159 142 + 148 150 151 152 153 202 202 203 204 205 206 206 207 159 159 159 + 211 210 213 201 201 202 202 11 11 144 144 52 57 57 57 58 + 58 58 229 230 234 234 69 70 70 71 72 74 75 77 78 78 + 166 131 183 185 187 126 173 48 163 165 87 10 147 49 83 160 + 143 47 45 43 3 4 5 6 7 8 9 9 11 12 12 13 + 18 20 21 21 23 62 246 245 245 63 172 140 1 141 141 141 + 35 35 5 5 38 4 39 3 3 43 44 2 94 95 46 173 + 254 82 16 61 53 54 55 60 57 58 59 55 61 61 62 76 + 250 68 69 236 70 71 71 73 75 75 76 77 77 78 78 79 + 151 83 84 84 86 86 89 22 23 24 246 245 103 140 141 79 + 98 61 62 246 245 63 173 78 255 128 106 11 12 110 110 112 + 113 114 115 116 117 118 119 119 123 124 125 125 126 127 191 142 + 131 163 164 165 166 167 168 136 137 170 139 172 140 159 142 143 + 146 147 148 149 150 150 151 153 153 39 41 43 44 102 1 78 + 163 250 68 69 70 237 71 238 238 239 76 172 173 141 142 191 + 179 179 180 181 182 182 183 184 184 186 186 187 188 189 47 142 + 145 196 196 197 200 201 201 202 203 204 205 205 206 207 159 159 + 209 209 210 212 213 200 152 14 13 251 218 219 221 222 225 225 + 226 226 227 228 229 230 233 234 236 236 70 71 73 75 77 76 + 162 161 241 184 186 189 77 105 104 163 165 251 144 48 80 48 + 143 47 2 3 4 5 6 7 8 9 10 11 13 14 15 215 + 84 17 17 19 20 21 23 246 246 246 245 103 140 173 141 141 + 33 33 34 35 35 5 38 39 39 3 43 93 2 94 95 140 + 147 49 50 55 247 53 54 60 56 56 58 59 60 61 62 75 + 249 65 233 234 236 70 71 72 73 74 75 75 76 77 78 78 + 254 50 50 82 84 84 85 88 99 22 24 246 245 172 173 78 + 97 166 61 23 246 245 173 78 160 105 252 251 14 108 109 110 + 111 113 114 115 116 117 118 118 119 119 124 125 126 127 191 175 + 130 130 131 132 133 134 135 135 136 137 246 139 140 47 174 143 + 144 144 145 146 147 148 199 150 151 153 40 41 43 30 158 173 + 161 162 163 164 165 166 237 237 238 239 239 76 173 79 174 191 + 176 177 178 178 179 180 182 183 183 184 185 186 187 188 46 142 + 144 144 194 195 196 197 200 201 202 203 204 205 206 207 159 159 + 209 208 210 211 212 213 198 215 216 216 218 218 220 220 220 222 + 224 224 226 226 228 229 229 230 234 234 236 70 71 75 76 76 + 65 161 241 184 185 188 77 252 248 64 165 216 252 253 48 104 + 143 47 2 3 5 6 7 8 10 11 12 13 14 15 15 215 + 51 96 16 16 17 19 21 23 24 26 246 245 172 140 173 47 + 8 32 32 33 34 35 5 5 4 4 244 3 43 2 95 172 + 253 48 49 54 247 52 53 59 219 225 56 58 59 60 62 75 + 162 64 65 233 234 69 70 237 73 73 74 75 75 76 78 78 + 147 254 49 80 50 83 83 85 86 88 91 24 246 63 173 78 + 96 60 61 61 62 245 172 77 105 252 251 215 15 15 108 108 + 110 111 113 114 115 116 116 117 118 119 123 125 126 127 191 175 + 128 255 255 255 131 132 133 134 88 168 170 246 172 140 141 143 + 11 11 144 144 145 146 147 148 149 151 153 40 155 43 102 173 + 160 104 64 162 163 164 166 237 237 238 239 76 77 79 174 191 + 177 176 176 176 177 179 180 181 182 183 184 185 187 188 46 142 + 11 192 144 144 195 196 197 198 201 202 203 204 205 207 159 159 + 209 208 209 210 211 212 197 215 215 216 217 218 219 220 220 220 + 222 224 224 226 226 228 228 229 230 233 234 236 71 73 76 76 + 65 161 241 184 184 188 77 252 247 53 163 215 14 252 105 160 + 143 46 43 4 35 7 8 10 11 12 14 15 15 15 15 215 + 49 55 55 96 97 17 19 21 22 24 26 246 63 172 140 173 + 9 9 8 8 32 33 34 35 5 38 4 244 3 2 94 103 + 106 48 48 54 217 52 52 58 219 222 225 56 58 60 61 74 + 248 64 232 232 233 234 234 70 71 72 73 74 75 76 77 78 + 253 48 48 48 49 50 82 83 84 85 89 91 26 245 172 77 + 54 60 60 61 62 62 171 77 106 252 216 215 215 15 15 14 + 108 110 111 113 115 115 116 116 117 118 119 123 125 126 191 142 + 106 105 160 160 255 162 132 132 134 167 136 170 139 140 141 175 + 251 107 252 11 144 144 145 147 148 150 152 153 154 43 31 77 + 105 248 64 64 64 250 164 69 70 237 238 239 172 173 174 191 + 109 176 176 176 176 177 178 180 181 182 183 185 186 187 95 141 + 13 252 11 11 144 194 195 214 198 201 202 203 205 206 207 159 + 209 208 209 210 211 212 195 215 215 216 216 218 219 220 220 220 + 220 222 224 224 226 226 227 228 229 230 234 234 70 71 75 75 + 65 161 241 184 184 188 63 216 252 248 104 215 215 251 106 160 + 143 95 3 38 33 7 9 11 12 14 15 15 15 15 15 215 + 49 54 54 55 55 16 17 19 20 23 23 246 245 63 140 173 + 10 10 9 8 8 8 32 34 35 5 4 4 244 43 2 245 + 252 105 253 53 217 52 52 58 219 220 223 56 58 59 61 73 + 248 228 228 229 230 233 234 236 70 71 72 73 74 75 77 78 + 144 253 146 48 48 49 150 50 83 84 86 99 100 246 172 77 + 54 54 60 97 61 62 171 77 252 251 215 215 215 15 15 15 + 14 108 110 113 115 115 115 116 116 117 119 123 125 126 127 174 + 106 247 105 160 160 255 162 162 133 135 136 137 171 140 141 175 + 215 251 251 107 252 10 144 145 146 148 150 152 40 155 2 172 + 247 248 248 160 65 64 66 68 69 237 238 239 171 173 174 143 + 14 108 110 176 176 176 177 178 180 181 182 184 186 187 95 141 + 216 216 251 252 144 144 194 195 197 200 201 203 204 206 207 207 + 208 208 208 209 211 194 144 215 15 215 216 217 219 220 220 220 + 220 221 224 224 224 226 226 227 228 229 230 234 236 71 75 75 + 65 160 241 184 183 187 207 216 247 247 53 215 215 14 252 160 + 143 95 3 5 7 8 10 12 13 15 15 15 15 15 15 215 + 48 54 54 54 55 96 16 17 19 20 23 62 246 245 172 46 + 11 11 10 9 9 8 7 7 33 5 5 4 4 3 43 245 + 252 247 247 53 217 218 52 57 218 219 221 224 57 59 61 73 + 56 227 227 228 229 230 233 234 236 70 71 73 73 75 77 77 + 106 105 105 253 48 48 48 150 50 152 84 86 91 26 139 77 + 53 59 250 163 17 23 246 77 252 216 215 215 215 15 15 15 + 15 14 109 111 113 115 115 115 116 117 118 119 124 126 190 174 + 252 247 247 247 160 160 161 161 163 165 135 136 138 172 141 175 + 215 215 14 251 107 252 252 144 145 195 199 151 153 155 2 172 + 252 247 248 248 64 64 65 66 68 70 237 239 171 173 79 175 + 15 14 14 108 176 176 176 177 178 180 182 183 184 186 94 79 + 216 216 216 251 252 192 192 194 196 197 201 202 203 156 207 207 + 208 208 209 210 218 144 10 15 15 215 216 217 219 220 220 220 + 219 220 221 224 224 224 226 226 240 240 240 233 234 71 74 75 + 65 160 241 184 183 3 157 216 217 247 52 216 215 215 251 160 + 143 94 3 35 8 9 11 13 15 15 15 15 15 15 15 215 + 53 53 53 54 54 55 55 16 17 19 21 23 246 245 63 158 + 12 109 11 10 10 9 8 7 7 35 35 5 4 244 43 245 + 216 247 247 52 217 218 56 56 218 219 220 222 56 58 60 72 + 247 226 226 226 228 229 230 234 69 236 70 71 73 74 76 77 + 252 252 105 105 105 48 48 49 49 50 83 85 99 24 245 77 + 53 58 249 55 16 23 62 77 252 215 215 15 15 15 15 15 + 15 15 108 110 113 114 115 115 116 116 118 119 124 126 127 174 + 252 252 247 247 247 160 160 104 162 164 166 136 170 139 141 175 + 215 216 216 216 251 107 107 11 144 145 148 150 152 39 43 63 + 252 247 248 247 248 64 64 66 67 69 70 238 239 77 79 175 + 15 15 15 14 108 176 176 176 178 179 181 182 184 186 188 141 + 216 216 216 216 217 144 192 144 195 214 198 202 203 205 206 207 + 208 208 209 218 218 218 192 15 215 215 216 217 218 219 220 220 + 220 220 220 224 224 224 224 226 240 240 240 240 233 70 73 74 + 65 161 241 185 182 3 157 216 216 247 52 216 215 215 251 160 + 143 31 4 34 8 10 12 14 15 15 15 15 15 15 15 215 + 52 53 53 53 54 55 55 96 16 17 19 23 246 246 245 103 + 13 108 109 11 11 10 9 8 7 33 34 5 38 244 3 246 + 216 247 247 247 217 218 218 56 218 218 219 220 225 57 60 72 + 247 56 226 226 228 228 229 230 234 69 70 71 71 73 76 76 + 252 251 252 247 105 105 48 48 49 49 82 153 88 23 246 76 + 52 57 58 54 16 19 62 76 251 215 215 15 15 15 15 15 + 15 15 14 110 113 113 114 115 115 116 117 119 123 125 127 174 + 251 247 247 247 247 248 248 160 161 163 165 88 137 139 140 175 + 215 215 216 216 215 14 251 107 11 144 146 149 36 4 156 207 + 252 247 247 248 248 248 64 65 66 68 236 237 239 77 79 175 + 15 15 15 15 14 14 176 176 176 178 180 182 183 185 188 46 + 215 216 216 216 216 217 144 192 194 214 198 200 203 205 206 207 + 208 208 210 219 219 218 217 215 15 215 216 216 218 219 219 220 + 220 220 220 221 224 224 224 225 240 240 240 240 233 236 72 74 + 65 160 241 184 182 244 2 215 216 247 247 215 215 215 215 160 +])) + +data diff --git a/demo/mod/first_person3d.fnl b/demo/mod/first_person3d.fnl index e45e089..7df90ea 100644 --- a/demo/mod/first_person3d.fnl +++ b/demo/mod/first_person3d.fnl @@ -1,13 +1,18 @@ (local pxl8 (require :pxl8)) (local effects (require :pxl8.effects)) (local net (require :pxl8.net)) + +(local colormap (require :mod.colormap)) +(local menu (require :mod.menu)) +(local palette (require :mod.palette)) (local sky (require :mod.sky)) +(local textures (require :mod.textures)) (local bob-amount 4.0) (local bob-speed 8.0) (local cam-smoothing 0.25) (local cell-size 64) -(local cursor-sensitivity 0.008) +(local cursor-sensitivity 0.010) (local gravity -800) (local grid-size 64) (local ground-y 64) @@ -16,7 +21,7 @@ (local land-squash-amount -4) (local max-pitch 1.5) (local move-speed 200) -(local turn-speed 2.0) +(local turn-speed 4.0) (local sim-tick-rate 60) (local sim-dt (/ 1.0 sim-tick-rate)) @@ -32,10 +37,10 @@ (var cam-yaw 0) (var cam-z 1000) (var camera nil) -(var cursor-look? true) (var grounded? true) (var land-squash 0) (var light-time 0) +(var real-time 0) (var network nil) (var smooth-cam-x 1000) (var smooth-cam-z 1000) @@ -43,16 +48,148 @@ (var world nil) (var fps-avg 0) (var fps-sample-count 0) +(var fireball-mesh nil) +(var last-dt 0.016) +(var lights nil) -(local FIREBALL_COLOR 184) +(local cursor-look? true) +(local FIREBALL_COLOR 218) +(local STONE_FLOOR_START 37) +(local STONE_WALL_START 2) +(local MOSS_COLOR 200) -(fn init-fireball-palette [] - (for [i 0 7] - (let [t (/ i 7) - r (math.floor (+ 0xFF (* t 0))) - g (math.floor (+ 0x60 (* t (- 0xE0 0x60)))) - b (math.floor (+ 0x10 (* t (- 0x80 0x10))))] - (pxl8.set_palette_rgb (+ FIREBALL_COLOR i) r g b)))) +(local trail-positions []) +(local TRAIL_LENGTH 8) + +(fn create-fireball-mesh [] + (let [verts [] + indices [] + radius 5 + rings 4 + segments 6 + core-color (+ FIREBALL_COLOR 6) + spike-color (+ FIREBALL_COLOR 2)] + + ;; top pole + (table.insert verts {:x 0 :y radius :z 0 :nx 0 :ny 1 :nz 0 :color core-color :light 255}) + + ;; sphere rings + (for [ring 1 (- rings 1)] + (let [phi (* (/ ring rings) math.pi) + sin-phi (math.sin phi) + cos-phi (math.cos phi) + y (* radius cos-phi) + ring-radius (* radius sin-phi)] + (for [seg 0 (- segments 1)] + (let [theta (* (/ seg segments) math.pi 2) + x (* ring-radius (math.cos theta)) + z (* ring-radius (math.sin theta)) + nx (* sin-phi (math.cos theta)) + nz (* sin-phi (math.sin theta))] + (table.insert verts {:x x :y y :z z :nx nx :ny cos-phi :nz nz :color core-color :light 255}))))) + + ;; bottom pole + (let [bottom-idx (length verts)] + (table.insert verts {:x 0 :y (- radius) :z 0 :nx 0 :ny -1 :nz 0 :color core-color :light 255}) + + ;; top cap triangles + (for [seg 0 (- segments 1)] + (let [next-seg (% (+ seg 1) segments)] + (table.insert indices 0) + (table.insert indices (+ 1 next-seg)) + (table.insert indices (+ 1 seg)))) + + ;; middle quads + (for [ring 0 (- rings 3)] + (for [seg 0 (- segments 1)] + (let [next-seg (% (+ seg 1) segments) + curr-row (+ 1 (* ring segments)) + next-row (+ 1 (* (+ ring 1) segments))] + (table.insert indices (+ curr-row seg)) + (table.insert indices (+ curr-row next-seg)) + (table.insert indices (+ next-row seg)) + (table.insert indices (+ curr-row next-seg)) + (table.insert indices (+ next-row next-seg)) + (table.insert indices (+ next-row seg))))) + + ;; bottom cap triangles + (let [last-ring-start (+ 1 (* (- rings 2) segments))] + (for [seg 0 (- segments 1)] + (let [next-seg (% (+ seg 1) segments)] + (table.insert indices bottom-idx) + (table.insert indices (+ last-ring-start seg)) + (table.insert indices (+ last-ring-start next-seg)))))) + + ;; add spikes - evenly distributed using golden ratio + (let [num-spikes 12 + spike-len 8 + base-size 1.2 + golden-ratio (/ (+ 1 (math.sqrt 5)) 2)] + (for [i 0 (- num-spikes 1)] + (let [;; fibonacci sphere distribution + y (- 1 (* (/ i (- num-spikes 1)) 2)) + r-at-y (math.sqrt (- 1 (* y y))) + theta (* math.pi 2 i golden-ratio) + nx (* r-at-y (math.cos theta)) + ny y + nz (* r-at-y (math.sin theta)) + ;; tangent vectors for base + tx (if (> (math.abs ny) 0.9) 1 0) + ty (if (> (math.abs ny) 0.9) 0 1) + tz 0 + ;; cross product for perpendicular + px (- (* ty nz) (* tz ny)) + py (- (* tz nx) (* tx nz)) + pz (- (* tx ny) (* ty nx)) + pl (math.sqrt (+ (* px px) (* py py) (* pz pz))) + px (/ px pl) py (/ py pl) pz (/ pz pl) + ;; second perpendicular + qx (- (* ny pz) (* nz py)) + qy (- (* nz px) (* nx pz)) + qz (- (* nx py) (* ny px)) + ;; base center inside sphere + bx (* radius 0.8 nx) + by (* radius 0.8 ny) + bz (* radius 0.8 nz) + ;; spike tip + sx (* (+ radius spike-len) nx) + sy (* (+ radius spike-len) ny) + sz (* (+ radius spike-len) nz) + base-idx (length verts)] + ;; 4 base vertices forming a square + (table.insert verts {:x (+ bx (* base-size px) (* base-size qx)) + :y (+ by (* base-size py) (* base-size qy)) + :z (+ bz (* base-size pz) (* base-size qz)) + :nx nx :ny ny :nz nz :color core-color :light 255}) + (table.insert verts {:x (+ bx (* base-size px) (* (- base-size) qx)) + :y (+ by (* base-size py) (* (- base-size) qy)) + :z (+ bz (* base-size pz) (* (- base-size) qz)) + :nx nx :ny ny :nz nz :color core-color :light 255}) + (table.insert verts {:x (+ bx (* (- base-size) px) (* (- base-size) qx)) + :y (+ by (* (- base-size) py) (* (- base-size) qy)) + :z (+ bz (* (- base-size) pz) (* (- base-size) qz)) + :nx nx :ny ny :nz nz :color core-color :light 255}) + (table.insert verts {:x (+ bx (* (- base-size) px) (* base-size qx)) + :y (+ by (* (- base-size) py) (* base-size qy)) + :z (+ bz (* (- base-size) pz) (* base-size qz)) + :nx nx :ny ny :nz nz :color core-color :light 255}) + ;; spike tip + (table.insert verts {:x sx :y sy :z sz :nx nx :ny ny :nz nz :color spike-color :light 255}) + ;; 4 triangular faces of pyramid + (table.insert indices base-idx) + (table.insert indices (+ base-idx 1)) + (table.insert indices (+ base-idx 4)) + (table.insert indices (+ base-idx 1)) + (table.insert indices (+ base-idx 2)) + (table.insert indices (+ base-idx 4)) + (table.insert indices (+ base-idx 2)) + (table.insert indices (+ base-idx 3)) + (table.insert indices (+ base-idx 4)) + (table.insert indices (+ base-idx 3)) + (table.insert indices base-idx) + (table.insert indices (+ base-idx 4))))) + + (set fireball-mesh (pxl8.create_mesh verts indices)))) (var client-tick 0) (var last-processed-tick 0) @@ -99,10 +236,22 @@ (values new-x new-z)) (fn init [] + (pxl8.set_relative_mouse_mode true) + (pxl8.set_palette palette 256) + (pxl8.set_colormap colormap 16384) + (for [i 0 7] + (let [t (/ i 7) + r 0xFF + g (math.floor (+ 0x60 (* t (- 0xE0 0x60)))) + b (math.floor (+ 0x10 (* t (- 0x80 0x10))))] + (pxl8.set_palette_rgb (+ FIREBALL_COLOR i) r g b))) + (sky.update-gradient 1 2 6 6 10 18) + (pxl8.update_palette_deps) (set camera (pxl8.create_camera_3d)) (set world (pxl8.create_world)) + (set lights (pxl8.create_lights)) (sky.generate-stars 12345) - (init-fireball-palette) + (create-fireball-mesh) (set network (net.Net.new {:port 7777})) (when network @@ -119,17 +268,9 @@ :num_rooms 20})] (if (< result 0) (pxl8.error (.. "Failed to generate rooms - result: " result)) - (let [floor-tex (pxl8.procgen_tex {:name "floor" - :seed 11111 - :width 64 - :height 64 - :base_color 19}) - wall-tex (pxl8.procgen_tex {:name "wall" - :seed 12345 - :width 64 - :height 64 - :base_color 4}) - sky-tex (pxl8.create_texture [0] 1 1)] + (let [floor-tex (textures.mossy-cobblestone 44444 STONE_FLOOR_START MOSS_COLOR) + wall-tex (textures.ashlar-wall 55555 STONE_WALL_START MOSS_COLOR) + sky-tex (pxl8.create_texture [0] 1 1)] (let [result (world:apply_textures [ {:name "floor" @@ -193,6 +334,7 @@ (store-position t cam-x cam-z hist.yaw)))))))))) (fn update [dt] + (set last-dt dt) (let [fps (pxl8.get_fps)] (set fps-sample-count (+ fps-sample-count 1)) (set fps-avg (+ (* fps-avg (/ (- fps-sample-count 1) fps-sample-count)) @@ -234,9 +376,9 @@ (when (and (not cursor-look?) (pxl8.key_down "down")) (set cam-pitch (math.max (- max-pitch) (- cam-pitch (* turn-speed dt))))) (when (and (not cursor-look?) (pxl8.key_down "left")) - (set cam-yaw (+ cam-yaw (* turn-speed dt)))) - (when (and (not cursor-look?) (pxl8.key_down "right")) (set cam-yaw (- cam-yaw (* turn-speed dt)))) + (when (and (not cursor-look?) (pxl8.key_down "right")) + (set cam-yaw (+ cam-yaw (* turn-speed dt)))) (when network (let [(ok err) (pcall (fn [] @@ -287,7 +429,8 @@ (let [target-phase (* (math.floor (/ bob-time math.pi)) math.pi)] (set bob-time (+ (* bob-time 0.8) (* target-phase 0.2)))))) - (set light-time (+ light-time (* dt 0.15)))))) + (set light-time (+ light-time (* dt 0.5))) + (set real-time (+ real-time dt))))) (fn frame [] (pxl8.clear 1) @@ -316,77 +459,57 @@ [0 1 0]) (camera:set_perspective 1.047 aspect 1.0 4096.0) - (let [light-pulse (+ 0.7 (* 0.3 (math.sin (* light-time 2)))) - forward-x (- (math.sin cam-yaw)) - forward-z (- (math.cos cam-yaw)) - light-x (+ smooth-cam-x (* 150 forward-x) (* 50 (math.cos light-time))) - light-z (+ smooth-cam-z (* 150 forward-z) (* 50 (math.sin light-time))) - light-y (+ eye-y 30)] - (pxl8.begin_frame_3d camera { - :ambient 80 + (let [light-x (+ 1000 (* 50 (math.cos light-time))) + light-z (+ 940 (* 50 (math.sin light-time))) + light-y 80 + phase (+ (* light-x 0.01) 1.7) + f1 (* 0.08 (math.sin (+ (* real-time 2.5) phase))) + f2 (* 0.05 (math.sin (+ (* real-time 4.1) (* phase 0.7)))) + f3 (* 0.03 (math.sin (+ (* real-time 7.3) (* phase 1.2)))) + flicker (+ 0.92 f1 f2 f3) + light-intensity (math.floor (math.max 0 (math.min 255 (* 255 flicker)))) + r1 (* 0.06 (math.sin (+ (* real-time 1.8) (* phase 0.5)))) + r2 (* 0.04 (math.sin (+ (* real-time 3.2) phase))) + light-radius (* 150 (+ 0.95 r1 r2))] + (lights:clear) + (lights:add light-x light-y light-z 255 200 150 light-intensity light-radius) + (pxl8.begin_frame_3d camera lights { + :ambient 30 + :fog_density 0.0 :celestial_dir [0.5 -0.8 0.3] - :celestial_intensity 0.5 - :lights [{:x light-x :y light-y :z light-z - :r 255 :g 200 :b 150 - :intensity (* 255 light-pulse) - :radius 400}]}) + :celestial_intensity 0.5}) (pxl8.clear_depth) (sky.update-gradient 1 2 6 6 10 18) - (sky.render smooth-cam-x eye-y smooth-cam-z) + (sky.render smooth-cam-x eye-y smooth-cam-z (menu.is-wireframe)) (pxl8.clear_depth) + (world:set_wireframe (menu.is-wireframe) 15) (world:render [smooth-cam-x eye-y smooth-cam-z]) - (pxl8.end_frame_3d) + (when fireball-mesh + (let [wire (menu.is-wireframe)] + (pxl8.draw_mesh fireball-mesh {:x light-x :y light-y :z light-z + :passthrough true + :wireframe wire + :emissive 1.0}))) - (let [dx (- light-x smooth-cam-x) - dy (- light-y eye-y) - dz (- light-z smooth-cam-z) - dist (math.sqrt (+ (* dx dx) (* dy dy) (* dz dz)))] - (when (> dist 1) - (let [inv-dist (/ 1 dist) - dir-x (* dx inv-dist) - dir-y (* dy inv-dist) - dir-z (* dz inv-dist) - cos-yaw (math.cos cam-yaw) - sin-yaw (math.sin cam-yaw) - cos-pitch (math.cos cam-pitch) - sin-pitch (math.sin cam-pitch) - rx (+ (* dir-x cos-yaw) (* dir-z sin-yaw)) - rz (+ (* (- dir-x) sin-yaw) (* dir-z cos-yaw)) - ry (- (* dir-y cos-pitch) (* rz sin-pitch)) - fz (+ (* dir-y sin-pitch) (* rz cos-pitch))] - (when (> fz 0.01) - (let [width (pxl8.get_width) - height (pxl8.get_height) - fov 1.047 - half-fov-tan (math.tan (* fov 0.5)) - ndc-x (/ rx (* fz half-fov-tan aspect)) - ndc-y (/ ry (* fz half-fov-tan)) - sx (math.floor (* (+ 1 ndc-x) 0.5 width)) - sy (math.floor (* (- 1 ndc-y) 0.5 height)) - screen-size (/ 400 dist) - base-radius (math.max 2 (math.min 12 (math.floor screen-size))) - pulse-int (math.floor (* 180 light-pulse))] - (when (and (>= sx 0) (< sx width) (>= sy 0) (< sy height)) - (effects.glows [ - {:x sx :y sy :radius (+ base-radius 2) :intensity (/ pulse-int 5) :color (+ FIREBALL_COLOR 1) :shape effects.GLOW_CIRCLE} - {:x sx :y sy :radius base-radius :intensity pulse-int :color (+ FIREBALL_COLOR 5) :shape effects.GLOW_DIAMOND}])))))))) + (pxl8.end_frame_3d)) - (sky.render-stars cam-yaw cam-pitch 1.0) + (sky.render-stars smooth-cam-x eye-y smooth-cam-z 1.0 last-dt) (let [cx (/ (pxl8.get_width) 2) cy (/ (pxl8.get_height) 2) crosshair-size 4 - red-color 18] - (pxl8.line (- cx crosshair-size) cy (+ cx crosshair-size) cy red-color) - (pxl8.line cx (- cy crosshair-size) cx (+ cy crosshair-size) red-color)) + crosshair-color 240 + text-color 251] + (pxl8.line (- cx crosshair-size) cy (+ cx crosshair-size) cy crosshair-color) + (pxl8.line cx (- cy crosshair-size) cx (+ cy crosshair-size) crosshair-color) - (pxl8.text (.. "fps: " (string.format "%.0f" fps-avg)) 5 5 12) - (pxl8.text (.. "pos: " (string.format "%.0f" cam-x) "," - (string.format "%.0f" cam-y) "," - (string.format "%.0f" cam-z)) 5 15 12)))) + (pxl8.text (.. "fps: " (string.format "%.0f" fps-avg)) 5 5 text-color) + (pxl8.text (.. "pos: " (string.format "%.0f" cam-x) "," + (string.format "%.0f" cam-y) "," + (string.format "%.0f" cam-z)) 5 15 text-color))))) {:init init :update update diff --git a/demo/mod/menu.fnl b/demo/mod/menu.fnl index d8b9834..689fc49 100644 --- a/demo/mod/menu.fnl +++ b/demo/mod/menu.fnl @@ -2,6 +2,7 @@ (local music (require :mod.music)) (var paused false) +(var wireframe false) (var gui nil) (fn init [] @@ -37,18 +38,22 @@ (when gui (gui:begin_frame) - (pxl8.gui_window 200 100 240 180 "pxl8 demo") + (pxl8.gui_window 200 100 240 200 "pxl8 demo") - (when (gui:button 1 215 145 210 32 "Resume") + (when (gui:button 1 215 147 210 30 "Resume") (hide)) (let [music-label (if (music.is-playing) "Music: On" "Music: Off")] - (when (gui:button 3 215 185 210 32 music-label) + (when (gui:button 3 215 182 210 30 music-label) (if (music.is-playing) (music.stop) (music.start)))) - (when (gui:button 2 215 225 210 32 "Quit") + (let [wire-label (if wireframe "Wireframe: On" "Wireframe: Off")] + (when (gui:button 4 215 217 210 30 wire-label) + (set wireframe (not wireframe)))) + + (when (gui:button 2 215 252 210 30 "Quit") (pxl8.quit)) (if (gui:is_hovering) @@ -58,6 +63,7 @@ (gui:end_frame))) {:is-paused (fn [] paused) + :is-wireframe (fn [] wireframe) :toggle toggle :show show :hide hide diff --git a/demo/mod/palette.fnl b/demo/mod/palette.fnl new file mode 100644 index 0000000..f97f744 --- /dev/null +++ b/demo/mod/palette.fnl @@ -0,0 +1,263 @@ +(require :pxl8) +(local ffi (require :ffi)) + +(local data (ffi.new "u32[256]" [ + 0x080602 + 0x14120E + 0x23211E + 0x31302C + 0x403E3B + 0x4B4946 + 0x595755 + 0x676664 + 0x767573 + 0x858382 + 0x939290 + 0xA2A09F + 0xB0AFAE + 0xBEBDBC + 0xCDCCCC + 0xDADAD9 + 0x594625 + 0x544023 + 0x4F3C24 + 0x4C3A22 + 0x453821 + 0x40321F + 0x3E2F20 + 0x382D1D + 0x33291E + 0x30271F + 0x2F251D + 0x2D231E + 0x28211C + 0x251F1D + 0x23201A + 0x221F1B + 0x646269 + 0x5F5C61 + 0x5C545A + 0x584F55 + 0x5B514F + 0x554A47 + 0x4B413F + 0x423C36 + 0x463D31 + 0x3E352A + 0x362E25 + 0x2D2922 + 0x26221D + 0x1C1916 + 0x151310 + 0x100F0D + 0x8C6F52 + 0x7E6045 + 0x73553B + 0x715134 + 0xBA8346 + 0xA1723B + 0x815C2E + 0x745226 + 0xCC8926 + 0xBB7E22 + 0x9F6B1F + 0x875A1C + 0x6E4918 + 0x553712 + 0x3B250D + 0x24180A + 0xA34331 + 0x9B3728 + 0x923220 + 0x882E18 + 0x842B16 + 0x772312 + 0x69200D + 0x5A1C06 + 0x541C04 + 0x4C1A03 + 0x411701 + 0x371000 + 0x2E0D00 + 0x250B00 + 0x1B0600 + 0x130500 + 0x7D5741 + 0x76503A + 0x6E4C37 + 0x684833 + 0x5D3F2F + 0x553A2C + 0x4F3628 + 0x483024 + 0x4A3126 + 0x483025 + 0x432D22 + 0x3C2C22 + 0x352922 + 0x2C241F + 0x221C1B + 0x1A1916 + 0x6E4626 + 0x5F4025 + 0x523924 + 0x433322 + 0x352B1E + 0x28231A + 0x1A1A14 + 0x1C1815 + 0x96544B + 0xAC7369 + 0xB48C86 + 0xBCA7A4 + 0xB1BCC2 + 0x9DB0B9 + 0x8A9FAA + 0x77929F + 0x738995 + 0x5E7C8B + 0x4A6C7D + 0x345E72 + 0x1F4C64 + 0x19445C + 0x143C51 + 0x10384B + 0x183748 + 0x1A3341 + 0x192F39 + 0x152B34 + 0x13262E + 0x101E23 + 0x0E1519 + 0x0B0E10 + 0x896463 + 0x815C5B + 0x785352 + 0x6F4C4D + 0x664444 + 0x5F3C3D + 0x573738 + 0x523233 + 0x442929 + 0x392324 + 0x2D1D1D + 0x241414 + 0x1A0E0E + 0x100909 + 0x070403 + 0x000000 + 0x98936F + 0x918B68 + 0x887F60 + 0x807759 + 0x797055 + 0x73684D + 0x6B6146 + 0x63593F + 0x5B523A + 0x504834 + 0x423D2D + 0x373226 + 0x2E2B1F + 0x222018 + 0x161511 + 0x0E0F0A + 0x9A554F + 0x904D48 + 0x87453F + 0x7D4037 + 0x743831 + 0x693329 + 0x612C24 + 0x572720 + 0x4F231A + 0x441E16 + 0x391914 + 0x2D150F + 0x22110D + 0x1A0B06 + 0x0D0403 + 0x040202 + 0x7F77C0 + 0x7770B5 + 0x6E68A8 + 0x686099 + 0x60588C + 0x575381 + 0x4E4C72 + 0x454263 + 0x3D3957 + 0x34324A + 0x2C2940 + 0x242135 + 0x1E1928 + 0x16121D + 0x0C0A12 + 0x050306 + 0x88AF7B + 0x81A473 + 0x7B9A67 + 0x728E5D + 0x6D8553 + 0x61794A + 0x5B7144 + 0x61734B + 0x586A3D + 0x4D5E2D + 0x465422 + 0x3F4D17 + 0x36420E + 0x2F3507 + 0x272804 + 0x211F02 + 0x1EF708 + 0x3CE10D + 0x51CC1B + 0x64B621 + 0x6DA12C + 0x69882B + 0x727F3B + 0xE4DDCE + 0xEEE6BA + 0xEAE290 + 0xE9E26D + 0xE5DE43 + 0xE3DB20 + 0xE1CC18 + 0xDFB911 + 0xDCA60B + 0xE8A306 + 0xDF9312 + 0xE17B05 + 0xC86815 + 0xBC5908 + 0xB14805 + 0xA63D07 + 0xB6431E + 0xAA381A + 0x9A2E12 + 0x8C270F + 0x892B17 + 0x762311 + 0x5F1F0D + 0x491B09 + 0x3B1809 + 0xE50F19 + 0x6A34C4 + 0xE00B28 + 0x2B08C8 + 0x322A33 + 0x281C0E + 0x2F1E15 + 0xD48067 + 0xC26B4C + 0x974928 + 0x814123 + 0xD5B3A9 + 0xBE9D93 + 0x9A7B6C + 0x7F5F51 + 0x8E504C +])) + +data diff --git a/demo/mod/sky.fnl b/demo/mod/sky.fnl index 49da5a5..426512b 100644 --- a/demo/mod/sky.fnl +++ b/demo/mod/sky.fnl @@ -1,23 +1,32 @@ -(local ffi (require :ffi)) (local pxl8 (require :pxl8)) -(local effects (require :pxl8.effects)) (local SKY_GRADIENT_START 144) (local SKY_GRADIENT_COUNT 16) (local sky-radius 900) (local sky-segments 16) (local sky-rings 16) -(local max-theta (* math.pi 0.55)) -(local STAR_COUNT 200) -(local TINY_STAR_COUNT 5000) -(local STAR_SILVER_START 160) -(local STAR_BLUE_START 168) -(local STAR_RED_START 176) +(local NUM_RANDOM_STARS 300) +(local NUM_TINY_STARS 7000) +(local STAR_SEED 0xDEADBEEF) +(local STAR_CYCLE_PERIOD 7200) + +;; Use existing bright palette colors +;; Silver/white: indices 14-15 (brightest grays) +(local IDX_SILVER 14) +;; Warm/torch: indices 216-218 (bright creams/yellows) +(local IDX_TORCH 216) +;; Blue/magic: indices 176-178 (purples - brightest of the range) +(local IDX_MAGIC 176) -(var sky-mesh nil) (var last-gradient-key nil) -(var stars []) +(var random-stars []) +(var sky-mesh nil) +(var star-count 0) +(var star-directions nil) +(var star-glows nil) +(var star-projected nil) +(var star-time 0) (var tiny-stars []) (fn generate-sky-gradient [zenith-r zenith-g zenith-b horizon-r horizon-g horizon-b] @@ -33,8 +42,8 @@ indices []] (for [i 0 (- sky-rings 1)] - (let [theta0 (* (/ i sky-rings) max-theta) - theta1 (* (/ (+ i 1) sky-rings) max-theta) + (let [theta0 (* (/ i sky-rings) math.pi 0.5) + theta1 (* (/ (+ i 1) sky-rings) math.pi 0.5) sin-t0 (math.sin theta0) cos-t0 (math.cos theta0) sin-t1 (math.sin theta1) @@ -67,22 +76,17 @@ (if (= i 0) (do - ;; First ring is degenerate - just a triangle from pole - ;; Vertices: v00 (pole, c0), v11 (bottom-right, c1), v10 (bottom-left, c1) (table.insert verts {:x x00 :y y0 :z z00 :nx nx00 :ny ny00 :nz nz00 :color c0 :light 255}) (table.insert verts {:x x11 :y y1 :z z11 :nx nx11 :ny ny11 :nz nz11 :color c1 :light 255}) (table.insert verts {:x x10 :y y1 :z z10 :nx nx10 :ny ny10 :nz nz10 :color c1 :light 255}) - ;; Triangle: base, base+2, base+1 (table.insert indices base-idx) (table.insert indices (+ base-idx 2)) (table.insert indices (+ base-idx 1))) (do - ;; Regular quad: v00 (top-left), v01 (top-right), v11 (bottom-right), v10 (bottom-left) (table.insert verts {:x x00 :y y0 :z z00 :nx nx00 :ny ny00 :nz nz00 :color c0 :light 255}) (table.insert verts {:x x01 :y y0 :z z01 :nx nx01 :ny ny01 :nz nz01 :color c0 :light 255}) (table.insert verts {:x x11 :y y1 :z z11 :nx nx11 :ny ny11 :nz nz11 :color c1 :light 255}) (table.insert verts {:x x10 :y y1 :z z10 :nx nx10 :ny ny10 :nz nz10 :color c1 :light 255}) - ;; push_quad(base, base+3, base+2, base+1) = triangles (base,base+3,base+2) and (base,base+2,base+1) (table.insert indices base-idx) (table.insert indices (+ base-idx 3)) (table.insert indices (+ base-idx 2)) @@ -98,149 +102,142 @@ (generate-sky-gradient zenith-r zenith-g zenith-b horizon-r horizon-g horizon-b) (set last-gradient-key key)))) -(fn palette-ramp [start c0 c1] - (let [r0 (bit.rshift (bit.band c0 0xFF0000) 16) - g0 (bit.rshift (bit.band c0 0x00FF00) 8) - b0 (bit.band c0 0x0000FF) - r1 (bit.rshift (bit.band c1 0xFF0000) 16) - g1 (bit.rshift (bit.band c1 0x00FF00) 8) - b1 (bit.band c1 0x0000FF)] - (for [i 0 7] - (let [t (/ i 7) - r (math.floor (+ r0 (* t (- r1 r0)))) - g (math.floor (+ g0 (* t (- g1 g0)))) - b (math.floor (+ b0 (* t (- b1 b0))))] - (pxl8.set_palette_rgb (+ start i) r g b))))) +(fn galactic-band-factor [dx dy dz] + (let [band-len (math.sqrt (+ (* 0.6 0.6) (* 0.3 0.3) (* 0.742 0.742))) + bx (/ 0.6 band-len) + by (/ 0.3 band-len) + bz (/ 0.742 band-len) + dist-from-band (math.abs (+ (* dx bx) (* dy by) (* dz bz))) + in-band (- 1 (math.min (* dist-from-band 3) 1))] + (* in-band in-band))) -(fn init-star-palette [] - (palette-ramp STAR_SILVER_START 0x707888 0xFFFFFF) ;; silver - (palette-ramp STAR_BLUE_START 0x5070B0 0xD0E8FF) ;; blue - (palette-ramp STAR_RED_START 0x802020 0xFF9090)) ;; red - -(fn generate-stars [seed] - (set stars []) +(fn generate-stars [] + (set random-stars []) (set tiny-stars []) - (init-star-palette) - (pxl8.rng_seed seed) - (for [i 1 STAR_COUNT] - (let [theta (math.acos (- 1 (* (pxl8.rng_f32) 0.85))) - phi (* (pxl8.rng_f32) math.pi 2) - brightness (pxl8.rng_range 1 4) - color-type (pxl8.rng_range 0 100) - shade (pxl8.rng_range 0 5) - color (if (< color-type 3) (+ STAR_RED_START shade) - (< color-type 15) (+ STAR_BLUE_START shade) - (+ STAR_SILVER_START shade)) - sin-t (math.sin theta) - cos-t (math.cos theta)] - (table.insert stars {:dx (* sin-t (math.cos phi)) - :dy cos-t - :dz (* sin-t (math.sin phi)) - :brightness brightness - :color color}))) + ;; Generate random stars - use full upper hemisphere (dy > -0.1) + (for [i 0 (- NUM_RANDOM_STARS 1)] + (let [h1 (pxl8.hash32 (+ STAR_SEED (* i 5))) + h2 (pxl8.hash32 (+ STAR_SEED (* i 5) 1)) + h3 (pxl8.hash32 (+ STAR_SEED (* i 5) 2)) + h4 (pxl8.hash32 (+ STAR_SEED (* i 5) 3)) + theta (* (/ h1 0xFFFFFFFF) math.pi 2) + phi (math.acos (- 1 (* (/ h2 0xFFFFFFFF) 1.0))) + sin-phi (math.sin phi) + cos-phi (math.cos phi) + dx (* sin-phi (math.cos theta)) + dy cos-phi + dz (* sin-phi (math.sin theta)) + brightness-raw (/ (% h3 256) 255) + brightness (math.floor (+ 60 (* brightness-raw brightness-raw 195))) + color-type (% h4 100) + color (if (< color-type 8) (+ IDX_TORCH (% (bit.rshift h4 8) 2)) + (< color-type 16) (+ IDX_MAGIC (% (bit.rshift h4 8) 2)) + (+ IDX_SILVER (% (bit.rshift h4 8) 2)))] - (pxl8.rng_seed (+ seed 0xCAFEBABE)) - (for [i 1 TINY_STAR_COUNT] - (let [theta (math.acos (- 1 (* (pxl8.rng_f32) 0.95))) - phi (* (pxl8.rng_f32) math.pi 2) - brightness (+ 25 (pxl8.rng_range 0 40)) - shade (pxl8.rng_range 0 3) - color-type (pxl8.rng_range 0 100) - color (if (< color-type 15) (+ STAR_BLUE_START shade) - (+ STAR_SILVER_START shade)) - sin-t (math.sin theta) - cos-t (math.cos theta)] - (table.insert tiny-stars {:dx (* sin-t (math.cos phi)) - :dy cos-t - :dz (* sin-t (math.sin phi)) - :brightness brightness - :color color})))) + (when (> dy -0.1) + (table.insert random-stars {:dx dx :dy dy :dz dz + :brightness brightness + :color color})))) -(fn project-direction [dir-x dir-y dir-z yaw pitch width height] - (let [cos-yaw (math.cos yaw) - sin-yaw (math.sin yaw) - cos-pitch (math.cos pitch) - sin-pitch (math.sin pitch) - rotated-x (+ (* dir-x cos-yaw) (* dir-z sin-yaw)) - rotated-z (+ (* (- dir-x) sin-yaw) (* dir-z cos-yaw)) - rotated-y (- (* dir-y cos-pitch) (* rotated-z sin-pitch)) - final-z (+ (* dir-y sin-pitch) (* rotated-z cos-pitch))] - (when (> final-z 0.01) - (let [fov 1.047 - aspect (/ width height) - half-fov-tan (math.tan (* fov 0.5)) - ndc-x (/ rotated-x (* final-z half-fov-tan aspect)) - ndc-y (/ rotated-y (* final-z half-fov-tan))] - (when (and (>= ndc-x -1) (<= ndc-x 1) (>= ndc-y -1) (<= ndc-y 1)) - {:x (math.floor (* (+ 1 ndc-x) 0.5 width)) - :y (math.floor (* (- 1 ndc-y) 0.5 height))}))))) + (let [tiny-seed (+ STAR_SEED 0xCAFEBABE)] + (for [i 0 (- NUM_TINY_STARS 1)] + (let [h1 (pxl8.hash32 (+ tiny-seed (* i 4))) + h2 (pxl8.hash32 (+ tiny-seed (* i 4) 1)) + h3 (pxl8.hash32 (+ tiny-seed (* i 4) 2)) + h4 (pxl8.hash32 (+ tiny-seed (* i 4) 3)) + theta (* (/ h1 0xFFFFFFFF) math.pi 2) + phi (math.acos (- 1 (* (/ h2 0xFFFFFFFF) 1.0))) + sin-phi (math.sin phi) + cos-phi (math.cos phi) + dx (* sin-phi (math.cos theta)) + dy cos-phi + dz (* sin-phi (math.sin theta)) + band-boost (galactic-band-factor dx dy dz) + base-bright (+ 40 (% h3 50)) + brightness (+ base-bright (math.floor (* band-boost 40))) + color-shift (% h4 100) + color (if (< color-shift 3) (+ IDX_TORCH (% (bit.rshift h4 8) 2)) + (< color-shift 12) (+ IDX_MAGIC (% (bit.rshift h4 8) 2)) + (+ IDX_SILVER (% (bit.rshift h4 8) 2)))] + (when (> dy -0.1) + (table.insert tiny-stars {:dx dx :dy dy :dz dz + :brightness brightness + :color color}))))) -(fn render-stars [yaw pitch intensity] - (when (> intensity 0) - (let [width (pxl8.get_width) - height (pxl8.get_height) - glows [] - fade-sq (* intensity intensity)] + (set star-count (+ (length tiny-stars) (length random-stars))) + (set star-directions (pxl8.create_vec3_array star-count)) + (set star-glows (pxl8.create_glows 10000)) + (set star-projected (pxl8.create_vec3_array star-count)) - (each [_ star (ipairs tiny-stars)] - (let [screen (project-direction star.dx star.dy star.dz yaw pitch width height)] - (when screen - (let [int (math.floor (* star.brightness fade-sq))] + (var idx 0) + (each [_ star (ipairs tiny-stars)] + (let [dir (. star-directions idx)] + (set dir.x star.dx) + (set dir.y star.dy) + (set dir.z star.dz)) + (set idx (+ idx 1))) + (each [_ star (ipairs random-stars)] + (let [dir (. star-directions idx)] + (set dir.x star.dx) + (set dir.y star.dy) + (set dir.z star.dz)) + (set idx (+ idx 1)))) + +(fn render-stars [cam-x cam-y cam-z intensity dt] + (set star-time (+ star-time (or dt 0))) + (when (and (> intensity 0) (> star-count 0) star-glows) + (let [fade-in (* intensity intensity) + time-factor (/ star-time 60) + star-rotation (/ (* star-time math.pi 2) STAR_CYCLE_PERIOD) + t (pxl8.mat4_translate cam-x cam-y cam-z) + r (pxl8.mat4_rotate_y star-rotation) + s (pxl8.mat4_scale sky-radius sky-radius sky-radius) + transform (pxl8.mat4_multiply t (pxl8.mat4_multiply r s)) + tiny-count (length tiny-stars)] + + (star-glows:clear) + (pxl8.project_points star-directions star-projected star-count transform) + + (for [i 0 (- tiny-count 1)] + (let [screen (. star-projected i)] + (when (> screen.z 0) + (let [star (. tiny-stars (+ i 1)) + int (math.floor (* star.brightness fade-in))] (when (> int 8) - (table.insert glows {:x screen.x :y screen.y - :radius 1 - :intensity int - :color star.color - :shape effects.GLOW_CIRCLE})))))) + (star-glows:add (math.floor screen.x) (math.floor screen.y) + 1 int star.color pxl8.GLOW_CIRCLE)))))) - (each [_ star (ipairs stars)] - (let [screen (project-direction star.dx star.dy star.dz yaw pitch width height)] - (when screen - (let [base-int (math.floor (* star.brightness 50 fade-sq 1.5))] - (if (>= star.brightness 4) + (for [i 0 (- (length random-stars) 1)] + (let [screen (. star-projected (+ tiny-count i))] + (when (> screen.z 0) + (let [star (. random-stars (+ i 1)) + phase (+ (* (+ i 1) 2.137) (* time-factor 3.0)) + twinkle (+ 0.75 (* 0.25 (math.sin (* phase 6.28)))) + int (math.floor (* star.brightness fade-in twinkle)) + sx (math.floor screen.x) + sy (math.floor screen.y)] + (if (> star.brightness 220) (do - (table.insert glows {:x screen.x :y screen.y - :radius 4 - :intensity (math.floor (/ base-int 4)) - :color star.color - :shape effects.GLOW_CIRCLE}) - (table.insert glows {:x screen.x :y screen.y - :radius 2 - :intensity base-int - :color star.color - :shape effects.GLOW_DIAMOND})) - (>= star.brightness 3) + (star-glows:add sx sy 3 (math.floor (* int 1.5)) star.color pxl8.GLOW_DIAMOND) + (star-glows:add sx sy 5 (math.floor (/ int 2)) star.color pxl8.GLOW_CIRCLE)) + (> star.brightness 180) (do - (table.insert glows {:x screen.x :y screen.y - :radius 3 - :intensity (math.floor (/ base-int 4)) - :color star.color - :shape effects.GLOW_CIRCLE}) - (table.insert glows {:x screen.x :y screen.y - :radius 2 - :intensity base-int - :color star.color - :shape effects.GLOW_DIAMOND})) - (>= star.brightness 2) - (table.insert glows {:x screen.x :y screen.y - :radius 2 - :intensity base-int - :color star.color - :shape effects.GLOW_DIAMOND}) - (table.insert glows {:x screen.x :y screen.y - :radius 1 - :intensity (math.floor (* base-int 0.7)) - :color star.color - :shape effects.GLOW_CIRCLE})))))) + (star-glows:add sx sy 2 int star.color pxl8.GLOW_DIAMOND) + (star-glows:add sx sy 4 (math.floor (/ int 3)) star.color pxl8.GLOW_CIRCLE)) + (> star.brightness 120) + (do + (star-glows:add sx sy 2 (math.floor (* int 0.67)) star.color pxl8.GLOW_DIAMOND) + (star-glows:add sx sy 3 (math.floor (/ int 4)) star.color pxl8.GLOW_CIRCLE)) + (star-glows:add sx sy 2 (math.floor (* int 0.5)) star.color pxl8.GLOW_CIRCLE)))))) - (when (> (length glows) 0) - (effects.glows glows))))) + (when (> (star-glows:count) 0) + (star-glows:render))))) -(fn render [cam-x cam-y cam-z] +(fn render [cam-x cam-y cam-z wireframe] (when (not sky-mesh) (create-sky-dome)) (when sky-mesh - (pxl8.draw_mesh sky-mesh {:x cam-x :y cam-y :z cam-z :passthrough true}))) + (pxl8.draw_mesh sky-mesh {:x cam-x :y cam-y :z cam-z :passthrough true :wireframe wireframe}))) {:render render :render-stars render-stars diff --git a/demo/mod/textures.fnl b/demo/mod/textures.fnl new file mode 100644 index 0000000..c4966ef --- /dev/null +++ b/demo/mod/textures.fnl @@ -0,0 +1,168 @@ +(local pxl8 (require :pxl8)) +(local procgen (require :pxl8.procgen)) + +(local textures {}) + +(fn build-graph [seed builder] + (let [g (pxl8.create_graph 128) + x (g:add_node procgen.OP_INPUT_X 0 0 0 0 0) + y (g:add_node procgen.OP_INPUT_Y 0 0 0 0 0) + ctx {:graph g :x x :y y}] + (g:set_seed seed) + (let [output (builder ctx)] + (g:set_output output) + g))) + +(fn const [ctx val] + (ctx.graph:add_node procgen.OP_CONST 0 0 0 0 val)) + +(fn add [ctx a b] + (ctx.graph:add_node procgen.OP_ADD a b 0 0 0)) + +(fn sub [ctx a b] + (ctx.graph:add_node procgen.OP_SUB a b 0 0 0)) + +(fn mul [ctx a b] + (ctx.graph:add_node procgen.OP_MUL a b 0 0 0)) + +(fn div [ctx a b] + (ctx.graph:add_node procgen.OP_DIV a b 0 0 0)) + +(fn min-op [ctx a b] + (ctx.graph:add_node procgen.OP_MIN a b 0 0 0)) + +(fn max-op [ctx a b] + (ctx.graph:add_node procgen.OP_MAX a b 0 0 0)) + +(fn abs [ctx a] + (ctx.graph:add_node procgen.OP_ABS a 0 0 0 0)) + +(fn floor [ctx a] + (ctx.graph:add_node procgen.OP_FLOOR a 0 0 0 0)) + +(fn fract [ctx a] + (ctx.graph:add_node procgen.OP_FRACT a 0 0 0 0)) + +(fn lerp [ctx a b t] + (ctx.graph:add_node procgen.OP_LERP a b t 0 0)) + +(fn clamp [ctx val lo hi] + (ctx.graph:add_node procgen.OP_CLAMP val lo hi 0 0)) + +(fn select [ctx cond a b] + (ctx.graph:add_node procgen.OP_SELECT a b cond 0 0)) + +(fn smoothstep [ctx edge0 edge1 x] + (ctx.graph:add_node procgen.OP_SMOOTHSTEP edge0 edge1 x 0 0)) + +(fn noise-value [ctx scale] + (let [s (const ctx scale)] + (ctx.graph:add_node procgen.OP_NOISE_VALUE ctx.x ctx.y s 0 0))) + +(fn noise-perlin [ctx scale] + (let [s (const ctx scale)] + (ctx.graph:add_node procgen.OP_NOISE_PERLIN ctx.x ctx.y s 0 0))) + +(fn noise-fbm [ctx octaves scale persistence] + (let [s (const ctx scale) + p (const ctx persistence)] + (ctx.graph:add_node procgen.OP_NOISE_FBM ctx.x ctx.y s p octaves))) + +(fn noise-ridged [ctx octaves scale persistence] + (let [s (const ctx scale) + p (const ctx persistence)] + (ctx.graph:add_node procgen.OP_NOISE_RIDGED ctx.x ctx.y s p octaves))) + +(fn noise-turbulence [ctx octaves scale persistence] + (let [s (const ctx scale) + p (const ctx persistence)] + (ctx.graph:add_node procgen.OP_NOISE_TURBULENCE ctx.x ctx.y s p octaves))) + +(fn voronoi-cell [ctx scale] + (let [s (const ctx scale)] + (ctx.graph:add_node procgen.OP_VORONOI_CELL ctx.x ctx.y s 0 0))) + +(fn voronoi-edge [ctx scale] + (let [s (const ctx scale)] + (ctx.graph:add_node procgen.OP_VORONOI_EDGE ctx.x ctx.y s 0 0))) + +(fn voronoi-id [ctx scale] + (let [s (const ctx scale)] + (ctx.graph:add_node procgen.OP_VORONOI_ID ctx.x ctx.y s 0 0))) + +(fn gradient-linear [ctx angle] + (let [a (const ctx angle)] + (ctx.graph:add_node procgen.OP_GRADIENT_LINEAR ctx.x ctx.y a 0 0))) + +(fn gradient-radial [ctx cx cy] + (let [center-x (const ctx cx) + center-y (const ctx cy)] + (ctx.graph:add_node procgen.OP_GRADIENT_RADIAL ctx.x ctx.y center-x center-y 0))) + +(fn quantize [ctx val base range] + (let [r (const ctx range)] + (ctx.graph:add_node procgen.OP_QUANTIZE val r 0 0 base))) + +(fn textures.mossy-cobblestone [seed base-color moss-color] + (let [g (build-graph seed + (fn [ctx] + (let [cell (voronoi-cell ctx 6) + edge (voronoi-edge ctx 6) + mortar-threshold (const ctx 0.05) + is-mortar (sub ctx mortar-threshold edge) + mortar-color (const ctx (- base-color 2)) + stone-detail (noise-value ctx 48) + stone-base (mul ctx cell (const ctx 0.6)) + stone-combined (add ctx stone-base (mul ctx stone-detail (const ctx 0.4))) + stone-quant (quantize ctx stone-combined base-color 8) + moss-pattern (noise-fbm ctx 4 10 0.5) + moss-detail (noise-value ctx 64) + moss-var (add ctx (mul ctx moss-pattern (const ctx 0.7)) + (mul ctx moss-detail (const ctx 0.3))) + moss-threshold (const ctx 0.55) + has-moss (sub ctx moss-pattern moss-threshold) + moss-quant (quantize ctx moss-var moss-color 6) + stone-or-moss (select ctx has-moss moss-quant stone-quant)] + (select ctx is-mortar mortar-color stone-or-moss))))] + (let [tex-id (g:eval_texture 64 64)] + (g:destroy) + tex-id))) + +(fn textures.ashlar-wall [seed base-color moss-color] + (let [g (build-graph seed + (fn [ctx] + (let [cell (voronoi-cell ctx 5) + edge (voronoi-edge ctx 5) + cell-id (voronoi-id ctx 5) + mortar-threshold (const ctx 0.12) + is-mortar (sub ctx mortar-threshold edge) + stone-detail (noise-fbm ctx 3 32 0.5) + stone-tint (mul ctx cell-id (const ctx 0.4)) + stone-shade (mul ctx cell (const ctx 0.3)) + stone-combined (add ctx stone-detail (add ctx stone-tint stone-shade)) + stone-quant (quantize ctx stone-combined base-color 10) + crack-moss (noise-fbm ctx 3 16 0.5) + moss-in-crack (mul ctx crack-moss (sub ctx (const ctx 0.2) edge)) + moss-threshold (const ctx 0.06) + has-moss (sub ctx moss-in-crack moss-threshold) + moss-quant (quantize ctx crack-moss moss-color 4) + mortar-color (const ctx (+ base-color 1)) + stone-or-moss (select ctx has-moss moss-quant stone-quant)] + (select ctx is-mortar mortar-color stone-or-moss))))] + (let [tex-id (g:eval_texture 64 64)] + (g:destroy) + tex-id))) + +(fn textures.gradient-sky [seed zenith-color horizon-color] + (let [g (build-graph seed + (fn [ctx] + (let [grad (gradient-linear ctx (* math.pi 0.5)) + zenith (const ctx zenith-color) + horizon (const ctx horizon-color) + range (const ctx (- horizon-color zenith-color))] + (quantize ctx grad zenith-color (- horizon-color zenith-color)))))] + (let [tex-id (g:eval_texture 64 64)] + (g:destroy) + tex-id))) + +textures diff --git a/demo/profile_3d.fnl b/demo/profile_3d.fnl new file mode 100644 index 0000000..461c45a --- /dev/null +++ b/demo/profile_3d.fnl @@ -0,0 +1,5 @@ +(local first_person3d (require :mod.first_person3d)) + +(global init first_person3d.init) +(global update first_person3d.update) +(global frame first_person3d.frame) diff --git a/pxl8.sh b/pxl8.sh index 93fb8dc..4dec268 100755 --- a/pxl8.sh +++ b/pxl8.sh @@ -62,12 +62,17 @@ build_server() { print_info "Building server ($mode mode)" cd server if [[ "$mode" == "release" ]]; then - cargo build --release > /dev/null 2>&1 + cargo build --release else - cargo build > /dev/null 2>&1 + cargo build fi + local status=$? cd - > /dev/null - print_info "Built server" + if [[ $status -eq 0 ]]; then + print_info "Built server" + else + print_error "Server build failed" + fi fi } @@ -79,11 +84,16 @@ start_server() { else server_bin="server/target/debug/pxl8-server" fi + print_info "Server mode: $mode, binary: $server_bin" if [[ -f "$server_bin" ]]; then - print_info "Starting server" + print_info "Starting server..." ./$server_bin & SERVER_PID=$! - sleep 0.2 + print_info "Server started with PID $SERVER_PID" + sleep 0.5 + else + print_error "Server binary not found: $server_bin" + print_error "Build the server first with: cd server && cargo build" fi } @@ -213,7 +223,7 @@ timestamp() { update_fennel() { print_info "Fetching Fennel" - local version="1.6.0" + local version="1.6.1" if curl -sL --max-time 5 -o lib/fennel/fennel.lua "https://fennel-lang.org/downloads/fennel-${version}.lua" 2>/dev/null; then if [[ -f "lib/fennel/fennel.lua" ]] && [[ -s "lib/fennel/fennel.lua" ]]; then @@ -304,7 +314,8 @@ for arg in "$@"; do done if [ "$MODE" = "release" ]; then - CFLAGS="$CFLAGS -O3 -ffast-math -funroll-loops -fno-unwind-tables -fno-asynchronous-unwind-tables" + CFLAGS="$CFLAGS -O3 -flto -ffast-math -funroll-loops -fno-unwind-tables -fno-asynchronous-unwind-tables" + LINKER_FLAGS="$LINKER_FLAGS -flto" BUILDDIR="$BUILDDIR/release" BINDIR="$BINDIR/release" else @@ -313,7 +324,7 @@ else BINDIR="$BINDIR/debug" fi -DEP_CFLAGS="-O3 -ffast-math -funroll-loops" +DEP_CFLAGS="-O3 -funroll-loops" case "$COMMAND" in build) @@ -360,7 +371,7 @@ case "$COMMAND" in print_info "Compiler cache: ccache enabled" fi - INCLUDES="-Isrc/core -Isrc/math -Isrc/gfx -Isrc/sfx -Isrc/script -Isrc/hal -Isrc/world -Isrc/asset -Isrc/game -Isrc/net -Ilib -Ilib/luajit/src -Ilib/linenoise -Ilib/miniz" + INCLUDES="-Isrc/asset -Isrc/core -Isrc/gfx -Isrc/gui -Isrc/hal -Isrc/math -Isrc/net -Isrc/procgen -Isrc/script -Isrc/sfx -Isrc/world -Ilib/linenoise -Ilib/luajit/src -Ilib/miniz" COMPILE_FLAGS="$CFLAGS $INCLUDES" DEP_COMPILE_FLAGS="$DEP_CFLAGS $INCLUDES" @@ -377,7 +388,6 @@ case "$COMMAND" in src/math/pxl8_math.c src/gfx/pxl8_anim.c src/gfx/pxl8_atlas.c - src/gfx/pxl8_blend.c src/gfx/pxl8_blit.c src/gfx/pxl8_3d_camera.c src/gfx/pxl8_colormap.c @@ -385,6 +395,9 @@ case "$COMMAND" in src/gfx/pxl8_dither.c src/gfx/pxl8_font.c src/gfx/pxl8_gfx.c + src/gfx/pxl8_glows.c + src/gfx/pxl8_lightmap.c + src/gfx/pxl8_lights.c src/gfx/pxl8_mesh.c src/gfx/pxl8_palette.c src/gfx/pxl8_particles.c @@ -394,15 +407,17 @@ case "$COMMAND" in src/sfx/pxl8_sfx.c src/script/pxl8_repl.c src/script/pxl8_script.c - src/hal/pxl8_sdl3.c + src/hal/pxl8_hal_sdl3.c + src/hal/pxl8_mem_sdl3.c src/world/pxl8_bsp.c src/world/pxl8_gen.c src/world/pxl8_world.c + src/procgen/pxl8_graph.c src/asset/pxl8_ase.c src/asset/pxl8_cart.c src/asset/pxl8_save.c - src/game/pxl8_gui.c - src/game/pxl8_replay.c + src/gui/pxl8_gui.c + src/core/pxl8_replay.c src/net/pxl8_net.c src/net/pxl8_protocol.c " @@ -477,7 +492,7 @@ case "$COMMAND" in RUN_SERVER=false for arg in "$@"; do if [[ "$arg" == "--release" ]]; then - continue + MODE="release" elif [[ "$arg" == "--repl" ]]; then EXTRA_ARGS="$EXTRA_ARGS --repl" elif [[ "$arg" == "--server" ]]; then diff --git a/server/build.rs b/server/build.rs index e9b3b52..5c30ae3 100644 --- a/server/build.rs +++ b/server/build.rs @@ -3,14 +3,14 @@ use std::path::PathBuf; fn main() { let manifest_dir = env::var("CARGO_MANIFEST_DIR").unwrap(); - let client_src = PathBuf::from(&manifest_dir).join("../client/src"); + let pxl8_src = PathBuf::from(&manifest_dir).join("../src"); - println!("cargo:rerun-if-changed=../client/src/net/pxl8_protocol.h"); - println!("cargo:rerun-if-changed=../client/src/core/pxl8_types.h"); + println!("cargo:rerun-if-changed=../src/net/pxl8_protocol.h"); + println!("cargo:rerun-if-changed=../src/core/pxl8_types.h"); let bindings = bindgen::Builder::default() - .header(client_src.join("net/pxl8_protocol.h").to_str().unwrap()) - .clang_arg(format!("-I{}", client_src.join("core").display())) + .header(pxl8_src.join("net/pxl8_protocol.h").to_str().unwrap()) + .clang_arg(format!("-I{}", pxl8_src.join("core").display())) .use_core() .rustified_enum(".*") .generate() diff --git a/src/asset/pxl8_ase.c b/src/asset/pxl8_ase.c index 36f9620..df78459 100644 --- a/src/asset/pxl8_ase.c +++ b/src/asset/pxl8_ase.c @@ -14,6 +14,7 @@ #include "pxl8_io.h" #include "pxl8_log.h" +#include "pxl8_mem.h" static pxl8_result parse_ase_header(pxl8_stream* stream, pxl8_ase_header* header) { header->file_size = pxl8_read_u32(stream); @@ -58,7 +59,7 @@ static pxl8_result parse_old_palette_chunk(pxl8_stream* stream, pxl8_ase_palette palette->entry_count = total_colors; palette->first_color = 0; palette->last_color = total_colors - 1; - palette->colors = (u32*)malloc(total_colors * sizeof(u32)); + palette->colors = (u32*)pxl8_malloc(total_colors * sizeof(u32)); if (!palette->colors) { return PXL8_ERROR_OUT_OF_MEMORY; } @@ -97,7 +98,7 @@ static pxl8_result parse_layer_chunk(pxl8_stream* stream, pxl8_ase_layer* layer) u16 name_len = pxl8_read_u16(stream); if (name_len > 0) { - layer->name = (char*)malloc(name_len + 1); + layer->name = (char*)pxl8_malloc(name_len + 1); if (!layer->name) return PXL8_ERROR_OUT_OF_MEMORY; pxl8_read_bytes(stream, layer->name, name_len); layer->name[name_len] = '\0'; @@ -120,7 +121,7 @@ static pxl8_result parse_palette_chunk(pxl8_stream* stream, pxl8_ase_palette* pa return PXL8_ERROR_ASE_MALFORMED_CHUNK; } - palette->colors = (u32*)malloc(color_count * sizeof(u32)); + palette->colors = (u32*)pxl8_malloc(color_count * sizeof(u32)); if (!palette->colors) { return PXL8_ERROR_OUT_OF_MEMORY; } @@ -154,7 +155,7 @@ static pxl8_result parse_user_data_chunk(pxl8_stream* stream, pxl8_ase_user_data if (user_data->has_text) { u16 text_len = pxl8_read_u16(stream); if (text_len > 0) { - user_data->text = (char*)malloc(text_len + 1); + user_data->text = (char*)pxl8_malloc(text_len + 1); if (!user_data->text) return PXL8_ERROR_OUT_OF_MEMORY; pxl8_read_bytes(stream, user_data->text, text_len); user_data->text[text_len] = '\0'; @@ -174,14 +175,14 @@ static pxl8_result parse_user_data_chunk(pxl8_stream* stream, pxl8_ase_user_data u32 num_properties = pxl8_read_u32(stream); if (num_properties > 0) { - user_data->properties = (pxl8_ase_property*)calloc(num_properties, sizeof(pxl8_ase_property)); + user_data->properties = (pxl8_ase_property*)pxl8_calloc(num_properties, sizeof(pxl8_ase_property)); if (!user_data->properties) return PXL8_ERROR_OUT_OF_MEMORY; user_data->property_count = num_properties; for (u32 i = 0; i < num_properties; i++) { u16 name_len = pxl8_read_u16(stream); if (name_len > 0) { - user_data->properties[i].name = (char*)malloc(name_len + 1); + user_data->properties[i].name = (char*)pxl8_malloc(name_len + 1); if (!user_data->properties[i].name) return PXL8_ERROR_OUT_OF_MEMORY; pxl8_read_bytes(stream, user_data->properties[i].name, name_len); user_data->properties[i].name[name_len] = '\0'; @@ -207,7 +208,7 @@ static pxl8_result parse_user_data_chunk(pxl8_stream* stream, pxl8_ase_user_data case 8: { u16 str_len = pxl8_read_u16(stream); if (str_len > 0) { - user_data->properties[i].string_val = (char*)malloc(str_len + 1); + user_data->properties[i].string_val = (char*)pxl8_malloc(str_len + 1); if (!user_data->properties[i].string_val) return PXL8_ERROR_OUT_OF_MEMORY; pxl8_read_bytes(stream, user_data->properties[i].string_val, str_len); user_data->properties[i].string_val[str_len] = '\0'; @@ -236,7 +237,7 @@ static pxl8_result parse_tileset_chunk(pxl8_stream* stream, pxl8_ase_tileset* ti u16 name_len = pxl8_read_u16(stream); if (name_len > 0) { - tileset->name = (char*)malloc(name_len + 1); + tileset->name = (char*)pxl8_malloc(name_len + 1); if (!tileset->name) return PXL8_ERROR_OUT_OF_MEMORY; pxl8_read_bytes(stream, tileset->name, name_len); tileset->name[name_len] = '\0'; @@ -249,7 +250,7 @@ static pxl8_result parse_tileset_chunk(pxl8_stream* stream, pxl8_ase_tileset* ti if (tileset->flags & 2) { u32 compressed_size = pxl8_read_u32(stream); tileset->pixels_size = tileset->tile_width * tileset->tile_height * tileset->tile_count; - tileset->pixels = (u8*)malloc(tileset->pixels_size); + tileset->pixels = (u8*)pxl8_malloc(tileset->pixels_size); if (!tileset->pixels) return PXL8_ERROR_OUT_OF_MEMORY; const u8* compressed_data = pxl8_read_ptr(stream, compressed_size); @@ -257,13 +258,13 @@ static pxl8_result parse_tileset_chunk(pxl8_stream* stream, pxl8_ase_tileset* ti i32 result = mz_uncompress(tileset->pixels, &dest_len, compressed_data, compressed_size); if (result != MZ_OK) { pxl8_error("Failed to decompress tileset data: miniz error %d", result); - free(tileset->pixels); + pxl8_free(tileset->pixels); tileset->pixels = NULL; return PXL8_ERROR_ASE_MALFORMED_CHUNK; } } - tileset->tile_user_data = (pxl8_ase_user_data*)calloc(tileset->tile_count, sizeof(pxl8_ase_user_data)); + tileset->tile_user_data = (pxl8_ase_user_data*)pxl8_calloc(tileset->tile_count, sizeof(pxl8_ase_user_data)); if (!tileset->tile_user_data) return PXL8_ERROR_OUT_OF_MEMORY; return PXL8_OK; @@ -288,7 +289,7 @@ static pxl8_result parse_cel_chunk(pxl8_stream* stream, u32 chunk_size, pxl8_ase u32 pixels_size = cel->image.width * cel->image.height; u32 compressed_size = chunk_size - 20; - cel->image.pixels = (u8*)malloc(pixels_size); + cel->image.pixels = (u8*)pxl8_malloc(pixels_size); if (!cel->image.pixels) return PXL8_ERROR_OUT_OF_MEMORY; const u8* compressed_data = pxl8_read_ptr(stream, compressed_size); @@ -296,7 +297,7 @@ static pxl8_result parse_cel_chunk(pxl8_stream* stream, u32 chunk_size, pxl8_ase i32 result = mz_uncompress(cel->image.pixels, &dest_len, compressed_data, compressed_size); if (result != MZ_OK) { pxl8_error("Failed to decompress cel data: miniz error %d", result); - free(cel->image.pixels); + pxl8_free(cel->image.pixels); cel->image.pixels = NULL; return PXL8_ERROR_ASE_MALFORMED_CHUNK; } @@ -321,7 +322,7 @@ static pxl8_result parse_cel_chunk(pxl8_stream* stream, u32 chunk_size, pxl8_ase u32 uncompressed_size = tile_count * bytes_per_tile; u32 compressed_size = chunk_size - 36; - u8* temp_buffer = (u8*)malloc(uncompressed_size); + u8* temp_buffer = (u8*)pxl8_malloc(uncompressed_size); if (!temp_buffer) return PXL8_ERROR_OUT_OF_MEMORY; const u8* compressed_data = pxl8_read_ptr(stream, compressed_size); @@ -329,13 +330,13 @@ static pxl8_result parse_cel_chunk(pxl8_stream* stream, u32 chunk_size, pxl8_ase i32 result = mz_uncompress(temp_buffer, &dest_len, compressed_data, compressed_size); if (result != MZ_OK) { pxl8_error("Failed to decompress tilemap data: miniz error %d", result); - free(temp_buffer); + pxl8_free(temp_buffer); return PXL8_ERROR_ASE_MALFORMED_CHUNK; } - cel->tilemap.tiles = (u32*)calloc(tile_count, sizeof(u32)); + cel->tilemap.tiles = (u32*)pxl8_calloc(tile_count, sizeof(u32)); if (!cel->tilemap.tiles) { - free(temp_buffer); + pxl8_free(temp_buffer); return PXL8_ERROR_OUT_OF_MEMORY; } @@ -353,7 +354,7 @@ static pxl8_result parse_cel_chunk(pxl8_stream* stream, u32 chunk_size, pxl8_ase } } - free(temp_buffer); + pxl8_free(temp_buffer); } return PXL8_OK; @@ -367,7 +368,7 @@ pxl8_result pxl8_ase_load(const char* filepath, pxl8_ase_file* ase_file) { memset(ase_file, 0, sizeof(pxl8_ase_file)); u8* file_data; - size_t file_size; + usize file_size; pxl8_result result = pxl8_io_read_binary_file(filepath, &file_data, &file_size); if (result != PXL8_OK) { return result; @@ -387,7 +388,7 @@ pxl8_result pxl8_ase_load(const char* filepath, pxl8_ase_file* ase_file) { } ase_file->frame_count = ase_file->header.frames; - ase_file->frames = (pxl8_ase_frame*)calloc(ase_file->frame_count, sizeof(pxl8_ase_frame)); + ase_file->frames = (pxl8_ase_frame*)pxl8_calloc(ase_file->frame_count, sizeof(pxl8_ase_frame)); if (!ase_file->frames) { pxl8_io_free_binary_data(file_data); return PXL8_ERROR_OUT_OF_MEMORY; @@ -425,7 +426,7 @@ pxl8_result pxl8_ase_load(const char* filepath, pxl8_ase_file* ase_file) { frame->duration = frame_header.duration; u32 pixel_count = frame->width * frame->height; - frame->pixels = (u8*)calloc(pixel_count, sizeof(u8)); + frame->pixels = (u8*)pxl8_calloc(pixel_count, sizeof(u8)); if (!frame->pixels) { result = PXL8_ERROR_OUT_OF_MEMORY; break; @@ -457,7 +458,7 @@ pxl8_result pxl8_ase_load(const char* filepath, pxl8_ase_file* ase_file) { case PXL8_ASE_CHUNK_LAYER: { pxl8_ase_layer* new_layers = - (pxl8_ase_layer*)realloc(ase_file->layers, + (pxl8_ase_layer*)pxl8_realloc(ase_file->layers, (ase_file->layer_count + 1) * sizeof(pxl8_ase_layer)); if (!new_layers) { result = PXL8_ERROR_OUT_OF_MEMORY; @@ -476,7 +477,7 @@ pxl8_result pxl8_ase_load(const char* filepath, pxl8_ase_file* ase_file) { pxl8_ase_cel cel = {0}; result = parse_cel_chunk(&stream, chunk_header.chunk_size - 6, &cel); if (result == PXL8_OK) { - pxl8_ase_cel* new_cels = (pxl8_ase_cel*)realloc(frame->cels, (frame->cel_count + 1) * sizeof(pxl8_ase_cel)); + pxl8_ase_cel* new_cels = (pxl8_ase_cel*)pxl8_realloc(frame->cels, (frame->cel_count + 1) * sizeof(pxl8_ase_cel)); if (!new_cels) { result = PXL8_ERROR_OUT_OF_MEMORY; break; @@ -515,14 +516,14 @@ pxl8_result pxl8_ase_load(const char* filepath, pxl8_ase_file* ase_file) { case PXL8_ASE_CHUNK_PALETTE: if (ase_file->palette.colors) { - free(ase_file->palette.colors); + pxl8_free(ase_file->palette.colors); ase_file->palette.colors = NULL; } result = parse_palette_chunk(&stream, &ase_file->palette); break; case PXL8_ASE_CHUNK_TILESET: { - pxl8_ase_tileset* new_tilesets = (pxl8_ase_tileset*)realloc(ase_file->tilesets, + pxl8_ase_tileset* new_tilesets = (pxl8_ase_tileset*)pxl8_realloc(ase_file->tilesets, (ase_file->tileset_count + 1) * sizeof(pxl8_ase_tileset)); if (!new_tilesets) { result = PXL8_ERROR_OUT_OF_MEMORY; @@ -579,57 +580,57 @@ void pxl8_ase_destroy(pxl8_ase_file* ase_file) { if (ase_file->frames) { for (u32 i = 0; i < ase_file->frame_count; i++) { - if (ase_file->frames[i].pixels) free(ase_file->frames[i].pixels); + if (ase_file->frames[i].pixels) pxl8_free(ase_file->frames[i].pixels); if (ase_file->frames[i].cels) { for (u32 j = 0; j < ase_file->frames[i].cel_count; j++) { pxl8_ase_cel* cel = &ase_file->frames[i].cels[j]; if (cel->cel_type == 2 && cel->image.pixels) { - free(cel->image.pixels); + pxl8_free(cel->image.pixels); } else if (cel->cel_type == 3 && cel->tilemap.tiles) { - free(cel->tilemap.tiles); + pxl8_free(cel->tilemap.tiles); } } - free(ase_file->frames[i].cels); + pxl8_free(ase_file->frames[i].cels); } } - free(ase_file->frames); + pxl8_free(ase_file->frames); } if (ase_file->palette.colors) { - free(ase_file->palette.colors); + pxl8_free(ase_file->palette.colors); } if (ase_file->layers) { for (u32 i = 0; i < ase_file->layer_count; i++) { if (ase_file->layers[i].name) { - free(ase_file->layers[i].name); + pxl8_free(ase_file->layers[i].name); } } - free(ase_file->layers); + pxl8_free(ase_file->layers); } if (ase_file->tilesets) { for (u32 i = 0; i < ase_file->tileset_count; i++) { - if (ase_file->tilesets[i].name) free(ase_file->tilesets[i].name); - if (ase_file->tilesets[i].pixels) free(ase_file->tilesets[i].pixels); + if (ase_file->tilesets[i].name) pxl8_free(ase_file->tilesets[i].name); + if (ase_file->tilesets[i].pixels) pxl8_free(ase_file->tilesets[i].pixels); if (ase_file->tilesets[i].tile_user_data) { for (u32 j = 0; j < ase_file->tilesets[i].tile_count; j++) { pxl8_ase_user_data* ud = &ase_file->tilesets[i].tile_user_data[j]; - if (ud->text) free(ud->text); + if (ud->text) pxl8_free(ud->text); if (ud->properties) { for (u32 k = 0; k < ud->property_count; k++) { - if (ud->properties[k].name) free(ud->properties[k].name); + if (ud->properties[k].name) pxl8_free(ud->properties[k].name); if (ud->properties[k].type == 8 && ud->properties[k].string_val) { - free(ud->properties[k].string_val); + pxl8_free(ud->properties[k].string_val); } } - free(ud->properties); + pxl8_free(ud->properties); } } - free(ase_file->tilesets[i].tile_user_data); + pxl8_free(ase_file->tilesets[i].tile_user_data); } } - free(ase_file->tilesets); + pxl8_free(ase_file->tilesets); } memset(ase_file, 0, sizeof(pxl8_ase_file)); diff --git a/src/asset/pxl8_cart.c b/src/asset/pxl8_cart.c index 1bbf69f..9f4131e 100644 --- a/src/asset/pxl8_cart.c +++ b/src/asset/pxl8_cart.c @@ -8,6 +8,7 @@ #include #include "pxl8_log.h" +#include "pxl8_mem.h" #define PXL8_CART_MAGIC 0x43585850 #define PXL8_CART_VERSION 1 @@ -62,7 +63,7 @@ static bool is_directory(const char* path) { } static bool is_pxc_file(const char* path) { - size_t len = strlen(path); + usize len = strlen(path); return len > 4 && strcmp(path + len - 4, ".pxc") == 0; } @@ -97,7 +98,7 @@ static void collect_files_recursive(const char* dir_path, const char* prefix, } else { if (*count >= *capacity) { *capacity = (*capacity == 0) ? 64 : (*capacity * 2); - *paths = realloc(*paths, *capacity * sizeof(char*)); + *paths = pxl8_realloc(*paths, *capacity * sizeof(char*)); } (*paths)[(*count)++] = strdup(rel_path); } @@ -123,13 +124,13 @@ static pxl8_result load_packed_cart(pxl8_cart* cart, const u8* data, u32 size) { if (header->magic != PXL8_CART_MAGIC) return PXL8_ERROR_INVALID_FORMAT; if (header->version > PXL8_CART_VERSION) return PXL8_ERROR_INVALID_FORMAT; - cart->data = malloc(size); + cart->data = pxl8_malloc(size); if (!cart->data) return PXL8_ERROR_OUT_OF_MEMORY; memcpy(cart->data, data, size); cart->data_size = size; cart->file_count = header->file_count; - cart->files = calloc(cart->file_count, sizeof(pxl8_cart_file)); + cart->files = pxl8_calloc(cart->file_count, sizeof(pxl8_cart_file)); if (!cart->files) return PXL8_ERROR_OUT_OF_MEMORY; const u8* toc = cart->data + sizeof(pxl8_cart_header); @@ -137,7 +138,7 @@ static pxl8_result load_packed_cart(pxl8_cart* cart, const u8* data, u32 size) { const pxl8_cart_entry* entry = (const pxl8_cart_entry*)toc; toc += sizeof(pxl8_cart_entry); - cart->files[i].path = malloc(entry->path_len + 1); + cart->files[i].path = pxl8_malloc(entry->path_len + 1); memcpy(cart->files[i].path, toc, entry->path_len); cart->files[i].path[entry->path_len] = '\0'; toc += entry->path_len; @@ -151,7 +152,7 @@ static pxl8_result load_packed_cart(pxl8_cart* cart, const u8* data, u32 size) { } pxl8_cart* pxl8_cart_create(void) { - pxl8_cart* cart = calloc(1, sizeof(pxl8_cart)); + pxl8_cart* cart = pxl8_calloc(1, sizeof(pxl8_cart)); if (cart) { cart->resolution = PXL8_RESOLUTION_640x360; cart->window_size = (pxl8_size){1280, 720}; @@ -167,7 +168,7 @@ pxl8_cart* pxl8_get_cart(void) { void pxl8_cart_destroy(pxl8_cart* cart) { if (!cart) return; pxl8_cart_unload(cart); - free(cart); + pxl8_free(cart); } pxl8_result pxl8_cart_load(pxl8_cart* cart, const char* path) { @@ -202,16 +203,16 @@ pxl8_result pxl8_cart_load(pxl8_cart* cart, const char* path) { u32 size = (u32)ftell(file); fseek(file, 0, SEEK_SET); - u8* data = malloc(size); + u8* data = pxl8_malloc(size); if (!data || fread(data, 1, size, file) != size) { - free(data); + pxl8_free(data); fclose(file); return PXL8_ERROR_SYSTEM_FAILURE; } fclose(file); pxl8_result result = load_packed_cart(cart, data, size); - free(data); + pxl8_free(data); if (result == PXL8_OK) { pxl8_info("Loaded cart"); @@ -242,16 +243,16 @@ pxl8_result pxl8_cart_load_embedded(pxl8_cart* cart, const char* exe_path) { } fseek(file, trailer.cart_offset, SEEK_SET); - u8* data = malloc(trailer.cart_size); + u8* data = pxl8_malloc(trailer.cart_size); if (!data || fread(data, 1, trailer.cart_size, file) != trailer.cart_size) { - free(data); + pxl8_free(data); fclose(file); return PXL8_ERROR_SYSTEM_FAILURE; } fclose(file); pxl8_result result = load_packed_cart(cart, data, trailer.cart_size); - free(data); + pxl8_free(data); if (result == PXL8_OK) { pxl8_info("Loaded embedded cart"); @@ -265,7 +266,7 @@ void pxl8_cart_unload(pxl8_cart* cart) { if (cart->title) { pxl8_info("Unloaded cart: %s", cart->title); pxl8_cart_unmount(cart); - free(cart->title); + pxl8_free(cart->title); cart->title = NULL; } else if (cart->base_path || cart->data) { pxl8_info("Unloaded cart"); @@ -274,18 +275,18 @@ void pxl8_cart_unload(pxl8_cart* cart) { if (cart->files) { for (u32 i = 0; i < cart->file_count; i++) { - free(cart->files[i].path); + pxl8_free(cart->files[i].path); } - free(cart->files); + pxl8_free(cart->files); cart->files = NULL; } cart->file_count = 0; - free(cart->data); + pxl8_free(cart->data); cart->data = NULL; cart->data_size = 0; - free(cart->base_path); + pxl8_free(cart->base_path); cart->base_path = NULL; cart->is_folder = false; } @@ -302,7 +303,7 @@ pxl8_result pxl8_cart_mount(pxl8_cart* cart) { pxl8_original_cwd = getcwd(NULL, 0); if (chdir(cart->base_path) != 0) { pxl8_error("Failed to change to cart directory: %s", cart->base_path); - free(pxl8_original_cwd); + pxl8_free(pxl8_original_cwd); pxl8_original_cwd = NULL; return PXL8_ERROR_FILE_NOT_FOUND; } @@ -323,7 +324,7 @@ void pxl8_cart_unmount(pxl8_cart* cart) { if (pxl8_original_cwd) { chdir(pxl8_original_cwd); - free(pxl8_original_cwd); + pxl8_free(pxl8_original_cwd); pxl8_original_cwd = NULL; } @@ -343,7 +344,7 @@ const char* pxl8_cart_get_title(const pxl8_cart* cart) { void pxl8_cart_set_title(pxl8_cart* cart, const char* title) { if (!cart || !title) return; - free(cart->title); + pxl8_free(cart->title); cart->title = strdup(title); } @@ -399,16 +400,16 @@ bool pxl8_cart_file_exists(const pxl8_cart* cart, const char* path) { return find_file(cart, path) != NULL; } -bool pxl8_cart_resolve_path(const pxl8_cart* cart, const char* relative_path, char* out_path, size_t out_size) { +bool pxl8_cart_resolve_path(const pxl8_cart* cart, const char* relative_path, char* out_path, usize out_size) { if (!cart || !relative_path || !out_path || out_size == 0) return false; if (cart->is_folder && cart->base_path) { i32 written = snprintf(out_path, out_size, "%s/%s", cart->base_path, relative_path); - return written >= 0 && (size_t)written < out_size; + return written >= 0 && (usize)written < out_size; } i32 written = snprintf(out_path, out_size, "%s", relative_path); - return written >= 0 && (size_t)written < out_size; + return written >= 0 && (usize)written < out_size; } pxl8_result pxl8_cart_read_file(const pxl8_cart* cart, const char* path, u8** data_out, u32* size_out) { @@ -427,9 +428,9 @@ pxl8_result pxl8_cart_read_file(const pxl8_cart* cart, const char* path, u8** da *size_out = (u32)ftell(file); fseek(file, 0, SEEK_SET); - *data_out = malloc(*size_out); + *data_out = pxl8_malloc(*size_out); if (!*data_out || fread(*data_out, 1, *size_out, file) != *size_out) { - free(*data_out); + pxl8_free(*data_out); *data_out = NULL; fclose(file); return PXL8_ERROR_SYSTEM_FAILURE; @@ -442,7 +443,7 @@ pxl8_result pxl8_cart_read_file(const pxl8_cart* cart, const char* path, u8** da if (!cf) return PXL8_ERROR_FILE_NOT_FOUND; *size_out = cf->size; - *data_out = malloc(cf->size); + *data_out = pxl8_malloc(cf->size); if (!*data_out) return PXL8_ERROR_OUT_OF_MEMORY; memcpy(*data_out, cart->data + cf->offset, cf->size); @@ -450,7 +451,7 @@ pxl8_result pxl8_cart_read_file(const pxl8_cart* cart, const char* path, u8** da } void pxl8_cart_free_file(u8* data) { - free(data); + pxl8_free(data); } pxl8_result pxl8_cart_pack(const char* folder_path, const char* output_path) { @@ -483,7 +484,7 @@ pxl8_result pxl8_cart_pack(const char* folder_path, const char* output_path) { u32 data_offset = sizeof(pxl8_cart_header) + toc_size; u32 total_size = data_offset; - u32* file_sizes = malloc(count * sizeof(u32)); + u32* file_sizes = pxl8_malloc(count * sizeof(u32)); for (u32 i = 0; i < count; i++) { char full_path[1024]; snprintf(full_path, sizeof(full_path), "%s/%s", folder_path, paths[i]); @@ -496,11 +497,11 @@ pxl8_result pxl8_cart_pack(const char* folder_path, const char* output_path) { } } - u8* buffer = calloc(1, total_size); + u8* buffer = pxl8_calloc(1, total_size); if (!buffer) { - free(file_sizes); - for (u32 i = 0; i < count; i++) free(paths[i]); - free(paths); + pxl8_free(file_sizes); + for (u32 i = 0; i < count; i++) pxl8_free(paths[i]); + pxl8_free(paths); return PXL8_ERROR_OUT_OF_MEMORY; } @@ -536,20 +537,20 @@ pxl8_result pxl8_cart_pack(const char* folder_path, const char* output_path) { } file_offset += file_sizes[i]; - free(paths[i]); + pxl8_free(paths[i]); } - free(paths); - free(file_sizes); + pxl8_free(paths); + pxl8_free(file_sizes); FILE* out = fopen(output_path, "wb"); if (!out) { - free(buffer); + pxl8_free(buffer); return PXL8_ERROR_SYSTEM_FAILURE; } fwrite(buffer, 1, total_size, out); fclose(out); - free(buffer); + pxl8_free(buffer); pxl8_info("Cart packed: %u files, %u bytes", count, total_size); return PXL8_OK; @@ -573,7 +574,7 @@ pxl8_result pxl8_cart_bundle(const char* input_path, const char* output_path, co fseek(f, 0, SEEK_END); cart_size = (u32)ftell(f); fseek(f, 0, SEEK_SET); - cart_data = malloc(cart_size); + cart_data = pxl8_malloc(cart_size); fread(cart_data, 1, cart_size, f); fclose(f); unlink(temp_pxc); @@ -584,7 +585,7 @@ pxl8_result pxl8_cart_bundle(const char* input_path, const char* output_path, co fseek(f, 0, SEEK_END); cart_size = (u32)ftell(f); fseek(f, 0, SEEK_SET); - cart_data = malloc(cart_size); + cart_data = pxl8_malloc(cart_size); fread(cart_data, 1, cart_size, f); fclose(f); free_cart = true; @@ -594,30 +595,30 @@ pxl8_result pxl8_cart_bundle(const char* input_path, const char* output_path, co FILE* exe = fopen(exe_path, "rb"); if (!exe) { - if (free_cart) free(cart_data); + if (free_cart) pxl8_free(cart_data); return PXL8_ERROR_FILE_NOT_FOUND; } fseek(exe, 0, SEEK_END); u32 exe_size = (u32)ftell(exe); fseek(exe, 0, SEEK_SET); - u8* exe_data = malloc(exe_size); + u8* exe_data = pxl8_malloc(exe_size); fread(exe_data, 1, exe_size, exe); fclose(exe); FILE* out = fopen(output_path, "wb"); if (!out) { - free(exe_data); - if (free_cart) free(cart_data); + pxl8_free(exe_data); + if (free_cart) pxl8_free(cart_data); return PXL8_ERROR_SYSTEM_FAILURE; } fwrite(exe_data, 1, exe_size, out); - free(exe_data); + pxl8_free(exe_data); u32 cart_offset = exe_size; fwrite(cart_data, 1, cart_size, out); - if (free_cart) free(cart_data); + if (free_cart) pxl8_free(cart_data); pxl8_cart_trailer trailer = { .magic = PXL8_CART_TRAILER_MAGIC, diff --git a/src/asset/pxl8_cart.h b/src/asset/pxl8_cart.h index b142c9b..9384192 100644 --- a/src/asset/pxl8_cart.h +++ b/src/asset/pxl8_cart.h @@ -34,7 +34,7 @@ bool pxl8_cart_is_packed(const pxl8_cart* cart); bool pxl8_cart_has_embedded(const char* exe_path); bool pxl8_cart_file_exists(const pxl8_cart* cart, const char* path); -bool pxl8_cart_resolve_path(const pxl8_cart* cart, const char* relative_path, char* out_path, size_t out_size); +bool pxl8_cart_resolve_path(const pxl8_cart* cart, const char* relative_path, char* out_path, usize out_size); pxl8_result pxl8_cart_read_file(const pxl8_cart* cart, const char* path, u8** data_out, u32* size_out); void pxl8_cart_free_file(u8* data); diff --git a/src/asset/pxl8_save.c b/src/asset/pxl8_save.c index 2bec3fa..5233869 100644 --- a/src/asset/pxl8_save.c +++ b/src/asset/pxl8_save.c @@ -17,6 +17,7 @@ #endif #include "pxl8_log.h" +#include "pxl8_mem.h" typedef struct { u32 magic; @@ -40,7 +41,7 @@ static u32 pxl8_save_checksum(const u8* data, u32 size) { return hash; } -static void pxl8_save_get_slot_path(pxl8_save* save, u8 slot, char* path, size_t path_size) { +static void pxl8_save_get_slot_path(pxl8_save* save, u8 slot, char* path, usize path_size) { if (slot == PXL8_SAVE_HOTRELOAD_SLOT) { snprintf(path, path_size, "%s%chotreload.sav", save->directory, PATH_SEP); } else { @@ -68,7 +69,7 @@ static pxl8_result pxl8_save_ensure_directory(const char* path) { pxl8_save* pxl8_save_create(const char* game_name, u32 magic, u32 version) { if (!game_name) return NULL; - pxl8_save* save = (pxl8_save*)calloc(1, sizeof(pxl8_save)); + pxl8_save* save = (pxl8_save*)pxl8_calloc(1, sizeof(pxl8_save)); if (!save) return NULL; save->magic = magic; @@ -81,7 +82,7 @@ pxl8_save* pxl8_save_create(const char* game_name, u32 magic, u32 version) { snprintf(save->directory, sizeof(save->directory), "%s%cpxl8%c%s", base_dir, PATH_SEP, PATH_SEP, game_name); } else { - free(save); + pxl8_free(save); return NULL; } #else @@ -91,7 +92,7 @@ pxl8_save* pxl8_save_create(const char* game_name, u32 magic, u32 version) { if (pw) home = pw->pw_dir; } if (!home) { - free(save); + pxl8_free(save); return NULL; } @@ -106,7 +107,7 @@ pxl8_save* pxl8_save_create(const char* game_name, u32 magic, u32 version) { #endif if (pxl8_save_ensure_directory(save->directory) != PXL8_OK) { - free(save); + pxl8_free(save); return NULL; } @@ -116,7 +117,7 @@ pxl8_save* pxl8_save_create(const char* game_name, u32 magic, u32 version) { void pxl8_save_destroy(pxl8_save* save) { if (save) { - free(save); + pxl8_free(save); } } @@ -199,14 +200,14 @@ pxl8_result pxl8_save_read(pxl8_save* save, u8 slot, u8** data_out, u32* size_ou return PXL8_ERROR_INVALID_FORMAT; } - u8* data = (u8*)malloc(header.size); + u8* data = (u8*)pxl8_malloc(header.size); if (!data) { fclose(file); return PXL8_ERROR_OUT_OF_MEMORY; } if (fread(data, 1, header.size, file) != header.size) { - free(data); + pxl8_free(data); fclose(file); return PXL8_ERROR_SYSTEM_FAILURE; } @@ -215,7 +216,7 @@ pxl8_result pxl8_save_read(pxl8_save* save, u8 slot, u8** data_out, u32* size_ou u32 checksum = pxl8_save_checksum(data, header.size); if (checksum != header.checksum) { - free(data); + pxl8_free(data); pxl8_error("Save file checksum mismatch"); return PXL8_ERROR_INVALID_FORMAT; } @@ -234,7 +235,7 @@ pxl8_result pxl8_save_read(pxl8_save* save, u8 slot, u8** data_out, u32* size_ou void pxl8_save_free(u8* data) { if (data) { - free(data); + pxl8_free(data); } } diff --git a/src/core/pxl8.c b/src/core/pxl8.c index 8e29af4..f6943f8 100644 --- a/src/core/pxl8.c +++ b/src/core/pxl8.c @@ -6,7 +6,6 @@ #include #include -#include #include #include @@ -14,6 +13,7 @@ #include "pxl8_hal.h" #include "pxl8_log.h" #include "pxl8_macros.h" +#include "pxl8_mem.h" #include "pxl8_repl.h" #include "pxl8_replay.h" #include "pxl8_script.h" @@ -39,23 +39,23 @@ static void pxl8_audio_event_callback(u8 event_type, u8 context_id, u8 note, f32 #endif pxl8* pxl8_create(const pxl8_hal* hal) { - pxl8* sys = (pxl8*)calloc(1, sizeof(pxl8)); + pxl8* sys = (pxl8*)pxl8_calloc(1, sizeof(pxl8)); if (!sys) return NULL; pxl8_log_init(&sys->log); if (!hal) { pxl8_error("hal cannot be null"); - free(sys); + pxl8_free(sys); return NULL; } sys->hal = hal; - sys->game = (pxl8_game*)calloc(1, sizeof(pxl8_game)); + sys->game = (pxl8_game*)pxl8_calloc(1, sizeof(pxl8_game)); if (!sys->game) { pxl8_error("failed to allocate game"); - free(sys); + pxl8_free(sys); return NULL; } @@ -65,11 +65,11 @@ pxl8* pxl8_create(const pxl8_hal* hal) { void pxl8_destroy(pxl8* sys) { if (!sys) return; - if (sys->game) free(sys->game); + if (sys->game) pxl8_free(sys->game); if (sys->cart) pxl8_cart_destroy(sys->cart); if (sys->hal && sys->platform_data) sys->hal->destroy(sys->platform_data); - free(sys); + pxl8_free(sys); } static void pxl8_print_help(void) { @@ -171,7 +171,7 @@ pxl8_result pxl8_init(pxl8* sys, i32 argc, char* argv[]) { cart_path = "."; } else { pxl8_error("no main.fnl or main.lua found in current directory"); - free(original_cwd); + pxl8_free(original_cwd); return PXL8_ERROR_INITIALIZATION_FAILED; } } @@ -190,7 +190,7 @@ pxl8_result pxl8_init(pxl8* sys, i32 argc, char* argv[]) { pxl8_error("failed to load cart%s%s", load_from_path ? ": " : "", load_from_path ? cart_path : ""); if (sys->cart) pxl8_cart_destroy(sys->cart); sys->cart = NULL; - free(original_cwd); + pxl8_free(original_cwd); return PXL8_ERROR_INITIALIZATION_FAILED; } @@ -203,7 +203,7 @@ pxl8_result pxl8_init(pxl8* sys, i32 argc, char* argv[]) { } else if (script_arg) { pxl8_strncpy(game->script_path, script_arg, sizeof(game->script_path)); } - free(original_cwd); + pxl8_free(original_cwd); const char* window_title = pxl8_cart_get_title(sys->cart); if (!window_title) window_title = "pxl8"; @@ -310,7 +310,7 @@ pxl8_result pxl8_update(pxl8* sys) { if (pxl8_script_load_module(game->script, "pxl8") != PXL8_OK) { const char* err_msg = pxl8_script_get_last_error(game->script); - pxl8_error("failed to setup pxl8 global: %s", err_msg); + pxl8_error("failed to load pxl8 global: %s", err_msg); } sys->repl = pxl8_repl_create(); diff --git a/src/core/pxl8_bytes.c b/src/core/pxl8_bytes.c index 1894878..7da60b0 100644 --- a/src/core/pxl8_bytes.c +++ b/src/core/pxl8_bytes.c @@ -1,35 +1,35 @@ #include "pxl8_bytes.h" #include -void pxl8_pack_u8(u8* buf, size_t offset, u8 val) { +void pxl8_pack_u8(u8* buf, usize offset, u8 val) { buf[offset] = val; } -void pxl8_pack_u16_le(u8* buf, size_t offset, u16 val) { +void pxl8_pack_u16_le(u8* buf, usize offset, u16 val) { buf[offset] = (u8)(val); buf[offset + 1] = (u8)(val >> 8); } -void pxl8_pack_u16_be(u8* buf, size_t offset, u16 val) { +void pxl8_pack_u16_be(u8* buf, usize offset, u16 val) { buf[offset] = (u8)(val >> 8); buf[offset + 1] = (u8)(val); } -void pxl8_pack_u32_le(u8* buf, size_t offset, u32 val) { +void pxl8_pack_u32_le(u8* buf, usize offset, u32 val) { buf[offset] = (u8)(val); buf[offset + 1] = (u8)(val >> 8); buf[offset + 2] = (u8)(val >> 16); buf[offset + 3] = (u8)(val >> 24); } -void pxl8_pack_u32_be(u8* buf, size_t offset, u32 val) { +void pxl8_pack_u32_be(u8* buf, usize offset, u32 val) { buf[offset] = (u8)(val >> 24); buf[offset + 1] = (u8)(val >> 16); buf[offset + 2] = (u8)(val >> 8); buf[offset + 3] = (u8)(val); } -void pxl8_pack_u64_le(u8* buf, size_t offset, u64 val) { +void pxl8_pack_u64_le(u8* buf, usize offset, u64 val) { buf[offset] = (u8)(val); buf[offset + 1] = (u8)(val >> 8); buf[offset + 2] = (u8)(val >> 16); @@ -40,7 +40,7 @@ void pxl8_pack_u64_le(u8* buf, size_t offset, u64 val) { buf[offset + 7] = (u8)(val >> 56); } -void pxl8_pack_u64_be(u8* buf, size_t offset, u64 val) { +void pxl8_pack_u64_be(u8* buf, usize offset, u64 val) { buf[offset] = (u8)(val >> 56); buf[offset + 1] = (u8)(val >> 48); buf[offset + 2] = (u8)(val >> 40); @@ -51,85 +51,85 @@ void pxl8_pack_u64_be(u8* buf, size_t offset, u64 val) { buf[offset + 7] = (u8)(val); } -void pxl8_pack_i8(u8* buf, size_t offset, i8 val) { +void pxl8_pack_i8(u8* buf, usize offset, i8 val) { buf[offset] = (u8)val; } -void pxl8_pack_i16_le(u8* buf, size_t offset, i16 val) { +void pxl8_pack_i16_le(u8* buf, usize offset, i16 val) { pxl8_pack_u16_le(buf, offset, (u16)val); } -void pxl8_pack_i16_be(u8* buf, size_t offset, i16 val) { +void pxl8_pack_i16_be(u8* buf, usize offset, i16 val) { pxl8_pack_u16_be(buf, offset, (u16)val); } -void pxl8_pack_i32_le(u8* buf, size_t offset, i32 val) { +void pxl8_pack_i32_le(u8* buf, usize offset, i32 val) { pxl8_pack_u32_le(buf, offset, (u32)val); } -void pxl8_pack_i32_be(u8* buf, size_t offset, i32 val) { +void pxl8_pack_i32_be(u8* buf, usize offset, i32 val) { pxl8_pack_u32_be(buf, offset, (u32)val); } -void pxl8_pack_i64_le(u8* buf, size_t offset, i64 val) { +void pxl8_pack_i64_le(u8* buf, usize offset, i64 val) { pxl8_pack_u64_le(buf, offset, (u64)val); } -void pxl8_pack_i64_be(u8* buf, size_t offset, i64 val) { +void pxl8_pack_i64_be(u8* buf, usize offset, i64 val) { pxl8_pack_u64_be(buf, offset, (u64)val); } -void pxl8_pack_f32_le(u8* buf, size_t offset, f32 val) { +void pxl8_pack_f32_le(u8* buf, usize offset, f32 val) { u32 bits; memcpy(&bits, &val, sizeof(bits)); pxl8_pack_u32_le(buf, offset, bits); } -void pxl8_pack_f32_be(u8* buf, size_t offset, f32 val) { +void pxl8_pack_f32_be(u8* buf, usize offset, f32 val) { u32 bits; memcpy(&bits, &val, sizeof(bits)); pxl8_pack_u32_be(buf, offset, bits); } -void pxl8_pack_f64_le(u8* buf, size_t offset, f64 val) { +void pxl8_pack_f64_le(u8* buf, usize offset, f64 val) { u64 bits; memcpy(&bits, &val, sizeof(bits)); pxl8_pack_u64_le(buf, offset, bits); } -void pxl8_pack_f64_be(u8* buf, size_t offset, f64 val) { +void pxl8_pack_f64_be(u8* buf, usize offset, f64 val) { u64 bits; memcpy(&bits, &val, sizeof(bits)); pxl8_pack_u64_be(buf, offset, bits); } -u8 pxl8_unpack_u8(const u8* buf, size_t offset) { +u8 pxl8_unpack_u8(const u8* buf, usize offset) { return buf[offset]; } -u16 pxl8_unpack_u16_le(const u8* buf, size_t offset) { +u16 pxl8_unpack_u16_le(const u8* buf, usize offset) { return (u16)buf[offset] | ((u16)buf[offset + 1] << 8); } -u16 pxl8_unpack_u16_be(const u8* buf, size_t offset) { +u16 pxl8_unpack_u16_be(const u8* buf, usize offset) { return ((u16)buf[offset] << 8) | (u16)buf[offset + 1]; } -u32 pxl8_unpack_u32_le(const u8* buf, size_t offset) { +u32 pxl8_unpack_u32_le(const u8* buf, usize offset) { return (u32)buf[offset] | ((u32)buf[offset + 1] << 8) | ((u32)buf[offset + 2] << 16) | ((u32)buf[offset + 3] << 24); } -u32 pxl8_unpack_u32_be(const u8* buf, size_t offset) { +u32 pxl8_unpack_u32_be(const u8* buf, usize offset) { return ((u32)buf[offset] << 24) | ((u32)buf[offset + 1] << 16) | ((u32)buf[offset + 2] << 8) | (u32)buf[offset + 3]; } -u64 pxl8_unpack_u64_le(const u8* buf, size_t offset) { +u64 pxl8_unpack_u64_le(const u8* buf, usize offset) { return (u64)buf[offset] | ((u64)buf[offset + 1] << 8) | ((u64)buf[offset + 2] << 16) | @@ -140,7 +140,7 @@ u64 pxl8_unpack_u64_le(const u8* buf, size_t offset) { ((u64)buf[offset + 7] << 56); } -u64 pxl8_unpack_u64_be(const u8* buf, size_t offset) { +u64 pxl8_unpack_u64_be(const u8* buf, usize offset) { return ((u64)buf[offset] << 56) | ((u64)buf[offset + 1] << 48) | ((u64)buf[offset + 2] << 40) | @@ -151,56 +151,56 @@ u64 pxl8_unpack_u64_be(const u8* buf, size_t offset) { (u64)buf[offset + 7]; } -i8 pxl8_unpack_i8(const u8* buf, size_t offset) { +i8 pxl8_unpack_i8(const u8* buf, usize offset) { return (i8)buf[offset]; } -i16 pxl8_unpack_i16_le(const u8* buf, size_t offset) { +i16 pxl8_unpack_i16_le(const u8* buf, usize offset) { return (i16)pxl8_unpack_u16_le(buf, offset); } -i16 pxl8_unpack_i16_be(const u8* buf, size_t offset) { +i16 pxl8_unpack_i16_be(const u8* buf, usize offset) { return (i16)pxl8_unpack_u16_be(buf, offset); } -i32 pxl8_unpack_i32_le(const u8* buf, size_t offset) { +i32 pxl8_unpack_i32_le(const u8* buf, usize offset) { return (i32)pxl8_unpack_u32_le(buf, offset); } -i32 pxl8_unpack_i32_be(const u8* buf, size_t offset) { +i32 pxl8_unpack_i32_be(const u8* buf, usize offset) { return (i32)pxl8_unpack_u32_be(buf, offset); } -i64 pxl8_unpack_i64_le(const u8* buf, size_t offset) { +i64 pxl8_unpack_i64_le(const u8* buf, usize offset) { return (i64)pxl8_unpack_u64_le(buf, offset); } -i64 pxl8_unpack_i64_be(const u8* buf, size_t offset) { +i64 pxl8_unpack_i64_be(const u8* buf, usize offset) { return (i64)pxl8_unpack_u64_be(buf, offset); } -f32 pxl8_unpack_f32_le(const u8* buf, size_t offset) { +f32 pxl8_unpack_f32_le(const u8* buf, usize offset) { u32 bits = pxl8_unpack_u32_le(buf, offset); f32 result; memcpy(&result, &bits, sizeof(result)); return result; } -f32 pxl8_unpack_f32_be(const u8* buf, size_t offset) { +f32 pxl8_unpack_f32_be(const u8* buf, usize offset) { u32 bits = pxl8_unpack_u32_be(buf, offset); f32 result; memcpy(&result, &bits, sizeof(result)); return result; } -f64 pxl8_unpack_f64_le(const u8* buf, size_t offset) { +f64 pxl8_unpack_f64_le(const u8* buf, usize offset) { u64 bits = pxl8_unpack_u64_le(buf, offset); f64 result; memcpy(&result, &bits, sizeof(result)); return result; } -f64 pxl8_unpack_f64_be(const u8* buf, size_t offset) { +f64 pxl8_unpack_f64_be(const u8* buf, usize offset) { u64 bits = pxl8_unpack_u64_be(buf, offset); f64 result; memcpy(&result, &bits, sizeof(result)); diff --git a/src/core/pxl8_bytes.h b/src/core/pxl8_bytes.h index 5f5a5e7..852f50a 100644 --- a/src/core/pxl8_bytes.h +++ b/src/core/pxl8_bytes.h @@ -10,43 +10,43 @@ void pxl8_bit_set(u32* val, u8 bit); bool pxl8_bit_test(u32 val, u8 bit); void pxl8_bit_toggle(u32* val, u8 bit); -void pxl8_pack_u8(u8* buf, size_t offset, u8 val); -void pxl8_pack_u16_be(u8* buf, size_t offset, u16 val); -void pxl8_pack_u16_le(u8* buf, size_t offset, u16 val); -void pxl8_pack_u32_be(u8* buf, size_t offset, u32 val); -void pxl8_pack_u32_le(u8* buf, size_t offset, u32 val); -void pxl8_pack_u64_be(u8* buf, size_t offset, u64 val); -void pxl8_pack_u64_le(u8* buf, size_t offset, u64 val); -void pxl8_pack_i8(u8* buf, size_t offset, i8 val); -void pxl8_pack_i16_be(u8* buf, size_t offset, i16 val); -void pxl8_pack_i16_le(u8* buf, size_t offset, i16 val); -void pxl8_pack_i32_be(u8* buf, size_t offset, i32 val); -void pxl8_pack_i32_le(u8* buf, size_t offset, i32 val); -void pxl8_pack_i64_be(u8* buf, size_t offset, i64 val); -void pxl8_pack_i64_le(u8* buf, size_t offset, i64 val); -void pxl8_pack_f32_be(u8* buf, size_t offset, f32 val); -void pxl8_pack_f32_le(u8* buf, size_t offset, f32 val); -void pxl8_pack_f64_be(u8* buf, size_t offset, f64 val); -void pxl8_pack_f64_le(u8* buf, size_t offset, f64 val); +void pxl8_pack_u8(u8* buf, usize offset, u8 val); +void pxl8_pack_u16_be(u8* buf, usize offset, u16 val); +void pxl8_pack_u16_le(u8* buf, usize offset, u16 val); +void pxl8_pack_u32_be(u8* buf, usize offset, u32 val); +void pxl8_pack_u32_le(u8* buf, usize offset, u32 val); +void pxl8_pack_u64_be(u8* buf, usize offset, u64 val); +void pxl8_pack_u64_le(u8* buf, usize offset, u64 val); +void pxl8_pack_i8(u8* buf, usize offset, i8 val); +void pxl8_pack_i16_be(u8* buf, usize offset, i16 val); +void pxl8_pack_i16_le(u8* buf, usize offset, i16 val); +void pxl8_pack_i32_be(u8* buf, usize offset, i32 val); +void pxl8_pack_i32_le(u8* buf, usize offset, i32 val); +void pxl8_pack_i64_be(u8* buf, usize offset, i64 val); +void pxl8_pack_i64_le(u8* buf, usize offset, i64 val); +void pxl8_pack_f32_be(u8* buf, usize offset, f32 val); +void pxl8_pack_f32_le(u8* buf, usize offset, f32 val); +void pxl8_pack_f64_be(u8* buf, usize offset, f64 val); +void pxl8_pack_f64_le(u8* buf, usize offset, f64 val); -u8 pxl8_unpack_u8(const u8* buf, size_t offset); -u16 pxl8_unpack_u16_be(const u8* buf, size_t offset); -u16 pxl8_unpack_u16_le(const u8* buf, size_t offset); -u32 pxl8_unpack_u32_be(const u8* buf, size_t offset); -u32 pxl8_unpack_u32_le(const u8* buf, size_t offset); -u64 pxl8_unpack_u64_be(const u8* buf, size_t offset); -u64 pxl8_unpack_u64_le(const u8* buf, size_t offset); -i8 pxl8_unpack_i8(const u8* buf, size_t offset); -i16 pxl8_unpack_i16_be(const u8* buf, size_t offset); -i16 pxl8_unpack_i16_le(const u8* buf, size_t offset); -i32 pxl8_unpack_i32_be(const u8* buf, size_t offset); -i32 pxl8_unpack_i32_le(const u8* buf, size_t offset); -i64 pxl8_unpack_i64_be(const u8* buf, size_t offset); -i64 pxl8_unpack_i64_le(const u8* buf, size_t offset); -f32 pxl8_unpack_f32_be(const u8* buf, size_t offset); -f32 pxl8_unpack_f32_le(const u8* buf, size_t offset); -f64 pxl8_unpack_f64_be(const u8* buf, size_t offset); -f64 pxl8_unpack_f64_le(const u8* buf, size_t offset); +u8 pxl8_unpack_u8(const u8* buf, usize offset); +u16 pxl8_unpack_u16_be(const u8* buf, usize offset); +u16 pxl8_unpack_u16_le(const u8* buf, usize offset); +u32 pxl8_unpack_u32_be(const u8* buf, usize offset); +u32 pxl8_unpack_u32_le(const u8* buf, usize offset); +u64 pxl8_unpack_u64_be(const u8* buf, usize offset); +u64 pxl8_unpack_u64_le(const u8* buf, usize offset); +i8 pxl8_unpack_i8(const u8* buf, usize offset); +i16 pxl8_unpack_i16_be(const u8* buf, usize offset); +i16 pxl8_unpack_i16_le(const u8* buf, usize offset); +i32 pxl8_unpack_i32_be(const u8* buf, usize offset); +i32 pxl8_unpack_i32_le(const u8* buf, usize offset); +i64 pxl8_unpack_i64_be(const u8* buf, usize offset); +i64 pxl8_unpack_i64_le(const u8* buf, usize offset); +f32 pxl8_unpack_f32_be(const u8* buf, usize offset); +f32 pxl8_unpack_f32_le(const u8* buf, usize offset); +f64 pxl8_unpack_f64_be(const u8* buf, usize offset); +f64 pxl8_unpack_f64_le(const u8* buf, usize offset); typedef struct { const u8* bytes; diff --git a/src/game/pxl8_game.h b/src/core/pxl8_game.h similarity index 100% rename from src/game/pxl8_game.h rename to src/core/pxl8_game.h diff --git a/src/core/pxl8_io.c b/src/core/pxl8_io.c index ae354b7..3de6ca1 100644 --- a/src/core/pxl8_io.c +++ b/src/core/pxl8_io.c @@ -1,4 +1,5 @@ #include "pxl8_io.h" +#include "pxl8_mem.h" #include #include @@ -10,7 +11,7 @@ static inline char pxl8_to_lower(char c) { return (c >= 'A' && c <= 'Z') ? c + 32 : c; } -pxl8_result pxl8_io_read_file(const char* path, char** content, size_t* size) { +pxl8_result pxl8_io_read_file(const char* path, char** content, usize* size) { if (!path || !content || !size) return PXL8_ERROR_NULL_POINTER; pxl8_cart* cart = pxl8_get_cart(); @@ -19,7 +20,7 @@ pxl8_result pxl8_io_read_file(const char* path, char** content, size_t* size) { u32 cart_size = 0; pxl8_result result = pxl8_cart_read_file(cart, path, &data, &cart_size); if (result == PXL8_OK) { - *content = realloc(data, cart_size + 1); + *content = pxl8_realloc(data, cart_size + 1); if (!*content) { pxl8_cart_free_file(data); return PXL8_ERROR_OUT_OF_MEMORY; @@ -44,13 +45,13 @@ pxl8_result pxl8_io_read_file(const char* path, char** content, size_t* size) { return PXL8_ERROR_SYSTEM_FAILURE; } - *content = malloc(file_size + 1); + *content = pxl8_malloc(file_size + 1); if (!*content) { fclose(file); return PXL8_ERROR_OUT_OF_MEMORY; } - size_t bytes_read = fread(*content, 1, file_size, file); + usize bytes_read = fread(*content, 1, file_size, file); (*content)[bytes_read] = '\0'; *size = bytes_read; @@ -58,7 +59,7 @@ pxl8_result pxl8_io_read_file(const char* path, char** content, size_t* size) { return PXL8_OK; } -pxl8_result pxl8_io_write_file(const char* path, const char* content, size_t size) { +pxl8_result pxl8_io_write_file(const char* path, const char* content, usize size) { if (!path || !content) return PXL8_ERROR_NULL_POINTER; FILE* file = fopen(path, "wb"); @@ -66,17 +67,17 @@ pxl8_result pxl8_io_write_file(const char* path, const char* content, size_t siz return PXL8_ERROR_SYSTEM_FAILURE; } - size_t bytes_written = fwrite(content, 1, size, file); + usize bytes_written = fwrite(content, 1, size, file); fclose(file); return (bytes_written == size) ? PXL8_OK : PXL8_ERROR_SYSTEM_FAILURE; } -pxl8_result pxl8_io_read_binary_file(const char* path, u8** data, size_t* size) { +pxl8_result pxl8_io_read_binary_file(const char* path, u8** data, usize* size) { return pxl8_io_read_file(path, (char**)data, size); } -pxl8_result pxl8_io_write_binary_file(const char* path, const u8* data, size_t size) { +pxl8_result pxl8_io_write_binary_file(const char* path, const u8* data, usize size) { return pxl8_io_write_file(path, (const char*)data, size); } @@ -112,13 +113,13 @@ pxl8_result pxl8_io_create_directory(const char* path) { void pxl8_io_free_file_content(char* content) { if (content) { - free(content); + pxl8_free(content); } } void pxl8_io_free_binary_data(u8* data) { if (data) { - free(data); + pxl8_free(data); } } @@ -144,7 +145,7 @@ static i32 pxl8_key_code(const char* key_name) { }; char lower_name[64]; - size_t i; + usize i; for (i = 0; i < sizeof(lower_name) - 1 && key_name[i]; i++) { lower_name[i] = pxl8_to_lower(key_name[i]); } diff --git a/src/core/pxl8_io.h b/src/core/pxl8_io.h index 13daab5..9770ebe 100644 --- a/src/core/pxl8_io.h +++ b/src/core/pxl8_io.h @@ -15,10 +15,10 @@ bool pxl8_io_file_exists(const char* path); void pxl8_io_free_binary_data(u8* data); void pxl8_io_free_file_content(char* content); f64 pxl8_io_get_file_modified_time(const char* path); -pxl8_result pxl8_io_read_binary_file(const char* path, u8** data, size_t* size); -pxl8_result pxl8_io_read_file(const char* path, char** content, size_t* size); -pxl8_result pxl8_io_write_binary_file(const char* path, const u8* data, size_t size); -pxl8_result pxl8_io_write_file(const char* path, const char* content, size_t size); +pxl8_result pxl8_io_read_binary_file(const char* path, u8** data, usize* size); +pxl8_result pxl8_io_read_file(const char* path, char** content, usize* size); +pxl8_result pxl8_io_write_binary_file(const char* path, const u8* data, usize size); +pxl8_result pxl8_io_write_file(const char* path, const char* content, usize size); bool pxl8_key_down(const pxl8_input_state* input, const char* key_name); bool pxl8_key_pressed(const pxl8_input_state* input, const char* key_name); diff --git a/src/core/pxl8_log.c b/src/core/pxl8_log.c index d897000..688760b 100644 --- a/src/core/pxl8_log.c +++ b/src/core/pxl8_log.c @@ -34,7 +34,7 @@ void pxl8_log_set_level(pxl8_log_level level) { if (g_log) g_log->level = level; } -static void log_timestamp(char* buffer, size_t size) { +static void log_timestamp(char* buffer, usize size) { time_t now = time(NULL); struct tm* tm_info = localtime(&now); strftime(buffer, size, "%H:%M:%S", tm_info); diff --git a/src/game/pxl8_replay.c b/src/core/pxl8_replay.c similarity index 93% rename from src/game/pxl8_replay.c rename to src/core/pxl8_replay.c index 32983fd..205b1f7 100644 --- a/src/game/pxl8_replay.c +++ b/src/core/pxl8_replay.c @@ -1,5 +1,6 @@ #include "pxl8_replay.h" #include "pxl8_log.h" +#include "pxl8_mem.h" #include "pxl8_sys.h" #include @@ -42,8 +43,8 @@ struct pxl8_replay { static void pxl8_replay_chunk_free(pxl8_replay_chunk* chunk) { while (chunk) { pxl8_replay_chunk* next = chunk->next; - free(chunk->data); - free(chunk); + pxl8_free(chunk->data); + pxl8_free(chunk); chunk = next; } } @@ -52,7 +53,7 @@ static void pxl8_replay_keyframe_entry_free(pxl8_keyframe_entry* entry) { while (entry) { pxl8_keyframe_entry* next = entry->next; pxl8_replay_chunk_free(entry->input_deltas); - free(entry); + pxl8_free(entry); entry = next; } } @@ -64,7 +65,7 @@ pxl8_replay* pxl8_replay_create(const char* path, u32 keyframe_interval) { return NULL; } - pxl8_replay* r = calloc(1, sizeof(pxl8_replay)); + pxl8_replay* r = pxl8_calloc(1, sizeof(pxl8_replay)); if (!r) { fclose(f); return NULL; @@ -85,7 +86,7 @@ pxl8_replay* pxl8_replay_create(const char* path, u32 keyframe_interval) { } pxl8_replay* pxl8_replay_create_buffer(u32 keyframe_interval, u32 max_keyframes) { - pxl8_replay* r = calloc(1, sizeof(pxl8_replay)); + pxl8_replay* r = pxl8_calloc(1, sizeof(pxl8_replay)); if (!r) return NULL; r->recording = true; @@ -125,7 +126,7 @@ pxl8_replay* pxl8_replay_open(const char* path) { return NULL; } - pxl8_replay* r = calloc(1, sizeof(pxl8_replay)); + pxl8_replay* r = pxl8_calloc(1, sizeof(pxl8_replay)); if (!r) { fclose(f); return NULL; @@ -146,14 +147,14 @@ pxl8_replay* pxl8_replay_open(const char* path) { if (fread(size_bytes, 3, 1, f) != 1) break; u32 size = size_bytes[0] | (size_bytes[1] << 8) | (size_bytes[2] << 16); - u8* data = malloc(size); + u8* data = pxl8_malloc(size); if (!data || fread(data, size, 1, f) != 1) { - free(data); + pxl8_free(data); break; } if (chunk_type == PXL8_REPLAY_CHUNK_KEYFRAME) { - pxl8_keyframe_entry* entry = calloc(1, sizeof(pxl8_keyframe_entry)); + pxl8_keyframe_entry* entry = pxl8_calloc(1, sizeof(pxl8_keyframe_entry)); if (entry && size >= sizeof(pxl8_keyframe)) { memcpy(&entry->keyframe, data, sizeof(pxl8_keyframe)); entry->prev = r->current_keyframe; @@ -166,10 +167,10 @@ pxl8_replay* pxl8_replay_open(const char* path) { } r->keyframe_count++; } - free(data); + pxl8_free(data); } else if (chunk_type == PXL8_REPLAY_CHUNK_INPUT) { if (r->current_keyframe) { - pxl8_replay_chunk* chunk = calloc(1, sizeof(pxl8_replay_chunk)); + pxl8_replay_chunk* chunk = pxl8_calloc(1, sizeof(pxl8_replay_chunk)); if (chunk) { chunk->type = chunk_type; chunk->size = size; @@ -185,9 +186,9 @@ pxl8_replay* pxl8_replay_open(const char* path) { } } } - free(data); + pxl8_free(data); } else if (chunk_type == PXL8_REPLAY_CHUNK_AUDIO_EVENT) { - pxl8_replay_chunk* chunk = calloc(1, sizeof(pxl8_replay_chunk)); + pxl8_replay_chunk* chunk = pxl8_calloc(1, sizeof(pxl8_replay_chunk)); if (chunk) { chunk->type = chunk_type; chunk->size = size; @@ -202,9 +203,9 @@ pxl8_replay* pxl8_replay_open(const char* path) { r->audio_events_tail = chunk; } } - free(data); + pxl8_free(data); } else { - free(data); + pxl8_free(data); } } @@ -231,7 +232,7 @@ void pxl8_replay_destroy(pxl8_replay* r) { pxl8_replay_chunk_free(r->pending_inputs); pxl8_replay_chunk_free(r->audio_events); - free(r); + pxl8_free(r); } bool pxl8_replay_is_recording(pxl8_replay* r) { @@ -262,14 +263,14 @@ static void write_chunk(FILE* f, u8 type, const void* data, u32 size) { } static void add_chunk_to_buffer(pxl8_replay* r, u8 type, const void* data, u32 size) { - pxl8_replay_chunk* chunk = calloc(1, sizeof(pxl8_replay_chunk)); + pxl8_replay_chunk* chunk = pxl8_calloc(1, sizeof(pxl8_replay_chunk)); if (!chunk) return; chunk->type = type; chunk->size = size; - chunk->data = malloc(size); + chunk->data = pxl8_malloc(size); if (!chunk->data) { - free(chunk); + pxl8_free(chunk); return; } memcpy(chunk->data, data, size); @@ -327,7 +328,7 @@ void pxl8_replay_write_keyframe(pxl8_replay* r, u32 frame, f32 time, pxl8_rng* r write_chunk(r->file, PXL8_REPLAY_CHUNK_KEYFRAME, &kf, sizeof(kf)); fflush(r->file); } else { - pxl8_keyframe_entry* entry = calloc(1, sizeof(pxl8_keyframe_entry)); + pxl8_keyframe_entry* entry = pxl8_calloc(1, sizeof(pxl8_keyframe_entry)); if (!entry) return; entry->keyframe = kf; @@ -342,7 +343,7 @@ void pxl8_replay_write_keyframe(pxl8_replay* r, u32 frame, f32 time, pxl8_rng* r r->keyframes->prev = NULL; } pxl8_replay_chunk_free(oldest->input_deltas); - free(oldest); + pxl8_free(oldest); r->keyframe_count--; } @@ -446,14 +447,14 @@ void pxl8_replay_write_audio_event(pxl8_replay* r, u32 frame, u8 event_type, u8 if (r->file) { write_chunk(r->file, PXL8_REPLAY_CHUNK_AUDIO_EVENT, &evt, sizeof(evt)); } else { - pxl8_replay_chunk* chunk = calloc(1, sizeof(pxl8_replay_chunk)); + pxl8_replay_chunk* chunk = pxl8_calloc(1, sizeof(pxl8_replay_chunk)); if (!chunk) return; chunk->type = PXL8_REPLAY_CHUNK_AUDIO_EVENT; chunk->size = sizeof(evt); - chunk->data = malloc(sizeof(evt)); + chunk->data = pxl8_malloc(sizeof(evt)); if (!chunk->data) { - free(chunk); + pxl8_free(chunk); return; } memcpy(chunk->data, &evt, sizeof(evt)); diff --git a/src/game/pxl8_replay.h b/src/core/pxl8_replay.h similarity index 100% rename from src/game/pxl8_replay.h rename to src/core/pxl8_replay.h diff --git a/src/core/pxl8_types.h b/src/core/pxl8_types.h index e5e1135..437ebce 100644 --- a/src/core/pxl8_types.h +++ b/src/core/pxl8_types.h @@ -23,6 +23,9 @@ typedef uint16_t u16; typedef uint32_t u32; typedef uint64_t u64; +typedef size_t usize; +typedef ptrdiff_t isize; + #if defined(__SIZEOF_INT128__) typedef __int128_t i128; typedef __uint128_t u128; diff --git a/src/gfx/pxl8_3d_camera.c b/src/gfx/pxl8_3d_camera.c index 3cec31d..fc5429f 100644 --- a/src/gfx/pxl8_3d_camera.c +++ b/src/gfx/pxl8_3d_camera.c @@ -1,4 +1,5 @@ #include "pxl8_3d_camera.h" +#include "pxl8_mem.h" #include #include @@ -28,7 +29,7 @@ struct pxl8_3d_camera { }; pxl8_3d_camera* pxl8_3d_camera_create(void) { - pxl8_3d_camera* cam = calloc(1, sizeof(pxl8_3d_camera)); + pxl8_3d_camera* cam = pxl8_calloc(1, sizeof(pxl8_3d_camera)); if (!cam) return NULL; cam->position = (pxl8_vec3){0, 0, 0}; @@ -46,7 +47,7 @@ pxl8_3d_camera* pxl8_3d_camera_create(void) { } void pxl8_3d_camera_destroy(pxl8_3d_camera* cam) { - free(cam); + pxl8_free(cam); } void pxl8_3d_camera_lookat(pxl8_3d_camera* cam, pxl8_vec3 eye, pxl8_vec3 target, pxl8_vec3 up) { @@ -56,8 +57,8 @@ void pxl8_3d_camera_lookat(pxl8_3d_camera* cam, pxl8_vec3 eye, pxl8_vec3 target, pxl8_vec3 forward = pxl8_vec3_normalize(pxl8_vec3_sub(target, eye)); - cam->pitch = asinf(-forward.y); - cam->yaw = atan2f(forward.x, forward.z); + cam->pitch = asinf(forward.y); + cam->yaw = atan2f(-forward.x, -forward.z); cam->roll = 0; (void)up; @@ -104,9 +105,9 @@ pxl8_vec3 pxl8_3d_camera_get_forward(const pxl8_3d_camera* cam) { f32 sy = sinf(cam->yaw); return (pxl8_vec3){ - cp * sy, - -sp, - cp * cy + -sy * cp, + sp, + -cy * cp }; } @@ -121,7 +122,7 @@ pxl8_mat4 pxl8_3d_camera_get_projection(const pxl8_3d_camera* cam) { if (cam->mode == PXL8_3D_CAMERA_PERSPECTIVE) { return pxl8_mat4_perspective(cam->fov, cam->aspect, cam->near, cam->far); } else { - return pxl8_mat4_ortho( + return pxl8_mat4_orthographic( cam->ortho_left, cam->ortho_right, cam->ortho_bottom, cam->ortho_top, cam->near, cam->far @@ -183,8 +184,8 @@ void pxl8_3d_camera_follow(pxl8_3d_camera* cam, pxl8_vec3 target, pxl8_vec3 offs cam->position = pxl8_vec3_lerp(cam->position, desired, t); pxl8_vec3 forward = pxl8_vec3_normalize(pxl8_vec3_sub(target, cam->position)); - cam->pitch = asinf(-forward.y); - cam->yaw = atan2f(forward.x, forward.z); + cam->pitch = asinf(forward.y); + cam->yaw = atan2f(-forward.x, -forward.z); } void pxl8_3d_camera_shake(pxl8_3d_camera* cam, f32 intensity, f32 duration) { @@ -212,3 +213,30 @@ void pxl8_3d_camera_update(pxl8_3d_camera* cam, f32 dt) { } } } + +pxl8_projected_point pxl8_3d_camera_world_to_screen(const pxl8_3d_camera* cam, pxl8_vec3 world_pos, u32 screen_width, u32 screen_height) { + pxl8_projected_point result = {0, 0, 0.0f, false}; + if (!cam) return result; + + pxl8_mat4 view = pxl8_3d_camera_get_view(cam); + pxl8_mat4 proj = pxl8_3d_camera_get_projection(cam); + pxl8_mat4 vp = pxl8_mat4_multiply(proj, view); + + pxl8_vec4 clip = pxl8_mat4_multiply_vec4(vp, (pxl8_vec4){world_pos.x, world_pos.y, world_pos.z, 1.0f}); + + if (clip.w <= 0.0f) return result; + + f32 inv_w = 1.0f / clip.w; + f32 ndc_x = clip.x * inv_w; + f32 ndc_y = clip.y * inv_w; + f32 ndc_z = clip.z * inv_w; + + if (ndc_x < -1.0f || ndc_x > 1.0f || ndc_y < -1.0f || ndc_y > 1.0f) return result; + + result.x = (i32)((ndc_x + 1.0f) * 0.5f * (f32)screen_width); + result.y = (i32)((1.0f - ndc_y) * 0.5f * (f32)screen_height); + result.depth = ndc_z; + result.visible = true; + + return result; +} diff --git a/src/gfx/pxl8_3d_camera.h b/src/gfx/pxl8_3d_camera.h index 24ee8dd..e3a9fc4 100644 --- a/src/gfx/pxl8_3d_camera.h +++ b/src/gfx/pxl8_3d_camera.h @@ -32,6 +32,7 @@ pxl8_mat4 pxl8_3d_camera_get_view(const pxl8_3d_camera* cam); void pxl8_3d_camera_blend(pxl8_3d_camera* dest, const pxl8_3d_camera* a, const pxl8_3d_camera* b, f32 t); void pxl8_3d_camera_follow(pxl8_3d_camera* cam, pxl8_vec3 target, pxl8_vec3 offset, f32 smoothing, f32 dt); +pxl8_projected_point pxl8_3d_camera_world_to_screen(const pxl8_3d_camera* cam, pxl8_vec3 world_pos, u32 screen_width, u32 screen_height); void pxl8_3d_camera_shake(pxl8_3d_camera* cam, f32 intensity, f32 duration); void pxl8_3d_camera_update(pxl8_3d_camera* cam, f32 dt); diff --git a/src/gfx/pxl8_anim.c b/src/gfx/pxl8_anim.c index 9fbffc5..638848e 100644 --- a/src/gfx/pxl8_anim.c +++ b/src/gfx/pxl8_anim.c @@ -7,6 +7,7 @@ #include "pxl8_atlas.h" #include "pxl8_gfx.h" #include "pxl8_log.h" +#include "pxl8_mem.h" #define PXL8_ANIM_MAX_STATES 32 @@ -36,36 +37,36 @@ pxl8_anim* pxl8_anim_create(const u32* frame_ids, const u16* frame_durations, u1 return NULL; } - pxl8_anim* anim = (pxl8_anim*)calloc(1, sizeof(pxl8_anim)); + pxl8_anim* anim = (pxl8_anim*)pxl8_calloc(1, sizeof(pxl8_anim)); if (!anim) { pxl8_error("Failed to allocate animation"); return NULL; } - anim->frame_ids = (u32*)malloc(frame_count * sizeof(u32)); + anim->frame_ids = (u32*)pxl8_malloc(frame_count * sizeof(u32)); if (!anim->frame_ids) { pxl8_error("Failed to allocate frame IDs"); - free(anim); + pxl8_free(anim); return NULL; } memcpy(anim->frame_ids, frame_ids, frame_count * sizeof(u32)); if (frame_durations) { - anim->frame_durations = (u16*)malloc(frame_count * sizeof(u16)); + anim->frame_durations = (u16*)pxl8_malloc(frame_count * sizeof(u16)); if (!anim->frame_durations) { pxl8_error("Failed to allocate frame durations"); - free(anim->frame_ids); - free(anim); + pxl8_free(anim->frame_ids); + pxl8_free(anim); return NULL; } memcpy(anim->frame_durations, frame_durations, frame_count * sizeof(u16)); } else { - anim->frame_durations = (u16*)calloc(frame_count, sizeof(u16)); + anim->frame_durations = (u16*)pxl8_calloc(frame_count, sizeof(u16)); if (!anim->frame_durations) { pxl8_error("Failed to allocate frame durations"); - free(anim->frame_ids); - free(anim); + pxl8_free(anim->frame_ids); + pxl8_free(anim); return NULL; } for (u16 i = 0; i < frame_count; i++) { @@ -107,12 +108,12 @@ pxl8_anim* pxl8_anim_create_from_ase(pxl8_gfx* gfx, const char* path) { return NULL; } - u32* frame_ids = (u32*)malloc(ase_file.frame_count * sizeof(u32)); - u16* frame_durations = (u16*)malloc(ase_file.frame_count * sizeof(u16)); + u32* frame_ids = (u32*)pxl8_malloc(ase_file.frame_count * sizeof(u32)); + u16* frame_durations = (u16*)pxl8_malloc(ase_file.frame_count * sizeof(u16)); if (!frame_ids || !frame_durations) { pxl8_error("Failed to allocate frame arrays"); - free(frame_ids); - free(frame_durations); + pxl8_free(frame_ids); + pxl8_free(frame_durations); pxl8_ase_destroy(&ase_file); return NULL; } @@ -122,8 +123,8 @@ pxl8_anim* pxl8_anim_create_from_ase(pxl8_gfx* gfx, const char* path) { result = pxl8_gfx_create_texture(gfx, frame->pixels, frame->width, frame->height); if (result != PXL8_OK) { pxl8_error("Failed to create texture for frame %u", i); - free(frame_ids); - free(frame_durations); + pxl8_free(frame_ids); + pxl8_free(frame_durations); pxl8_ase_destroy(&ase_file); return NULL; } @@ -133,8 +134,8 @@ pxl8_anim* pxl8_anim_create_from_ase(pxl8_gfx* gfx, const char* path) { pxl8_anim* anim = pxl8_anim_create(frame_ids, frame_durations, ase_file.frame_count); - free(frame_ids); - free(frame_durations); + pxl8_free(frame_ids); + pxl8_free(frame_durations); pxl8_ase_destroy(&ase_file); return anim; @@ -145,15 +146,15 @@ void pxl8_anim_destroy(pxl8_anim* anim) { if (anim->state_machine) { for (u16 i = 0; i < anim->state_machine->state_count; i++) { - free(anim->state_machine->states[i].name); + pxl8_free(anim->state_machine->states[i].name); pxl8_anim_destroy(anim->state_machine->states[i].anim); } - free(anim->state_machine); + pxl8_free(anim->state_machine); } - free(anim->frame_ids); - free(anim->frame_durations); - free(anim); + pxl8_free(anim->frame_ids); + pxl8_free(anim->frame_durations); + pxl8_free(anim); } pxl8_result pxl8_anim_add_state(pxl8_anim* anim, const char* name, pxl8_anim* state_anim) { @@ -162,7 +163,7 @@ pxl8_result pxl8_anim_add_state(pxl8_anim* anim, const char* name, pxl8_anim* st } if (!anim->state_machine) { - anim->state_machine = (pxl8_anim_state_machine*)calloc(1, sizeof(pxl8_anim_state_machine)); + anim->state_machine = (pxl8_anim_state_machine*)pxl8_calloc(1, sizeof(pxl8_anim_state_machine)); if (!anim->state_machine) { return PXL8_ERROR_OUT_OF_MEMORY; } diff --git a/src/gfx/pxl8_atlas.c b/src/gfx/pxl8_atlas.c index f752145..910dba6 100644 --- a/src/gfx/pxl8_atlas.c +++ b/src/gfx/pxl8_atlas.c @@ -7,6 +7,7 @@ #include "pxl8_color.h" #include "pxl8_log.h" +#include "pxl8_mem.h" typedef struct pxl8_skyline_fit { bool found; @@ -27,6 +28,8 @@ typedef struct pxl8_skyline { struct pxl8_atlas { u32 height, width; u8* pixels; + u8* pixels_tiled; + u32 tiled_capacity, tiled_size; bool dirty; @@ -103,7 +106,7 @@ static bool pxl8_skyline_add_rect(pxl8_skyline* skyline, pxl8_point pos, u32 w, if (skyline->count - nodes_to_remove + 1 > skyline->capacity) { u32 new_capacity = (skyline->count - nodes_to_remove + 1) * 2; - pxl8_skyline_node* new_nodes = (pxl8_skyline_node*)realloc( + pxl8_skyline_node* new_nodes = (pxl8_skyline_node*)pxl8_realloc( skyline->nodes, new_capacity * sizeof(pxl8_skyline_node) ); @@ -142,44 +145,44 @@ static void pxl8_skyline_compact(pxl8_skyline* skyline) { } pxl8_atlas* pxl8_atlas_create(u32 width, u32 height, pxl8_pixel_mode pixel_mode) { - pxl8_atlas* atlas = (pxl8_atlas*)calloc(1, sizeof(pxl8_atlas)); + pxl8_atlas* atlas = (pxl8_atlas*)pxl8_calloc(1, sizeof(pxl8_atlas)); if (!atlas) return NULL; atlas->height = height; atlas->width = width; i32 bytes_per_pixel = pxl8_bytes_per_pixel(pixel_mode); - atlas->pixels = (u8*)calloc(width * height, bytes_per_pixel); + atlas->pixels = (u8*)pxl8_calloc(width * height, bytes_per_pixel); if (!atlas->pixels) { - free(atlas); + pxl8_free(atlas); return NULL; } atlas->entry_capacity = PXL8_DEFAULT_ATLAS_ENTRY_CAPACITY; - atlas->entries = (pxl8_atlas_entry*)calloc(atlas->entry_capacity, sizeof(pxl8_atlas_entry)); + atlas->entries = (pxl8_atlas_entry*)pxl8_calloc(atlas->entry_capacity, sizeof(pxl8_atlas_entry)); if (!atlas->entries) { - free(atlas->pixels); - free(atlas); + pxl8_free(atlas->pixels); + pxl8_free(atlas); return NULL; } atlas->free_capacity = 16; - atlas->free_list = (u32*)calloc(atlas->free_capacity, sizeof(u32)); + atlas->free_list = (u32*)pxl8_calloc(atlas->free_capacity, sizeof(u32)); if (!atlas->free_list) { - free(atlas->entries); - free(atlas->pixels); - free(atlas); + pxl8_free(atlas->entries); + pxl8_free(atlas->pixels); + pxl8_free(atlas); return NULL; } atlas->skyline.capacity = 16; atlas->skyline.nodes = - (pxl8_skyline_node*)calloc(atlas->skyline.capacity, sizeof(pxl8_skyline_node)); + (pxl8_skyline_node*)pxl8_calloc(atlas->skyline.capacity, sizeof(pxl8_skyline_node)); if (!atlas->skyline.nodes) { - free(atlas->free_list); - free(atlas->entries); - free(atlas->pixels); - free(atlas); + pxl8_free(atlas->free_list); + pxl8_free(atlas->entries); + pxl8_free(atlas->pixels); + pxl8_free(atlas); return NULL; } @@ -192,11 +195,12 @@ pxl8_atlas* pxl8_atlas_create(u32 width, u32 height, pxl8_pixel_mode pixel_mode) void pxl8_atlas_destroy(pxl8_atlas* atlas) { if (!atlas) return; - free(atlas->entries); - free(atlas->free_list); - free(atlas->pixels); - free(atlas->skyline.nodes); - free(atlas); + pxl8_free(atlas->entries); + pxl8_free(atlas->free_list); + pxl8_free(atlas->pixels); + pxl8_free(atlas->pixels_tiled); + pxl8_free(atlas->skyline.nodes); + pxl8_free(atlas); } void pxl8_atlas_clear(pxl8_atlas* atlas, u32 preserve_count) { @@ -209,6 +213,13 @@ void pxl8_atlas_clear(pxl8_atlas* atlas, u32 preserve_count) { atlas->entry_count = preserve_count; atlas->free_count = 0; + if (preserve_count == 0) { + atlas->tiled_size = 0; + } else { + pxl8_atlas_entry* last = &atlas->entries[preserve_count - 1]; + atlas->tiled_size = last->tiled_base + (u32)(last->w * last->h); + } + atlas->skyline.nodes[0] = (pxl8_skyline_node){0, 0, (i32)atlas->width}; atlas->skyline.count = 1; @@ -222,13 +233,13 @@ bool pxl8_atlas_expand(pxl8_atlas* atlas, pxl8_pixel_mode pixel_mode) { u32 new_size = atlas->width * 2; u32 old_width = atlas->width; - u8* new_pixels = (u8*)calloc(new_size * new_size, bytes_per_pixel); + u8* new_pixels = (u8*)pxl8_calloc(new_size * new_size, bytes_per_pixel); if (!new_pixels) return false; pxl8_skyline new_skyline; - new_skyline.nodes = (pxl8_skyline_node*)calloc(16, sizeof(pxl8_skyline_node)); + new_skyline.nodes = (pxl8_skyline_node*)pxl8_calloc(16, sizeof(pxl8_skyline_node)); if (!new_skyline.nodes) { - free(new_pixels); + pxl8_free(new_pixels); return false; } @@ -248,8 +259,8 @@ bool pxl8_atlas_expand(pxl8_atlas* atlas, pxl8_pixel_mode pixel_mode) { ); if (!fit.found) { - free(new_skyline.nodes); - free(new_pixels); + pxl8_free(new_skyline.nodes); + pxl8_free(new_pixels); return false; } @@ -269,15 +280,15 @@ bool pxl8_atlas_expand(pxl8_atlas* atlas, pxl8_pixel_mode pixel_mode) { atlas->entries[i].y = fit.pos.y; if (!pxl8_skyline_add_rect(&new_skyline, fit.pos, atlas->entries[i].w, atlas->entries[i].h)) { - free(new_skyline.nodes); - free(new_pixels); + pxl8_free(new_skyline.nodes); + pxl8_free(new_pixels); return false; } pxl8_skyline_compact(&new_skyline); } - free(atlas->pixels); - free(atlas->skyline.nodes); + pxl8_free(atlas->pixels); + pxl8_free(atlas->skyline.nodes); atlas->pixels = new_pixels; atlas->skyline = new_skyline; @@ -316,7 +327,7 @@ u32 pxl8_atlas_add_texture( } else { if (atlas->entry_count >= atlas->entry_capacity) { u32 new_capacity = atlas->entry_capacity * 2; - pxl8_atlas_entry* new_entries = (pxl8_atlas_entry*)realloc( + pxl8_atlas_entry* new_entries = (pxl8_atlas_entry*)pxl8_realloc( atlas->entries, new_capacity * sizeof(pxl8_atlas_entry) ); @@ -334,6 +345,7 @@ u32 pxl8_atlas_add_texture( entry->y = fit.pos.y; entry->w = w; entry->h = h; + entry->log2_w = pxl8_log2(w); i32 bytes_per_pixel = pxl8_bytes_per_pixel(pixel_mode); for (u32 y = 0; y < h; y++) { @@ -349,6 +361,30 @@ u32 pxl8_atlas_add_texture( } } + u32 tiled_tex_size = w * h; + u32 new_tiled_size = atlas->tiled_size + tiled_tex_size; + if (new_tiled_size > atlas->tiled_capacity) { + u32 new_cap = atlas->tiled_capacity ? atlas->tiled_capacity * 2 : 4096; + while (new_cap < new_tiled_size) new_cap *= 2; + u8* new_tiled = (u8*)pxl8_realloc(atlas->pixels_tiled, new_cap); + if (!new_tiled) { + entry->active = false; + return UINT32_MAX; + } + atlas->pixels_tiled = new_tiled; + atlas->tiled_capacity = new_cap; + } + + entry->tiled_base = atlas->tiled_size; + u8* tiled_dst = atlas->pixels_tiled + entry->tiled_base; + for (u32 ty = 0; ty < h; ty++) { + for (u32 tx = 0; tx < w; tx++) { + u32 tiled_offset = pxl8_tile_addr(tx, ty, entry->log2_w); + tiled_dst[tiled_offset] = pixels[ty * w + tx]; + } + } + atlas->tiled_size = new_tiled_size; + if (!pxl8_skyline_add_rect(&atlas->skyline, fit.pos, w, h)) { entry->active = false; return UINT32_MAX; @@ -377,6 +413,10 @@ const u8* pxl8_atlas_get_pixels(const pxl8_atlas* atlas) { return atlas ? atlas->pixels : NULL; } +const u8* pxl8_atlas_get_pixels_tiled(const pxl8_atlas* atlas) { + return atlas ? atlas->pixels_tiled : NULL; +} + u32 pxl8_atlas_get_width(const pxl8_atlas* atlas) { return atlas ? atlas->width : 0; } diff --git a/src/gfx/pxl8_atlas.h b/src/gfx/pxl8_atlas.h index 2f0313b..2a429f9 100644 --- a/src/gfx/pxl8_atlas.h +++ b/src/gfx/pxl8_atlas.h @@ -8,28 +8,42 @@ typedef struct pxl8_atlas_entry { bool active; u32 texture_id; i32 x, y, w, h; + u32 tiled_base; + u8 log2_w; } pxl8_atlas_entry; +static inline u32 pxl8_tile_addr(u32 u, u32 v, u8 log2_w) { + u32 tile_y = v >> 3; + u32 tile_x = u >> 3; + u32 local_y = v & 7; + u32 local_x = u & 7; + return (tile_y << (log2_w + 3)) | (tile_x << 6) | (local_y << 3) | local_x; +} + +static inline u8 pxl8_log2(u32 v) { + u8 r = 0; + while (v >>= 1) r++; + return r; +} + #ifdef __cplusplus extern "C" { #endif +u32 pxl8_atlas_add_texture(pxl8_atlas* atlas, const u8* pixels, u32 w, u32 h, pxl8_pixel_mode pixel_mode); +void pxl8_atlas_clear(pxl8_atlas* atlas, u32 preserve_count); pxl8_atlas* pxl8_atlas_create(u32 width, u32 height, pxl8_pixel_mode pixel_mode); void pxl8_atlas_destroy(pxl8_atlas* atlas); - +bool pxl8_atlas_expand(pxl8_atlas* atlas, pxl8_pixel_mode pixel_mode); const pxl8_atlas_entry* pxl8_atlas_get_entry(const pxl8_atlas* atlas, u32 id); u32 pxl8_atlas_get_entry_count(const pxl8_atlas* atlas); u32 pxl8_atlas_get_height(const pxl8_atlas* atlas); const u8* pxl8_atlas_get_pixels(const pxl8_atlas* atlas); +const u8* pxl8_atlas_get_pixels_tiled(const pxl8_atlas* atlas); u32 pxl8_atlas_get_width(const pxl8_atlas* atlas); bool pxl8_atlas_is_dirty(const pxl8_atlas* atlas); - void pxl8_atlas_mark_clean(pxl8_atlas* atlas); -u32 pxl8_atlas_add_texture(pxl8_atlas* atlas, const u8* pixels, u32 w, u32 h, pxl8_pixel_mode pixel_mode); -void pxl8_atlas_clear(pxl8_atlas* atlas, u32 preserve_count); -bool pxl8_atlas_expand(pxl8_atlas* atlas, pxl8_pixel_mode pixel_mode); - #ifdef __cplusplus } #endif diff --git a/src/gfx/pxl8_blend.c b/src/gfx/pxl8_blend.c deleted file mode 100644 index 74ba68a..0000000 --- a/src/gfx/pxl8_blend.c +++ /dev/null @@ -1,194 +0,0 @@ -#include "pxl8_blend.h" -#include "pxl8_colormap.h" - -#include - -struct pxl8_palette_cube { - u8 colors[PXL8_PALETTE_SIZE * 3]; - u8 table[PXL8_CUBE_ENTRIES]; - u8 stable[PXL8_CUBE_ENTRIES]; -}; - -struct pxl8_additive_table { - u8 table[PXL8_BLEND_TABLE_SIZE]; -}; - -struct pxl8_overbright_table { - u8 table[PXL8_OVERBRIGHT_TABLE_SIZE]; -}; - -static u8 find_closest_stable(const pxl8_palette* pal, u8 r, u8 g, u8 b) { - u8 best_idx = 1; - u32 best_dist = 0xFFFFFFFF; - - u8 dynamic_end = PXL8_DYNAMIC_RANGE_START + PXL8_DYNAMIC_RANGE_COUNT; - - for (u32 i = 1; i < PXL8_FULLBRIGHT_START; i++) { - if (i >= PXL8_DYNAMIC_RANGE_START && i < dynamic_end) { - continue; - } - - u8 pr, pg, pb; - pxl8_palette_get_rgb(pal, (u8)i, &pr, &pg, &pb); - - i32 dr = (i32)r - (i32)pr; - i32 dg = (i32)g - (i32)pg; - i32 db = (i32)b - (i32)pb; - u32 dist = (u32)(dr * dr + dg * dg + db * db); - - if (dist < best_dist) { - best_dist = dist; - best_idx = (u8)i; - if (dist == 0) break; - } - } - - return best_idx; -} - -pxl8_palette_cube* pxl8_palette_cube_create(const pxl8_palette* pal) { - pxl8_palette_cube* cube = calloc(1, sizeof(pxl8_palette_cube)); - if (!cube) return NULL; - pxl8_palette_cube_rebuild(cube, pal); - return cube; -} - -void pxl8_palette_cube_destroy(pxl8_palette_cube* cube) { - free(cube); -} - -void pxl8_palette_cube_rebuild(pxl8_palette_cube* cube, const pxl8_palette* pal) { - if (!cube || !pal) return; - - for (u32 i = 0; i < PXL8_PALETTE_SIZE; i++) { - u8 r, g, b; - pxl8_palette_get_rgb(pal, (u8)i, &r, &g, &b); - cube->colors[i * 3 + 0] = r; - cube->colors[i * 3 + 1] = g; - cube->colors[i * 3 + 2] = b; - } - - for (u32 bi = 0; bi < PXL8_CUBE_SIZE; bi++) { - for (u32 gi = 0; gi < PXL8_CUBE_SIZE; gi++) { - for (u32 ri = 0; ri < PXL8_CUBE_SIZE; ri++) { - u32 idx = (bi * PXL8_CUBE_SIZE * PXL8_CUBE_SIZE) + (gi * PXL8_CUBE_SIZE) + ri; - u8 r8 = (u8)((ri * 255) / (PXL8_CUBE_SIZE - 1)); - u8 g8 = (u8)((gi * 255) / (PXL8_CUBE_SIZE - 1)); - u8 b8 = (u8)((bi * 255) / (PXL8_CUBE_SIZE - 1)); - - cube->table[idx] = pxl8_palette_find_closest(pal, r8, g8, b8); - cube->stable[idx] = find_closest_stable(pal, r8, g8, b8); - } - } - } -} - -u8 pxl8_palette_cube_lookup(const pxl8_palette_cube* cube, u8 r, u8 g, u8 b) { - u32 ri = (r * (PXL8_CUBE_SIZE - 1)) / 255; - u32 gi = (g * (PXL8_CUBE_SIZE - 1)) / 255; - u32 bi = (b * (PXL8_CUBE_SIZE - 1)) / 255; - u32 idx = (bi * PXL8_CUBE_SIZE * PXL8_CUBE_SIZE) + (gi * PXL8_CUBE_SIZE) + ri; - return cube->table[idx]; -} - -u8 pxl8_palette_cube_lookup_stable(const pxl8_palette_cube* cube, u8 r, u8 g, u8 b) { - u32 ri = (r * (PXL8_CUBE_SIZE - 1)) / 255; - u32 gi = (g * (PXL8_CUBE_SIZE - 1)) / 255; - u32 bi = (b * (PXL8_CUBE_SIZE - 1)) / 255; - u32 idx = (bi * PXL8_CUBE_SIZE * PXL8_CUBE_SIZE) + (gi * PXL8_CUBE_SIZE) + ri; - return cube->stable[idx]; -} - -void pxl8_palette_cube_get_rgb(const pxl8_palette_cube* cube, u8 idx, u8* r, u8* g, u8* b) { - *r = cube->colors[idx * 3 + 0]; - *g = cube->colors[idx * 3 + 1]; - *b = cube->colors[idx * 3 + 2]; -} - -pxl8_additive_table* pxl8_additive_table_create(const pxl8_palette* pal) { - pxl8_additive_table* table = calloc(1, sizeof(pxl8_additive_table)); - if (!table) return NULL; - pxl8_additive_table_rebuild(table, pal); - return table; -} - -void pxl8_additive_table_destroy(pxl8_additive_table* table) { - free(table); -} - -void pxl8_additive_table_rebuild(pxl8_additive_table* table, const pxl8_palette* pal) { - if (!table || !pal) return; - - for (u32 src = 0; src < 256; src++) { - u8 sr, sg, sb; - pxl8_palette_get_rgb(pal, (u8)src, &sr, &sg, &sb); - - for (u32 dst = 0; dst < 256; dst++) { - u32 idx = src * 256 + dst; - - if (src == PXL8_TRANSPARENT) { - table->table[idx] = (u8)dst; - continue; - } - - u8 dr, dg, db; - pxl8_palette_get_rgb(pal, (u8)dst, &dr, &dg, &db); - - u16 ar = (u16)sr + (u16)dr; - u16 ag = (u16)sg + (u16)dg; - u16 ab = (u16)sb + (u16)db; - if (ar > 255) ar = 255; - if (ag > 255) ag = 255; - if (ab > 255) ab = 255; - - table->table[idx] = find_closest_stable(pal, (u8)ar, (u8)ag, (u8)ab); - } - } -} - -u8 pxl8_additive_blend(const pxl8_additive_table* table, u8 src, u8 dst) { - return table->table[(u32)src * 256 + dst]; -} - -pxl8_overbright_table* pxl8_overbright_table_create(const pxl8_palette* pal) { - pxl8_overbright_table* table = calloc(1, sizeof(pxl8_overbright_table)); - if (!table) return NULL; - pxl8_overbright_table_rebuild(table, pal); - return table; -} - -void pxl8_overbright_table_destroy(pxl8_overbright_table* table) { - free(table); -} - -void pxl8_overbright_table_rebuild(pxl8_overbright_table* table, const pxl8_palette* pal) { - if (!table || !pal) return; - - for (u32 level = 0; level < PXL8_OVERBRIGHT_LEVELS; level++) { - f32 overbright = (f32)level / (f32)(PXL8_OVERBRIGHT_LEVELS - 1); - - for (u32 pal_idx = 0; pal_idx < 256; pal_idx++) { - u32 idx = level * 256 + pal_idx; - - if (pal_idx == PXL8_TRANSPARENT) { - table->table[idx] = PXL8_TRANSPARENT; - continue; - } - - u8 r, g, b; - pxl8_palette_get_rgb(pal, (u8)pal_idx, &r, &g, &b); - - u8 or = (u8)(r + (255 - r) * overbright); - u8 og = (u8)(g + (255 - g) * overbright); - u8 ob = (u8)(b + (255 - b) * overbright); - - table->table[idx] = find_closest_stable(pal, or, og, ob); - } - } -} - -u8 pxl8_overbright_lookup(const pxl8_overbright_table* table, u8 pal_idx, f32 emissive) { - u32 level = (u32)(emissive * (PXL8_OVERBRIGHT_LEVELS - 1)); - if (level >= PXL8_OVERBRIGHT_LEVELS) level = PXL8_OVERBRIGHT_LEVELS - 1; - return table->table[level * 256 + pal_idx]; -} diff --git a/src/gfx/pxl8_blend.h b/src/gfx/pxl8_blend.h deleted file mode 100644 index 94f8a30..0000000 --- a/src/gfx/pxl8_blend.h +++ /dev/null @@ -1,39 +0,0 @@ -#pragma once - -#include "pxl8_palette.h" -#include "pxl8_types.h" - -#ifdef __cplusplus -extern "C" { -#endif - -#define PXL8_CUBE_SIZE 32 -#define PXL8_CUBE_ENTRIES (PXL8_CUBE_SIZE * PXL8_CUBE_SIZE * PXL8_CUBE_SIZE) -#define PXL8_BLEND_TABLE_SIZE (256 * 256) -#define PXL8_OVERBRIGHT_LEVELS 16 -#define PXL8_OVERBRIGHT_TABLE_SIZE (256 * PXL8_OVERBRIGHT_LEVELS) - -typedef struct pxl8_additive_table pxl8_additive_table; -typedef struct pxl8_overbright_table pxl8_overbright_table; -typedef struct pxl8_palette_cube pxl8_palette_cube; - -pxl8_additive_table* pxl8_additive_table_create(const pxl8_palette* pal); -void pxl8_additive_table_destroy(pxl8_additive_table* table); -void pxl8_additive_table_rebuild(pxl8_additive_table* table, const pxl8_palette* pal); -u8 pxl8_additive_blend(const pxl8_additive_table* table, u8 src, u8 dst); - -pxl8_overbright_table* pxl8_overbright_table_create(const pxl8_palette* pal); -void pxl8_overbright_table_destroy(pxl8_overbright_table* table); -void pxl8_overbright_table_rebuild(pxl8_overbright_table* table, const pxl8_palette* pal); -u8 pxl8_overbright_lookup(const pxl8_overbright_table* table, u8 pal_idx, f32 emissive); - -pxl8_palette_cube* pxl8_palette_cube_create(const pxl8_palette* pal); -void pxl8_palette_cube_destroy(pxl8_palette_cube* cube); -void pxl8_palette_cube_rebuild(pxl8_palette_cube* cube, const pxl8_palette* pal); -u8 pxl8_palette_cube_lookup(const pxl8_palette_cube* cube, u8 r, u8 g, u8 b); -u8 pxl8_palette_cube_lookup_stable(const pxl8_palette_cube* cube, u8 r, u8 g, u8 b); -void pxl8_palette_cube_get_rgb(const pxl8_palette_cube* cube, u8 idx, u8* r, u8* g, u8* b); - -#ifdef __cplusplus -} -#endif diff --git a/src/gfx/pxl8_colormap.c b/src/gfx/pxl8_colormap.c index 4240ed3..925fd87 100644 --- a/src/gfx/pxl8_colormap.c +++ b/src/gfx/pxl8_colormap.c @@ -1,42 +1,12 @@ #include "pxl8_colormap.h" #include -static void rgb_to_hsl(u8 r, u8 g, u8 b, i32* h, i32* s, i32* l) { - i32 max = r > g ? (r > b ? r : b) : (g > b ? g : b); - i32 min = r < g ? (r < b ? r : b) : (g < b ? g : b); - i32 chroma = max - min; - - *l = (max + min) / 2; - - if (chroma == 0) { - *h = 0; - *s = 0; - } else { - i32 denom = 255 - (*l > 127 ? 2 * (*l) - 255 : 255 - 2 * (*l)); - if (denom <= 0) denom = 1; - *s = (chroma * 255) / denom; - if (*s > 255) *s = 255; - - if (max == (i32)r) { - *h = (((i32)g - (i32)b) * 60) / chroma; - if (*h < 0) *h += 360; - } else if (max == (i32)g) { - *h = 120 + (((i32)b - (i32)r) * 60) / chroma; - } else { - *h = 240 + (((i32)r - (i32)g) * 60) / chroma; - } - } -} - static u8 find_closest_color(const u32* palette, u8 target_r, u8 target_g, u8 target_b) { u8 best_idx = 1; u32 best_dist = 0xFFFFFFFF; u8 dynamic_end = PXL8_DYNAMIC_RANGE_START + PXL8_DYNAMIC_RANGE_COUNT; - i32 th, ts, tl; - rgb_to_hsl(target_r, target_g, target_b, &th, &ts, &tl); - for (u32 i = 1; i < PXL8_FULLBRIGHT_START; i++) { if (i >= PXL8_DYNAMIC_RANGE_START && i < dynamic_end) { continue; @@ -47,17 +17,10 @@ static u8 find_closest_color(const u32* palette, u8 target_r, u8 target_g, u8 ta u8 pg = (c >> 8) & 0xFF; u8 pb = (c >> 16) & 0xFF; - i32 ph, ps, pl; - rgb_to_hsl(pr, pg, pb, &ph, &ps, &pl); - - i32 dh = th - ph; - if (dh > 180) dh -= 360; - if (dh < -180) dh += 360; - - i32 ds = ts - ps; - i32 dl = tl - pl; - - u32 dist = (u32)(dh * dh * 4 + ds * ds + dl * dl); + i32 dr = (i32)target_r - (i32)pr; + i32 dg = (i32)target_g - (i32)pg; + i32 db = (i32)target_b - (i32)pb; + u32 dist = (u32)(dr * dr + dg * dg + db * db); if (dist < best_dist) { best_dist = dist; @@ -69,26 +32,19 @@ static u8 find_closest_color(const u32* palette, u8 target_r, u8 target_g, u8 ta return best_idx; } -void pxl8_colormap_generate(pxl8_colormap* cm, const u32* palette, const pxl8_level_tint* tint) { - if (!cm || !palette) return; +void pxl8_set_colormap(pxl8_colormap* cm, const u8* data, u32 size) { + if (!cm || !data || size == 0) return; + u32 copy_size = size > PXL8_COLORMAP_SIZE ? PXL8_COLORMAP_SIZE : size; + memcpy(cm->table, data, copy_size); +} - u8 dark_r, dark_g, dark_b; - if (tint && tint->tint_strength > 0.0f) { - f32 t = tint->tint_strength; - f32 inv = 1.0f - t; - dark_r = (u8)(tint->dark_r * inv + tint->tint_r * t); - dark_g = (u8)(tint->dark_g * inv + tint->tint_g * t); - dark_b = (u8)(tint->dark_b * inv + tint->tint_b * t); - } else if (tint) { - dark_r = tint->dark_r; - dark_g = tint->dark_g; - dark_b = tint->dark_b; - } else { - dark_r = dark_g = dark_b = 0; - } +static void generate_light_table(pxl8_colormap* cm, const u32* palette, pxl8_light_color light_color) { + pxl8_rgb light = pxl8_light_colors[light_color]; + u32 base_row = (u32)light_color * PXL8_LIGHT_LEVELS; - for (u32 light = 0; light < PXL8_LIGHT_LEVELS; light++) { - f32 brightness = (f32)light / (f32)(PXL8_LIGHT_LEVELS - 1); + for (u32 level = 0; level < PXL8_LIGHT_LEVELS; level++) { + f32 brightness = (f32)level / (f32)(PXL8_LIGHT_LEVELS - 1); + u32 row = base_row + level; for (u32 pal_idx = 0; pal_idx < 256; pal_idx++) { u8 result_idx; @@ -103,14 +59,65 @@ void pxl8_colormap_generate(pxl8_colormap* cm, const u32* palette, const pxl8_le u8 g = (c >> 8) & 0xFF; u8 b = (c >> 16) & 0xFF; - u8 target_r = (u8)(dark_r + (r - dark_r) * brightness); - u8 target_g = (u8)(dark_g + (g - dark_g) * brightness); - u8 target_b = (u8)(dark_b + (b - dark_b) * brightness); + f32 lr = (f32)light.r / 255.0f; + f32 lg = (f32)light.g / 255.0f; + f32 lb = (f32)light.b / 255.0f; + + u8 target_r = (u8)(r * brightness * lr); + u8 target_g = (u8)(g * brightness * lg); + u8 target_b = (u8)(b * brightness * lb); result_idx = find_closest_color(palette, target_r, target_g, target_b); } - cm->table[light * 256 + pal_idx] = result_idx; + cm->table[row * 256 + pal_idx] = result_idx; } } } + +static void generate_blend_table(pxl8_colormap* cm, const u32* palette) { + for (u32 src = 0; src < 256; src++) { + u32 row = PXL8_LIGHT_ROWS + src; + + u8 sr, sg, sb; + if (src == PXL8_TRANSPARENT) { + sr = sg = sb = 0; + } else { + u32 sc = palette[src]; + sr = sc & 0xFF; + sg = (sc >> 8) & 0xFF; + sb = (sc >> 16) & 0xFF; + } + + for (u32 dst = 0; dst < 256; dst++) { + u8 result_idx; + + if (src == PXL8_TRANSPARENT) { + result_idx = (u8)dst; + } else { + u32 dc = palette[dst]; + u8 dr = dc & 0xFF; + u8 dg = (dc >> 8) & 0xFF; + u8 db = (dc >> 16) & 0xFF; + + u8 blend_r = (u8)((sr + dr) / 2); + u8 blend_g = (u8)((sg + dg) / 2); + u8 blend_b = (u8)((sb + db) / 2); + + result_idx = find_closest_color(palette, blend_r, blend_g, blend_b); + } + + cm->table[row * 256 + dst] = result_idx; + } + } +} + +void pxl8_colormap_generate(pxl8_colormap* cm, const u32* palette) { + if (!cm || !palette) return; + + for (u32 light = 0; light < PXL8_LIGHT_COLORS; light++) { + generate_light_table(cm, palette, (pxl8_light_color)light); + } + + generate_blend_table(cm, palette); +} diff --git a/src/gfx/pxl8_colormap.h b/src/gfx/pxl8_colormap.h index 6e090a0..04f8fd0 100644 --- a/src/gfx/pxl8_colormap.h +++ b/src/gfx/pxl8_colormap.h @@ -7,35 +7,65 @@ extern "C" { #endif -#define PXL8_LIGHT_LEVELS 64 -#define PXL8_COLORMAP_SIZE (256 * PXL8_LIGHT_LEVELS) +#define PXL8_LIGHT_COLORS 8 +#define PXL8_LIGHT_LEVELS 8 +#define PXL8_LIGHT_ROWS (PXL8_LIGHT_COLORS * PXL8_LIGHT_LEVELS) +#define PXL8_BLEND_ROWS 256 +#define PXL8_COLORMAP_ROWS (PXL8_LIGHT_ROWS + PXL8_BLEND_ROWS) +#define PXL8_COLORMAP_SIZE (256 * PXL8_COLORMAP_ROWS) #define PXL8_FULLBRIGHT_START 240 #define PXL8_TRANSPARENT 0 #define PXL8_DYNAMIC_RANGE_START 144 #define PXL8_DYNAMIC_RANGE_COUNT 16 +typedef enum { + PXL8_LIGHT_WHITE = 0, + PXL8_LIGHT_RED = 1, + PXL8_LIGHT_ORANGE = 2, + PXL8_LIGHT_YELLOW = 3, + PXL8_LIGHT_GREEN = 4, + PXL8_LIGHT_CYAN = 5, + PXL8_LIGHT_BLUE = 6, + PXL8_LIGHT_PURPLE = 7, +} pxl8_light_color; + +typedef struct { + u8 r, g, b; +} pxl8_rgb; + +static const pxl8_rgb pxl8_light_colors[PXL8_LIGHT_COLORS] = { + {255, 255, 255}, + {255, 64, 64}, + {255, 160, 64}, + {255, 255, 64}, + {64, 255, 64}, + {64, 255, 255}, + {64, 64, 255}, + {255, 64, 255}, +}; + typedef struct { u8 table[PXL8_COLORMAP_SIZE]; } pxl8_colormap; -typedef struct { - u8 dark_r, dark_g, dark_b; - u8 tint_r, tint_g, tint_b; - f32 tint_strength; -} pxl8_level_tint; +void pxl8_colormap_generate(pxl8_colormap* cm, const u32* palette); +void pxl8_set_colormap(pxl8_colormap* cm, const u8* data, u32 size); -void pxl8_colormap_generate(pxl8_colormap* cm, const u32* palette, const pxl8_level_tint* tint); - -static inline u8 pxl8_colormap_lookup(const pxl8_colormap* cm, u8 pal_idx, u8 light) { - u32 light_idx = light >> 2; - return cm->table[light_idx * 256 + pal_idx]; +static inline u8 pxl8_colormap_lookup(const pxl8_colormap* cm, u8 pal_idx, pxl8_light_color light_color, u8 intensity) { + u32 light_row = ((u32)light_color << 3) + (intensity >> 5); + return cm->table[(light_row << 8) + pal_idx]; } -static inline u8 pxl8_colormap_lookup_dithered(const pxl8_colormap* cm, u8 pal_idx, u8 light, u32 x, u32 y) { - u8 dithered = pxl8_dither_light(light, x, y); - u32 light_idx = dithered >> 2; - return cm->table[light_idx * 256 + pal_idx]; +static inline u8 pxl8_colormap_lookup_dithered(const pxl8_colormap* cm, u8 pal_idx, pxl8_light_color light_color, u8 intensity, u32 x, u32 y) { + u8 dithered = pxl8_dither_light(intensity, x, y); + u32 light_row = ((u32)light_color << 3) + (dithered >> 5); + return cm->table[(light_row << 8) + pal_idx]; +} + +static inline u8 pxl8_colormap_blend(const pxl8_colormap* cm, u8 src, u8 dst) { + u32 blend_row = PXL8_LIGHT_ROWS + src; + return cm->table[(blend_row << 8) + dst]; } #ifdef __cplusplus diff --git a/src/gfx/pxl8_cpu.c b/src/gfx/pxl8_cpu.c index 4ff5b88..a43d494 100644 --- a/src/gfx/pxl8_cpu.c +++ b/src/gfx/pxl8_cpu.c @@ -1,10 +1,10 @@ #include "pxl8_cpu.h" +#include "pxl8_mem.h" +#include #include #include -#include "pxl8_simd.h" - struct pxl8_cpu_render_target { u8* framebuffer; u32 height; @@ -72,8 +72,8 @@ static pxl8_light_result calc_vertex_light( if (sky_factor < 0.0f) sky_factor = 0.0f; intensity += sky_factor * frame->uniforms.celestial_intensity * 0.3f; - for (u32 i = 0; i < frame->uniforms.num_lights; i++) { - const pxl8_light* light = &frame->uniforms.lights[i]; + for (u32 i = 0; i < frame->lights_count; i++) { + const pxl8_light* light = &frame->lights[i]; f32 contrib = calc_light_intensity(light, world_pos, normal); if (contrib > 0.0f) { intensity += contrib; @@ -119,6 +119,7 @@ struct pxl8_cpu_backend { pxl8_cpu_render_target* target_stack[PXL8_MAX_TARGET_STACK]; u32 target_stack_depth; const pxl8_colormap* colormap; + const pxl8_palette_cube* palette_cube; const u32* palette; pxl8_3d_frame frame; pxl8_mat4 mvp; @@ -173,7 +174,7 @@ static inline void clip_line_2d(i32* x0, i32* y0, i32* x1, i32* y1, i32 w, i32 h } pxl8_cpu_backend* pxl8_cpu_create(u32 width, u32 height) { - pxl8_cpu_backend* cpu = calloc(1, sizeof(pxl8_cpu_backend)); + pxl8_cpu_backend* cpu = pxl8_calloc(1, sizeof(pxl8_cpu_backend)); if (!cpu) return NULL; pxl8_cpu_render_target_desc desc = { @@ -184,7 +185,7 @@ pxl8_cpu_backend* pxl8_cpu_create(u32 width, u32 height) { }; pxl8_cpu_render_target* base_target = pxl8_cpu_create_render_target(&desc); if (!base_target) { - free(cpu); + pxl8_free(cpu); return NULL; } @@ -193,10 +194,10 @@ pxl8_cpu_backend* pxl8_cpu_create(u32 width, u32 height) { cpu->current_target = base_target; cpu->output_size = width * height; - cpu->output = calloc(cpu->output_size, sizeof(u32)); + cpu->output = pxl8_calloc(cpu->output_size, sizeof(u32)); if (!cpu->output) { pxl8_cpu_destroy_render_target(base_target); - free(cpu); + pxl8_free(cpu); return NULL; } @@ -208,14 +209,14 @@ void pxl8_cpu_destroy(pxl8_cpu_backend* cpu) { for (u32 i = 0; i < cpu->target_stack_depth; i++) { pxl8_cpu_destroy_render_target(cpu->target_stack[i]); } - free(cpu->output); - free(cpu); + pxl8_free(cpu->output); + pxl8_free(cpu); } void pxl8_cpu_begin_frame(pxl8_cpu_backend* cpu, const pxl8_3d_frame* frame) { if (!cpu || !frame) return; cpu->frame = *frame; - cpu->mvp = pxl8_mat4_mul(frame->projection, frame->view); + cpu->mvp = pxl8_mat4_multiply(frame->projection, frame->view); } void pxl8_cpu_end_frame(pxl8_cpu_backend* cpu) { @@ -231,14 +232,12 @@ void pxl8_cpu_clear(pxl8_cpu_backend* cpu, u8 color) { void pxl8_cpu_clear_depth(pxl8_cpu_backend* cpu) { if (!cpu || !cpu->current_target) return; pxl8_cpu_render_target* render_target = cpu->current_target; + u32 count = render_target->width * render_target->height; if (render_target->zbuffer) { - u32 count = render_target->width * render_target->height; - for (u32 i = 0; i < count; i++) { - render_target->zbuffer[i] = 0xFFFF; - } + memset(render_target->zbuffer, 0xFF, count * sizeof(u16)); } if (render_target->light_accum) { - memset(render_target->light_accum, 0, render_target->width * render_target->height * sizeof(u32)); + memset(render_target->light_accum, 0, count * sizeof(u32)); } } @@ -246,6 +245,10 @@ void pxl8_cpu_set_colormap(pxl8_cpu_backend* cpu, const pxl8_colormap* cm) { if (cpu) cpu->colormap = cm; } +void pxl8_cpu_set_palette_cube(pxl8_cpu_backend* cpu, const pxl8_palette_cube* cube) { + if (cpu) cpu->palette_cube = cube; +} + void pxl8_cpu_set_palette(pxl8_cpu_backend* cpu, const u32* palette) { if (cpu) cpu->palette = palette; } @@ -366,8 +369,8 @@ void pxl8_cpu_draw_line_3d(pxl8_cpu_backend* cpu, pxl8_vec3 v0, pxl8_vec3 v1, u8 if (!cpu || !cpu->current_target) return; pxl8_cpu_render_target* render_target = cpu->current_target; - pxl8_vec4 c0 = pxl8_mat4_mul_vec4(cpu->mvp, (pxl8_vec4){v0.x, v0.y, v0.z, 1.0f}); - pxl8_vec4 c1 = pxl8_mat4_mul_vec4(cpu->mvp, (pxl8_vec4){v1.x, v1.y, v1.z, 1.0f}); + pxl8_vec4 c0 = pxl8_mat4_multiply_vec4(cpu->mvp, (pxl8_vec4){v0.x, v0.y, v0.z, 1.0f}); + pxl8_vec4 c1 = pxl8_mat4_multiply_vec4(cpu->mvp, (pxl8_vec4){v1.x, v1.y, v1.z, 1.0f}); if (c0.w <= 0.0f || c1.w <= 0.0f) return; @@ -699,6 +702,22 @@ static void rasterize_triangle_opaque( f32 v_end = (vw + dvw * steps) * pw_end; f32 l_start = lw * pw_start; f32 l_end = (lw + d_lw * steps) * pw_end; + + f32 fog_density = cpu->frame.uniforms.fog_density; + if (fog_density > 0.0f) { + f32 z_end_fog = z + dz * steps; + f32 t_start = (z + 1.0f) * 0.5f; + f32 t_end = (z_end_fog + 1.0f) * 0.5f; + if (t_start < 0.0f) t_start = 0.0f; + if (t_end < 0.0f) t_end = 0.0f; + f32 fog_start = t_start * t_start * fog_density; + f32 fog_end = t_end * t_end * fog_density; + if (fog_start > 1.0f) fog_start = 1.0f; + if (fog_end > 1.0f) fog_end = 1.0f; + l_start *= (1.0f - fog_start); + l_end *= (1.0f - fog_end); + } + if (l_start > 255.0f) l_start = 255.0f; if (l_end > 255.0f) l_end = 255.0f; @@ -727,7 +746,7 @@ static void rasterize_triangle_opaque( if (dither) { light = pxl8_dither_light(light, (u32)px, (u32)y); } - u8 pal_idx = cpu->colormap ? pxl8_colormap_lookup(cpu->colormap, tex_idx, light) : tex_idx; + u8 pal_idx = cpu->colormap ? pxl8_colormap_lookup(cpu->colormap, tex_idx, PXL8_LIGHT_WHITE, light) : tex_idx; prow[px] = pal_idx; zrow[px] = z16; if (light_accum) { @@ -948,6 +967,22 @@ static void rasterize_triangle_alpha( f32 v_end = (vw + dvw * steps) * pw_end; f32 l_start = lw * pw_start; f32 l_end = (lw + d_lw * steps) * pw_end; + + f32 fog_density = cpu->frame.uniforms.fog_density; + if (fog_density > 0.0f) { + f32 z_end_fog = z + dz * steps; + f32 t_start = (z + 1.0f) * 0.5f; + f32 t_end = (z_end_fog + 1.0f) * 0.5f; + if (t_start < 0.0f) t_start = 0.0f; + if (t_end < 0.0f) t_end = 0.0f; + f32 fog_start = t_start * t_start * fog_density; + f32 fog_end = t_end * t_end * fog_density; + if (fog_start > 1.0f) fog_start = 1.0f; + if (fog_end > 1.0f) fog_end = 1.0f; + l_start *= (1.0f - fog_start); + l_end *= (1.0f - fog_end); + } + if (l_start > 255.0f) l_start = 255.0f; if (l_end > 255.0f) l_end = 255.0f; @@ -974,7 +1009,7 @@ static void rasterize_triangle_alpha( if (dither) { light = pxl8_dither_light(light, (u32)px, (u32)y); } - u8 src_idx = cpu->colormap ? pxl8_colormap_lookup(cpu->colormap, tex_idx, light) : tex_idx; + u8 src_idx = cpu->colormap ? pxl8_colormap_lookup(cpu->colormap, tex_idx, PXL8_LIGHT_WHITE, light) : tex_idx; if (mat_alpha >= 128) { prow[px] = src_idx; @@ -1002,11 +1037,42 @@ static void rasterize_triangle_alpha( } } +static void rasterize_triangle_wireframe( + pxl8_cpu_backend* cpu, + const vertex_output* vo0, const vertex_output* vo1, const vertex_output* vo2, + u8 color, bool double_sided +) { + pxl8_cpu_render_target* render_target = cpu->current_target; + f32 hw = (f32)render_target->width * 0.5f; + f32 hh = (f32)render_target->height * 0.5f; + + i32 x0 = (i32)(hw + vo0->clip_pos.x / vo0->clip_pos.w * hw); + i32 y0 = (i32)(hh - vo0->clip_pos.y / vo0->clip_pos.w * hh); + i32 x1 = (i32)(hw + vo1->clip_pos.x / vo1->clip_pos.w * hw); + i32 y1 = (i32)(hh - vo1->clip_pos.y / vo1->clip_pos.w * hh); + i32 x2 = (i32)(hw + vo2->clip_pos.x / vo2->clip_pos.w * hw); + i32 y2 = (i32)(hh - vo2->clip_pos.y / vo2->clip_pos.w * hh); + + if (!double_sided) { + i32 cross = (x1 - x0) * (y2 - y0) - (y1 - y0) * (x2 - x0); + if (cross >= 0) return; + } + + pxl8_cpu_draw_line_2d(cpu, x0, y0, x1, y1, color); + pxl8_cpu_draw_line_2d(cpu, x1, y1, x2, y2, color); + pxl8_cpu_draw_line_2d(cpu, x2, y2, x0, y0, color); +} + static void dispatch_triangle( pxl8_cpu_backend* cpu, const vertex_output* vo0, const vertex_output* vo1, const vertex_output* vo2, - const pxl8_atlas* textures, const pxl8_material* material + const pxl8_atlas* textures, const pxl8_gfx_material* material ) { + if (material->wireframe) { + rasterize_triangle_wireframe(cpu, vo0, vo1, vo2, 15, material->double_sided); + return; + } + pxl8_cpu_render_target* render_target = cpu->current_target; tri_setup setup; if (!setup_triangle(&setup, vo0, vo1, vo2, render_target->width, render_target->height, material->double_sided)) { @@ -1029,13 +1095,13 @@ void pxl8_cpu_draw_mesh( pxl8_cpu_backend* cpu, const pxl8_mesh* mesh, const pxl8_mat4* model, - const pxl8_material* material, + const pxl8_gfx_material* material, const pxl8_atlas* textures ) { if (!cpu || !mesh || !model || !material || mesh->index_count < 3 || !cpu->current_target) return; - pxl8_mat4 mv = pxl8_mat4_mul(cpu->frame.view, *model); - pxl8_mat4 mvp = pxl8_mat4_mul(cpu->frame.projection, mv); + pxl8_mat4 mv = pxl8_mat4_multiply(cpu->frame.view, *model); + pxl8_mat4 mvp = pxl8_mat4_multiply(cpu->frame.projection, mv); f32 near = cpu->frame.near_clip > 0.0f ? cpu->frame.near_clip : 0.1f; @@ -1054,13 +1120,13 @@ void pxl8_cpu_draw_mesh( pxl8_vec4 p1 = {v1->position.x, v1->position.y, v1->position.z, 1.0f}; pxl8_vec4 p2 = {v2->position.x, v2->position.y, v2->position.z, 1.0f}; - vo0.clip_pos = pxl8_mat4_mul_vec4(mvp, p0); - vo1.clip_pos = pxl8_mat4_mul_vec4(mvp, p1); - vo2.clip_pos = pxl8_mat4_mul_vec4(mvp, p2); + vo0.clip_pos = pxl8_mat4_multiply_vec4(mvp, p0); + vo1.clip_pos = pxl8_mat4_multiply_vec4(mvp, p1); + vo2.clip_pos = pxl8_mat4_multiply_vec4(mvp, p2); - pxl8_vec4 w0 = pxl8_mat4_mul_vec4(*model, p0); - pxl8_vec4 w1 = pxl8_mat4_mul_vec4(*model, p1); - pxl8_vec4 w2 = pxl8_mat4_mul_vec4(*model, p2); + pxl8_vec4 w0 = pxl8_mat4_multiply_vec4(*model, p0); + pxl8_vec4 w1 = pxl8_mat4_multiply_vec4(*model, p1); + pxl8_vec4 w2 = pxl8_mat4_multiply_vec4(*model, p2); vo0.world_pos = (pxl8_vec3){w0.x, w0.y, w0.z}; vo1.world_pos = (pxl8_vec3){w1.x, w1.y, w1.z}; vo2.world_pos = (pxl8_vec3){w2.x, w2.y, w2.z}; @@ -1078,9 +1144,9 @@ void pxl8_cpu_draw_mesh( vo2.color = v2->color; if (material->dynamic_lighting) { - pxl8_vec3 n0 = pxl8_vec3_normalize(pxl8_mat4_mul_vec3(*model, v0->normal)); - pxl8_vec3 n1 = pxl8_vec3_normalize(pxl8_mat4_mul_vec3(*model, v1->normal)); - pxl8_vec3 n2 = pxl8_vec3_normalize(pxl8_mat4_mul_vec3(*model, v2->normal)); + pxl8_vec3 n0 = pxl8_vec3_normalize(pxl8_mat4_multiply_vec3(*model, v0->normal)); + pxl8_vec3 n1 = pxl8_vec3_normalize(pxl8_mat4_multiply_vec3(*model, v1->normal)); + pxl8_vec3 n2 = pxl8_vec3_normalize(pxl8_mat4_multiply_vec3(*model, v2->normal)); pxl8_light_result lr0 = calc_vertex_light(vo0.world_pos, n0, &cpu->frame); pxl8_light_result lr1 = calc_vertex_light(vo1.world_pos, n1, &cpu->frame); @@ -1111,44 +1177,6 @@ void pxl8_cpu_draw_mesh( } } -void pxl8_cpu_draw_mesh_wireframe( - pxl8_cpu_backend* cpu, - const pxl8_mesh* mesh, - pxl8_mat4 model, - u8 color -) { - if (!cpu || !cpu->current_target || !mesh || mesh->index_count < 3) return; - pxl8_cpu_render_target* render_target = cpu->current_target; - - pxl8_mat4 mvp = pxl8_mat4_mul(cpu->frame.projection, pxl8_mat4_mul(cpu->frame.view, model)); - - for (u32 i = 0; i < mesh->index_count; i += 3) { - const pxl8_vertex* v0 = &mesh->vertices[mesh->indices[i]]; - const pxl8_vertex* v1 = &mesh->vertices[mesh->indices[i + 1]]; - const pxl8_vertex* v2 = &mesh->vertices[mesh->indices[i + 2]]; - - pxl8_vec4 c0 = pxl8_mat4_mul_vec4(mvp, (pxl8_vec4){v0->position.x, v0->position.y, v0->position.z, 1.0f}); - pxl8_vec4 c1 = pxl8_mat4_mul_vec4(mvp, (pxl8_vec4){v1->position.x, v1->position.y, v1->position.z, 1.0f}); - pxl8_vec4 c2 = pxl8_mat4_mul_vec4(mvp, (pxl8_vec4){v2->position.x, v2->position.y, v2->position.z, 1.0f}); - - if (c0.w <= 0.0f || c1.w <= 0.0f || c2.w <= 0.0f) continue; - - f32 hw = (f32)render_target->width * 0.5f; - f32 hh = (f32)render_target->height * 0.5f; - - i32 x0 = (i32)(hw + c0.x / c0.w * hw); - i32 y0 = (i32)(hh - c0.y / c0.w * hh); - i32 x1 = (i32)(hw + c1.x / c1.w * hw); - i32 y1 = (i32)(hh - c1.y / c1.w * hh); - i32 x2 = (i32)(hw + c2.x / c2.w * hw); - i32 y2 = (i32)(hh - c2.y / c2.w * hh); - - pxl8_cpu_draw_line_2d(cpu, x0, y0, x1, y1, color); - pxl8_cpu_draw_line_2d(cpu, x1, y1, x2, y2, color); - pxl8_cpu_draw_line_2d(cpu, x2, y2, x0, y0, color); - } -} - u8* pxl8_cpu_get_framebuffer(pxl8_cpu_backend* cpu) { if (!cpu || cpu->target_stack_depth == 0) return NULL; return cpu->target_stack[0]->framebuffer; @@ -1167,33 +1195,33 @@ u32 pxl8_cpu_get_width(const pxl8_cpu_backend* cpu) { pxl8_cpu_render_target* pxl8_cpu_create_render_target(const pxl8_cpu_render_target_desc* desc) { if (!desc) return NULL; - pxl8_cpu_render_target* target = calloc(1, sizeof(pxl8_cpu_render_target)); + pxl8_cpu_render_target* target = pxl8_calloc(1, sizeof(pxl8_cpu_render_target)); if (!target) return NULL; u32 size = desc->width * desc->height; target->width = desc->width; target->height = desc->height; - target->framebuffer = calloc(size, sizeof(u8)); + target->framebuffer = pxl8_calloc(size, sizeof(u8)); if (!target->framebuffer) { - free(target); + pxl8_free(target); return NULL; } if (desc->with_depth) { - target->zbuffer = calloc(size, sizeof(u16)); + target->zbuffer = pxl8_calloc(size, sizeof(u16)); if (!target->zbuffer) { - free(target->framebuffer); - free(target); + pxl8_free(target->framebuffer); + pxl8_free(target); return NULL; } } if (desc->with_lighting) { - target->light_accum = calloc(size, sizeof(u32)); + target->light_accum = pxl8_calloc(size, sizeof(u32)); if (!target->light_accum) { - free(target->zbuffer); - free(target->framebuffer); - free(target); + pxl8_free(target->zbuffer); + pxl8_free(target->framebuffer); + pxl8_free(target); return NULL; } } @@ -1203,10 +1231,10 @@ pxl8_cpu_render_target* pxl8_cpu_create_render_target(const pxl8_cpu_render_targ void pxl8_cpu_destroy_render_target(pxl8_cpu_render_target* target) { if (!target) return; - free(target->light_accum); - free(target->zbuffer); - free(target->framebuffer); - free(target); + pxl8_free(target->light_accum); + pxl8_free(target->zbuffer); + pxl8_free(target->framebuffer); + pxl8_free(target); } pxl8_cpu_render_target* pxl8_cpu_get_target(pxl8_cpu_backend* cpu) { @@ -1237,10 +1265,12 @@ void pxl8_cpu_blit(pxl8_cpu_backend* cpu, pxl8_cpu_render_target* src, i32 x, i3 for (i32 row = 0; row < copy_h; row++) { u8* src_row = src->framebuffer + (src_y0 + row) * src->width + src_x0; u8* dst_row = dst->framebuffer + (dst_y0 + row) * dst->width + dst_x0; + u32* light_row = dst->light_accum ? dst->light_accum + (dst_y0 + row) * dst->width + dst_x0 : NULL; for (i32 col = 0; col < copy_w; col++) { u8 pixel = src_row[col]; if (pixel != transparent_idx) { dst_row[col] = pixel; + if (light_row) light_row[col] = 0; } } } @@ -1300,13 +1330,9 @@ u32* pxl8_cpu_get_output(pxl8_cpu_backend* cpu) { void pxl8_cpu_render_glows( pxl8_cpu_backend* cpu, - const pxl8_glow_source* glows, - u32 glow_count, - const pxl8_additive_table* additive, - const pxl8_palette_cube* palette_cube, - const pxl8_overbright_table* overbright + const pxl8_glow* glows, + u32 glow_count ) { - (void)overbright; if (!cpu || cpu->target_stack_depth == 0) return; pxl8_cpu_render_target* target = cpu->target_stack[cpu->target_stack_depth - 1]; @@ -1319,7 +1345,7 @@ void pxl8_cpu_render_glows( u32* light_accum = target->light_accum; for (u32 gi = 0; gi < glow_count; gi++) { - const pxl8_glow_source* glow = &glows[gi]; + const pxl8_glow* glow = &glows[gi]; i32 cx = glow->x; i32 cy = glow->y; i32 radius = glow->radius; @@ -1392,25 +1418,21 @@ void pxl8_cpu_render_glows( u8 int_val = intensity < 1.0f ? (u8)(intensity * 255.0f) : 255; u8 light_level = pxl8_ordered_dither(int_val, (u32)x, (u32)y); - // Skip very dark pixels to create stippled transparency effect if (light_level < 8) continue; - u8 shaded = pxl8_colormap_lookup(cpu->colormap, base_color, light_level); + u8 shaded = pxl8_colormap_lookup(cpu->colormap, base_color, PXL8_LIGHT_WHITE, light_level); - if (intensity > 1.0f && palette_cube) { - f32 over = intensity - 1.0f; - if (over > 1.0f) over = 1.0f; - u8 r, g, b; - pxl8_palette_cube_get_rgb(palette_cube, shaded, &r, &g, &b); - u8 or = (u8)(r + (255 - r) * over); - u8 og = (u8)(g + (255 - g) * over); - u8 ob = (u8)(b + (255 - b) * over); - shaded = pxl8_palette_cube_lookup_stable(palette_cube, or, og, ob); - } - - u8 dst = pixels[idx]; - if (additive) { - pixels[idx] = pxl8_additive_blend(additive, shaded, dst); + if (cpu->palette_cube) { + u8 sr, sg, sb, dr, dg, db; + pxl8_palette_cube_get_rgb(cpu->palette_cube, shaded, &sr, &sg, &sb); + pxl8_palette_cube_get_rgb(cpu->palette_cube, pixels[idx], &dr, &dg, &db); + u32 r = (u32)sr + (u32)dr; + u32 g = (u32)sg + (u32)dg; + u32 b = (u32)sb + (u32)db; + if (r > 255) r = 255; + if (g > 255) g = 255; + if (b > 255) b = 255; + pixels[idx] = pxl8_palette_cube_lookup(cpu->palette_cube, (u8)r, (u8)g, (u8)b); } else { pixels[idx] = shaded; } diff --git a/src/gfx/pxl8_cpu.h b/src/gfx/pxl8_cpu.h index 0f4ab5b..bfde3f1 100644 --- a/src/gfx/pxl8_cpu.h +++ b/src/gfx/pxl8_cpu.h @@ -1,12 +1,13 @@ #pragma once #include "pxl8_atlas.h" -#include "pxl8_blend.h" #include "pxl8_colormap.h" #include "pxl8_gfx.h" #include "pxl8_gfx3d.h" +#include "pxl8_lightmap.h" #include "pxl8_math.h" #include "pxl8_mesh.h" +#include "pxl8_palette.h" #include "pxl8_types.h" #ifdef __cplusplus @@ -34,6 +35,10 @@ void pxl8_cpu_clear_depth(pxl8_cpu_backend* cpu); void pxl8_cpu_set_colormap(pxl8_cpu_backend* cpu, const pxl8_colormap* cm); void pxl8_cpu_set_palette(pxl8_cpu_backend* cpu, const u32* palette); +void pxl8_cpu_set_palette_cube(pxl8_cpu_backend* cpu, const pxl8_palette_cube* cube); + +u32 pxl8_cpu_add_lightmap(pxl8_cpu_backend* cpu, pxl8_lightmap* lm); +pxl8_lightmap* pxl8_cpu_get_lightmap(pxl8_cpu_backend* cpu, u32 id); void pxl8_cpu_draw_pixel(pxl8_cpu_backend* cpu, i32 x, i32 y, u8 color); u8 pxl8_cpu_get_pixel(pxl8_cpu_backend* cpu, i32 x, i32 y); @@ -48,17 +53,10 @@ void pxl8_cpu_draw_mesh( pxl8_cpu_backend* cpu, const pxl8_mesh* mesh, const pxl8_mat4* model, - const pxl8_material* material, + const pxl8_gfx_material* material, const pxl8_atlas* textures ); -void pxl8_cpu_draw_mesh_wireframe( - pxl8_cpu_backend* cpu, - const pxl8_mesh* mesh, - pxl8_mat4 model, - u8 color -); - u8* pxl8_cpu_get_framebuffer(pxl8_cpu_backend* cpu); u32* pxl8_cpu_get_output(pxl8_cpu_backend* cpu); u32 pxl8_cpu_get_height(const pxl8_cpu_backend* cpu); @@ -66,11 +64,8 @@ u32 pxl8_cpu_get_width(const pxl8_cpu_backend* cpu); void pxl8_cpu_render_glows( pxl8_cpu_backend* cpu, - const pxl8_glow_source* glows, - u32 glow_count, - const pxl8_additive_table* additive, - const pxl8_palette_cube* palette_cube, - const pxl8_overbright_table* overbright + const pxl8_glow* glows, + u32 glow_count ); void pxl8_cpu_resolve(pxl8_cpu_backend* cpu); diff --git a/src/gfx/pxl8_font.c b/src/gfx/pxl8_font.c index 445ec67..3d8ad7b 100644 --- a/src/gfx/pxl8_font.c +++ b/src/gfx/pxl8_font.c @@ -1,4 +1,5 @@ #include "pxl8_font.h" +#include "pxl8_mem.h" #include #include @@ -15,7 +16,7 @@ pxl8_result pxl8_font_create_atlas(const pxl8_font* font, u8** atlas_data, i32* *atlas_height = rows_needed * font->default_height; i32 atlas_size = (*atlas_width) * (*atlas_height); - *atlas_data = (u8*)malloc(atlas_size); + *atlas_data = (u8*)pxl8_malloc(atlas_size); if (!*atlas_data) { return PXL8_ERROR_OUT_OF_MEMORY; } diff --git a/src/gfx/pxl8_gfx.c b/src/gfx/pxl8_gfx.c index a0f42e8..00e2826 100644 --- a/src/gfx/pxl8_gfx.c +++ b/src/gfx/pxl8_gfx.c @@ -6,7 +6,6 @@ #include "pxl8_ase.h" #include "pxl8_atlas.h" #include "pxl8_backend.h" -#include "pxl8_blend.h" #include "pxl8_blit.h" #include "pxl8_color.h" #include "pxl8_colormap.h" @@ -15,6 +14,7 @@ #include "pxl8_log.h" #include "pxl8_macros.h" #include "pxl8_math.h" +#include "pxl8_mem.h" #include "pxl8_sys.h" #include "pxl8_types.h" @@ -25,7 +25,6 @@ typedef struct pxl8_sprite_cache_entry { } pxl8_sprite_cache_entry; struct pxl8_gfx { - pxl8_additive_table* additive_table; pxl8_atlas* atlas; pxl8_gfx_backend backend; pxl8_colormap* colormap; @@ -35,7 +34,6 @@ struct pxl8_gfx { pxl8_frustum frustum; const pxl8_hal* hal; bool initialized; - pxl8_overbright_table* overbright_table; pxl8_palette* palette; pxl8_palette_cube* palette_cube; pxl8_pixel_mode pixel_mode; @@ -44,6 +42,7 @@ struct pxl8_gfx { u32 sprite_cache_capacity; u32 sprite_cache_count; pxl8_viewport viewport; + pxl8_mat4 view_proj; }; pxl8_bounds pxl8_gfx_get_bounds(pxl8_gfx* gfx) { @@ -78,10 +77,14 @@ i32 pxl8_gfx_get_width(const pxl8_gfx* gfx) { return gfx ? gfx->framebuffer_width : 0; } -pxl8_palette* pxl8_gfx_get_palette(pxl8_gfx* gfx) { +pxl8_palette* pxl8_gfx_palette(pxl8_gfx* gfx) { return gfx ? gfx->palette : NULL; } +pxl8_colormap* pxl8_gfx_colormap(pxl8_gfx* gfx) { + return gfx ? gfx->colormap : NULL; +} + u8 pxl8_gfx_find_color(pxl8_gfx* gfx, u32 color) { if (!gfx || !gfx->palette) return 0; if (color <= 0xFFFFFF) color = (color << 8) | 0xFF; @@ -91,37 +94,24 @@ u8 pxl8_gfx_find_color(pxl8_gfx* gfx, u32 color) { return pxl8_palette_find_closest(gfx->palette, r, g, b); } -void pxl8_gfx_set_palette(pxl8_gfx* gfx, pxl8_palette* pal) { - if (!gfx) return; - if (gfx->palette) { - pxl8_palette_destroy(gfx->palette); - } - gfx->palette = pal; - - if (gfx->palette && gfx->pixel_mode != PXL8_PIXEL_HICOLOR) { - u32* colors = pxl8_palette_colors(gfx->palette); - if (gfx->colormap) { - pxl8_colormap_generate(gfx->colormap, colors, NULL); - } - if (gfx->backend.type == PXL8_GFX_BACKEND_CPU) { - pxl8_cpu_set_palette(gfx->backend.cpu, colors); - } +void pxl8_gfx_set_palette_colors(pxl8_gfx* gfx, const u32* colors, u16 count) { + if (!gfx || !gfx->palette || !colors) return; + pxl8_set_palette(gfx->palette, colors, count); + if (gfx->pixel_mode != PXL8_PIXEL_HICOLOR && gfx->backend.type == PXL8_GFX_BACKEND_CPU) { + pxl8_cpu_set_palette(gfx->backend.cpu, pxl8_palette_colors(gfx->palette)); } } i32 pxl8_gfx_load_palette(pxl8_gfx* gfx, const char* filepath) { - if (!gfx || !filepath) return -1; - pxl8_palette* pal = gfx->palette; - if (!pal) return -1; - pxl8_result result = pxl8_palette_load_ase(pal, filepath); + if (!gfx || !gfx->palette || !filepath) return -1; + pxl8_result result = pxl8_palette_load_ase(gfx->palette, filepath); if (result != PXL8_OK) return (i32)result; if (gfx->pixel_mode != PXL8_PIXEL_HICOLOR) { - u32* colors = pxl8_palette_colors(pal); if (gfx->colormap) { - pxl8_colormap_generate(gfx->colormap, colors, NULL); + pxl8_colormap_generate(gfx->colormap, pxl8_palette_colors(gfx->palette)); } if (gfx->backend.type == PXL8_GFX_BACKEND_CPU) { - pxl8_cpu_set_palette(gfx->backend.cpu, colors); + pxl8_cpu_set_palette(gfx->backend.cpu, pxl8_palette_colors(gfx->palette)); } } return 0; @@ -133,7 +123,7 @@ pxl8_gfx* pxl8_gfx_create( pxl8_pixel_mode mode, pxl8_resolution resolution ) { - pxl8_gfx* gfx = (pxl8_gfx*)calloc(1, sizeof(pxl8_gfx)); + pxl8_gfx* gfx = (pxl8_gfx*)pxl8_calloc(1, sizeof(pxl8_gfx)); if (!gfx) { pxl8_error("Failed to allocate graphics context"); return NULL; @@ -149,7 +139,7 @@ pxl8_gfx* pxl8_gfx_create( if (!gfx->platform_data) { pxl8_error("Platform data cannot be NULL"); - free(gfx); + pxl8_free(gfx); return NULL; } @@ -168,7 +158,7 @@ pxl8_gfx* pxl8_gfx_create( gfx->framebuffer = pxl8_cpu_get_framebuffer(gfx->backend.cpu); if (mode != PXL8_PIXEL_HICOLOR) { - gfx->colormap = calloc(1, sizeof(pxl8_colormap)); + gfx->colormap = pxl8_calloc(1, sizeof(pxl8_colormap)); if (gfx->colormap) { pxl8_cpu_set_colormap(gfx->backend.cpu, gfx->colormap); } @@ -187,18 +177,16 @@ pxl8_gfx* pxl8_gfx_create( void pxl8_gfx_destroy(pxl8_gfx* gfx) { if (!gfx) return; - pxl8_additive_table_destroy(gfx->additive_table); pxl8_atlas_destroy(gfx->atlas); if (gfx->backend.type == PXL8_GFX_BACKEND_CPU) { pxl8_cpu_destroy(gfx->backend.cpu); } - free(gfx->colormap); - pxl8_overbright_table_destroy(gfx->overbright_table); + pxl8_free(gfx->colormap); pxl8_palette_cube_destroy(gfx->palette_cube); pxl8_palette_destroy(gfx->palette); - free(gfx->sprite_cache); + pxl8_free(gfx->sprite_cache); - free(gfx); + pxl8_free(gfx); } static pxl8_result pxl8_gfx_ensure_atlas(pxl8_gfx* gfx) { @@ -239,7 +227,7 @@ pxl8_result pxl8_gfx_load_sprite(pxl8_gfx* gfx, const char* path) { if (!gfx->sprite_cache) { gfx->sprite_cache_capacity = PXL8_DEFAULT_SPRITE_CACHE_CAPACITY; - gfx->sprite_cache = (pxl8_sprite_cache_entry*)calloc( + gfx->sprite_cache = (pxl8_sprite_cache_entry*)pxl8_calloc( gfx->sprite_cache_capacity, sizeof(pxl8_sprite_cache_entry) ); if (!gfx->sprite_cache) return PXL8_ERROR_OUT_OF_MEMORY; @@ -284,7 +272,7 @@ pxl8_result pxl8_gfx_load_sprite(pxl8_gfx* gfx, const char* path) { if (gfx->sprite_cache_count >= gfx->sprite_cache_capacity) { u32 new_capacity = gfx->sprite_cache_capacity * 2; - pxl8_sprite_cache_entry* new_cache = (pxl8_sprite_cache_entry*)realloc( + pxl8_sprite_cache_entry* new_cache = (pxl8_sprite_cache_entry*)pxl8_realloc( gfx->sprite_cache, new_capacity * sizeof(pxl8_sprite_cache_entry) ); @@ -523,6 +511,7 @@ void pxl8_2d_sprite(pxl8_gfx* gfx, u32 sprite_id, i32 x, i32 y, i32 w, i32 h, bo if (!gfx || !gfx->atlas) return; u8* framebuffer = NULL; + u32* light_accum = NULL; i32 fb_width = 0; i32 fb_height = 0; @@ -531,6 +520,7 @@ void pxl8_2d_sprite(pxl8_gfx* gfx, u32 sprite_id, i32 x, i32 y, i32 w, i32 h, bo pxl8_cpu_render_target* render_target = pxl8_cpu_get_target(gfx->backend.cpu); if (!render_target) return; framebuffer = pxl8_cpu_render_target_get_framebuffer(render_target); + light_accum = pxl8_cpu_render_target_get_light_accum(render_target); fb_width = (i32)pxl8_cpu_render_target_get_width(render_target); fb_height = (i32)pxl8_cpu_render_target_get_height(render_target); break; @@ -567,6 +557,11 @@ void pxl8_2d_sprite(pxl8_gfx* gfx, u32 sprite_id, i32 x, i32 y, i32 w, i32 h, bo if (is_1to1_scale && is_unclipped && !is_flipped) { const u8* sprite_data = atlas_pixels + entry->y * atlas_width + entry->x; pxl8_blit_indexed(framebuffer, fb_width, sprite_data, atlas_width, x, y, w, h); + if (light_accum) { + for (i32 py = 0; py < h; py++) { + memset(light_accum + (y + py) * fb_width + x, 0, w * sizeof(u32)); + } + } } else { for (i32 py = 0; py < draw_height; py++) { for (i32 px = 0; px < draw_width; px++) { @@ -580,6 +575,7 @@ void pxl8_2d_sprite(pxl8_gfx* gfx, u32 sprite_id, i32 x, i32 y, i32 w, i32 h, bo i32 dest_idx = (dest_y + py) * fb_width + (dest_x + px); framebuffer[dest_idx] = pxl8_blend_indexed(atlas_pixels[src_idx], framebuffer[dest_idx]); + if (light_accum) light_accum[dest_idx] = 0; } } } @@ -612,13 +608,17 @@ pxl8_3d_frame pxl8_3d_frame_from_camera(const pxl8_3d_camera* camera, const pxl8 return frame; } -void pxl8_3d_begin_frame(pxl8_gfx* gfx, const pxl8_3d_camera* camera, const pxl8_3d_uniforms* uniforms) { +void pxl8_3d_begin_frame(pxl8_gfx* gfx, const pxl8_3d_camera* camera, const pxl8_lights* lights, const pxl8_3d_uniforms* uniforms) { if (!gfx || !camera) return; pxl8_3d_frame frame = pxl8_3d_frame_from_camera(camera, uniforms); + frame.lights = lights ? pxl8_lights_data(lights) : NULL; + frame.lights_count = lights ? pxl8_lights_count(lights) : 0; + + pxl8_mat4 vp = pxl8_mat4_multiply(frame.projection, frame.view); - pxl8_mat4 vp = pxl8_mat4_mul(frame.projection, frame.view); gfx->frustum = pxl8_frustum_from_matrix(vp); + gfx->view_proj = vp; switch (gfx->backend.type) { case PXL8_GFX_BACKEND_CPU: @@ -634,6 +634,38 @@ const pxl8_frustum* pxl8_3d_get_frustum(pxl8_gfx* gfx) { return &gfx->frustum; } +const pxl8_mat4* pxl8_3d_get_view_proj(pxl8_gfx* gfx) { + if (!gfx) return NULL; + return &gfx->view_proj; +} + +u32 pxl8_3d_project_points(pxl8_gfx* gfx, const pxl8_vec3* in, pxl8_vec3* out, u32 count, const pxl8_mat4* transform) { + if (!gfx || !in || !out) return 0; + + pxl8_mat4 mvp = transform ? pxl8_mat4_multiply(gfx->view_proj, *transform) : gfx->view_proj; + + f32 hw = (f32)gfx->framebuffer_width * 0.5f; + f32 hh = (f32)gfx->framebuffer_height * 0.5f; + u32 visible = 0; + + for (u32 i = 0; i < count; i++) { + pxl8_vec4 clip = pxl8_mat4_multiply_vec4(mvp, (pxl8_vec4){in[i].x, in[i].y, in[i].z, 1.0f}); + + if (clip.w <= 0.0f) { + out[i].z = -1.0f; + continue; + } + + f32 inv_w = 1.0f / clip.w; + out[i].x = hw + clip.x * inv_w * hw; + out[i].y = hh - clip.y * inv_w * hh; + out[i].z = clip.w; + visible++; + } + + return visible; +} + void pxl8_3d_clear(pxl8_gfx* gfx, u8 color) { if (!gfx) return; switch (gfx->backend.type) { @@ -667,7 +699,7 @@ void pxl8_3d_draw_line(pxl8_gfx* gfx, pxl8_vec3 v0, pxl8_vec3 v1, u8 color) { } } -void pxl8_3d_draw_mesh(pxl8_gfx* gfx, const pxl8_mesh* mesh, const pxl8_mat4* model, const pxl8_material* material) { +void pxl8_3d_draw_mesh(pxl8_gfx* gfx, const pxl8_mesh* mesh, const pxl8_mat4* model, const pxl8_gfx_material* material) { if (!gfx || !mesh || !model || !material) return; switch (gfx->backend.type) { case PXL8_GFX_BACKEND_CPU: @@ -678,17 +710,6 @@ void pxl8_3d_draw_mesh(pxl8_gfx* gfx, const pxl8_mesh* mesh, const pxl8_mat4* mo } } -void pxl8_3d_draw_mesh_wireframe(pxl8_gfx* gfx, const pxl8_mesh* mesh, pxl8_mat4 model, u8 color) { - if (!gfx || !mesh) return; - switch (gfx->backend.type) { - case PXL8_GFX_BACKEND_CPU: - pxl8_cpu_draw_mesh_wireframe(gfx->backend.cpu, mesh, model, color); - break; - case PXL8_GFX_BACKEND_GPU: - break; - } -} - void pxl8_3d_end_frame(pxl8_gfx* gfx) { if (!gfx) return; switch (gfx->backend.type) { @@ -733,31 +754,27 @@ void pxl8_gfx_pop_target(pxl8_gfx* gfx) { } } -static void pxl8_gfx_ensure_blend_tables(pxl8_gfx* gfx) { +void pxl8_gfx_ensure_blend_tables(pxl8_gfx* gfx) { if (!gfx || !gfx->palette) return; - if (!gfx->additive_table) { - gfx->additive_table = pxl8_additive_table_create(gfx->palette); - } - if (!gfx->overbright_table) { - gfx->overbright_table = pxl8_overbright_table_create(gfx->palette); - } if (!gfx->palette_cube) { gfx->palette_cube = pxl8_palette_cube_create(gfx->palette); + if (gfx->backend.cpu) { + pxl8_cpu_set_palette_cube(gfx->backend.cpu, gfx->palette_cube); + } } } void pxl8_gfx_blend_tables_update(pxl8_gfx* gfx) { if (!gfx || !gfx->palette) return; - if (gfx->additive_table) { - pxl8_additive_table_rebuild(gfx->additive_table, gfx->palette); - } - if (gfx->overbright_table) { - pxl8_overbright_table_rebuild(gfx->overbright_table, gfx->palette); - } + pxl8_gfx_ensure_blend_tables(gfx); + if (gfx->palette_cube) { pxl8_palette_cube_rebuild(gfx->palette_cube, gfx->palette); + if (gfx->backend.cpu) { + pxl8_cpu_set_palette_cube(gfx->backend.cpu, gfx->palette_cube); + } } } @@ -765,29 +782,33 @@ void pxl8_gfx_colormap_update(pxl8_gfx* gfx) { if (!gfx || !gfx->palette || !gfx->colormap) return; u32* colors = pxl8_palette_colors(gfx->palette); if (colors) { - pxl8_colormap_generate(gfx->colormap, colors, NULL); + pxl8_colormap_generate(gfx->colormap, colors); } } +u8 pxl8_gfx_find_closest_color(pxl8_gfx* gfx, u8 r, u8 g, u8 b) { + if (!gfx || !gfx->palette) return 0; + return pxl8_palette_find_closest(gfx->palette, r, g, b); +} + +u8 pxl8_gfx_ui_color(pxl8_gfx* gfx, u8 index) { + if (!gfx || !gfx->palette || index >= PXL8_UI_PALETTE_SIZE) return 0; + u32 abgr = pxl8_ui_palette[index]; + u8 r = (abgr >> 0) & 0xFF; + u8 g = (abgr >> 8) & 0xFF; + u8 b = (abgr >> 16) & 0xFF; + return pxl8_palette_find_closest(gfx->palette, r, g, b); +} + void pxl8_gfx_apply_effect(pxl8_gfx* gfx, pxl8_gfx_effect effect, const void* params, u32 count) { if (!gfx || !params || count == 0) return; switch (effect) { case PXL8_GFX_EFFECT_GLOWS: { - pxl8_gfx_ensure_blend_tables(gfx); - if (!gfx->additive_table || !gfx->overbright_table || !gfx->palette_cube) return; - - const pxl8_glow_source* glows = (const pxl8_glow_source*)params; + const pxl8_glow* glows = (const pxl8_glow*)params; switch (gfx->backend.type) { case PXL8_GFX_BACKEND_CPU: - pxl8_cpu_render_glows( - gfx->backend.cpu, - glows, - count, - gfx->additive_table, - gfx->palette_cube, - gfx->overbright_table - ); + pxl8_cpu_render_glows(gfx->backend.cpu, glows, count); break; case PXL8_GFX_BACKEND_GPU: break; diff --git a/src/gfx/pxl8_gfx.h b/src/gfx/pxl8_gfx.h index 11fb2e4..ec03ed4 100644 --- a/src/gfx/pxl8_gfx.h +++ b/src/gfx/pxl8_gfx.h @@ -2,9 +2,12 @@ #include "pxl8_gfx2d.h" #include "pxl8_gfx3d.h" +#include "pxl8_glows.h" #include "pxl8_hal.h" +#include "pxl8_colormap.h" #include "pxl8_palette.h" #include "pxl8_types.h" +#include "pxl8_gui_palette.h" typedef struct pxl8_gfx pxl8_gfx; @@ -12,53 +15,6 @@ typedef enum pxl8_gfx_effect { PXL8_GFX_EFFECT_GLOWS = 0, } pxl8_gfx_effect; -#define PXL8_MAX_GLOWS 256 - -typedef enum pxl8_glow_shape { - PXL8_GLOW_CIRCLE = 0, - PXL8_GLOW_DIAMOND = 1, - PXL8_GLOW_SHAFT = 2, -} pxl8_glow_shape; - -typedef struct pxl8_glow_source { - u8 color; - u16 depth; - u8 height; - u16 intensity; - u8 radius; - pxl8_glow_shape shape; - i16 x; - i16 y; -} pxl8_glow_source; - -static inline pxl8_glow_source pxl8_glow_create(i32 x, i32 y, u8 radius, u16 intensity, u8 color) { - return (pxl8_glow_source){ - .color = color, - .depth = 0xFFFF, - .height = 0, - .intensity = intensity, - .radius = radius, - .shape = PXL8_GLOW_CIRCLE, - .x = (i16)x, - .y = (i16)y, - }; -} - -static inline pxl8_glow_source pxl8_glow_with_depth(pxl8_glow_source g, u16 depth) { - g.depth = depth; - return g; -} - -static inline pxl8_glow_source pxl8_glow_with_shape(pxl8_glow_source g, pxl8_glow_shape shape) { - g.shape = shape; - return g; -} - -static inline pxl8_glow_source pxl8_glow_with_height(pxl8_glow_source g, u8 height) { - g.height = height; - return g; -} - #ifdef __cplusplus extern "C" { #endif @@ -76,13 +32,14 @@ pxl8_bounds pxl8_gfx_get_bounds(pxl8_gfx* gfx); u8* pxl8_gfx_get_framebuffer_indexed(pxl8_gfx* gfx); u16* pxl8_gfx_get_framebuffer_hicolor(pxl8_gfx* gfx); i32 pxl8_gfx_get_height(const pxl8_gfx* gfx); -pxl8_palette* pxl8_gfx_get_palette(pxl8_gfx* gfx); +pxl8_palette* pxl8_gfx_palette(pxl8_gfx* gfx); +pxl8_colormap* pxl8_gfx_colormap(pxl8_gfx* gfx); pxl8_pixel_mode pxl8_gfx_get_pixel_mode(pxl8_gfx* gfx); i32 pxl8_gfx_get_width(const pxl8_gfx* gfx); i32 pxl8_gfx_load_palette(pxl8_gfx* gfx, const char* filepath); void pxl8_gfx_project(pxl8_gfx* gfx, f32 left, f32 right, f32 top, f32 bottom); -void pxl8_gfx_set_palette(pxl8_gfx* gfx, pxl8_palette* pal); +void pxl8_gfx_set_palette_colors(pxl8_gfx* gfx, const u32* colors, u16 count); void pxl8_gfx_set_viewport(pxl8_gfx* gfx, pxl8_viewport vp); pxl8_viewport pxl8_gfx_viewport(pxl8_bounds bounds, i32 width, i32 height); @@ -97,6 +54,10 @@ void pxl8_gfx_pop_target(pxl8_gfx* gfx); void pxl8_gfx_apply_effect(pxl8_gfx* gfx, pxl8_gfx_effect effect, const void* params, u32 count); void pxl8_gfx_blend_tables_update(pxl8_gfx* gfx); void pxl8_gfx_colormap_update(pxl8_gfx* gfx); +void pxl8_gfx_ensure_blend_tables(pxl8_gfx* gfx); + +u8 pxl8_gfx_find_closest_color(pxl8_gfx* gfx, u8 r, u8 g, u8 b); +u8 pxl8_gfx_ui_color(pxl8_gfx* gfx, u8 index); #ifdef __cplusplus } diff --git a/src/gfx/pxl8_gfx3d.h b/src/gfx/pxl8_gfx3d.h index 61c5a12..b5cf0e9 100644 --- a/src/gfx/pxl8_gfx3d.h +++ b/src/gfx/pxl8_gfx3d.h @@ -1,53 +1,31 @@ #pragma once #include "pxl8_3d_camera.h" +#include "pxl8_lights.h" #include "pxl8_math.h" #include "pxl8_mesh.h" #include "pxl8_types.h" typedef struct pxl8_gfx pxl8_gfx; -#define PXL8_MAX_LIGHTS 16 - -typedef struct pxl8_light { - pxl8_vec3 position; - u8 r, g, b; - u8 intensity; - f32 radius; - f32 radius_sq; - f32 inv_radius_sq; -} pxl8_light; - -static inline pxl8_light pxl8_light_create(pxl8_vec3 pos, u8 r, u8 g, u8 b, u8 intensity, f32 radius) { - f32 radius_sq = radius * radius; - return (pxl8_light){ - .position = pos, - .r = r, .g = g, .b = b, - .intensity = intensity, - .radius = radius, - .radius_sq = radius_sq, - .inv_radius_sq = radius_sq > 0.0f ? 1.0f / radius_sq : 0.0f, - }; -} - typedef struct pxl8_3d_uniforms { u8 ambient; pxl8_vec3 celestial_dir; f32 celestial_intensity; u8 fog_color; f32 fog_density; - pxl8_light lights[PXL8_MAX_LIGHTS]; - u32 num_lights; f32 time; } pxl8_3d_uniforms; typedef struct pxl8_3d_frame { - pxl8_3d_uniforms uniforms; pxl8_vec3 camera_dir; pxl8_vec3 camera_pos; f32 far_clip; + const pxl8_light* lights; + u32 lights_count; f32 near_clip; pxl8_mat4 projection; + pxl8_3d_uniforms uniforms; pxl8_mat4 view; } pxl8_3d_frame; @@ -55,15 +33,16 @@ typedef struct pxl8_3d_frame { extern "C" { #endif -void pxl8_3d_begin_frame(pxl8_gfx* gfx, const pxl8_3d_camera* camera, const pxl8_3d_uniforms* uniforms); +void pxl8_3d_begin_frame(pxl8_gfx* gfx, const pxl8_3d_camera* camera, const pxl8_lights* lights, const pxl8_3d_uniforms* uniforms); void pxl8_3d_clear(pxl8_gfx* gfx, u8 color); void pxl8_3d_clear_depth(pxl8_gfx* gfx); void pxl8_3d_draw_line(pxl8_gfx* gfx, pxl8_vec3 v0, pxl8_vec3 v1, u8 color); -void pxl8_3d_draw_mesh(pxl8_gfx* gfx, const pxl8_mesh* mesh, const pxl8_mat4* model, const pxl8_material* material); -void pxl8_3d_draw_mesh_wireframe(pxl8_gfx* gfx, const pxl8_mesh* mesh, pxl8_mat4 model, u8 color); +void pxl8_3d_draw_mesh(pxl8_gfx* gfx, const pxl8_mesh* mesh, const pxl8_mat4* model, const pxl8_gfx_material* material); void pxl8_3d_end_frame(pxl8_gfx* gfx); u8* pxl8_3d_get_framebuffer(pxl8_gfx* gfx); const pxl8_frustum* pxl8_3d_get_frustum(pxl8_gfx* gfx); +const pxl8_mat4* pxl8_3d_get_view_proj(pxl8_gfx* gfx); +u32 pxl8_3d_project_points(pxl8_gfx* gfx, const pxl8_vec3* in, pxl8_vec3* out, u32 count, const pxl8_mat4* transform); pxl8_3d_frame pxl8_3d_frame_from_camera(const pxl8_3d_camera* camera, const pxl8_3d_uniforms* uniforms); diff --git a/src/gfx/pxl8_glows.c b/src/gfx/pxl8_glows.c new file mode 100644 index 0000000..018fea5 --- /dev/null +++ b/src/gfx/pxl8_glows.c @@ -0,0 +1,62 @@ +#include "pxl8_glows.h" + +#include "pxl8_gfx.h" +#include "pxl8_mem.h" + +#include + +struct pxl8_glows { + pxl8_glow* data; + u32 capacity; + u32 count; +}; + +pxl8_glows* pxl8_glows_create(u32 capacity) { + pxl8_glows* glows = pxl8_calloc(1, sizeof(pxl8_glows)); + if (!glows) return NULL; + + glows->data = pxl8_calloc(capacity, sizeof(pxl8_glow)); + if (!glows->data) { + pxl8_free(glows); + return NULL; + } + + glows->capacity = capacity; + glows->count = 0; + + return glows; +} + +void pxl8_glows_destroy(pxl8_glows* glows) { + if (!glows) return; + pxl8_free(glows->data); + pxl8_free(glows); +} + +void pxl8_glows_add(pxl8_glows* glows, i16 x, i16 y, u8 radius, u16 intensity, u8 color, u8 shape) { + if (!glows || glows->count >= glows->capacity) return; + + pxl8_glow* g = &glows->data[glows->count++]; + g->x = x; + g->y = y; + g->radius = radius; + g->intensity = intensity; + g->color = color; + g->shape = shape; + g->depth = 0xFFFF; + g->height = 0; +} + +void pxl8_glows_clear(pxl8_glows* glows) { + if (!glows) return; + glows->count = 0; +} + +u32 pxl8_glows_count(const pxl8_glows* glows) { + return glows ? glows->count : 0; +} + +void pxl8_glows_render(pxl8_glows* glows, pxl8_gfx* gfx) { + if (!glows || !gfx || glows->count == 0) return; + pxl8_gfx_apply_effect(gfx, PXL8_GFX_EFFECT_GLOWS, glows->data, glows->count); +} diff --git a/src/gfx/pxl8_glows.h b/src/gfx/pxl8_glows.h new file mode 100644 index 0000000..5edb1bd --- /dev/null +++ b/src/gfx/pxl8_glows.h @@ -0,0 +1,42 @@ +#pragma once + +#include "pxl8_types.h" + +#define PXL8_GLOWS_MAX 16384 + +typedef enum pxl8_glow_shape { + PXL8_GLOW_CIRCLE = 0, + PXL8_GLOW_DIAMOND = 1, + PXL8_GLOW_SHAFT = 2, +} pxl8_glow_shape; + +typedef struct pxl8_glow { + u8 color; + u16 depth; + u8 height; + u16 intensity; + u8 radius; + pxl8_glow_shape shape; + i16 x; + i16 y; +} pxl8_glow; + +typedef struct pxl8_gfx pxl8_gfx; +typedef struct pxl8_glows pxl8_glows; + +#ifdef __cplusplus +extern "C" { +#endif + +pxl8_glows* pxl8_glows_create(u32 capacity); +void pxl8_glows_destroy(pxl8_glows* glows); + +void pxl8_glows_add(pxl8_glows* glows, i16 x, i16 y, u8 radius, u16 intensity, u8 color, u8 shape); +void pxl8_glows_clear(pxl8_glows* glows); +u32 pxl8_glows_count(const pxl8_glows* glows); +const pxl8_glow* pxl8_glows_data(const pxl8_glows* glows); +void pxl8_glows_render(pxl8_glows* glows, pxl8_gfx* gfx); + +#ifdef __cplusplus +} +#endif diff --git a/src/gfx/pxl8_lightmap.c b/src/gfx/pxl8_lightmap.c new file mode 100644 index 0000000..4a4ccf8 --- /dev/null +++ b/src/gfx/pxl8_lightmap.c @@ -0,0 +1,114 @@ +#include "pxl8_lightmap.h" +#include "pxl8_mem.h" + +#include +#include + +pxl8_lightmap* pxl8_lightmap_create(u32 width, u32 height, u32 scale) { + pxl8_lightmap* lm = pxl8_calloc(1, sizeof(pxl8_lightmap)); + if (!lm) return NULL; + + lm->width = width; + lm->height = height; + lm->scale = scale; + lm->data = pxl8_calloc(width * height * 3, sizeof(u8)); + if (!lm->data) { + pxl8_free(lm); + return NULL; + } + + pxl8_lightmap_clear(lm, PXL8_LIGHTMAP_NEUTRAL, PXL8_LIGHTMAP_NEUTRAL, PXL8_LIGHTMAP_NEUTRAL); + return lm; +} + +void pxl8_lightmap_destroy(pxl8_lightmap* lm) { + if (!lm) return; + pxl8_free(lm->data); + pxl8_free(lm); +} + +void pxl8_lightmap_clear(pxl8_lightmap* lm, u8 r, u8 g, u8 b) { + if (!lm || !lm->data) return; + u32 count = lm->width * lm->height; + for (u32 i = 0; i < count; i++) { + lm->data[i * 3 + 0] = r; + lm->data[i * 3 + 1] = g; + lm->data[i * 3 + 2] = b; + } +} + +void pxl8_lightmap_set(pxl8_lightmap* lm, u32 x, u32 y, u8 r, u8 g, u8 b) { + if (!lm || !lm->data || x >= lm->width || y >= lm->height) return; + u32 idx = (y * lm->width + x) * 3; + lm->data[idx + 0] = r; + lm->data[idx + 1] = g; + lm->data[idx + 2] = b; +} + +void pxl8_lightmap_get(const pxl8_lightmap* lm, u32 x, u32 y, u8* r, u8* g, u8* b) { + if (!lm || !lm->data || x >= lm->width || y >= lm->height) { + *r = *g = *b = PXL8_LIGHTMAP_NEUTRAL; + return; + } + u32 idx = (y * lm->width + x) * 3; + *r = lm->data[idx + 0]; + *g = lm->data[idx + 1]; + *b = lm->data[idx + 2]; +} + +void pxl8_lightmap_add_point( + pxl8_lightmap* lm, + f32 lx, f32 ly, + u8 r, u8 g, u8 b, + f32 radius, + f32 intensity +) { + if (!lm || !lm->data || radius <= 0.0f) return; + + f32 radius_sq = radius * radius; + f32 inv_radius_sq = 1.0f / radius_sq; + + i32 cx = (i32)(lx * (f32)lm->width); + i32 cy = (i32)(ly * (f32)lm->height); + i32 rad_pixels = (i32)(radius * (f32)lm->width) + 1; + + i32 x0 = cx - rad_pixels; + i32 y0 = cy - rad_pixels; + i32 x1 = cx + rad_pixels; + i32 y1 = cy + rad_pixels; + + if (x0 < 0) x0 = 0; + if (y0 < 0) y0 = 0; + if (x1 >= (i32)lm->width) x1 = (i32)lm->width - 1; + if (y1 >= (i32)lm->height) y1 = (i32)lm->height - 1; + + f32 scale_x = 1.0f / (f32)lm->width; + f32 scale_y = 1.0f / (f32)lm->height; + + for (i32 y = y0; y <= y1; y++) { + f32 dy = ((f32)y * scale_y) - ly; + for (i32 x = x0; x <= x1; x++) { + f32 dx = ((f32)x * scale_x) - lx; + f32 dist_sq = dx * dx + dy * dy; + + if (dist_sq >= radius_sq) continue; + + f32 falloff = 1.0f - dist_sq * inv_radius_sq; + f32 contrib = falloff * falloff * intensity; + + u32 idx = ((u32)y * lm->width + (u32)x) * 3; + + i32 nr = (i32)lm->data[idx + 0] + (i32)((f32)(r - 128) * contrib); + i32 ng = (i32)lm->data[idx + 1] + (i32)((f32)(g - 128) * contrib); + i32 nb = (i32)lm->data[idx + 2] + (i32)((f32)(b - 128) * contrib); + + if (nr < 0) nr = 0; if (nr > 255) nr = 255; + if (ng < 0) ng = 0; if (ng > 255) ng = 255; + if (nb < 0) nb = 0; if (nb > 255) nb = 255; + + lm->data[idx + 0] = (u8)nr; + lm->data[idx + 1] = (u8)ng; + lm->data[idx + 2] = (u8)nb; + } + } +} diff --git a/src/gfx/pxl8_lightmap.h b/src/gfx/pxl8_lightmap.h new file mode 100644 index 0000000..549eb2a --- /dev/null +++ b/src/gfx/pxl8_lightmap.h @@ -0,0 +1,48 @@ +#pragma once + +#include "pxl8_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define PXL8_LIGHTMAP_MAX 16 +#define PXL8_LIGHTMAP_NEUTRAL 128 + +typedef struct pxl8_lightmap { + u8* data; + u32 width; + u32 height; + u32 scale; +} pxl8_lightmap; + +pxl8_lightmap* pxl8_lightmap_create(u32 width, u32 height, u32 scale); +void pxl8_lightmap_destroy(pxl8_lightmap* lm); +void pxl8_lightmap_clear(pxl8_lightmap* lm, u8 r, u8 g, u8 b); +void pxl8_lightmap_set(pxl8_lightmap* lm, u32 x, u32 y, u8 r, u8 g, u8 b); +void pxl8_lightmap_get(const pxl8_lightmap* lm, u32 x, u32 y, u8* r, u8* g, u8* b); + +void pxl8_lightmap_add_point( + pxl8_lightmap* lm, + f32 lx, f32 ly, + u8 r, u8 g, u8 b, + f32 radius, + f32 intensity +); + +static inline void pxl8_lightmap_sample( + const pxl8_lightmap* lm, + f32 u, f32 v, + u8* r, u8* g, u8* b +) { + i32 x = (i32)(u * (f32)lm->width) & (i32)(lm->width - 1); + i32 y = (i32)(v * (f32)lm->height) & (i32)(lm->height - 1); + u32 idx = ((u32)y * lm->width + (u32)x) * 3; + *r = lm->data[idx + 0]; + *g = lm->data[idx + 1]; + *b = lm->data[idx + 2]; +} + +#ifdef __cplusplus +} +#endif diff --git a/src/gfx/pxl8_lights.c b/src/gfx/pxl8_lights.c new file mode 100644 index 0000000..429ef14 --- /dev/null +++ b/src/gfx/pxl8_lights.c @@ -0,0 +1,64 @@ +#include "pxl8_lights.h" +#include "pxl8_mem.h" + +#include + +struct pxl8_lights { + pxl8_light* data; + u32 capacity; + u32 count; +}; + +pxl8_lights* pxl8_lights_create(u32 capacity) { + if (capacity > PXL8_LIGHTS_MAX) capacity = PXL8_LIGHTS_MAX; + + pxl8_lights* lights = pxl8_calloc(1, sizeof(pxl8_lights)); + if (!lights) return NULL; + + lights->data = pxl8_calloc(capacity, sizeof(pxl8_light)); + if (!lights->data) { + pxl8_free(lights); + return NULL; + } + + lights->capacity = capacity; + lights->count = 0; + + return lights; +} + +void pxl8_lights_destroy(pxl8_lights* lights) { + if (!lights) return; + pxl8_free(lights->data); + pxl8_free(lights); +} + +void pxl8_lights_add(pxl8_lights* lights, f32 x, f32 y, f32 z, u8 r, u8 g, u8 b, u8 intensity, f32 radius) { + if (!lights || lights->count >= lights->capacity) return; + + f32 radius_sq = radius * radius; + pxl8_light* l = &lights->data[lights->count++]; + l->position.x = x; + l->position.y = y; + l->position.z = z; + l->r = r; + l->g = g; + l->b = b; + l->intensity = intensity; + l->radius = radius; + l->radius_sq = radius_sq; + l->inv_radius_sq = radius_sq > 0.0f ? 1.0f / radius_sq : 0.0f; +} + +void pxl8_lights_clear(pxl8_lights* lights) { + if (!lights) return; + lights->count = 0; +} + +u32 pxl8_lights_count(const pxl8_lights* lights) { + return lights ? lights->count : 0; +} + +const pxl8_light* pxl8_lights_data(const pxl8_lights* lights) { + return lights ? lights->data : NULL; +} diff --git a/src/gfx/pxl8_lights.h b/src/gfx/pxl8_lights.h new file mode 100644 index 0000000..4a445bd --- /dev/null +++ b/src/gfx/pxl8_lights.h @@ -0,0 +1,33 @@ +#pragma once + +#include "pxl8_math.h" +#include "pxl8_types.h" + +#define PXL8_LIGHTS_MAX 256 + +typedef struct pxl8_light { + pxl8_vec3 position; + f32 inv_radius_sq; + u8 r, g, b; + u8 intensity; + f32 radius; + f32 radius_sq; +} pxl8_light; + +typedef struct pxl8_lights pxl8_lights; + +#ifdef __cplusplus +extern "C" { +#endif + +pxl8_lights* pxl8_lights_create(u32 capacity); +void pxl8_lights_destroy(pxl8_lights* lights); + +void pxl8_lights_add(pxl8_lights* lights, f32 x, f32 y, f32 z, u8 r, u8 g, u8 b, u8 intensity, f32 radius); +void pxl8_lights_clear(pxl8_lights* lights); +u32 pxl8_lights_count(const pxl8_lights* lights); +const pxl8_light* pxl8_lights_data(const pxl8_lights* lights); + +#ifdef __cplusplus +} +#endif diff --git a/src/gfx/pxl8_mesh.c b/src/gfx/pxl8_mesh.c index 6f8da2c..05698ec 100644 --- a/src/gfx/pxl8_mesh.c +++ b/src/gfx/pxl8_mesh.c @@ -1,3 +1,4 @@ +#include "pxl8_mem.h" #include "pxl8_mesh.h" #include #include @@ -6,16 +7,16 @@ pxl8_mesh* pxl8_mesh_create(u32 vertex_capacity, u32 index_capacity) { if (vertex_capacity > PXL8_MESH_MAX_VERTICES) vertex_capacity = PXL8_MESH_MAX_VERTICES; if (index_capacity > PXL8_MESH_MAX_INDICES) index_capacity = PXL8_MESH_MAX_INDICES; - pxl8_mesh* mesh = calloc(1, sizeof(pxl8_mesh)); + pxl8_mesh* mesh = pxl8_calloc(1, sizeof(pxl8_mesh)); if (!mesh) return NULL; - mesh->vertices = calloc(vertex_capacity, sizeof(pxl8_vertex)); - mesh->indices = calloc(index_capacity, sizeof(u16)); + mesh->vertices = pxl8_calloc(vertex_capacity, sizeof(pxl8_vertex)); + mesh->indices = pxl8_calloc(index_capacity, sizeof(u16)); if (!mesh->vertices || !mesh->indices) { - free(mesh->vertices); - free(mesh->indices); - free(mesh); + pxl8_free(mesh->vertices); + pxl8_free(mesh->indices); + pxl8_free(mesh); return NULL; } @@ -29,9 +30,9 @@ pxl8_mesh* pxl8_mesh_create(u32 vertex_capacity, u32 index_capacity) { void pxl8_mesh_destroy(pxl8_mesh* mesh) { if (!mesh) return; - free(mesh->vertices); - free(mesh->indices); - free(mesh); + pxl8_free(mesh->vertices); + pxl8_free(mesh->indices); + pxl8_free(mesh); } void pxl8_mesh_clear(pxl8_mesh* mesh) { diff --git a/src/gfx/pxl8_mesh.h b/src/gfx/pxl8_mesh.h index 78ac881..cb85ab0 100644 --- a/src/gfx/pxl8_mesh.h +++ b/src/gfx/pxl8_mesh.h @@ -17,8 +17,15 @@ typedef enum pxl8_blend_mode { PXL8_BLEND_ADDITIVE, } pxl8_blend_mode; -typedef struct pxl8_material { +typedef struct pxl8_gfx_material { + char name[16]; + pxl8_vec3 u_axis; + pxl8_vec3 v_axis; + f32 u_offset; + f32 v_offset; + u32 texture_id; + u32 lightmap_id; u8 alpha; u8 blend_mode; bool dither; @@ -26,13 +33,15 @@ typedef struct pxl8_material { bool dynamic_lighting; bool per_pixel; bool vertex_color_passthrough; + bool wireframe; f32 emissive_intensity; -} pxl8_material; +} pxl8_gfx_material; typedef struct pxl8_vertex { pxl8_vec3 position; pxl8_vec3 normal; f32 u, v; + f32 lu, lv; u8 color; u8 light; u8 _pad[2]; @@ -62,62 +71,6 @@ static inline u32 pxl8_mesh_triangle_count(const pxl8_mesh* mesh) { return mesh->index_count / 3; } -static inline pxl8_material pxl8_material_create(u32 texture_id) { - return (pxl8_material){ - .texture_id = texture_id, - .alpha = 255, - .blend_mode = PXL8_BLEND_OPAQUE, - .dither = true, - .double_sided = false, - .dynamic_lighting = false, - .per_pixel = false, - .vertex_color_passthrough = false, - .emissive_intensity = 0.0f, - }; -} - -static inline pxl8_material pxl8_material_with_alpha(pxl8_material m, u8 alpha) { - m.alpha = alpha; - if (alpha < 255 && m.blend_mode == PXL8_BLEND_OPAQUE) { - m.blend_mode = PXL8_BLEND_ALPHA; - } - return m; -} - -static inline pxl8_material pxl8_material_with_blend(pxl8_material m, pxl8_blend_mode mode) { - m.blend_mode = mode; - return m; -} - -static inline pxl8_material pxl8_material_with_double_sided(pxl8_material m) { - m.double_sided = true; - return m; -} - -static inline pxl8_material pxl8_material_with_emissive(pxl8_material m, f32 intensity) { - m.emissive_intensity = intensity; - return m; -} - -static inline pxl8_material pxl8_material_with_lighting(pxl8_material m) { - m.dynamic_lighting = true; - return m; -} - -static inline pxl8_material pxl8_material_with_no_dither(pxl8_material m) { - m.dither = false; - return m; -} - -static inline pxl8_material pxl8_material_with_passthrough(pxl8_material m) { - m.vertex_color_passthrough = true; - return m; -} - -static inline pxl8_material pxl8_material_with_per_pixel(pxl8_material m) { - m.per_pixel = true; - return m; -} #ifdef __cplusplus } diff --git a/src/gfx/pxl8_palette.c b/src/gfx/pxl8_palette.c index 9cdc3d2..6e32aef 100644 --- a/src/gfx/pxl8_palette.c +++ b/src/gfx/pxl8_palette.c @@ -5,10 +5,18 @@ #include "pxl8_ase.h" #include "pxl8_color.h" +#include "pxl8_colormap.h" #include "pxl8_log.h" +#include "pxl8_mem.h" #define PXL8_PALETTE_HASH_SIZE 512 +struct pxl8_palette_cube { + u8 colors[PXL8_PALETTE_SIZE * 3]; + u8 table[PXL8_CUBE_ENTRIES]; + u8 stable[PXL8_CUBE_ENTRIES]; +}; + typedef struct { u32 color; i16 index; @@ -200,7 +208,7 @@ static void update_cycle_colors(pxl8_palette* pal, u8 slot) { } pxl8_palette* pxl8_palette_create(void) { - pxl8_palette* pal = calloc(1, sizeof(pxl8_palette)); + pxl8_palette* pal = pxl8_calloc(1, sizeof(pxl8_palette)); if (!pal) return NULL; pal->colors[0] = 0x00000000; @@ -221,7 +229,7 @@ pxl8_palette* pxl8_palette_create(void) { } void pxl8_palette_destroy(pxl8_palette* pal) { - free(pal); + pxl8_free(pal); } pxl8_result pxl8_palette_load_ase(pxl8_palette* pal, const char* path) { @@ -332,10 +340,6 @@ void pxl8_palette_get_rgba(const pxl8_palette* pal, u8 idx, u8* r, u8* g, u8* b, unpack_rgba(pal->colors[idx], r, g, b, a); } -void pxl8_palette_set(pxl8_palette* pal, u8 idx, u32 color) { - if (pal) pal->colors[idx] = color; -} - void pxl8_palette_set_rgb(pxl8_palette* pal, u8 idx, u8 r, u8 g, u8 b) { if (pal) pal->colors[idx] = pack_rgb(r, g, b); } @@ -344,6 +348,17 @@ void pxl8_palette_set_rgba(pxl8_palette* pal, u8 idx, u8 r, u8 g, u8 b, u8 a) { if (pal) pal->colors[idx] = pack_rgba(r, g, b, a); } +void pxl8_set_palette(pxl8_palette* pal, const u32* colors, u16 count) { + if (!pal || !colors) return; + for (u16 i = 0; i < count; i++) { + u32 rgb = colors[i]; + u8 r = (rgb >> 16) & 0xFF; + u8 g = (rgb >> 8) & 0xFF; + u8 b = rgb & 0xFF; + pal->colors[i] = pack_rgb(r, g, b); + } +} + void pxl8_palette_fill_gradient(pxl8_palette* pal, u8 start, u8 count, u32 from, u32 to) { if (!pal || count == 0) return; @@ -472,3 +487,91 @@ pxl8_cycle_range pxl8_cycle_range_disabled(void) { }; return range; } + +static u8 find_closest_stable(const pxl8_palette* pal, u8 r, u8 g, u8 b) { + u8 best_idx = 1; + u32 best_dist = 0xFFFFFFFF; + + u8 dynamic_end = PXL8_DYNAMIC_RANGE_START + PXL8_DYNAMIC_RANGE_COUNT; + + for (u32 i = 1; i < PXL8_FULLBRIGHT_START; i++) { + if (i >= PXL8_DYNAMIC_RANGE_START && i < dynamic_end) { + continue; + } + + u8 pr, pg, pb; + pxl8_palette_get_rgb(pal, (u8)i, &pr, &pg, &pb); + + i32 dr = (i32)r - (i32)pr; + i32 dg = (i32)g - (i32)pg; + i32 db = (i32)b - (i32)pb; + u32 dist = (u32)(dr * dr + dg * dg + db * db); + + if (dist < best_dist) { + best_dist = dist; + best_idx = (u8)i; + if (dist == 0) break; + } + } + + return best_idx; +} + +pxl8_palette_cube* pxl8_palette_cube_create(const pxl8_palette* pal) { + pxl8_palette_cube* cube = pxl8_calloc(1, sizeof(pxl8_palette_cube)); + if (!cube) return NULL; + pxl8_palette_cube_rebuild(cube, pal); + return cube; +} + +void pxl8_palette_cube_destroy(pxl8_palette_cube* cube) { + pxl8_free(cube); +} + +void pxl8_palette_cube_rebuild(pxl8_palette_cube* cube, const pxl8_palette* pal) { + if (!cube || !pal) return; + + for (u32 i = 0; i < PXL8_PALETTE_SIZE; i++) { + u8 r, g, b; + pxl8_palette_get_rgb(pal, (u8)i, &r, &g, &b); + cube->colors[i * 3 + 0] = r; + cube->colors[i * 3 + 1] = g; + cube->colors[i * 3 + 2] = b; + } + + for (u32 bi = 0; bi < PXL8_CUBE_SIZE; bi++) { + for (u32 gi = 0; gi < PXL8_CUBE_SIZE; gi++) { + for (u32 ri = 0; ri < PXL8_CUBE_SIZE; ri++) { + u32 idx = (bi * PXL8_CUBE_SIZE * PXL8_CUBE_SIZE) + (gi * PXL8_CUBE_SIZE) + ri; + u8 r8 = (u8)((ri * 255) / (PXL8_CUBE_SIZE - 1)); + u8 g8 = (u8)((gi * 255) / (PXL8_CUBE_SIZE - 1)); + u8 b8 = (u8)((bi * 255) / (PXL8_CUBE_SIZE - 1)); + + cube->table[idx] = pxl8_palette_find_closest(pal, r8, g8, b8); + cube->stable[idx] = find_closest_stable(pal, r8, g8, b8); + } + } + } +} + +u8 pxl8_palette_cube_lookup(const pxl8_palette_cube* cube, u8 r, u8 g, u8 b) { + u32 ri = (r * (PXL8_CUBE_SIZE - 1)) / 255; + u32 gi = (g * (PXL8_CUBE_SIZE - 1)) / 255; + u32 bi = (b * (PXL8_CUBE_SIZE - 1)) / 255; + u32 idx = (bi * PXL8_CUBE_SIZE * PXL8_CUBE_SIZE) + (gi * PXL8_CUBE_SIZE) + ri; + return cube->table[idx]; +} + +u8 pxl8_palette_cube_lookup_stable(const pxl8_palette_cube* cube, u8 r, u8 g, u8 b) { + u32 ri = (r * (PXL8_CUBE_SIZE - 1)) / 255; + u32 gi = (g * (PXL8_CUBE_SIZE - 1)) / 255; + u32 bi = (b * (PXL8_CUBE_SIZE - 1)) / 255; + u32 idx = (bi * PXL8_CUBE_SIZE * PXL8_CUBE_SIZE) + (gi * PXL8_CUBE_SIZE) + ri; + return cube->stable[idx]; +} + +void pxl8_palette_cube_get_rgb(const pxl8_palette_cube* cube, u8 idx, u8* r, u8* g, u8* b) { + *r = cube->colors[idx * 3 + 0]; + *g = cube->colors[idx * 3 + 1]; + *b = cube->colors[idx * 3 + 2]; +} diff --git a/src/gfx/pxl8_palette.h b/src/gfx/pxl8_palette.h index 9d99eb5..0cfbf9b 100644 --- a/src/gfx/pxl8_palette.h +++ b/src/gfx/pxl8_palette.h @@ -5,8 +5,11 @@ #define PXL8_PALETTE_SIZE 256 #define PXL8_MAX_CYCLES 8 #define PXL8_MAX_CYCLE_LEN 16 +#define PXL8_CUBE_SIZE 32 +#define PXL8_CUBE_ENTRIES (PXL8_CUBE_SIZE * PXL8_CUBE_SIZE * PXL8_CUBE_SIZE) typedef struct pxl8_palette pxl8_palette; +typedef struct pxl8_palette_cube pxl8_palette_cube; typedef enum pxl8_cycle_mode { PXL8_CYCLE_LOOP, @@ -49,9 +52,9 @@ u32 pxl8_palette_color(const pxl8_palette* pal, u8 idx); i32 pxl8_palette_index(const pxl8_palette* pal, u32 color); void pxl8_palette_get_rgb(const pxl8_palette* pal, u8 idx, u8* r, u8* g, u8* b); void pxl8_palette_get_rgba(const pxl8_palette* pal, u8 idx, u8* r, u8* g, u8* b, u8* a); -void pxl8_palette_set(pxl8_palette* pal, u8 idx, u32 color); void pxl8_palette_set_rgb(pxl8_palette* pal, u8 idx, u8 r, u8 g, u8 b); void pxl8_palette_set_rgba(pxl8_palette* pal, u8 idx, u8 r, u8 g, u8 b, u8 a); +void pxl8_set_palette(pxl8_palette* pal, const u32* colors, u16 count); void pxl8_palette_fill_gradient(pxl8_palette* pal, u8 start, u8 count, u32 from, u32 to); void pxl8_palette_fill_gradient_rgb(pxl8_palette* pal, u8 start, u8 count, u8 r0, u8 g0, u8 b0, u8 r1, u8 g1, u8 b1); @@ -65,6 +68,13 @@ void pxl8_palette_tick(pxl8_palette* pal, u16 delta_ticks); pxl8_cycle_range pxl8_cycle_range_create(u8 start, u8 len, u16 period); pxl8_cycle_range pxl8_cycle_range_disabled(void); +pxl8_palette_cube* pxl8_palette_cube_create(const pxl8_palette* pal); +void pxl8_palette_cube_destroy(pxl8_palette_cube* cube); +void pxl8_palette_cube_rebuild(pxl8_palette_cube* cube, const pxl8_palette* pal); +u8 pxl8_palette_cube_lookup(const pxl8_palette_cube* cube, u8 r, u8 g, u8 b); +u8 pxl8_palette_cube_lookup_stable(const pxl8_palette_cube* cube, u8 r, u8 g, u8 b); +void pxl8_palette_cube_get_rgb(const pxl8_palette_cube* cube, u8 idx, u8* r, u8* g, u8* b); + #ifdef __cplusplus } #endif diff --git a/src/gfx/pxl8_particles.c b/src/gfx/pxl8_particles.c index deb2d83..5448625 100644 --- a/src/gfx/pxl8_particles.c +++ b/src/gfx/pxl8_particles.c @@ -3,6 +3,7 @@ #include #include "pxl8_gfx.h" +#include "pxl8_mem.h" #include "pxl8_gfx2d.h" #include "pxl8_palette.h" #include "pxl8_rng.h" @@ -37,12 +38,12 @@ struct pxl8_particles { }; pxl8_particles* pxl8_particles_create(u32 max_count, pxl8_rng* rng) { - pxl8_particles* ps = calloc(1, sizeof(pxl8_particles)); + pxl8_particles* ps = pxl8_calloc(1, sizeof(pxl8_particles)); if (!ps) return NULL; - ps->particles = calloc(max_count, sizeof(pxl8_particle)); + ps->particles = pxl8_calloc(max_count, sizeof(pxl8_particle)); if (!ps->particles) { - free(ps); + pxl8_free(ps); return NULL; } @@ -61,8 +62,8 @@ pxl8_particles* pxl8_particles_create(u32 max_count, pxl8_rng* rng) { void pxl8_particles_destroy(pxl8_particles* ps) { if (!ps) return; - free(ps->particles); - free(ps); + pxl8_free(ps->particles); + pxl8_free(ps); } void pxl8_particles_clear(pxl8_particles* ps) { diff --git a/src/gfx/pxl8_tilemap.c b/src/gfx/pxl8_tilemap.c index ca129e9..263b65c 100644 --- a/src/gfx/pxl8_tilemap.c +++ b/src/gfx/pxl8_tilemap.c @@ -6,6 +6,7 @@ #include "pxl8_ase.h" #include "pxl8_log.h" #include "pxl8_macros.h" +#include "pxl8_mem.h" #include "pxl8_tilesheet.h" struct pxl8_tilesheet { @@ -58,7 +59,7 @@ static pxl8_tile_chunk* pxl8_get_or_create_chunk(pxl8_tilemap_layer* layer, u32 if (idx >= layer->chunks_wide * layer->chunks_high) return NULL; if (!layer->chunks[idx]) { - layer->chunks[idx] = calloc(1, sizeof(pxl8_tile_chunk)); + layer->chunks[idx] = pxl8_calloc(1, sizeof(pxl8_tile_chunk)); if (!layer->chunks[idx]) return NULL; layer->chunks[idx]->chunk_x = chunk_x; @@ -75,7 +76,7 @@ pxl8_tilemap* pxl8_tilemap_create(u32 width, u32 height, u32 tile_size) { return NULL; } - pxl8_tilemap* tilemap = calloc(1, sizeof(pxl8_tilemap)); + pxl8_tilemap* tilemap = pxl8_calloc(1, sizeof(pxl8_tilemap)); if (!tilemap) return NULL; tilemap->width = width; @@ -85,7 +86,7 @@ pxl8_tilemap* pxl8_tilemap_create(u32 width, u32 height, u32 tile_size) { tilemap->tilesheet = pxl8_tilesheet_create(tilemap->tile_size); if (!tilemap->tilesheet) { - free(tilemap); + pxl8_free(tilemap); return NULL; } @@ -103,13 +104,13 @@ pxl8_tilemap* pxl8_tilemap_create(u32 width, u32 height, u32 tile_size) { layer->visible = (i == 0); layer->opacity = 255; - layer->chunks = calloc(layer->chunk_count, sizeof(pxl8_tile_chunk*)); + layer->chunks = pxl8_calloc(layer->chunk_count, sizeof(pxl8_tile_chunk*)); if (!layer->chunks) { for (u32 j = 0; j < i; j++) { - free(tilemap->layers[j].chunks); + pxl8_free(tilemap->layers[j].chunks); } if (tilemap->tilesheet) pxl8_tilesheet_destroy(tilemap->tilesheet); - free(tilemap); + pxl8_free(tilemap); return NULL; } } @@ -125,17 +126,17 @@ void pxl8_tilemap_destroy(pxl8_tilemap* tilemap) { if (layer->chunks) { for (u32 j = 0; j < layer->chunk_count; j++) { if (layer->chunks[j]) { - free(layer->chunks[j]); + pxl8_free(layer->chunks[j]); } } - free(layer->chunks); + pxl8_free(layer->chunks); } } if (tilemap->tilesheet) pxl8_tilesheet_unref(tilemap->tilesheet); - if (tilemap->tile_user_data) free(tilemap->tile_user_data); + if (tilemap->tile_user_data) pxl8_free(tilemap->tile_user_data); - free(tilemap); + pxl8_free(tilemap); } u32 pxl8_tilemap_get_width(const pxl8_tilemap* tilemap) { @@ -155,7 +156,7 @@ void pxl8_tilemap_set_tile_user_data(pxl8_tilemap* tilemap, u16 tile_id, void* u if (tile_id >= tilemap->tile_user_data_capacity) { u32 new_capacity = tile_id + 64; - void** new_data = realloc(tilemap->tile_user_data, new_capacity * sizeof(void*)); + void** new_data = pxl8_realloc(tilemap->tile_user_data, new_capacity * sizeof(void*)); if (!new_data) return; for (u32 i = tilemap->tile_user_data_capacity; i < new_capacity; i++) { @@ -478,7 +479,7 @@ void pxl8_tilemap_compress(pxl8_tilemap* tilemap) { } if (!has_tiles) { - free(chunk); + pxl8_free(chunk); layer->chunks[j] = NULL; layer->allocated_chunks--; } else { @@ -535,8 +536,8 @@ pxl8_result pxl8_tilemap_load_ase(pxl8_tilemap* tilemap, const char* filepath, u u32 tilesheet_width = tiles_per_row * tilemap->tile_size; u32 tilesheet_height = tilesheet_rows * tilemap->tile_size; - if (tilemap->tilesheet->data) free(tilemap->tilesheet->data); - tilemap->tilesheet->data = calloc(tilesheet_width * tilesheet_height, 1); + if (tilemap->tilesheet->data) pxl8_free(tilemap->tilesheet->data); + tilemap->tilesheet->data = pxl8_calloc(tilesheet_width * tilesheet_height, 1); if (!tilemap->tilesheet->data) { pxl8_ase_destroy(&ase_file); return PXL8_ERROR_OUT_OF_MEMORY; @@ -548,8 +549,8 @@ pxl8_result pxl8_tilemap_load_ase(pxl8_tilemap* tilemap, const char* filepath, u tilemap->tilesheet->total_tiles = tileset->tile_count; tilemap->tilesheet->pixel_mode = PXL8_PIXEL_INDEXED; - if (tilemap->tilesheet->tile_valid) free(tilemap->tilesheet->tile_valid); - tilemap->tilesheet->tile_valid = calloc(tileset->tile_count + 1, sizeof(bool)); + if (tilemap->tilesheet->tile_valid) pxl8_free(tilemap->tilesheet->tile_valid); + tilemap->tilesheet->tile_valid = pxl8_calloc(tileset->tile_count + 1, sizeof(bool)); for (u32 i = 0; i < tileset->tile_count; i++) { u32 sheet_row = i / tiles_per_row; diff --git a/src/gfx/pxl8_tilesheet.c b/src/gfx/pxl8_tilesheet.c index 3f8dd39..9f41cd3 100644 --- a/src/gfx/pxl8_tilesheet.c +++ b/src/gfx/pxl8_tilesheet.c @@ -7,6 +7,7 @@ #include "pxl8_color.h" #include "pxl8_gfx.h" #include "pxl8_log.h" +#include "pxl8_mem.h" #include "pxl8_tilemap.h" struct pxl8_tilesheet { @@ -32,7 +33,7 @@ struct pxl8_tilesheet { }; pxl8_tilesheet* pxl8_tilesheet_create(u32 tile_size) { - pxl8_tilesheet* tilesheet = calloc(1, sizeof(pxl8_tilesheet)); + pxl8_tilesheet* tilesheet = pxl8_calloc(1, sizeof(pxl8_tilesheet)); if (!tilesheet) return NULL; tilesheet->tile_size = tile_size; @@ -45,37 +46,37 @@ void pxl8_tilesheet_destroy(pxl8_tilesheet* tilesheet) { if (!tilesheet) return; if (tilesheet->data) { - free(tilesheet->data); + pxl8_free(tilesheet->data); } if (tilesheet->tile_valid) { - free(tilesheet->tile_valid); + pxl8_free(tilesheet->tile_valid); } if (tilesheet->animations) { for (u32 i = 0; i < tilesheet->animation_count; i++) { if (tilesheet->animations[i].frames) { - free(tilesheet->animations[i].frames); + pxl8_free(tilesheet->animations[i].frames); } } - free(tilesheet->animations); + pxl8_free(tilesheet->animations); } if (tilesheet->properties) { - free(tilesheet->properties); + pxl8_free(tilesheet->properties); } if (tilesheet->autotile_rules) { for (u32 i = 0; i <= tilesheet->total_tiles; i++) { if (tilesheet->autotile_rules[i]) { - free(tilesheet->autotile_rules[i]); + pxl8_free(tilesheet->autotile_rules[i]); } } - free(tilesheet->autotile_rules); - free(tilesheet->autotile_rule_counts); + pxl8_free(tilesheet->autotile_rules); + pxl8_free(tilesheet->autotile_rule_counts); } - free(tilesheet); + pxl8_free(tilesheet); } pxl8_result pxl8_tilesheet_load(pxl8_tilesheet* tilesheet, const char* filepath, pxl8_gfx* gfx) { @@ -89,7 +90,7 @@ pxl8_result pxl8_tilesheet_load(pxl8_tilesheet* tilesheet, const char* filepath, } if (tilesheet->data) { - free(tilesheet->data); + pxl8_free(tilesheet->data); } u32 width = ase_file.header.width; @@ -111,8 +112,8 @@ pxl8_result pxl8_tilesheet_load(pxl8_tilesheet* tilesheet, const char* filepath, u16 ase_depth = ase_file.header.color_depth; bool gfx_hicolor = (tilesheet->pixel_mode == PXL8_PIXEL_HICOLOR); - size_t data_size = pixel_count * pxl8_bytes_per_pixel(tilesheet->pixel_mode); - tilesheet->data = malloc(data_size); + usize data_size = pixel_count * pxl8_bytes_per_pixel(tilesheet->pixel_mode); + tilesheet->data = pxl8_malloc(data_size); if (!tilesheet->data) { pxl8_ase_destroy(&ase_file); return PXL8_ERROR_OUT_OF_MEMORY; @@ -138,9 +139,9 @@ pxl8_result pxl8_tilesheet_load(pxl8_tilesheet* tilesheet, const char* filepath, } else if (ase_depth == 8 && gfx_hicolor) { pxl8_warn("Indexed ASE with hicolor gfx - storing as indexed"); tilesheet->pixel_mode = PXL8_PIXEL_INDEXED; - u8* new_data = realloc(tilesheet->data, pixel_count); + u8* new_data = pxl8_realloc(tilesheet->data, pixel_count); if (!new_data) { - free(tilesheet->data); + pxl8_free(tilesheet->data); tilesheet->data = NULL; pxl8_ase_destroy(&ase_file); return PXL8_ERROR_OUT_OF_MEMORY; @@ -149,16 +150,16 @@ pxl8_result pxl8_tilesheet_load(pxl8_tilesheet* tilesheet, const char* filepath, memcpy(tilesheet->data, src, pixel_count); } else { pxl8_error("Unsupported ASE color depth %d for gfx mode", ase_depth); - free(tilesheet->data); + pxl8_free(tilesheet->data); tilesheet->data = NULL; pxl8_ase_destroy(&ase_file); return PXL8_ERROR_INVALID_ARGUMENT; } } - tilesheet->tile_valid = calloc(tilesheet->total_tiles + 1, sizeof(bool)); + tilesheet->tile_valid = pxl8_calloc(tilesheet->total_tiles + 1, sizeof(bool)); if (!tilesheet->tile_valid) { - free(tilesheet->data); + pxl8_free(tilesheet->data); tilesheet->data = NULL; pxl8_ase_destroy(&ase_file); return PXL8_ERROR_OUT_OF_MEMORY; @@ -259,14 +260,14 @@ pxl8_result pxl8_tilesheet_add_animation(pxl8_tilesheet* tilesheet, u16 base_til if (base_tile_id == 0 || base_tile_id > tilesheet->total_tiles) return PXL8_ERROR_INVALID_ARGUMENT; if (!tilesheet->animations) { - tilesheet->animations = calloc(tilesheet->total_tiles + 1, sizeof(pxl8_tile_animation)); + tilesheet->animations = pxl8_calloc(tilesheet->total_tiles + 1, sizeof(pxl8_tile_animation)); if (!tilesheet->animations) return PXL8_ERROR_OUT_OF_MEMORY; } pxl8_tile_animation* anim = &tilesheet->animations[base_tile_id]; - if (anim->frames) free(anim->frames); + if (anim->frames) pxl8_free(anim->frames); - anim->frames = malloc(frame_count * sizeof(u16)); + anim->frames = pxl8_malloc(frame_count * sizeof(u16)); if (!anim->frames) return PXL8_ERROR_OUT_OF_MEMORY; memcpy(anim->frames, frames, frame_count * sizeof(u16)); @@ -340,7 +341,7 @@ void pxl8_tilesheet_set_tile_property(pxl8_tilesheet* tilesheet, u16 tile_id, if (!tilesheet || !props || tile_id == 0 || tile_id > tilesheet->total_tiles) return; if (!tilesheet->properties) { - tilesheet->properties = calloc(tilesheet->total_tiles + 1, sizeof(pxl8_tile_properties)); + tilesheet->properties = pxl8_calloc(tilesheet->total_tiles + 1, sizeof(pxl8_tile_properties)); if (!tilesheet->properties) return; } @@ -365,15 +366,15 @@ pxl8_result pxl8_tilesheet_add_autotile_rule(pxl8_tilesheet* tilesheet, u16 base } if (!tilesheet->autotile_rules) { - tilesheet->autotile_rules = calloc(tilesheet->total_tiles + 1, sizeof(pxl8_autotile_rule*)); - tilesheet->autotile_rule_counts = calloc(tilesheet->total_tiles + 1, sizeof(u32)); + tilesheet->autotile_rules = pxl8_calloc(tilesheet->total_tiles + 1, sizeof(pxl8_autotile_rule*)); + tilesheet->autotile_rule_counts = pxl8_calloc(tilesheet->total_tiles + 1, sizeof(u32)); if (!tilesheet->autotile_rules || !tilesheet->autotile_rule_counts) { return PXL8_ERROR_OUT_OF_MEMORY; } } u32 count = tilesheet->autotile_rule_counts[base_tile_id]; - pxl8_autotile_rule* new_rules = realloc(tilesheet->autotile_rules[base_tile_id], + pxl8_autotile_rule* new_rules = pxl8_realloc(tilesheet->autotile_rules[base_tile_id], (count + 1) * sizeof(pxl8_autotile_rule)); if (!new_rules) return PXL8_ERROR_OUT_OF_MEMORY; diff --git a/src/gfx/pxl8_transition.c b/src/gfx/pxl8_transition.c index f19001f..ba76e1d 100644 --- a/src/gfx/pxl8_transition.c +++ b/src/gfx/pxl8_transition.c @@ -6,6 +6,7 @@ #include "pxl8_gfx.h" #include "pxl8_log.h" #include "pxl8_math.h" +#include "pxl8_mem.h" pxl8_transition* pxl8_transition_create(pxl8_transition_type type, f32 duration) { if (duration <= 0.0f) { @@ -13,7 +14,7 @@ pxl8_transition* pxl8_transition_create(pxl8_transition_type type, f32 duration) return NULL; } - pxl8_transition* transition = (pxl8_transition*)calloc(1, sizeof(pxl8_transition)); + pxl8_transition* transition = (pxl8_transition*)pxl8_calloc(1, sizeof(pxl8_transition)); if (!transition) { pxl8_error("Failed to allocate transition"); return NULL; @@ -33,7 +34,7 @@ pxl8_transition* pxl8_transition_create(pxl8_transition_type type, f32 duration) void pxl8_transition_destroy(pxl8_transition* transition) { if (!transition) return; - free(transition); + pxl8_free(transition); } f32 pxl8_transition_get_progress(const pxl8_transition* transition) { diff --git a/src/game/pxl8_gui.c b/src/gui/pxl8_gui.c similarity index 69% rename from src/game/pxl8_gui.c rename to src/gui/pxl8_gui.c index 6f8bbd3..f81a910 100644 --- a/src/game/pxl8_gui.c +++ b/src/gui/pxl8_gui.c @@ -4,9 +4,10 @@ #include #include "pxl8_gfx.h" +#include "pxl8_mem.h" pxl8_gui_state* pxl8_gui_state_create(void) { - pxl8_gui_state* state = (pxl8_gui_state*)malloc(sizeof(pxl8_gui_state)); + pxl8_gui_state* state = (pxl8_gui_state*)pxl8_malloc(sizeof(pxl8_gui_state)); if (!state) return NULL; memset(state, 0, sizeof(pxl8_gui_state)); @@ -15,21 +16,23 @@ pxl8_gui_state* pxl8_gui_state_create(void) { void pxl8_gui_state_destroy(pxl8_gui_state* state) { if (!state) return; - free(state); + pxl8_free(state); } -void pxl8_gui_begin_frame(pxl8_gui_state* state) { +void pxl8_gui_begin_frame(pxl8_gui_state* state, pxl8_gfx* gfx) { if (!state) return; state->hot_id = 0; + if (gfx) pxl8_gfx_push_target(gfx); } -void pxl8_gui_end_frame(pxl8_gui_state* state) { +void pxl8_gui_end_frame(pxl8_gui_state* state, pxl8_gfx* gfx) { if (!state) return; if (!state->cursor_down) { state->active_id = 0; } state->cursor_clicked = false; + if (gfx) pxl8_gfx_pop_target(gfx); } void pxl8_gui_cursor_move(pxl8_gui_state* state, i32 x, i32 y) { @@ -80,16 +83,16 @@ bool pxl8_gui_button(pxl8_gui_state* state, pxl8_gfx* gfx, u32 id, i32 x, i32 y, i32 offset_y = 0; if (is_active) { - bg_color = 4; - border_color = 3; + bg_color = pxl8_gfx_ui_color(gfx, PXL8_UI_BG3); + border_color = pxl8_gfx_ui_color(gfx, PXL8_UI_BG2); offset_x = 1; offset_y = 1; } else if (is_hot || cursor_over) { - bg_color = 4; - border_color = 8; + bg_color = pxl8_gfx_ui_color(gfx, PXL8_UI_BG3); + border_color = pxl8_gfx_ui_color(gfx, PXL8_UI_FG0); } else { - bg_color = 3; - border_color = 4; + bg_color = pxl8_gfx_ui_color(gfx, PXL8_UI_BG2); + border_color = pxl8_gfx_ui_color(gfx, PXL8_UI_BG3); } pxl8_2d_rect_fill(gfx, x, y, w, h, bg_color); @@ -98,7 +101,7 @@ bool pxl8_gui_button(pxl8_gui_state* state, pxl8_gfx* gfx, u32 id, i32 x, i32 y, i32 text_len = (i32)strlen(label); i32 text_x = x + (w / 2) - ((text_len * 8) / 2) + offset_x; i32 text_y = y + (h / 2) - 5 + offset_y; - pxl8_2d_text(gfx, label, text_x, text_y, 6); + pxl8_2d_text(gfx, label, text_x, text_y, pxl8_gfx_ui_color(gfx, PXL8_UI_FG1)); return clicked; } @@ -106,14 +109,19 @@ bool pxl8_gui_button(pxl8_gui_state* state, pxl8_gfx* gfx, u32 id, i32 x, i32 y, void pxl8_gui_window(pxl8_gfx* gfx, i32 x, i32 y, i32 w, i32 h, const char* title) { if (!gfx || !title) return; - pxl8_2d_rect_fill(gfx, x, y, w, 28, 1); - pxl8_2d_rect_fill(gfx, x, y + 28, w, h - 28, 2); - pxl8_2d_rect(gfx, x, y, w, h, 4); - pxl8_2d_rect_fill(gfx, x, y + 28, w, 1, 4); + u8 title_bg = pxl8_gfx_ui_color(gfx, PXL8_UI_BG1); + u8 body_bg = pxl8_gfx_ui_color(gfx, PXL8_UI_BG2); + u8 border = pxl8_gfx_ui_color(gfx, PXL8_UI_BG3); + u8 title_fg = pxl8_gfx_ui_color(gfx, PXL8_UI_FG0); + + pxl8_2d_rect_fill(gfx, x, y, w, 28, title_bg); + pxl8_2d_rect_fill(gfx, x, y + 28, w, h - 28, body_bg); + pxl8_2d_rect(gfx, x, y, w, h, border); + pxl8_2d_rect_fill(gfx, x, y + 28, w, 1, border); i32 title_x = x + 10; i32 title_y = y + (28 / 2) - 5; - pxl8_2d_text(gfx, title, title_x, title_y, 8); + pxl8_2d_text(gfx, title, title_x, title_y, title_fg); } void pxl8_gui_label(pxl8_gfx* gfx, i32 x, i32 y, const char* text, u8 color) { diff --git a/src/game/pxl8_gui.h b/src/gui/pxl8_gui.h similarity index 88% rename from src/game/pxl8_gui.h rename to src/gui/pxl8_gui.h index db1147f..1d7646a 100644 --- a/src/game/pxl8_gui.h +++ b/src/gui/pxl8_gui.h @@ -22,8 +22,8 @@ void pxl8_gui_state_destroy(pxl8_gui_state* state); void pxl8_gui_get_cursor_pos(const pxl8_gui_state* state, i32* x, i32* y); bool pxl8_gui_is_hovering(const pxl8_gui_state* state); -void pxl8_gui_begin_frame(pxl8_gui_state* state); -void pxl8_gui_end_frame(pxl8_gui_state* state); +void pxl8_gui_begin_frame(pxl8_gui_state* state, pxl8_gfx* gfx); +void pxl8_gui_end_frame(pxl8_gui_state* state, pxl8_gfx* gfx); void pxl8_gui_cursor_down(pxl8_gui_state* state); void pxl8_gui_cursor_move(pxl8_gui_state* state, i32 x, i32 y); diff --git a/src/gui/pxl8_gui_palette.h b/src/gui/pxl8_gui_palette.h new file mode 100644 index 0000000..2d87599 --- /dev/null +++ b/src/gui/pxl8_gui_palette.h @@ -0,0 +1,41 @@ +#pragma once + +#include "pxl8_types.h" + +#define PXL8_UI_PALETTE_SIZE 16 + +#define PXL8_UI_BG0 0 +#define PXL8_UI_BG1 1 +#define PXL8_UI_BG2 2 +#define PXL8_UI_BG3 3 +#define PXL8_UI_FG0 4 +#define PXL8_UI_FG1 5 +#define PXL8_UI_FG2 6 +#define PXL8_UI_FG3 7 +#define PXL8_UI_RED 8 +#define PXL8_UI_GREEN 9 +#define PXL8_UI_YELLOW 10 +#define PXL8_UI_BLUE 11 +#define PXL8_UI_PURPLE 12 +#define PXL8_UI_AQUA 13 +#define PXL8_UI_ORANGE 14 +#define PXL8_UI_GRAY 15 + +static const u32 pxl8_ui_palette[PXL8_UI_PALETTE_SIZE] = { + 0xFF282828, + 0xFF3c3836, + 0xFF504945, + 0xFF665c54, + 0xFFc7f1fb, + 0xFFb2dbeb, + 0xFFa1c4d5, + 0xFF93aebd, + 0xFF3449fb, + 0xFF26bbb8, + 0xFF2fbdfa, + 0xFF98a583, + 0xFF9b86d3, + 0xFF7cc08e, + 0xFF1980fe, + 0xFF928374, +}; diff --git a/src/hal/pxl8_sdl3.c b/src/hal/pxl8_hal_sdl3.c similarity index 99% rename from src/hal/pxl8_sdl3.c rename to src/hal/pxl8_hal_sdl3.c index 3f2f909..66c4f0b 100644 --- a/src/hal/pxl8_sdl3.c +++ b/src/hal/pxl8_hal_sdl3.c @@ -1,4 +1,4 @@ -#include "pxl8_sdl3.h" +#include "pxl8_hal.h" #define SDL_MAIN_USE_CALLBACKS #include @@ -8,13 +8,15 @@ #include "pxl8_log.h" #include "pxl8_sys.h" +extern const pxl8_hal pxl8_hal_sdl3; + typedef struct pxl8_sdl3_context { SDL_Texture* framebuffer; SDL_Renderer* renderer; SDL_Window* window; u32* rgba_buffer; - size_t rgba_buffer_size; + usize rgba_buffer_size; } pxl8_sdl3_context; static void* sdl3_create(i32 render_w, i32 render_h, @@ -101,7 +103,7 @@ static void sdl3_upload_texture(void* platform_data, const void* pixels, u32 w, if (!platform_data || !pixels) return; pxl8_sdl3_context* ctx = (pxl8_sdl3_context*)platform_data; - size_t pixel_count = w * h; + usize pixel_count = w * h; if (bpp == 4) { SDL_UpdateTexture(ctx->framebuffer, NULL, pixels, w * 4); diff --git a/src/hal/pxl8_mem.h b/src/hal/pxl8_mem.h new file mode 100644 index 0000000..790a19c --- /dev/null +++ b/src/hal/pxl8_mem.h @@ -0,0 +1,8 @@ +#pragma once + +#include "pxl8_types.h" + +void* pxl8_malloc(usize size); +void* pxl8_calloc(usize count, usize size); +void* pxl8_realloc(void* ptr, usize size); +void pxl8_free(void* ptr); diff --git a/src/hal/pxl8_mem_sdl3.c b/src/hal/pxl8_mem_sdl3.c new file mode 100644 index 0000000..4fc5aaa --- /dev/null +++ b/src/hal/pxl8_mem_sdl3.c @@ -0,0 +1,19 @@ +#include "pxl8_mem.h" + +#include + +void* pxl8_malloc(usize size) { + return SDL_malloc(size); +} + +void* pxl8_calloc(usize count, usize size) { + return SDL_calloc(count, size); +} + +void* pxl8_realloc(void* ptr, usize size) { + return SDL_realloc(ptr, size); +} + +void pxl8_free(void* ptr) { + SDL_free(ptr); +} diff --git a/src/hal/pxl8_sdl3.h b/src/hal/pxl8_sdl3.h deleted file mode 100644 index 4051e9e..0000000 --- a/src/hal/pxl8_sdl3.h +++ /dev/null @@ -1,5 +0,0 @@ -#pragma once - -#include "pxl8_hal.h" - -extern const pxl8_hal pxl8_hal_sdl3; diff --git a/src/lua/pxl8.lua b/src/lua/pxl8.lua index 0efeff8..3f02c39 100644 --- a/src/lua/pxl8.lua +++ b/src/lua/pxl8.lua @@ -1,13 +1,15 @@ local anim = require("pxl8.anim") local bytes = require("pxl8.bytes") local core = require("pxl8.core") +local effects = require("pxl8.effects") local gfx2d = require("pxl8.gfx2d") local gfx3d = require("pxl8.gfx3d") local gui = require("pxl8.gui") local input = require("pxl8.input") -local math3d = require("pxl8.math") +local math = require("pxl8.math") local net = require("pxl8.net") local particles = require("pxl8.particles") +local procgen = require("pxl8.procgen") local sfx = require("pxl8.sfx") local tilemap = require("pxl8.tilemap") local transition = require("pxl8.transition") @@ -27,16 +29,20 @@ pxl8.debug = core.debug pxl8.trace = core.trace pxl8.quit = core.quit -pxl8.rng_seed = core.rng_seed -pxl8.rng_next = core.rng_next +pxl8.hash32 = math.hash32 pxl8.rng_f32 = core.rng_f32 +pxl8.rng_next = core.rng_next pxl8.rng_range = core.rng_range +pxl8.rng_seed = core.rng_seed pxl8.find_color = core.find_color pxl8.palette_color = core.palette_color pxl8.palette_index = core.palette_index pxl8.ramp_index = core.ramp_index +pxl8.set_colormap = core.set_colormap +pxl8.set_palette = core.set_palette pxl8.set_palette_rgb = core.set_palette_rgb +pxl8.update_palette_deps = core.update_palette_deps pxl8.clear = gfx2d.clear pxl8.pixel = gfx2d.pixel @@ -78,18 +84,28 @@ pxl8.Anim = anim.Anim pxl8.create_anim = anim.Anim.new pxl8.create_anim_from_ase = anim.Anim.from_ase -pxl8.bounds = math3d.bounds +pxl8.bounds = math.bounds pxl8.Camera3D = gfx3d.Camera3D -pxl8.create_camera_3d = gfx3d.Camera3D.new +pxl8.Mesh = gfx3d.Mesh pxl8.begin_frame_3d = gfx3d.begin_frame pxl8.clear_3d = gfx3d.clear pxl8.clear_depth = gfx3d.clear_depth +pxl8.create_camera_3d = gfx3d.Camera3D.new +pxl8.create_mesh = gfx3d.Mesh.new +pxl8.create_vec3_array = gfx3d.create_vec3_array pxl8.draw_line_3d = gfx3d.draw_line pxl8.draw_mesh = gfx3d.draw_mesh pxl8.end_frame_3d = gfx3d.end_frame -pxl8.Mesh = gfx3d.Mesh -pxl8.create_mesh = gfx3d.Mesh.new +pxl8.project_points = gfx3d.project_points + +pxl8.GLOW_CIRCLE = effects.GLOW_CIRCLE +pxl8.GLOW_DIAMOND = effects.GLOW_DIAMOND +pxl8.GLOW_SHAFT = effects.GLOW_SHAFT +pxl8.Glows = effects.Glows +pxl8.create_glows = effects.Glows.new +pxl8.Lights = effects.Lights +pxl8.create_lights = effects.Lights.new pxl8.Compressor = sfx.Compressor pxl8.create_compressor = sfx.Compressor.new @@ -103,16 +119,18 @@ pxl8.create_gui = gui.Gui.new pxl8.gui_label = gui.label pxl8.gui_window = gui.window -pxl8.mat4_identity = math3d.mat4_identity -pxl8.mat4_lookat = math3d.mat4_lookat -pxl8.mat4_multiply = math3d.mat4_multiply -pxl8.mat4_ortho = math3d.mat4_ortho -pxl8.mat4_perspective = math3d.mat4_perspective -pxl8.mat4_rotate_x = math3d.mat4_rotate_x -pxl8.mat4_rotate_y = math3d.mat4_rotate_y -pxl8.mat4_rotate_z = math3d.mat4_rotate_z -pxl8.mat4_scale = math3d.mat4_scale -pxl8.mat4_translate = math3d.mat4_translate +pxl8.mat4_identity = math.mat4_identity +pxl8.mat4_lookat = math.mat4_lookat +pxl8.mat4_multiply = math.mat4_multiply +pxl8.mat4_multiply_vec3 = math.mat4_multiply_vec3 +pxl8.mat4_multiply_vec4 = math.mat4_multiply_vec4 +pxl8.mat4_orthographic = math.mat4_orthographic +pxl8.mat4_perspective = math.mat4_perspective +pxl8.mat4_rotate_x = math.mat4_rotate_x +pxl8.mat4_rotate_y = math.mat4_rotate_y +pxl8.mat4_rotate_z = math.mat4_rotate_z +pxl8.mat4_scale = math.mat4_scale +pxl8.mat4_translate = math.mat4_translate pxl8.Net = net.Net pxl8.create_net = net.Net.new @@ -141,9 +159,10 @@ pxl8.pack_u64_le = bytes.pack_u64_le pxl8.Particles = particles.Particles pxl8.create_particles = particles.Particles.new +pxl8.Graph = procgen.Graph +pxl8.create_graph = procgen.create_graph pxl8.PROCGEN_ROOMS = world.PROCGEN_ROOMS pxl8.PROCGEN_TERRAIN = world.PROCGEN_TERRAIN -pxl8.procgen_tex = world.procgen_tex pxl8.SfxContext = sfx.SfxContext pxl8.SfxNode = sfx.SfxNode diff --git a/src/lua/pxl8/core.lua b/src/lua/pxl8/core.lua index 6b703c8..afd5dac 100644 --- a/src/lua/pxl8/core.lua +++ b/src/lua/pxl8/core.lua @@ -20,27 +20,40 @@ function core.get_fps() end function core.palette_color(index) - local pal = C.pxl8_gfx_get_palette(core.gfx) + local pal = C.pxl8_gfx_palette(core.gfx) if pal == nil then return 0 end return C.pxl8_palette_color(pal, index) end function core.palette_index(color) - local pal = C.pxl8_gfx_get_palette(core.gfx) + local pal = C.pxl8_gfx_palette(core.gfx) if pal == nil then return -1 end return C.pxl8_palette_index(pal, color) end function core.set_palette_rgb(index, r, g, b) - local pal = C.pxl8_gfx_get_palette(core.gfx) + local pal = C.pxl8_gfx_palette(core.gfx) if pal == nil then return end C.pxl8_palette_set_rgb(pal, index, r, g, b) +end + +function core.set_palette(colors, count) + C.pxl8_gfx_set_palette_colors(core.gfx, colors, count) +end + +function core.set_colormap(data, size) + local cm = C.pxl8_gfx_colormap(core.gfx) + if cm == nil then return end + C.pxl8_set_colormap(cm, data, size) +end + +function core.update_palette_deps() C.pxl8_gfx_blend_tables_update(core.gfx) C.pxl8_gfx_colormap_update(core.gfx) end function core.ramp_index(position) - local pal = C.pxl8_gfx_get_palette(core.gfx) + local pal = C.pxl8_gfx_palette(core.gfx) if pal == nil then return 0 end return C.pxl8_palette_ramp_index(pal, position) end diff --git a/src/lua/pxl8/effects.lua b/src/lua/pxl8/effects.lua index 4db069a..7edc0a2 100644 --- a/src/lua/pxl8/effects.lua +++ b/src/lua/pxl8/effects.lua @@ -8,25 +8,72 @@ effects.GLOW_CIRCLE = 0 effects.GLOW_DIAMOND = 1 effects.GLOW_SHAFT = 2 -function effects.glows(glows) - if not glows or #glows == 0 then return end +local Glows = {} +Glows.__index = Glows - local count = #glows - local glow_array = ffi.new("pxl8_glow_source[?]", count) - - for i, g in ipairs(glows) do - local idx = i - 1 - glow_array[idx].x = g.x or 0 - glow_array[idx].y = g.y or 0 - glow_array[idx].radius = g.radius or 8 - glow_array[idx].intensity = g.intensity or 255 - glow_array[idx].color = g.color or 15 - glow_array[idx].depth = g.depth or 0xFFFF - glow_array[idx].height = g.height or 0 - glow_array[idx].shape = g.shape or 0 +function Glows.new(capacity) + local ptr = C.pxl8_glows_create(capacity or 1000) + if ptr == nil then + return nil end - - C.pxl8_gfx_apply_effect(core.gfx, C.PXL8_GFX_EFFECT_GLOWS, glow_array, count) + return setmetatable({ _ptr = ptr }, Glows) end +function Glows:add(x, y, radius, intensity, color, shape) + C.pxl8_glows_add(self._ptr, x, y, radius or 8, intensity or 255, color or 15, shape or 0) +end + +function Glows:clear() + C.pxl8_glows_clear(self._ptr) +end + +function Glows:count() + return C.pxl8_glows_count(self._ptr) +end + +function Glows:destroy() + if self._ptr then + C.pxl8_glows_destroy(self._ptr) + self._ptr = nil + end +end + +function Glows:render() + C.pxl8_glows_render(self._ptr, core.gfx) +end + +effects.Glows = Glows + +local Lights = {} +Lights.__index = Lights + +function Lights.new(capacity) + local ptr = C.pxl8_lights_create(capacity or 256) + if ptr == nil then + return nil + end + return setmetatable({ _ptr = ptr }, Lights) +end + +function Lights:add(x, y, z, r, g, b, intensity, radius) + C.pxl8_lights_add(self._ptr, x, y, z, r or 255, g or 255, b or 255, intensity or 255, radius or 10) +end + +function Lights:clear() + C.pxl8_lights_clear(self._ptr) +end + +function Lights:count() + return C.pxl8_lights_count(self._ptr) +end + +function Lights:destroy() + if self._ptr then + C.pxl8_lights_destroy(self._ptr) + self._ptr = nil + end +end + +effects.Lights = Lights + return effects diff --git a/src/lua/pxl8/gfx3d.lua b/src/lua/pxl8/gfx3d.lua index dd84914..61ec31c 100644 --- a/src/lua/pxl8/gfx3d.lua +++ b/src/lua/pxl8/gfx3d.lua @@ -75,6 +75,15 @@ function Camera3D:update(dt) C.pxl8_3d_camera_update(self._ptr, dt) end +function Camera3D:world_to_screen(x, y, z, width, height) + local pos = ffi.new("pxl8_vec3", {x = x, y = y, z = z}) + local result = C.pxl8_3d_camera_world_to_screen(self._ptr, pos, width, height) + if result.visible then + return {x = result.x, y = result.y, depth = result.depth} + end + return nil +end + gfx3d.Camera3D = Camera3D local Mesh = {} @@ -123,14 +132,15 @@ gfx3d.Mesh = Mesh function gfx3d.draw_mesh(mesh, opts) opts = opts or {} local model = ffi.new("pxl8_mat4") - model.m[0] = 1 - model.m[5] = 1 - model.m[10] = 1 + local s = opts.scale or 1 + model.m[0] = s + model.m[5] = s + model.m[10] = s model.m[15] = 1 if opts.x then model.m[12] = opts.x end if opts.y then model.m[13] = opts.y end if opts.z then model.m[14] = opts.z end - local material = ffi.new("pxl8_material", { + local material = ffi.new("pxl8_gfx_material", { texture_id = opts.texture or 0, alpha = opts.alpha or 255, blend_mode = opts.blend_mode or 0, @@ -139,12 +149,13 @@ function gfx3d.draw_mesh(mesh, opts) dynamic_lighting = opts.lighting or false, per_pixel = opts.per_pixel or false, vertex_color_passthrough = opts.passthrough or false, + wireframe = opts.wireframe or false, emissive_intensity = opts.emissive or 0.0, }) C.pxl8_3d_draw_mesh(core.gfx, mesh._ptr, model, material) end -function gfx3d.begin_frame(camera, uniforms) +function gfx3d.begin_frame(camera, lights, uniforms) uniforms = uniforms or {} local u = ffi.new("pxl8_3d_uniforms") @@ -164,27 +175,8 @@ function gfx3d.begin_frame(camera, uniforms) end u.celestial_intensity = uniforms.celestial_intensity or 0.0 - u.num_lights = 0 - if uniforms.lights then - for i, light in ipairs(uniforms.lights) do - if i > 16 then break end - local idx = i - 1 - u.lights[idx].position.x = light.x or 0 - u.lights[idx].position.y = light.y or 0 - u.lights[idx].position.z = light.z or 0 - u.lights[idx].r = light.r or 255 - u.lights[idx].g = light.g or 255 - u.lights[idx].b = light.b or 255 - u.lights[idx].intensity = light.intensity or 255 - u.lights[idx].radius = light.radius or 100 - local radius_sq = u.lights[idx].radius * u.lights[idx].radius - u.lights[idx].radius_sq = radius_sq - u.lights[idx].inv_radius_sq = radius_sq > 0 and (1.0 / radius_sq) or 0 - u.num_lights = i - end - end - - C.pxl8_3d_begin_frame(core.gfx, camera._ptr, u) + local lights_ptr = lights and lights._ptr or nil + C.pxl8_3d_begin_frame(core.gfx, camera._ptr, lights_ptr, u) end function gfx3d.clear(color) @@ -205,4 +197,12 @@ function gfx3d.end_frame() C.pxl8_3d_end_frame(core.gfx) end +function gfx3d.project_points(input, output, count, transform) + C.pxl8_3d_project_points(core.gfx, input, output, count, transform) +end + +function gfx3d.create_vec3_array(count) + return ffi.new("pxl8_vec3[?]", count) +end + return gfx3d diff --git a/src/lua/pxl8/gui.lua b/src/lua/pxl8/gui.lua index b8cba94..b1f379c 100644 --- a/src/lua/pxl8/gui.lua +++ b/src/lua/pxl8/gui.lua @@ -16,7 +16,7 @@ function Gui.new() end function Gui:begin_frame() - C.pxl8_gui_begin_frame(self._ptr) + C.pxl8_gui_begin_frame(self._ptr, core.gfx) end function Gui:button(id, x, y, w, h, label) @@ -43,7 +43,7 @@ function Gui:destroy() end function Gui:end_frame() - C.pxl8_gui_end_frame(self._ptr) + C.pxl8_gui_end_frame(self._ptr, core.gfx) end function Gui:get_cursor_pos() diff --git a/src/lua/pxl8/math.lua b/src/lua/pxl8/math.lua index c82ad84..7bf4663 100644 --- a/src/lua/pxl8/math.lua +++ b/src/lua/pxl8/math.lua @@ -1,53 +1,65 @@ local ffi = require("ffi") local C = ffi.C -local math3d = {} +local math = {} -function math3d.mat4_identity() +function math.hash32(x) + return C.pxl8_hash32(x) +end + +function math.mat4_identity() return C.pxl8_mat4_identity() end -function math3d.mat4_mul(a, b) - return C.pxl8_mat4_mul(a, b) +function math.mat4_multiply(a, b) + return C.pxl8_mat4_multiply(a, b) end -function math3d.mat4_translate(x, y, z) +function math.mat4_multiply_vec3(m, v) + return C.pxl8_mat4_multiply_vec3(m, v) +end + +function math.mat4_multiply_vec4(m, v) + return C.pxl8_mat4_multiply_vec4(m, v) +end + +function math.mat4_translate(x, y, z) return C.pxl8_mat4_translate(x, y, z) end -function math3d.mat4_rotate_x(angle) +function math.mat4_rotate_x(angle) return C.pxl8_mat4_rotate_x(angle) end -function math3d.mat4_rotate_y(angle) +function math.mat4_rotate_y(angle) return C.pxl8_mat4_rotate_y(angle) end -function math3d.mat4_rotate_z(angle) +function math.mat4_rotate_z(angle) return C.pxl8_mat4_rotate_z(angle) end -function math3d.mat4_scale(x, y, z) +function math.mat4_scale(x, y, z) return C.pxl8_mat4_scale(x, y, z) end -function math3d.mat4_ortho(left, right, bottom, top, near, far) - return C.pxl8_mat4_ortho(left, right, bottom, top, near, far) +function math.mat4_orthographic(left, right, bottom, top, near, far) + return C.pxl8_mat4_orthographic(left, right, bottom, top, near, far) end -function math3d.mat4_perspective(fov, aspect, near, far) +function math.mat4_perspective(fov, aspect, near, far) return C.pxl8_mat4_perspective(fov, aspect, near, far) end -function math3d.mat4_lookat(eye, center, up) +function math.mat4_lookat(eye, center, up) local eye_vec = ffi.new("pxl8_vec3", {x = eye[1], y = eye[2], z = eye[3]}) local center_vec = ffi.new("pxl8_vec3", {x = center[1], y = center[2], z = center[3]}) local up_vec = ffi.new("pxl8_vec3", {x = up[1], y = up[2], z = up[3]}) return C.pxl8_mat4_lookat(eye_vec, center_vec, up_vec) end -function math3d.bounds(x, y, w, h) +function math.bounds(x, y, w, h) return ffi.new("pxl8_bounds", {x = x, y = y, w = w, h = h}) end -return math3d +return math diff --git a/src/lua/pxl8/particles.lua b/src/lua/pxl8/particles.lua index 41eacef..a0abfe6 100644 --- a/src/lua/pxl8/particles.lua +++ b/src/lua/pxl8/particles.lua @@ -12,7 +12,7 @@ function Particles.new(max_count) if ps == nil then return nil end - local pal = C.pxl8_gfx_get_palette(core.gfx) + local pal = C.pxl8_gfx_palette(core.gfx) if pal ~= nil then C.pxl8_particles_set_palette(ps, pal) end diff --git a/src/lua/pxl8/procgen.lua b/src/lua/pxl8/procgen.lua new file mode 100644 index 0000000..d5b1c27 --- /dev/null +++ b/src/lua/pxl8/procgen.lua @@ -0,0 +1,99 @@ +local ffi = require("ffi") +local C = ffi.C +local core = require("pxl8.core") + +local procgen = {} + +procgen.OP_CONST = C.PXL8_OP_CONST +procgen.OP_INPUT_AGE = C.PXL8_OP_INPUT_AGE +procgen.OP_INPUT_SEED = C.PXL8_OP_INPUT_SEED +procgen.OP_INPUT_TIME = C.PXL8_OP_INPUT_TIME +procgen.OP_INPUT_X = C.PXL8_OP_INPUT_X +procgen.OP_INPUT_Y = C.PXL8_OP_INPUT_Y + +procgen.OP_ABS = C.PXL8_OP_ABS +procgen.OP_ADD = C.PXL8_OP_ADD +procgen.OP_CEIL = C.PXL8_OP_CEIL +procgen.OP_CLAMP = C.PXL8_OP_CLAMP +procgen.OP_COS = C.PXL8_OP_COS +procgen.OP_DIV = C.PXL8_OP_DIV +procgen.OP_FLOOR = C.PXL8_OP_FLOOR +procgen.OP_FRACT = C.PXL8_OP_FRACT +procgen.OP_GRADIENT_LINEAR = C.PXL8_OP_GRADIENT_LINEAR +procgen.OP_GRADIENT_RADIAL = C.PXL8_OP_GRADIENT_RADIAL +procgen.OP_LERP = C.PXL8_OP_LERP +procgen.OP_MAX = C.PXL8_OP_MAX +procgen.OP_MIN = C.PXL8_OP_MIN +procgen.OP_MOD = C.PXL8_OP_MOD +procgen.OP_MUL = C.PXL8_OP_MUL +procgen.OP_NEGATE = C.PXL8_OP_NEGATE +procgen.OP_NOISE_FBM = C.PXL8_OP_NOISE_FBM +procgen.OP_NOISE_PERLIN = C.PXL8_OP_NOISE_PERLIN +procgen.OP_NOISE_RIDGED = C.PXL8_OP_NOISE_RIDGED +procgen.OP_NOISE_TURBULENCE = C.PXL8_OP_NOISE_TURBULENCE +procgen.OP_NOISE_VALUE = C.PXL8_OP_NOISE_VALUE +procgen.OP_POW = C.PXL8_OP_POW +procgen.OP_QUANTIZE = C.PXL8_OP_QUANTIZE +procgen.OP_SELECT = C.PXL8_OP_SELECT +procgen.OP_SIN = C.PXL8_OP_SIN +procgen.OP_SMOOTHSTEP = C.PXL8_OP_SMOOTHSTEP +procgen.OP_SQRT = C.PXL8_OP_SQRT +procgen.OP_SUB = C.PXL8_OP_SUB +procgen.OP_VORONOI_CELL = C.PXL8_OP_VORONOI_CELL +procgen.OP_VORONOI_EDGE = C.PXL8_OP_VORONOI_EDGE +procgen.OP_VORONOI_ID = C.PXL8_OP_VORONOI_ID + +local Graph = {} +Graph.__index = Graph + +function Graph.new(capacity) + capacity = capacity or 64 + local ptr = C.pxl8_graph_create(capacity) + if ptr == nil then + return nil + end + return setmetatable({ _ptr = ptr }, Graph) +end + +function Graph:destroy() + if self._ptr then + C.pxl8_graph_destroy(self._ptr) + self._ptr = nil + end +end + +function Graph:clear() + C.pxl8_graph_clear(self._ptr) +end + +function Graph:add_node(op, in0, in1, in2, in3, param) + return C.pxl8_graph_add_node(self._ptr, op, in0 or 0, in1 or 0, in2 or 0, in3 or 0, param or 0) +end + +function Graph:set_output(reg) + C.pxl8_graph_set_output(self._ptr, reg) +end + +function Graph:set_seed(seed) + C.pxl8_graph_set_seed(self._ptr, seed) +end + +function Graph:eval_texture(width, height) + width = width or 64 + height = height or 64 + local buffer = ffi.new("u8[?]", width * height) + C.pxl8_graph_eval_texture(self._ptr, buffer, width, height) + local tex_id = C.pxl8_gfx_create_texture(core.gfx, buffer, width, height) + if tex_id < 0 then + return nil + end + return tex_id +end + +procgen.Graph = Graph + +function procgen.create_graph(capacity) + return Graph.new(capacity) +end + +return procgen diff --git a/src/lua/pxl8/world.lua b/src/lua/pxl8/world.lua index 589917e..d1c016f 100644 --- a/src/lua/pxl8/world.lua +++ b/src/lua/pxl8/world.lua @@ -85,36 +85,14 @@ function World:resolve_collision(from_x, from_y, from_z, to_x, to_y, to_z, radiu return result.x, result.y, result.z end +function World:set_wireframe(enabled) + C.pxl8_world_set_wireframe(self._ptr, enabled) +end + function World:unload() C.pxl8_world_unload(self._ptr) end world.World = World -function world.procgen_tex(params) - local width = params.width or 64 - local height = params.height or 64 - local buffer = ffi.new("u8[?]", width * height) - local tex_params = ffi.new("pxl8_procgen_tex_params") - - local name = params.name or "" - ffi.copy(tex_params.name, name, math.min(#name, 15)) - - tex_params.seed = params.seed or 0 - tex_params.width = width - tex_params.height = height - tex_params.scale = params.scale or 1.0 - tex_params.roughness = params.roughness or 0.0 - tex_params.base_color = params.base_color or 0 - tex_params.variation = params.variation or 0 - - C.pxl8_procgen_tex(buffer, tex_params) - - local tex_id = C.pxl8_gfx_create_texture(core.gfx, buffer, width, height) - if tex_id < 0 then - return nil - end - return tex_id -end - return world diff --git a/src/math/pxl8_math.c b/src/math/pxl8_math.c index 4b5ce26..bd85905 100644 --- a/src/math/pxl8_math.c +++ b/src/math/pxl8_math.c @@ -1,5 +1,14 @@ #include "pxl8_math.h" +u32 pxl8_hash32(u32 x) { + x ^= x >> 16; + x *= 0x85EBCA6Bu; + x ^= x >> 13; + x *= 0xC2B2AE35u; + x ^= x >> 16; + return x; +} + pxl8_vec2 pxl8_vec2_add(pxl8_vec2 a, pxl8_vec2 b) { return (pxl8_vec2){ .x = a.x + b.x, @@ -101,7 +110,7 @@ pxl8_mat4 pxl8_mat4_identity(void) { return mat; } -pxl8_mat4 pxl8_mat4_mul(pxl8_mat4 a, pxl8_mat4 b) { +pxl8_mat4 pxl8_mat4_multiply(pxl8_mat4 a, pxl8_mat4 b) { pxl8_mat4 mat = {0}; for (i32 col = 0; col < 4; col++) { @@ -117,7 +126,7 @@ pxl8_mat4 pxl8_mat4_mul(pxl8_mat4 a, pxl8_mat4 b) { return mat; } -pxl8_vec4 pxl8_mat4_mul_vec4(pxl8_mat4 m, pxl8_vec4 v) { +pxl8_vec4 pxl8_mat4_multiply_vec4(pxl8_mat4 m, pxl8_vec4 v) { return (pxl8_vec4){ .x = m.m[0] * v.x + m.m[4] * v.y + m.m[8] * v.z + m.m[12] * v.w, .y = m.m[1] * v.x + m.m[5] * v.y + m.m[9] * v.z + m.m[13] * v.w, @@ -126,7 +135,7 @@ pxl8_vec4 pxl8_mat4_mul_vec4(pxl8_mat4 m, pxl8_vec4 v) { }; } -pxl8_vec3 pxl8_mat4_mul_vec3(pxl8_mat4 m, pxl8_vec3 v) { +pxl8_vec3 pxl8_mat4_multiply_vec3(pxl8_mat4 m, pxl8_vec3 v) { return (pxl8_vec3){ .x = m.m[0] * v.x + m.m[4] * v.y + m.m[8] * v.z, .y = m.m[1] * v.x + m.m[5] * v.y + m.m[9] * v.z, @@ -193,7 +202,7 @@ pxl8_mat4 pxl8_mat4_scale(f32 x, f32 y, f32 z) { return mat; } -pxl8_mat4 pxl8_mat4_ortho(f32 left, f32 right, f32 bottom, f32 top, f32 near, f32 far) { +pxl8_mat4 pxl8_mat4_orthographic(f32 left, f32 right, f32 bottom, f32 top, f32 near, f32 far) { pxl8_mat4 mat = {0}; mat.m[0] = 2.0f / (right - left); @@ -246,15 +255,15 @@ pxl8_frustum pxl8_frustum_from_matrix(pxl8_mat4 vp) { pxl8_frustum frustum; const f32* m = vp.m; - frustum.planes[0].normal.x = m[3] - m[0]; - frustum.planes[0].normal.y = m[7] - m[4]; - frustum.planes[0].normal.z = m[11] - m[8]; - frustum.planes[0].distance = m[15] - m[12]; + frustum.planes[0].normal.x = m[3] + m[0]; + frustum.planes[0].normal.y = m[7] + m[4]; + frustum.planes[0].normal.z = m[11] + m[8]; + frustum.planes[0].distance = m[15] + m[12]; - frustum.planes[1].normal.x = m[3] + m[0]; - frustum.planes[1].normal.y = m[7] + m[4]; - frustum.planes[1].normal.z = m[11] + m[8]; - frustum.planes[1].distance = m[15] + m[12]; + frustum.planes[1].normal.x = m[3] - m[0]; + frustum.planes[1].normal.y = m[7] - m[4]; + frustum.planes[1].normal.z = m[11] - m[8]; + frustum.planes[1].distance = m[15] - m[12]; frustum.planes[2].normal.x = m[3] + m[1]; frustum.planes[2].normal.y = m[7] + m[5]; @@ -266,15 +275,15 @@ pxl8_frustum pxl8_frustum_from_matrix(pxl8_mat4 vp) { frustum.planes[3].normal.z = m[11] - m[9]; frustum.planes[3].distance = m[15] - m[13]; - frustum.planes[4].normal.x = m[3] - m[2]; - frustum.planes[4].normal.y = m[7] - m[6]; - frustum.planes[4].normal.z = m[11] - m[10]; - frustum.planes[4].distance = m[15] - m[14]; + frustum.planes[4].normal.x = m[3] + m[2]; + frustum.planes[4].normal.y = m[7] + m[6]; + frustum.planes[4].normal.z = m[11] + m[10]; + frustum.planes[4].distance = m[15] + m[14]; - frustum.planes[5].normal.x = m[3] + m[2]; - frustum.planes[5].normal.y = m[7] + m[6]; - frustum.planes[5].normal.z = m[11] + m[10]; - frustum.planes[5].distance = m[15] + m[14]; + frustum.planes[5].normal.x = m[3] - m[2]; + frustum.planes[5].normal.y = m[7] - m[6]; + frustum.planes[5].normal.z = m[11] - m[10]; + frustum.planes[5].distance = m[15] - m[14]; for (i32 i = 0; i < 6; i++) { f32 len = pxl8_vec3_length(frustum.planes[i].normal); @@ -289,19 +298,21 @@ pxl8_frustum pxl8_frustum_from_matrix(pxl8_mat4 vp) { } bool pxl8_frustum_test_aabb(const pxl8_frustum* frustum, pxl8_vec3 min, pxl8_vec3 max) { + const f32 FRUSTUM_EPSILON = -75.0f; + for (i32 i = 0; i < 6; i++) { pxl8_vec3 normal = frustum->planes[i].normal; f32 d = frustum->planes[i].distance; pxl8_vec3 p_vertex = { - (normal.x >= 0.0f) ? max.x : min.x, - (normal.y >= 0.0f) ? max.y : min.y, - (normal.z >= 0.0f) ? max.z : min.z + (normal.x > 0.0f) ? max.x : min.x, + (normal.y > 0.0f) ? max.y : min.y, + (normal.z > 0.0f) ? max.z : min.z }; f32 p_dist = pxl8_vec3_dot(normal, p_vertex) + d; - if (p_dist < 0.0f) { + if (p_dist < FRUSTUM_EPSILON) { return false; } } diff --git a/src/math/pxl8_math.h b/src/math/pxl8_math.h index 26dcec8..df4ff1b 100644 --- a/src/math/pxl8_math.h +++ b/src/math/pxl8_math.h @@ -4,16 +4,49 @@ #include "pxl8_types.h" +#if defined(__x86_64__) || defined(_M_X64) + #include +#elif defined(__aarch64__) || defined(_M_ARM64) + #include +#endif + #define PXL8_PI 3.14159265358979323846f #define PXL8_TAU (PXL8_PI * 2.0f) static inline f32 pxl8_fast_inv_sqrt(f32 x) { +#if defined(__x86_64__) || defined(_M_X64) + __m128 v = _mm_set_ss(x); + v = _mm_rsqrt_ss(v); + return _mm_cvtss_f32(v); +#elif defined(__aarch64__) || defined(_M_ARM64) + float32x2_t v = vdup_n_f32(x); + float32x2_t est = vrsqrte_f32(v); + est = vmul_f32(est, vrsqrts_f32(vmul_f32(v, est), est)); + return vget_lane_f32(est, 0); +#else f32 half = 0.5f * x; i32 i = *(i32*)&x; i = 0x5f3759df - (i >> 1); x = *(f32*)&i; x = x * (1.5f - half * x * x); return x; +#endif +} + +static inline f32 pxl8_fast_rcp(f32 x) { +#if defined(__x86_64__) || defined(_M_X64) + __m128 v = _mm_set_ss(x); + __m128 rcp = _mm_rcp_ss(v); + rcp = _mm_add_ss(rcp, _mm_mul_ss(rcp, _mm_sub_ss(_mm_set_ss(1.0f), _mm_mul_ss(v, rcp)))); + return _mm_cvtss_f32(rcp); +#elif defined(__aarch64__) || defined(_M_ARM64) + float32x2_t v = vdup_n_f32(x); + float32x2_t est = vrecpe_f32(v); + est = vmul_f32(est, vrecps_f32(v, est)); + return vget_lane_f32(est, 0); +#else + return 1.0f / x; +#endif } typedef struct pxl8_vec2 { @@ -33,18 +66,27 @@ typedef struct pxl8_mat4 { } pxl8_mat4; typedef struct pxl8_plane { - pxl8_vec3 normal; f32 distance; + pxl8_vec3 normal; } pxl8_plane; typedef struct pxl8_frustum { pxl8_plane planes[6]; } pxl8_frustum; +typedef struct pxl8_projected_point { + f32 depth; + i32 x; + i32 y; + bool visible; +} pxl8_projected_point; + #ifdef __cplusplus extern "C" { #endif +u32 pxl8_hash32(u32 x); + pxl8_vec2 pxl8_vec2_add(pxl8_vec2 a, pxl8_vec2 b); f32 pxl8_vec2_dot(pxl8_vec2 a, pxl8_vec2 b); f32 pxl8_vec2_length(pxl8_vec2 v); @@ -63,10 +105,10 @@ pxl8_vec3 pxl8_vec3_sub(pxl8_vec3 a, pxl8_vec3 b); pxl8_mat4 pxl8_mat4_identity(void); pxl8_mat4 pxl8_mat4_lookat(pxl8_vec3 eye, pxl8_vec3 center, pxl8_vec3 up); -pxl8_mat4 pxl8_mat4_mul(pxl8_mat4 a, pxl8_mat4 b); -pxl8_vec3 pxl8_mat4_mul_vec3(pxl8_mat4 m, pxl8_vec3 v); -pxl8_vec4 pxl8_mat4_mul_vec4(pxl8_mat4 m, pxl8_vec4 v); -pxl8_mat4 pxl8_mat4_ortho(f32 left, f32 right, f32 bottom, f32 top, f32 near, f32 far); +pxl8_mat4 pxl8_mat4_multiply(pxl8_mat4 a, pxl8_mat4 b); +pxl8_vec3 pxl8_mat4_multiply_vec3(pxl8_mat4 m, pxl8_vec3 v); +pxl8_vec4 pxl8_mat4_multiply_vec4(pxl8_mat4 m, pxl8_vec4 v); +pxl8_mat4 pxl8_mat4_orthographic(f32 left, f32 right, f32 bottom, f32 top, f32 near, f32 far); pxl8_mat4 pxl8_mat4_perspective(f32 fov, f32 aspect, f32 near, f32 far); pxl8_mat4 pxl8_mat4_rotate_x(f32 angle); pxl8_mat4 pxl8_mat4_rotate_y(f32 angle); diff --git a/src/math/pxl8_simd.h b/src/math/pxl8_simd.h deleted file mode 100644 index 18490fd..0000000 --- a/src/math/pxl8_simd.h +++ /dev/null @@ -1,291 +0,0 @@ -#pragma once - -#include "pxl8_types.h" - -#if defined(__x86_64__) || defined(_M_X64) - #define PXL8_SIMD_SSE2 1 - #include -#elif defined(__aarch64__) || defined(_M_ARM64) - #define PXL8_SIMD_NEON 1 - #include -#else - #define PXL8_SIMD_SCALAR 1 -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -#if defined(PXL8_SIMD_SSE2) - -typedef struct { __m128 v; } pxl8_f32x4; -typedef struct { __m128i v; } pxl8_i32x4; -typedef struct { __m128i v; } pxl8_u16x8; - -static inline pxl8_f32x4 pxl8_f32x4_splat(f32 x) { - return (pxl8_f32x4){ _mm_set1_ps(x) }; -} - -static inline pxl8_f32x4 pxl8_f32x4_new(f32 a, f32 b, f32 c, f32 d) { - return (pxl8_f32x4){ _mm_set_ps(d, c, b, a) }; -} - -static inline pxl8_f32x4 pxl8_f32x4_add(pxl8_f32x4 a, pxl8_f32x4 b) { - return (pxl8_f32x4){ _mm_add_ps(a.v, b.v) }; -} - -static inline pxl8_f32x4 pxl8_f32x4_sub(pxl8_f32x4 a, pxl8_f32x4 b) { - return (pxl8_f32x4){ _mm_sub_ps(a.v, b.v) }; -} - -static inline pxl8_f32x4 pxl8_f32x4_mul(pxl8_f32x4 a, pxl8_f32x4 b) { - return (pxl8_f32x4){ _mm_mul_ps(a.v, b.v) }; -} - -static inline pxl8_f32x4 pxl8_f32x4_div(pxl8_f32x4 a, pxl8_f32x4 b) { - return (pxl8_f32x4){ _mm_div_ps(a.v, b.v) }; -} - -static inline pxl8_f32x4 pxl8_f32x4_min(pxl8_f32x4 a, pxl8_f32x4 b) { - return (pxl8_f32x4){ _mm_min_ps(a.v, b.v) }; -} - -static inline pxl8_f32x4 pxl8_f32x4_max(pxl8_f32x4 a, pxl8_f32x4 b) { - return (pxl8_f32x4){ _mm_max_ps(a.v, b.v) }; -} - -static inline pxl8_f32x4 pxl8_f32x4_cmplt(pxl8_f32x4 a, pxl8_f32x4 b) { - return (pxl8_f32x4){ _mm_cmplt_ps(a.v, b.v) }; -} - -static inline i32 pxl8_f32x4_movemask(pxl8_f32x4 a) { - return _mm_movemask_ps(a.v); -} - -static inline pxl8_i32x4 pxl8_f32x4_to_i32x4(pxl8_f32x4 a) { - return (pxl8_i32x4){ _mm_cvttps_epi32(a.v) }; -} - -static inline void pxl8_f32x4_store(pxl8_f32x4 a, f32* out) { - _mm_storeu_ps(out, a.v); -} - -static inline pxl8_i32x4 pxl8_i32x4_splat(i32 x) { - return (pxl8_i32x4){ _mm_set1_epi32(x) }; -} - -static inline pxl8_i32x4 pxl8_i32x4_slli(pxl8_i32x4 a, i32 n) { - return (pxl8_i32x4){ _mm_slli_epi32(a.v, n) }; -} - -static inline pxl8_i32x4 pxl8_i32x4_srai(pxl8_i32x4 a, i32 n) { - return (pxl8_i32x4){ _mm_srai_epi32(a.v, n) }; -} - -static inline pxl8_i32x4 pxl8_i32x4_and(pxl8_i32x4 a, pxl8_i32x4 b) { - return (pxl8_i32x4){ _mm_and_si128(a.v, b.v) }; -} - -static inline pxl8_i32x4 pxl8_i32x4_or(pxl8_i32x4 a, pxl8_i32x4 b) { - return (pxl8_i32x4){ _mm_or_si128(a.v, b.v) }; -} - -static inline void pxl8_i32x4_store(pxl8_i32x4 a, i32* out) { - _mm_storeu_si128((__m128i*)out, a.v); -} - -static inline pxl8_u16x8 pxl8_u16x8_cmplt(pxl8_u16x8 a, pxl8_u16x8 b) { - return (pxl8_u16x8){ _mm_cmplt_epi16(a.v, b.v) }; -} - -static inline pxl8_u16x8 pxl8_u16x8_blend(pxl8_u16x8 a, pxl8_u16x8 b, pxl8_u16x8 mask) { - __m128i not_mask = _mm_andnot_si128(mask.v, a.v); - __m128i and_mask = _mm_and_si128(mask.v, b.v); - return (pxl8_u16x8){ _mm_or_si128(not_mask, and_mask) }; -} - -static inline i32 pxl8_u16x8_movemask(pxl8_u16x8 a) { - return _mm_movemask_epi8(a.v); -} - -#elif defined(PXL8_SIMD_NEON) - -typedef struct { float32x4_t v; } pxl8_f32x4; -typedef struct { int32x4_t v; } pxl8_i32x4; -typedef struct { uint16x8_t v; } pxl8_u16x8; - -static inline pxl8_f32x4 pxl8_f32x4_splat(f32 x) { - return (pxl8_f32x4){ vdupq_n_f32(x) }; -} - -static inline pxl8_f32x4 pxl8_f32x4_new(f32 a, f32 b, f32 c, f32 d) { - f32 arr[4] = {a, b, c, d}; - return (pxl8_f32x4){ vld1q_f32(arr) }; -} - -static inline pxl8_f32x4 pxl8_f32x4_add(pxl8_f32x4 a, pxl8_f32x4 b) { - return (pxl8_f32x4){ vaddq_f32(a.v, b.v) }; -} - -static inline pxl8_f32x4 pxl8_f32x4_sub(pxl8_f32x4 a, pxl8_f32x4 b) { - return (pxl8_f32x4){ vsubq_f32(a.v, b.v) }; -} - -static inline pxl8_f32x4 pxl8_f32x4_mul(pxl8_f32x4 a, pxl8_f32x4 b) { - return (pxl8_f32x4){ vmulq_f32(a.v, b.v) }; -} - -static inline pxl8_f32x4 pxl8_f32x4_div(pxl8_f32x4 a, pxl8_f32x4 b) { - return (pxl8_f32x4){ vdivq_f32(a.v, b.v) }; -} - -static inline pxl8_f32x4 pxl8_f32x4_min(pxl8_f32x4 a, pxl8_f32x4 b) { - return (pxl8_f32x4){ vminq_f32(a.v, b.v) }; -} - -static inline pxl8_f32x4 pxl8_f32x4_max(pxl8_f32x4 a, pxl8_f32x4 b) { - return (pxl8_f32x4){ vmaxq_f32(a.v, b.v) }; -} - -static inline pxl8_f32x4 pxl8_f32x4_cmplt(pxl8_f32x4 a, pxl8_f32x4 b) { - uint32x4_t cmp = vcltq_f32(a.v, b.v); - return (pxl8_f32x4){ vreinterpretq_f32_u32(cmp) }; -} - -static inline i32 pxl8_f32x4_movemask(pxl8_f32x4 a) { - uint32x4_t input = vreinterpretq_u32_f32(a.v); - static const i32 shifts[4] = {0, 1, 2, 3}; - uint32x4_t shifted = vshrq_n_u32(input, 31); - return vgetq_lane_u32(shifted, 0) | (vgetq_lane_u32(shifted, 1) << 1) | - (vgetq_lane_u32(shifted, 2) << 2) | (vgetq_lane_u32(shifted, 3) << 3); -} - -static inline pxl8_i32x4 pxl8_f32x4_to_i32x4(pxl8_f32x4 a) { - return (pxl8_i32x4){ vcvtq_s32_f32(a.v) }; -} - -static inline void pxl8_f32x4_store(pxl8_f32x4 a, f32* out) { - vst1q_f32(out, a.v); -} - -static inline pxl8_i32x4 pxl8_i32x4_splat(i32 x) { - return (pxl8_i32x4){ vdupq_n_s32(x) }; -} - -static inline pxl8_i32x4 pxl8_i32x4_slli(pxl8_i32x4 a, i32 n) { - return (pxl8_i32x4){ vshlq_s32(a.v, vdupq_n_s32(n)) }; -} - -static inline pxl8_i32x4 pxl8_i32x4_srai(pxl8_i32x4 a, i32 n) { - return (pxl8_i32x4){ vshlq_s32(a.v, vdupq_n_s32(-n)) }; -} - -static inline pxl8_i32x4 pxl8_i32x4_and(pxl8_i32x4 a, pxl8_i32x4 b) { - return (pxl8_i32x4){ vandq_s32(a.v, b.v) }; -} - -static inline pxl8_i32x4 pxl8_i32x4_or(pxl8_i32x4 a, pxl8_i32x4 b) { - return (pxl8_i32x4){ vorrq_s32(a.v, b.v) }; -} - -static inline void pxl8_i32x4_store(pxl8_i32x4 a, i32* out) { - vst1q_s32(out, a.v); -} - -#else - -typedef struct { f32 v[4]; } pxl8_f32x4; -typedef struct { i32 v[4]; } pxl8_i32x4; -typedef struct { u16 v[8]; } pxl8_u16x8; - -static inline pxl8_f32x4 pxl8_f32x4_splat(f32 x) { - return (pxl8_f32x4){{ x, x, x, x }}; -} - -static inline pxl8_f32x4 pxl8_f32x4_new(f32 a, f32 b, f32 c, f32 d) { - return (pxl8_f32x4){{ a, b, c, d }}; -} - -static inline pxl8_f32x4 pxl8_f32x4_add(pxl8_f32x4 a, pxl8_f32x4 b) { - return (pxl8_f32x4){{ a.v[0]+b.v[0], a.v[1]+b.v[1], a.v[2]+b.v[2], a.v[3]+b.v[3] }}; -} - -static inline pxl8_f32x4 pxl8_f32x4_sub(pxl8_f32x4 a, pxl8_f32x4 b) { - return (pxl8_f32x4){{ a.v[0]-b.v[0], a.v[1]-b.v[1], a.v[2]-b.v[2], a.v[3]-b.v[3] }}; -} - -static inline pxl8_f32x4 pxl8_f32x4_mul(pxl8_f32x4 a, pxl8_f32x4 b) { - return (pxl8_f32x4){{ a.v[0]*b.v[0], a.v[1]*b.v[1], a.v[2]*b.v[2], a.v[3]*b.v[3] }}; -} - -static inline pxl8_f32x4 pxl8_f32x4_div(pxl8_f32x4 a, pxl8_f32x4 b) { - return (pxl8_f32x4){{ a.v[0]/b.v[0], a.v[1]/b.v[1], a.v[2]/b.v[2], a.v[3]/b.v[3] }}; -} - -static inline pxl8_f32x4 pxl8_f32x4_min(pxl8_f32x4 a, pxl8_f32x4 b) { - return (pxl8_f32x4){{ - a.v[0]b.v[0]?a.v[0]:b.v[0], a.v[1]>b.v[1]?a.v[1]:b.v[1], - a.v[2]>b.v[2]?a.v[2]:b.v[2], a.v[3]>b.v[3]?a.v[3]:b.v[3] - }}; -} - -static inline pxl8_f32x4 pxl8_f32x4_cmplt(pxl8_f32x4 a, pxl8_f32x4 b) { - pxl8_f32x4 r; - u32* rv = (u32*)r.v; - rv[0] = a.v[0] < b.v[0] ? 0xFFFFFFFF : 0; - rv[1] = a.v[1] < b.v[1] ? 0xFFFFFFFF : 0; - rv[2] = a.v[2] < b.v[2] ? 0xFFFFFFFF : 0; - rv[3] = a.v[3] < b.v[3] ? 0xFFFFFFFF : 0; - return r; -} - -static inline i32 pxl8_f32x4_movemask(pxl8_f32x4 a) { - u32* av = (u32*)a.v; - return ((av[0] >> 31) & 1) | ((av[1] >> 31) & 1) << 1 | - ((av[2] >> 31) & 1) << 2 | ((av[3] >> 31) & 1) << 3; -} - -static inline pxl8_i32x4 pxl8_f32x4_to_i32x4(pxl8_f32x4 a) { - return (pxl8_i32x4){{ (i32)a.v[0], (i32)a.v[1], (i32)a.v[2], (i32)a.v[3] }}; -} - -static inline void pxl8_f32x4_store(pxl8_f32x4 a, f32* out) { - out[0] = a.v[0]; out[1] = a.v[1]; out[2] = a.v[2]; out[3] = a.v[3]; -} - -static inline pxl8_i32x4 pxl8_i32x4_splat(i32 x) { - return (pxl8_i32x4){{ x, x, x, x }}; -} - -static inline pxl8_i32x4 pxl8_i32x4_slli(pxl8_i32x4 a, i32 n) { - return (pxl8_i32x4){{ a.v[0]<>n, a.v[1]>>n, a.v[2]>>n, a.v[3]>>n }}; -} - -static inline pxl8_i32x4 pxl8_i32x4_and(pxl8_i32x4 a, pxl8_i32x4 b) { - return (pxl8_i32x4){{ a.v[0]&b.v[0], a.v[1]&b.v[1], a.v[2]&b.v[2], a.v[3]&b.v[3] }}; -} - -static inline pxl8_i32x4 pxl8_i32x4_or(pxl8_i32x4 a, pxl8_i32x4 b) { - return (pxl8_i32x4){{ a.v[0]|b.v[0], a.v[1]|b.v[1], a.v[2]|b.v[2], a.v[3]|b.v[3] }}; -} - -static inline void pxl8_i32x4_store(pxl8_i32x4 a, i32* out) { - out[0] = a.v[0]; out[1] = a.v[1]; out[2] = a.v[2]; out[3] = a.v[3]; -} - -#endif - -#ifdef __cplusplus -} -#endif diff --git a/src/net/pxl8_net.c b/src/net/pxl8_net.c index e5cba62..8ea7440 100644 --- a/src/net/pxl8_net.c +++ b/src/net/pxl8_net.c @@ -1,4 +1,5 @@ #include "pxl8_net.h" +#include "pxl8_mem.h" #include #include @@ -94,7 +95,7 @@ bool pxl8_net_connected(const pxl8_net* net) { } pxl8_net* pxl8_net_create(const pxl8_net_config* config) { - pxl8_net* net = calloc(1, sizeof(pxl8_net)); + pxl8_net* net = pxl8_calloc(1, sizeof(pxl8_net)); if (!net) return NULL; net->mode = config->mode; @@ -116,7 +117,7 @@ pxl8_net* pxl8_net_create(const pxl8_net_config* config) { void pxl8_net_destroy(pxl8_net* net) { if (!net) return; pxl8_net_disconnect(net); - free(net); + pxl8_free(net); } void pxl8_net_disconnect(pxl8_net* net) { @@ -203,11 +204,11 @@ u64 pxl8_net_player_id(const pxl8_net* net) { bool pxl8_net_poll(pxl8_net* net) { if (!net || !net->connected) return false; - size_t len = pxl8_net_recv(net, net->recv_buf, sizeof(net->recv_buf)); + usize len = pxl8_net_recv(net, net->recv_buf, sizeof(net->recv_buf)); if (len < sizeof(pxl8_msg_header)) return false; pxl8_msg_header hdr; - size_t offset = pxl8_protocol_deserialize_header(net->recv_buf, len, &hdr); + usize offset = pxl8_protocol_deserialize_header(net->recv_buf, len, &hdr); if (hdr.type != PXL8_MSG_SNAPSHOT) return false; pxl8_snapshot_header snap; @@ -243,17 +244,17 @@ void pxl8_net_predicted_tick_set(pxl8_net* net, u64 tick) { net->predicted_tick = tick; } -size_t pxl8_net_recv(pxl8_net* net, u8* buf, size_t len) { +usize pxl8_net_recv(pxl8_net* net, u8* buf, usize len) { if (!net || !net->connected) return 0; struct sockaddr_in from; socklen_t from_len = sizeof(from); ssize_t received = recvfrom(net->sock, (char*)buf, len, 0, (struct sockaddr*)&from, &from_len); - return (received > 0) ? (size_t)received : 0; + return (received > 0) ? (usize)received : 0; } -pxl8_result pxl8_net_send(pxl8_net* net, const u8* data, size_t len) { +pxl8_result pxl8_net_send(pxl8_net* net, const u8* data, usize len) { if (!net || !net->connected) return PXL8_ERROR_INVALID_ARGUMENT; ssize_t sent = sendto(net->sock, (const char*)data, len, 0, @@ -273,7 +274,7 @@ pxl8_result pxl8_net_send_command(pxl8_net* net, const pxl8_command_msg* cmd) { .sequence = 0 }; - size_t offset = pxl8_protocol_serialize_header(&hdr, buf, sizeof(buf)); + usize offset = pxl8_protocol_serialize_header(&hdr, buf, sizeof(buf)); offset += pxl8_protocol_serialize_command(cmd, buf + offset, sizeof(buf) - offset); return pxl8_net_send(net, buf, offset); @@ -290,7 +291,7 @@ pxl8_result pxl8_net_send_input(pxl8_net* net, const pxl8_input_msg* input) { .sequence = 0 }; - size_t offset = pxl8_protocol_serialize_header(&hdr, buf, sizeof(buf)); + usize offset = pxl8_protocol_serialize_header(&hdr, buf, sizeof(buf)); offset += pxl8_protocol_serialize_input(input, buf + offset, sizeof(buf) - offset); return pxl8_net_send(net, buf, offset); diff --git a/src/net/pxl8_net.h b/src/net/pxl8_net.h index d14ea10..cf81270 100644 --- a/src/net/pxl8_net.h +++ b/src/net/pxl8_net.h @@ -41,8 +41,8 @@ u64 pxl8_net_player_id(const pxl8_net* net); bool pxl8_net_poll(pxl8_net* net); u8* pxl8_net_predicted_state(pxl8_net* net); void pxl8_net_predicted_tick_set(pxl8_net* net, u64 tick); -size_t pxl8_net_recv(pxl8_net* net, u8* buf, size_t len); -pxl8_result pxl8_net_send(pxl8_net* net, const u8* data, size_t len); +usize pxl8_net_recv(pxl8_net* net, u8* buf, usize len); +pxl8_result pxl8_net_send(pxl8_net* net, const u8* data, usize len); pxl8_result pxl8_net_send_command(pxl8_net* net, const pxl8_command_msg* cmd); pxl8_result pxl8_net_send_input(pxl8_net* net, const pxl8_input_msg* input); const pxl8_snapshot_header* pxl8_net_snapshot(const pxl8_net* net); diff --git a/src/net/pxl8_protocol.c b/src/net/pxl8_protocol.c index 3c4a48d..cb74099 100644 --- a/src/net/pxl8_protocol.c +++ b/src/net/pxl8_protocol.c @@ -1,7 +1,7 @@ #include "pxl8_protocol.h" #include "pxl8_bytes.h" -size_t pxl8_protocol_serialize_header(const pxl8_msg_header* msg, u8* buf, size_t len) { +usize pxl8_protocol_serialize_header(const pxl8_msg_header* msg, u8* buf, usize len) { if (len < sizeof(pxl8_msg_header)) return 0; pxl8_write_stream s = pxl8_write_stream_create(buf, (u32)len); pxl8_write_u32_be(&s, msg->sequence); @@ -11,7 +11,7 @@ size_t pxl8_protocol_serialize_header(const pxl8_msg_header* msg, u8* buf, size_ return s.offset; } -size_t pxl8_protocol_deserialize_header(const u8* buf, size_t len, pxl8_msg_header* msg) { +usize pxl8_protocol_deserialize_header(const u8* buf, usize len, pxl8_msg_header* msg) { if (len < sizeof(pxl8_msg_header)) return 0; pxl8_stream s = pxl8_stream_create(buf, (u32)len); msg->sequence = pxl8_read_u32_be(&s); @@ -21,7 +21,7 @@ size_t pxl8_protocol_deserialize_header(const u8* buf, size_t len, pxl8_msg_head return s.offset; } -size_t pxl8_protocol_serialize_input(const pxl8_input_msg* msg, u8* buf, size_t len) { +usize pxl8_protocol_serialize_input(const pxl8_input_msg* msg, u8* buf, usize len) { if (len < sizeof(pxl8_input_msg)) return 0; pxl8_write_stream s = pxl8_write_stream_create(buf, (u32)len); pxl8_write_u32_be(&s, msg->buttons); @@ -35,7 +35,7 @@ size_t pxl8_protocol_serialize_input(const pxl8_input_msg* msg, u8* buf, size_t return s.offset; } -size_t pxl8_protocol_deserialize_input(const u8* buf, size_t len, pxl8_input_msg* msg) { +usize pxl8_protocol_deserialize_input(const u8* buf, usize len, pxl8_input_msg* msg) { if (len < sizeof(pxl8_input_msg)) return 0; pxl8_stream s = pxl8_stream_create(buf, (u32)len); msg->buttons = pxl8_read_u32_be(&s); @@ -49,7 +49,7 @@ size_t pxl8_protocol_deserialize_input(const u8* buf, size_t len, pxl8_input_msg return s.offset; } -size_t pxl8_protocol_serialize_command(const pxl8_command_msg* msg, u8* buf, size_t len) { +usize pxl8_protocol_serialize_command(const pxl8_command_msg* msg, u8* buf, usize len) { if (len < sizeof(pxl8_command_msg)) return 0; pxl8_write_stream s = pxl8_write_stream_create(buf, (u32)len); pxl8_write_u16_be(&s, msg->cmd_type); @@ -59,7 +59,7 @@ size_t pxl8_protocol_serialize_command(const pxl8_command_msg* msg, u8* buf, siz return s.offset; } -size_t pxl8_protocol_deserialize_command(const u8* buf, size_t len, pxl8_command_msg* msg) { +usize pxl8_protocol_deserialize_command(const u8* buf, usize len, pxl8_command_msg* msg) { if (len < sizeof(pxl8_command_msg)) return 0; pxl8_stream s = pxl8_stream_create(buf, (u32)len); msg->cmd_type = pxl8_read_u16_be(&s); @@ -69,7 +69,7 @@ size_t pxl8_protocol_deserialize_command(const u8* buf, size_t len, pxl8_command return s.offset; } -size_t pxl8_protocol_serialize_entity_state(const pxl8_entity_state* state, u8* buf, size_t len) { +usize pxl8_protocol_serialize_entity_state(const pxl8_entity_state* state, u8* buf, usize len) { if (len < sizeof(pxl8_entity_state)) return 0; pxl8_write_stream s = pxl8_write_stream_create(buf, (u32)len); pxl8_write_u64_be(&s, state->entity_id); @@ -77,7 +77,7 @@ size_t pxl8_protocol_serialize_entity_state(const pxl8_entity_state* state, u8* return s.offset; } -size_t pxl8_protocol_deserialize_entity_state(const u8* buf, size_t len, pxl8_entity_state* state) { +usize pxl8_protocol_deserialize_entity_state(const u8* buf, usize len, pxl8_entity_state* state) { if (len < sizeof(pxl8_entity_state)) return 0; pxl8_stream s = pxl8_stream_create(buf, (u32)len); state->entity_id = pxl8_read_u64_be(&s); @@ -85,7 +85,7 @@ size_t pxl8_protocol_deserialize_entity_state(const u8* buf, size_t len, pxl8_en return s.offset; } -size_t pxl8_protocol_serialize_event(const pxl8_event_msg* msg, u8* buf, size_t len) { +usize pxl8_protocol_serialize_event(const pxl8_event_msg* msg, u8* buf, usize len) { if (len < sizeof(pxl8_event_msg)) return 0; pxl8_write_stream s = pxl8_write_stream_create(buf, (u32)len); pxl8_write_u8(&s, msg->event_type); @@ -93,7 +93,7 @@ size_t pxl8_protocol_serialize_event(const pxl8_event_msg* msg, u8* buf, size_t return s.offset; } -size_t pxl8_protocol_deserialize_event(const u8* buf, size_t len, pxl8_event_msg* msg) { +usize pxl8_protocol_deserialize_event(const u8* buf, usize len, pxl8_event_msg* msg) { if (len < sizeof(pxl8_event_msg)) return 0; pxl8_stream s = pxl8_stream_create(buf, (u32)len); msg->event_type = pxl8_read_u8(&s); @@ -101,7 +101,7 @@ size_t pxl8_protocol_deserialize_event(const u8* buf, size_t len, pxl8_event_msg return s.offset; } -size_t pxl8_protocol_serialize_snapshot_header(const pxl8_snapshot_header* hdr, u8* buf, size_t len) { +usize pxl8_protocol_serialize_snapshot_header(const pxl8_snapshot_header* hdr, u8* buf, usize len) { if (len < sizeof(pxl8_snapshot_header)) return 0; pxl8_write_stream s = pxl8_write_stream_create(buf, (u32)len); pxl8_write_u16_be(&s, hdr->entity_count); @@ -112,7 +112,7 @@ size_t pxl8_protocol_serialize_snapshot_header(const pxl8_snapshot_header* hdr, return s.offset; } -size_t pxl8_protocol_deserialize_snapshot_header(const u8* buf, size_t len, pxl8_snapshot_header* hdr) { +usize pxl8_protocol_deserialize_snapshot_header(const u8* buf, usize len, pxl8_snapshot_header* hdr) { if (len < sizeof(pxl8_snapshot_header)) return 0; pxl8_stream s = pxl8_stream_create(buf, (u32)len); hdr->entity_count = pxl8_read_u16_be(&s); diff --git a/src/net/pxl8_protocol.h b/src/net/pxl8_protocol.h index 78a4207..696a7ad 100644 --- a/src/net/pxl8_protocol.h +++ b/src/net/pxl8_protocol.h @@ -70,23 +70,23 @@ typedef struct pxl8_snapshot_header { f32 time; } pxl8_snapshot_header; -size_t pxl8_protocol_serialize_header(const pxl8_msg_header* msg, u8* buf, size_t len); -size_t pxl8_protocol_deserialize_header(const u8* buf, size_t len, pxl8_msg_header* msg); +usize pxl8_protocol_serialize_header(const pxl8_msg_header* msg, u8* buf, usize len); +usize pxl8_protocol_deserialize_header(const u8* buf, usize len, pxl8_msg_header* msg); -size_t pxl8_protocol_serialize_input(const pxl8_input_msg* msg, u8* buf, size_t len); -size_t pxl8_protocol_deserialize_input(const u8* buf, size_t len, pxl8_input_msg* msg); +usize pxl8_protocol_serialize_input(const pxl8_input_msg* msg, u8* buf, usize len); +usize pxl8_protocol_deserialize_input(const u8* buf, usize len, pxl8_input_msg* msg); -size_t pxl8_protocol_serialize_command(const pxl8_command_msg* msg, u8* buf, size_t len); -size_t pxl8_protocol_deserialize_command(const u8* buf, size_t len, pxl8_command_msg* msg); +usize pxl8_protocol_serialize_command(const pxl8_command_msg* msg, u8* buf, usize len); +usize pxl8_protocol_deserialize_command(const u8* buf, usize len, pxl8_command_msg* msg); -size_t pxl8_protocol_serialize_entity_state(const pxl8_entity_state* state, u8* buf, size_t len); -size_t pxl8_protocol_deserialize_entity_state(const u8* buf, size_t len, pxl8_entity_state* state); +usize pxl8_protocol_serialize_entity_state(const pxl8_entity_state* state, u8* buf, usize len); +usize pxl8_protocol_deserialize_entity_state(const u8* buf, usize len, pxl8_entity_state* state); -size_t pxl8_protocol_serialize_event(const pxl8_event_msg* msg, u8* buf, size_t len); -size_t pxl8_protocol_deserialize_event(const u8* buf, size_t len, pxl8_event_msg* msg); +usize pxl8_protocol_serialize_event(const pxl8_event_msg* msg, u8* buf, usize len); +usize pxl8_protocol_deserialize_event(const u8* buf, usize len, pxl8_event_msg* msg); -size_t pxl8_protocol_serialize_snapshot_header(const pxl8_snapshot_header* hdr, u8* buf, size_t len); -size_t pxl8_protocol_deserialize_snapshot_header(const u8* buf, size_t len, pxl8_snapshot_header* hdr); +usize pxl8_protocol_serialize_snapshot_header(const pxl8_snapshot_header* hdr, u8* buf, usize len); +usize pxl8_protocol_deserialize_snapshot_header(const u8* buf, usize len, pxl8_snapshot_header* hdr); #ifdef __cplusplus } diff --git a/src/procgen/pxl8_graph.c b/src/procgen/pxl8_graph.c new file mode 100644 index 0000000..ffb377c --- /dev/null +++ b/src/procgen/pxl8_graph.c @@ -0,0 +1,332 @@ +#include "pxl8_graph.h" + +#include +#include +#include + +#include "pxl8_math.h" +#include "pxl8_mem.h" + +static inline u32 hash2d(i32 x, i32 y, u32 seed) { + return pxl8_hash32((u32)x ^ ((u32)y * 2654435769u) ^ seed); +} + +static inline f32 hash2d_f(i32 x, i32 y, u32 seed) { + return (f32)hash2d(x, y, seed) / (f32)0xFFFFFFFF; +} + +static f32 gradient2d(i32 ix, i32 iy, f32 fx, f32 fy, u32 seed) { + u32 h = hash2d(ix, iy, seed); + f32 angle = (f32)h / (f32)0xFFFFFFFF * 6.28318530718f; + f32 gx = cosf(angle); + f32 gy = sinf(angle); + return gx * fx + gy * fy; +} + +static inline f32 smoothstep(f32 t) { + return t * t * (3.0f - 2.0f * t); +} + +static inline f32 lerp(f32 a, f32 b, f32 t) { + return a + t * (b - a); +} + +static f32 noise_value(f32 x, f32 y, f32 scale, u32 seed) { + f32 sx = x * scale; + f32 sy = y * scale; + i32 ix = (i32)floorf(sx); + i32 iy = (i32)floorf(sy); + f32 fx = sx - (f32)ix; + f32 fy = sy - (f32)iy; + f32 u = smoothstep(fx); + f32 v = smoothstep(fy); + + f32 n00 = hash2d_f(ix, iy, seed); + f32 n10 = hash2d_f(ix + 1, iy, seed); + f32 n01 = hash2d_f(ix, iy + 1, seed); + f32 n11 = hash2d_f(ix + 1, iy + 1, seed); + + return lerp(lerp(n00, n10, u), lerp(n01, n11, u), v); +} + +static f32 noise_perlin(f32 x, f32 y, f32 scale, u32 seed) { + f32 sx = x * scale; + f32 sy = y * scale; + i32 ix = (i32)floorf(sx); + i32 iy = (i32)floorf(sy); + f32 fx = sx - (f32)ix; + f32 fy = sy - (f32)iy; + f32 u = smoothstep(fx); + f32 v = smoothstep(fy); + + f32 n00 = gradient2d(ix, iy, fx, fy, seed); + f32 n10 = gradient2d(ix + 1, iy, fx - 1.0f, fy, seed); + f32 n01 = gradient2d(ix, iy + 1, fx, fy - 1.0f, seed); + f32 n11 = gradient2d(ix + 1, iy + 1, fx - 1.0f, fy - 1.0f, seed); + + f32 result = lerp(lerp(n00, n10, u), lerp(n01, n11, u), v); + return result * 0.5f + 0.5f; +} + +static f32 noise_fbm(f32 x, f32 y, i32 octaves, f32 scale, f32 persistence, u32 seed) { + f32 value = 0.0f; + f32 amplitude = 1.0f; + f32 frequency = scale; + f32 max_value = 0.0f; + + for (i32 i = 0; i < octaves; i++) { + value += amplitude * noise_perlin(x, y, frequency, seed + (u32)i * 1337); + max_value += amplitude; + amplitude *= persistence; + frequency *= 2.0f; + } + + return value / max_value; +} + +static f32 noise_ridged(f32 x, f32 y, i32 octaves, f32 scale, f32 persistence, u32 seed) { + f32 value = 0.0f; + f32 amplitude = 1.0f; + f32 frequency = scale; + f32 max_value = 0.0f; + + for (i32 i = 0; i < octaves; i++) { + f32 n = noise_perlin(x, y, frequency, seed + (u32)i * 1337); + n = 1.0f - fabsf(n * 2.0f - 1.0f); + value += amplitude * n; + max_value += amplitude; + amplitude *= persistence; + frequency *= 2.0f; + } + + return value / max_value; +} + +static f32 noise_turbulence(f32 x, f32 y, i32 octaves, f32 scale, f32 persistence, u32 seed) { + f32 value = 0.0f; + f32 amplitude = 1.0f; + f32 frequency = scale; + f32 max_value = 0.0f; + + for (i32 i = 0; i < octaves; i++) { + f32 n = noise_perlin(x, y, frequency, seed + (u32)i * 1337); + value += amplitude * fabsf(n * 2.0f - 1.0f); + max_value += amplitude; + amplitude *= persistence; + frequency *= 2.0f; + } + + return value / max_value; +} + +static void voronoi(f32 x, f32 y, f32 scale, u32 seed, f32* cell_dist, f32* edge_dist, i32* cell_id) { + f32 sx = x * scale; + f32 sy = y * scale; + i32 cx = (i32)floorf(sx); + i32 cy = (i32)floorf(sy); + f32 fx = sx - (f32)cx; + f32 fy = sy - (f32)cy; + + f32 min_dist = 1e30f; + f32 second_dist = 1e30f; + i32 closest_id = 0; + + for (i32 dy = -1; dy <= 1; dy++) { + for (i32 dx = -1; dx <= 1; dx++) { + i32 nx = cx + dx; + i32 ny = cy + dy; + u32 h = hash2d(nx, ny, seed); + f32 px = (f32)dx + (f32)(h & 0xFF) / 255.0f - 0.5f - fx; + f32 py = (f32)dy + (f32)((h >> 8) & 0xFF) / 255.0f - 0.5f - fy; + f32 dist = px * px + py * py; + + if (dist < min_dist) { + second_dist = min_dist; + min_dist = dist; + closest_id = (i32)h; + } else if (dist < second_dist) { + second_dist = dist; + } + } + } + + *cell_dist = sqrtf(min_dist); + *edge_dist = sqrtf(second_dist) - sqrtf(min_dist); + *cell_id = closest_id; +} + +static f32 gradient_linear(f32 x, f32 y, f32 angle) { + f32 dx = cosf(angle); + f32 dy = sinf(angle); + f32 result = x * dx + y * dy; + return fmaxf(0.0f, fminf(1.0f, result)); +} + +static f32 gradient_radial(f32 x, f32 y, f32 cx, f32 cy) { + f32 dx = x - cx; + f32 dy = y - cy; + return fmaxf(0.0f, fminf(1.0f, sqrtf(dx * dx + dy * dy))); +} + +pxl8_graph* pxl8_graph_create(u32 capacity) { + pxl8_graph* graph = pxl8_calloc(1, sizeof(pxl8_graph)); + if (!graph) return NULL; + + graph->nodes = pxl8_calloc(capacity, sizeof(pxl8_node)); + if (!graph->nodes) { + pxl8_free(graph); + return NULL; + } + + graph->capacity = capacity; + graph->count = 0; + graph->seed = 0; + graph->output_reg = 0; + return graph; +} + +void pxl8_graph_destroy(pxl8_graph* graph) { + if (!graph) return; + pxl8_free(graph->nodes); + pxl8_free(graph); +} + +void pxl8_graph_clear(pxl8_graph* graph) { + if (!graph) return; + graph->count = 0; + graph->output_reg = 0; +} + +u8 pxl8_graph_add_node(pxl8_graph* graph, pxl8_graph_op op, u8 in0, u8 in1, u8 in2, u8 in3, f32 param) { + if (!graph || graph->count >= graph->capacity) return 0; + + u8 out = (u8)(graph->count + 4); + pxl8_node* node = &graph->nodes[graph->count++]; + node->op = (u8)op; + node->out = out; + node->in[0] = in0; + node->in[1] = in1; + node->in[2] = in2; + node->in[3] = in3; + node->param = param; + + return out; +} + +void pxl8_graph_set_output(pxl8_graph* graph, u8 reg) { + if (graph) graph->output_reg = reg; +} + +void pxl8_graph_set_seed(pxl8_graph* graph, u32 seed) { + if (graph) graph->seed = seed; +} + +f32 pxl8_graph_eval(const pxl8_graph* graph, pxl8_graph_context* ctx) { + if (!graph || !ctx) return 0.0f; + + for (u32 i = 0; i < graph->count; i++) { + const pxl8_node* n = &graph->nodes[i]; + f32 a = ctx->regs[n->in[0]]; + f32 b = ctx->regs[n->in[1]]; + f32 c = ctx->regs[n->in[2]]; + f32 d = ctx->regs[n->in[3]]; + f32 result = 0.0f; + + switch (n->op) { + case PXL8_OP_CONST: result = n->param; break; + case PXL8_OP_INPUT_AGE: result = ctx->regs[3]; break; + case PXL8_OP_INPUT_SEED: result = (f32)ctx->seed; break; + case PXL8_OP_INPUT_TIME: result = ctx->regs[2]; break; + case PXL8_OP_INPUT_X: result = ctx->regs[0]; break; + case PXL8_OP_INPUT_Y: result = ctx->regs[1]; break; + + case PXL8_OP_ABS: result = fabsf(a); break; + case PXL8_OP_CEIL: result = ceilf(a); break; + case PXL8_OP_COS: result = cosf(a); break; + case PXL8_OP_FLOOR: result = floorf(a); break; + case PXL8_OP_FRACT: result = a - floorf(a); break; + case PXL8_OP_NEGATE: result = -a; break; + case PXL8_OP_SIN: result = sinf(a); break; + case PXL8_OP_SQRT: result = sqrtf(a); break; + + case PXL8_OP_ADD: result = a + b; break; + case PXL8_OP_DIV: result = b != 0.0f ? a / b : 0.0f; break; + case PXL8_OP_MAX: result = fmaxf(a, b); break; + case PXL8_OP_MIN: result = fminf(a, b); break; + case PXL8_OP_MOD: result = b != 0.0f ? fmodf(a, b) : 0.0f; break; + case PXL8_OP_MUL: result = a * b; break; + case PXL8_OP_POW: result = powf(a, b); break; + case PXL8_OP_SUB: result = a - b; break; + + case PXL8_OP_CLAMP: result = fmaxf(b, fminf(c, a)); break; + case PXL8_OP_LERP: result = a + c * (b - a); break; + case PXL8_OP_SELECT: result = c > 0.0f ? a : b; break; + case PXL8_OP_SMOOTHSTEP: { + f32 t = fmaxf(0.0f, fminf(1.0f, (c - a) / (b - a))); + result = t * t * (3.0f - 2.0f * t); + break; + } + + case PXL8_OP_NOISE_FBM: result = noise_fbm(a, b, (i32)n->param, c, d, ctx->seed); break; + case PXL8_OP_NOISE_PERLIN: result = noise_perlin(a, b, c, ctx->seed); break; + case PXL8_OP_NOISE_RIDGED: result = noise_ridged(a, b, (i32)n->param, c, d, ctx->seed); break; + case PXL8_OP_NOISE_TURBULENCE:result = noise_turbulence(a, b, (i32)n->param, c, d, ctx->seed); break; + case PXL8_OP_NOISE_VALUE: result = noise_value(a, b, c, ctx->seed); break; + + case PXL8_OP_VORONOI_CELL: { + f32 cell, edge; i32 id; + voronoi(a, b, c, ctx->seed, &cell, &edge, &id); + result = cell; + break; + } + case PXL8_OP_VORONOI_EDGE: { + f32 cell, edge; i32 id; + voronoi(a, b, c, ctx->seed, &cell, &edge, &id); + result = edge; + break; + } + case PXL8_OP_VORONOI_ID: { + f32 cell, edge; i32 id; + voronoi(a, b, c, ctx->seed, &cell, &edge, &id); + result = (f32)(id & 0xFF) / 255.0f; + break; + } + + case PXL8_OP_GRADIENT_LINEAR: result = gradient_linear(a, b, c); break; + case PXL8_OP_GRADIENT_RADIAL: result = gradient_radial(a, b, c, d); break; + + case PXL8_OP_QUANTIZE: { + u8 base = (u8)n->param; + f32 range = b; + f32 clamped = fmaxf(0.0f, fminf(1.0f, a)); + result = (f32)(base + (u8)fminf(clamped * range, range - 1.0f)); + break; + } + + default: break; + } + + ctx->regs[n->out] = result; + } + + return ctx->regs[graph->output_reg]; +} + +void pxl8_graph_eval_texture(const pxl8_graph* graph, u8* buffer, i32 width, i32 height) { + if (!graph || !buffer) return; + + pxl8_graph_context ctx = {0}; + ctx.seed = graph->seed; + + for (i32 y = 0; y < height; y++) { + for (i32 x = 0; x < width; x++) { + ctx.regs[0] = (f32)x / (f32)width; + ctx.regs[1] = (f32)y / (f32)height; + ctx.regs[2] = 0.0f; + ctx.regs[3] = 0.0f; + + f32 result = pxl8_graph_eval(graph, &ctx); + buffer[y * width + x] = (u8)fmaxf(0.0f, fminf(255.0f, result)); + } + } +} diff --git a/src/procgen/pxl8_graph.h b/src/procgen/pxl8_graph.h new file mode 100644 index 0000000..81f7882 --- /dev/null +++ b/src/procgen/pxl8_graph.h @@ -0,0 +1,90 @@ +#pragma once + +#include "pxl8_types.h" + +typedef enum pxl8_graph_op { + PXL8_OP_CONST, // param -> out + PXL8_OP_INPUT_AGE, // particle normalized age -> out + PXL8_OP_INPUT_SEED, // seed -> out + PXL8_OP_INPUT_TIME, // time -> out + PXL8_OP_INPUT_X, // x coord -> out + PXL8_OP_INPUT_Y, // y coord -> out + + PXL8_OP_ABS, // |a| -> out + PXL8_OP_CEIL, // ceil(a) -> out + PXL8_OP_COS, // cos(a) -> out + PXL8_OP_FLOOR, // floor(a) -> out + PXL8_OP_FRACT, // fract(a) -> out + PXL8_OP_NEGATE, // -a -> out + PXL8_OP_SIN, // sin(a) -> out + PXL8_OP_SQRT, // sqrt(a) -> out + + PXL8_OP_ADD, // a + b -> out + PXL8_OP_DIV, // a / b -> out + PXL8_OP_MAX, // max(a, b) -> out + PXL8_OP_MIN, // min(a, b) -> out + PXL8_OP_MOD, // fmod(a, b) -> out + PXL8_OP_MUL, // a * b -> out + PXL8_OP_POW, // pow(a, b) -> out + PXL8_OP_SUB, // a - b -> out + + PXL8_OP_CLAMP, // clamp(a, min, max) -> out + PXL8_OP_LERP, // lerp(a, b, t) -> out + PXL8_OP_SELECT, // t > 0 ? a : b -> out + PXL8_OP_SMOOTHSTEP, // smoothstep(edge0, edge1, x) -> out + + PXL8_OP_NOISE_FBM, // fbm(x, y, octaves, scale, persistence) -> out + PXL8_OP_NOISE_PERLIN, // perlin noise(x, y, scale) -> out + PXL8_OP_NOISE_RIDGED, // ridged(x, y, octaves, scale, persistence) -> out + PXL8_OP_NOISE_TURBULENCE,// turbulence(x, y, octaves, scale, persistence) -> out + PXL8_OP_NOISE_VALUE, // value noise(x, y, scale) -> out + + PXL8_OP_VORONOI_CELL, // voronoi cell distance(x, y, scale) -> out + PXL8_OP_VORONOI_EDGE, // voronoi edge distance(x, y, scale) -> out + PXL8_OP_VORONOI_ID, // voronoi cell id(x, y, scale) -> out + + PXL8_OP_GRADIENT_LINEAR, // linear gradient(x, y, angle) -> out + PXL8_OP_GRADIENT_RADIAL, // radial gradient(x, y, cx, cy) -> out + + PXL8_OP_QUANTIZE, // quantize to palette: base + floor(a * range) -> out + + PXL8_OP_COUNT +} pxl8_graph_op; + +typedef struct pxl8_node { + u8 in[4]; + u8 op; + u8 out; + f32 param; +} pxl8_node; + +typedef struct pxl8_graph { + u32 capacity; + u32 count; + pxl8_node* nodes; + u8 output_reg; + u32 seed; +} pxl8_graph; + +typedef struct pxl8_graph_context { + f32 regs[256]; + u32 seed; +} pxl8_graph_context; + +#ifdef __cplusplus +extern "C" { +#endif + +f32 pxl8_graph_eval(const pxl8_graph* graph, pxl8_graph_context* ctx); +void pxl8_graph_eval_texture(const pxl8_graph* graph, u8* buffer, i32 width, i32 height); + +u8 pxl8_graph_add_node(pxl8_graph* graph, pxl8_graph_op op, u8 in0, u8 in1, u8 in2, u8 in3, f32 param); +void pxl8_graph_clear(pxl8_graph* graph); +pxl8_graph* pxl8_graph_create(u32 capacity); +void pxl8_graph_destroy(pxl8_graph* graph); +void pxl8_graph_set_output(pxl8_graph* graph, u8 reg); +void pxl8_graph_set_seed(pxl8_graph* graph, u32 seed); + +#ifdef __cplusplus +} +#endif diff --git a/src/script/pxl8_repl.c b/src/script/pxl8_repl.c index 5c0d3e0..5c7853f 100644 --- a/src/script/pxl8_repl.c +++ b/src/script/pxl8_repl.c @@ -1,14 +1,14 @@ #include "pxl8_repl.h" +#include "pxl8_mem.h" #include -#include #include #include #include #include -#include #include +#include #include #define PXL8_MAX_REPL_COMMAND_SIZE 4096 @@ -29,7 +29,7 @@ struct pxl8_repl { atomic_uint log_read_idx; atomic_bool should_quit; - pthread_t thread; + SDL_Thread* thread; char accumulator[PXL8_MAX_REPL_COMMAND_SIZE]; pxl8_repl_command command; }; @@ -56,15 +56,15 @@ static void pxl8_repl_completion(const char* buf, linenoiseCompletions* lc) { "pxl8.error", "pxl8.debug", "pxl8.trace" }; - size_t buf_len = strlen(buf); + usize buf_len = strlen(buf); - for (size_t i = 0; i < sizeof(fennel_keywords) / sizeof(fennel_keywords[0]); i++) { + for (usize i = 0; i < sizeof(fennel_keywords) / sizeof(fennel_keywords[0]); i++) { if (strncmp(buf, fennel_keywords[i], buf_len) == 0) { linenoiseAddCompletion(lc, fennel_keywords[i]); } } - for (size_t i = 0; i < sizeof(pxl8_functions) / sizeof(pxl8_functions[0]); i++) { + for (usize i = 0; i < sizeof(pxl8_functions) / sizeof(pxl8_functions[0]); i++) { if (strncmp(buf, pxl8_functions[i], buf_len) == 0) { linenoiseAddCompletion(lc, pxl8_functions[i]); } @@ -105,7 +105,7 @@ static void pxl8_repl_flush_logs(pxl8_repl* repl) { fflush(stdout); } -static void* pxl8_repl_thread(void* arg) { +static int pxl8_repl_thread(void* arg) { pxl8_repl* repl = (pxl8_repl*)arg; printf("[pxl8 REPL] Fennel 1.6.0 - Tab for completion, Ctrl-D to exit\n"); @@ -204,8 +204,7 @@ static void* pxl8_repl_thread(void* arg) { lw = atomic_load(&repl->log_write_idx); } fflush(stdout); - struct timespec ts = {.tv_sec = 0, .tv_nsec = 1000000}; - nanosleep(&ts, NULL); + SDL_Delay(1); } atomic_store(&repl->cmd_complete, false); } @@ -214,11 +213,11 @@ static void* pxl8_repl_thread(void* arg) { pxl8_repl_flush_logs(repl); - return NULL; + return 0; } pxl8_repl* pxl8_repl_create(void) { - pxl8_repl* repl = (pxl8_repl*)calloc(1, sizeof(pxl8_repl)); + pxl8_repl* repl = (pxl8_repl*)pxl8_calloc(1, sizeof(pxl8_repl)); if (!repl) return NULL; repl->accumulator[0] = '\0'; @@ -237,8 +236,9 @@ pxl8_repl* pxl8_repl_create(void) { g_repl = repl; - if (pthread_create(&repl->thread, NULL, pxl8_repl_thread, repl) != 0) { - free(repl); + repl->thread = SDL_CreateThread(pxl8_repl_thread, "pxl8-repl", repl); + if (!repl->thread) { + pxl8_free(repl); g_repl = NULL; return NULL; } @@ -251,19 +251,18 @@ void pxl8_repl_destroy(pxl8_repl* repl) { atomic_store(&repl->should_quit, true); - struct timespec ts = {.tv_sec = 0, .tv_nsec = 2000000}; - nanosleep(&ts, NULL); + SDL_Delay(2); printf("\r\033[K"); fflush(stdout); - pthread_join(repl->thread, NULL); + SDL_WaitThread(repl->thread, NULL); pxl8_repl_flush_logs(repl); g_repl = NULL; system("stty sane 2>/dev/null"); - free(repl); + pxl8_free(repl); } pxl8_repl_command* pxl8_repl_pop_command(pxl8_repl* repl) { diff --git a/src/script/pxl8_script.c b/src/script/pxl8_script.c index 481e8ca..dda3c5f 100644 --- a/src/script/pxl8_script.c +++ b/src/script/pxl8_script.c @@ -17,6 +17,7 @@ #include "pxl8_gui.h" #include "pxl8_log.h" #include "pxl8_macros.h" +#include "pxl8_mem.h" #include "pxl8_script_ffi.h" struct pxl8_script { @@ -37,7 +38,7 @@ struct pxl8_script { static int pxl8_cart_loader(lua_State* L) { const char* found_path = lua_tostring(L, lua_upvalueindex(1)); const char* code = lua_tostring(L, lua_upvalueindex(2)); - size_t code_len = lua_objlen(L, lua_upvalueindex(2)); + usize code_len = lua_objlen(L, lua_upvalueindex(2)); bool is_fennel = lua_toboolean(L, lua_upvalueindex(3)); if (is_fennel) { @@ -75,9 +76,9 @@ static int pxl8_cart_searcher(lua_State* L) { } char path[512]; - size_t len = strlen(modname); - size_t j = 0; - for (size_t i = 0; i < len && j < sizeof(path) - 5; i++) { + usize len = strlen(modname); + usize j = 0; + for (usize i = 0; i < len && j < sizeof(path) - 5; i++) { if (modname[i] == '.') { path[j++] = '/'; } else { @@ -114,9 +115,9 @@ static int pxl8_cart_searcher(lua_State* L) { return 1; } -static void pxl8_script_repl_promote_locals(const char* input, char* output, size_t output_size) { - size_t i = 0; - size_t j = 0; +static void pxl8_script_repl_promote_locals(const char* input, char* output, usize output_size) { + usize i = 0; + usize j = 0; bool in_string = false; bool in_comment = false; @@ -182,18 +183,18 @@ static void pxl8_script_set_error(pxl8_script* script, const char* error) { src += 9; const char* mod_start = src; while (*src && !(*src == '"' && *(src+1) == ']')) src++; - size_t mod_len = src - mod_start; + usize mod_len = src - mod_start; if (mod_len > 4 && strncmp(mod_start, "pxl8", 4) == 0) { const char* prefix = "src/lua/"; while (*prefix && dst < end) *dst++ = *prefix++; - for (size_t i = 0; i < mod_len && dst < end; i++) { + for (usize i = 0; i < mod_len && dst < end; i++) { *dst++ = (mod_start[i] == '.') ? '/' : mod_start[i]; } const char* suffix = ".lua"; while (*suffix && dst < end) *dst++ = *suffix++; } else { - for (size_t i = 0; i < mod_len && dst < end; i++) { + for (usize i = 0; i < mod_len && dst < end; i++) { *dst++ = mod_start[i]; } } @@ -244,13 +245,13 @@ static void pxl8_install_embed_searcher(lua_State* L) { } pxl8_script* pxl8_script_create(bool repl_mode) { - pxl8_script* script = (pxl8_script*)calloc(1, sizeof(pxl8_script)); + pxl8_script* script = (pxl8_script*)pxl8_calloc(1, sizeof(pxl8_script)); if (!script) return NULL; script->repl_mode = repl_mode; script->L = luaL_newstate(); if (!script->L) { - free(script); + pxl8_free(script); return NULL; } @@ -349,7 +350,7 @@ void pxl8_script_destroy(pxl8_script* script) { } lua_close(script->L); } - free(script); + pxl8_free(script); } void pxl8_script_set_gfx(pxl8_script* script, pxl8_gfx* gfx) { @@ -395,7 +396,7 @@ void pxl8_script_set_sys(pxl8_script* script, void* sys) { } } -static pxl8_result pxl8_script_prepare_path(pxl8_script* script, const char* filename, char* out_basename, size_t basename_size) { +static pxl8_result pxl8_script_prepare_path(pxl8_script* script, const char* filename, char* out_basename, usize basename_size) { char filename_copy[PATH_MAX]; pxl8_strncpy(filename_copy, filename, sizeof(filename_copy)); @@ -470,7 +471,7 @@ static time_t get_latest_script_mod_time(const char* dir_path) { latest = subdir_time; } } else { - size_t len = strlen(entry->d_name); + usize len = strlen(entry->d_name); bool is_script = (len > 4 && strcmp(entry->d_name + len - 4, ".fnl") == 0) || (len > 4 && strcmp(entry->d_name + len - 4, ".lua") == 0); @@ -618,8 +619,8 @@ static pxl8_result pxl8_script_eval_internal(pxl8_script* script, const char* co const char* error = lua_tostring(script->L, -1); if (error) { char cleaned_error[2048]; - size_t j = 0; - for (size_t i = 0; error[i] && j < sizeof(cleaned_error) - 1; i++) { + usize j = 0; + for (usize i = 0; error[i] && j < sizeof(cleaned_error) - 1; i++) { if (error[i] == '\t') { cleaned_error[j++] = ' '; } else { @@ -877,7 +878,7 @@ typedef struct { static void ser_buffer_init(ser_buffer* buf) { buf->capacity = 1024; - buf->data = malloc(buf->capacity); + buf->data = pxl8_malloc(buf->capacity); buf->size = 0; } @@ -886,7 +887,7 @@ static void ser_buffer_grow(ser_buffer* buf, u32 needed) { while (buf->size + needed > buf->capacity) { buf->capacity *= 2; } - buf->data = realloc(buf->data, buf->capacity); + buf->data = pxl8_realloc(buf->data, buf->capacity); } } @@ -930,7 +931,7 @@ static void ser_write_value(ser_buffer* buf, lua_State* L, int idx, int depth) { ser_write_f64(buf, lua_tonumber(L, idx)); break; case LUA_TSTRING: { - size_t len; + usize len; const char* str = lua_tolstring(L, idx, &len); ser_write_u8(buf, SER_STRING); ser_write_u32(buf, (u32)len); @@ -1080,7 +1081,7 @@ void pxl8_script_deserialize_globals(pxl8_script* script, const u8* data, u32 si } void pxl8_script_free_serialized(u8* data) { - free(data); + pxl8_free(data); } pxl8_result pxl8_script_load_main(pxl8_script* script, const char* path) { diff --git a/src/script/pxl8_script_ffi.h b/src/script/pxl8_script_ffi.h index 0729bab..4ca83fe 100644 --- a/src/script/pxl8_script_ffi.h +++ b/src/script/pxl8_script_ffi.h @@ -11,6 +11,8 @@ static const char* pxl8_ffi_cdefs = "typedef int64_t i64;\n" "typedef float f32;\n" "typedef double f64;\n" +"typedef size_t usize;\n" +"typedef ptrdiff_t isize;\n" "typedef struct pxl8 pxl8;\n" "typedef struct pxl8_gfx pxl8_gfx;\n" "typedef struct { int x, y, w, h; } pxl8_bounds;\n" @@ -27,11 +29,16 @@ static const char* pxl8_ffi_cdefs = "u8 pxl8_gfx_find_color(pxl8_gfx* gfx, u32 color);\n" "i32 pxl8_gfx_get_height(pxl8_gfx* ctx);\n" "typedef struct pxl8_palette pxl8_palette;\n" -"pxl8_palette* pxl8_gfx_get_palette(pxl8_gfx* gfx);\n" +"pxl8_palette* pxl8_gfx_palette(pxl8_gfx* gfx);\n" "u32 pxl8_palette_color(const pxl8_palette* pal, u8 idx);\n" "void pxl8_palette_set_rgb(pxl8_palette* pal, u8 idx, u8 r, u8 g, u8 b);\n" +"void pxl8_gfx_set_palette_colors(pxl8_gfx* gfx, const u32* colors, u16 count);\n" "i32 pxl8_palette_index(const pxl8_palette* pal, u32 color);\n" "u8 pxl8_palette_ramp_index(const pxl8_palette* pal, u8 position);\n" +"typedef struct pxl8_colormap pxl8_colormap;\n" +"pxl8_colormap* pxl8_gfx_colormap(pxl8_gfx* gfx);\n" +"void pxl8_set_colormap(pxl8_colormap* cm, const u8* data, u32 size);\n" +"void pxl8_gfx_ensure_blend_tables(pxl8_gfx* gfx);\n" "i32 pxl8_gfx_get_width(pxl8_gfx* ctx);\n" "void pxl8_2d_circle(pxl8_gfx* ctx, i32 x, i32 y, i32 r, u32 color);\n" "void pxl8_2d_circle_fill(pxl8_gfx* ctx, i32 x, i32 y, i32 r, u32 color);\n" @@ -192,21 +199,27 @@ static const char* pxl8_ffi_cdefs = "\n" "typedef struct pxl8_light {\n" " pxl8_vec3 position;\n" +" f32 inv_radius_sq;\n" " u8 r, g, b;\n" " u8 intensity;\n" " f32 radius;\n" " f32 radius_sq;\n" -" f32 inv_radius_sq;\n" "} pxl8_light;\n" "\n" +"typedef struct pxl8_lights pxl8_lights;\n" +"pxl8_lights* pxl8_lights_create(u32 capacity);\n" +"void pxl8_lights_destroy(pxl8_lights* lights);\n" +"void pxl8_lights_add(pxl8_lights* lights, f32 x, f32 y, f32 z, u8 r, u8 g, u8 b, u8 intensity, f32 radius);\n" +"void pxl8_lights_clear(pxl8_lights* lights);\n" +"u32 pxl8_lights_count(const pxl8_lights* lights);\n" +"const pxl8_light* pxl8_lights_data(const pxl8_lights* lights);\n" +"\n" "typedef struct pxl8_3d_uniforms {\n" " u8 ambient;\n" " pxl8_vec3 celestial_dir;\n" " f32 celestial_intensity;\n" " u8 fog_color;\n" " f32 fog_density;\n" -" pxl8_light lights[16];\n" -" u32 num_lights;\n" " f32 time;\n" "} pxl8_3d_uniforms;\n" "\n" @@ -224,12 +237,14 @@ static const char* pxl8_ffi_cdefs = "pxl8_mat4 pxl8_3d_camera_get_view(const pxl8_3d_camera* cam);\n" "pxl8_mat4 pxl8_3d_camera_get_projection(const pxl8_3d_camera* cam);\n" "void pxl8_3d_camera_update(pxl8_3d_camera* cam, f32 dt);\n" +"typedef struct pxl8_projected_point { i32 x; i32 y; f32 depth; bool visible; } pxl8_projected_point;\n" +"pxl8_projected_point pxl8_3d_camera_world_to_screen(const pxl8_3d_camera* cam, pxl8_vec3 world_pos, u32 screen_width, u32 screen_height);\n" "\n" "typedef enum pxl8_gfx_effect { PXL8_GFX_EFFECT_GLOWS = 0 } pxl8_gfx_effect;\n" "\n" "typedef enum pxl8_glow_shape { PXL8_GLOW_CIRCLE = 0, PXL8_GLOW_DIAMOND = 1, PXL8_GLOW_SHAFT = 2 } pxl8_glow_shape;\n" "\n" -"typedef struct pxl8_glow_source {\n" +"typedef struct pxl8_glow {\n" " u8 color;\n" " u16 depth;\n" " u8 height;\n" @@ -238,22 +253,37 @@ static const char* pxl8_ffi_cdefs = " pxl8_glow_shape shape;\n" " i16 x;\n" " i16 y;\n" -"} pxl8_glow_source;\n" +"} pxl8_glow;\n" "\n" "void pxl8_gfx_apply_effect(pxl8_gfx* gfx, pxl8_gfx_effect effect, const void* params, u32 count);\n" "void pxl8_gfx_blend_tables_update(pxl8_gfx* gfx);\n" +"\n" +"typedef struct pxl8_glows pxl8_glows;\n" +"pxl8_glows* pxl8_glows_create(u32 capacity);\n" +"void pxl8_glows_destroy(pxl8_glows* glows);\n" +"void pxl8_glows_add(pxl8_glows* glows, i16 x, i16 y, u8 radius, u16 intensity, u8 color, u8 shape);\n" +"void pxl8_glows_clear(pxl8_glows* glows);\n" +"u32 pxl8_glows_count(const pxl8_glows* glows);\n" +"void pxl8_glows_render(pxl8_glows* glows, pxl8_gfx* gfx);\n" "void pxl8_gfx_colormap_update(pxl8_gfx* gfx);\n" "\n" -"void pxl8_3d_begin_frame(pxl8_gfx* gfx, const pxl8_3d_camera* camera, const pxl8_3d_uniforms* uniforms);\n" +"void pxl8_3d_begin_frame(pxl8_gfx* gfx, const pxl8_3d_camera* camera, const pxl8_lights* lights, const pxl8_3d_uniforms* uniforms);\n" "void pxl8_3d_clear(pxl8_gfx* gfx, u8 color);\n" "void pxl8_3d_clear_depth(pxl8_gfx* gfx);\n" "void pxl8_3d_draw_line(pxl8_gfx* gfx, pxl8_vec3 p0, pxl8_vec3 p1, u8 color);\n" "void pxl8_3d_end_frame(pxl8_gfx* gfx);\n" +"u32 pxl8_3d_project_points(pxl8_gfx* gfx, const pxl8_vec3* in, pxl8_vec3* out, u32 count, const pxl8_mat4* transform);\n" "\n" "typedef enum pxl8_blend_mode { PXL8_BLEND_OPAQUE = 0, PXL8_BLEND_ALPHA_TEST, PXL8_BLEND_ALPHA, PXL8_BLEND_ADDITIVE } pxl8_blend_mode;\n" "\n" -"typedef struct pxl8_material {\n" +"typedef struct pxl8_gfx_material {\n" +" char name[16];\n" +" pxl8_vec3 u_axis;\n" +" pxl8_vec3 v_axis;\n" +" f32 u_offset;\n" +" f32 v_offset;\n" " u32 texture_id;\n" +" u32 lightmap_id;\n" " u8 alpha;\n" " u8 blend_mode;\n" " bool dither;\n" @@ -261,13 +291,15 @@ static const char* pxl8_ffi_cdefs = " bool dynamic_lighting;\n" " bool per_pixel;\n" " bool vertex_color_passthrough;\n" +" bool wireframe;\n" " f32 emissive_intensity;\n" -"} pxl8_material;\n" +"} pxl8_gfx_material;\n" "\n" "typedef struct pxl8_vertex {\n" " pxl8_vec3 position;\n" " pxl8_vec3 normal;\n" " f32 u, v;\n" +" f32 lu, lv;\n" " u8 color;\n" " u8 light;\n" " u8 _pad[2];\n" @@ -287,12 +319,16 @@ static const char* pxl8_ffi_cdefs = "void pxl8_mesh_clear(pxl8_mesh* mesh);\n" "u16 pxl8_mesh_push_vertex(pxl8_mesh* mesh, pxl8_vertex v);\n" "void pxl8_mesh_push_triangle(pxl8_mesh* mesh, u16 i0, u16 i1, u16 i2);\n" -"void pxl8_3d_draw_mesh(pxl8_gfx* gfx, const pxl8_mesh* mesh, const pxl8_mat4* model, const pxl8_material* material);\n" +"void pxl8_3d_draw_mesh(pxl8_gfx* gfx, const pxl8_mesh* mesh, const pxl8_mat4* model, const pxl8_gfx_material* material);\n" +"\n" +"u32 pxl8_hash32(u32 x);\n" "\n" "pxl8_mat4 pxl8_mat4_identity(void);\n" "pxl8_mat4 pxl8_mat4_lookat(pxl8_vec3 eye, pxl8_vec3 center, pxl8_vec3 up);\n" -"pxl8_mat4 pxl8_mat4_mul(pxl8_mat4 a, pxl8_mat4 b);\n" -"pxl8_mat4 pxl8_mat4_ortho(float left, float right, float bottom, float top, float near, float far);\n" +"pxl8_mat4 pxl8_mat4_multiply(pxl8_mat4 a, pxl8_mat4 b);\n" +"pxl8_vec3 pxl8_mat4_multiply_vec3(pxl8_mat4 m, pxl8_vec3 v);\n" +"pxl8_vec4 pxl8_mat4_multiply_vec4(pxl8_mat4 m, pxl8_vec4 v);\n" +"pxl8_mat4 pxl8_mat4_orthographic(float left, float right, float bottom, float top, float near, float far);\n" "pxl8_mat4 pxl8_mat4_perspective(float fov, float aspect, float near, float far);\n" "pxl8_mat4 pxl8_mat4_rotate_x(float angle);\n" "pxl8_mat4 pxl8_mat4_rotate_y(float angle);\n" @@ -316,18 +352,76 @@ static const char* pxl8_ffi_cdefs = " int num_rooms;\n" "} pxl8_procgen_params;\n" "\n" -"typedef struct pxl8_procgen_tex_params {\n" -" char name[16];\n" -" unsigned int seed;\n" -" int width;\n" -" int height;\n" -" float scale;\n" -" float roughness;\n" -" unsigned char base_color;\n" -" unsigned char variation;\n" -"} pxl8_procgen_tex_params;\n" +"typedef enum pxl8_graph_op {\n" +" PXL8_OP_CONST = 0,\n" +" PXL8_OP_INPUT_AGE,\n" +" PXL8_OP_INPUT_SEED,\n" +" PXL8_OP_INPUT_TIME,\n" +" PXL8_OP_INPUT_X,\n" +" PXL8_OP_INPUT_Y,\n" "\n" -"void pxl8_procgen_tex(u8* buffer, const pxl8_procgen_tex_params* params);\n" +" PXL8_OP_ABS,\n" +" PXL8_OP_CEIL,\n" +" PXL8_OP_COS,\n" +" PXL8_OP_FLOOR,\n" +" PXL8_OP_FRACT,\n" +" PXL8_OP_NEGATE,\n" +" PXL8_OP_SIN,\n" +" PXL8_OP_SQRT,\n" +"\n" +" PXL8_OP_ADD,\n" +" PXL8_OP_DIV,\n" +" PXL8_OP_MAX,\n" +" PXL8_OP_MIN,\n" +" PXL8_OP_MOD,\n" +" PXL8_OP_MUL,\n" +" PXL8_OP_POW,\n" +" PXL8_OP_SUB,\n" +"\n" +" PXL8_OP_CLAMP,\n" +" PXL8_OP_LERP,\n" +" PXL8_OP_SELECT,\n" +" PXL8_OP_SMOOTHSTEP,\n" +"\n" +" PXL8_OP_NOISE_FBM,\n" +" PXL8_OP_NOISE_PERLIN,\n" +" PXL8_OP_NOISE_RIDGED,\n" +" PXL8_OP_NOISE_TURBULENCE,\n" +" PXL8_OP_NOISE_VALUE,\n" +"\n" +" PXL8_OP_VORONOI_CELL,\n" +" PXL8_OP_VORONOI_EDGE,\n" +" PXL8_OP_VORONOI_ID,\n" +"\n" +" PXL8_OP_GRADIENT_LINEAR,\n" +" PXL8_OP_GRADIENT_RADIAL,\n" +"\n" +" PXL8_OP_QUANTIZE,\n" +" PXL8_OP_COUNT\n" +"} pxl8_graph_op;\n" +"\n" +"typedef struct pxl8_node {\n" +" u8 in[4];\n" +" u8 op;\n" +" u8 out;\n" +" f32 param;\n" +"} pxl8_node;\n" +"\n" +"typedef struct pxl8_graph {\n" +" u32 capacity;\n" +" u32 count;\n" +" pxl8_node* nodes;\n" +" u8 output_reg;\n" +" u32 seed;\n" +"} pxl8_graph;\n" +"\n" +"pxl8_graph* pxl8_graph_create(u32 capacity);\n" +"void pxl8_graph_destroy(pxl8_graph* graph);\n" +"void pxl8_graph_clear(pxl8_graph* graph);\n" +"u8 pxl8_graph_add_node(pxl8_graph* graph, pxl8_graph_op op, u8 in0, u8 in1, u8 in2, u8 in3, f32 param);\n" +"void pxl8_graph_set_output(pxl8_graph* graph, u8 reg);\n" +"void pxl8_graph_set_seed(pxl8_graph* graph, u32 seed);\n" +"void pxl8_graph_eval_texture(const pxl8_graph* graph, u8* buffer, i32 width, i32 height);\n" "\n" "typedef struct pxl8_bsp pxl8_bsp;\n" "typedef struct pxl8_bsp_face pxl8_bsp_face;\n" @@ -350,12 +444,13 @@ static const char* pxl8_ffi_cdefs = "bool pxl8_world_is_loaded(const pxl8_world* world);\n" "void pxl8_world_render(pxl8_world* world, pxl8_gfx* gfx, pxl8_vec3 camera_pos);\n" "pxl8_vec3 pxl8_world_resolve_collision(const pxl8_world* world, pxl8_vec3 from, pxl8_vec3 to, float radius);\n" +"void pxl8_world_set_wireframe(pxl8_world* world, bool enabled);\n" "\n" "typedef struct { i32 cursor_x; i32 cursor_y; bool cursor_down; bool cursor_clicked; u32 hot_id; u32 active_id; } pxl8_gui_state;\n" "pxl8_gui_state* pxl8_gui_state_create(void);\n" "void pxl8_gui_state_destroy(pxl8_gui_state* state);\n" -"void pxl8_gui_begin_frame(pxl8_gui_state* state);\n" -"void pxl8_gui_end_frame(pxl8_gui_state* state);\n" +"void pxl8_gui_begin_frame(pxl8_gui_state* state, pxl8_gfx* gfx);\n" +"void pxl8_gui_end_frame(pxl8_gui_state* state, pxl8_gfx* gfx);\n" "void pxl8_gui_cursor_move(pxl8_gui_state* state, i32 x, i32 y);\n" "void pxl8_gui_cursor_down(pxl8_gui_state* state);\n" "void pxl8_gui_cursor_up(pxl8_gui_state* state);\n" @@ -486,40 +581,40 @@ static const char* pxl8_ffi_cdefs = "bool pxl8_bit_test(u32 val, u8 bit);\n" "void pxl8_bit_toggle(u32* val, u8 bit);\n" "\n" -"void pxl8_pack_u8(u8* buf, size_t offset, u8 val);\n" -"void pxl8_pack_u16_be(u8* buf, size_t offset, u16 val);\n" -"void pxl8_pack_u16_le(u8* buf, size_t offset, u16 val);\n" -"void pxl8_pack_u32_be(u8* buf, size_t offset, u32 val);\n" -"void pxl8_pack_u32_le(u8* buf, size_t offset, u32 val);\n" -"void pxl8_pack_u64_be(u8* buf, size_t offset, u64 val);\n" -"void pxl8_pack_u64_le(u8* buf, size_t offset, u64 val);\n" -"void pxl8_pack_i8(u8* buf, size_t offset, i8 val);\n" -"void pxl8_pack_i16_be(u8* buf, size_t offset, i16 val);\n" -"void pxl8_pack_i16_le(u8* buf, size_t offset, i16 val);\n" -"void pxl8_pack_i32_be(u8* buf, size_t offset, i32 val);\n" -"void pxl8_pack_i32_le(u8* buf, size_t offset, i32 val);\n" -"void pxl8_pack_i64_be(u8* buf, size_t offset, i64 val);\n" -"void pxl8_pack_i64_le(u8* buf, size_t offset, i64 val);\n" -"void pxl8_pack_f32_be(u8* buf, size_t offset, f32 val);\n" -"void pxl8_pack_f32_le(u8* buf, size_t offset, f32 val);\n" -"void pxl8_pack_f64_be(u8* buf, size_t offset, f64 val);\n" -"void pxl8_pack_f64_le(u8* buf, size_t offset, f64 val);\n" +"void pxl8_pack_u8(u8* buf, usize offset, u8 val);\n" +"void pxl8_pack_u16_be(u8* buf, usize offset, u16 val);\n" +"void pxl8_pack_u16_le(u8* buf, usize offset, u16 val);\n" +"void pxl8_pack_u32_be(u8* buf, usize offset, u32 val);\n" +"void pxl8_pack_u32_le(u8* buf, usize offset, u32 val);\n" +"void pxl8_pack_u64_be(u8* buf, usize offset, u64 val);\n" +"void pxl8_pack_u64_le(u8* buf, usize offset, u64 val);\n" +"void pxl8_pack_i8(u8* buf, usize offset, i8 val);\n" +"void pxl8_pack_i16_be(u8* buf, usize offset, i16 val);\n" +"void pxl8_pack_i16_le(u8* buf, usize offset, i16 val);\n" +"void pxl8_pack_i32_be(u8* buf, usize offset, i32 val);\n" +"void pxl8_pack_i32_le(u8* buf, usize offset, i32 val);\n" +"void pxl8_pack_i64_be(u8* buf, usize offset, i64 val);\n" +"void pxl8_pack_i64_le(u8* buf, usize offset, i64 val);\n" +"void pxl8_pack_f32_be(u8* buf, usize offset, f32 val);\n" +"void pxl8_pack_f32_le(u8* buf, usize offset, f32 val);\n" +"void pxl8_pack_f64_be(u8* buf, usize offset, f64 val);\n" +"void pxl8_pack_f64_le(u8* buf, usize offset, f64 val);\n" "\n" -"u8 pxl8_unpack_u8(const u8* buf, size_t offset);\n" -"u16 pxl8_unpack_u16_be(const u8* buf, size_t offset);\n" -"u16 pxl8_unpack_u16_le(const u8* buf, size_t offset);\n" -"u32 pxl8_unpack_u32_be(const u8* buf, size_t offset);\n" -"u32 pxl8_unpack_u32_le(const u8* buf, size_t offset);\n" -"u64 pxl8_unpack_u64_be(const u8* buf, size_t offset);\n" -"u64 pxl8_unpack_u64_le(const u8* buf, size_t offset);\n" -"i8 pxl8_unpack_i8(const u8* buf, size_t offset);\n" -"i16 pxl8_unpack_i16_be(const u8* buf, size_t offset);\n" -"i16 pxl8_unpack_i16_le(const u8* buf, size_t offset);\n" -"i32 pxl8_unpack_i32_be(const u8* buf, size_t offset);\n" -"i32 pxl8_unpack_i32_le(const u8* buf, size_t offset);\n" -"i64 pxl8_unpack_i64_be(const u8* buf, size_t offset);\n" -"i64 pxl8_unpack_i64_le(const u8* buf, size_t offset);\n" -"f32 pxl8_unpack_f32_be(const u8* buf, size_t offset);\n" -"f32 pxl8_unpack_f32_le(const u8* buf, size_t offset);\n" -"f64 pxl8_unpack_f64_be(const u8* buf, size_t offset);\n" -"f64 pxl8_unpack_f64_le(const u8* buf, size_t offset);\n"; +"u8 pxl8_unpack_u8(const u8* buf, usize offset);\n" +"u16 pxl8_unpack_u16_be(const u8* buf, usize offset);\n" +"u16 pxl8_unpack_u16_le(const u8* buf, usize offset);\n" +"u32 pxl8_unpack_u32_be(const u8* buf, usize offset);\n" +"u32 pxl8_unpack_u32_le(const u8* buf, usize offset);\n" +"u64 pxl8_unpack_u64_be(const u8* buf, usize offset);\n" +"u64 pxl8_unpack_u64_le(const u8* buf, usize offset);\n" +"i8 pxl8_unpack_i8(const u8* buf, usize offset);\n" +"i16 pxl8_unpack_i16_be(const u8* buf, usize offset);\n" +"i16 pxl8_unpack_i16_le(const u8* buf, usize offset);\n" +"i32 pxl8_unpack_i32_be(const u8* buf, usize offset);\n" +"i32 pxl8_unpack_i32_le(const u8* buf, usize offset);\n" +"i64 pxl8_unpack_i64_be(const u8* buf, usize offset);\n" +"i64 pxl8_unpack_i64_le(const u8* buf, usize offset);\n" +"f32 pxl8_unpack_f32_be(const u8* buf, usize offset);\n" +"f32 pxl8_unpack_f32_le(const u8* buf, usize offset);\n" +"f64 pxl8_unpack_f64_be(const u8* buf, usize offset);\n" +"f64 pxl8_unpack_f64_le(const u8* buf, usize offset);\n"; diff --git a/src/sfx/pxl8_sfx.c b/src/sfx/pxl8_sfx.c index 02357fe..1d143d7 100644 --- a/src/sfx/pxl8_sfx.c +++ b/src/sfx/pxl8_sfx.c @@ -6,9 +6,15 @@ #include "pxl8_hal.h" #include "pxl8_log.h" #include "pxl8_math.h" +#include "pxl8_mem.h" #define VOICE_SCALE 0.15f +static inline f32 sanitize_audio(f32 x) { + union { f32 f; u32 u; } conv = { .f = x }; + return ((conv.u & 0x7F800000) == 0x7F800000) ? 0.0f : x; +} + typedef enum envelope_state { ENV_ATTACK = 0, ENV_DECAY, @@ -461,14 +467,14 @@ static void delay_process_stereo(void* state, f32* left, f32* right) { static void delay_destroy_state(void* state) { delay_state* d = (delay_state*)state; if (d) { - free(d->buffer_l); - free(d->buffer_r); - free(d); + pxl8_free(d->buffer_l); + pxl8_free(d->buffer_r); + pxl8_free(d); } } static void comb_init(comb_filter* c, u32 size, f32 feedback, f32 damping) { - c->buffer = (f32*)calloc(size, sizeof(f32)); + c->buffer = (f32*)pxl8_calloc(size, sizeof(f32)); c->size = size; c->feedback = feedback; c->damping = damping; @@ -477,7 +483,7 @@ static void comb_init(comb_filter* c, u32 size, f32 feedback, f32 damping) { } static void comb_destroy(comb_filter* c) { - free(c->buffer); + pxl8_free(c->buffer); } static f32 comb_process(comb_filter* c, f32 input) { @@ -492,14 +498,14 @@ static f32 comb_process(comb_filter* c, f32 input) { } static void allpass_init(allpass_filter* a, u32 size) { - a->buffer = (f32*)calloc(size, sizeof(f32)); + a->buffer = (f32*)pxl8_calloc(size, sizeof(f32)); a->size = size; a->feedback = 0.5f; a->index = 0; } static void allpass_destroy(allpass_filter* a) { - free(a->buffer); + pxl8_free(a->buffer); } static f32 allpass_process(allpass_filter* a, f32 input) { @@ -555,7 +561,7 @@ static void reverb_destroy_state(void* state) { if (r) { for (int i = 0; i < 4; i++) comb_destroy(&r->combs[i]); for (int i = 0; i < 2; i++) allpass_destroy(&r->allpasses[i]); - free(r); + pxl8_free(r); } } @@ -601,7 +607,7 @@ static void compressor_process_stereo(void* state, f32* left, f32* right) { } static void compressor_destroy_state(void* state) { - free(state); + pxl8_free(state); } static void context_process_sample(pxl8_sfx_context* ctx, f32* out_left, f32* out_right) { @@ -649,12 +655,12 @@ static void context_process_sample(pxl8_sfx_context* ctx, f32* out_left, f32* ou pxl8_sfx_mixer* pxl8_sfx_mixer_create(const pxl8_hal* hal) { if (!hal || !hal->audio_create) return NULL; - pxl8_sfx_mixer* mixer = (pxl8_sfx_mixer*)calloc(1, sizeof(pxl8_sfx_mixer)); + pxl8_sfx_mixer* mixer = (pxl8_sfx_mixer*)pxl8_calloc(1, sizeof(pxl8_sfx_mixer)); if (!mixer) return NULL; - mixer->output_buffer = (f32*)calloc(PXL8_SFX_BUFFER_SIZE * 2, sizeof(f32)); + mixer->output_buffer = (f32*)pxl8_calloc(PXL8_SFX_BUFFER_SIZE * 2, sizeof(f32)); if (!mixer->output_buffer) { - free(mixer); + pxl8_free(mixer); return NULL; } @@ -663,8 +669,8 @@ pxl8_sfx_mixer* pxl8_sfx_mixer_create(const pxl8_hal* hal) { mixer->audio_handle = hal->audio_create(PXL8_SFX_SAMPLE_RATE, 2); if (!mixer->audio_handle) { - free(mixer->output_buffer); - free(mixer); + pxl8_free(mixer->output_buffer); + pxl8_free(mixer); return NULL; } @@ -681,8 +687,8 @@ void pxl8_sfx_mixer_destroy(pxl8_sfx_mixer* mixer) { mixer->hal->audio_destroy(mixer->audio_handle); } - free(mixer->output_buffer); - free(mixer); + pxl8_free(mixer->output_buffer); + pxl8_free(mixer); } void pxl8_sfx_mixer_process(pxl8_sfx_mixer* mixer) { @@ -716,8 +722,8 @@ void pxl8_sfx_mixer_process(pxl8_sfx_mixer* mixer) { left = fmaxf(-1.0f, fminf(1.0f, left)); right = fmaxf(-1.0f, fminf(1.0f, right)); - if (!isfinite(left)) left = 0.0f; - if (!isfinite(right)) right = 0.0f; + left = sanitize_audio(left); + right = sanitize_audio(right); mixer->output_buffer[i * 2] = left; mixer->output_buffer[i * 2 + 1] = right; @@ -785,7 +791,7 @@ f32 pxl8_sfx_mixer_get_master_volume(const pxl8_sfx_mixer* mixer) { } pxl8_sfx_context* pxl8_sfx_context_create(void) { - pxl8_sfx_context* ctx = (pxl8_sfx_context*)calloc(1, sizeof(pxl8_sfx_context)); + pxl8_sfx_context* ctx = (pxl8_sfx_context*)pxl8_calloc(1, sizeof(pxl8_sfx_context)); if (!ctx) return NULL; ctx->volume = 1.0f; @@ -804,7 +810,7 @@ void pxl8_sfx_context_destroy(pxl8_sfx_context* ctx) { node = next; } - free(ctx); + pxl8_free(ctx); } void pxl8_sfx_context_set_volume(pxl8_sfx_context* ctx, f32 volume) { @@ -871,26 +877,26 @@ void pxl8_sfx_node_destroy(pxl8_sfx_node* node) { if (node->destroy && node->state) { node->destroy(node->state); } - free(node); + pxl8_free(node); } pxl8_sfx_node* pxl8_sfx_delay_create(pxl8_sfx_delay_config cfg) { - pxl8_sfx_node* node = (pxl8_sfx_node*)calloc(1, sizeof(pxl8_sfx_node)); + pxl8_sfx_node* node = (pxl8_sfx_node*)pxl8_calloc(1, sizeof(pxl8_sfx_node)); if (!node) return NULL; - delay_state* d = (delay_state*)calloc(1, sizeof(delay_state)); + delay_state* d = (delay_state*)pxl8_calloc(1, sizeof(delay_state)); if (!d) { - free(node); + pxl8_free(node); return NULL; } - d->buffer_l = (f32*)calloc(PXL8_SFX_MAX_DELAY_SAMPLES, sizeof(f32)); - d->buffer_r = (f32*)calloc(PXL8_SFX_MAX_DELAY_SAMPLES, sizeof(f32)); + d->buffer_l = (f32*)pxl8_calloc(PXL8_SFX_MAX_DELAY_SAMPLES, sizeof(f32)); + d->buffer_r = (f32*)pxl8_calloc(PXL8_SFX_MAX_DELAY_SAMPLES, sizeof(f32)); if (!d->buffer_l || !d->buffer_r) { - free(d->buffer_l); - free(d->buffer_r); - free(d); - free(node); + pxl8_free(d->buffer_l); + pxl8_free(d->buffer_r); + pxl8_free(d); + pxl8_free(node); return NULL; } @@ -933,12 +939,12 @@ void pxl8_sfx_delay_set_mix(pxl8_sfx_node* node, f32 mix) { } pxl8_sfx_node* pxl8_sfx_reverb_create(pxl8_sfx_reverb_config cfg) { - pxl8_sfx_node* node = (pxl8_sfx_node*)calloc(1, sizeof(pxl8_sfx_node)); + pxl8_sfx_node* node = (pxl8_sfx_node*)pxl8_calloc(1, sizeof(pxl8_sfx_node)); if (!node) return NULL; - reverb_state* r = (reverb_state*)calloc(1, sizeof(reverb_state)); + reverb_state* r = (reverb_state*)pxl8_calloc(1, sizeof(reverb_state)); if (!r) { - free(node); + pxl8_free(node); return NULL; } @@ -991,12 +997,12 @@ void pxl8_sfx_reverb_set_mix(pxl8_sfx_node* node, f32 mix) { } pxl8_sfx_node* pxl8_sfx_compressor_create(pxl8_sfx_compressor_config cfg) { - pxl8_sfx_node* node = (pxl8_sfx_node*)calloc(1, sizeof(pxl8_sfx_node)); + pxl8_sfx_node* node = (pxl8_sfx_node*)pxl8_calloc(1, sizeof(pxl8_sfx_node)); if (!node) return NULL; - compressor_state* c = (compressor_state*)calloc(1, sizeof(compressor_state)); + compressor_state* c = (compressor_state*)pxl8_calloc(1, sizeof(compressor_state)); if (!c) { - free(node); + pxl8_free(node); return NULL; } diff --git a/src/world/pxl8_bsp.c b/src/world/pxl8_bsp.c index 18b6367..3275b31 100644 --- a/src/world/pxl8_bsp.c +++ b/src/world/pxl8_bsp.c @@ -8,6 +8,7 @@ #include "pxl8_gfx.h" #include "pxl8_io.h" #include "pxl8_log.h" +#include "pxl8_mem.h" #define BSP_VERSION 29 @@ -40,15 +41,23 @@ typedef struct { pxl8_bsp_chunk chunks[CHUNK_COUNT]; } pxl8_bsp_header; +typedef struct { + f32 x0, y0, x1, y1; +} screen_rect; + +typedef struct { + u32 leaf; + screen_rect window; +} portal_queue_entry; + static inline pxl8_vec3 read_vec3(pxl8_stream* stream) { - pxl8_vec3 v; - v.x = pxl8_read_f32(stream); - v.y = pxl8_read_f32(stream); - v.z = pxl8_read_f32(stream); - return v; + f32 x = pxl8_read_f32(stream); + f32 y = pxl8_read_f32(stream); + f32 z = pxl8_read_f32(stream); + return (pxl8_vec3){x, z, y}; } -static bool validate_chunk(const pxl8_bsp_chunk* chunk, u32 element_size, size_t file_size) { +static bool validate_chunk(const pxl8_bsp_chunk* chunk, u32 element_size, usize file_size) { if (chunk->size == 0) return true; if (chunk->offset >= file_size) return false; if (chunk->offset + chunk->size > file_size) return false; @@ -75,32 +84,13 @@ static inline bool pxl8_bsp_get_edge_vertex(const pxl8_bsp* bsp, i32 surfedge_id return *out_vert_idx < bsp->num_vertices; } -static inline bool pxl8_bsp_get_edge_vertices(const pxl8_bsp* bsp, i32 surfedge_idx, u32* out_v0_idx, u32* out_v1_idx) { - if (surfedge_idx >= (i32)bsp->num_surfedges) return false; - - i32 edge_idx = bsp->surfedges[surfedge_idx]; - - if (edge_idx >= 0) { - if ((u32)edge_idx >= bsp->num_edges) return false; - *out_v0_idx = bsp->edges[edge_idx].vertex[0]; - *out_v1_idx = bsp->edges[edge_idx].vertex[1]; - } else { - edge_idx = -edge_idx; - if ((u32)edge_idx >= bsp->num_edges) return false; - *out_v0_idx = bsp->edges[edge_idx].vertex[1]; - *out_v1_idx = bsp->edges[edge_idx].vertex[0]; - } - - return *out_v0_idx < bsp->num_vertices && *out_v1_idx < bsp->num_vertices; -} - pxl8_result pxl8_bsp_load(const char* path, pxl8_bsp* bsp) { if (!path || !bsp) return PXL8_ERROR_INVALID_ARGUMENT; memset(bsp, 0, sizeof(*bsp)); u8* file_data = NULL; - size_t file_size = 0; + usize file_size = 0; pxl8_result result = pxl8_io_read_binary_file(path, &file_data, &file_size); if (result != PXL8_OK) { pxl8_error("Failed to load BSP file: %s", path); @@ -109,7 +99,7 @@ pxl8_result pxl8_bsp_load(const char* path, pxl8_bsp* bsp) { if (file_size < sizeof(pxl8_bsp_header)) { pxl8_error("BSP file too small: %s", path); - free(file_data); + pxl8_free(file_data); return PXL8_ERROR_INVALID_FORMAT; } @@ -120,7 +110,7 @@ pxl8_result pxl8_bsp_load(const char* path, pxl8_bsp* bsp) { if (header.version != BSP_VERSION) { pxl8_error("Invalid BSP version: %u (expected %d)", header.version, BSP_VERSION); - free(file_data); + pxl8_free(file_data); return PXL8_ERROR_INVALID_FORMAT; } @@ -133,7 +123,7 @@ pxl8_result pxl8_bsp_load(const char* path, pxl8_bsp* bsp) { if (!validate_chunk(chunk, 12, file_size)) goto error_cleanup; bsp->num_vertices = chunk->size / 12; if (bsp->num_vertices > 0) { - bsp->vertices = calloc(bsp->num_vertices, sizeof(pxl8_bsp_vertex)); + bsp->vertices = pxl8_calloc(bsp->num_vertices, sizeof(pxl8_bsp_vertex)); if (!bsp->vertices) goto error_cleanup; pxl8_stream_seek(&stream, chunk->offset); for (u32 i = 0; i < bsp->num_vertices; i++) { @@ -145,7 +135,7 @@ pxl8_result pxl8_bsp_load(const char* path, pxl8_bsp* bsp) { if (!validate_chunk(chunk, 4, file_size)) goto error_cleanup; bsp->num_edges = chunk->size / 4; if (bsp->num_edges > 0) { - bsp->edges = calloc(bsp->num_edges, sizeof(pxl8_bsp_edge)); + bsp->edges = pxl8_calloc(bsp->num_edges, sizeof(pxl8_bsp_edge)); pxl8_stream_seek(&stream, chunk->offset); for (u32 i = 0; i < bsp->num_edges; i++) { bsp->edges[i].vertex[0] = pxl8_read_u16(&stream); @@ -157,7 +147,7 @@ pxl8_result pxl8_bsp_load(const char* path, pxl8_bsp* bsp) { if (!validate_chunk(chunk, 4, file_size)) goto error_cleanup; bsp->num_surfedges = chunk->size / 4; if (bsp->num_surfedges > 0) { - bsp->surfedges = calloc(bsp->num_surfedges, sizeof(i32)); + bsp->surfedges = pxl8_calloc(bsp->num_surfedges, sizeof(i32)); pxl8_stream_seek(&stream, chunk->offset); for (u32 i = 0; i < bsp->num_surfedges; i++) { bsp->surfedges[i] = pxl8_read_i32(&stream); @@ -168,7 +158,7 @@ pxl8_result pxl8_bsp_load(const char* path, pxl8_bsp* bsp) { if (!validate_chunk(chunk, 20, file_size)) goto error_cleanup; bsp->num_planes = chunk->size / 20; if (bsp->num_planes > 0) { - bsp->planes = calloc(bsp->num_planes, sizeof(pxl8_bsp_plane)); + bsp->planes = pxl8_calloc(bsp->num_planes, sizeof(pxl8_bsp_plane)); pxl8_stream_seek(&stream, chunk->offset); for (u32 i = 0; i < bsp->num_planes; i++) { bsp->planes[i].normal = read_vec3(&stream); @@ -179,16 +169,20 @@ pxl8_result pxl8_bsp_load(const char* path, pxl8_bsp* bsp) { chunk = &header.chunks[CHUNK_TEXINFO]; if (!validate_chunk(chunk, 40, file_size)) goto error_cleanup; - bsp->num_texinfo = chunk->size / 40; - if (bsp->num_texinfo > 0) { - bsp->texinfo = calloc(bsp->num_texinfo, sizeof(pxl8_bsp_texinfo)); + bsp->num_materials = chunk->size / 40; + if (bsp->num_materials > 0) { + bsp->materials = pxl8_calloc(bsp->num_materials, sizeof(pxl8_gfx_material)); pxl8_stream_seek(&stream, chunk->offset); - for (u32 i = 0; i < bsp->num_texinfo; i++) { - bsp->texinfo[i].u_axis = read_vec3(&stream); - bsp->texinfo[i].u_offset = pxl8_read_f32(&stream); - bsp->texinfo[i].v_axis = read_vec3(&stream); - bsp->texinfo[i].v_offset = pxl8_read_f32(&stream); - bsp->texinfo[i].miptex = pxl8_read_u32(&stream); + for (u32 i = 0; i < bsp->num_materials; i++) { + bsp->materials[i].u_axis = read_vec3(&stream); + bsp->materials[i].u_offset = pxl8_read_f32(&stream); + bsp->materials[i].v_axis = read_vec3(&stream); + bsp->materials[i].v_offset = pxl8_read_f32(&stream); + bsp->materials[i].texture_id = pxl8_read_u32(&stream); + bsp->materials[i].alpha = 255; + bsp->materials[i].dither = true; + bsp->materials[i].dynamic_lighting = true; + bsp->materials[i].double_sided = true; } } @@ -196,14 +190,14 @@ pxl8_result pxl8_bsp_load(const char* path, pxl8_bsp* bsp) { if (!validate_chunk(chunk, 20, file_size)) goto error_cleanup; bsp->num_faces = chunk->size / 20; if (bsp->num_faces > 0) { - bsp->faces = calloc(bsp->num_faces, sizeof(pxl8_bsp_face)); + bsp->faces = pxl8_calloc(bsp->num_faces, sizeof(pxl8_bsp_face)); pxl8_stream_seek(&stream, chunk->offset); for (u32 i = 0; i < bsp->num_faces; i++) { bsp->faces[i].plane_id = pxl8_read_u16(&stream); bsp->faces[i].side = pxl8_read_u16(&stream); bsp->faces[i].first_edge = pxl8_read_u32(&stream); bsp->faces[i].num_edges = pxl8_read_u16(&stream); - bsp->faces[i].texinfo_id = pxl8_read_u16(&stream); + bsp->faces[i].material_id = pxl8_read_u16(&stream); bsp->faces[i].styles[0] = pxl8_read_u8(&stream); bsp->faces[i].styles[1] = pxl8_read_u8(&stream); bsp->faces[i].styles[2] = pxl8_read_u8(&stream); @@ -219,14 +213,24 @@ pxl8_result pxl8_bsp_load(const char* path, pxl8_bsp* bsp) { if (!validate_chunk(chunk, 24, file_size)) goto error_cleanup; bsp->num_nodes = chunk->size / 24; if (bsp->num_nodes > 0) { - bsp->nodes = calloc(bsp->num_nodes, sizeof(pxl8_bsp_node)); + bsp->nodes = pxl8_calloc(bsp->num_nodes, sizeof(pxl8_bsp_node)); pxl8_stream_seek(&stream, chunk->offset); for (u32 i = 0; i < bsp->num_nodes; i++) { bsp->nodes[i].plane_id = pxl8_read_u32(&stream); bsp->nodes[i].children[0] = pxl8_read_i16(&stream); bsp->nodes[i].children[1] = pxl8_read_i16(&stream); - for (u32 j = 0; j < 3; j++) bsp->nodes[i].mins[j] = pxl8_read_i16(&stream); - for (u32 j = 0; j < 3; j++) bsp->nodes[i].maxs[j] = pxl8_read_i16(&stream); + i16 nx = pxl8_read_i16(&stream); + i16 ny = pxl8_read_i16(&stream); + i16 nz = pxl8_read_i16(&stream); + bsp->nodes[i].mins[0] = nx; + bsp->nodes[i].mins[1] = nz; + bsp->nodes[i].mins[2] = ny; + i16 mx = pxl8_read_i16(&stream); + i16 my = pxl8_read_i16(&stream); + i16 mz = pxl8_read_i16(&stream); + bsp->nodes[i].maxs[0] = mx; + bsp->nodes[i].maxs[1] = mz; + bsp->nodes[i].maxs[2] = my; bsp->nodes[i].first_face = pxl8_read_u16(&stream); bsp->nodes[i].num_faces = pxl8_read_u16(&stream); } @@ -236,13 +240,23 @@ pxl8_result pxl8_bsp_load(const char* path, pxl8_bsp* bsp) { if (!validate_chunk(chunk, 28, file_size)) goto error_cleanup; bsp->num_leafs = chunk->size / 28; if (bsp->num_leafs > 0) { - bsp->leafs = calloc(bsp->num_leafs, sizeof(pxl8_bsp_leaf)); + bsp->leafs = pxl8_calloc(bsp->num_leafs, sizeof(pxl8_bsp_leaf)); pxl8_stream_seek(&stream, chunk->offset); for (u32 i = 0; i < bsp->num_leafs; i++) { bsp->leafs[i].contents = pxl8_read_i32(&stream); bsp->leafs[i].visofs = pxl8_read_i32(&stream); - for (u32 j = 0; j < 3; j++) bsp->leafs[i].mins[j] = pxl8_read_i16(&stream); - for (u32 j = 0; j < 3; j++) bsp->leafs[i].maxs[j] = pxl8_read_i16(&stream); + i16 nx = pxl8_read_i16(&stream); + i16 ny = pxl8_read_i16(&stream); + i16 nz = pxl8_read_i16(&stream); + bsp->leafs[i].mins[0] = nx; + bsp->leafs[i].mins[1] = nz; + bsp->leafs[i].mins[2] = ny; + i16 mx = pxl8_read_i16(&stream); + i16 my = pxl8_read_i16(&stream); + i16 mz = pxl8_read_i16(&stream); + bsp->leafs[i].maxs[0] = mx; + bsp->leafs[i].maxs[1] = mz; + bsp->leafs[i].maxs[2] = my; bsp->leafs[i].first_marksurface = pxl8_read_u16(&stream); bsp->leafs[i].num_marksurfaces = pxl8_read_u16(&stream); for (u32 j = 0; j < 4; j++) bsp->leafs[i].ambient_level[j] = pxl8_read_u8(&stream); @@ -253,7 +267,7 @@ pxl8_result pxl8_bsp_load(const char* path, pxl8_bsp* bsp) { if (!validate_chunk(chunk, 2, file_size)) goto error_cleanup; bsp->num_marksurfaces = chunk->size / 2; if (bsp->num_marksurfaces > 0) { - bsp->marksurfaces = calloc(bsp->num_marksurfaces, sizeof(u16)); + bsp->marksurfaces = pxl8_calloc(bsp->num_marksurfaces, sizeof(u16)); pxl8_stream_seek(&stream, chunk->offset); for (u32 i = 0; i < bsp->num_marksurfaces; i++) { bsp->marksurfaces[i] = pxl8_read_u16(&stream); @@ -264,11 +278,21 @@ pxl8_result pxl8_bsp_load(const char* path, pxl8_bsp* bsp) { if (!validate_chunk(chunk, 64, file_size)) goto error_cleanup; bsp->num_models = chunk->size / 64; if (bsp->num_models > 0) { - bsp->models = calloc(bsp->num_models, sizeof(pxl8_bsp_model)); + bsp->models = pxl8_calloc(bsp->num_models, sizeof(pxl8_bsp_model)); pxl8_stream_seek(&stream, chunk->offset); for (u32 i = 0; i < bsp->num_models; i++) { - for (u32 j = 0; j < 3; j++) bsp->models[i].mins[j] = pxl8_read_f32(&stream); - for (u32 j = 0; j < 3; j++) bsp->models[i].maxs[j] = pxl8_read_f32(&stream); + f32 minx = pxl8_read_f32(&stream); + f32 miny = pxl8_read_f32(&stream); + f32 minz = pxl8_read_f32(&stream); + bsp->models[i].mins[0] = minx; + bsp->models[i].mins[1] = minz; + bsp->models[i].mins[2] = miny; + f32 maxx = pxl8_read_f32(&stream); + f32 maxy = pxl8_read_f32(&stream); + f32 maxz = pxl8_read_f32(&stream); + bsp->models[i].maxs[0] = maxx; + bsp->models[i].maxs[1] = maxz; + bsp->models[i].maxs[2] = maxy; bsp->models[i].origin = read_vec3(&stream); for (u32 j = 0; j < 4; j++) bsp->models[i].headnode[j] = pxl8_read_i32(&stream); bsp->models[i].visleafs = pxl8_read_i32(&stream); @@ -281,7 +305,7 @@ pxl8_result pxl8_bsp_load(const char* path, pxl8_bsp* bsp) { if (!validate_chunk(chunk, 1, file_size)) goto error_cleanup; bsp->visdata_size = chunk->size; if (bsp->visdata_size > 0) { - bsp->visdata = malloc(bsp->visdata_size); + bsp->visdata = pxl8_malloc(bsp->visdata_size); memcpy(bsp->visdata, file_data + chunk->offset, bsp->visdata_size); } @@ -289,11 +313,11 @@ pxl8_result pxl8_bsp_load(const char* path, pxl8_bsp* bsp) { if (!validate_chunk(chunk, 1, file_size)) goto error_cleanup; bsp->lightdata_size = chunk->size; if (bsp->lightdata_size > 0) { - bsp->lightdata = malloc(bsp->lightdata_size); + bsp->lightdata = pxl8_malloc(bsp->lightdata_size); memcpy(bsp->lightdata, file_data + chunk->offset, bsp->lightdata_size); } - free(file_data); + pxl8_free(file_data); for (u32 i = 0; i < bsp->num_faces; i++) { pxl8_bsp_face* face = &bsp->faces[i]; @@ -327,7 +351,7 @@ pxl8_result pxl8_bsp_load(const char* path, pxl8_bsp* bsp) { error_cleanup: pxl8_error("BSP chunk validation failed: %s", path); - free(file_data); + pxl8_free(file_data); pxl8_bsp_destroy(bsp); return PXL8_ERROR_INVALID_FORMAT; } @@ -335,18 +359,21 @@ error_cleanup: void pxl8_bsp_destroy(pxl8_bsp* bsp) { if (!bsp) return; - free(bsp->edges); - free(bsp->faces); - free(bsp->leafs); - free(bsp->lightdata); - free(bsp->marksurfaces); - free(bsp->models); - free(bsp->nodes); - free(bsp->planes); - free(bsp->surfedges); - free(bsp->texinfo); - free(bsp->vertices); - free(bsp->visdata); + pxl8_free(bsp->cell_portals); + pxl8_free(bsp->edges); + pxl8_free(bsp->faces); + pxl8_free(bsp->leafs); + pxl8_free(bsp->lightdata); + pxl8_free(bsp->marksurfaces); + pxl8_free(bsp->materials); + pxl8_free(bsp->models); + pxl8_free(bsp->nodes); + pxl8_free(bsp->planes); + pxl8_free(bsp->render_face_flags); + pxl8_free(bsp->surfedges); + pxl8_free(bsp->vertex_lights); + pxl8_free(bsp->vertices); + pxl8_free(bsp->visdata); memset(bsp, 0, sizeof(*bsp)); } @@ -375,85 +402,88 @@ bool pxl8_bsp_is_leaf_visible(const pxl8_bsp* bsp, i32 leaf_from, i32 leaf_to) { i32 visofs = bsp->leafs[leaf_from].visofs; if (visofs < 0) return true; - u32 target_byte = leaf_to >> 3; - u32 target_bit = leaf_to & 7; - u32 pvs_size = (bsp->num_leafs + 7) / 8; + u32 row_size = (bsp->num_leafs + 7) >> 3; + u32 byte_idx = (u32)leaf_to >> 3; + u32 bit_idx = (u32)leaf_to & 7; - u32 pos = (u32)visofs; - u32 current_byte = 0; + u8* vis = bsp->visdata + visofs; + u8* vis_end = bsp->visdata + bsp->visdata_size; + u32 out = 0; - while (current_byte < pvs_size && pos < bsp->visdata_size) { - u8 b = bsp->visdata[pos++]; - - if (b != 0) { - if (current_byte == target_byte) { - return (b & (1 << target_bit)) != 0; + while (out < row_size && vis < vis_end) { + if (*vis) { + if (out == byte_idx) { + return (*vis & (1 << bit_idx)) != 0; } - current_byte++; + out++; + vis++; } else { - if (pos >= bsp->visdata_size) return false; - u32 count = bsp->visdata[pos++]; - if (target_byte < current_byte + count) { + vis++; + if (vis >= vis_end) break; + u32 count = *vis++; + if (out + count > byte_idx && byte_idx >= out) { return false; } - current_byte += count; + out += count; } } - return false; + return out > byte_idx ? false : true; } pxl8_bsp_pvs pxl8_bsp_decompress_pvs(const pxl8_bsp* bsp, i32 leaf) { pxl8_bsp_pvs pvs = {0}; - u32 pvs_size = (bsp->num_leafs + 7) / 8; - pvs.data = calloc(pvs_size, 1); - pvs.size = pvs_size; + u32 row = (bsp->num_leafs + 7) >> 3; + pvs.data = pxl8_malloc(row); + pvs.size = row; if (!pvs.data) return pvs; if (!bsp || leaf < 0 || (u32)leaf >= bsp->num_leafs) { - memset(pvs.data, 0xFF, pvs_size); + memset(pvs.data, 0xFF, row); return pvs; } i32 visofs = bsp->leafs[leaf].visofs; if (visofs < 0 || !bsp->visdata || bsp->visdata_size == 0) { - memset(pvs.data, 0xFF, pvs_size); + memset(pvs.data, 0xFF, row); return pvs; } - u32 pos = (u32)visofs; - u32 out = 0; + u8* in = bsp->visdata + visofs; + u8* out = pvs.data; + u8* out_end = pvs.data + row; - while (out < pvs_size && pos < bsp->visdata_size) { - u8 b = bsp->visdata[pos++]; - - if (b != 0) { - pvs.data[out++] = b; + do { + if (*in) { + *out++ = *in++; } else { - if (pos >= bsp->visdata_size) break; - u32 count = bsp->visdata[pos++]; - out += count; + in++; + i32 c = *in++; + while (c > 0 && out < out_end) { + *out++ = 0; + c--; + } } - } + } while (out < out_end); return pvs; } void pxl8_bsp_pvs_destroy(pxl8_bsp_pvs* pvs) { if (pvs) { - free(pvs->data); + pxl8_free(pvs->data); pvs->data = NULL; pvs->size = 0; } } bool pxl8_bsp_pvs_is_visible(const pxl8_bsp_pvs* pvs, i32 leaf) { - if (!pvs || !pvs->data || leaf < 0) return false; - u32 byte_idx = leaf >> 3; - u32 bit_idx = leaf & 7; - if (byte_idx >= pvs->size) return false; + if (!pvs || !pvs->data || leaf < 0) return true; + u32 byte_idx = (u32)leaf >> 3; + u32 bit_idx = (u32)leaf & 7; + if (byte_idx >= pvs->size) return true; return (pvs->data[byte_idx] & (1 << bit_idx)) != 0; } @@ -546,6 +576,89 @@ static inline bool face_in_frustum(const pxl8_bsp* bsp, u32 face_id, const pxl8_ return pxl8_frustum_test_aabb(frustum, face->aabb_min, face->aabb_max); } +static inline bool leaf_in_frustum(const pxl8_bsp_leaf* leaf, const pxl8_frustum* frustum) { + pxl8_vec3 mins = {(f32)leaf->mins[0], (f32)leaf->mins[1], (f32)leaf->mins[2]}; + pxl8_vec3 maxs = {(f32)leaf->maxs[0], (f32)leaf->maxs[1], (f32)leaf->maxs[2]}; + return pxl8_frustum_test_aabb(frustum, mins, maxs); +} + +static inline bool screen_rect_valid(screen_rect r) { + return r.x0 < r.x1 && r.y0 < r.y1; +} + +static inline screen_rect screen_rect_intersect(screen_rect a, screen_rect b) { + return (screen_rect){ + .x0 = (a.x0 > b.x0) ? a.x0 : b.x0, + .y0 = (a.y0 > b.y0) ? a.y0 : b.y0, + .x1 = (a.x1 < b.x1) ? a.x1 : b.x1, + .y1 = (a.y1 < b.y1) ? a.y1 : b.y1, + }; +} + +static inline void expand_rect_with_ndc(screen_rect* r, f32 nx, f32 ny) { + if (nx < r->x0) r->x0 = nx; + if (nx > r->x1) r->x1 = nx; + if (ny < r->y0) r->y0 = ny; + if (ny > r->y1) r->y1 = ny; +} + +static screen_rect project_portal_to_screen(const pxl8_bsp_portal* portal, const pxl8_mat4* vp, f32 wall_height) { + pxl8_vec3 world_corners[4] = { + {portal->x0, 0, portal->z0}, + {portal->x1, 0, portal->z1}, + {portal->x1, wall_height, portal->z1}, + {portal->x0, wall_height, portal->z0}, + }; + + pxl8_vec4 clip[4]; + bool in_front[4]; + i32 front_count = 0; + + const f32 NEAR_W = 0.001f; + + for (i32 i = 0; i < 4; i++) { + clip[i] = pxl8_mat4_multiply_vec4(*vp, (pxl8_vec4){world_corners[i].x, world_corners[i].y, world_corners[i].z, 1.0f}); + in_front[i] = clip[i].w > NEAR_W; + if (in_front[i]) front_count++; + } + + if (front_count == 0) return (screen_rect){0, 0, 0, 0}; + + screen_rect result = {1e30f, 1e30f, -1e30f, -1e30f}; + + for (i32 i = 0; i < 4; i++) { + i32 j = (i + 1) % 4; + pxl8_vec4 a = clip[i]; + pxl8_vec4 b = clip[j]; + bool a_in = in_front[i]; + bool b_in = in_front[j]; + + if (a_in) { + f32 inv_w = 1.0f / a.w; + expand_rect_with_ndc(&result, a.x * inv_w, a.y * inv_w); + } + + if (a_in != b_in) { + f32 t = (NEAR_W - a.w) / (b.w - a.w); + pxl8_vec4 intersection = { + a.x + t * (b.x - a.x), + a.y + t * (b.y - a.y), + a.z + t * (b.z - a.z), + NEAR_W + }; + f32 inv_w = 1.0f / intersection.w; + expand_rect_with_ndc(&result, intersection.x * inv_w, intersection.y * inv_w); + } + } + + if (result.x0 < -1.0f) result.x0 = -1.0f; + if (result.y0 < -1.0f) result.y0 = -1.0f; + if (result.x1 > 1.0f) result.x1 = 1.0f; + if (result.y1 > 1.0f) result.y1 = 1.0f; + + return result; +} + static void collect_face_to_mesh( const pxl8_bsp* bsp, u32 face_id, @@ -564,17 +677,18 @@ static void collect_face_to_mesh( } } - const pxl8_bsp_texinfo* texinfo = NULL; + const pxl8_gfx_material* material = NULL; f32 tex_scale = 64.0f; - if (face->texinfo_id < bsp->num_texinfo) { - texinfo = &bsp->texinfo[face->texinfo_id]; + if (face->material_id < bsp->num_materials) { + material = &bsp->materials[face->material_id]; } u16 base_idx = (u16)mesh->vertex_count; u32 num_verts = 0; for (u32 i = 0; i < face->num_edges && num_verts < 64; i++) { - i32 surfedge_idx = face->first_edge + i; + u32 edge_i = face->side ? (face->num_edges - 1 - i) : i; + i32 surfedge_idx = face->first_edge + edge_i; u32 vert_idx; if (!pxl8_bsp_get_edge_vertex(bsp, surfedge_idx, &vert_idx)) { @@ -584,9 +698,9 @@ static void collect_face_to_mesh( pxl8_vec3 pos = bsp->vertices[vert_idx].position; f32 u = 0.0f, v = 0.0f; - if (texinfo) { - u = (pxl8_vec3_dot(pos, texinfo->u_axis) + texinfo->u_offset) / tex_scale; - v = (pxl8_vec3_dot(pos, texinfo->v_axis) + texinfo->v_offset) / tex_scale; + if (material) { + u = (pxl8_vec3_dot(pos, material->u_axis) + material->u_offset) / tex_scale; + v = (pxl8_vec3_dot(pos, material->v_axis) + material->v_offset) / tex_scale; } u8 light = 255; @@ -613,8 +727,8 @@ static void collect_face_to_mesh( } } -void pxl8_bsp_render_face(pxl8_gfx* gfx, const pxl8_bsp* bsp, u32 face_id, u32 texture_id) { - if (!gfx || !bsp || face_id >= bsp->num_faces) return; +void pxl8_bsp_render_face(pxl8_gfx* gfx, const pxl8_bsp* bsp, u32 face_id, const pxl8_gfx_material* material) { + if (!gfx || !bsp || face_id >= bsp->num_faces || !material) return; pxl8_mesh* mesh = pxl8_mesh_create(64, 192); if (!mesh) return; @@ -623,109 +737,115 @@ void pxl8_bsp_render_face(pxl8_gfx* gfx, const pxl8_bsp* bsp, u32 face_id, u32 t if (mesh->index_count > 0) { pxl8_mat4 identity = pxl8_mat4_identity(); - pxl8_material mat = pxl8_material_create(texture_id); - pxl8_3d_draw_mesh(gfx, mesh, &identity, &mat); + pxl8_3d_draw_mesh(gfx, mesh, &identity, material); } pxl8_mesh_destroy(mesh); } -void pxl8_bsp_render_textured(pxl8_gfx* gfx, const pxl8_bsp* bsp, pxl8_vec3 camera_pos) { - static int call_count = 0; - if (!gfx || !bsp || bsp->num_faces == 0) { - if (call_count++ < 5) { - pxl8_debug("bsp_render_textured: early return - gfx=%p, bsp=%p, num_faces=%u", - (void*)gfx, (void*)bsp, bsp ? bsp->num_faces : 0); - } - return; - } +void pxl8_bsp_render(pxl8_gfx* gfx, const pxl8_bsp* bsp, pxl8_vec3 camera_pos) { + if (!gfx || !bsp || bsp->num_faces == 0) return; + if (!bsp->cell_portals || bsp->num_cell_portals == 0) return; + if (!bsp->materials || bsp->num_materials == 0) return; const pxl8_frustum* frustum = pxl8_3d_get_frustum(gfx); - if (!frustum) { - if (call_count++ < 5) { - pxl8_debug("bsp_render_textured: frustum is NULL!"); - } + const pxl8_mat4* vp = pxl8_3d_get_view_proj(gfx); + if (!frustum || !vp) return; + + i32 camera_leaf = pxl8_bsp_find_leaf(bsp, camera_pos); + if (camera_leaf < 0 || (u32)camera_leaf >= bsp->num_cell_portals) return; + + pxl8_bsp* bsp_mut = (pxl8_bsp*)bsp; + if (!bsp_mut->render_face_flags) { + bsp_mut->render_face_flags = pxl8_calloc(bsp->num_faces, 1); + if (!bsp_mut->render_face_flags) return; + } + memset(bsp_mut->render_face_flags, 0, bsp->num_faces); + + pxl8_bsp_pvs pvs = pxl8_bsp_decompress_pvs(bsp, camera_leaf); + + u32 visited_bytes = (bsp->num_leafs + 7) / 8; + u8* visited = pxl8_calloc(visited_bytes, 1); + screen_rect* cell_windows = pxl8_calloc(bsp->num_leafs, sizeof(screen_rect)); + portal_queue_entry* queue = pxl8_malloc(bsp->num_leafs * 4 * sizeof(portal_queue_entry)); + if (!visited || !cell_windows || !queue) { + pxl8_free(visited); + pxl8_free(cell_windows); + pxl8_free(queue); + pxl8_bsp_pvs_destroy(&pvs); return; } - i32 camera_leaf = pxl8_bsp_find_leaf(bsp, camera_pos); + u32 head = 0, tail = 0; + screen_rect full_screen = {-1.0f, -1.0f, 1.0f, 1.0f}; - static u8* rendered_faces = NULL; - static u32 rendered_faces_capacity = 0; + visited[camera_leaf >> 3] |= (1 << (camera_leaf & 7)); + cell_windows[camera_leaf] = full_screen; + queue[tail++] = (portal_queue_entry){camera_leaf, full_screen}; - if (rendered_faces_capacity < bsp->num_faces) { - u8* new_buffer = realloc(rendered_faces, bsp->num_faces); - if (!new_buffer) return; - rendered_faces = new_buffer; - rendered_faces_capacity = bsp->num_faces; - } + f32 wall_height = 128.0f; - memset(rendered_faces, 0, bsp->num_faces); + while (head < tail) { + portal_queue_entry entry = queue[head++]; + u32 leaf_id = entry.leaf; + screen_rect window = entry.window; - pxl8_mesh* mesh = pxl8_mesh_create(8192, 16384); - if (!mesh) return; + if (leaf_id >= bsp->num_cell_portals) continue; + const pxl8_bsp_cell_portals* cp = &bsp->cell_portals[leaf_id]; - u32 current_texture = 0xFFFFFFFF; + for (u8 i = 0; i < cp->num_portals; i++) { + const pxl8_bsp_portal* portal = &cp->portals[i]; + u32 target = portal->target_leaf; - for (u32 leaf_id = 0; leaf_id < bsp->num_leafs; leaf_id++) { - if (camera_leaf >= 0 && !pxl8_bsp_is_leaf_visible(bsp, camera_leaf, leaf_id)) continue; + if (target >= bsp->num_leafs) continue; + if (bsp->leafs[target].contents == -1) continue; + if (!pxl8_bsp_pvs_is_visible(&pvs, target)) continue; - const pxl8_bsp_leaf* leaf = &bsp->leafs[leaf_id]; + screen_rect portal_rect = project_portal_to_screen(portal, vp, wall_height); + if (!screen_rect_valid(portal_rect)) continue; - for (u32 i = 0; i < leaf->num_marksurfaces; i++) { - u32 surf_idx = leaf->first_marksurface + i; - if (surf_idx >= bsp->num_marksurfaces) continue; + screen_rect new_window = screen_rect_intersect(window, portal_rect); + if (!screen_rect_valid(new_window)) continue; - u32 face_id = bsp->marksurfaces[surf_idx]; - if (face_id >= bsp->num_faces) continue; - - if (rendered_faces[face_id]) continue; - rendered_faces[face_id] = 1; - - if (!face_in_frustum(bsp, face_id, frustum)) { + u32 byte = target >> 3; + u32 bit = target & 7; + if (visited[byte] & (1 << bit)) { + screen_rect existing = cell_windows[target]; + bool expanded = false; + if (new_window.x0 < existing.x0) { cell_windows[target].x0 = new_window.x0; expanded = true; } + if (new_window.y0 < existing.y0) { cell_windows[target].y0 = new_window.y0; expanded = true; } + if (new_window.x1 > existing.x1) { cell_windows[target].x1 = new_window.x1; expanded = true; } + if (new_window.y1 > existing.y1) { cell_windows[target].y1 = new_window.y1; expanded = true; } + if (expanded && tail < bsp->num_leafs * 4) { + queue[tail++] = (portal_queue_entry){target, cell_windows[target]}; + } continue; } - const pxl8_bsp_face* face = &bsp->faces[face_id]; - u32 texture_id = 0; - if (face->texinfo_id < bsp->num_texinfo) { - texture_id = bsp->texinfo[face->texinfo_id].miptex; - } - - if (texture_id != current_texture && mesh->index_count > 0) { - pxl8_mat4 identity = pxl8_mat4_identity(); - pxl8_material mat = pxl8_material_with_lighting(pxl8_material_with_double_sided(pxl8_material_create(current_texture))); - pxl8_3d_draw_mesh(gfx, mesh, &identity, &mat); - pxl8_mesh_clear(mesh); - } - - current_texture = texture_id; - collect_face_to_mesh(bsp, face_id, mesh); + visited[byte] |= (1 << bit); + cell_windows[target] = new_window; + queue[tail++] = (portal_queue_entry){target, new_window}; } } - if (mesh->index_count > 0) { - pxl8_mat4 identity = pxl8_mat4_identity(); - pxl8_material mat = pxl8_material_with_lighting(pxl8_material_with_double_sided(pxl8_material_create(current_texture))); - pxl8_3d_draw_mesh(gfx, mesh, &identity, &mat); + pxl8_mesh* mesh = pxl8_mesh_create(8192, 16384); + if (!mesh) { + pxl8_free(visited); + pxl8_free(cell_windows); + pxl8_free(queue); + return; } - pxl8_mesh_destroy(mesh); -} - -void pxl8_bsp_render_wireframe(pxl8_gfx* gfx, const pxl8_bsp* bsp, pxl8_vec3 camera_pos, u32 color) { - if (!gfx || !bsp) return; - - const pxl8_frustum* frustum = pxl8_3d_get_frustum(gfx); - if (!frustum) return; - - i32 camera_leaf = pxl8_bsp_find_leaf(bsp, camera_pos); - u8 line_color = (u8)(color & 0xFF); + u32 current_material = 0xFFFFFFFF; + u32 total_faces = 0; for (u32 leaf_id = 0; leaf_id < bsp->num_leafs; leaf_id++) { - if (camera_leaf >= 0 && !pxl8_bsp_is_leaf_visible(bsp, camera_leaf, leaf_id)) continue; + u32 byte = leaf_id >> 3; + u32 bit = leaf_id & 7; + if (!(visited[byte] & (1 << bit))) continue; const pxl8_bsp_leaf* leaf = &bsp->leafs[leaf_id]; + if (!leaf_in_frustum(leaf, frustum)) continue; for (u32 i = 0; i < leaf->num_marksurfaces; i++) { u32 surf_idx = leaf->first_marksurface + i; @@ -734,23 +854,45 @@ void pxl8_bsp_render_wireframe(pxl8_gfx* gfx, const pxl8_bsp* bsp, pxl8_vec3 cam u32 face_id = bsp->marksurfaces[surf_idx]; if (face_id >= bsp->num_faces) continue; + if (bsp_mut->render_face_flags[face_id]) continue; + bsp_mut->render_face_flags[face_id] = 1; + if (!face_in_frustum(bsp, face_id, frustum)) continue; const pxl8_bsp_face* face = &bsp->faces[face_id]; + u32 material_id = face->material_id; + if (material_id >= bsp->num_materials) continue; + total_faces++; - for (u32 e = 0; e < face->num_edges; e++) { - i32 surfedge_idx = face->first_edge + e; - - if (surfedge_idx >= (i32)bsp->num_surfedges) continue; - - u32 v0_idx, v1_idx; - if (!pxl8_bsp_get_edge_vertices(bsp, surfedge_idx, &v0_idx, &v1_idx)) continue; - - pxl8_vec3 p0 = bsp->vertices[v0_idx].position; - pxl8_vec3 p1 = bsp->vertices[v1_idx].position; - - pxl8_3d_draw_line(gfx, p0, p1, line_color); + if (material_id != current_material && mesh->index_count > 0 && current_material < bsp->num_materials) { + pxl8_mat4 identity = pxl8_mat4_identity(); + pxl8_3d_draw_mesh(gfx, mesh, &identity, &bsp->materials[current_material]); + pxl8_mesh_clear(mesh); } + + current_material = material_id; + collect_face_to_mesh(bsp, face_id, mesh); } } + + if (mesh->index_count > 0 && current_material < bsp->num_materials) { + pxl8_mat4 identity = pxl8_mat4_identity(); + pxl8_3d_draw_mesh(gfx, mesh, &identity, &bsp->materials[current_material]); + } + + static u32 debug_count = 0; + if (debug_count++ < 5) { + pxl8_debug("BSP render: %u faces, mesh verts=%u indices=%u", total_faces, mesh->vertex_count, mesh->index_count); + if (mesh->vertex_count > 0) { + pxl8_vertex* v = &mesh->vertices[0]; + pxl8_debug(" vert[0]: pos=(%.1f,%.1f,%.1f) uv=(%.2f,%.2f)", + v->position.x, v->position.y, v->position.z, v->u, v->v); + } + } + + pxl8_bsp_pvs_destroy(&pvs); + pxl8_free(visited); + pxl8_free(cell_windows); + pxl8_free(queue); + pxl8_mesh_destroy(mesh); } diff --git a/src/world/pxl8_bsp.h b/src/world/pxl8_bsp.h index 5a587d4..84b4ce7 100644 --- a/src/world/pxl8_bsp.h +++ b/src/world/pxl8_bsp.h @@ -17,7 +17,7 @@ typedef struct pxl8_bsp_face { u16 side; u8 styles[4]; - u16 texinfo_id; + u16 material_id; pxl8_vec3 aabb_min; pxl8_vec3 aabb_max; @@ -63,16 +63,6 @@ typedef struct pxl8_bsp_plane { i32 type; } pxl8_bsp_plane; -typedef struct pxl8_bsp_texinfo { - u32 miptex; - char name[16]; - - f32 u_offset; - pxl8_vec3 u_axis; - - f32 v_offset; - pxl8_vec3 v_axis; -} pxl8_bsp_texinfo; typedef struct pxl8_bsp_vertex { pxl8_vec3 position; @@ -91,47 +81,52 @@ typedef struct pxl8_bsp_lightmap_sample { u8 r; } pxl8_bsp_lightmap_sample; -typedef struct pxl8_bsp_material_batch { - u16* face_indices; - u32 face_count; - u8 material_id; - pxl8_mesh* mesh; -} pxl8_bsp_material_batch; - typedef struct pxl8_bsp_pvs { u8* data; u32 size; } pxl8_bsp_pvs; +typedef struct pxl8_bsp_portal { + f32 x0, z0; + f32 x1, z1; + u32 target_leaf; +} pxl8_bsp_portal; + +typedef struct pxl8_bsp_cell_portals { + pxl8_bsp_portal portals[4]; + u8 num_portals; +} pxl8_bsp_cell_portals; + typedef struct pxl8_bsp { + pxl8_bsp_cell_portals* cell_portals; pxl8_bsp_edge* edges; pxl8_bsp_face* faces; pxl8_bsp_leaf* leafs; u8* lightdata; pxl8_bsp_lightmap* lightmaps; u16* marksurfaces; - pxl8_bsp_material_batch* material_batches; + pxl8_gfx_material* materials; pxl8_bsp_model* models; pxl8_bsp_node* nodes; pxl8_bsp_plane* planes; + u8* render_face_flags; i32* surfedges; - pxl8_bsp_texinfo* texinfo; u32* vertex_lights; pxl8_bsp_vertex* vertices; u8* visdata; u32 lightdata_size; + u32 num_cell_portals; u32 num_edges; u32 num_faces; u32 num_leafs; u32 num_lightmaps; u32 num_marksurfaces; - u32 num_material_batches; + u32 num_materials; u32 num_models; u32 num_nodes; u32 num_planes; u32 num_surfedges; - u32 num_texinfo; u32 num_vertex_lights; u32 num_vertices; u32 visdata_size; @@ -155,9 +150,8 @@ pxl8_bsp_lightmap pxl8_bsp_lightmap_uniform(u8 r, u8 g, u8 b); pxl8_bsp_lightmap pxl8_bsp_lightmap_mapped(u8 width, u8 height, u32 offset); pxl8_bsp_lightmap_sample pxl8_bsp_sample_lightmap(const pxl8_bsp* bsp, u32 face_idx, f32 u, f32 v); -void pxl8_bsp_render_face(pxl8_gfx* gfx, const pxl8_bsp* bsp, u32 face_id, u32 texture_id); -void pxl8_bsp_render_textured(pxl8_gfx* gfx, const pxl8_bsp* bsp, pxl8_vec3 camera_pos); -void pxl8_bsp_render_wireframe(pxl8_gfx* gfx, const pxl8_bsp* bsp, pxl8_vec3 camera_pos, u32 color); +void pxl8_bsp_render_face(pxl8_gfx* gfx, const pxl8_bsp* bsp, u32 face_id, const pxl8_gfx_material* material); +void pxl8_bsp_render(pxl8_gfx* gfx, const pxl8_bsp* bsp, pxl8_vec3 camera_pos); #ifdef __cplusplus } diff --git a/src/world/pxl8_gen.c b/src/world/pxl8_gen.c index ba80b11..eb2982e 100644 --- a/src/world/pxl8_gen.c +++ b/src/world/pxl8_gen.c @@ -1,21 +1,40 @@ #include "pxl8_gen.h" +#include #include #include #include "pxl8_log.h" +#include "pxl8_mem.h" #include "pxl8_rng.h" +#define CELL_SIZE 64.0f +#define PVS_MAX_DEPTH 64 +#define WALL_HEIGHT 128.0f + typedef struct room_grid { u8* cells; i32 width; i32 height; } room_grid; +typedef struct bsp_build_context { + pxl8_bsp* bsp; + const room_grid* grid; + u32 node_count; + u32 plane_offset; +} bsp_build_context; + +typedef struct light_source { + pxl8_vec3 position; + f32 intensity; + f32 radius; +} light_source; + static bool room_grid_init(room_grid* grid, i32 width, i32 height) { grid->width = width; grid->height = height; - grid->cells = calloc(width * height, sizeof(u8)); + grid->cells = pxl8_calloc(width * height, sizeof(u8)); return grid->cells != NULL; } @@ -57,6 +76,333 @@ static void room_grid_fill(room_grid* grid, u8 value) { } } +static f32 compute_vertex_light( + pxl8_vec3 pos, + pxl8_vec3 normal, + const light_source* lights, + u32 num_lights, + f32 ambient +) { + f32 total = ambient; + + for (u32 i = 0; i < num_lights; i++) { + pxl8_vec3 to_light = { + lights[i].position.x - pos.x, + lights[i].position.y - pos.y, + lights[i].position.z - pos.z + }; + + f32 dist_sq = to_light.x * to_light.x + to_light.y * to_light.y + to_light.z * to_light.z; + f32 dist = sqrtf(dist_sq); + + if (dist > lights[i].radius) continue; + if (dist < 1.0f) dist = 1.0f; + + f32 inv_dist = 1.0f / dist; + pxl8_vec3 light_dir = { + to_light.x * inv_dist, + to_light.y * inv_dist, + to_light.z * inv_dist + }; + + f32 ndotl = normal.x * light_dir.x + normal.y * light_dir.y + normal.z * light_dir.z; + if (ndotl < 0) ndotl = 0; + + f32 attenuation = 1.0f - (dist / lights[i].radius); + if (attenuation < 0) attenuation = 0; + attenuation *= attenuation; + + total += lights[i].intensity * ndotl * attenuation; + } + + if (total > 1.0f) total = 1.0f; + return total; +} + +static void compute_bsp_vertex_lighting( + pxl8_bsp* bsp, + const light_source* lights, + u32 num_lights, + f32 ambient +) { + if (!bsp || bsp->num_vertices == 0) return; + + bsp->vertex_lights = pxl8_calloc(bsp->num_vertices, sizeof(u32)); + if (!bsp->vertex_lights) return; + bsp->num_vertex_lights = bsp->num_vertices; + + for (u32 f = 0; f < bsp->num_faces; f++) { + const pxl8_bsp_face* face = &bsp->faces[f]; + pxl8_vec3 normal = {0, 1, 0}; + + if (face->plane_id < bsp->num_planes) { + normal = bsp->planes[face->plane_id].normal; + } + + for (u32 e = 0; e < face->num_edges; e++) { + i32 surfedge_idx = face->first_edge + e; + if (surfedge_idx >= (i32)bsp->num_surfedges) continue; + + i32 edge_idx = bsp->surfedges[surfedge_idx]; + u32 vert_idx; + + if (edge_idx >= 0) { + if ((u32)edge_idx >= bsp->num_edges) continue; + vert_idx = bsp->edges[edge_idx].vertex[0]; + } else { + edge_idx = -edge_idx; + if ((u32)edge_idx >= bsp->num_edges) continue; + vert_idx = bsp->edges[edge_idx].vertex[1]; + } + + if (vert_idx >= bsp->num_vertices) continue; + + pxl8_vec3 pos = bsp->vertices[vert_idx].position; + f32 light = compute_vertex_light(pos, normal, lights, num_lights, ambient); + + u8 light_byte = (u8)(light * 255.0f); + bsp->vertex_lights[vert_idx] = ((u32)light_byte << 24) | 0x00FFFFFF; + } + } + + pxl8_debug("Computed vertex lighting: %u vertices, %u lights", bsp->num_vertices, num_lights); +} + +static pxl8_bsp_cell_portals* build_pxl8_bsp_cell_portals(const room_grid* grid, f32 cell_size) { + i32 total_cells = grid->width * grid->height; + pxl8_bsp_cell_portals* portals = pxl8_calloc(total_cells, sizeof(pxl8_bsp_cell_portals)); + if (!portals) return NULL; + + for (i32 y = 0; y < grid->height; y++) { + for (i32 x = 0; x < grid->width; x++) { + if (room_grid_get(grid, x, y) != 0) continue; + + i32 c = y * grid->width + x; + f32 cx = x * cell_size; + f32 cz = y * cell_size; + + if (x > 0 && room_grid_get(grid, x - 1, y) == 0) { + pxl8_bsp_portal* p = &portals[c].portals[portals[c].num_portals++]; + p->x0 = cx; + p->z0 = cz; + p->x1 = cx; + p->z1 = cz + cell_size; + p->target_leaf = y * grid->width + (x - 1); + } + if (x < grid->width - 1 && room_grid_get(grid, x + 1, y) == 0) { + pxl8_bsp_portal* p = &portals[c].portals[portals[c].num_portals++]; + p->x0 = cx + cell_size; + p->z0 = cz + cell_size; + p->x1 = cx + cell_size; + p->z1 = cz; + p->target_leaf = y * grid->width + (x + 1); + } + if (y > 0 && room_grid_get(grid, x, y - 1) == 0) { + pxl8_bsp_portal* p = &portals[c].portals[portals[c].num_portals++]; + p->x0 = cx + cell_size; + p->z0 = cz; + p->x1 = cx; + p->z1 = cz; + p->target_leaf = (y - 1) * grid->width + x; + } + if (y < grid->height - 1 && room_grid_get(grid, x, y + 1) == 0) { + pxl8_bsp_portal* p = &portals[c].portals[portals[c].num_portals++]; + p->x0 = cx; + p->z0 = cz + cell_size; + p->x1 = cx + cell_size; + p->z1 = cz + cell_size; + p->target_leaf = (y + 1) * grid->width + x; + } + } + } + return portals; +} + +typedef struct flood_entry { + u32 leaf; + u32 depth; +} flood_entry; + +static void portal_flood_bfs( + u32 start_leaf, + const pxl8_bsp_cell_portals* portals, + const pxl8_bsp_leaf* leafs, + u8* pvs, + u32 num_leafs, + f32 cell_size, + i32 grid_width +) { + (void)cell_size; + (void)grid_width; + + u32 pvs_bytes = (num_leafs + 7) / 8; + u8* visited = pxl8_calloc(pvs_bytes, 1); + flood_entry* queue = pxl8_malloc(num_leafs * sizeof(flood_entry)); + if (!visited || !queue) { + pxl8_free(visited); + pxl8_free(queue); + return; + } + + u32 head = 0, tail = 0; + + pvs[start_leaf >> 3] |= (1 << (start_leaf & 7)); + visited[start_leaf >> 3] |= (1 << (start_leaf & 7)); + queue[tail++] = (flood_entry){start_leaf, 0}; + + while (head < tail) { + flood_entry e = queue[head++]; + + if (e.depth >= PVS_MAX_DEPTH) continue; + if (leafs[e.leaf].contents == -1) continue; + + const pxl8_bsp_cell_portals* cp = &portals[e.leaf]; + for (u8 i = 0; i < cp->num_portals; i++) { + u32 target = cp->portals[i].target_leaf; + u32 byte = target >> 3; + u32 bit = target & 7; + + if (visited[byte] & (1 << bit)) continue; + visited[byte] |= (1 << bit); + + if (leafs[target].contents == -1) continue; + + pvs[byte] |= (1 << bit); + queue[tail++] = (flood_entry){target, e.depth + 1}; + } + } + + pxl8_free(visited); + pxl8_free(queue); +} + +static u8* compute_leaf_pvs(u32 start_leaf, const pxl8_bsp_cell_portals* portals, + u32 num_leafs, const pxl8_bsp_leaf* leafs, + const room_grid* grid, f32 cell_size) { + u32 pvs_bytes = (num_leafs + 7) / 8; + u8* pvs = pxl8_calloc(pvs_bytes, 1); + if (!pvs) return NULL; + + portal_flood_bfs(start_leaf, portals, leafs, pvs, num_leafs, cell_size, grid->width); + + return pvs; +} + +static u32 rle_compress_pvs(const u8* pvs, u32 pvs_bytes, u8* out) { + u32 out_pos = 0; + u32 i = 0; + + while (i < pvs_bytes) { + if (pvs[i] != 0) { + out[out_pos++] = pvs[i++]; + } else { + u32 count = 0; + while (i < pvs_bytes && pvs[i] == 0 && count < 255) { + count++; + i++; + } + out[out_pos++] = 0; + out[out_pos++] = (u8)count; + } + } + return out_pos; +} + +static pxl8_result build_pvs_data(pxl8_bsp* bsp, const pxl8_bsp_cell_portals* portals, + const room_grid* grid, f32 cell_size) { + u32 num_leafs = bsp->num_leafs; + u32 pvs_bytes = (num_leafs + 7) / 8; + + u32 max_visdata = num_leafs * pvs_bytes * 2; + u8* visdata = pxl8_malloc(max_visdata); + if (!visdata) return PXL8_ERROR_OUT_OF_MEMORY; + + u32 visdata_pos = 0; + + u8* compressed = pxl8_malloc(pvs_bytes * 2); + if (!compressed) { + pxl8_free(visdata); + return PXL8_ERROR_OUT_OF_MEMORY; + } + + u32 debug_count = 0; + for (u32 leaf = 0; leaf < num_leafs; leaf++) { + if (bsp->leafs[leaf].contents == -1) { + bsp->leafs[leaf].visofs = -1; + continue; + } + + u8* pvs = compute_leaf_pvs(leaf, portals, num_leafs, bsp->leafs, grid, cell_size); + if (!pvs) { + pxl8_free(compressed); + pxl8_free(visdata); + return PXL8_ERROR_OUT_OF_MEMORY; + } + + if (debug_count < 3) { + u32 visible = 0; + for (u32 b = 0; b < pvs_bytes; b++) { + for (u32 i = 0; i < 8; i++) { + if (pvs[b] & (1 << i)) visible++; + } + } + pxl8_debug("Leaf %u PVS: %u cells visible (portals: %u)", leaf, visible, portals[leaf].num_portals); + debug_count++; + } + + u32 compressed_size = rle_compress_pvs(pvs, pvs_bytes, compressed); + + bsp->leafs[leaf].visofs = visdata_pos; + memcpy(visdata + visdata_pos, compressed, compressed_size); + visdata_pos += compressed_size; + + pxl8_free(pvs); + } + + pxl8_free(compressed); + bsp->visdata = pxl8_realloc(visdata, visdata_pos > 0 ? visdata_pos : 1); + bsp->visdata_size = visdata_pos; + + pxl8_debug("Built PVS: %u leafs, %u bytes visdata", num_leafs, visdata_pos); + return PXL8_OK; +} + +static i32 build_bsp_node(bsp_build_context* ctx, i32 x0, i32 y0, i32 x1, i32 y1, i32 depth) { + if (x1 - x0 == 1 && y1 - y0 == 1) { + i32 leaf_idx = y0 * ctx->grid->width + x0; + return -(leaf_idx + 1); + } + + i32 node_idx = ctx->node_count++; + pxl8_bsp_node* node = &ctx->bsp->nodes[node_idx]; + + i32 plane_idx = ctx->plane_offset++; + pxl8_bsp_plane* plane = &ctx->bsp->planes[plane_idx]; + node->plane_id = plane_idx; + + if (depth % 2 == 0) { + i32 mid_x = (x0 + x1) / 2; + f32 split_pos = mid_x * CELL_SIZE; + + plane->normal = (pxl8_vec3){1, 0, 0}; + plane->dist = split_pos; + + node->children[0] = build_bsp_node(ctx, mid_x, y0, x1, y1, depth + 1); + node->children[1] = build_bsp_node(ctx, x0, y0, mid_x, y1, depth + 1); + } else { + i32 mid_y = (y0 + y1) / 2; + f32 split_pos = mid_y * CELL_SIZE; + + plane->normal = (pxl8_vec3){0, 0, 1}; + plane->dist = split_pos; + + node->children[0] = build_bsp_node(ctx, x0, mid_y, x1, y1, depth + 1); + node->children[1] = build_bsp_node(ctx, x0, y0, x1, mid_y, depth + 1); + } + + return node_idx; +} + static pxl8_result grid_to_bsp(pxl8_bsp* bsp, const room_grid* grid) { i32 vertex_count = 0; i32 face_count = 0; @@ -74,37 +420,47 @@ static pxl8_result grid_to_bsp(pxl8_bsp* bsp, const room_grid* grid) { } } - face_count += floor_ceiling_count * 2; + face_count += floor_ceiling_count; vertex_count = face_count * 4; - pxl8_debug("Cave generation: %dx%d grid -> %d faces, %d vertices", + pxl8_debug("Level generation: %dx%d grid -> %d faces, %d vertices", grid->width, grid->height, face_count, vertex_count); - bsp->vertices = calloc(vertex_count, sizeof(pxl8_bsp_vertex)); - bsp->faces = calloc(face_count, sizeof(pxl8_bsp_face)); - bsp->planes = calloc(face_count, sizeof(pxl8_bsp_plane)); - bsp->edges = calloc(vertex_count, sizeof(pxl8_bsp_edge)); - bsp->surfedges = calloc(vertex_count, sizeof(i32)); + i32 total_cells = grid->width * grid->height; + u32 max_nodes = 2 * total_cells; + u32 total_planes = face_count + max_nodes; - if (!bsp->vertices || !bsp->faces || !bsp->planes || !bsp->edges || !bsp->surfedges) { + bsp->vertices = pxl8_calloc(vertex_count, sizeof(pxl8_bsp_vertex)); + bsp->faces = pxl8_calloc(face_count, sizeof(pxl8_bsp_face)); + bsp->planes = pxl8_calloc(total_planes, sizeof(pxl8_bsp_plane)); + bsp->edges = pxl8_calloc(vertex_count, sizeof(pxl8_bsp_edge)); + bsp->surfedges = pxl8_calloc(vertex_count, sizeof(i32)); + bsp->nodes = pxl8_calloc(max_nodes, sizeof(pxl8_bsp_node)); + + u32* face_cell = pxl8_calloc(face_count, sizeof(u32)); + + if (!bsp->vertices || !bsp->faces || !bsp->planes || !bsp->edges || + !bsp->surfedges || !bsp->nodes || !face_cell) { + pxl8_free(face_cell); return PXL8_ERROR_OUT_OF_MEMORY; } - bsp->texinfo = NULL; - bsp->num_texinfo = 0; + bsp->materials = NULL; + bsp->num_materials = 0; i32 vert_idx = 0; i32 face_idx = 0; i32 edge_idx = 0; - const f32 cell_size = 64.0f; - const f32 wall_height = 128.0f; + const f32 cell_size = CELL_SIZE; + const f32 wall_height = WALL_HEIGHT; for (i32 y = 0; y < grid->height; y++) { for (i32 x = 0; x < grid->width; x++) { if (room_grid_get(grid, x, y) == 0) { f32 fx = (f32)x * cell_size; f32 fy = (f32)y * cell_size; + i32 cell_idx = y * grid->width + x; if (room_grid_get(grid, x - 1, y) == 1) { bsp->vertices[vert_idx + 0].position = (pxl8_vec3){fx, 0, fy}; @@ -112,13 +468,13 @@ static pxl8_result grid_to_bsp(pxl8_bsp* bsp, const room_grid* grid) { bsp->vertices[vert_idx + 2].position = (pxl8_vec3){fx, wall_height, fy + cell_size}; bsp->vertices[vert_idx + 3].position = (pxl8_vec3){fx, 0, fy + cell_size}; - bsp->planes[face_idx].normal = (pxl8_vec3){-1, 0, 0}; - bsp->planes[face_idx].dist = -fx; + bsp->planes[face_idx].normal = (pxl8_vec3){1, 0, 0}; + bsp->planes[face_idx].dist = fx; bsp->faces[face_idx].plane_id = face_idx; bsp->faces[face_idx].num_edges = 4; bsp->faces[face_idx].first_edge = edge_idx; - bsp->faces[face_idx].texinfo_id = 0; + bsp->faces[face_idx].material_id = 0; for (i32 i = 0; i < 4; i++) { bsp->edges[edge_idx + i].vertex[0] = vert_idx + i; @@ -127,6 +483,7 @@ static pxl8_result grid_to_bsp(pxl8_bsp* bsp, const room_grid* grid) { } compute_face_aabb(&bsp->faces[face_idx], bsp->vertices, vert_idx); + face_cell[face_idx] = cell_idx; vert_idx += 4; edge_idx += 4; @@ -139,13 +496,13 @@ static pxl8_result grid_to_bsp(pxl8_bsp* bsp, const room_grid* grid) { bsp->vertices[vert_idx + 2].position = (pxl8_vec3){fx + cell_size, wall_height, fy + cell_size}; bsp->vertices[vert_idx + 3].position = (pxl8_vec3){fx + cell_size, wall_height, fy}; - bsp->planes[face_idx].normal = (pxl8_vec3){1, 0, 0}; - bsp->planes[face_idx].dist = fx + cell_size; + bsp->planes[face_idx].normal = (pxl8_vec3){-1, 0, 0}; + bsp->planes[face_idx].dist = -(fx + cell_size); bsp->faces[face_idx].plane_id = face_idx; bsp->faces[face_idx].num_edges = 4; bsp->faces[face_idx].first_edge = edge_idx; - bsp->faces[face_idx].texinfo_id = 0; + bsp->faces[face_idx].material_id = 0; for (i32 i = 0; i < 4; i++) { bsp->edges[edge_idx + i].vertex[0] = vert_idx + i; @@ -154,6 +511,7 @@ static pxl8_result grid_to_bsp(pxl8_bsp* bsp, const room_grid* grid) { } compute_face_aabb(&bsp->faces[face_idx], bsp->vertices, vert_idx); + face_cell[face_idx] = cell_idx; vert_idx += 4; edge_idx += 4; @@ -166,13 +524,13 @@ static pxl8_result grid_to_bsp(pxl8_bsp* bsp, const room_grid* grid) { bsp->vertices[vert_idx + 2].position = (pxl8_vec3){fx + cell_size, wall_height, fy}; bsp->vertices[vert_idx + 3].position = (pxl8_vec3){fx, wall_height, fy}; - bsp->planes[face_idx].normal = (pxl8_vec3){0, 0, -1}; - bsp->planes[face_idx].dist = -fy; + bsp->planes[face_idx].normal = (pxl8_vec3){0, 0, 1}; + bsp->planes[face_idx].dist = fy; bsp->faces[face_idx].plane_id = face_idx; bsp->faces[face_idx].num_edges = 4; bsp->faces[face_idx].first_edge = edge_idx; - bsp->faces[face_idx].texinfo_id = 0; + bsp->faces[face_idx].material_id = 0; for (i32 i = 0; i < 4; i++) { bsp->edges[edge_idx + i].vertex[0] = vert_idx + i; @@ -181,6 +539,7 @@ static pxl8_result grid_to_bsp(pxl8_bsp* bsp, const room_grid* grid) { } compute_face_aabb(&bsp->faces[face_idx], bsp->vertices, vert_idx); + face_cell[face_idx] = cell_idx; vert_idx += 4; edge_idx += 4; @@ -193,13 +552,13 @@ static pxl8_result grid_to_bsp(pxl8_bsp* bsp, const room_grid* grid) { bsp->vertices[vert_idx + 2].position = (pxl8_vec3){fx + cell_size, wall_height, fy + cell_size}; bsp->vertices[vert_idx + 3].position = (pxl8_vec3){fx + cell_size, 0, fy + cell_size}; - bsp->planes[face_idx].normal = (pxl8_vec3){0, 0, 1}; - bsp->planes[face_idx].dist = fy + cell_size; + bsp->planes[face_idx].normal = (pxl8_vec3){0, 0, -1}; + bsp->planes[face_idx].dist = -(fy + cell_size); bsp->faces[face_idx].plane_id = face_idx; bsp->faces[face_idx].num_edges = 4; bsp->faces[face_idx].first_edge = edge_idx; - bsp->faces[face_idx].texinfo_id = 0; + bsp->faces[face_idx].material_id = 0; for (i32 i = 0; i < 4; i++) { bsp->edges[edge_idx + i].vertex[0] = vert_idx + i; @@ -208,6 +567,7 @@ static pxl8_result grid_to_bsp(pxl8_bsp* bsp, const room_grid* grid) { } compute_face_aabb(&bsp->faces[face_idx], bsp->vertices, vert_idx); + face_cell[face_idx] = cell_idx; vert_idx += 4; edge_idx += 4; @@ -222,6 +582,7 @@ static pxl8_result grid_to_bsp(pxl8_bsp* bsp, const room_grid* grid) { if (room_grid_get(grid, x, y) == 0) { f32 fx = (f32)x * cell_size; f32 fy = (f32)y * cell_size; + i32 cell_idx = y * grid->width + x; bsp->vertices[vert_idx + 0].position = (pxl8_vec3){fx, 0, fy}; bsp->vertices[vert_idx + 1].position = (pxl8_vec3){fx, 0, fy + cell_size}; @@ -234,32 +595,7 @@ static pxl8_result grid_to_bsp(pxl8_bsp* bsp, const room_grid* grid) { bsp->faces[face_idx].plane_id = face_idx; bsp->faces[face_idx].num_edges = 4; bsp->faces[face_idx].first_edge = edge_idx; - bsp->faces[face_idx].texinfo_id = 0; - - for (i32 i = 0; i < 4; i++) { - bsp->edges[edge_idx + i].vertex[0] = vert_idx + i; - bsp->edges[edge_idx + i].vertex[1] = vert_idx + ((i + 1) % 4); - bsp->surfedges[edge_idx + i] = edge_idx + i; - } - - compute_face_aabb(&bsp->faces[face_idx], bsp->vertices, vert_idx); - - vert_idx += 4; - edge_idx += 4; - face_idx++; - - bsp->vertices[vert_idx + 0].position = (pxl8_vec3){fx, wall_height, fy}; - bsp->vertices[vert_idx + 1].position = (pxl8_vec3){fx + cell_size, wall_height, fy}; - bsp->vertices[vert_idx + 2].position = (pxl8_vec3){fx + cell_size, wall_height, fy + cell_size}; - bsp->vertices[vert_idx + 3].position = (pxl8_vec3){fx, wall_height, fy + cell_size}; - - bsp->planes[face_idx].normal = (pxl8_vec3){0, -1, 0}; - bsp->planes[face_idx].dist = -wall_height; - - bsp->faces[face_idx].plane_id = face_idx; - bsp->faces[face_idx].num_edges = 4; - bsp->faces[face_idx].first_edge = edge_idx; - bsp->faces[face_idx].texinfo_id = 0; + bsp->faces[face_idx].material_id = 0; for (i32 i = 0; i < 4; i++) { bsp->edges[edge_idx + i].vertex[0] = vert_idx + i; @@ -268,6 +604,7 @@ static pxl8_result grid_to_bsp(pxl8_bsp* bsp, const room_grid* grid) { } compute_face_aabb(&bsp->faces[face_idx], bsp->vertices, vert_idx); + face_cell[face_idx] = cell_idx; vert_idx += 4; edge_idx += 4; @@ -278,28 +615,147 @@ static pxl8_result grid_to_bsp(pxl8_bsp* bsp, const room_grid* grid) { bsp->num_vertices = vertex_count; bsp->num_faces = face_count; - bsp->num_planes = face_count; bsp->num_edges = vertex_count; bsp->num_surfedges = vertex_count; - bsp->leafs = calloc(1, sizeof(pxl8_bsp_leaf)); - bsp->marksurfaces = calloc(face_count, sizeof(u16)); + bsp->leafs = pxl8_calloc(total_cells, sizeof(pxl8_bsp_leaf)); + bsp->marksurfaces = pxl8_calloc(face_count, sizeof(u16)); if (!bsp->leafs || !bsp->marksurfaces) { + pxl8_free(face_cell); return PXL8_ERROR_OUT_OF_MEMORY; } - bsp->num_leafs = 1; + bsp->num_leafs = total_cells; bsp->num_marksurfaces = face_count; - bsp->leafs[0].first_marksurface = 0; - bsp->leafs[0].num_marksurfaces = face_count; - bsp->leafs[0].contents = -2; + u32* faces_per_cell = pxl8_calloc(total_cells, sizeof(u32)); + u32* cell_offset = pxl8_calloc(total_cells, sizeof(u32)); + u32* cell_cursor = pxl8_calloc(total_cells, sizeof(u32)); + + if (!faces_per_cell || !cell_offset || !cell_cursor) { + pxl8_free(faces_per_cell); + pxl8_free(cell_offset); + pxl8_free(cell_cursor); + pxl8_free(face_cell); + return PXL8_ERROR_OUT_OF_MEMORY; + } for (i32 i = 0; i < face_count; i++) { - bsp->marksurfaces[i] = i; + faces_per_cell[face_cell[i]]++; } + u32 offset = 0; + for (i32 c = 0; c < total_cells; c++) { + cell_offset[c] = offset; + offset += faces_per_cell[c]; + } + + for (i32 i = 0; i < face_count; i++) { + u32 c = face_cell[i]; + bsp->marksurfaces[cell_offset[c] + cell_cursor[c]++] = i; + } + + for (i32 y = 0; y < grid->height; y++) { + for (i32 x = 0; x < grid->width; x++) { + i32 c = y * grid->width + x; + pxl8_bsp_leaf* leaf = &bsp->leafs[c]; + + f32 fx = (f32)x * cell_size; + f32 fz = (f32)y * cell_size; + + leaf->mins[0] = (i16)fx; + leaf->mins[1] = 0; + leaf->mins[2] = (i16)fz; + leaf->maxs[0] = (i16)(fx + cell_size); + leaf->maxs[1] = (i16)wall_height; + leaf->maxs[2] = (i16)(fz + cell_size); + + if (room_grid_get(grid, x, y) == 0) { + leaf->contents = -2; + leaf->first_marksurface = cell_offset[c]; + leaf->num_marksurfaces = faces_per_cell[c]; + } else { + leaf->contents = -1; + leaf->first_marksurface = 0; + leaf->num_marksurfaces = 0; + } + leaf->visofs = -1; + } + } + + pxl8_free(faces_per_cell); + pxl8_free(cell_offset); + pxl8_free(cell_cursor); + pxl8_free(face_cell); + + bsp_build_context ctx = { + .bsp = bsp, + .grid = grid, + .node_count = 0, + .plane_offset = face_count, + }; + + build_bsp_node(&ctx, 0, 0, grid->width, grid->height, 0); + bsp->num_nodes = ctx.node_count; + bsp->num_planes = ctx.plane_offset; + + pxl8_debug("Built BSP tree: %u nodes, %u leafs, %u planes", + bsp->num_nodes, bsp->num_leafs, bsp->num_planes); + + pxl8_bsp_cell_portals* portals = build_pxl8_bsp_cell_portals(grid, cell_size); + if (!portals) { + return PXL8_ERROR_OUT_OF_MEMORY; + } + + u32 walkable_cells = 0; + u32 total_portals = 0; + i32 first_walkable = -1; + for (i32 c = 0; c < total_cells; c++) { + if (bsp->leafs[c].contents == -2) { + walkable_cells++; + if (first_walkable < 0) first_walkable = c; + } + total_portals += portals[c].num_portals; + } + pxl8_debug("Portal stats: %u walkable cells, %u total portals (avg %.1f per cell)", + walkable_cells, total_portals, (f32)total_portals / walkable_cells); + + if (first_walkable >= 0) { + u32 pvs_bytes = (total_cells + 7) / 8; + u8* visited = pxl8_calloc(pvs_bytes, 1); + u8* queue = pxl8_malloc(total_cells * sizeof(u32)); + u32 head = 0, tail = 0; + ((u32*)queue)[tail++] = first_walkable; + visited[first_walkable >> 3] |= (1 << (first_walkable & 7)); + u32 reachable = 0; + while (head < tail) { + u32 c = ((u32*)queue)[head++]; + reachable++; + for (u8 i = 0; i < portals[c].num_portals; i++) { + u32 n = portals[c].portals[i].target_leaf; + u32 nb = n >> 3, ni = n & 7; + if (!(visited[nb] & (1 << ni))) { + visited[nb] |= (1 << ni); + ((u32*)queue)[tail++] = n; + } + } + } + pxl8_debug("Connectivity: %u/%u walkable cells reachable from leaf %d", + reachable, walkable_cells, first_walkable); + pxl8_free(visited); + pxl8_free(queue); + } + + pxl8_result pvs_result = build_pvs_data(bsp, portals, grid, cell_size); + if (pvs_result != PXL8_OK) { + pxl8_free(portals); + return pvs_result; + } + + bsp->cell_portals = portals; + bsp->num_cell_portals = total_cells; + return PXL8_OK; } @@ -348,6 +804,9 @@ static pxl8_result procgen_rooms(pxl8_bsp* bsp, const pxl8_procgen_params* param i32 room_count = 0; i32 max_attempts = params->num_rooms * 10; + const f32 cell_size = CELL_SIZE; + const f32 light_height = 80.0f; + for (i32 attempt = 0; attempt < max_attempts && room_count < params->num_rooms && room_count < 256; attempt++) { i32 w = params->min_room_size + (pxl8_rng_next(&rng) % (params->max_room_size - params->min_room_size + 1)); i32 h = params->min_room_size + (pxl8_rng_next(&rng) % (params->max_room_size - params->min_room_size + 1)); @@ -394,7 +853,27 @@ static pxl8_result procgen_rooms(pxl8_bsp* bsp, const pxl8_procgen_params* param params->width, params->height, room_count); pxl8_result result = grid_to_bsp(bsp, &grid); - free(grid.cells); + pxl8_free(grid.cells); + + if (result != PXL8_OK) { + return result; + } + + light_source lights[256]; + u32 num_lights = 0; + + for (i32 i = 0; i < room_count && num_lights < 256; i++) { + f32 cx = (rooms[i].x + rooms[i].w / 2.0f) * cell_size; + f32 cy = (rooms[i].y + rooms[i].h / 2.0f) * cell_size; + + lights[num_lights++] = (light_source){ + .position = {cx, light_height, cy}, + .intensity = 0.8f, + .radius = 300.0f, + }; + } + + compute_bsp_vertex_lighting(bsp, lights, num_lights, 0.1f); return result; } @@ -417,88 +896,3 @@ pxl8_result pxl8_procgen(pxl8_bsp* bsp, const pxl8_procgen_params* params) { return PXL8_ERROR_INVALID_ARGUMENT; } } - -static u32 hash2d(i32 x, i32 y) { - u32 h = ((u32)x * 374761393u) + ((u32)y * 668265263u); - h ^= h >> 13; - h ^= h << 17; - h ^= h >> 5; - return h; -} - -void pxl8_procgen_tex(u8* buffer, const pxl8_procgen_tex_params* params) { - if (!buffer || !params) return; - - for (i32 y = 0; y < params->height; y++) { - for (i32 x = 0; x < params->width; x++) { - f32 u = (f32)x / (f32)params->width; - f32 v = (f32)y / (f32)params->height; - - u8 color = params->base_color; - - // Tile-based pattern (floor style) - if (params->seed == 11111) { - i32 tile_x = (i32)floorf(u * 8.0f); - i32 tile_y = (i32)floorf(v * 8.0f); - u32 h = hash2d(tile_x, tile_y); - - f32 pattern = (f32)(h & 0xFF) / 255.0f; - i32 quantized = (pattern < 0.3f) ? 0 : (pattern < 0.7f) ? 1 : 2; - - color = params->base_color + quantized; - - // Checkerboard dither - if (((tile_x + tile_y) & 1) == 0 && (h & 0x100)) { - color = (color < 255) ? color + 1 : color; - } - } - // Large tile pattern (ceiling style) - else if (params->seed == 22222) { - i32 coarse_x = (i32)floorf(u * 2.0f); - i32 coarse_y = (i32)floorf(v * 2.0f); - u32 coarse_h = hash2d(coarse_x, coarse_y); - - i32 subdivision = (coarse_h >> 8) & 0x3; - i32 tile_x, tile_y; - - switch (subdivision) { - case 0: tile_x = (i32)floorf(u * 3.0f); tile_y = (i32)floorf(v * 3.0f); break; - case 1: tile_x = (i32)floorf(u * 5.0f); tile_y = (i32)floorf(v * 5.0f); break; - case 2: tile_x = (i32)floorf(u * 2.0f); tile_y = (i32)floorf(v * 4.0f); break; - default: tile_x = (i32)floorf(u * 4.0f); tile_y = (i32)floorf(v * 2.0f); break; - } - - u32 h = hash2d(tile_x, tile_y); - f32 pattern = (f32)(h & 0xFF) / 255.0f; - - if (pattern < 0.25f) color = params->base_color; - else if (pattern < 0.50f) color = params->base_color + 1; - else if (pattern < 0.75f) color = params->base_color + 2; - else color = params->base_color + 3; - } - // Brick pattern (wall style) - else { - f32 brick_y = floorf(v * 4.0f); - f32 offset = ((i32)brick_y & 1) ? 0.5f : 0.0f; - i32 brick_x = (i32)floorf(u * 4.0f + offset); - brick_y = (i32)brick_y; - - f32 brick_u = fabsf((u * 4.0f + offset) - floorf(u * 4.0f + offset) - 0.5f); - f32 brick_v = fabsf((v * 4.0f) - floorf(v * 4.0f) - 0.5f); - - u32 h = hash2d(brick_x, (i32)brick_y); - f32 noise = (f32)(h & 0xFF) / 255.0f; - - // Mortar lines - if (brick_u > 0.47f || brick_v > 0.47f) { - color = params->base_color - 2; - } else { - i32 shade = (i32)(noise * 3.0f); - color = params->base_color + shade; - } - } - - buffer[y * params->width + x] = color; - } - } -} diff --git a/src/world/pxl8_gen.h b/src/world/pxl8_gen.h index a887eb1..bef83b0 100644 --- a/src/world/pxl8_gen.h +++ b/src/world/pxl8_gen.h @@ -21,24 +21,11 @@ typedef struct pxl8_procgen_params { i32 num_rooms; } pxl8_procgen_params; -typedef struct pxl8_procgen_tex_params { - char name[16]; - u32 seed; - i32 width; - i32 height; - f32 scale; - f32 roughness; - u8 base_color; - u8 variation; - u8 max_color; -} pxl8_procgen_tex_params; - #ifdef __cplusplus extern "C" { #endif pxl8_result pxl8_procgen(pxl8_bsp* bsp, const pxl8_procgen_params* params); -void pxl8_procgen_tex(u8* buffer, const pxl8_procgen_tex_params* params); #ifdef __cplusplus } diff --git a/src/world/pxl8_world.c b/src/world/pxl8_world.c index 027ce03..b4d1840 100644 --- a/src/world/pxl8_world.c +++ b/src/world/pxl8_world.c @@ -7,23 +7,21 @@ #include "pxl8_gen.h" #include "pxl8_log.h" #include "pxl8_math.h" +#include "pxl8_mem.h" struct pxl8_world { pxl8_bsp bsp; bool loaded; - bool wireframe; - u32 wireframe_color; }; pxl8_world* pxl8_world_create(void) { - pxl8_world* world = (pxl8_world*)calloc(1, sizeof(pxl8_world)); + pxl8_world* world = (pxl8_world*)pxl8_calloc(1, sizeof(pxl8_world)); if (!world) { pxl8_error("Failed to allocate world"); return NULL; } world->loaded = false; - world->wireframe_color = 15; return world; } @@ -35,7 +33,7 @@ void pxl8_world_destroy(pxl8_world* world) { pxl8_bsp_destroy(&world->bsp); } - free(world); + pxl8_free(world); } pxl8_result pxl8_world_generate(pxl8_world* world, pxl8_gfx* gfx, const pxl8_procgen_params* params) { @@ -98,12 +96,12 @@ pxl8_result pxl8_world_apply_textures(pxl8_world* world, const pxl8_world_textur pxl8_bsp* bsp = &world->bsp; - u32 max_texinfo = count * 6; - bsp->texinfo = calloc(max_texinfo, sizeof(pxl8_bsp_texinfo)); - if (!bsp->texinfo) { + u32 max_materials = count * 6; + bsp->materials = pxl8_calloc(max_materials, sizeof(pxl8_gfx_material)); + if (!bsp->materials) { return PXL8_ERROR_OUT_OF_MEMORY; } - bsp->num_texinfo = 0; + bsp->num_materials = 0; for (u32 face_idx = 0; face_idx < bsp->num_faces; face_idx++) { pxl8_bsp_face* face = &bsp->faces[face_idx]; @@ -136,45 +134,50 @@ pxl8_result pxl8_world_apply_textures(pxl8_world* world, const pxl8_world_textur v_axis = (pxl8_vec3){0.0f, 1.0f, 0.0f}; } - u32 texinfo_idx = bsp->num_texinfo; + u32 material_idx = bsp->num_materials; bool found_existing = false; - for (u32 i = 0; i < bsp->num_texinfo; i++) { - if (strcmp(bsp->texinfo[i].name, matched->name) == 0 && - bsp->texinfo[i].miptex == matched->texture_id && - bsp->texinfo[i].u_axis.x == u_axis.x && - bsp->texinfo[i].u_axis.y == u_axis.y && - bsp->texinfo[i].u_axis.z == u_axis.z && - bsp->texinfo[i].v_axis.x == v_axis.x && - bsp->texinfo[i].v_axis.y == v_axis.y && - bsp->texinfo[i].v_axis.z == v_axis.z) { - texinfo_idx = i; + for (u32 i = 0; i < bsp->num_materials; i++) { + if (strcmp(bsp->materials[i].name, matched->name) == 0 && + bsp->materials[i].texture_id == matched->texture_id && + bsp->materials[i].u_axis.x == u_axis.x && + bsp->materials[i].u_axis.y == u_axis.y && + bsp->materials[i].u_axis.z == u_axis.z && + bsp->materials[i].v_axis.x == v_axis.x && + bsp->materials[i].v_axis.y == v_axis.y && + bsp->materials[i].v_axis.z == v_axis.z) { + material_idx = i; found_existing = true; break; } } if (!found_existing) { - if (bsp->num_texinfo >= max_texinfo) { - pxl8_error("Too many unique texinfo entries"); + if (bsp->num_materials >= max_materials) { + pxl8_error("Too many unique material entries"); return PXL8_ERROR_OUT_OF_MEMORY; } - memcpy(bsp->texinfo[texinfo_idx].name, matched->name, sizeof(bsp->texinfo[texinfo_idx].name)); - bsp->texinfo[texinfo_idx].name[sizeof(bsp->texinfo[texinfo_idx].name) - 1] = '\0'; - bsp->texinfo[texinfo_idx].miptex = matched->texture_id; - bsp->texinfo[texinfo_idx].u_offset = 0.0f; - bsp->texinfo[texinfo_idx].v_offset = 0.0f; - bsp->texinfo[texinfo_idx].u_axis = u_axis; - bsp->texinfo[texinfo_idx].v_axis = v_axis; + pxl8_gfx_material* mat = &bsp->materials[material_idx]; + memcpy(mat->name, matched->name, sizeof(mat->name)); + mat->name[sizeof(mat->name) - 1] = '\0'; + mat->texture_id = matched->texture_id; + mat->u_offset = 0.0f; + mat->v_offset = 0.0f; + mat->u_axis = u_axis; + mat->v_axis = v_axis; + mat->alpha = 255; + mat->dither = true; + mat->double_sided = true; + mat->dynamic_lighting = true; - bsp->num_texinfo++; + bsp->num_materials++; } - face->texinfo_id = texinfo_idx; + face->material_id = material_idx; } - pxl8_info("Applied %u textures to %u faces, created %u texinfo entries", - count, bsp->num_faces, bsp->num_texinfo); + pxl8_info("Applied %u textures to %u faces, created %u materials", + count, bsp->num_faces, bsp->num_materials); return PXL8_OK; } @@ -398,9 +401,13 @@ void pxl8_world_render(pxl8_world* world, pxl8_gfx* gfx, pxl8_vec3 camera_pos) { return; } - if (world->wireframe) { - pxl8_bsp_render_wireframe(gfx, &world->bsp, camera_pos, world->wireframe_color); - } else { - pxl8_bsp_render_textured(gfx, &world->bsp, camera_pos); + pxl8_bsp_render(gfx, &world->bsp, camera_pos); +} + +void pxl8_world_set_wireframe(pxl8_world* world, bool enabled) { + if (!world || !world->loaded) return; + + for (u32 i = 0; i < world->bsp.num_materials; i++) { + world->bsp.materials[i].wireframe = enabled; } } diff --git a/src/world/pxl8_world.h b/src/world/pxl8_world.h index 5388a12..8e78fd1 100644 --- a/src/world/pxl8_world.h +++ b/src/world/pxl8_world.h @@ -32,6 +32,7 @@ bool pxl8_world_check_collision(const pxl8_world* world, pxl8_vec3 pos, f32 radi bool pxl8_world_is_loaded(const pxl8_world* world); void pxl8_world_render(pxl8_world* world, pxl8_gfx* gfx, pxl8_vec3 camera_pos); pxl8_vec3 pxl8_world_resolve_collision(const pxl8_world* world, pxl8_vec3 from, pxl8_vec3 to, f32 radius); +void pxl8_world_set_wireframe(pxl8_world* world, bool enabled); #ifdef __cplusplus }