diff --git a/client/src/core/pxl8_io.h b/client/src/core/pxl8_io.h deleted file mode 100644 index f4e73bb..0000000 --- a/client/src/core/pxl8_io.h +++ /dev/null @@ -1,126 +0,0 @@ -#pragma once - -#include -#include -#include - -#include "pxl8_types.h" - -typedef struct { - const u8* bytes; - u32 offset; - u32 size; - bool overflow; -} pxl8_stream; - -static inline pxl8_stream pxl8_stream_create(const u8* bytes, u32 size) { - return (pxl8_stream){ - .bytes = bytes, - .offset = 0, - .size = size, - .overflow = false - }; -} - -static inline bool pxl8_stream_can_read(const pxl8_stream* stream, u32 count) { - return !stream->overflow && stream->offset + count <= stream->size; -} - -static inline bool pxl8_stream_has_overflow(const pxl8_stream* stream) { - return stream->overflow; -} - -static inline void pxl8_stream_seek(pxl8_stream* stream, u32 offset) { - stream->offset = offset; -} - -static inline u32 pxl8_stream_position(const pxl8_stream* stream) { - return stream->offset; -} - -static inline u8 pxl8_read_u8(pxl8_stream* stream) { - if (stream->offset + 1 > stream->size) { stream->overflow = true; return 0; } - return stream->bytes[stream->offset++]; -} - -static inline u16 pxl8_read_u16(pxl8_stream* stream) { - if (stream->offset + 2 > stream->size) { stream->overflow = true; return 0; } - u16 val = (u16)stream->bytes[stream->offset] | ((u16)stream->bytes[stream->offset + 1] << 8); - stream->offset += 2; - return val; -} - -static inline u32 pxl8_read_u32(pxl8_stream* stream) { - if (stream->offset + 4 > stream->size) { stream->overflow = true; return 0; } - u32 val = (u32)stream->bytes[stream->offset] | - ((u32)stream->bytes[stream->offset + 1] << 8) | - ((u32)stream->bytes[stream->offset + 2] << 16) | - ((u32)stream->bytes[stream->offset + 3] << 24); - stream->offset += 4; - return val; -} - -static inline i16 pxl8_read_i16(pxl8_stream* stream) { - return (i16)pxl8_read_u16(stream); -} - -static inline i32 pxl8_read_i32(pxl8_stream* stream) { - return (i32)pxl8_read_u32(stream); -} - -static inline f32 pxl8_read_f32(pxl8_stream* stream) { - u32 val = pxl8_read_u32(stream); - f32 result; - memcpy(&result, &val, sizeof(f32)); - return result; -} - -static inline void pxl8_read_bytes(pxl8_stream* stream, void* dest, u32 count) { - if (stream->offset + count > stream->size) { stream->overflow = true; return; } - for (u32 i = 0; i < count; i++) { - ((u8*)dest)[i] = stream->bytes[stream->offset++]; - } -} - -static inline void pxl8_skip_bytes(pxl8_stream* stream, u32 count) { - if (stream->offset + count > stream->size) { stream->overflow = true; return; } - stream->offset += count; -} - -static inline const u8* pxl8_read_ptr(pxl8_stream* stream, u32 count) { - if (stream->offset + count > stream->size) { stream->overflow = true; return NULL; } - const u8* ptr = &stream->bytes[stream->offset]; - stream->offset += count; - return ptr; -} - -#ifdef __cplusplus -extern "C" { -#endif - -pxl8_result pxl8_io_create_directory(const char* path); -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); - -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); -bool pxl8_key_released(const pxl8_input_state* input, const char* key_name); - -i32 pxl8_mouse_dx(const pxl8_input_state* input); -i32 pxl8_mouse_dy(const pxl8_input_state* input); -bool pxl8_mouse_pressed(const pxl8_input_state* input, i32 button); -bool pxl8_mouse_released(const pxl8_input_state* input, i32 button); -i32 pxl8_mouse_wheel_x(const pxl8_input_state* input); -i32 pxl8_mouse_wheel_y(const pxl8_input_state* input); -i32 pxl8_mouse_x(const pxl8_input_state* input); -i32 pxl8_mouse_y(const pxl8_input_state* input); - -#ifdef __cplusplus -} -#endif diff --git a/client/src/gfx/pxl8_colormap.c b/client/src/gfx/pxl8_colormap.c deleted file mode 100644 index f967751..0000000 --- a/client/src/gfx/pxl8_colormap.c +++ /dev/null @@ -1,79 +0,0 @@ -#include "pxl8_colormap.h" -#include - -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; - - for (u32 i = 1; i < PXL8_FULLBRIGHT_START; i++) { - if (i >= PXL8_DYNAMIC_RANGE_START && i < dynamic_end) { - continue; - } - - u32 c = palette[i]; - u8 pr = (c >> 24) & 0xFF; - u8 pg = (c >> 16) & 0xFF; - u8 pb = (c >> 8) & 0xFF; - - 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; - best_idx = (u8)i; - if (dist == 0) break; - } - } - - return best_idx; -} - -void pxl8_colormap_generate(pxl8_colormap* cm, const u32* palette, const pxl8_level_tint* tint) { - if (!cm || !palette) return; - - 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; - } - - for (u32 light = 0; light < PXL8_LIGHT_LEVELS; light++) { - f32 brightness = (f32)light / (f32)(PXL8_LIGHT_LEVELS - 1); - - for (u32 pal_idx = 0; pal_idx < 256; pal_idx++) { - u8 result_idx; - - if (pal_idx == PXL8_TRANSPARENT) { - result_idx = PXL8_TRANSPARENT; - } else if (pal_idx >= PXL8_FULLBRIGHT_START) { - result_idx = (u8)pal_idx; - } else { - u32 c = palette[pal_idx]; - u8 r = (c >> 24) & 0xFF; - u8 g = (c >> 16) & 0xFF; - u8 b = (c >> 8) & 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); - - result_idx = find_closest_color(palette, target_r, target_g, target_b); - } - - cm->table[light * 256 + pal_idx] = result_idx; - } - } -} diff --git a/client/src/gfx/pxl8_colormap.h b/client/src/gfx/pxl8_colormap.h deleted file mode 100644 index 6e090a0..0000000 --- a/client/src/gfx/pxl8_colormap.h +++ /dev/null @@ -1,43 +0,0 @@ -#pragma once - -#include "pxl8_dither.h" -#include "pxl8_types.h" - -#ifdef __cplusplus -extern "C" { -#endif - -#define PXL8_LIGHT_LEVELS 64 -#define PXL8_COLORMAP_SIZE (256 * PXL8_LIGHT_LEVELS) - -#define PXL8_FULLBRIGHT_START 240 -#define PXL8_TRANSPARENT 0 -#define PXL8_DYNAMIC_RANGE_START 144 -#define PXL8_DYNAMIC_RANGE_COUNT 16 - -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, 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_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]; -} - -#ifdef __cplusplus -} -#endif diff --git a/client/src/gfx/pxl8_gfx.h b/client/src/gfx/pxl8_gfx.h deleted file mode 100644 index ac3acd4..0000000 --- a/client/src/gfx/pxl8_gfx.h +++ /dev/null @@ -1,48 +0,0 @@ -#pragma once - -#include "pxl8_gfx2d.h" -#include "pxl8_gfx3d.h" -#include "pxl8_hal.h" -#include "pxl8_palette.h" -#include "pxl8_types.h" - -typedef struct pxl8_gfx pxl8_gfx; - -#ifdef __cplusplus -extern "C" { -#endif - -pxl8_gfx* pxl8_gfx_create(const pxl8_hal* hal, void* platform_data, pxl8_pixel_mode mode, pxl8_resolution resolution); -void pxl8_gfx_destroy(pxl8_gfx* gfx); - -void pxl8_gfx_present(pxl8_gfx* gfx); -void pxl8_gfx_update(pxl8_gfx* gfx, f32 dt); -void pxl8_gfx_upload_framebuffer(pxl8_gfx* gfx); - -u8 pxl8_gfx_find_color(pxl8_gfx* gfx, u32 color); - -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_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_viewport(pxl8_gfx* gfx, pxl8_viewport vp); -pxl8_viewport pxl8_gfx_viewport(pxl8_bounds bounds, i32 width, i32 height); - -void pxl8_gfx_clear_textures(pxl8_gfx* gfx); -pxl8_result pxl8_gfx_create_texture(pxl8_gfx* gfx, const u8* pixels, u32 width, u32 height); -pxl8_result pxl8_gfx_load_font_atlas(pxl8_gfx* gfx); -pxl8_result pxl8_gfx_load_sprite(pxl8_gfx* gfx, const char* path); - -bool pxl8_gfx_push_target(pxl8_gfx* gfx); -void pxl8_gfx_pop_target(pxl8_gfx* gfx); - -#ifdef __cplusplus -} -#endif diff --git a/client/src/gfx/pxl8_gfx3d.h b/client/src/gfx/pxl8_gfx3d.h deleted file mode 100644 index 0c4f2df..0000000 --- a/client/src/gfx/pxl8_gfx3d.h +++ /dev/null @@ -1,33 +0,0 @@ -#pragma once - -#include "pxl8_3d_camera.h" -#include "pxl8_math.h" -#include "pxl8_mesh.h" -#include "pxl8_types.h" - -typedef struct pxl8_gfx pxl8_gfx; - -typedef struct pxl8_3d_uniforms { - u8 ambient; - u8 fog_color; - f32 fog_density; - f32 time; -} pxl8_3d_uniforms; - -#ifdef __cplusplus -extern "C" { -#endif - -void pxl8_3d_begin_frame(pxl8_gfx* gfx, const pxl8_3d_camera* camera, 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, pxl8_mat4 model, pxl8_material material); -void pxl8_3d_draw_mesh_wireframe(pxl8_gfx* gfx, const pxl8_mesh* mesh, pxl8_mat4 model, u8 color); -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); - -#ifdef __cplusplus -} -#endif diff --git a/client/src/lua/pxl8/vfx.lua b/client/src/lua/pxl8/vfx.lua deleted file mode 100644 index a4372b4..0000000 --- a/client/src/lua/pxl8/vfx.lua +++ /dev/null @@ -1,65 +0,0 @@ -local ffi = require("ffi") -local C = ffi.C -local core = require("pxl8.core") - -local vfx = {} - -function vfx.raster_bars(bars, time) - local c_bars = ffi.new("pxl8_raster_bar[?]", #bars) - for i, bar in ipairs(bars) do - c_bars[i-1].base_y = bar.base_y or 0 - c_bars[i-1].amplitude = bar.amplitude or 10 - c_bars[i-1].height = bar.height or 5 - c_bars[i-1].speed = bar.speed or 1.0 - c_bars[i-1].phase = bar.phase or 0 - c_bars[i-1].color = bar.color or 15 - c_bars[i-1].fade_color = bar.fade_color or bar.color or 15 - end - C.pxl8_vfx_raster_bars(core.gfx, c_bars, #bars, time) -end - -function vfx.plasma(time, scale1, scale2, palette_offset) - C.pxl8_vfx_plasma(core.gfx, time, scale1 or 0.05, scale2 or 0.03, palette_offset or 0) -end - -function vfx.rotozoom(angle, zoom, cx, cy) - local width = C.pxl8_gfx_get_width(core.gfx) - local height = C.pxl8_gfx_get_height(core.gfx) - C.pxl8_vfx_rotozoom(core.gfx, angle, zoom, cx or width/2, cy or height/2) -end - -function vfx.tunnel(time, speed, twist) - C.pxl8_vfx_tunnel(core.gfx, time, speed or 2.0, twist or 0.5) -end - -function vfx.explosion(ps, x, y, color, force) - C.pxl8_vfx_explosion(ps, x, y, color or 15, force or 200.0) -end - -function vfx.fire(ps, x, y, width, palette_start) - C.pxl8_vfx_fire(ps, x, y, width or 50, palette_start or 64) -end - -function vfx.rain(ps, width, wind) - local w = width or C.pxl8_gfx_get_width(core.gfx) - C.pxl8_vfx_rain(ps, w, wind or 0.0) -end - -function vfx.smoke(ps, x, y, color) - C.pxl8_vfx_smoke(ps, x, y, color or 8) -end - -function vfx.snow(ps, width, wind) - local w = width or C.pxl8_gfx_get_width(core.gfx) - C.pxl8_vfx_snow(ps, w, wind or 10.0) -end - -function vfx.sparks(ps, x, y, color) - C.pxl8_vfx_sparks(ps, x, y, color or 15) -end - -function vfx.starfield(ps, speed, spread) - C.pxl8_vfx_starfield(ps, speed or 5.0, spread or 500.0) -end - -return vfx diff --git a/client/src/math/pxl8_simd.h b/client/src/math/pxl8_simd.h deleted file mode 100644 index 8202b24..0000000 --- a/client/src/math/pxl8_simd.h +++ /dev/null @@ -1,299 +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 - -static inline f32 pxl8_fast_inv_sqrt(f32 x) { - f32 half = 0.5f * x; - i32 i = *(i32*)&x; - i = 0x5f375a86 - (i >> 1); - f32 y = *(f32*)&i; - return y * (1.5f - half * y * y); -} - -#ifdef __cplusplus -} -#endif diff --git a/client/src/world/pxl8_gen.c b/client/src/world/pxl8_gen.c deleted file mode 100644 index ba80b11..0000000 --- a/client/src/world/pxl8_gen.c +++ /dev/null @@ -1,504 +0,0 @@ -#include "pxl8_gen.h" - -#include -#include - -#include "pxl8_log.h" -#include "pxl8_rng.h" - -typedef struct room_grid { - u8* cells; - i32 width; - i32 height; -} room_grid; - -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)); - - return grid->cells != NULL; -} - -static u8 room_grid_get(const room_grid* grid, i32 x, i32 y) { - if (x < 0 || x >= grid->width || y < 0 || y >= grid->height) { - return 1; - } - return grid->cells[y * grid->width + x]; -} - -static void room_grid_set(room_grid* grid, i32 x, i32 y, u8 value) { - if (x < 0 || x >= grid->width || y < 0 || y >= grid->height) { - return; - } - grid->cells[y * grid->width + x] = value; -} - -static inline void compute_face_aabb(pxl8_bsp_face* face, const pxl8_bsp_vertex* verts, u32 vert_idx) { - face->aabb_min = (pxl8_vec3){1e30f, 1e30f, 1e30f}; - face->aabb_max = (pxl8_vec3){-1e30f, -1e30f, -1e30f}; - - for (u32 i = 0; i < 4; i++) { - pxl8_vec3 v = verts[vert_idx + i].position; - if (v.x < face->aabb_min.x) face->aabb_min.x = v.x; - if (v.x > face->aabb_max.x) face->aabb_max.x = v.x; - if (v.y < face->aabb_min.y) face->aabb_min.y = v.y; - if (v.y > face->aabb_max.y) face->aabb_max.y = v.y; - if (v.z < face->aabb_min.z) face->aabb_min.z = v.z; - if (v.z > face->aabb_max.z) face->aabb_max.z = v.z; - } -} - -static void room_grid_fill(room_grid* grid, u8 value) { - for (i32 y = 0; y < grid->height; y++) { - for (i32 x = 0; x < grid->width; x++) { - room_grid_set(grid, x, y, value); - } - } -} - -static pxl8_result grid_to_bsp(pxl8_bsp* bsp, const room_grid* grid) { - i32 vertex_count = 0; - i32 face_count = 0; - i32 floor_ceiling_count = 0; - - for (i32 y = 0; y < grid->height; y++) { - for (i32 x = 0; x < grid->width; x++) { - if (room_grid_get(grid, x, y) == 0) { - if (room_grid_get(grid, x - 1, y) == 1) face_count++; - if (room_grid_get(grid, x + 1, y) == 1) face_count++; - if (room_grid_get(grid, x, y - 1) == 1) face_count++; - if (room_grid_get(grid, x, y + 1) == 1) face_count++; - floor_ceiling_count++; - } - } - } - - face_count += floor_ceiling_count * 2; - vertex_count = face_count * 4; - - pxl8_debug("Cave 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)); - - if (!bsp->vertices || !bsp->faces || !bsp->planes || !bsp->edges || !bsp->surfedges) { - return PXL8_ERROR_OUT_OF_MEMORY; - } - - bsp->texinfo = NULL; - bsp->num_texinfo = 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; - - 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; - - if (room_grid_get(grid, x - 1, y) == 1) { - bsp->vertices[vert_idx + 0].position = (pxl8_vec3){fx, 0, fy}; - bsp->vertices[vert_idx + 1].position = (pxl8_vec3){fx, wall_height, fy}; - 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->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++; - } - - if (room_grid_get(grid, x + 1, y) == 1) { - bsp->vertices[vert_idx + 0].position = (pxl8_vec3){fx + cell_size, 0, fy}; - bsp->vertices[vert_idx + 1].position = (pxl8_vec3){fx + cell_size, 0, fy + cell_size}; - 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->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++; - } - - if (room_grid_get(grid, x, y - 1) == 1) { - bsp->vertices[vert_idx + 0].position = (pxl8_vec3){fx, 0, fy}; - bsp->vertices[vert_idx + 1].position = (pxl8_vec3){fx + cell_size, 0, fy}; - 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->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++; - } - - if (room_grid_get(grid, x, y + 1) == 1) { - bsp->vertices[vert_idx + 0].position = (pxl8_vec3){fx, 0, fy + cell_size}; - bsp->vertices[vert_idx + 1].position = (pxl8_vec3){fx, wall_height, fy + cell_size}; - 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->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++; - } - } - } - } - - 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; - - bsp->vertices[vert_idx + 0].position = (pxl8_vec3){fx, 0, fy}; - bsp->vertices[vert_idx + 1].position = (pxl8_vec3){fx, 0, fy + cell_size}; - bsp->vertices[vert_idx + 2].position = (pxl8_vec3){fx + cell_size, 0, fy + cell_size}; - bsp->vertices[vert_idx + 3].position = (pxl8_vec3){fx + cell_size, 0, fy}; - - bsp->planes[face_idx].normal = (pxl8_vec3){0, 1, 0}; - bsp->planes[face_idx].dist = 0; - - 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; - - 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->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)); - - if (!bsp->leafs || !bsp->marksurfaces) { - return PXL8_ERROR_OUT_OF_MEMORY; - } - - bsp->num_leafs = 1; - bsp->num_marksurfaces = face_count; - - bsp->leafs[0].first_marksurface = 0; - bsp->leafs[0].num_marksurfaces = face_count; - bsp->leafs[0].contents = -2; - - for (i32 i = 0; i < face_count; i++) { - bsp->marksurfaces[i] = i; - } - - return PXL8_OK; -} - -static bool bounds_intersects(const pxl8_bounds* a, const pxl8_bounds* b) { - return !(a->x + a->w <= b->x || b->x + b->w <= a->x || - a->y + a->h <= b->y || b->y + b->h <= a->y); -} - -static void carve_corridor_h(room_grid* grid, i32 x1, i32 x2, i32 y) { - i32 start = (x1 < x2) ? x1 : x2; - i32 end = (x1 > x2) ? x1 : x2; - for (i32 x = start; x <= end; x++) { - room_grid_set(grid, x, y, 0); - room_grid_set(grid, x, y - 1, 0); - room_grid_set(grid, x, y + 1, 0); - } -} - -static void carve_corridor_v(room_grid* grid, i32 y1, i32 y2, i32 x) { - i32 start = (y1 < y2) ? y1 : y2; - i32 end = (y1 > y2) ? y1 : y2; - for (i32 y = start; y <= end; y++) { - room_grid_set(grid, x, y, 0); - room_grid_set(grid, x - 1, y, 0); - room_grid_set(grid, x + 1, y, 0); - } -} - -static pxl8_result procgen_rooms(pxl8_bsp* bsp, const pxl8_procgen_params* params) { - pxl8_debug("procgen_rooms called: %dx%d, seed=%u, min=%d, max=%d, num=%d", - params->width, params->height, params->seed, - params->min_room_size, params->max_room_size, params->num_rooms); - - pxl8_rng rng; - pxl8_rng_seed(&rng, params->seed); - - room_grid grid; - if (!room_grid_init(&grid, params->width, params->height)) { - pxl8_error("Failed to allocate room grid"); - return PXL8_ERROR_OUT_OF_MEMORY; - } - - room_grid_fill(&grid, 1); - - pxl8_bounds rooms[256]; - i32 room_count = 0; - i32 max_attempts = params->num_rooms * 10; - - 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)); - i32 x = 1 + (pxl8_rng_next(&rng) % (params->width - w - 2)); - i32 y = 1 + (pxl8_rng_next(&rng) % (params->height - h - 2)); - - pxl8_bounds new_room = {x, y, w, h}; - - bool overlaps = false; - for (i32 i = 0; i < room_count; i++) { - if (bounds_intersects(&new_room, &rooms[i])) { - overlaps = true; - break; - } - } - - if (!overlaps) { - for (i32 ry = y; ry < y + h; ry++) { - for (i32 rx = x; rx < x + w; rx++) { - room_grid_set(&grid, rx, ry, 0); - } - } - - if (room_count > 0) { - i32 new_cx = x + w / 2; - i32 new_cy = y + h / 2; - i32 prev_cx = rooms[room_count - 1].x + rooms[room_count - 1].w / 2; - i32 prev_cy = rooms[room_count - 1].y + rooms[room_count - 1].h / 2; - - if (pxl8_rng_next(&rng) % 2 == 0) { - carve_corridor_h(&grid, prev_cx, new_cx, prev_cy); - carve_corridor_v(&grid, prev_cy, new_cy, new_cx); - } else { - carve_corridor_v(&grid, prev_cy, new_cy, prev_cx); - carve_corridor_h(&grid, prev_cx, new_cx, new_cy); - } - } - - rooms[room_count++] = new_room; - } - } - - pxl8_debug("Room generation: %dx%d grid -> %d rooms created", - params->width, params->height, room_count); - - pxl8_result result = grid_to_bsp(bsp, &grid); - free(grid.cells); - - return result; -} - -pxl8_result pxl8_procgen(pxl8_bsp* bsp, const pxl8_procgen_params* params) { - if (!bsp || !params) { - return PXL8_ERROR_NULL_POINTER; - } - - switch (params->type) { - case PXL8_PROCGEN_ROOMS: - return procgen_rooms(bsp, params); - - case PXL8_PROCGEN_TERRAIN: - pxl8_error("Terrain generation not yet implemented"); - return PXL8_ERROR_NOT_INITIALIZED; - - default: - pxl8_error("Unknown procgen type: %d", params->type); - 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/demo/main.fnl b/demo/main.fnl index d078be3..6b9367d 100644 --- a/demo/main.fnl +++ b/demo/main.fnl @@ -1,16 +1,15 @@ (local pxl8 (require :pxl8)) (local menu (require :mod.menu)) (local music (require :mod.music)) -(local worldgen (require :mod.worldgen)) +(local first_person3d (require :mod.first_person3d)) (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,15 +31,12 @@ (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) - (music.start) - (worldgen.init))) + (music.init))) (global update (fn [dt] (when (pxl8.key_pressed "escape") (menu.toggle) - (when (= active-demo :worldgen) + (when (= active-demo :first_person3d) (pxl8.set_relative_mouse_mode (not (menu.is-paused))))) (when (not (menu.is-paused)) @@ -50,15 +46,16 @@ (transition:update dt) (when (transition:is_complete) (when transition-pending - (when (and (= active-demo :worldgen) (not= transition-pending :worldgen)) + (when (and (= active-demo :first_person3d) (not= transition-pending :first_person3d)) (pxl8.set_relative_mouse_mode false)) - (when (and (not= active-demo :worldgen) (= transition-pending :worldgen)) + (when (and (not= active-demo :first_person3d) (= transition-pending :first_person3d)) (pxl8.set_relative_mouse_mode true)) (set active-demo transition-pending) (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))) @@ -69,12 +66,14 @@ (when (pxl8.key_pressed "5") (switch-demo :fire)) (when (pxl8.key_pressed "6") (switch-demo :rain)) (when (pxl8.key_pressed "7") (switch-demo :snow)) - (when (pxl8.key_pressed "8") (switch-demo :worldgen)) + (when (pxl8.key_pressed "8") (switch-demo :first_person3d)) (when (pxl8.key_pressed "=") (set use-famicube-palette? (not use-famicube-palette?)) (local palette-path (if use-famicube-palette? "res/palettes/famicube.ase" "res/sprites/pxl8_logo.ase")) (pxl8.load_palette palette-path)) + (music.update dt) + (case active-demo :logo (do (set logo-x (+ logo-x (* logo-dx dt))) @@ -91,14 +90,14 @@ (when (> logo-y 296) (set logo-y 296) (set logo-dy (- (math.abs logo-dy))))) - :worldgen (worldgen.update dt)) - - (music.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)))) @@ -173,7 +172,8 @@ (set snow-init? true)) (particles:render))) - :worldgen (worldgen.frame) + :first_person3d (first_person3d.frame) + _ (pxl8.clear 0)) 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 new file mode 100644 index 0000000..c7a7af3 --- /dev/null +++ b/demo/mod/first_person3d.fnl @@ -0,0 +1,516 @@ +(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.010) +(local gravity -800) +(local grid-size 64) +(local ground-y 64) +(local jump-force 175) +(local land-recovery-speed 20) +(local land-squash-amount -4) +(local max-pitch 1.5) +(local move-speed 200) +(local turn-speed 4.0) + +(local sim-tick-rate 60) +(local sim-dt (/ 1.0 sim-tick-rate)) +(local history-size 128) +(local correction-threshold 1.0) + +(var auto-run? false) +(var auto-run-cancel-key nil) +(var bob-time 0) +(var cam-pitch 0) +(var cam-x 1000) +(var cam-y 64) +(var cam-yaw 0) +(var cam-z 1000) +(var camera nil) +(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) +(var velocity-y 0) +(var world nil) +(var fps-avg 0) +(var fps-sample-count 0) +(var fireball-mesh nil) +(var last-dt 0.016) + +(local cursor-look? true) +(local FIREBALL_COLOR 218) +(local STONE_FLOOR_START 37) +(local STONE_WALL_START 2) +(local MOSS_COLOR 200) + +(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) +(var time-accumulator 0) +(var position-history {}) +(var pending-inputs {}) + +(fn history-idx [tick] + (+ 1 (% tick history-size))) + +(fn store-position [tick x z yaw] + (tset position-history (history-idx tick) {:tick tick :x x :z z :yaw yaw})) + +(fn get-position [tick] + (let [entry (. position-history (history-idx tick))] + (when (and entry (= entry.tick tick)) + entry))) + +(fn store-pending-input [tick input] + (tset pending-inputs (history-idx tick) {:tick tick :input input})) + +(fn get-pending-input [tick] + (let [entry (. pending-inputs (history-idx tick))] + (when (and entry (= entry.tick tick)) + entry.input))) + +(fn apply-movement [x z yaw input] + (var new-x x) + (var new-z z) + + (let [move-forward (or input.move_y 0) + move-right (or input.move_x 0)] + (when (or (not= move-forward 0) (not= move-right 0)) + (let [forward-x (- (math.sin yaw)) + forward-z (- (math.cos yaw)) + right-x (math.cos yaw) + right-z (- (math.sin yaw)) + len (math.sqrt (+ (* move-forward move-forward) (* move-right move-right))) + norm-forward (/ move-forward len) + norm-right (/ move-right len) + move-delta (* move-speed sim-dt)] + (set new-x (+ new-x (* move-delta (+ (* forward-x norm-forward) (* right-x norm-right))))) + (set new-z (+ new-z (* move-delta (+ (* forward-z norm-forward) (* right-z norm-right)))))))) + + (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)) + (sky.generate-stars 12345) + (create-fireball-mesh) + + (set network (net.Net.new {:port 7777})) + (when network + (network:connect) + (network:spawn cam-x cam-y cam-z cam-yaw cam-pitch)) + + (let [result (world:generate { + :type pxl8.PROCGEN_ROOMS + :width 64 + :height 64 + :seed 42 + :min_room_size 5 + :max_room_size 10 + :num_rooms 20})] + (if (< result 0) + (pxl8.error (.. "Failed to generate rooms - result: " result)) + (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" + :texture_id floor-tex + :rule (fn [normal] (> normal.y 0.7))} + {:name "ceiling" + :texture_id sky-tex + :rule (fn [normal] (< normal.y -0.7))} + {:name "wall" + :texture_id wall-tex + :rule (fn [normal] (and (<= normal.y 0.7) (>= normal.y -0.7)))}])] + (when (< result 0) + (pxl8.error (.. "Failed to apply textures - result: " result)))))))) + +(fn sample-input [] + (var move-forward 0) + (var move-right 0) + + (when (pxl8.key_pressed "`") + (set auto-run? (not auto-run?)) + (when (and auto-run? (pxl8.key_down "w")) + (set auto-run-cancel-key "w"))) + (when (and auto-run? (not auto-run-cancel-key) (or (pxl8.key_down "w") (pxl8.key_down "s"))) + (set auto-run? false) + (when (pxl8.key_down "s") + (set auto-run-cancel-key "s"))) + (when (and auto-run-cancel-key (not (pxl8.key_down auto-run-cancel-key))) + (set auto-run-cancel-key nil)) + + (when (or (pxl8.key_down "w") auto-run?) + (set move-forward (+ move-forward 1))) + (when (and (pxl8.key_down "s") (not= auto-run-cancel-key "s")) + (set move-forward (- move-forward 1))) + (when (pxl8.key_down "a") + (set move-right (- move-right 1))) + (when (pxl8.key_down "d") + (set move-right (+ move-right 1))) + + {:move_x move-right + :move_y move-forward + :look_dx (pxl8.mouse_dx) + :look_dy (pxl8.mouse_dy)}) + +(fn reconcile [server-tick server-x server-z] + (let [predicted (get-position server-tick)] + (when predicted + (let [dx (- predicted.x server-x) + dz (- predicted.z server-z) + error (math.sqrt (+ (* dx dx) (* dz dz)))] + (when (> error correction-threshold) + (set cam-x server-x) + (set cam-z server-z) + + (for [t (+ server-tick 1) client-tick] + (let [input (get-pending-input t) + hist (get-position t)] + (when (and input hist) + (let [(new-x new-z) (apply-movement cam-x cam-z hist.yaw input)] + (set cam-x new-x) + (set cam-z new-z) + (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)) + (/ fps fps-sample-count))) + (when (>= fps-sample-count 120) + (set fps-sample-count 0) + (set fps-avg 0))) + + (when (world:is_loaded) + (let [input (sample-input) + grid-max (* grid-size cell-size) + movement-yaw cam-yaw] + + (set time-accumulator (+ time-accumulator dt)) + + (while (>= time-accumulator sim-dt) + (set time-accumulator (- time-accumulator sim-dt)) + (set client-tick (+ client-tick 1)) + + (store-pending-input client-tick input) + + (let [(new-x new-z) (apply-movement cam-x cam-z movement-yaw input)] + (when (and (>= new-x 0) (<= new-x grid-max) + (>= new-z 0) (<= new-z grid-max)) + (let [(resolved-x _ resolved-z) (world:resolve_collision cam-x cam-y cam-z new-x cam-y new-z 5)] + (set cam-x resolved-x) + (set cam-z resolved-z))) + + (store-position client-tick cam-x cam-z movement-yaw))) + + (when cursor-look? + (set cam-yaw (- cam-yaw (* input.look_dx cursor-sensitivity))) + (set cam-pitch (math.max (- max-pitch) + (math.min max-pitch + (- cam-pitch (* input.look_dy cursor-sensitivity)))))) + + (when (and (not cursor-look?) (pxl8.key_down "up")) + (set cam-pitch (math.min max-pitch (+ cam-pitch (* turn-speed dt))))) + (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 network + (let [(ok err) (pcall (fn [] + (network:send_input {:move_x input.move_x + :move_y input.move_y + :look_dx input.look_dx + :look_dy input.look_dy + :yaw movement-yaw + :tick client-tick}) + (network:update dt) + (when (network:poll) + (let [snapshot (network:snapshot)] + (when (and snapshot (> snapshot.tick last-processed-tick)) + (set last-processed-tick snapshot.tick) + (let [player-id (network:player_id)] + (when (> player-id 0) + (let [curr (network:entity_userdata player-id)] + (when curr + (let [srv-x (pxl8.unpack_f32_be curr 0) + srv-z (pxl8.unpack_f32_be curr 8)] + (reconcile snapshot.tick srv-x srv-z)))))))))))] + (when (not ok) + (pxl8.error (.. "Network error: " err))))) + + (set smooth-cam-x (+ (* smooth-cam-x (- 1 cam-smoothing)) (* cam-x cam-smoothing))) + (set smooth-cam-z (+ (* smooth-cam-z (- 1 cam-smoothing)) (* cam-z cam-smoothing))) + + (when (and (pxl8.key_pressed "space") grounded?) + (set velocity-y jump-force) + (set grounded? false)) + + (set velocity-y (+ velocity-y (* gravity dt))) + (set cam-y (+ cam-y (* velocity-y dt))) + + (when (<= cam-y ground-y) + (when (not grounded?) + (set land-squash land-squash-amount)) + (set cam-y ground-y) + (set velocity-y 0) + (set grounded? true)) + + (when (< land-squash 0) + (set land-squash (math.min 0 (+ land-squash (* land-recovery-speed dt))))) + + (let [moving (or (not= input.move_x 0) (not= input.move_y 0))] + (if (and moving grounded?) + (set bob-time (+ bob-time (* dt bob-speed))) + (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.5))) + (set real-time (+ real-time dt))))) + +(fn frame [] + (pxl8.clear 1) + + (when (not camera) + (pxl8.error "camera is nil!")) + + (when (not world) + (pxl8.error "world is nil!")) + + (when (and world (not (world:is_loaded))) + (pxl8.text "World not loaded yet..." 5 30 12)) + + (when (and camera world (world:is_loaded)) + (let [bob-offset (* (math.sin bob-time) bob-amount) + eye-y (+ cam-y bob-offset land-squash) + forward-x (- (math.sin cam-yaw)) + forward-z (- (math.cos cam-yaw)) + target-x (+ smooth-cam-x forward-x) + target-y (+ eye-y (math.sin cam-pitch)) + target-z (+ smooth-cam-z forward-z) + aspect (/ (pxl8.get_width) (pxl8.get_height))] + + (camera:lookat [smooth-cam-x eye-y smooth-cam-z] + [target-x target-y target-z] + [0 1 0]) + (camera:set_perspective 1.047 aspect 1.0 4096.0) + + (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))] + (pxl8.begin_frame_3d camera { + :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 light-intensity + :radius light-radius}]}) + (pxl8.clear_depth) + + (sky.update-gradient 1 2 6 6 10 18) + (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]) + + (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}))) + + (pxl8.end_frame_3d)) + + (sky.render-stars cam-yaw cam-pitch 1.0 last-dt) + + (let [cx (/ (pxl8.get_width) 2) + cy (/ (pxl8.get_height) 2) + crosshair-size 4 + 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 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 + :frame frame} diff --git a/demo/mod/menu.fnl b/demo/mod/menu.fnl index 34ee9e0..dca9f0e 100644 --- a/demo/mod/menu.fnl +++ b/demo/mod/menu.fnl @@ -1,6 +1,8 @@ (local pxl8 (require :pxl8)) +(local music (require :mod.music)) (var paused false) +(var wireframe false) (var gui nil) (fn init [] @@ -36,12 +38,22 @@ (when gui (gui:begin_frame) - (pxl8.gui_window 200 100 240 140 "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 140 210 30 "Resume") (hide)) - (when (gui:button 2 215 185 210 32 "Quit") + (let [music-label (if (music.is-playing) "Music: On" "Music: Off")] + (when (gui:button 3 215 175 210 30 music-label) + (if (music.is-playing) + (music.stop) + (music.start)))) + + (let [wire-label (if wireframe "Wireframe: On" "Wireframe: Off")] + (when (gui:button 4 215 210 210 30 wire-label) + (set wireframe (not wireframe)))) + + (when (gui:button 2 215 245 210 30 "Quit") (pxl8.quit)) (if (gui:is_hovering) @@ -51,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/music.fnl b/demo/mod/music.fnl index cdbfc6a..a4e83e4 100644 --- a/demo/mod/music.fnl +++ b/demo/mod/music.fnl @@ -101,7 +101,7 @@ (fn update [dt] (when playing (set time (+ time dt)) - (when (>= time step-duration) + (while (>= time step-duration) (set time (- time step-duration)) (local melody-idx (+ 1 (% step (length melody)))) @@ -125,4 +125,5 @@ :start start :stop stop :update update - :is-playing (fn [] playing)} + :is-playing (fn [] playing) + :get-step (fn [] step)} 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 new file mode 100644 index 0000000..ab359c3 --- /dev/null +++ b/demo/mod/sky.fnl @@ -0,0 +1,271 @@ +(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 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 star-time 0) +(var last-gradient-key nil) +(var random-stars []) +(var tiny-stars []) + +(fn generate-sky-gradient [zenith-r zenith-g zenith-b horizon-r horizon-g horizon-b] + (for [i 0 (- SKY_GRADIENT_COUNT 1)] + (let [t (/ i (- SKY_GRADIENT_COUNT 1)) + r (math.floor (+ zenith-r (* t (- horizon-r zenith-r)))) + g (math.floor (+ zenith-g (* t (- horizon-g zenith-g)))) + b (math.floor (+ zenith-b (* t (- horizon-b zenith-b))))] + (pxl8.set_palette_rgb (+ SKY_GRADIENT_START i) r g b)))) + +(fn create-sky-dome [] + (let [verts [] + indices []] + + (for [i 0 (- sky-rings 1)] + (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) + cos-t1 (math.cos theta1) + y0 (* sky-radius cos-t0) + y1 (* sky-radius cos-t1) + r0 (* sky-radius sin-t0) + r1 (* sky-radius sin-t1) + t0 (/ i sky-rings) + t1 (/ (+ i 1) sky-rings) + c0 (math.floor (+ SKY_GRADIENT_START (* t0 (- SKY_GRADIENT_COUNT 1)) 0.5)) + c1 (math.floor (+ SKY_GRADIENT_START (* t1 (- SKY_GRADIENT_COUNT 1)) 0.5))] + + (for [j 0 (- sky-segments 1)] + (let [phi0 (* (/ j sky-segments) math.pi 2) + phi1 (* (/ (+ j 1) sky-segments) math.pi 2) + cos-p0 (math.cos phi0) + sin-p0 (math.sin phi0) + cos-p1 (math.cos phi1) + sin-p1 (math.sin phi1) + x00 (* r0 cos-p0) z00 (* r0 sin-p0) + x01 (* r0 cos-p1) z01 (* r0 sin-p1) + x10 (* r1 cos-p0) z10 (* r1 sin-p0) + x11 (* r1 cos-p1) z11 (* r1 sin-p1) + nx00 (- (* sin-t0 cos-p0)) ny00 (- cos-t0) nz00 (- (* sin-t0 sin-p0)) + nx01 (- (* sin-t0 cos-p1)) ny01 (- cos-t0) nz01 (- (* sin-t0 sin-p1)) + nx10 (- (* sin-t1 cos-p0)) ny10 (- cos-t1) nz10 (- (* sin-t1 sin-p0)) + nx11 (- (* sin-t1 cos-p1)) ny11 (- cos-t1) nz11 (- (* sin-t1 sin-p1)) + base-idx (# verts)] + + (if (= i 0) + (do + (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}) + (table.insert indices base-idx) + (table.insert indices (+ base-idx 2)) + (table.insert indices (+ base-idx 1))) + (do + (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}) + (table.insert indices base-idx) + (table.insert indices (+ base-idx 3)) + (table.insert indices (+ base-idx 2)) + (table.insert indices base-idx) + (table.insert indices (+ base-idx 2)) + (table.insert indices (+ base-idx 1)))))))) + + (set sky-mesh (pxl8.create_mesh verts indices)))) + +(fn update-gradient [zenith-r zenith-g zenith-b horizon-r horizon-g horizon-b] + (let [key (.. zenith-r "," zenith-g "," zenith-b "," horizon-r "," horizon-g "," horizon-b)] + (when (not= key last-gradient-key) + (generate-sky-gradient zenith-r zenith-g zenith-b horizon-r horizon-g horizon-b) + (set last-gradient-key key)))) + +(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 generate-stars [] + (set random-stars []) + (set tiny-stars []) + + ;; 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)))] + + (when (> dy -0.1) + (table.insert random-stars {:dx dx :dy dy :dz dz + :brightness brightness + :color color})))) + + (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 project-direction [dir-x dir-y dir-z yaw pitch cos-rot sin-rot width height] + (let [rot-x (- (* dir-x cos-rot) (* dir-z sin-rot)) + rot-z (+ (* dir-x sin-rot) (* dir-z cos-rot)) + cos-yaw (math.cos yaw) + sin-yaw (math.sin yaw) + cos-pitch (math.cos pitch) + sin-pitch (math.sin pitch) + rotated-x (+ (* rot-x cos-yaw) (* rot-z sin-yaw)) + rotated-z (+ (* (- rot-x) sin-yaw) (* rot-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))}))))) + +(fn render-stars [yaw pitch intensity dt] + (set star-time (+ star-time (or dt 0))) + (when (> intensity 0) + (let [width (pxl8.get_width) + height (pxl8.get_height) + glows [] + fade-in (* intensity intensity) + time-factor (/ star-time 60) + star-rotation (/ (* star-time math.pi 2) STAR_CYCLE_PERIOD) + cos-rot (math.cos star-rotation) + sin-rot (math.sin star-rotation)] + + (each [i star (ipairs tiny-stars)] + (let [screen (project-direction star.dx star.dy star.dz yaw pitch cos-rot sin-rot width height)] + (when screen + (let [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})))))) + + (each [i star (ipairs random-stars)] + (let [screen (project-direction star.dx star.dy star.dz yaw pitch cos-rot sin-rot width height)] + (when screen + (let [phase (+ (* i 2.137) (* time-factor 3.0)) + twinkle (+ 0.75 (* 0.25 (math.sin (* phase 6.28)))) + int (math.floor (* star.brightness fade-in twinkle))] + (if (> star.brightness 220) + (do + (table.insert glows {:x screen.x :y screen.y + :radius 3 + :intensity (math.floor (* int 1.5)) + :color star.color + :shape effects.GLOW_DIAMOND}) + (table.insert glows {:x screen.x :y screen.y + :radius 5 + :intensity (math.floor (/ int 2)) + :color star.color + :shape effects.GLOW_CIRCLE})) + (> star.brightness 180) + (do + (table.insert glows {:x screen.x :y screen.y + :radius 2 + :intensity int + :color star.color + :shape effects.GLOW_DIAMOND}) + (table.insert glows {:x screen.x :y screen.y + :radius 4 + :intensity (math.floor (/ int 3)) + :color star.color + :shape effects.GLOW_CIRCLE})) + (> star.brightness 120) + (do + (table.insert glows {:x screen.x :y screen.y + :radius 2 + :intensity (math.floor (* int 0.67)) + :color star.color + :shape effects.GLOW_DIAMOND}) + (table.insert glows {:x screen.x :y screen.y + :radius 3 + :intensity (math.floor (/ int 4)) + :color star.color + :shape effects.GLOW_CIRCLE})) + (table.insert glows {:x screen.x :y screen.y + :radius 2 + :intensity (math.floor (* int 0.5)) + :color star.color + :shape effects.GLOW_CIRCLE})))))) + + (when (> (length glows) 0) + (effects.glows glows))))) + +(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 :wireframe wireframe}))) + +{:render render + :render-stars render-stars + :generate-stars generate-stars + :update-gradient update-gradient + :SKY_GRADIENT_START SKY_GRADIENT_START + :SKY_GRADIENT_COUNT SKY_GRADIENT_COUNT} 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/mod/vfx.fnl b/demo/mod/vfx.fnl new file mode 100644 index 0000000..446de1c --- /dev/null +++ b/demo/mod/vfx.fnl @@ -0,0 +1,75 @@ +(local vfx {}) + +(fn vfx.explosion [ps x y ?opts] + (let [opts (or ?opts {}) + color (or opts.color 208) + force (or opts.force 200)] + (ps:set_position x y) + (ps:set_colors color (+ color 15)) + (ps:set_velocity (- force) force (- force) force) + (ps:set_gravity 0 100) + (ps:set_life 0.3 0.8) + (ps:set_size 1 3) + (ps:set_drag 0.98) + (ps:set_spawn_rate 0) + (ps:emit (or opts.count 50)))) + +(fn vfx.fire [ps x y ?opts] + (let [opts (or ?opts {}) + width (or opts.width 50) + color (or opts.color 208)] + (ps:set_position x y) + (ps:set_spread width 5) + (ps:set_colors color (+ color 15)) + (ps:set_velocity -20 20 -80 -40) + (ps:set_gravity 0 -30) + (ps:set_life 0.5 1.5) + (ps:set_size 1 2) + (ps:set_turbulence 30) + (ps:set_drag 0.95) + (ps:set_spawn_rate (or opts.rate 50)))) + +(fn vfx.rain [ps width ?opts] + (let [opts (or ?opts {}) + wind (or opts.wind 0) + color (or opts.color 153)] + (ps:set_position (/ width 2) -10) + (ps:set_spread width 0) + (ps:set_colors color (+ color 3)) + (ps:set_velocity (- wind 10) (+ wind 10) 300 400) + (ps:set_gravity 0 200) + (ps:set_life 1 2) + (ps:set_size 1 1) + (ps:set_drag 1) + (ps:set_spawn_rate (or opts.rate 100)))) + +(fn vfx.smoke [ps x y ?opts] + (let [opts (or ?opts {}) + color (or opts.color 248)] + (ps:set_position x y) + (ps:set_spread 10 5) + (ps:set_colors color (+ color 7)) + (ps:set_velocity -15 15 -30 -10) + (ps:set_gravity 0 -20) + (ps:set_life 1 3) + (ps:set_size 2 4) + (ps:set_turbulence 20) + (ps:set_drag 0.98) + (ps:set_spawn_rate (or opts.rate 20)))) + +(fn vfx.snow [ps width ?opts] + (let [opts (or ?opts {}) + wind (or opts.wind 10) + color (or opts.color 15)] + (ps:set_position (/ width 2) -10) + (ps:set_spread width 0) + (ps:set_colors color color) + (ps:set_velocity (- wind 20) (+ wind 20) 30 60) + (ps:set_gravity 0 10) + (ps:set_life 3 6) + (ps:set_size 1 2) + (ps:set_turbulence 15) + (ps:set_drag 0.99) + (ps:set_spawn_rate (or opts.rate 30)))) + +vfx diff --git a/demo/mod/worldgen.fnl b/demo/mod/worldgen.fnl deleted file mode 100644 index 88e1358..0000000 --- a/demo/mod/worldgen.fnl +++ /dev/null @@ -1,224 +0,0 @@ -(local pxl8 (require :pxl8)) - -(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 gravity -800) -(local grid-size 64) -(local ground-y 64) -(local jump-force 175) -(local land-recovery-speed 20) -(local land-squash-amount -4) -(local max-pitch 1.5) -(local move-speed 200) -(local turn-speed 2.0) - -(var auto-run? false) -(var auto-run-cancel-key nil) -(var bob-time 0) -(var cam-pitch 0) -(var cam-x 1000) -(var cam-y 64) -(var cam-yaw 0) -(var cam-z 1000) -(var camera nil) -(var cursor-look? true) -(var grounded? true) -(var land-squash 0) -(var smooth-cam-x 1000) -(var smooth-cam-z 1000) -(var velocity-y 0) -(var world nil) - -(fn init [] - (set camera (pxl8.create_camera_3d)) - (set world (pxl8.create_world)) - (let [result (world:generate { - :type pxl8.PROCGEN_ROOMS - :width 64 - :height 64 - :seed 42 - :min_room_size 5 - :max_room_size 10 - :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}) - ceiling-tex (pxl8.procgen_tex {:name "ceiling" - :seed 22222 - :width 64 - :height 64 - :base_color 1}) - wall-tex (pxl8.procgen_tex {:name "wall" - :seed 12345 - :width 64 - :height 64 - :base_color 4})] - - (let [result (world:apply_textures [ - {:name "floor" - :texture_id floor-tex - :rule (fn [normal] (> normal.y 0.7))} - {:name "ceiling" - :texture_id ceiling-tex - :rule (fn [normal] (< normal.y -0.7))} - {:name "wall" - :texture_id wall-tex - :rule (fn [normal] (and (<= normal.y 0.7) (>= normal.y -0.7)))}])] - (when (< result 0) - (pxl8.error (.. "Failed to apply textures - result: " result)))))))) - -(fn update [dt] - (when (pxl8.key_pressed "`") - (set auto-run? (not auto-run?)) - (when (and auto-run? (pxl8.key_down "w")) - (set auto-run-cancel-key "w"))) - (when (and auto-run? (not auto-run-cancel-key) (or (pxl8.key_down "w") (pxl8.key_down "s"))) - (set auto-run? false) - (when (pxl8.key_down "s") - (set auto-run-cancel-key "s"))) - (when (and auto-run-cancel-key (not (pxl8.key_down auto-run-cancel-key))) - (set auto-run-cancel-key nil)) - - (when (world:is_loaded) - (let [forward-x (- (math.sin cam-yaw)) - forward-z (- (math.cos cam-yaw)) - right-x (math.cos cam-yaw) - right-z (- (math.sin cam-yaw)) - grid-max (* grid-size cell-size) - move-delta (* move-speed dt)] - - (var moving false) - (var move-forward 0) - (var move-right 0) - - (when (or (pxl8.key_down "w") auto-run?) - (set move-forward (+ move-forward 1))) - - (when (and (pxl8.key_down "s") (not= auto-run-cancel-key "s")) - (set move-forward (- move-forward 1))) - - (when (pxl8.key_down "a") - (set move-right (- move-right 1))) - - (when (pxl8.key_down "d") - (set move-right (+ move-right 1))) - - (set moving (or (not= move-forward 0) (not= move-right 0))) - - (var new-x cam-x) - (var new-z cam-z) - - (when moving - (let [len (math.sqrt (+ (* move-forward move-forward) (* move-right move-right))) - norm-forward (/ move-forward len) - norm-right (/ move-right len)] - (set new-x (+ new-x (* move-delta (+ (* forward-x norm-forward) (* right-x norm-right))))) - (set new-z (+ new-z (* move-delta (+ (* forward-z norm-forward) (* right-z norm-right))))))) - - (when (and (>= new-x 0) (<= new-x grid-max) - (>= new-z 0) (<= new-z grid-max)) - (let [(resolved-x resolved-y resolved-z) (world:resolve_collision cam-x cam-y cam-z new-x cam-y new-z 5)] - (set cam-x resolved-x) - (set cam-z resolved-z))) - - (set smooth-cam-x (+ (* smooth-cam-x (- 1 cam-smoothing)) (* cam-x cam-smoothing))) - (set smooth-cam-z (+ (* smooth-cam-z (- 1 cam-smoothing)) (* cam-z cam-smoothing))) - - (when cursor-look? - (let [dx (pxl8.mouse_dx) - dy (pxl8.mouse_dy)] - (set cam-yaw (- cam-yaw (* dx cursor-sensitivity))) - (set cam-pitch (math.max (- max-pitch) - (math.min max-pitch - (- cam-pitch (* dy cursor-sensitivity))))))) - - (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 "up")) - (set cam-pitch (math.min max-pitch (+ cam-pitch (* turn-speed dt))))) - - (when (and (not cursor-look?) (pxl8.key_down "down")) - (set cam-pitch (math.max (- max-pitch) (- cam-pitch (* turn-speed dt))))) - - (when (and (pxl8.key_pressed "space") grounded?) - (set velocity-y jump-force) - (set grounded? false)) - - (set velocity-y (+ velocity-y (* gravity dt))) - (set cam-y (+ cam-y (* velocity-y dt))) - - (when (<= cam-y ground-y) - (when (not grounded?) - (set land-squash land-squash-amount)) - (set cam-y ground-y) - (set velocity-y 0) - (set grounded? true)) - - (when (< land-squash 0) - (set land-squash (math.min 0 (+ land-squash (* land-recovery-speed dt))))) - - (if (and moving grounded?) - (set bob-time (+ bob-time (* dt bob-speed))) - (let [target-phase (* (math.floor (/ bob-time math.pi)) math.pi)] - (set bob-time (+ (* bob-time 0.8) (* target-phase 0.2)))))))) - -(fn frame [] - (pxl8.clear 0) - - (when (not camera) - (pxl8.error "camera is nil!")) - - (when (not world) - (pxl8.error "world is nil!")) - - (when (and world (not (world:is_loaded))) - (pxl8.text "World not loaded yet..." 5 30 12)) - - (when (and camera world (world:is_loaded)) - (let [bob-offset (* (math.sin bob-time) bob-amount) - eye-y (+ cam-y bob-offset land-squash) - forward-x (- (math.sin cam-yaw)) - forward-z (- (math.cos cam-yaw)) - target-x (+ smooth-cam-x forward-x) - target-y (+ eye-y (math.sin cam-pitch)) - target-z (+ smooth-cam-z forward-z) - aspect (/ (pxl8.get_width) (pxl8.get_height))] - - (camera:lookat [smooth-cam-x eye-y smooth-cam-z] - [target-x target-y target-z] - [0 1 0]) - (camera:set_perspective 1.047 aspect 1.0 4096.0) - - (pxl8.begin_frame_3d camera) - (pxl8.clear_depth) - - (world:render [smooth-cam-x eye-y smooth-cam-z]) - - (pxl8.end_frame_3d) - - (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)) - - (pxl8.text (.. "fps: " (string.format "%.1f" (pxl8.get_fps))) 5 5 12) - (pxl8.text (.. "pos: " (string.format "%.0f" cam-x) "," - (string.format "%.0f" cam-y) "," - (string.format "%.0f" cam-z)) 5 15 12)))) - -{:init init - :update update - :frame frame} diff --git a/demo/res/tiles/adventurer.png b/demo/res/tiles/adventurer.png new file mode 100644 index 0000000..d3b784d Binary files /dev/null and b/demo/res/tiles/adventurer.png differ diff --git a/demo/res/tiles/castle-wall.jpg b/demo/res/tiles/castle-wall.jpg new file mode 100644 index 0000000..151a5c1 Binary files /dev/null and b/demo/res/tiles/castle-wall.jpg differ diff --git a/pxl8.sh b/pxl8.sh index 140dc7a..9ef8c35 100755 --- a/pxl8.sh +++ b/pxl8.sh @@ -56,6 +56,55 @@ build_luajit() { fi } +build_server() { + local mode="$1" + if [[ -d "server" ]]; then + print_info "Building server ($mode mode)" + cd server + if [[ "$mode" == "release" ]]; then + cargo build --release + else + cargo build + fi + local status=$? + cd - > /dev/null + if [[ $status -eq 0 ]]; then + print_info "Built server" + else + print_error "Server build failed" + fi + fi +} + +start_server() { + local mode="$1" + local server_bin + if [[ "$mode" == "release" ]]; then + server_bin="server/target/release/pxl8-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..." + ./$server_bin & + SERVER_PID=$! + 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 +} + +stop_server() { + if [[ -n "$SERVER_PID" ]]; then + print_info "Stopping server" + kill $SERVER_PID 2>/dev/null || true + wait $SERVER_PID 2>/dev/null || true + fi +} + build_sdl() { if [[ ! -f "lib/SDL/build/libSDL3.so" ]] && [[ ! -f "lib/SDL/build/libSDL3.a" ]] && [[ ! -f "lib/SDL/build/libSDL3.dylib" ]]; then print_info "Building SDL3" @@ -113,6 +162,7 @@ print_usage() { echo " --all Clean both build artifacts and dependencies" echo " --deps Clean only dependencies" echo " --release Build/run/clean in release mode (default: debug)" + echo " --server Start game server before running (for networked games)" } setup_sdl3() { @@ -173,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 @@ -264,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 @@ -273,7 +324,7 @@ else BINDIR="$BINDIR/debug" fi -DEP_CFLAGS="-O3 -ffast-math -funroll-loops" +DEP_CFLAGS="-O3 -funroll-loops" case "$COMMAND" in build) @@ -320,7 +371,7 @@ case "$COMMAND" in print_info "Compiler cache: ccache enabled" fi - INCLUDES="-Iclient/src/core -Iclient/src/math -Iclient/src/gfx -Iclient/src/sfx -Iclient/src/script -Iclient/src/hal -Iclient/src/world -Iclient/src/asset -Iclient/src/game -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" @@ -329,38 +380,43 @@ case "$COMMAND" in LIB_SOURCE_FILES="lib/linenoise/linenoise.c lib/miniz/miniz.c" PXL8_SOURCE_FILES=" - client/src/core/pxl8.c - client/src/core/pxl8_io.c - client/src/core/pxl8_log.c - client/src/core/pxl8_rng.c - client/src/math/pxl8_math.c - client/src/gfx/pxl8_anim.c - client/src/gfx/pxl8_atlas.c - client/src/gfx/pxl8_blit.c - client/src/gfx/pxl8_3d_camera.c - client/src/gfx/pxl8_colormap.c - client/src/gfx/pxl8_cpu.c - client/src/gfx/pxl8_dither.c - client/src/gfx/pxl8_font.c - client/src/gfx/pxl8_gfx.c - client/src/gfx/pxl8_mesh.c - client/src/gfx/pxl8_palette.c - client/src/gfx/pxl8_particles.c - client/src/gfx/pxl8_tilemap.c - client/src/gfx/pxl8_tilesheet.c - client/src/gfx/pxl8_transition.c - client/src/sfx/pxl8_sfx.c - client/src/script/pxl8_repl.c - client/src/script/pxl8_script.c - client/src/hal/pxl8_sdl3.c - client/src/world/pxl8_bsp.c - client/src/world/pxl8_gen.c - client/src/world/pxl8_world.c - client/src/asset/pxl8_ase.c - client/src/asset/pxl8_cart.c - client/src/asset/pxl8_save.c - client/src/game/pxl8_gui.c - client/src/game/pxl8_replay.c + src/core/pxl8.c + src/core/pxl8_bytes.c + src/core/pxl8_io.c + src/core/pxl8_log.c + src/core/pxl8_rng.c + src/math/pxl8_math.c + src/gfx/pxl8_anim.c + src/gfx/pxl8_atlas.c + src/gfx/pxl8_blit.c + src/gfx/pxl8_3d_camera.c + src/gfx/pxl8_colormap.c + src/gfx/pxl8_cpu.c + src/gfx/pxl8_dither.c + src/gfx/pxl8_font.c + src/gfx/pxl8_gfx.c + src/gfx/pxl8_lightmap.c + src/gfx/pxl8_mesh.c + src/gfx/pxl8_palette.c + src/gfx/pxl8_particles.c + src/gfx/pxl8_tilemap.c + src/gfx/pxl8_tilesheet.c + src/gfx/pxl8_transition.c + src/sfx/pxl8_sfx.c + src/script/pxl8_repl.c + src/script/pxl8_script.c + src/hal/pxl8_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/gui/pxl8_gui.c + src/core/pxl8_replay.c + src/net/pxl8_net.c + src/net/pxl8_protocol.c " LUAJIT_LIB="lib/luajit/src/libluajit.a" @@ -390,13 +446,13 @@ case "$COMMAND" in NEEDS_REBUILD=false if [[ "$src_file" -nt "$obj_file" ]] || \ - [[ "client/src/core/pxl8_types.h" -nt "$obj_file" ]] || \ - [[ "client/src/core/pxl8_macros.h" -nt "$obj_file" ]]; then + [[ "src/core/pxl8_types.h" -nt "$obj_file" ]] || \ + [[ "src/core/pxl8_macros.h" -nt "$obj_file" ]]; then NEEDS_REBUILD=true fi - if [[ "$src_file" == "client/src/script/pxl8_script.c" ]]; then - for lua_file in client/src/lua/*.lua client/src/lua/pxl8/*.lua lib/fennel/fennel.lua; do + if [[ "$src_file" == "src/script/pxl8_script.c" ]]; then + for lua_file in src/lua/*.lua src/lua/pxl8/*.lua lib/fennel/fennel.lua; do if [[ -f "$lua_file" ]] && [[ "$lua_file" -nt "$obj_file" ]]; then NEEDS_REBUILD=true break @@ -430,16 +486,25 @@ case "$COMMAND" in CART="" EXTRA_ARGS="" + 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 + RUN_SERVER=true elif [[ -z "$CART" ]]; then CART="$arg" fi done + if [[ "$RUN_SERVER" == true ]]; then + build_server "$MODE" + start_server "$MODE" + trap stop_server EXIT + fi + if [[ -z "$CART" ]]; then "$BINDIR/pxl8" $EXTRA_ARGS else diff --git a/server/.cargo/config.toml b/server/.cargo/config.toml new file mode 100644 index 0000000..7317206 --- /dev/null +++ b/server/.cargo/config.toml @@ -0,0 +1,2 @@ +[unstable] +build-std = ["core", "alloc"] diff --git a/server/.gitignore b/server/.gitignore new file mode 100644 index 0000000..2f7896d --- /dev/null +++ b/server/.gitignore @@ -0,0 +1 @@ +target/ diff --git a/server/Cargo.lock b/server/Cargo.lock new file mode 100644 index 0000000..fbbf93d --- /dev/null +++ b/server/Cargo.lock @@ -0,0 +1,1090 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "aho-corasick" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301" +dependencies = [ + "memchr", +] + +[[package]] +name = "arrayvec" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" + +[[package]] +name = "assert_type_match" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f548ad2c4031f2902e3edc1f29c29e835829437de49562d8eb5dc5584d3a1043" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "async-channel" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "924ed96dd52d1b75e9c1a3e6275715fd320f5f9439fb5a4a11fa51f4221158d2" +dependencies = [ + "concurrent-queue", + "event-listener-strategy", + "futures-core", + "pin-project-lite", +] + +[[package]] +name = "async-task" +version = "4.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b75356056920673b02621b35afd0f7dda9306d03c79a30f5c56c44cf256e3de" +dependencies = [ + "portable-atomic", +] + +[[package]] +name = "atomic-waker" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" +dependencies = [ + "portable-atomic", +] + +[[package]] +name = "bevy_ecs" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24637a7c8643cab493f4085cda6bde4895f0e0816699c59006f18819da2ca0b8" +dependencies = [ + "arrayvec", + "bevy_ecs_macros", + "bevy_platform", + "bevy_ptr", + "bevy_reflect", + "bevy_tasks", + "bevy_utils", + "bitflags", + "bumpalo", + "concurrent-queue", + "derive_more", + "fixedbitset", + "indexmap", + "log", + "nonmax", + "serde", + "slotmap", + "smallvec", + "thiserror", + "variadics_please", +] + +[[package]] +name = "bevy_ecs_macros" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6eb14c18ca71e11c69fbae873c2db129064efac6d52e48d0127d37bfba1acfa8" +dependencies = [ + "bevy_macro_utils", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "bevy_macro_utils" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b7272fca0bf30d8ca2571a803598856104b63e5c596d52850f811ed37c5e1e3" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "toml_edit", +] + +[[package]] +name = "bevy_platform" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b29ea749a8e85f98186ab662f607b885b97c804bb14cdb0cdf838164496d474" +dependencies = [ + "critical-section", + "foldhash", + "futures-channel", + "hashbrown", + "js-sys", + "portable-atomic", + "portable-atomic-util", + "serde", + "spin", + "wasm-bindgen", + "wasm-bindgen-futures", +] + +[[package]] +name = "bevy_ptr" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f98cbc6d34bbdb58240b72ed1731931b4991a893b3a3238bb7c42ae054aa676" + +[[package]] +name = "bevy_reflect" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b2a977e2b8dba65b6e9c11039c5f9ef108be428f036b3d1cac13ad86ec59f9c" +dependencies = [ + "assert_type_match", + "bevy_platform", + "bevy_ptr", + "bevy_reflect_derive", + "bevy_utils", + "derive_more", + "disqualified", + "downcast-rs", + "erased-serde", + "foldhash", + "glam", + "indexmap", + "serde", + "smallvec", + "smol_str", + "thiserror", + "uuid", + "variadics_please", + "wgpu-types", +] + +[[package]] +name = "bevy_reflect_derive" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "067af30072b1611fda1a577f1cb678b8ea2c9226133068be808dd49aac30cef0" +dependencies = [ + "bevy_macro_utils", + "indexmap", + "proc-macro2", + "quote", + "syn", + "uuid", +] + +[[package]] +name = "bevy_tasks" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "990ffedd374dd2c4fe8f0fd4bcefd5617d1ee59164b6c3fcc356a69b48e26e8e" +dependencies = [ + "async-channel", + "async-task", + "atomic-waker", + "bevy_platform", + "crossbeam-queue", + "derive_more", + "futures-lite", + "heapless", + "pin-project", +] + +[[package]] +name = "bevy_utils" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e258c44d869f9c41ac0f88a16815c67f2569eb9fff4716828a40273d127b6f84" +dependencies = [ + "bevy_platform", + "disqualified", + "thread_local", +] + +[[package]] +name = "bindgen" +version = "0.72.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "993776b509cfb49c750f11b8f07a46fa23e0a1386ffc01fb1e7d343efc387895" +dependencies = [ + "bitflags", + "cexpr", + "clang-sys", + "itertools", + "log", + "prettyplease", + "proc-macro2", + "quote", + "regex", + "rustc-hash", + "shlex", + "syn", +] + +[[package]] +name = "bitflags" +version = "2.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3" +dependencies = [ + "serde_core", +] + +[[package]] +name = "bumpalo" +version = "3.19.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5dd9dc738b7a8311c7ade152424974d8115f2cdad61e8dab8dac9f2362298510" + +[[package]] +name = "bytemuck" +version = "1.24.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fbdf580320f38b612e485521afda1ee26d10cc9884efaaa750d383e13e3c5f4" +dependencies = [ + "bytemuck_derive", +] + +[[package]] +name = "bytemuck_derive" +version = "1.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9abbd1bc6865053c427f7198e6af43bfdedc55ab791faed4fbd361d789575ff" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "cexpr" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766" +dependencies = [ + "nom", +] + +[[package]] +name = "cfg-if" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" + +[[package]] +name = "clang-sys" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4" +dependencies = [ + "glob", + "libc", + "libloading", +] + +[[package]] +name = "concurrent-queue" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973" +dependencies = [ + "crossbeam-utils", + "portable-atomic", +] + +[[package]] +name = "convert_case" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "633458d4ef8c78b72454de2d54fd6ab2e60f9e02be22f3c6104cdc8a4e0fceb9" +dependencies = [ + "unicode-segmentation", +] + +[[package]] +name = "critical-section" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "790eea4361631c5e7d22598ecd5723ff611904e3344ce8720784c93e3d83d40b" + +[[package]] +name = "crossbeam-queue" +version = "0.3.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f58bbc28f91df819d0aa2a2c00cd19754769c2fad90579b3592b1c9ba7a3115" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" + +[[package]] +name = "derive_more" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d751e9e49156b02b44f9c1815bcb94b984cdcc4396ecc32521c739452808b134" +dependencies = [ + "derive_more-impl", +] + +[[package]] +name = "derive_more-impl" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "799a97264921d8623a957f6c3b9011f3b5492f557bbb7a5a19b7fa6d06ba8dcb" +dependencies = [ + "convert_case", + "proc-macro2", + "quote", + "rustc_version", + "syn", + "unicode-xid", +] + +[[package]] +name = "disqualified" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9c272297e804878a2a4b707cfcfc6d2328b5bb936944613b4fdf2b9269afdfd" + +[[package]] +name = "downcast-rs" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "117240f60069e65410b3ae1bb213295bd828f707b5bec6596a1afc8793ce0cbc" + +[[package]] +name = "either" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" + +[[package]] +name = "equivalent" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" + +[[package]] +name = "erased-serde" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89e8918065695684b2b0702da20382d5ae6065cf3327bc2d6436bd49a71ce9f3" +dependencies = [ + "serde", + "serde_core", + "typeid", +] + +[[package]] +name = "event-listener" +version = "5.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e13b66accf52311f30a0db42147dadea9850cb48cd070028831ae5f5d4b856ab" +dependencies = [ + "concurrent-queue", + "pin-project-lite", +] + +[[package]] +name = "event-listener-strategy" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8be9f3dfaaffdae2972880079a491a1a8bb7cbed0b8dd7a347f668b4150a3b93" +dependencies = [ + "event-listener", + "pin-project-lite", +] + +[[package]] +name = "fixedbitset" +version = "0.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d674e81391d1e1ab681a28d99df07927c6d4aa5b027d7da16ba32d1d21ecd99" + +[[package]] +name = "foldhash" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb" + +[[package]] +name = "futures-channel" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" +dependencies = [ + "futures-core", +] + +[[package]] +name = "futures-core" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" + +[[package]] +name = "futures-lite" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f78e10609fe0e0b3f4157ffab1876319b5b0db102a2c60dc4626306dc46b44ad" +dependencies = [ + "futures-core", + "pin-project-lite", +] + +[[package]] +name = "futures-task" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" + +[[package]] +name = "futures-util" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" +dependencies = [ + "futures-core", + "futures-task", + "pin-project-lite", + "pin-utils", + "slab", +] + +[[package]] +name = "getrandom" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" +dependencies = [ + "cfg-if", + "libc", + "r-efi", + "wasip2", +] + +[[package]] +name = "glam" +version = "0.30.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19fc433e8437a212d1b6f1e68c7824af3aed907da60afa994e7f542d18d12aa9" +dependencies = [ + "serde_core", +] + +[[package]] +name = "glob" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280" + +[[package]] +name = "hash32" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47d60b12902ba28e2730cd37e95b8c9223af2808df9e902d4df49588d1470606" +dependencies = [ + "byteorder", +] + +[[package]] +name = "hashbrown" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" +dependencies = [ + "equivalent", + "serde", + "serde_core", +] + +[[package]] +name = "heapless" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2af2455f757db2b292a9b1768c4b70186d443bcb3b316252d6b540aec1cd89ed" +dependencies = [ + "hash32", + "portable-atomic", + "stable_deref_trait", +] + +[[package]] +name = "indexmap" +version = "2.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7714e70437a7dc3ac8eb7e6f8df75fd8eb422675fc7678aff7364301092b1017" +dependencies = [ + "equivalent", + "hashbrown", +] + +[[package]] +name = "itertools" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" +dependencies = [ + "either", +] + +[[package]] +name = "js-sys" +version = "0.3.85" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c942ebf8e95485ca0d52d97da7c5a2c387d0e7f0ba4c35e93bfcaee045955b3" +dependencies = [ + "once_cell", + "wasm-bindgen", +] + +[[package]] +name = "libc" +version = "0.2.180" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bcc35a38544a891a5f7c865aca548a982ccb3b8650a5b06d0fd33a10283c56fc" + +[[package]] +name = "libloading" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7c4b02199fee7c5d21a5ae7d8cfa79a6ef5bb2fc834d6e9058e89c825efdc55" +dependencies = [ + "cfg-if", + "windows-link", +] + +[[package]] +name = "libm" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9fbbcab51052fe104eb5e5d351cf728d30a5be1fe14d9be8a3b097481fb97de" + +[[package]] +name = "log" +version = "0.4.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" + +[[package]] +name = "memchr" +version = "2.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" + +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + +[[package]] +name = "nom" +version = "7.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" +dependencies = [ + "memchr", + "minimal-lexical", +] + +[[package]] +name = "nonmax" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "610a5acd306ec67f907abe5567859a3c693fb9886eb1f012ab8f2a47bef3db51" + +[[package]] +name = "once_cell" +version = "1.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" + +[[package]] +name = "pin-project" +version = "1.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677f1add503faace112b9f1373e43e9e054bfdd22ff1a63c1bc485eaec6a6a8a" +dependencies = [ + "pin-project-internal", +] + +[[package]] +name = "pin-project-internal" +version = "1.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e918e4ff8c4549eb882f14b3a4bc8c8bc93de829416eacf579f1207a8fbf861" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "portable-atomic" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f89776e4d69bb58bc6993e99ffa1d11f228b839984854c7daeb5d37f87cbe950" + +[[package]] +name = "portable-atomic-util" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8a2f0d8d040d7848a709caf78912debcc3f33ee4b3cac47d73d1e1069e83507" +dependencies = [ + "portable-atomic", +] + +[[package]] +name = "prettyplease" +version = "0.2.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" +dependencies = [ + "proc-macro2", + "syn", +] + +[[package]] +name = "proc-macro2" +version = "1.0.105" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "535d180e0ecab6268a3e718bb9fd44db66bbbc256257165fc699dadf70d16fe7" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "pxl8-server" +version = "0.1.0" +dependencies = [ + "bevy_ecs", + "bindgen", + "libc", + "libm", + "windows-sys", +] + +[[package]] +name = "quote" +version = "1.0.43" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc74d9a594b72ae6656596548f56f667211f8a97b3d4c3d467150794690dc40a" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "r-efi" +version = "5.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" + +[[package]] +name = "regex" +version = "1.12.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "843bc0191f75f3e22651ae5f1e72939ab2f72a4bc30fa80a066bd66edefc24d4" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5276caf25ac86c8d810222b3dbb938e512c55c6831a10f3e6ed1c93b84041f1c" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a2d987857b319362043e95f5353c0535c1f58eec5336fdfcf626430af7def58" + +[[package]] +name = "rustc-hash" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d" + +[[package]] +name = "rustc_version" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" +dependencies = [ + "semver", +] + +[[package]] +name = "rustversion" +version = "1.0.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" + +[[package]] +name = "semver" +version = "1.0.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2" + +[[package]] +name = "serde" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" +dependencies = [ + "serde_core", + "serde_derive", +] + +[[package]] +name = "serde_core" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + +[[package]] +name = "slab" +version = "0.4.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a2ae44ef20feb57a68b23d846850f861394c2e02dc425a50098ae8c90267589" + +[[package]] +name = "slotmap" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bdd58c3c93c3d278ca835519292445cb4b0d4dc59ccfdf7ceadaab3f8aeb4038" +dependencies = [ + "version_check", +] + +[[package]] +name = "smallvec" +version = "1.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" + +[[package]] +name = "smol_str" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd538fb6910ac1099850255cf94a94df6551fbdd602454387d0adb2d1ca6dead" +dependencies = [ + "serde", +] + +[[package]] +name = "spin" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5fe4ccb98d9c292d56fec89a5e07da7fc4cf0dc11e156b41793132775d3e591" +dependencies = [ + "portable-atomic", +] + +[[package]] +name = "stable_deref_trait" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" + +[[package]] +name = "syn" +version = "2.0.114" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4d107df263a3013ef9b1879b0df87d706ff80f65a86ea879bd9c31f9b307c2a" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "thiserror" +version = "2.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f63587ca0f12b72a0600bcba1d40081f830876000bb46dd2337a3051618f4fc8" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "2.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ff15c8ecd7de3849db632e14d18d2571fa09dfc5ed93479bc4485c7a517c913" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "thread_local" +version = "1.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f60246a4944f24f6e018aa17cdeffb7818b76356965d03b07d6a9886e8962185" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "toml_datetime" +version = "0.7.5+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92e1cfed4a3038bc5a127e35a2d360f145e1f4b971b551a2ba5fd7aedf7e1347" +dependencies = [ + "serde_core", +] + +[[package]] +name = "toml_edit" +version = "0.23.10+spec-1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84c8b9f757e028cee9fa244aea147aab2a9ec09d5325a9b01e0a49730c2b5269" +dependencies = [ + "indexmap", + "toml_datetime", + "toml_parser", + "winnow", +] + +[[package]] +name = "toml_parser" +version = "1.0.6+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3198b4b0a8e11f09dd03e133c0280504d0801269e9afa46362ffde1cbeebf44" +dependencies = [ + "winnow", +] + +[[package]] +name = "typeid" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc7d623258602320d5c55d1bc22793b57daff0ec7efc270ea7d55ce1d5f5471c" + +[[package]] +name = "unicode-ident" +version = "1.0.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5" + +[[package]] +name = "unicode-segmentation" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" + +[[package]] +name = "unicode-xid" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" + +[[package]] +name = "uuid" +version = "1.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2e054861b4bd027cd373e18e8d8d8e6548085000e41290d95ce0c373a654b4a" +dependencies = [ + "getrandom", + "js-sys", + "serde_core", + "wasm-bindgen", +] + +[[package]] +name = "variadics_please" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41b6d82be61465f97d42bd1d15bf20f3b0a3a0905018f38f9d6f6962055b0b5c" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "version_check" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" + +[[package]] +name = "wasip2" +version = "1.0.2+wasi-0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9517f9239f02c069db75e65f174b3da828fe5f5b945c4dd26bd25d89c03ebcf5" +dependencies = [ + "wit-bindgen", +] + +[[package]] +name = "wasm-bindgen" +version = "0.2.108" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64024a30ec1e37399cf85a7ffefebdb72205ca1c972291c51512360d90bd8566" +dependencies = [ + "cfg-if", + "once_cell", + "rustversion", + "wasm-bindgen-macro", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.58" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70a6e77fd0ae8029c9ea0063f87c46fde723e7d887703d74ad2616d792e51e6f" +dependencies = [ + "cfg-if", + "futures-util", + "js-sys", + "once_cell", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.108" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "008b239d9c740232e71bd39e8ef6429d27097518b6b30bdf9086833bd5b6d608" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.108" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5256bae2d58f54820e6490f9839c49780dff84c65aeab9e772f15d5f0e913a55" +dependencies = [ + "bumpalo", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.108" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f01b580c9ac74c8d8f0c0e4afb04eeef2acf145458e52c03845ee9cd23e3d12" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "web-sys" +version = "0.3.85" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "312e32e551d92129218ea9a2452120f4aabc03529ef03e4d0d82fb2780608598" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "wgpu-types" +version = "27.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "afdcf84c395990db737f2dd91628706cb31e86d72e53482320d368e52b5da5eb" +dependencies = [ + "bitflags", + "bytemuck", + "js-sys", + "log", + "serde", + "thiserror", + "web-sys", +] + +[[package]] +name = "windows-link" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" + +[[package]] +name = "windows-sys" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" +dependencies = [ + "windows-link", +] + +[[package]] +name = "winnow" +version = "0.7.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a5364e9d77fcdeeaa6062ced926ee3381faa2ee02d3eb83a5c27a8825540829" +dependencies = [ + "memchr", +] + +[[package]] +name = "wit-bindgen" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5" diff --git a/server/Cargo.toml b/server/Cargo.toml new file mode 100644 index 0000000..2ef61a7 --- /dev/null +++ b/server/Cargo.toml @@ -0,0 +1,34 @@ +[package] +name = "pxl8-server" +version = "0.1.0" +edition = "2024" + +[build-dependencies] +bindgen = "0.72" + +[dependencies] +bevy_ecs = { version = "0.18", default-features = false } +libc = { version = "0.2", default-features = false } +libm = { version = "0.2", default-features = false } + +[target.'cfg(windows)'.dependencies] +windows-sys = { version = "0.61", default-features = false, features = [ + "Win32_System_Memory", + "Win32_System_Performance", + "Win32_System_Threading", + "Win32_Networking_WinSock", +] } + +[[bin]] +name = "pxl8-server" +path = "src/main.rs" + +[profile.dev] +panic = "abort" + +[profile.release] +panic = "abort" + +[features] +default = [] +std = ["bevy_ecs/std"] diff --git a/server/build.rs b/server/build.rs new file mode 100644 index 0000000..5c30ae3 --- /dev/null +++ b/server/build.rs @@ -0,0 +1,23 @@ +use std::env; +use std::path::PathBuf; + +fn main() { + let manifest_dir = env::var("CARGO_MANIFEST_DIR").unwrap(); + let pxl8_src = PathBuf::from(&manifest_dir).join("../src"); + + 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(pxl8_src.join("net/pxl8_protocol.h").to_str().unwrap()) + .clang_arg(format!("-I{}", pxl8_src.join("core").display())) + .use_core() + .rustified_enum(".*") + .generate() + .expect("Unable to generate bindings"); + + let out_path = PathBuf::from(env::var("OUT_DIR").unwrap()); + bindings + .write_to_file(out_path.join("protocol.rs")) + .expect("Couldn't write bindings"); +} diff --git a/server/rust-toolchain.toml b/server/rust-toolchain.toml new file mode 100644 index 0000000..5d56faf --- /dev/null +++ b/server/rust-toolchain.toml @@ -0,0 +1,2 @@ +[toolchain] +channel = "nightly" diff --git a/server/src/allocator.rs b/server/src/allocator.rs new file mode 100644 index 0000000..dada493 --- /dev/null +++ b/server/src/allocator.rs @@ -0,0 +1,36 @@ +use core::alloc::{GlobalAlloc, Layout}; + +pub struct Allocator; + +#[cfg(unix)] +unsafe impl GlobalAlloc for Allocator { + unsafe fn alloc(&self, layout: Layout) -> *mut u8 { + unsafe { libc::memalign(layout.align(), layout.size()) as *mut u8 } + } + + unsafe fn dealloc(&self, ptr: *mut u8, _layout: Layout) { + unsafe { libc::free(ptr as *mut libc::c_void) } + } + + unsafe fn realloc(&self, ptr: *mut u8, _layout: Layout, new_size: usize) -> *mut u8 { + unsafe { libc::realloc(ptr as *mut libc::c_void, new_size) as *mut u8 } + } +} + +#[cfg(windows)] +unsafe impl GlobalAlloc for Allocator { + unsafe fn alloc(&self, layout: Layout) -> *mut u8 { + use windows_sys::Win32::System::Memory::*; + unsafe { HeapAlloc(GetProcessHeap(), 0, layout.size()) as *mut u8 } + } + + unsafe fn dealloc(&self, ptr: *mut u8, _layout: Layout) { + use windows_sys::Win32::System::Memory::*; + unsafe { HeapFree(GetProcessHeap(), 0, ptr as *mut core::ffi::c_void) }; + } + + unsafe fn realloc(&self, ptr: *mut u8, _layout: Layout, new_size: usize) -> *mut u8 { + use windows_sys::Win32::System::Memory::*; + unsafe { HeapReAlloc(GetProcessHeap(), 0, ptr as *mut core::ffi::c_void, new_size) as *mut u8 } + } +} diff --git a/server/src/components.rs b/server/src/components.rs new file mode 100644 index 0000000..02f3516 --- /dev/null +++ b/server/src/components.rs @@ -0,0 +1,45 @@ +use bevy_ecs::prelude::*; + +#[derive(Component, Clone, Copy, Default)] +pub struct Position { + pub x: f32, + pub y: f32, + pub z: f32, +} + +#[derive(Component, Clone, Copy, Default)] +pub struct Rotation { + pub pitch: f32, + pub yaw: f32, +} + +#[derive(Component, Clone, Copy, Default)] +pub struct Velocity { + pub x: f32, + pub y: f32, + pub z: f32, +} + +#[derive(Component, Clone, Copy)] +pub struct Health { + pub current: f32, + pub max: f32, +} + +impl Health { + pub fn new(max: f32) -> Self { + Self { current: max, max } + } +} + +impl Default for Health { + fn default() -> Self { + Self::new(100.0) + } +} + +#[derive(Component, Clone, Copy, Default)] +pub struct Player; + +#[derive(Component, Clone, Copy)] +pub struct TypeId(pub u16); diff --git a/server/src/lib.rs b/server/src/lib.rs new file mode 100644 index 0000000..a628640 --- /dev/null +++ b/server/src/lib.rs @@ -0,0 +1,18 @@ +#![no_std] + +extern crate alloc; + +pub mod components; +mod simulation; +pub mod transport; + +#[allow(dead_code, non_camel_case_types, non_snake_case, non_upper_case_globals)] +pub mod protocol { + include!(concat!(env!("OUT_DIR"), "/protocol.rs")); +} + +pub use bevy_ecs::prelude::*; +pub use components::*; +pub use protocol::*; +pub use simulation::*; +pub use transport::*; diff --git a/server/src/main.rs b/server/src/main.rs new file mode 100644 index 0000000..165fbbc --- /dev/null +++ b/server/src/main.rs @@ -0,0 +1,142 @@ +#![no_std] +#![no_main] + +extern crate alloc; + +mod allocator; + +use core::panic::PanicInfo; +use pxl8_server::*; + +#[global_allocator] +static ALLOCATOR: allocator::Allocator = allocator::Allocator; + +#[panic_handler] +fn panic(_info: &PanicInfo) -> ! { + loop {} +} + +const TICK_RATE: u64 = 30; +const TICK_NS: u64 = 1_000_000_000 / TICK_RATE; + +#[cfg(unix)] +fn get_time_ns() -> u64 { + let mut ts = libc::timespec { tv_sec: 0, tv_nsec: 0 }; + unsafe { libc::clock_gettime(libc::CLOCK_MONOTONIC, &mut ts) }; + (ts.tv_sec as u64) * 1_000_000_000 + (ts.tv_nsec as u64) +} + +#[cfg(windows)] +fn get_time_ns() -> u64 { + use windows_sys::Win32::System::Performance::*; + static mut FREQ: i64 = 0; + unsafe { + if FREQ == 0 { + QueryPerformanceFrequency(&mut FREQ); + } + let mut count: i64 = 0; + QueryPerformanceCounter(&mut count); + ((count as u128 * 1_000_000_000) / FREQ as u128) as u64 + } +} + +#[cfg(unix)] +fn sleep_ms(ms: u64) { + let ts = libc::timespec { + tv_sec: (ms / 1000) as i64, + tv_nsec: ((ms % 1000) * 1_000_000) as i64, + }; + unsafe { libc::nanosleep(&ts, core::ptr::null_mut()) }; +} + +#[cfg(windows)] +fn sleep_ms(ms: u64) { + use windows_sys::Win32::System::Threading::Sleep; + unsafe { Sleep(ms as u32) }; +} + +fn extract_spawn_position(payload: &[u8]) -> (f32, f32, f32, f32, f32) { + let x = f32::from_be_bytes([payload[0], payload[1], payload[2], payload[3]]); + let y = f32::from_be_bytes([payload[4], payload[5], payload[6], payload[7]]); + let z = f32::from_be_bytes([payload[8], payload[9], payload[10], payload[11]]); + let yaw = f32::from_be_bytes([payload[12], payload[13], payload[14], payload[15]]); + let pitch = f32::from_be_bytes([payload[16], payload[17], payload[18], payload[19]]); + (x, y, z, yaw, pitch) +} + +#[unsafe(no_mangle)] +pub extern "C" fn main(_argc: i32, _argv: *const *const u8) -> i32 { + let mut transport = match transport::Transport::bind(transport::DEFAULT_PORT) { + Some(t) => t, + None => return 1, + }; + + let mut sim = Simulation::new(); + let mut player_id: u64 = 0; + let mut last_client_tick: u64 = 0; + + let mut sequence: u32 = 0; + let mut last_tick = get_time_ns(); + let mut entities_buf = [protocol::pxl8_entity_state { + entity_id: 0, + userdata: [0u8; 56], + }; 64]; + let mut inputs_buf: [protocol::pxl8_input_msg; 16] = unsafe { core::mem::zeroed() }; + + loop { + let now = get_time_ns(); + let elapsed = now.saturating_sub(last_tick); + + if elapsed >= TICK_NS { + last_tick = now; + let dt = (elapsed as f32) / 1_000_000_000.0; + + let mut latest_input: Option = None; + while let Some(msg_type) = transport.recv() { + match msg_type { + x if x == protocol::pxl8_msg_type::PXL8_MSG_INPUT as u8 => { + latest_input = Some(transport.get_input()); + } + x if x == protocol::pxl8_msg_type::PXL8_MSG_COMMAND as u8 => { + let cmd = transport.get_command(); + if cmd.cmd_type == protocol::pxl8_cmd_type::PXL8_CMD_SPAWN_ENTITY as u16 { + let (x, y, z, _yaw, _pitch) = extract_spawn_position(&cmd.payload); + let player = sim.spawn_player(x, y, z); + player_id = player.to_bits(); + } + } + _ => {} + } + } + + if let Some(input) = latest_input { + last_client_tick = input.tick; + inputs_buf[0] = input; + sim.step(&inputs_buf[..1], dt); + } else { + sim.step(&[], dt); + } + + let mut count = 0; + sim.generate_snapshot(player_id, |state| { + if count < entities_buf.len() { + entities_buf[count] = *state; + count += 1; + } + }); + + let header = protocol::pxl8_snapshot_header { + entity_count: count as u16, + event_count: 0, + player_id, + tick: last_client_tick, + time: sim.time, + }; + + transport.send_snapshot(&header, &entities_buf[..count], sequence); + sequence = sequence.wrapping_add(1); + } + + sleep_ms(1); + } +} diff --git a/server/src/simulation.rs b/server/src/simulation.rs new file mode 100644 index 0000000..5e9f231 --- /dev/null +++ b/server/src/simulation.rs @@ -0,0 +1,133 @@ +use bevy_ecs::prelude::*; +use libm::{cosf, sinf}; + +use crate::components::*; +use crate::protocol::*; + +#[derive(Resource, Default)] +pub struct SimTime { + pub dt: f32, + pub time: f32, +} + +pub struct Simulation { + pub player: Option, + pub tick: u64, + pub time: f32, + pub world: World, +} + +impl Simulation { + pub fn new() -> Self { + let mut world = World::new(); + world.insert_resource(SimTime::default()); + Self { + player: None, + tick: 0, + time: 0.0, + world, + } + } + + pub fn step(&mut self, inputs: &[pxl8_input_msg], dt: f32) { + self.tick += 1; + self.time += dt; + + if let Some(mut sim_time) = self.world.get_resource_mut::() { + sim_time.dt = dt; + sim_time.time = self.time; + } + + for input in inputs { + self.apply_input(input, dt); + } + } + + fn apply_input(&mut self, input: &pxl8_input_msg, dt: f32) { + let Some(player) = self.player else { return }; + let speed = 200.0; + + let yaw = input.yaw; + let sin_yaw = sinf(yaw); + let cos_yaw = cosf(yaw); + + let move_x = input.move_x; + let move_y = input.move_y; + let len_sq = move_x * move_x + move_y * move_y; + + if len_sq > 0.0 { + let len = libm::sqrtf(len_sq); + let norm_x = move_x / len; + let norm_y = move_y / len; + + let forward_x = -sin_yaw * norm_y * speed * dt; + let forward_z = -cos_yaw * norm_y * speed * dt; + let strafe_x = cos_yaw * norm_x * speed * dt; + let strafe_z = -sin_yaw * norm_x * speed * dt; + + if let Some(mut pos) = self.world.get_mut::(player) { + pos.x += forward_x + strafe_x; + pos.z += forward_z + strafe_z; + } + } + + if let Some(mut rot) = self.world.get_mut::(player) { + rot.yaw = yaw; + rot.pitch = (rot.pitch - input.look_dy * 0.008).clamp(-1.5, 1.5); + } + } + + pub fn spawn_entity(&mut self) -> Entity { + self.world.spawn(( + Position::default(), + Rotation::default(), + Velocity::default(), + )).id() + } + + pub fn spawn_player(&mut self, x: f32, y: f32, z: f32) -> Entity { + let entity = self.world.spawn(( + Player, + Position { x, y, z }, + Rotation::default(), + Velocity::default(), + Health::default(), + )).id(); + self.player = Some(entity); + entity + } + + pub fn generate_snapshot(&mut self, player_id: u64, mut writer: F) + where + F: FnMut(&pxl8_entity_state), + { + let mut query = self.world.query::<(Entity, &Position, &Rotation)>(); + for (entity, pos, rot) in query.iter(&self.world) { + let mut state = pxl8_entity_state { + entity_id: entity.to_bits(), + userdata: [0u8; 56], + }; + + let bytes = &mut state.userdata; + bytes[0..4].copy_from_slice(&pos.x.to_be_bytes()); + bytes[4..8].copy_from_slice(&pos.y.to_be_bytes()); + bytes[8..12].copy_from_slice(&pos.z.to_be_bytes()); + bytes[12..16].copy_from_slice(&rot.yaw.to_be_bytes()); + bytes[16..20].copy_from_slice(&rot.pitch.to_be_bytes()); + + writer(&state); + } + + let _ = player_id; + } + + pub fn entity_count(&self) -> usize { + self.world.entities().len() as usize + } +} + +impl Default for Simulation { + fn default() -> Self { + Self::new() + } +} diff --git a/server/src/transport.rs b/server/src/transport.rs new file mode 100644 index 0000000..2315433 --- /dev/null +++ b/server/src/transport.rs @@ -0,0 +1,281 @@ +use crate::protocol::*; + +pub const DEFAULT_PORT: u16 = 7777; + +#[cfg(unix)] +mod sys { + use libc::{c_int, c_void, sockaddr, sockaddr_in, socklen_t}; + + pub type RawSocket = c_int; + pub const INVALID_SOCKET: RawSocket = -1; + + pub fn socket() -> RawSocket { + unsafe { libc::socket(libc::AF_INET, libc::SOCK_DGRAM, 0) } + } + + pub fn bind(sock: RawSocket, port: u16) -> c_int { + let addr = sockaddr_in { + sin_family: libc::AF_INET as u16, + sin_port: port.to_be(), + sin_addr: libc::in_addr { s_addr: u32::from_be_bytes([127, 0, 0, 1]).to_be() }, + sin_zero: [0; 8], + }; + unsafe { libc::bind(sock, &addr as *const _ as *const sockaddr, core::mem::size_of::() as socklen_t) } + } + + pub fn set_nonblocking(sock: RawSocket) -> c_int { + unsafe { + let flags = libc::fcntl(sock, libc::F_GETFL, 0); + libc::fcntl(sock, libc::F_SETFL, flags | libc::O_NONBLOCK) + } + } + + pub fn recvfrom(sock: RawSocket, buf: &mut [u8], addr: &mut sockaddr_in) -> isize { + let mut addr_len = core::mem::size_of::() as socklen_t; + unsafe { + libc::recvfrom( + sock, + buf.as_mut_ptr() as *mut c_void, + buf.len(), + 0, + addr as *mut _ as *mut sockaddr, + &mut addr_len, + ) + } + } + + pub fn sendto(sock: RawSocket, buf: &[u8], addr: &sockaddr_in) -> isize { + unsafe { + libc::sendto( + sock, + buf.as_ptr() as *const c_void, + buf.len(), + 0, + addr as *const _ as *const sockaddr, + core::mem::size_of::() as socklen_t, + ) + } + } + + pub fn close(sock: RawSocket) { + unsafe { libc::close(sock) }; + } +} + +#[cfg(windows)] +mod sys { + use windows_sys::Win32::Networking::WinSock::*; + + pub type RawSocket = SOCKET; + pub const INVALID_SOCKET_VAL: RawSocket = INVALID_SOCKET; + + pub fn socket() -> RawSocket { + unsafe { socket(AF_INET as i32, SOCK_DGRAM as i32, 0) } + } + + pub fn bind(sock: RawSocket, port: u16) -> i32 { + let addr = SOCKADDR_IN { + sin_family: AF_INET, + sin_port: port.to_be(), + sin_addr: IN_ADDR { S_un: IN_ADDR_0 { S_addr: u32::from_be_bytes([127, 0, 0, 1]).to_be() } }, + sin_zero: [0; 8], + }; + unsafe { bind(sock, &addr as *const _ as *const SOCKADDR, core::mem::size_of::() as i32) } + } + + pub fn set_nonblocking(sock: RawSocket) -> i32 { + let mut nonblocking: u32 = 1; + unsafe { ioctlsocket(sock, FIONBIO as i32, &mut nonblocking) } + } + + pub fn recvfrom(sock: RawSocket, buf: &mut [u8], addr: &mut SOCKADDR_IN) -> i32 { + let mut addr_len = core::mem::size_of::() as i32; + unsafe { + recvfrom( + sock, + buf.as_mut_ptr(), + buf.len() as i32, + 0, + addr as *mut _ as *mut SOCKADDR, + &mut addr_len, + ) + } + } + + pub fn sendto(sock: RawSocket, buf: &[u8], addr: &SOCKADDR_IN) -> i32 { + unsafe { + sendto( + sock, + buf.as_ptr(), + buf.len() as i32, + 0, + addr as *const _ as *const SOCKADDR, + core::mem::size_of::() as i32, + ) + } + } + + pub fn close(sock: RawSocket) { + unsafe { closesocket(sock) }; + } +} + +#[cfg(unix)] +type SockAddr = libc::sockaddr_in; + +#[cfg(windows)] +type SockAddr = windows_sys::Win32::Networking::WinSock::SOCKADDR_IN; + +pub struct Transport { + client_addr: SockAddr, + has_client: bool, + recv_buf: [u8; 4096], + send_buf: [u8; 4096], + socket: sys::RawSocket, +} + +impl Transport { + pub fn bind(port: u16) -> Option { + let sock = sys::socket(); + if sock == sys::INVALID_SOCKET { + return None; + } + + if sys::bind(sock, port) < 0 { + sys::close(sock); + return None; + } + + if sys::set_nonblocking(sock) < 0 { + sys::close(sock); + return None; + } + + Some(Self { + client_addr: unsafe { core::mem::zeroed() }, + has_client: false, + recv_buf: [0u8; 4096], + send_buf: [0u8; 4096], + socket: sock, + }) + } + + pub fn recv(&mut self) -> Option { + let mut addr: SockAddr = unsafe { core::mem::zeroed() }; + let len = sys::recvfrom(self.socket, &mut self.recv_buf, &mut addr); + + if len <= 0 || (len as usize) < size_of::() { + return None; + } + + self.client_addr = addr; + self.has_client = true; + + let header = self.deserialize_header(); + Some(header.type_) + } + + pub fn get_input(&self) -> pxl8_input_msg { + self.deserialize_input() + } + + pub fn get_command(&self) -> pxl8_command_msg { + self.deserialize_command() + } + + pub fn send_snapshot( + &mut self, + header: &pxl8_snapshot_header, + entities: &[pxl8_entity_state], + sequence: u32, + ) { + if !self.has_client { + return; + } + + let mut offset = 0; + + let msg_header = pxl8_msg_header { + sequence, + size: 0, + type_: pxl8_msg_type::PXL8_MSG_SNAPSHOT as u8, + version: PXL8_PROTOCOL_VERSION as u8, + }; + offset += self.serialize_header(&msg_header, offset); + offset += self.serialize_snapshot_header(header, offset); + + for entity in entities { + offset += self.serialize_entity_state(entity, offset); + } + + sys::sendto(self.socket, &self.send_buf[..offset], &self.client_addr); + } + + fn serialize_header(&mut self, h: &pxl8_msg_header, offset: usize) -> usize { + let buf = &mut self.send_buf[offset..]; + buf[0..4].copy_from_slice(&h.sequence.to_be_bytes()); + buf[4..6].copy_from_slice(&h.size.to_be_bytes()); + buf[6] = h.type_; + buf[7] = h.version; + 8 + } + + fn serialize_snapshot_header(&mut self, h: &pxl8_snapshot_header, offset: usize) -> usize { + let buf = &mut self.send_buf[offset..]; + buf[0..2].copy_from_slice(&h.entity_count.to_be_bytes()); + buf[2..4].copy_from_slice(&h.event_count.to_be_bytes()); + buf[4..12].copy_from_slice(&h.player_id.to_be_bytes()); + buf[12..20].copy_from_slice(&h.tick.to_be_bytes()); + buf[20..24].copy_from_slice(&h.time.to_be_bytes()); + 24 + } + + fn serialize_entity_state(&mut self, e: &pxl8_entity_state, offset: usize) -> usize { + let buf = &mut self.send_buf[offset..]; + buf[0..8].copy_from_slice(&e.entity_id.to_be_bytes()); + buf[8..64].copy_from_slice(&e.userdata); + 64 + } + + fn deserialize_header(&self) -> pxl8_msg_header { + let buf = &self.recv_buf; + pxl8_msg_header { + sequence: u32::from_be_bytes([buf[0], buf[1], buf[2], buf[3]]), + size: u16::from_be_bytes([buf[4], buf[5]]), + type_: buf[6], + version: buf[7], + } + } + + fn deserialize_input(&self) -> pxl8_input_msg { + let buf = &self.recv_buf[8..]; + pxl8_input_msg { + buttons: u32::from_be_bytes([buf[0], buf[1], buf[2], buf[3]]), + look_dx: f32::from_be_bytes([buf[4], buf[5], buf[6], buf[7]]), + look_dy: f32::from_be_bytes([buf[8], buf[9], buf[10], buf[11]]), + move_x: f32::from_be_bytes([buf[12], buf[13], buf[14], buf[15]]), + move_y: f32::from_be_bytes([buf[16], buf[17], buf[18], buf[19]]), + yaw: f32::from_be_bytes([buf[20], buf[21], buf[22], buf[23]]), + tick: u64::from_be_bytes([buf[24], buf[25], buf[26], buf[27], buf[28], buf[29], buf[30], buf[31]]), + timestamp: u64::from_be_bytes([buf[32], buf[33], buf[34], buf[35], buf[36], buf[37], buf[38], buf[39]]), + } + } + + fn deserialize_command(&self) -> pxl8_command_msg { + let buf = &self.recv_buf[8..]; + let mut cmd = pxl8_command_msg { + cmd_type: u16::from_be_bytes([buf[0], buf[1]]), + payload: [0u8; 64], + payload_size: u16::from_be_bytes([buf[66], buf[67]]), + tick: u64::from_be_bytes([buf[68], buf[69], buf[70], buf[71], buf[72], buf[73], buf[74], buf[75]]), + }; + cmd.payload.copy_from_slice(&buf[2..66]); + cmd + } +} + +impl Drop for Transport { + fn drop(&mut self) { + sys::close(self.socket); + } +} diff --git a/client/src/asset/pxl8_ase.c b/src/asset/pxl8_ase.c similarity index 100% rename from client/src/asset/pxl8_ase.c rename to src/asset/pxl8_ase.c diff --git a/client/src/asset/pxl8_ase.h b/src/asset/pxl8_ase.h similarity index 100% rename from client/src/asset/pxl8_ase.h rename to src/asset/pxl8_ase.h diff --git a/client/src/asset/pxl8_cart.c b/src/asset/pxl8_cart.c similarity index 100% rename from client/src/asset/pxl8_cart.c rename to src/asset/pxl8_cart.c diff --git a/client/src/asset/pxl8_cart.h b/src/asset/pxl8_cart.h similarity index 100% rename from client/src/asset/pxl8_cart.h rename to src/asset/pxl8_cart.h diff --git a/client/src/asset/pxl8_embed.h b/src/asset/pxl8_embed.h similarity index 70% rename from client/src/asset/pxl8_embed.h rename to src/asset/pxl8_embed.h index 07791e6..a3efa98 100644 --- a/client/src/asset/pxl8_embed.h +++ b/src/asset/pxl8_embed.h @@ -8,55 +8,67 @@ static const char embed_fennel[] = { , 0 }; static const char embed_pxl8[] = { -#embed "client/src/lua/pxl8.lua" +#embed "src/lua/pxl8.lua" , 0 }; static const char embed_pxl8_anim[] = { -#embed "client/src/lua/pxl8/anim.lua" +#embed "src/lua/pxl8/anim.lua" +, 0 }; + +static const char embed_pxl8_bytes[] = { +#embed "src/lua/pxl8/bytes.lua" , 0 }; static const char embed_pxl8_core[] = { -#embed "client/src/lua/pxl8/core.lua" +#embed "src/lua/pxl8/core.lua" +, 0 }; + +static const char embed_pxl8_effects[] = { +#embed "src/lua/pxl8/effects.lua" , 0 }; static const char embed_pxl8_gfx2d[] = { -#embed "client/src/lua/pxl8/gfx2d.lua" +#embed "src/lua/pxl8/gfx2d.lua" , 0 }; static const char embed_pxl8_gfx3d[] = { -#embed "client/src/lua/pxl8/gfx3d.lua" +#embed "src/lua/pxl8/gfx3d.lua" , 0 }; static const char embed_pxl8_gui[] = { -#embed "client/src/lua/pxl8/gui.lua" +#embed "src/lua/pxl8/gui.lua" , 0 }; static const char embed_pxl8_input[] = { -#embed "client/src/lua/pxl8/input.lua" +#embed "src/lua/pxl8/input.lua" , 0 }; static const char embed_pxl8_math[] = { -#embed "client/src/lua/pxl8/math.lua" +#embed "src/lua/pxl8/math.lua" +, 0 }; + +static const char embed_pxl8_net[] = { +#embed "src/lua/pxl8/net.lua" , 0 }; static const char embed_pxl8_particles[] = { -#embed "client/src/lua/pxl8/particles.lua" +#embed "src/lua/pxl8/particles.lua" , 0 }; static const char embed_pxl8_sfx[] = { -#embed "client/src/lua/pxl8/sfx.lua" +#embed "src/lua/pxl8/sfx.lua" , 0 }; static const char embed_pxl8_tilemap[] = { -#embed "client/src/lua/pxl8/tilemap.lua" +#embed "src/lua/pxl8/tilemap.lua" , 0 }; static const char embed_pxl8_transition[] = { -#embed "client/src/lua/pxl8/transition.lua" +#embed "src/lua/pxl8/transition.lua" , 0 }; static const char embed_pxl8_world[] = { -#embed "client/src/lua/pxl8/world.lua" +#embed "src/lua/pxl8/world.lua" , 0 }; #define PXL8_EMBED_ENTRY(var, name) {name, var, sizeof(var) - 1} @@ -67,12 +79,15 @@ static const pxl8_embed pxl8_embeds[] = { PXL8_EMBED_ENTRY(embed_fennel, "fennel"), PXL8_EMBED_ENTRY(embed_pxl8, "pxl8"), PXL8_EMBED_ENTRY(embed_pxl8_anim, "pxl8.anim"), + PXL8_EMBED_ENTRY(embed_pxl8_bytes, "pxl8.bytes"), PXL8_EMBED_ENTRY(embed_pxl8_core, "pxl8.core"), + PXL8_EMBED_ENTRY(embed_pxl8_effects, "pxl8.effects"), PXL8_EMBED_ENTRY(embed_pxl8_gfx2d, "pxl8.gfx2d"), PXL8_EMBED_ENTRY(embed_pxl8_gfx3d, "pxl8.gfx3d"), PXL8_EMBED_ENTRY(embed_pxl8_gui, "pxl8.gui"), PXL8_EMBED_ENTRY(embed_pxl8_input, "pxl8.input"), PXL8_EMBED_ENTRY(embed_pxl8_math, "pxl8.math"), + PXL8_EMBED_ENTRY(embed_pxl8_net, "pxl8.net"), PXL8_EMBED_ENTRY(embed_pxl8_particles, "pxl8.particles"), PXL8_EMBED_ENTRY(embed_pxl8_sfx, "pxl8.sfx"), PXL8_EMBED_ENTRY(embed_pxl8_tilemap, "pxl8.tilemap"), diff --git a/client/src/asset/pxl8_save.c b/src/asset/pxl8_save.c similarity index 100% rename from client/src/asset/pxl8_save.c rename to src/asset/pxl8_save.c diff --git a/client/src/asset/pxl8_save.h b/src/asset/pxl8_save.h similarity index 100% rename from client/src/asset/pxl8_save.h rename to src/asset/pxl8_save.h diff --git a/client/src/core/pxl8.c b/src/core/pxl8.c similarity index 99% rename from client/src/core/pxl8.c rename to src/core/pxl8.c index 8e29af4..0c7d0d2 100644 --- a/client/src/core/pxl8.c +++ b/src/core/pxl8.c @@ -6,7 +6,6 @@ #include #include -#include #include #include @@ -310,7 +309,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 new file mode 100644 index 0000000..1894878 --- /dev/null +++ b/src/core/pxl8_bytes.c @@ -0,0 +1,234 @@ +#include "pxl8_bytes.h" +#include + +void pxl8_pack_u8(u8* buf, size_t offset, u8 val) { + buf[offset] = val; +} + +void pxl8_pack_u16_le(u8* buf, size_t 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) { + buf[offset] = (u8)(val >> 8); + buf[offset + 1] = (u8)(val); +} + +void pxl8_pack_u32_le(u8* buf, size_t 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) { + 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) { + buf[offset] = (u8)(val); + buf[offset + 1] = (u8)(val >> 8); + buf[offset + 2] = (u8)(val >> 16); + buf[offset + 3] = (u8)(val >> 24); + buf[offset + 4] = (u8)(val >> 32); + buf[offset + 5] = (u8)(val >> 40); + buf[offset + 6] = (u8)(val >> 48); + buf[offset + 7] = (u8)(val >> 56); +} + +void pxl8_pack_u64_be(u8* buf, size_t offset, u64 val) { + buf[offset] = (u8)(val >> 56); + buf[offset + 1] = (u8)(val >> 48); + buf[offset + 2] = (u8)(val >> 40); + buf[offset + 3] = (u8)(val >> 32); + buf[offset + 4] = (u8)(val >> 24); + buf[offset + 5] = (u8)(val >> 16); + buf[offset + 6] = (u8)(val >> 8); + buf[offset + 7] = (u8)(val); +} + +void pxl8_pack_i8(u8* buf, size_t offset, i8 val) { + buf[offset] = (u8)val; +} + +void pxl8_pack_i16_le(u8* buf, size_t offset, i16 val) { + pxl8_pack_u16_le(buf, offset, (u16)val); +} + +void pxl8_pack_i16_be(u8* buf, size_t offset, i16 val) { + pxl8_pack_u16_be(buf, offset, (u16)val); +} + +void pxl8_pack_i32_le(u8* buf, size_t offset, i32 val) { + pxl8_pack_u32_le(buf, offset, (u32)val); +} + +void pxl8_pack_i32_be(u8* buf, size_t offset, i32 val) { + pxl8_pack_u32_be(buf, offset, (u32)val); +} + +void pxl8_pack_i64_le(u8* buf, size_t offset, i64 val) { + pxl8_pack_u64_le(buf, offset, (u64)val); +} + +void pxl8_pack_i64_be(u8* buf, size_t offset, i64 val) { + pxl8_pack_u64_be(buf, offset, (u64)val); +} + +void pxl8_pack_f32_le(u8* buf, size_t 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) { + 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) { + 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) { + u64 bits; + memcpy(&bits, &val, sizeof(bits)); + pxl8_pack_u64_be(buf, offset, bits); +} + +u8 pxl8_unpack_u8(const u8* buf, size_t offset) { + return buf[offset]; +} + +u16 pxl8_unpack_u16_le(const u8* buf, size_t offset) { + return (u16)buf[offset] | ((u16)buf[offset + 1] << 8); +} + +u16 pxl8_unpack_u16_be(const u8* buf, size_t offset) { + return ((u16)buf[offset] << 8) | (u16)buf[offset + 1]; +} + +u32 pxl8_unpack_u32_le(const u8* buf, size_t 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) { + 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) { + return (u64)buf[offset] | + ((u64)buf[offset + 1] << 8) | + ((u64)buf[offset + 2] << 16) | + ((u64)buf[offset + 3] << 24) | + ((u64)buf[offset + 4] << 32) | + ((u64)buf[offset + 5] << 40) | + ((u64)buf[offset + 6] << 48) | + ((u64)buf[offset + 7] << 56); +} + +u64 pxl8_unpack_u64_be(const u8* buf, size_t offset) { + return ((u64)buf[offset] << 56) | + ((u64)buf[offset + 1] << 48) | + ((u64)buf[offset + 2] << 40) | + ((u64)buf[offset + 3] << 32) | + ((u64)buf[offset + 4] << 24) | + ((u64)buf[offset + 5] << 16) | + ((u64)buf[offset + 6] << 8) | + (u64)buf[offset + 7]; +} + +i8 pxl8_unpack_i8(const u8* buf, size_t offset) { + return (i8)buf[offset]; +} + +i16 pxl8_unpack_i16_le(const u8* buf, size_t offset) { + return (i16)pxl8_unpack_u16_le(buf, offset); +} + +i16 pxl8_unpack_i16_be(const u8* buf, size_t offset) { + return (i16)pxl8_unpack_u16_be(buf, offset); +} + +i32 pxl8_unpack_i32_le(const u8* buf, size_t offset) { + return (i32)pxl8_unpack_u32_le(buf, offset); +} + +i32 pxl8_unpack_i32_be(const u8* buf, size_t offset) { + return (i32)pxl8_unpack_u32_be(buf, offset); +} + +i64 pxl8_unpack_i64_le(const u8* buf, size_t offset) { + return (i64)pxl8_unpack_u64_le(buf, offset); +} + +i64 pxl8_unpack_i64_be(const u8* buf, size_t offset) { + return (i64)pxl8_unpack_u64_be(buf, offset); +} + +f32 pxl8_unpack_f32_le(const u8* buf, size_t 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) { + 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) { + 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) { + u64 bits = pxl8_unpack_u64_be(buf, offset); + f64 result; + memcpy(&result, &bits, sizeof(result)); + return result; +} + +void pxl8_bit_set(u32* val, u8 bit) { + *val |= (1u << bit); +} + +void pxl8_bit_clear(u32* val, u8 bit) { + *val &= ~(1u << bit); +} + +bool pxl8_bit_test(u32 val, u8 bit) { + return (val & (1u << bit)) != 0; +} + +u32 pxl8_bit_count(u32 val) { +#if defined(__GNUC__) || defined(__clang__) + return (u32)__builtin_popcount(val); +#else + val = val - ((val >> 1) & 0x55555555); + val = (val & 0x33333333) + ((val >> 2) & 0x33333333); + return (((val + (val >> 4)) & 0x0F0F0F0F) * 0x01010101) >> 24; +#endif +} + +void pxl8_bit_toggle(u32* val, u8 bit) { + *val ^= (1u << bit); +} diff --git a/src/core/pxl8_bytes.h b/src/core/pxl8_bytes.h new file mode 100644 index 0000000..5f5a5e7 --- /dev/null +++ b/src/core/pxl8_bytes.h @@ -0,0 +1,251 @@ +#pragma once + +#include + +#include "pxl8_types.h" + +void pxl8_bit_clear(u32* val, u8 bit); +u32 pxl8_bit_count(u32 val); +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); + +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); + +typedef struct { + const u8* bytes; + u32 offset; + u32 size; + bool overflow; +} pxl8_stream; + +typedef struct { + u8* bytes; + u32 capacity; + u32 offset; + bool overflow; +} pxl8_write_stream; + +static inline pxl8_stream pxl8_stream_create(const u8* bytes, u32 size) { + return (pxl8_stream){ + .bytes = bytes, + .offset = 0, + .size = size, + .overflow = false + }; +} + +static inline pxl8_write_stream pxl8_write_stream_create(u8* bytes, u32 capacity) { + return (pxl8_write_stream){ + .bytes = bytes, + .capacity = capacity, + .offset = 0, + .overflow = false + }; +} + +static inline bool pxl8_stream_can_read(const pxl8_stream* s, u32 count) { + return !s->overflow && s->offset + count <= s->size; +} + +static inline bool pxl8_stream_has_overflow(const pxl8_stream* s) { + return s->overflow; +} + +static inline bool pxl8_write_stream_has_overflow(const pxl8_write_stream* s) { + return s->overflow; +} + +static inline u32 pxl8_stream_position(const pxl8_stream* s) { + return s->offset; +} + +static inline u32 pxl8_write_stream_position(const pxl8_write_stream* s) { + return s->offset; +} + +static inline void pxl8_stream_seek(pxl8_stream* s, u32 offset) { + s->offset = offset; +} + +static inline u8 pxl8_read_u8(pxl8_stream* s) { + if (s->offset + 1 > s->size) { s->overflow = true; return 0; } + return pxl8_unpack_u8(s->bytes, s->offset++); +} + +static inline u16 pxl8_read_u16(pxl8_stream* s) { + if (s->offset + 2 > s->size) { s->overflow = true; return 0; } + u16 val = pxl8_unpack_u16_le(s->bytes, s->offset); + s->offset += 2; + return val; +} + +static inline u16 pxl8_read_u16_be(pxl8_stream* s) { + if (s->offset + 2 > s->size) { s->overflow = true; return 0; } + u16 val = pxl8_unpack_u16_be(s->bytes, s->offset); + s->offset += 2; + return val; +} + +static inline u32 pxl8_read_u32(pxl8_stream* s) { + if (s->offset + 4 > s->size) { s->overflow = true; return 0; } + u32 val = pxl8_unpack_u32_le(s->bytes, s->offset); + s->offset += 4; + return val; +} + +static inline u32 pxl8_read_u32_be(pxl8_stream* s) { + if (s->offset + 4 > s->size) { s->overflow = true; return 0; } + u32 val = pxl8_unpack_u32_be(s->bytes, s->offset); + s->offset += 4; + return val; +} + +static inline u64 pxl8_read_u64(pxl8_stream* s) { + if (s->offset + 8 > s->size) { s->overflow = true; return 0; } + u64 val = pxl8_unpack_u64_le(s->bytes, s->offset); + s->offset += 8; + return val; +} + +static inline u64 pxl8_read_u64_be(pxl8_stream* s) { + if (s->offset + 8 > s->size) { s->overflow = true; return 0; } + u64 val = pxl8_unpack_u64_be(s->bytes, s->offset); + s->offset += 8; + return val; +} + +static inline i16 pxl8_read_i16(pxl8_stream* s) { + return (i16)pxl8_read_u16(s); +} + +static inline i32 pxl8_read_i32(pxl8_stream* s) { + return (i32)pxl8_read_u32(s); +} + +static inline f32 pxl8_read_f32(pxl8_stream* s) { + if (s->offset + 4 > s->size) { s->overflow = true; return 0; } + f32 val = pxl8_unpack_f32_le(s->bytes, s->offset); + s->offset += 4; + return val; +} + +static inline f32 pxl8_read_f32_be(pxl8_stream* s) { + if (s->offset + 4 > s->size) { s->overflow = true; return 0; } + f32 val = pxl8_unpack_f32_be(s->bytes, s->offset); + s->offset += 4; + return val; +} + +static inline void pxl8_read_bytes(pxl8_stream* s, void* dest, u32 count) { + if (s->offset + count > s->size) { s->overflow = true; return; } + memcpy(dest, &s->bytes[s->offset], count); + s->offset += count; +} + +static inline void pxl8_skip_bytes(pxl8_stream* s, u32 count) { + if (s->offset + count > s->size) { s->overflow = true; return; } + s->offset += count; +} + +static inline const u8* pxl8_read_ptr(pxl8_stream* s, u32 count) { + if (s->offset + count > s->size) { s->overflow = true; return NULL; } + const u8* ptr = &s->bytes[s->offset]; + s->offset += count; + return ptr; +} + +static inline void pxl8_write_u8(pxl8_write_stream* s, u8 val) { + if (s->offset + 1 > s->capacity) { s->overflow = true; return; } + pxl8_pack_u8(s->bytes, s->offset++, val); +} + +static inline void pxl8_write_u16(pxl8_write_stream* s, u16 val) { + if (s->offset + 2 > s->capacity) { s->overflow = true; return; } + pxl8_pack_u16_le(s->bytes, s->offset, val); + s->offset += 2; +} + +static inline void pxl8_write_u16_be(pxl8_write_stream* s, u16 val) { + if (s->offset + 2 > s->capacity) { s->overflow = true; return; } + pxl8_pack_u16_be(s->bytes, s->offset, val); + s->offset += 2; +} + +static inline void pxl8_write_u32(pxl8_write_stream* s, u32 val) { + if (s->offset + 4 > s->capacity) { s->overflow = true; return; } + pxl8_pack_u32_le(s->bytes, s->offset, val); + s->offset += 4; +} + +static inline void pxl8_write_u32_be(pxl8_write_stream* s, u32 val) { + if (s->offset + 4 > s->capacity) { s->overflow = true; return; } + pxl8_pack_u32_be(s->bytes, s->offset, val); + s->offset += 4; +} + +static inline void pxl8_write_u64(pxl8_write_stream* s, u64 val) { + if (s->offset + 8 > s->capacity) { s->overflow = true; return; } + pxl8_pack_u64_le(s->bytes, s->offset, val); + s->offset += 8; +} + +static inline void pxl8_write_u64_be(pxl8_write_stream* s, u64 val) { + if (s->offset + 8 > s->capacity) { s->overflow = true; return; } + pxl8_pack_u64_be(s->bytes, s->offset, val); + s->offset += 8; +} + +static inline void pxl8_write_f32(pxl8_write_stream* s, f32 val) { + if (s->offset + 4 > s->capacity) { s->overflow = true; return; } + pxl8_pack_f32_le(s->bytes, s->offset, val); + s->offset += 4; +} + +static inline void pxl8_write_f32_be(pxl8_write_stream* s, f32 val) { + if (s->offset + 4 > s->capacity) { s->overflow = true; return; } + pxl8_pack_f32_be(s->bytes, s->offset, val); + s->offset += 4; +} + +static inline void pxl8_write_bytes(pxl8_write_stream* s, const void* src, u32 count) { + if (s->offset + count > s->capacity) { s->overflow = true; return; } + memcpy(&s->bytes[s->offset], src, count); + s->offset += count; +} diff --git a/client/src/game/pxl8_game.h b/src/core/pxl8_game.h similarity index 100% rename from client/src/game/pxl8_game.h rename to src/core/pxl8_game.h diff --git a/client/src/core/pxl8_io.c b/src/core/pxl8_io.c similarity index 100% rename from client/src/core/pxl8_io.c rename to src/core/pxl8_io.c diff --git a/src/core/pxl8_io.h b/src/core/pxl8_io.h new file mode 100644 index 0000000..13daab5 --- /dev/null +++ b/src/core/pxl8_io.h @@ -0,0 +1,38 @@ +#pragma once + +#include +#include + +#include "pxl8_bytes.h" +#include "pxl8_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +pxl8_result pxl8_io_create_directory(const char* path); +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); + +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); +bool pxl8_key_released(const pxl8_input_state* input, const char* key_name); + +i32 pxl8_mouse_dx(const pxl8_input_state* input); +i32 pxl8_mouse_dy(const pxl8_input_state* input); +bool pxl8_mouse_pressed(const pxl8_input_state* input, i32 button); +bool pxl8_mouse_released(const pxl8_input_state* input, i32 button); +i32 pxl8_mouse_wheel_x(const pxl8_input_state* input); +i32 pxl8_mouse_wheel_y(const pxl8_input_state* input); +i32 pxl8_mouse_x(const pxl8_input_state* input); +i32 pxl8_mouse_y(const pxl8_input_state* input); + +#ifdef __cplusplus +} +#endif diff --git a/client/src/core/pxl8_log.c b/src/core/pxl8_log.c similarity index 100% rename from client/src/core/pxl8_log.c rename to src/core/pxl8_log.c diff --git a/client/src/core/pxl8_log.h b/src/core/pxl8_log.h similarity index 100% rename from client/src/core/pxl8_log.h rename to src/core/pxl8_log.h diff --git a/client/src/core/pxl8_macros.h b/src/core/pxl8_macros.h similarity index 100% rename from client/src/core/pxl8_macros.h rename to src/core/pxl8_macros.h diff --git a/client/src/game/pxl8_replay.c b/src/core/pxl8_replay.c similarity index 100% rename from client/src/game/pxl8_replay.c rename to src/core/pxl8_replay.c diff --git a/client/src/game/pxl8_replay.h b/src/core/pxl8_replay.h similarity index 100% rename from client/src/game/pxl8_replay.h rename to src/core/pxl8_replay.h diff --git a/client/src/core/pxl8_rng.c b/src/core/pxl8_rng.c similarity index 100% rename from client/src/core/pxl8_rng.c rename to src/core/pxl8_rng.c diff --git a/client/src/core/pxl8_rng.h b/src/core/pxl8_rng.h similarity index 100% rename from client/src/core/pxl8_rng.h rename to src/core/pxl8_rng.h diff --git a/client/src/core/pxl8_sys.h b/src/core/pxl8_sys.h similarity index 100% rename from client/src/core/pxl8_sys.h rename to src/core/pxl8_sys.h diff --git a/client/src/core/pxl8_types.h b/src/core/pxl8_types.h similarity index 96% rename from client/src/core/pxl8_types.h rename to src/core/pxl8_types.h index 3a90580..e5e1135 100644 --- a/client/src/core/pxl8_types.h +++ b/src/core/pxl8_types.h @@ -29,8 +29,9 @@ typedef __uint128_t u128; #endif typedef enum pxl8_pixel_mode { - PXL8_PIXEL_INDEXED, - PXL8_PIXEL_HICOLOR + PXL8_PIXEL_INDEXED = 1, + PXL8_PIXEL_HICOLOR = 2, + PXL8_PIXEL_RGBA = 4, } pxl8_pixel_mode; typedef enum pxl8_cursor { diff --git a/client/src/gfx/pxl8_3d_camera.c b/src/gfx/pxl8_3d_camera.c similarity index 82% rename from client/src/gfx/pxl8_3d_camera.c rename to src/gfx/pxl8_3d_camera.c index 3cec31d..7f27b20 100644 --- a/client/src/gfx/pxl8_3d_camera.c +++ b/src/gfx/pxl8_3d_camera.c @@ -56,8 +56,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 +104,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 }; } @@ -183,8 +183,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 +212,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_mul(proj, view); + + pxl8_vec4 clip = pxl8_mat4_mul_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/client/src/gfx/pxl8_3d_camera.h b/src/gfx/pxl8_3d_camera.h similarity index 91% rename from client/src/gfx/pxl8_3d_camera.h rename to src/gfx/pxl8_3d_camera.h index 24ee8dd..e3a9fc4 100644 --- a/client/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/client/src/gfx/pxl8_anim.c b/src/gfx/pxl8_anim.c similarity index 100% rename from client/src/gfx/pxl8_anim.c rename to src/gfx/pxl8_anim.c diff --git a/client/src/gfx/pxl8_anim.h b/src/gfx/pxl8_anim.h similarity index 100% rename from client/src/gfx/pxl8_anim.h rename to src/gfx/pxl8_anim.h diff --git a/client/src/gfx/pxl8_atlas.c b/src/gfx/pxl8_atlas.c similarity index 88% rename from client/src/gfx/pxl8_atlas.c rename to src/gfx/pxl8_atlas.c index f752145..0f87389 100644 --- a/client/src/gfx/pxl8_atlas.c +++ b/src/gfx/pxl8_atlas.c @@ -27,6 +27,8 @@ typedef struct pxl8_skyline { struct pxl8_atlas { u32 height, width; u8* pixels; + u8* pixels_tiled; + u32 tiled_capacity, tiled_size; bool dirty; @@ -195,6 +197,7 @@ void pxl8_atlas_destroy(pxl8_atlas* atlas) { free(atlas->entries); free(atlas->free_list); free(atlas->pixels); + free(atlas->pixels_tiled); free(atlas->skyline.nodes); free(atlas); } @@ -209,6 +212,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; @@ -334,6 +344,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 +360,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*)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 +412,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/client/src/gfx/pxl8_atlas.h b/src/gfx/pxl8_atlas.h similarity index 70% rename from client/src/gfx/pxl8_atlas.h rename to src/gfx/pxl8_atlas.h index 2f0313b..2a429f9 100644 --- a/client/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/client/src/gfx/pxl8_backend.h b/src/gfx/pxl8_backend.h similarity index 100% rename from client/src/gfx/pxl8_backend.h rename to src/gfx/pxl8_backend.h diff --git a/client/src/gfx/pxl8_blit.c b/src/gfx/pxl8_blit.c similarity index 100% rename from client/src/gfx/pxl8_blit.c rename to src/gfx/pxl8_blit.c diff --git a/client/src/gfx/pxl8_blit.h b/src/gfx/pxl8_blit.h similarity index 100% rename from client/src/gfx/pxl8_blit.h rename to src/gfx/pxl8_blit.h diff --git a/client/src/gfx/pxl8_color.h b/src/gfx/pxl8_color.h similarity index 97% rename from client/src/gfx/pxl8_color.h rename to src/gfx/pxl8_color.h index 6f6eb55..285a147 100644 --- a/client/src/gfx/pxl8_color.h +++ b/src/gfx/pxl8_color.h @@ -3,7 +3,7 @@ #include "pxl8_types.h" static inline i32 pxl8_bytes_per_pixel(pxl8_pixel_mode mode) { - return (mode == PXL8_PIXEL_HICOLOR) ? 2 : 1; + return (i32)mode; } static inline u16 pxl8_rgb565_pack(u8 r, u8 g, u8 b) { diff --git a/src/gfx/pxl8_colormap.c b/src/gfx/pxl8_colormap.c new file mode 100644 index 0000000..925fd87 --- /dev/null +++ b/src/gfx/pxl8_colormap.c @@ -0,0 +1,123 @@ +#include "pxl8_colormap.h" +#include + +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; + + for (u32 i = 1; i < PXL8_FULLBRIGHT_START; i++) { + if (i >= PXL8_DYNAMIC_RANGE_START && i < dynamic_end) { + continue; + } + + u32 c = palette[i]; + u8 pr = c & 0xFF; + u8 pg = (c >> 8) & 0xFF; + u8 pb = (c >> 16) & 0xFF; + + 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; + best_idx = (u8)i; + if (dist == 0) break; + } + } + + return best_idx; +} + +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); +} + +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 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; + + if (pal_idx == PXL8_TRANSPARENT) { + result_idx = PXL8_TRANSPARENT; + } else if (pal_idx >= PXL8_FULLBRIGHT_START) { + result_idx = (u8)pal_idx; + } else { + u32 c = palette[pal_idx]; + u8 r = c & 0xFF; + u8 g = (c >> 8) & 0xFF; + u8 b = (c >> 16) & 0xFF; + + 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[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 new file mode 100644 index 0000000..04f8fd0 --- /dev/null +++ b/src/gfx/pxl8_colormap.h @@ -0,0 +1,73 @@ +#pragma once + +#include "pxl8_dither.h" +#include "pxl8_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#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; + +void pxl8_colormap_generate(pxl8_colormap* cm, const u32* palette); +void pxl8_set_colormap(pxl8_colormap* cm, const u8* data, u32 size); + +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, 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 +} +#endif diff --git a/client/src/gfx/pxl8_cpu.c b/src/gfx/pxl8_cpu.c similarity index 67% rename from client/src/gfx/pxl8_cpu.c rename to src/gfx/pxl8_cpu.c index 6881c06..6a3b3b4 100644 --- a/client/src/gfx/pxl8_cpu.c +++ b/src/gfx/pxl8_cpu.c @@ -1,18 +1,116 @@ #include "pxl8_cpu.h" +#include #include #include -#include "pxl8_simd.h" - struct pxl8_cpu_render_target { u8* framebuffer; u32 height; u32 width; - f32* zbuffer; + u16* zbuffer; u32* light_accum; }; +static inline u16 depth_to_u16(f32 z) { + f32 d = (z + 1.0f) * 32767.5f; + if (d < 0.0f) d = 0.0f; + if (d > 65535.0f) d = 65535.0f; + return (u16)d; +} + +static inline f32 calc_light_intensity(const pxl8_light* light, pxl8_vec3 world_pos, pxl8_vec3 normal) { + pxl8_vec3 to_light = pxl8_vec3_sub(light->position, world_pos); + f32 dist_sq = pxl8_vec3_dot(to_light, to_light); + + if (dist_sq >= light->radius_sq) { + return 0.0f; + } + + f32 intensity_norm = light->intensity * (1.0f / 255.0f); + + if (dist_sq < 0.001f) { + return intensity_norm; + } + + f32 inv_dist = pxl8_fast_inv_sqrt(dist_sq); + pxl8_vec3 light_dir = pxl8_vec3_scale(to_light, inv_dist); + f32 n_dot_l = pxl8_vec3_dot(normal, light_dir); + + if (n_dot_l <= 0.0f) { + return 0.0f; + } + + f32 falloff = 1.0f - dist_sq * light->inv_radius_sq; + return n_dot_l * falloff * intensity_norm; +} + +typedef struct pxl8_light_result { + u8 light; + u32 light_color; +} pxl8_light_result; + +static pxl8_light_result calc_vertex_light( + pxl8_vec3 world_pos, + pxl8_vec3 normal, + const pxl8_3d_frame* frame +) { + f32 intensity = 0.25f + frame->uniforms.ambient * (1.0f / 255.0f); + + f32 accum_r = 0.0f; + f32 accum_g = 0.0f; + f32 accum_b = 0.0f; + f32 total_dynamic = 0.0f; + + f32 celestial_dot = -pxl8_vec3_dot(normal, frame->uniforms.celestial_dir); + if (celestial_dot > 0.0f) { + intensity += celestial_dot * frame->uniforms.celestial_intensity; + } + + f32 sky_factor = normal.y * 0.5f + 0.5f; + 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]; + f32 contrib = calc_light_intensity(light, world_pos, normal); + if (contrib > 0.0f) { + intensity += contrib; + total_dynamic += contrib; + + accum_r += light->r * contrib; + accum_g += light->g * contrib; + accum_b += light->b * contrib; + } + } + + u32 light_color = 0; + if (total_dynamic > 0.001f) { + f32 inv_total = 1.0f / total_dynamic; + f32 tint_strength = total_dynamic * 1.5f; + if (tint_strength > 1.0f) tint_strength = 1.0f; + + u32 r = (u32)(accum_r * inv_total); + u32 g = (u32)(accum_g * inv_total); + u32 b = (u32)(accum_b * inv_total); + u32 a = (u32)(tint_strength * 255.0f); + + if (r > 255) r = 255; + if (g > 255) g = 255; + if (b > 255) b = 255; + + light_color = r | (g << 8) | (b << 16) | (a << 24); + } + + if (intensity < 0.0f) intensity = 0.0f; + if (intensity > 1.0f) intensity = 1.0f; + + return (pxl8_light_result){ + .light = (u8)(intensity * 255.0f), + .light_color = light_color, + }; +} + #define PXL8_MAX_TARGET_STACK 8 struct pxl8_cpu_backend { @@ -20,9 +118,12 @@ 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; + u32* output; + u32 output_size; }; static inline void clip_line_2d(i32* x0, i32* y0, i32* x1, i32* y1, i32 w, i32 h, bool* visible) { @@ -90,6 +191,15 @@ pxl8_cpu_backend* pxl8_cpu_create(u32 width, u32 height) { cpu->target_stack[0] = base_target; cpu->target_stack_depth = 1; cpu->current_target = base_target; + + cpu->output_size = width * height; + cpu->output = calloc(cpu->output_size, sizeof(u32)); + if (!cpu->output) { + pxl8_cpu_destroy_render_target(base_target); + free(cpu); + return NULL; + } + return cpu; } @@ -98,6 +208,7 @@ 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); } @@ -120,11 +231,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) { - memset(render_target->zbuffer, 0x7F, render_target->width * render_target->height * sizeof(f32)); + 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)); } } @@ -132,6 +244,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; } @@ -275,8 +391,44 @@ typedef struct { f32 u, v; u8 color; u8 light; + u32 light_color; } vertex_output; +static inline u32 blend_tri_light_color(u32 lc0, u32 lc1, u32 lc2) { + u32 a0 = (lc0 >> 24) & 0xFF; + u32 a1 = (lc1 >> 24) & 0xFF; + u32 a2 = (lc2 >> 24) & 0xFF; + u32 total_a = a0 + a1 + a2; + if (total_a == 0) return 0; + + u32 r = ((lc0 & 0xFF) * a0 + (lc1 & 0xFF) * a1 + (lc2 & 0xFF) * a2) / total_a; + u32 g = (((lc0 >> 8) & 0xFF) * a0 + ((lc1 >> 8) & 0xFF) * a1 + ((lc2 >> 8) & 0xFF) * a2) / total_a; + u32 b = (((lc0 >> 16) & 0xFF) * a0 + ((lc1 >> 16) & 0xFF) * a1 + ((lc2 >> 16) & 0xFF) * a2) / total_a; + u32 a = total_a / 3; + if (a > 255) a = 255; + + return r | (g << 8) | (b << 16) | (a << 24); +} + +static inline u32 lerp_light_color(u32 a, u32 b, f32 t) { + u32 ar = a & 0xFF; + u32 ag = (a >> 8) & 0xFF; + u32 ab = (a >> 16) & 0xFF; + u32 aa = (a >> 24) & 0xFF; + + u32 br = b & 0xFF; + u32 bg = (b >> 8) & 0xFF; + u32 bb = (b >> 16) & 0xFF; + u32 ba = (b >> 24) & 0xFF; + + u32 or = ar + (u32)((i32)(br - ar) * t); + u32 og = ag + (u32)((i32)(bg - ag) * t); + u32 ob = ab + (u32)((i32)(bb - ab) * t); + u32 oa = aa + (u32)((i32)(ba - aa) * t); + + return or | (og << 8) | (ob << 16) | (oa << 24); +} + static vertex_output lerp_vertex(const vertex_output* a, const vertex_output* b, f32 t) { vertex_output out; out.clip_pos.x = a->clip_pos.x + (b->clip_pos.x - a->clip_pos.x) * t; @@ -293,6 +445,7 @@ static vertex_output lerp_vertex(const vertex_output* a, const vertex_output* b, out.v = a->v + (b->v - a->v) * t; out.color = t < 0.5f ? a->color : b->color; out.light = (u8)(a->light + (b->light - a->light) * t); + out.light_color = lerp_light_color(a->light_color, b->light_color, t); return out; } @@ -348,6 +501,8 @@ typedef struct { f32 w0_recip, w1_recip, w2_recip; f32 u0_w, v0_w, u1_w, v1_w, u2_w, v2_w; f32 l0_w, l1_w, l2_w; + u32 lc0, lc1, lc2; + f32 c0_w, c1_w, c2_w; i32 y_start, y_end, total_height; f32 inv_total; u32 target_width, target_height; @@ -419,6 +574,14 @@ static bool setup_triangle( setup->l1_w = sorted[1]->light * setup->w1_recip; setup->l2_w = sorted[2]->light * setup->w2_recip; + setup->lc0 = sorted[0]->light_color; + setup->lc1 = sorted[1]->light_color; + setup->lc2 = sorted[2]->light_color; + + setup->c0_w = (f32)sorted[0]->color * setup->w0_recip; + setup->c1_w = (f32)sorted[1]->color * setup->w1_recip; + setup->c2_w = (f32)sorted[2]->color * setup->w2_recip; + setup->inv_total = 1.0f / (f32)setup->total_height; setup->target_width = width; setup->target_height = height; @@ -432,6 +595,8 @@ static void rasterize_triangle_opaque( const pxl8_atlas* textures, u32 texture_id, bool dither ) { pxl8_cpu_render_target* render_target = cpu->current_target; + u32* light_accum = render_target->light_accum; + u32 tri_light_color = light_accum ? blend_tri_light_color(setup->lc0, setup->lc1, setup->lc2) : 0; const pxl8_atlas_entry* tex_entry = textures ? pxl8_atlas_get_entry(textures, texture_id) : NULL; u32 atlas_width = textures ? pxl8_atlas_get_width(textures) : 1; f32 tex_w = tex_entry ? (f32)tex_entry->w : 1.0f; @@ -516,7 +681,7 @@ static void rasterize_triangle_opaque( u32 row_start = (u32)y * render_target->width; u8* prow = render_target->framebuffer + row_start; - f32* zrow = render_target->zbuffer + row_start; + u16* zrow = render_target->zbuffer + row_start; const i32 SUBDIV = 32; i32 x = x_start; @@ -536,6 +701,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; @@ -553,7 +734,8 @@ static void rasterize_triangle_opaque( f32 z_a = z; for (i32 px = x; px <= span_end; px++) { - if (z_a <= zrow[px]) { + u16 z16 = depth_to_u16(z_a); + if (z16 < zrow[px]) { i32 tx = (u_fixed >> 16) & tex_mask_w; i32 ty = (v_fixed >> 16) & tex_mask_h; u8 tex_idx = tex_pixels ? tex_pixels[tex_base + (u32)ty * (u32)tex_stride + (u32)tx] : 1; @@ -563,9 +745,12 @@ 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] = z_a; + zrow[px] = z16; + if (light_accum) { + light_accum[row_start + (u32)px] = tri_light_color; + } } } @@ -587,11 +772,9 @@ static void rasterize_triangle_opaque( static void rasterize_triangle_passthrough( pxl8_cpu_backend* cpu, - const tri_setup* setup, - const vertex_output* vo0 + const tri_setup* setup ) { pxl8_cpu_render_target* render_target = cpu->current_target; - u8 color = vo0->color; for (i32 y = setup->y_start; y <= setup->y_end; y++) { bool second_half = y > setup->y1 || setup->y1 == setup->y0; @@ -603,20 +786,33 @@ static void rasterize_triangle_passthrough( f32 ax = (f32)setup->x0 + (f32)(setup->x2 - setup->x0) * alpha; f32 az = setup->z0 + (setup->z2 - setup->z0) * alpha; - f32 bx, bz; + f32 a_wr = setup->w0_recip + (setup->w2_recip - setup->w0_recip) * alpha; + f32 a_cw = setup->c0_w + (setup->c2_w - setup->c0_w) * alpha; + + f32 bx, bz, b_wr, b_cw; if (second_half) { bx = (f32)setup->x1 + (f32)(setup->x2 - setup->x1) * beta; bz = setup->z1 + (setup->z2 - setup->z1) * beta; + b_wr = setup->w1_recip + (setup->w2_recip - setup->w1_recip) * beta; + b_cw = setup->c1_w + (setup->c2_w - setup->c1_w) * beta; } else { bx = (f32)setup->x0 + (f32)(setup->x1 - setup->x0) * beta; bz = setup->z0 + (setup->z1 - setup->z0) * beta; + b_wr = setup->w0_recip + (setup->w1_recip - setup->w0_recip) * beta; + b_cw = setup->c0_w + (setup->c1_w - setup->c0_w) * beta; } - f32 x_start_f, x_end_f, z_start, z_end; + f32 x_start_f, x_end_f, z_start, z_end, wr_start, wr_end, cw_start, cw_end; if (ax <= bx) { - x_start_f = ax; x_end_f = bx; z_start = az; z_end = bz; + x_start_f = ax; x_end_f = bx; + z_start = az; z_end = bz; + wr_start = a_wr; wr_end = b_wr; + cw_start = a_cw; cw_end = b_cw; } else { - x_start_f = bx; x_end_f = ax; z_start = bz; z_end = az; + x_start_f = bx; x_end_f = ax; + z_start = bz; z_end = az; + wr_start = b_wr; wr_end = a_wr; + cw_start = b_cw; cw_end = a_cw; } i32 x_start_orig = (i32)(x_start_f + 0.5f); @@ -630,19 +826,30 @@ static void rasterize_triangle_passthrough( f32 inv_width = 1.0f / (f32)width_orig; f32 dz = (z_end - z_start) * inv_width; + f32 dwr = (wr_end - wr_start) * inv_width; + f32 dcw = (cw_end - cw_start) * inv_width; + f32 skip = (f32)(x_start - x_start_orig); f32 z = z_start + dz * skip; + f32 wr = wr_start + dwr * skip; + f32 cw = cw_start + dcw * skip; u32 row_start = (u32)y * render_target->width; u8* prow = render_target->framebuffer + row_start; - f32* zrow = render_target->zbuffer + row_start; + u16* zrow = render_target->zbuffer + row_start; for (i32 px = x_start; px <= x_end; px++) { - if (z <= zrow[px]) { + u16 z16 = depth_to_u16(z); + if (z16 < zrow[px]) { + f32 w = 1.0f / wr; + f32 color_f = cw * w; + u8 color = pxl8_dither_float(color_f, (u32)px, (u32)y); prow[px] = color; - zrow[px] = z; + zrow[px] = z16; } z += dz; + wr += dwr; + cw += dcw; } } } @@ -653,6 +860,8 @@ static void rasterize_triangle_alpha( const pxl8_atlas* textures, u32 texture_id, u8 mat_alpha, bool dither ) { pxl8_cpu_render_target* render_target = cpu->current_target; + u32* light_accum = render_target->light_accum; + u32 tri_light_color = light_accum ? blend_tri_light_color(setup->lc0, setup->lc1, setup->lc2) : 0; const pxl8_atlas_entry* tex_entry = textures ? pxl8_atlas_get_entry(textures, texture_id) : NULL; u32 atlas_width = textures ? pxl8_atlas_get_width(textures) : 1; f32 tex_w = tex_entry ? (f32)tex_entry->w : 1.0f; @@ -737,7 +946,7 @@ static void rasterize_triangle_alpha( u32 row_start = (u32)y * render_target->width; u8* prow = render_target->framebuffer + row_start; - f32* zrow = render_target->zbuffer + row_start; + u16* zrow = render_target->zbuffer + row_start; const i32 SUBDIV = 32; i32 x = x_start; @@ -757,6 +966,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; @@ -783,11 +1008,15 @@ 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; - if (z_a <= zrow[px]) zrow[px] = z_a; + u16 z16 = depth_to_u16(z_a); + if (z16 < zrow[px]) zrow[px] = z16; + if (light_accum) { + light_accum[row_start + (u32)px] = tri_light_color; + } } } @@ -807,11 +1036,43 @@ 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) { + u8 color = (material->texture_id > 0) ? (u8)material->texture_id : 15; + rasterize_triangle_wireframe(cpu, vo0, vo1, vo2, color, 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)) { @@ -824,7 +1085,7 @@ static void dispatch_triangle( if (alpha_blend) { rasterize_triangle_alpha(cpu, &setup, textures, material->texture_id, material->alpha, material->dither); } else if (passthrough) { - rasterize_triangle_passthrough(cpu, &setup, vo0); + rasterize_triangle_passthrough(cpu, &setup); } else { rasterize_triangle_opaque(cpu, &setup, textures, material->texture_id, material->dither); } @@ -833,13 +1094,13 @@ static void dispatch_triangle( void pxl8_cpu_draw_mesh( pxl8_cpu_backend* cpu, const pxl8_mesh* mesh, - pxl8_mat4 model, - pxl8_material material, + const pxl8_mat4* model, + const pxl8_gfx_material* material, const pxl8_atlas* textures ) { - if (!cpu || !mesh || mesh->index_count < 3 || !cpu->current_target) return; + 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 mv = pxl8_mat4_mul(cpu->frame.view, *model); pxl8_mat4 mvp = pxl8_mat4_mul(cpu->frame.projection, mv); f32 near = cpu->frame.near_clip > 0.0f ? cpu->frame.near_clip : 0.1f; @@ -863,9 +1124,9 @@ void pxl8_cpu_draw_mesh( vo1.clip_pos = pxl8_mat4_mul_vec4(mvp, p1); vo2.clip_pos = pxl8_mat4_mul_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_mul_vec4(*model, p0); + pxl8_vec4 w1 = pxl8_mat4_mul_vec4(*model, p1); + pxl8_vec4 w2 = pxl8_mat4_mul_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}; @@ -882,15 +1143,36 @@ void pxl8_cpu_draw_mesh( vo1.color = v1->color; vo2.color = v2->color; - vo0.light = material.dynamic_lighting ? v0->light : 255; - vo1.light = material.dynamic_lighting ? v1->light : 255; - vo2.light = material.dynamic_lighting ? v2->light : 255; + 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_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); + pxl8_light_result lr2 = calc_vertex_light(vo2.world_pos, n2, &cpu->frame); + + vo0.light = lr0.light; + vo1.light = lr1.light; + vo2.light = lr2.light; + + vo0.light_color = lr0.light_color; + vo1.light_color = lr1.light_color; + vo2.light_color = lr2.light_color; + } else { + vo0.light = 255; + vo1.light = 255; + vo2.light = 255; + vo0.light_color = 0; + vo1.light_color = 0; + vo2.light_color = 0; + } vertex_output clipped[6]; i32 clipped_count = clip_triangle_near(&vo0, &vo1, &vo2, near, clipped); for (i32 t = 0; t < clipped_count; t += 3) { - dispatch_triangle(cpu, &clipped[t], &clipped[t+1], &clipped[t+2], textures, &material); + dispatch_triangle(cpu, &clipped[t], &clipped[t+1], &clipped[t+2], textures, material); } } } @@ -964,7 +1246,7 @@ pxl8_cpu_render_target* pxl8_cpu_create_render_target(const pxl8_cpu_render_targ } if (desc->with_depth) { - target->zbuffer = calloc(size, sizeof(f32)); + target->zbuffer = calloc(size, sizeof(u16)); if (!target->zbuffer) { free(target->framebuffer); free(target); @@ -1021,10 +1303,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; } } } @@ -1073,3 +1357,194 @@ u32 pxl8_cpu_render_target_get_height(const pxl8_cpu_render_target* target) { u32 pxl8_cpu_render_target_get_width(const pxl8_cpu_render_target* target) { return target ? target->width : 0; } + +u32* pxl8_cpu_render_target_get_light_accum(pxl8_cpu_render_target* target) { + return target ? target->light_accum : NULL; +} + +u32* pxl8_cpu_get_output(pxl8_cpu_backend* cpu) { + return cpu ? cpu->output : NULL; +} + +void pxl8_cpu_render_glows( + pxl8_cpu_backend* cpu, + const pxl8_glow_source* glows, + u32 glow_count +) { + if (!cpu || cpu->target_stack_depth == 0) return; + + pxl8_cpu_render_target* target = cpu->target_stack[cpu->target_stack_depth - 1]; + if (!target || !target->framebuffer) return; + + u32 width = target->width; + u32 height = target->height; + u8* pixels = target->framebuffer; + u16* zbuffer = target->zbuffer; + u32* light_accum = target->light_accum; + + for (u32 gi = 0; gi < glow_count; gi++) { + const pxl8_glow_source* glow = &glows[gi]; + i32 cx = glow->x; + i32 cy = glow->y; + i32 radius = glow->radius; + + if (radius <= 0 || glow->intensity == 0) continue; + + i32 x0 = cx - radius; + i32 y0 = cy - radius; + i32 x1 = cx + radius; + i32 y1 = cy + radius; + + if (x0 < 0) x0 = 0; + if (y0 < 0) y0 = 0; + if (x1 >= (i32)width) x1 = (i32)width - 1; + if (y1 >= (i32)height) y1 = (i32)height - 1; + + if (x0 >= x1 || y0 >= y1) continue; + + u16 glow_depth = glow->depth; + u8 base_color = glow->color; + f32 base_intensity = glow->intensity / 255.0f; + f32 radius_f = (f32)radius; + f32 radius_sq = radius_f * radius_f; + f32 inv_radius_sq = 1.0f / radius_sq; + f32 inv_radius = 1.0f / radius_f; + + for (i32 y = y0; y <= y1; y++) { + u32 row = (u32)y * width; + f32 dy = (f32)(y - cy); + + for (i32 x = x0; x <= x1; x++) { + u32 idx = row + (u32)x; + + if (zbuffer && glow_depth > zbuffer[idx]) continue; + + f32 dx = (f32)(x - cx); + f32 intensity = 0.0f; + + switch (glow->shape) { + case PXL8_GLOW_CIRCLE: { + f32 dist_sq = dx * dx + dy * dy; + if (dist_sq >= radius_sq) continue; + f32 falloff = 1.0f - dist_sq * inv_radius_sq; + intensity = base_intensity * falloff * falloff; + break; + } + case PXL8_GLOW_DIAMOND: { + f32 abs_dx = dx < 0 ? -dx : dx; + f32 abs_dy = dy < 0 ? -dy : dy; + f32 manhattan = abs_dx + abs_dy; + if (manhattan >= radius_f) continue; + f32 falloff = 1.0f - manhattan * inv_radius; + intensity = base_intensity * falloff * falloff; + break; + } + case PXL8_GLOW_SHAFT: { + f32 abs_dx = dx < 0 ? -dx : dx; + f32 abs_dy = dy < 0 ? -dy : dy; + f32 height_f = glow->height > 0 ? (f32)glow->height : radius_f; + if (abs_dx >= radius_f || abs_dy >= height_f) continue; + f32 falloff_x = 1.0f - abs_dx * inv_radius; + f32 falloff_y = 1.0f - abs_dy / height_f; + intensity = base_intensity * falloff_x * falloff_x * falloff_y; + break; + } + } + + if (intensity < 0.02f) continue; + + u8 int_val = intensity < 1.0f ? (u8)(intensity * 255.0f) : 255; + u8 light_level = pxl8_ordered_dither(int_val, (u32)x, (u32)y); + + if (light_level < 8) continue; + + u8 shaded = pxl8_colormap_lookup(cpu->colormap, base_color, PXL8_LIGHT_WHITE, light_level); + + 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; + } + + if (light_accum) { + light_accum[idx] = 0; + } + } + } + } +} + +void pxl8_cpu_resolve(pxl8_cpu_backend* cpu) { + if (!cpu || !cpu->palette || cpu->target_stack_depth == 0) return; + + pxl8_cpu_render_target* target = cpu->target_stack[0]; + if (!target || !target->framebuffer) return; + + u32 pixel_count = target->width * target->height; + const u8* pixels = target->framebuffer; + const u32* light_accum = target->light_accum; + const u32* palette = cpu->palette; + u32* output = cpu->output; + + for (u32 i = 0; i < pixel_count; i++) { + u32 base = palette[pixels[i]]; + + if (light_accum && light_accum[i] != 0) { + u32 light_color = light_accum[i]; + u32 tint_alpha = (light_color >> 24) & 0xFF; + + if (tint_alpha > 0) { + u32 lr = light_color & 0xFF; + u32 lg = (light_color >> 8) & 0xFF; + u32 lb = (light_color >> 16) & 0xFF; + + u32 br = base & 0xFF; + u32 bg = (base >> 8) & 0xFF; + u32 bb = (base >> 16) & 0xFF; + u32 ba = (base >> 24) & 0xFF; + + u32 t = (tint_alpha * tint_alpha) / 255; + u32 inv_t = 255 - t; + + u32 lr_norm = (lr * 255) / 240; + u32 lg_norm = (lg * 255) / 240; + u32 lb_norm = (lb * 255) / 220; + + u32 or = ((br * inv_t + (br * lr_norm / 255) * t) / 255); + u32 og = ((bg * inv_t + (bg * lg_norm / 255) * t) / 255); + u32 ob = ((bb * inv_t + (bb * lb_norm / 255) * t) / 255); + + if (or > 255) or = 255; + if (og > 255) og = 255; + if (ob > 255) ob = 255; + + output[i] = or | (og << 8) | (ob << 16) | (ba << 24); + continue; + } + } + + output[i] = base; + } + + for (u32 t = 1; t < cpu->target_stack_depth; t++) { + pxl8_cpu_render_target* overlay = cpu->target_stack[t]; + if (!overlay || !overlay->framebuffer) continue; + + const u8* overlay_pixels = overlay->framebuffer; + for (u32 i = 0; i < pixel_count; i++) { + u8 idx = overlay_pixels[i]; + if (idx != 0) { + output[i] = palette[idx]; + } + } + } +} diff --git a/client/src/gfx/pxl8_cpu.h b/src/gfx/pxl8_cpu.h similarity index 80% rename from client/src/gfx/pxl8_cpu.h rename to src/gfx/pxl8_cpu.h index 35f99a0..319253c 100644 --- a/client/src/gfx/pxl8_cpu.h +++ b/src/gfx/pxl8_cpu.h @@ -2,8 +2,12 @@ #include "pxl8_atlas.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 @@ -20,19 +24,6 @@ typedef struct pxl8_cpu_render_target_desc { bool with_lighting; } pxl8_cpu_render_target_desc; -typedef struct pxl8_3d_frame { - u8 ambient_light; - pxl8_vec3 camera_dir; - pxl8_vec3 camera_pos; - f32 far_clip; - u8 fog_color; - f32 fog_density; - f32 near_clip; - pxl8_mat4 projection; - f32 time; - pxl8_mat4 view; -} pxl8_3d_frame; - pxl8_cpu_backend* pxl8_cpu_create(u32 width, u32 height); void pxl8_cpu_destroy(pxl8_cpu_backend* cpu); @@ -44,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); @@ -57,8 +52,8 @@ void pxl8_cpu_draw_line_3d(pxl8_cpu_backend* cpu, pxl8_vec3 v0, pxl8_vec3 v1, u8 void pxl8_cpu_draw_mesh( pxl8_cpu_backend* cpu, const pxl8_mesh* mesh, - pxl8_mat4 model, - pxl8_material material, + const pxl8_mat4* model, + const pxl8_gfx_material* material, const pxl8_atlas* textures ); @@ -70,9 +65,18 @@ void pxl8_cpu_draw_mesh_wireframe( ); 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); 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 +); + +void pxl8_cpu_resolve(pxl8_cpu_backend* cpu); + pxl8_cpu_render_target* pxl8_cpu_create_render_target(const pxl8_cpu_render_target_desc* desc); void pxl8_cpu_destroy_render_target(pxl8_cpu_render_target* target); @@ -88,6 +92,7 @@ u32 pxl8_cpu_get_target_depth(const pxl8_cpu_backend* cpu); u8* pxl8_cpu_render_target_get_framebuffer(pxl8_cpu_render_target* target); u32 pxl8_cpu_render_target_get_height(const pxl8_cpu_render_target* target); u32 pxl8_cpu_render_target_get_width(const pxl8_cpu_render_target* target); +u32* pxl8_cpu_render_target_get_light_accum(pxl8_cpu_render_target* target); #ifdef __cplusplus } diff --git a/client/src/gfx/pxl8_dither.c b/src/gfx/pxl8_dither.c similarity index 100% rename from client/src/gfx/pxl8_dither.c rename to src/gfx/pxl8_dither.c diff --git a/client/src/gfx/pxl8_dither.h b/src/gfx/pxl8_dither.h similarity index 100% rename from client/src/gfx/pxl8_dither.h rename to src/gfx/pxl8_dither.h diff --git a/client/src/gfx/pxl8_font.c b/src/gfx/pxl8_font.c similarity index 100% rename from client/src/gfx/pxl8_font.c rename to src/gfx/pxl8_font.c diff --git a/client/src/gfx/pxl8_font.h b/src/gfx/pxl8_font.h similarity index 100% rename from client/src/gfx/pxl8_font.h rename to src/gfx/pxl8_font.h diff --git a/client/src/gfx/pxl8_gfx.c b/src/gfx/pxl8_gfx.c similarity index 79% rename from client/src/gfx/pxl8_gfx.c rename to src/gfx/pxl8_gfx.c index 565280b..b4f3202 100644 --- a/client/src/gfx/pxl8_gfx.c +++ b/src/gfx/pxl8_gfx.c @@ -34,6 +34,7 @@ struct pxl8_gfx { const pxl8_hal* hal; bool initialized; pxl8_palette* palette; + pxl8_palette_cube* palette_cube; pxl8_pixel_mode pixel_mode; void* platform_data; pxl8_sprite_cache_entry* sprite_cache; @@ -74,10 +75,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; @@ -87,37 +92,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; @@ -188,6 +180,7 @@ void pxl8_gfx_destroy(pxl8_gfx* gfx) { pxl8_cpu_destroy(gfx->backend.cpu); } free(gfx->colormap); + pxl8_palette_cube_destroy(gfx->palette_cube); pxl8_palette_destroy(gfx->palette); free(gfx->sprite_cache); @@ -309,15 +302,30 @@ pxl8_result pxl8_gfx_load_font_atlas(pxl8_gfx* gfx) { void pxl8_gfx_upload_framebuffer(pxl8_gfx* gfx) { if (!gfx || !gfx->initialized || !gfx->hal) return; - u32 bpp = (gfx->pixel_mode == PXL8_PIXEL_HICOLOR) ? 2 : 1; + if (gfx->backend.type == PXL8_GFX_BACKEND_CPU && gfx->pixel_mode == PXL8_PIXEL_INDEXED) { + pxl8_cpu_resolve(gfx->backend.cpu); + u32* output = pxl8_cpu_get_output(gfx->backend.cpu); + if (output) { + gfx->hal->upload_texture( + gfx->platform_data, + output, + gfx->framebuffer_width, + gfx->framebuffer_height, + PXL8_PIXEL_RGBA, + NULL + ); + return; + } + } + u32* colors = gfx->palette ? pxl8_palette_colors(gfx->palette) : NULL; gfx->hal->upload_texture( gfx->platform_data, gfx->framebuffer, gfx->framebuffer_width, gfx->framebuffer_height, - colors, - bpp + gfx->pixel_mode, + colors ); } @@ -438,6 +446,7 @@ void pxl8_2d_text(pxl8_gfx* gfx, const char* text, i32 x, i32 y, u32 color) { if (!gfx || !text) return; u8* framebuffer = NULL; + u32* light_accum = NULL; i32 fb_width = 0; i32 fb_height = 0; @@ -446,6 +455,7 @@ void pxl8_2d_text(pxl8_gfx* gfx, const char* text, i32 x, i32 y, u32 color) { 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; @@ -483,7 +493,9 @@ void pxl8_2d_text(pxl8_gfx* gfx, const char* text, i32 x, i32 y, u32 color) { } if (pixel_bit) { - framebuffer[py * fb_width + px] = (u8)color; + i32 idx = py * fb_width + px; + framebuffer[idx] = (u8)color; + if (light_accum) light_accum[idx] = 0; } } } @@ -497,6 +509,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; @@ -505,6 +518,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; @@ -541,6 +555,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++) { @@ -554,6 +573,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; } } } @@ -568,30 +588,32 @@ void pxl8_gfx_update(pxl8_gfx* gfx, f32 dt) { } } +pxl8_3d_frame pxl8_3d_frame_from_camera(const pxl8_3d_camera* camera, const pxl8_3d_uniforms* uniforms) { + pxl8_3d_frame frame = {0}; + if (!camera) return frame; + + frame.view = pxl8_3d_camera_get_view(camera); + frame.projection = pxl8_3d_camera_get_projection(camera); + frame.camera_pos = pxl8_3d_camera_get_position(camera); + frame.camera_dir = pxl8_3d_camera_get_forward(camera); + frame.near_clip = 1.0f; + frame.far_clip = 4096.0f; + + if (uniforms) { + frame.uniforms = *uniforms; + } + + return frame; +} + void pxl8_3d_begin_frame(pxl8_gfx* gfx, const pxl8_3d_camera* camera, const pxl8_3d_uniforms* uniforms) { if (!gfx || !camera) return; - pxl8_mat4 view = pxl8_3d_camera_get_view(camera); - pxl8_mat4 projection = pxl8_3d_camera_get_projection(camera); - pxl8_vec3 position = pxl8_3d_camera_get_position(camera); - pxl8_vec3 forward = pxl8_3d_camera_get_forward(camera); + pxl8_3d_frame frame = pxl8_3d_frame_from_camera(camera, uniforms); - pxl8_mat4 vp = pxl8_mat4_mul(projection, view); + pxl8_mat4 vp = pxl8_mat4_mul(frame.projection, frame.view); gfx->frustum = pxl8_frustum_from_matrix(vp); - pxl8_3d_frame frame = { - .ambient_light = uniforms ? uniforms->ambient : 0, - .camera_dir = forward, - .camera_pos = position, - .far_clip = 4096.0f, - .fog_color = uniforms ? uniforms->fog_color : 0, - .fog_density = uniforms ? uniforms->fog_density : 0.0f, - .near_clip = 1.0f, - .projection = projection, - .time = uniforms ? uniforms->time : 0.0f, - .view = view, - }; - switch (gfx->backend.type) { case PXL8_GFX_BACKEND_CPU: pxl8_cpu_begin_frame(gfx->backend.cpu, &frame); @@ -639,8 +661,8 @@ 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, pxl8_mat4 model, pxl8_material material) { - if (!gfx || !mesh) return; +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: pxl8_cpu_draw_mesh(gfx->backend.cpu, mesh, model, material, gfx->atlas); @@ -704,3 +726,67 @@ void pxl8_gfx_pop_target(pxl8_gfx* gfx) { break; } } + +void pxl8_gfx_ensure_blend_tables(pxl8_gfx* gfx) { + if (!gfx || !gfx->palette) return; + + 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; + + 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); + } + } +} + +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); + } +} + +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: { + const pxl8_glow_source* glows = (const pxl8_glow_source*)params; + switch (gfx->backend.type) { + case PXL8_GFX_BACKEND_CPU: + pxl8_cpu_render_glows(gfx->backend.cpu, glows, count); + break; + case PXL8_GFX_BACKEND_GPU: + break; + } + break; + } + } +} diff --git a/src/gfx/pxl8_gfx.h b/src/gfx/pxl8_gfx.h new file mode 100644 index 0000000..e543068 --- /dev/null +++ b/src/gfx/pxl8_gfx.h @@ -0,0 +1,110 @@ +#pragma once + +#include "pxl8_gfx2d.h" +#include "pxl8_gfx3d.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; + +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 + +pxl8_gfx* pxl8_gfx_create(const pxl8_hal* hal, void* platform_data, pxl8_pixel_mode mode, pxl8_resolution resolution); +void pxl8_gfx_destroy(pxl8_gfx* gfx); + +void pxl8_gfx_present(pxl8_gfx* gfx); +void pxl8_gfx_update(pxl8_gfx* gfx, f32 dt); +void pxl8_gfx_upload_framebuffer(pxl8_gfx* gfx); + +u8 pxl8_gfx_find_color(pxl8_gfx* gfx, u32 color); + +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_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_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); + +void pxl8_gfx_clear_textures(pxl8_gfx* gfx); +pxl8_result pxl8_gfx_create_texture(pxl8_gfx* gfx, const u8* pixels, u32 width, u32 height); +pxl8_result pxl8_gfx_load_font_atlas(pxl8_gfx* gfx); +pxl8_result pxl8_gfx_load_sprite(pxl8_gfx* gfx, const char* path); + +bool pxl8_gfx_push_target(pxl8_gfx* gfx); +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 +} +#endif diff --git a/client/src/gfx/pxl8_gfx2d.h b/src/gfx/pxl8_gfx2d.h similarity index 100% rename from client/src/gfx/pxl8_gfx2d.h rename to src/gfx/pxl8_gfx2d.h diff --git a/src/gfx/pxl8_gfx3d.h b/src/gfx/pxl8_gfx3d.h new file mode 100644 index 0000000..ba045d5 --- /dev/null +++ b/src/gfx/pxl8_gfx3d.h @@ -0,0 +1,72 @@ +#pragma once + +#include "pxl8_3d_camera.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; + f32 near_clip; + pxl8_mat4 projection; + pxl8_mat4 view; +} pxl8_3d_frame; + +#ifdef __cplusplus +extern "C" { +#endif + +void pxl8_3d_begin_frame(pxl8_gfx* gfx, const pxl8_3d_camera* camera, 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_gfx_material* material); +void pxl8_3d_draw_mesh_wireframe(pxl8_gfx* gfx, const pxl8_mesh* mesh, pxl8_mat4 model, u8 color); +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); + +pxl8_3d_frame pxl8_3d_frame_from_camera(const pxl8_3d_camera* camera, const pxl8_3d_uniforms* uniforms); + +#ifdef __cplusplus +} +#endif diff --git a/src/gfx/pxl8_lightmap.c b/src/gfx/pxl8_lightmap.c new file mode 100644 index 0000000..0c29521 --- /dev/null +++ b/src/gfx/pxl8_lightmap.c @@ -0,0 +1,113 @@ +#include "pxl8_lightmap.h" + +#include +#include + +pxl8_lightmap* pxl8_lightmap_create(u32 width, u32 height, u32 scale) { + pxl8_lightmap* lm = calloc(1, sizeof(pxl8_lightmap)); + if (!lm) return NULL; + + lm->width = width; + lm->height = height; + lm->scale = scale; + lm->data = calloc(width * height * 3, sizeof(u8)); + if (!lm->data) { + 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; + free(lm->data); + 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/client/src/gfx/pxl8_mesh.c b/src/gfx/pxl8_mesh.c similarity index 100% rename from client/src/gfx/pxl8_mesh.c rename to src/gfx/pxl8_mesh.c diff --git a/client/src/gfx/pxl8_mesh.h b/src/gfx/pxl8_mesh.h similarity index 50% rename from client/src/gfx/pxl8_mesh.h rename to src/gfx/pxl8_mesh.h index cbfad5c..803cad4 100644 --- a/client/src/gfx/pxl8_mesh.h +++ b/src/gfx/pxl8_mesh.h @@ -17,8 +17,9 @@ typedef enum pxl8_blend_mode { PXL8_BLEND_ADDITIVE, } pxl8_blend_mode; -typedef struct pxl8_material { +typedef struct pxl8_gfx_material { u32 texture_id; + u32 lightmap_id; u8 alpha; u8 blend_mode; bool dither; @@ -26,13 +27,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 +65,6 @@ static inline u32 pxl8_mesh_triangle_count(const pxl8_mesh* mesh) { return mesh->index_count / 3; } -static inline pxl8_material pxl8_material_new(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/client/src/gfx/pxl8_palette.c b/src/gfx/pxl8_palette.c similarity index 79% rename from client/src/gfx/pxl8_palette.c rename to src/gfx/pxl8_palette.c index 9d16390..93b4eee 100644 --- a/client/src/gfx/pxl8_palette.c +++ b/src/gfx/pxl8_palette.c @@ -5,10 +5,17 @@ #include "pxl8_ase.h" #include "pxl8_color.h" +#include "pxl8_colormap.h" #include "pxl8_log.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; @@ -332,10 +339,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 +347,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; @@ -449,7 +463,7 @@ void pxl8_palette_tick(pxl8_palette* pal, u16 delta_ticks) { } } -pxl8_cycle_range pxl8_cycle_range_new(u8 start, u8 len, u16 period) { +pxl8_cycle_range pxl8_cycle_range_create(u8 start, u8 len, u16 period) { pxl8_cycle_range range = { .easing = PXL8_EASE_LINEAR, .interpolate = true, @@ -472,3 +486,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 = 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]; +} diff --git a/client/src/gfx/pxl8_palette.h b/src/gfx/pxl8_palette.h similarity index 74% rename from client/src/gfx/pxl8_palette.h rename to src/gfx/pxl8_palette.h index 69b38db..0cfbf9b 100644 --- a/client/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); @@ -62,9 +65,16 @@ void pxl8_palette_set_cycle_colors(pxl8_palette* pal, u8 slot, const u32* colors void pxl8_palette_set_cycle_phase(pxl8_palette* pal, u8 slot, f32 phase); void pxl8_palette_tick(pxl8_palette* pal, u16 delta_ticks); -pxl8_cycle_range pxl8_cycle_range_new(u8 start, u8 len, u16 period); +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/client/src/gfx/pxl8_particles.c b/src/gfx/pxl8_particles.c similarity index 100% rename from client/src/gfx/pxl8_particles.c rename to src/gfx/pxl8_particles.c diff --git a/client/src/gfx/pxl8_particles.h b/src/gfx/pxl8_particles.h similarity index 100% rename from client/src/gfx/pxl8_particles.h rename to src/gfx/pxl8_particles.h diff --git a/client/src/gfx/pxl8_tilemap.c b/src/gfx/pxl8_tilemap.c similarity index 100% rename from client/src/gfx/pxl8_tilemap.c rename to src/gfx/pxl8_tilemap.c diff --git a/client/src/gfx/pxl8_tilemap.h b/src/gfx/pxl8_tilemap.h similarity index 100% rename from client/src/gfx/pxl8_tilemap.h rename to src/gfx/pxl8_tilemap.h diff --git a/client/src/gfx/pxl8_tilesheet.c b/src/gfx/pxl8_tilesheet.c similarity index 100% rename from client/src/gfx/pxl8_tilesheet.c rename to src/gfx/pxl8_tilesheet.c diff --git a/client/src/gfx/pxl8_tilesheet.h b/src/gfx/pxl8_tilesheet.h similarity index 100% rename from client/src/gfx/pxl8_tilesheet.h rename to src/gfx/pxl8_tilesheet.h diff --git a/client/src/gfx/pxl8_transition.c b/src/gfx/pxl8_transition.c similarity index 100% rename from client/src/gfx/pxl8_transition.c rename to src/gfx/pxl8_transition.c diff --git a/client/src/gfx/pxl8_transition.h b/src/gfx/pxl8_transition.h similarity index 100% rename from client/src/gfx/pxl8_transition.h rename to src/gfx/pxl8_transition.h diff --git a/client/src/game/pxl8_gui.c b/src/gui/pxl8_gui.c similarity index 72% rename from client/src/game/pxl8_gui.c rename to src/gui/pxl8_gui.c index 6f8bbd3..72fdc29 100644 --- a/client/src/game/pxl8_gui.c +++ b/src/gui/pxl8_gui.c @@ -18,18 +18,20 @@ void pxl8_gui_state_destroy(pxl8_gui_state* state) { 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 +82,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 +100,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 +108,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/client/src/game/pxl8_gui.h b/src/gui/pxl8_gui.h similarity index 88% rename from client/src/game/pxl8_gui.h rename to src/gui/pxl8_gui.h index db1147f..1d7646a 100644 --- a/client/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/client/src/hal/pxl8_hal.h b/src/hal/pxl8_hal.h similarity index 85% rename from client/src/hal/pxl8_hal.h rename to src/hal/pxl8_hal.h index 282cc90..df504c0 100644 --- a/client/src/hal/pxl8_hal.h +++ b/src/hal/pxl8_hal.h @@ -11,8 +11,8 @@ typedef struct pxl8_hal { void (*present)(void* platform_data); void (*set_cursor)(void* platform_data, u32 cursor); void (*set_relative_mouse_mode)(void* platform_data, bool enabled); - void (*upload_texture)(void* platform_data, const u8* pixels, u32 w, u32 h, - const u32* palette, u32 bpp); + void (*upload_texture)(void* platform_data, const void* pixels, u32 w, u32 h, + u32 bpp, const u32* palette); void* (*audio_create)(i32 sample_rate, i32 channels); void (*audio_destroy)(void* audio_handle); diff --git a/client/src/hal/pxl8_sdl3.c b/src/hal/pxl8_sdl3.c similarity index 94% rename from client/src/hal/pxl8_sdl3.c rename to src/hal/pxl8_sdl3.c index fe93912..3f2f909 100644 --- a/client/src/hal/pxl8_sdl3.c +++ b/src/hal/pxl8_sdl3.c @@ -81,7 +81,6 @@ static u64 sdl3_get_ticks(void) { return SDL_GetTicksNS(); } - static void sdl3_present(void* platform_data) { if (!platform_data) return; @@ -97,28 +96,34 @@ static void sdl3_present(void* platform_data) { SDL_RenderPresent(ctx->renderer); } -static void sdl3_upload_texture(void* platform_data, const u8* pixels, u32 w, u32 h, - const u32* palette, u32 bpp) { +static void sdl3_upload_texture(void* platform_data, const void* pixels, u32 w, u32 h, + u32 bpp, const u32* palette) { if (!platform_data || !pixels) return; pxl8_sdl3_context* ctx = (pxl8_sdl3_context*)platform_data; - size_t needed_size = w * h; + size_t pixel_count = w * h; - if (ctx->rgba_buffer_size < needed_size) { - u32* new_buffer = (u32*)SDL_realloc(ctx->rgba_buffer, needed_size * 4); + if (bpp == 4) { + SDL_UpdateTexture(ctx->framebuffer, NULL, pixels, w * 4); + return; + } + + if (ctx->rgba_buffer_size < pixel_count) { + u32* new_buffer = (u32*)SDL_realloc(ctx->rgba_buffer, pixel_count * 4); if (!new_buffer) return; ctx->rgba_buffer = new_buffer; - ctx->rgba_buffer_size = needed_size; + ctx->rgba_buffer_size = pixel_count; } if (bpp == 2) { const u16* pixels16 = (const u16*)pixels; - for (u32 i = 0; i < w * h; i++) { + for (u32 i = 0; i < pixel_count; i++) { ctx->rgba_buffer[i] = pxl8_rgb565_to_rgba32(pixels16[i]); } } else { - for (u32 i = 0; i < w * h; i++) { - ctx->rgba_buffer[i] = palette[pixels[i]]; + const u8* pixels8 = (const u8*)pixels; + for (u32 i = 0; i < pixel_count; i++) { + ctx->rgba_buffer[i] = palette[pixels8[i]]; } } diff --git a/client/src/hal/pxl8_sdl3.h b/src/hal/pxl8_sdl3.h similarity index 100% rename from client/src/hal/pxl8_sdl3.h rename to src/hal/pxl8_sdl3.h diff --git a/client/src/lua/pxl8.lua b/src/lua/pxl8.lua similarity index 58% rename from client/src/lua/pxl8.lua rename to src/lua/pxl8.lua index 5f91f34..3dfa593 100644 --- a/client/src/lua/pxl8.lua +++ b/src/lua/pxl8.lua @@ -1,11 +1,14 @@ local anim = require("pxl8.anim") +local bytes = require("pxl8.bytes") local core = require("pxl8.core") 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") @@ -25,15 +28,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 @@ -71,87 +79,96 @@ pxl8.center_cursor = input.center_cursor pxl8.set_cursor = input.set_cursor pxl8.set_relative_mouse_mode = input.set_relative_mouse_mode -pxl8.Particles = particles.Particles -pxl8.create_particles = function(max_count) return particles.Particles.new(max_count) end +pxl8.Anim = anim.Anim +pxl8.create_anim = anim.Anim.new +pxl8.create_anim_from_ase = anim.Anim.from_ase -pxl8.Tilesheet = tilemap.Tilesheet -pxl8.Tilemap = tilemap.Tilemap -pxl8.create_tilesheet = function(tile_size) return tilemap.Tilesheet.new(tile_size) end -pxl8.create_tilemap = function(w, h, tile_size) return tilemap.Tilemap.new(w, h, tile_size) end -pxl8.TILE_FLIP_X = tilemap.TILE_FLIP_X -pxl8.TILE_FLIP_Y = tilemap.TILE_FLIP_Y -pxl8.TILE_SOLID = tilemap.TILE_SOLID -pxl8.TILE_TRIGGER = tilemap.TILE_TRIGGER +pxl8.bounds = math.bounds pxl8.Camera3D = gfx3d.Camera3D -pxl8.create_camera_3d = function() return gfx3d.Camera3D.new() end +pxl8.create_camera_3d = gfx3d.Camera3D.new pxl8.begin_frame_3d = gfx3d.begin_frame -pxl8.end_frame_3d = gfx3d.end_frame pxl8.clear_3d = gfx3d.clear pxl8.clear_depth = gfx3d.clear_depth pxl8.draw_line_3d = gfx3d.draw_line -pxl8.Mesh = gfx3d.Mesh -pxl8.create_mesh = function(vertices, indices) return gfx3d.Mesh.new(vertices, indices) end pxl8.draw_mesh = gfx3d.draw_mesh +pxl8.end_frame_3d = gfx3d.end_frame +pxl8.Mesh = gfx3d.Mesh +pxl8.create_mesh = gfx3d.Mesh.new -pxl8.mat4_identity = math3d.mat4_identity -pxl8.mat4_multiply = math3d.mat4_multiply -pxl8.mat4_translate = math3d.mat4_translate -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_ortho = math3d.mat4_ortho -pxl8.mat4_perspective = math3d.mat4_perspective -pxl8.mat4_lookat = math3d.mat4_lookat -pxl8.bounds = math3d.bounds +pxl8.Compressor = sfx.Compressor +pxl8.create_compressor = sfx.Compressor.new +pxl8.Delay = sfx.Delay +pxl8.create_delay = sfx.Delay.new +pxl8.Reverb = sfx.Reverb +pxl8.create_reverb = sfx.Reverb.new pxl8.Gui = gui.Gui -pxl8.create_gui = function() return gui.Gui.new() end +pxl8.create_gui = gui.Gui.new pxl8.gui_label = gui.label pxl8.gui_window = gui.window -pxl8.World = world.World -pxl8.create_world = function() return world.World.new() end -pxl8.procgen_tex = world.procgen_tex +pxl8.mat4_identity = math.mat4_identity +pxl8.mat4_lookat = math.mat4_lookat +pxl8.mat4_multiply = math.mat4_multiply +pxl8.mat4_ortho = math.mat4_ortho +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 +pxl8.NET_MODE_LOCAL = net.MODE_LOCAL +pxl8.NET_MODE_REMOTE = net.MODE_REMOTE + +pxl8.pack_f32_be = bytes.pack_f32_be +pxl8.pack_f32_le = bytes.pack_f32_le +pxl8.pack_f64_be = bytes.pack_f64_be +pxl8.pack_f64_le = bytes.pack_f64_le +pxl8.pack_i8 = bytes.pack_i8 +pxl8.pack_i16_be = bytes.pack_i16_be +pxl8.pack_i16_le = bytes.pack_i16_le +pxl8.pack_i32_be = bytes.pack_i32_be +pxl8.pack_i32_le = bytes.pack_i32_le +pxl8.pack_i64_be = bytes.pack_i64_be +pxl8.pack_i64_le = bytes.pack_i64_le +pxl8.pack_u8 = bytes.pack_u8 +pxl8.pack_u16_be = bytes.pack_u16_be +pxl8.pack_u16_le = bytes.pack_u16_le +pxl8.pack_u32_be = bytes.pack_u32_be +pxl8.pack_u32_le = bytes.pack_u32_le +pxl8.pack_u64_be = bytes.pack_u64_be +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.Transition = transition.Transition -pxl8.create_transition = function(type_name, duration) return transition.Transition.new(type_name, duration) end -pxl8.TRANSITION_TYPES = transition.TYPES - -pxl8.Anim = anim.Anim -pxl8.create_anim = function(frame_ids, frame_durations) return anim.Anim.new(frame_ids, frame_durations) end -pxl8.create_anim_from_ase = function(filepath) return anim.Anim.from_ase(filepath) end - pxl8.SfxContext = sfx.SfxContext pxl8.SfxNode = sfx.SfxNode -pxl8.Compressor = sfx.Compressor -pxl8.Delay = sfx.Delay -pxl8.Reverb = sfx.Reverb -pxl8.create_sfx_context = function() return sfx.SfxContext.new() end -pxl8.create_compressor = function(opts) return sfx.Compressor.new(opts) end -pxl8.create_delay = function(opts) return sfx.Delay.new(opts) end -pxl8.create_reverb = function(opts) return sfx.Reverb.new(opts) end +pxl8.create_sfx_context = sfx.SfxContext.new pxl8.sfx_get_master_volume = sfx.get_master_volume -pxl8.sfx_set_master_volume = sfx.set_master_volume pxl8.sfx_note_to_freq = sfx.note_to_freq +pxl8.sfx_set_master_volume = sfx.set_master_volume pxl8.sfx_voice_params = sfx.voice_params pxl8.SFX_FILTER_BANDPASS = sfx.FILTER_BANDPASS pxl8.SFX_FILTER_HIGHPASS = sfx.FILTER_HIGHPASS pxl8.SFX_FILTER_LOWPASS = sfx.FILTER_LOWPASS pxl8.SFX_FILTER_NONE = sfx.FILTER_NONE - pxl8.SFX_LFO_AMPLITUDE = sfx.LFO_AMPLITUDE pxl8.SFX_LFO_FILTER = sfx.LFO_FILTER pxl8.SFX_LFO_PITCH = sfx.LFO_PITCH - pxl8.SFX_NODE_COMPRESSOR = sfx.NODE_COMPRESSOR pxl8.SFX_NODE_DELAY = sfx.NODE_DELAY pxl8.SFX_NODE_REVERB = sfx.NODE_REVERB - pxl8.SFX_WAVE_NOISE = sfx.WAVE_NOISE pxl8.SFX_WAVE_PULSE = sfx.WAVE_PULSE pxl8.SFX_WAVE_SAW = sfx.WAVE_SAW @@ -159,4 +176,39 @@ pxl8.SFX_WAVE_SINE = sfx.WAVE_SINE pxl8.SFX_WAVE_SQUARE = sfx.WAVE_SQUARE pxl8.SFX_WAVE_TRIANGLE = sfx.WAVE_TRIANGLE +pxl8.TILE_FLIP_X = tilemap.TILE_FLIP_X +pxl8.TILE_FLIP_Y = tilemap.TILE_FLIP_Y +pxl8.TILE_SOLID = tilemap.TILE_SOLID +pxl8.TILE_TRIGGER = tilemap.TILE_TRIGGER +pxl8.Tilemap = tilemap.Tilemap +pxl8.create_tilemap = tilemap.Tilemap.new +pxl8.Tilesheet = tilemap.Tilesheet +pxl8.create_tilesheet = tilemap.Tilesheet.new + +pxl8.Transition = transition.Transition +pxl8.create_transition = transition.Transition.new +pxl8.TRANSITION_TYPES = transition.TYPES + +pxl8.unpack_f32_be = bytes.unpack_f32_be +pxl8.unpack_f32_le = bytes.unpack_f32_le +pxl8.unpack_f64_be = bytes.unpack_f64_be +pxl8.unpack_f64_le = bytes.unpack_f64_le +pxl8.unpack_i8 = bytes.unpack_i8 +pxl8.unpack_i16_be = bytes.unpack_i16_be +pxl8.unpack_i16_le = bytes.unpack_i16_le +pxl8.unpack_i32_be = bytes.unpack_i32_be +pxl8.unpack_i32_le = bytes.unpack_i32_le +pxl8.unpack_i64_be = bytes.unpack_i64_be +pxl8.unpack_i64_le = bytes.unpack_i64_le +pxl8.unpack_u8 = bytes.unpack_u8 +pxl8.unpack_u16_be = bytes.unpack_u16_be +pxl8.unpack_u16_le = bytes.unpack_u16_le +pxl8.unpack_u32_be = bytes.unpack_u32_be +pxl8.unpack_u32_le = bytes.unpack_u32_le +pxl8.unpack_u64_be = bytes.unpack_u64_be +pxl8.unpack_u64_le = bytes.unpack_u64_le + +pxl8.World = world.World +pxl8.create_world = world.World.new + return pxl8 diff --git a/client/src/lua/pxl8/anim.lua b/src/lua/pxl8/anim.lua similarity index 100% rename from client/src/lua/pxl8/anim.lua rename to src/lua/pxl8/anim.lua diff --git a/src/lua/pxl8/bytes.lua b/src/lua/pxl8/bytes.lua new file mode 100644 index 0000000..b0ccb15 --- /dev/null +++ b/src/lua/pxl8/bytes.lua @@ -0,0 +1,44 @@ +local ffi = require("ffi") +local C = ffi.C + +local bytes = {} + +bytes.pack_f32_be = C.pxl8_pack_f32_be +bytes.pack_f32_le = C.pxl8_pack_f32_le +bytes.pack_f64_be = C.pxl8_pack_f64_be +bytes.pack_f64_le = C.pxl8_pack_f64_le +bytes.pack_i8 = C.pxl8_pack_i8 +bytes.pack_i16_be = C.pxl8_pack_i16_be +bytes.pack_i16_le = C.pxl8_pack_i16_le +bytes.pack_i32_be = C.pxl8_pack_i32_be +bytes.pack_i32_le = C.pxl8_pack_i32_le +bytes.pack_i64_be = C.pxl8_pack_i64_be +bytes.pack_i64_le = C.pxl8_pack_i64_le +bytes.pack_u8 = C.pxl8_pack_u8 +bytes.pack_u16_be = C.pxl8_pack_u16_be +bytes.pack_u16_le = C.pxl8_pack_u16_le +bytes.pack_u32_be = C.pxl8_pack_u32_be +bytes.pack_u32_le = C.pxl8_pack_u32_le +bytes.pack_u64_be = C.pxl8_pack_u64_be +bytes.pack_u64_le = C.pxl8_pack_u64_le + +bytes.unpack_f32_be = C.pxl8_unpack_f32_be +bytes.unpack_f32_le = C.pxl8_unpack_f32_le +bytes.unpack_f64_be = C.pxl8_unpack_f64_be +bytes.unpack_f64_le = C.pxl8_unpack_f64_le +bytes.unpack_i8 = C.pxl8_unpack_i8 +bytes.unpack_i16_be = C.pxl8_unpack_i16_be +bytes.unpack_i16_le = C.pxl8_unpack_i16_le +bytes.unpack_i32_be = C.pxl8_unpack_i32_be +bytes.unpack_i32_le = C.pxl8_unpack_i32_le +bytes.unpack_i64_be = C.pxl8_unpack_i64_be +bytes.unpack_i64_le = C.pxl8_unpack_i64_le +bytes.unpack_u8 = C.pxl8_unpack_u8 +bytes.unpack_u16_be = C.pxl8_unpack_u16_be +bytes.unpack_u16_le = C.pxl8_unpack_u16_le +bytes.unpack_u32_be = C.pxl8_unpack_u32_be +bytes.unpack_u32_le = C.pxl8_unpack_u32_le +bytes.unpack_u64_be = C.pxl8_unpack_u64_be +bytes.unpack_u64_le = C.pxl8_unpack_u64_le + +return bytes diff --git a/client/src/lua/pxl8/core.lua b/src/lua/pxl8/core.lua similarity index 77% rename from client/src/lua/pxl8/core.lua rename to src/lua/pxl8/core.lua index ecee66d..afd5dac 100644 --- a/client/src/lua/pxl8/core.lua +++ b/src/lua/pxl8/core.lua @@ -20,19 +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_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 new file mode 100644 index 0000000..4db069a --- /dev/null +++ b/src/lua/pxl8/effects.lua @@ -0,0 +1,32 @@ +local ffi = require("ffi") +local C = ffi.C +local core = require("pxl8.core") + +local effects = {} + +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 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 + end + + C.pxl8_gfx_apply_effect(core.gfx, C.PXL8_GFX_EFFECT_GLOWS, glow_array, count) +end + +return effects diff --git a/client/src/lua/pxl8/gfx2d.lua b/src/lua/pxl8/gfx2d.lua similarity index 100% rename from client/src/lua/pxl8/gfx2d.lua rename to src/lua/pxl8/gfx2d.lua diff --git a/client/src/lua/pxl8/gfx3d.lua b/src/lua/pxl8/gfx3d.lua similarity index 63% rename from client/src/lua/pxl8/gfx3d.lua rename to src/lua/pxl8/gfx3d.lua index 3772263..a08432a 100644 --- a/client/src/lua/pxl8/gfx3d.lua +++ b/src/lua/pxl8/gfx3d.lua @@ -42,6 +42,14 @@ function Camera3D:get_up() return {v.x, v.y, v.z} end +function Camera3D:get_view() + return C.pxl8_3d_camera_get_view(self._ptr) +end + +function Camera3D:get_projection() + return C.pxl8_3d_camera_get_projection(self._ptr) +end + function Camera3D:lookat(eye, target, up) up = up or {0, 1, 0} local eye_vec = ffi.new("pxl8_vec3", {x = eye[1], y = eye[2], z = eye[3]}) @@ -67,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 = {} @@ -114,8 +131,16 @@ gfx3d.Mesh = Mesh function gfx3d.draw_mesh(mesh, opts) opts = opts or {} - local model = C.pxl8_mat4_identity() - local material = ffi.new("pxl8_material", { + local model = ffi.new("pxl8_mat4") + 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_gfx_material", { texture_id = opts.texture or 0, alpha = opts.alpha or 255, blend_mode = opts.blend_mode or 0, @@ -124,6 +149,7 @@ 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) @@ -131,12 +157,44 @@ end function gfx3d.begin_frame(camera, uniforms) uniforms = uniforms or {} - local u = ffi.new("pxl8_3d_uniforms", { - ambient = uniforms.ambient or 0, - fog_color = uniforms.fog_color or 0, - fog_density = uniforms.fog_density or 0.0, - time = uniforms.time or 0.0, - }) + local u = ffi.new("pxl8_3d_uniforms") + + u.ambient = uniforms.ambient or 0 + u.fog_color = uniforms.fog_color or 0 + u.fog_density = uniforms.fog_density or 0.0 + u.time = uniforms.time or 0.0 + + if uniforms.celestial_dir then + u.celestial_dir.x = uniforms.celestial_dir[1] or 0 + u.celestial_dir.y = uniforms.celestial_dir[2] or -1 + u.celestial_dir.z = uniforms.celestial_dir[3] or 0 + else + u.celestial_dir.x = 0 + u.celestial_dir.y = -1 + u.celestial_dir.z = 0 + 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) end diff --git a/client/src/lua/pxl8/gui.lua b/src/lua/pxl8/gui.lua similarity index 93% rename from client/src/lua/pxl8/gui.lua rename to src/lua/pxl8/gui.lua index b8cba94..b1f379c 100644 --- a/client/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/client/src/lua/pxl8/input.lua b/src/lua/pxl8/input.lua similarity index 100% rename from client/src/lua/pxl8/input.lua rename to src/lua/pxl8/input.lua diff --git a/client/src/lua/pxl8/math.lua b/src/lua/pxl8/math.lua similarity index 62% rename from client/src/lua/pxl8/math.lua rename to src/lua/pxl8/math.lua index c82ad84..b0d8d36 100644 --- a/client/src/lua/pxl8/math.lua +++ b/src/lua/pxl8/math.lua @@ -1,53 +1,57 @@ 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) +function math.mat4_mul(a, b) return C.pxl8_mat4_mul(a, b) end -function math3d.mat4_translate(x, y, z) +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) +function math.mat4_ortho(left, right, bottom, top, near, far) return C.pxl8_mat4_ortho(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/net.lua b/src/lua/pxl8/net.lua new file mode 100644 index 0000000..318889f --- /dev/null +++ b/src/lua/pxl8/net.lua @@ -0,0 +1,182 @@ +local ffi = require("ffi") +local C = ffi.C + +local net = {} + +local Net = {} +Net.__index = Net + +net.MODE_LOCAL = C.PXL8_NET_LOCAL +net.MODE_REMOTE = C.PXL8_NET_REMOTE + +function Net.new(config) + config = config or {} + local cfg = ffi.new("pxl8_net_config") + cfg.address = config.address or "127.0.0.1" + cfg.mode = config.mode or C.PXL8_NET_REMOTE + cfg.port = config.port or 7777 + + local n = C.pxl8_net_create(cfg) + if n == nil then + return nil + end + return setmetatable({ _ptr = n }, Net) +end + +function Net:connect() + return C.pxl8_net_connect(self._ptr) == 0 +end + +function Net:connected() + return C.pxl8_net_connected(self._ptr) +end + +function Net:destroy() + if self._ptr then + C.pxl8_net_destroy(self._ptr) + self._ptr = nil + end +end + +function Net:disconnect() + C.pxl8_net_disconnect(self._ptr) +end + +function Net:entities() + local snap = C.pxl8_net_snapshot(self._ptr) + if snap == nil then + return {} + end + local ents = C.pxl8_net_entities(self._ptr) + if ents == nil then + return {} + end + local result = {} + for i = 0, snap.entity_count - 1 do + result[i + 1] = { + entity_id = tonumber(ents[i].entity_id), + userdata = ents[i].userdata + } + end + return result +end + +function Net:entity_prev_userdata(entity_id) + return C.pxl8_net_entity_prev_userdata(self._ptr, entity_id) +end + +function Net:entity_userdata(entity_id) + return C.pxl8_net_entity_userdata(self._ptr, entity_id) +end + +function Net:input_at(tick) + local input = C.pxl8_net_input_at(self._ptr, tick) + if input == nil then return nil end + return { + buttons = input.buttons, + look_dx = input.look_dx, + look_dy = input.look_dy, + move_x = input.move_x, + move_y = input.move_y, + yaw = input.yaw, + tick = tonumber(input.tick), + timestamp = tonumber(input.timestamp) + } +end + +function Net:input_oldest_tick() + return tonumber(C.pxl8_net_input_oldest_tick(self._ptr)) +end + +function Net:input_push(input) + local msg = ffi.new("pxl8_input_msg") + msg.buttons = input.buttons or 0 + msg.look_dx = input.look_dx or 0 + msg.look_dy = input.look_dy or 0 + msg.move_x = input.move_x or 0 + msg.move_y = input.move_y or 0 + msg.yaw = input.yaw or 0 + msg.tick = input.tick or 0 + msg.timestamp = input.timestamp or 0 + C.pxl8_net_input_push(self._ptr, msg) +end + +function Net:lerp_alpha() + return C.pxl8_net_lerp_alpha(self._ptr) +end + +function Net:needs_correction() + return C.pxl8_net_needs_correction(self._ptr) +end + +function Net:player_id() + return tonumber(C.pxl8_net_player_id(self._ptr)) +end + +function Net:poll() + return C.pxl8_net_poll(self._ptr) +end + +function Net:predicted_state() + return C.pxl8_net_predicted_state(self._ptr) +end + +function Net:predicted_tick_set(tick) + C.pxl8_net_predicted_tick_set(self._ptr, tick) +end + +function Net:send_command(cmd) + return C.pxl8_net_send_command(self._ptr, cmd) == 0 +end + +function Net:send_input(input) + local msg = ffi.new("pxl8_input_msg") + msg.buttons = input.buttons or 0 + msg.look_dx = input.look_dx or 0 + msg.look_dy = input.look_dy or 0 + msg.move_x = input.move_x or 0 + msg.move_y = input.move_y or 0 + msg.yaw = input.yaw or 0 + msg.tick = input.tick or 0 + msg.timestamp = input.timestamp or 0 + return C.pxl8_net_send_input(self._ptr, msg) == 0 +end + +function Net:snapshot() + local snap = C.pxl8_net_snapshot(self._ptr) + if snap == nil then + return nil + end + return { + entity_count = snap.entity_count, + event_count = snap.event_count, + player_id = tonumber(snap.player_id), + tick = tonumber(snap.tick), + time = snap.time + } +end + +function Net:spawn(x, y, z, yaw, pitch) + local cmd = ffi.new("pxl8_command_msg") + cmd.cmd_type = C.PXL8_CMD_SPAWN_ENTITY + C.pxl8_pack_f32_be(cmd.payload, 0, x or 0) + C.pxl8_pack_f32_be(cmd.payload, 4, y or 0) + C.pxl8_pack_f32_be(cmd.payload, 8, z or 0) + C.pxl8_pack_f32_be(cmd.payload, 12, yaw or 0) + C.pxl8_pack_f32_be(cmd.payload, 16, pitch or 0) + cmd.payload_size = 20 + cmd.tick = 0 + return self:send_command(cmd) +end + +function Net:tick() + return tonumber(C.pxl8_net_tick(self._ptr)) +end + +function Net:update(dt) + C.pxl8_net_update(self._ptr, dt) +end + +net.Net = Net + +return net diff --git a/client/src/lua/pxl8/particles.lua b/src/lua/pxl8/particles.lua similarity index 98% rename from client/src/lua/pxl8/particles.lua rename to src/lua/pxl8/particles.lua index 41eacef..a0abfe6 100644 --- a/client/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/client/src/lua/pxl8/sfx.lua b/src/lua/pxl8/sfx.lua similarity index 98% rename from client/src/lua/pxl8/sfx.lua rename to src/lua/pxl8/sfx.lua index 3a1faf5..ff942a1 100644 --- a/client/src/lua/pxl8/sfx.lua +++ b/src/lua/pxl8/sfx.lua @@ -200,9 +200,7 @@ function sfx.get_master_volume() return C.pxl8_sfx_mixer_get_master_volume(core.sfx) end -function sfx.note_to_freq(note) - return C.pxl8_sfx_note_to_freq(note) -end +sfx.note_to_freq = C.pxl8_sfx_note_to_freq function sfx.set_master_volume(volume) C.pxl8_sfx_mixer_set_master_volume(core.sfx, volume) diff --git a/client/src/lua/pxl8/tilemap.lua b/src/lua/pxl8/tilemap.lua similarity index 100% rename from client/src/lua/pxl8/tilemap.lua rename to src/lua/pxl8/tilemap.lua diff --git a/client/src/lua/pxl8/transition.lua b/src/lua/pxl8/transition.lua similarity index 100% rename from client/src/lua/pxl8/transition.lua rename to src/lua/pxl8/transition.lua diff --git a/client/src/lua/pxl8/world.lua b/src/lua/pxl8/world.lua similarity index 77% rename from client/src/lua/pxl8/world.lua rename to src/lua/pxl8/world.lua index 589917e..6d0d22e 100644 --- a/client/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, color) + C.pxl8_world_set_wireframe(self._ptr, enabled, color or 15) +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/client/src/math/pxl8_math.c b/src/math/pxl8_math.c similarity index 94% rename from client/src/math/pxl8_math.c rename to src/math/pxl8_math.c index 92b858f..feae87e 100644 --- a/client/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, @@ -126,6 +135,14 @@ pxl8_vec4 pxl8_mat4_mul_vec4(pxl8_mat4 m, pxl8_vec4 v) { }; } +pxl8_vec3 pxl8_mat4_mul_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, + .z = m.m[2] * v.x + m.m[6] * v.y + m.m[10] * v.z, + }; +} + pxl8_mat4 pxl8_mat4_translate(f32 x, f32 y, f32 z) { pxl8_mat4 mat = pxl8_mat4_identity(); diff --git a/client/src/math/pxl8_math.h b/src/math/pxl8_math.h similarity index 58% rename from client/src/math/pxl8_math.h rename to src/math/pxl8_math.h index 40ea22f..a5477c0 100644 --- a/client/src/math/pxl8_math.h +++ b/src/math/pxl8_math.h @@ -4,9 +4,51 @@ #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 { f32 x, y; } pxl8_vec2; @@ -24,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); @@ -55,6 +106,7 @@ 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_perspective(f32 fov, f32 aspect, f32 near, f32 far); diff --git a/src/net/pxl8_net.c b/src/net/pxl8_net.c new file mode 100644 index 0000000..e5cba62 --- /dev/null +++ b/src/net/pxl8_net.c @@ -0,0 +1,312 @@ +#include "pxl8_net.h" + +#include +#include + +#ifdef _WIN32 + #define WIN32_LEAN_AND_MEAN + #include + #include + typedef SOCKET socket_t; + #define INVALID_SOCK INVALID_SOCKET + #define close_socket closesocket +#else + #include + #include + #include + #include + #include + #include + typedef int socket_t; + #define INVALID_SOCK -1 + #define close_socket close +#endif + +#define PXL8_NET_DEFAULT_PORT 7777 +#define PXL8_NET_TICK_RATE 30.0f + +struct pxl8_net { + char address[256]; + bool connected; + pxl8_entity_state entities[PXL8_MAX_SNAPSHOT_ENTITIES]; + pxl8_event_msg events[PXL8_MAX_SNAPSHOT_EVENTS]; + u64 highest_tick; + pxl8_input_msg input_history[PXL8_NET_INPUT_HISTORY_SIZE]; + u64 input_head; + u64 input_oldest_tick; + f32 interp_time; + pxl8_net_mode mode; + u16 port; + u8 predicted_state[PXL8_NET_USERDATA_SIZE]; + u64 predicted_tick; + pxl8_entity_state prev_entities[PXL8_MAX_SNAPSHOT_ENTITIES]; + pxl8_snapshot_header prev_snapshot; + u8 recv_buf[4096]; + u8 send_buf[4096]; + u32 sequence; + struct sockaddr_in server_addr; + pxl8_snapshot_header snapshot; + socket_t sock; +}; + +static const pxl8_entity_state* find_entity(const pxl8_entity_state* entities, u16 count, u64 id) { + for (u16 i = 0; i < count; i++) { + if (entities[i].entity_id == id) return &entities[i]; + } + return NULL; +} + +pxl8_result pxl8_net_connect(pxl8_net* net) { + if (!net) return PXL8_ERROR_INVALID_ARGUMENT; + if (net->connected) return PXL8_OK; + +#ifdef _WIN32 + WSADATA wsa; + if (WSAStartup(MAKEWORD(2, 2), &wsa) != 0) { + return PXL8_ERROR_SYSTEM_FAILURE; + } +#endif + + net->sock = socket(AF_INET, SOCK_DGRAM, 0); + if (net->sock == INVALID_SOCK) { + return PXL8_ERROR_SYSTEM_FAILURE; + } + +#ifdef _WIN32 + u_long nonblocking = 1; + ioctlsocket(net->sock, FIONBIO, &nonblocking); +#else + int flags = fcntl(net->sock, F_GETFL, 0); + fcntl(net->sock, F_SETFL, flags | O_NONBLOCK); +#endif + + memset(&net->server_addr, 0, sizeof(net->server_addr)); + net->server_addr.sin_family = AF_INET; + net->server_addr.sin_port = htons(net->port); + inet_pton(AF_INET, net->address, &net->server_addr.sin_addr); + + net->connected = true; + return PXL8_OK; +} + +bool pxl8_net_connected(const pxl8_net* net) { + return net && net->connected; +} + +pxl8_net* pxl8_net_create(const pxl8_net_config* config) { + pxl8_net* net = calloc(1, sizeof(pxl8_net)); + if (!net) return NULL; + + net->mode = config->mode; + net->port = config->port ? config->port : PXL8_NET_DEFAULT_PORT; + net->sock = INVALID_SOCK; + net->connected = false; + net->sequence = 0; + net->highest_tick = 0; + + if (config->address) { + strncpy(net->address, config->address, sizeof(net->address) - 1); + } else { + strncpy(net->address, "127.0.0.1", sizeof(net->address) - 1); + } + + return net; +} + +void pxl8_net_destroy(pxl8_net* net) { + if (!net) return; + pxl8_net_disconnect(net); + free(net); +} + +void pxl8_net_disconnect(pxl8_net* net) { + if (!net) return; + if (net->sock != INVALID_SOCK) { + close_socket(net->sock); + net->sock = INVALID_SOCK; + } +#ifdef _WIN32 + WSACleanup(); +#endif + net->connected = false; +} + +const pxl8_entity_state* pxl8_net_entities(const pxl8_net* net) { + if (!net) return NULL; + return net->entities; +} + +const u8* pxl8_net_entity_prev_userdata(const pxl8_net* net, u64 entity_id) { + if (!net) return NULL; + const pxl8_entity_state* e = find_entity(net->prev_entities, net->prev_snapshot.entity_count, entity_id); + return e ? e->userdata : NULL; +} + +const u8* pxl8_net_entity_userdata(const pxl8_net* net, u64 entity_id) { + if (!net) return NULL; + const pxl8_entity_state* e = find_entity(net->entities, net->snapshot.entity_count, entity_id); + return e ? e->userdata : NULL; +} + +const pxl8_event_msg* pxl8_net_events(const pxl8_net* net) { + if (!net) return NULL; + return net->events; +} + +const pxl8_input_msg* pxl8_net_input_at(const pxl8_net* net, u64 tick) { + if (!net) return NULL; + for (u64 i = 0; i < PXL8_NET_INPUT_HISTORY_SIZE; i++) { + if (net->input_history[i].tick == tick) { + return &net->input_history[i]; + } + } + return NULL; +} + +u64 pxl8_net_input_oldest_tick(const pxl8_net* net) { + if (!net) return 0; + return net->input_oldest_tick; +} + +void pxl8_net_input_push(pxl8_net* net, const pxl8_input_msg* input) { + if (!net || !input) return; + u64 idx = net->input_head % PXL8_NET_INPUT_HISTORY_SIZE; + net->input_history[idx] = *input; + net->input_head++; + if (net->input_oldest_tick == 0 || input->tick < net->input_oldest_tick) { + net->input_oldest_tick = input->tick; + } +} + +f32 pxl8_net_lerp_alpha(const pxl8_net* net) { + if (!net) return 1.0f; + f32 tick_duration = 1.0f / PXL8_NET_TICK_RATE; + f32 alpha = net->interp_time / tick_duration; + return alpha > 1.0f ? 1.0f : alpha; +} + +bool pxl8_net_needs_correction(const pxl8_net* net) { + if (!net) return false; + if (net->snapshot.tick == 0) return false; + if (net->predicted_tick == 0) return false; + if (net->snapshot.tick > net->predicted_tick) return true; + const u8* server = pxl8_net_entity_userdata(net, net->snapshot.player_id); + if (!server) return false; + return memcmp(server, net->predicted_state, PXL8_NET_USERDATA_SIZE) != 0; +} + +u64 pxl8_net_player_id(const pxl8_net* net) { + if (!net) return 0; + return net->snapshot.player_id; +} + +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)); + if (len < sizeof(pxl8_msg_header)) return false; + + pxl8_msg_header hdr; + size_t offset = pxl8_protocol_deserialize_header(net->recv_buf, len, &hdr); + if (hdr.type != PXL8_MSG_SNAPSHOT) return false; + + pxl8_snapshot_header snap; + offset += pxl8_protocol_deserialize_snapshot_header(net->recv_buf + offset, len - offset, &snap); + + if (snap.tick <= net->highest_tick) return false; + + memcpy(net->prev_entities, net->entities, sizeof(net->entities)); + net->prev_snapshot = net->snapshot; + + net->highest_tick = snap.tick; + net->snapshot = snap; + net->interp_time = 0.0f; + + u16 count = snap.entity_count; + if (count > PXL8_MAX_SNAPSHOT_ENTITIES) count = PXL8_MAX_SNAPSHOT_ENTITIES; + + for (u16 i = 0; i < count; i++) { + offset += pxl8_protocol_deserialize_entity_state( + net->recv_buf + offset, len - offset, &net->entities[i]); + } + + return true; +} + +u8* pxl8_net_predicted_state(pxl8_net* net) { + if (!net) return NULL; + return net->predicted_state; +} + +void pxl8_net_predicted_tick_set(pxl8_net* net, u64 tick) { + if (!net) return; + net->predicted_tick = tick; +} + +size_t pxl8_net_recv(pxl8_net* net, u8* buf, size_t 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; +} + +pxl8_result pxl8_net_send(pxl8_net* net, const u8* data, size_t len) { + if (!net || !net->connected) return PXL8_ERROR_INVALID_ARGUMENT; + + ssize_t sent = sendto(net->sock, (const char*)data, len, 0, + (struct sockaddr*)&net->server_addr, + sizeof(net->server_addr)); + return (sent > 0) ? PXL8_OK : PXL8_ERROR_SYSTEM_FAILURE; +} + +pxl8_result pxl8_net_send_command(pxl8_net* net, const pxl8_command_msg* cmd) { + if (!net || !net->connected) return PXL8_ERROR_INVALID_ARGUMENT; + + u8 buf[sizeof(pxl8_msg_header) + sizeof(pxl8_command_msg)]; + pxl8_msg_header hdr = { + .type = PXL8_MSG_COMMAND, + .version = PXL8_PROTOCOL_VERSION, + .size = sizeof(pxl8_command_msg), + .sequence = 0 + }; + + size_t 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); +} + +pxl8_result pxl8_net_send_input(pxl8_net* net, const pxl8_input_msg* input) { + if (!net || !net->connected) return PXL8_ERROR_INVALID_ARGUMENT; + + u8 buf[sizeof(pxl8_msg_header) + sizeof(pxl8_input_msg)]; + pxl8_msg_header hdr = { + .type = PXL8_MSG_INPUT, + .version = PXL8_PROTOCOL_VERSION, + .size = sizeof(pxl8_input_msg), + .sequence = 0 + }; + + size_t 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); +} + +const pxl8_snapshot_header* pxl8_net_snapshot(const pxl8_net* net) { + if (!net) return NULL; + return &net->snapshot; +} + +u64 pxl8_net_tick(const pxl8_net* net) { + if (!net) return 0; + return net->snapshot.tick; +} + +void pxl8_net_update(pxl8_net* net, f32 dt) { + if (!net) return; + net->interp_time += dt; +} diff --git a/src/net/pxl8_net.h b/src/net/pxl8_net.h new file mode 100644 index 0000000..d14ea10 --- /dev/null +++ b/src/net/pxl8_net.h @@ -0,0 +1,54 @@ +#pragma once + +#include "pxl8_protocol.h" +#include "pxl8_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define PXL8_NET_INPUT_HISTORY_SIZE 64 +#define PXL8_NET_USERDATA_SIZE 56 + +typedef struct pxl8_net pxl8_net; + +typedef enum pxl8_net_mode { + PXL8_NET_LOCAL = 0, + PXL8_NET_REMOTE +} pxl8_net_mode; + +typedef struct pxl8_net_config { + const char* address; + pxl8_net_mode mode; + u16 port; +} pxl8_net_config; + +pxl8_result pxl8_net_connect(pxl8_net* net); +bool pxl8_net_connected(const pxl8_net* net); +pxl8_net* pxl8_net_create(const pxl8_net_config* config); +void pxl8_net_destroy(pxl8_net* net); +void pxl8_net_disconnect(pxl8_net* net); +const pxl8_entity_state* pxl8_net_entities(const pxl8_net* net); +const u8* pxl8_net_entity_prev_userdata(const pxl8_net* net, u64 entity_id); +const u8* pxl8_net_entity_userdata(const pxl8_net* net, u64 entity_id); +const pxl8_event_msg* pxl8_net_events(const pxl8_net* net); +const pxl8_input_msg* pxl8_net_input_at(const pxl8_net* net, u64 tick); +u64 pxl8_net_input_oldest_tick(const pxl8_net* net); +void pxl8_net_input_push(pxl8_net* net, const pxl8_input_msg* input); +f32 pxl8_net_lerp_alpha(const pxl8_net* net); +bool pxl8_net_needs_correction(const pxl8_net* net); +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); +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); +u64 pxl8_net_tick(const pxl8_net* net); +void pxl8_net_update(pxl8_net* net, f32 dt); + +#ifdef __cplusplus +} +#endif diff --git a/src/net/pxl8_protocol.c b/src/net/pxl8_protocol.c new file mode 100644 index 0000000..3c4a48d --- /dev/null +++ b/src/net/pxl8_protocol.c @@ -0,0 +1,124 @@ +#include "pxl8_protocol.h" +#include "pxl8_bytes.h" + +size_t pxl8_protocol_serialize_header(const pxl8_msg_header* msg, u8* buf, size_t 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); + pxl8_write_u16_be(&s, msg->size); + pxl8_write_u8(&s, msg->type); + pxl8_write_u8(&s, msg->version); + return s.offset; +} + +size_t pxl8_protocol_deserialize_header(const u8* buf, size_t 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); + msg->size = pxl8_read_u16_be(&s); + msg->type = pxl8_read_u8(&s); + msg->version = pxl8_read_u8(&s); + return s.offset; +} + +size_t pxl8_protocol_serialize_input(const pxl8_input_msg* msg, u8* buf, size_t 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); + pxl8_write_f32_be(&s, msg->look_dx); + pxl8_write_f32_be(&s, msg->look_dy); + pxl8_write_f32_be(&s, msg->move_x); + pxl8_write_f32_be(&s, msg->move_y); + pxl8_write_f32_be(&s, msg->yaw); + pxl8_write_u64_be(&s, msg->tick); + pxl8_write_u64_be(&s, msg->timestamp); + return s.offset; +} + +size_t pxl8_protocol_deserialize_input(const u8* buf, size_t 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); + msg->look_dx = pxl8_read_f32_be(&s); + msg->look_dy = pxl8_read_f32_be(&s); + msg->move_x = pxl8_read_f32_be(&s); + msg->move_y = pxl8_read_f32_be(&s); + msg->yaw = pxl8_read_f32_be(&s); + msg->tick = pxl8_read_u64_be(&s); + msg->timestamp = pxl8_read_u64_be(&s); + return s.offset; +} + +size_t pxl8_protocol_serialize_command(const pxl8_command_msg* msg, u8* buf, size_t 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); + pxl8_write_bytes(&s, msg->payload, PXL8_COMMAND_PAYLOAD_SIZE); + pxl8_write_u16_be(&s, msg->payload_size); + pxl8_write_u64_be(&s, msg->tick); + return s.offset; +} + +size_t pxl8_protocol_deserialize_command(const u8* buf, size_t 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); + pxl8_read_bytes(&s, msg->payload, PXL8_COMMAND_PAYLOAD_SIZE); + msg->payload_size = pxl8_read_u16_be(&s); + msg->tick = pxl8_read_u64_be(&s); + return s.offset; +} + +size_t pxl8_protocol_serialize_entity_state(const pxl8_entity_state* state, u8* buf, size_t 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); + pxl8_write_bytes(&s, state->userdata, 56); + return s.offset; +} + +size_t pxl8_protocol_deserialize_entity_state(const u8* buf, size_t 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); + pxl8_read_bytes(&s, state->userdata, 56); + return s.offset; +} + +size_t pxl8_protocol_serialize_event(const pxl8_event_msg* msg, u8* buf, size_t 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); + pxl8_write_bytes(&s, msg->payload, PXL8_EVENT_PAYLOAD_SIZE); + return s.offset; +} + +size_t pxl8_protocol_deserialize_event(const u8* buf, size_t 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); + pxl8_read_bytes(&s, msg->payload, PXL8_EVENT_PAYLOAD_SIZE); + return s.offset; +} + +size_t pxl8_protocol_serialize_snapshot_header(const pxl8_snapshot_header* hdr, u8* buf, size_t 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); + pxl8_write_u16_be(&s, hdr->event_count); + pxl8_write_u64_be(&s, hdr->player_id); + pxl8_write_u64_be(&s, hdr->tick); + pxl8_write_f32_be(&s, hdr->time); + return s.offset; +} + +size_t pxl8_protocol_deserialize_snapshot_header(const u8* buf, size_t 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); + hdr->event_count = pxl8_read_u16_be(&s); + hdr->player_id = pxl8_read_u64_be(&s); + hdr->tick = pxl8_read_u64_be(&s); + hdr->time = pxl8_read_f32_be(&s); + return s.offset; +} diff --git a/src/net/pxl8_protocol.h b/src/net/pxl8_protocol.h new file mode 100644 index 0000000..78a4207 --- /dev/null +++ b/src/net/pxl8_protocol.h @@ -0,0 +1,93 @@ +#pragma once + +#include "pxl8_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define PXL8_PROTOCOL_VERSION 1 +#define PXL8_MAX_SNAPSHOT_ENTITIES 256 +#define PXL8_MAX_SNAPSHOT_EVENTS 32 +#define PXL8_COMMAND_PAYLOAD_SIZE 64 +#define PXL8_EVENT_PAYLOAD_SIZE 15 + +typedef enum pxl8_msg_type { + PXL8_MSG_NONE = 0, + PXL8_MSG_CONNECT, + PXL8_MSG_DISCONNECT, + PXL8_MSG_INPUT, + PXL8_MSG_COMMAND, + PXL8_MSG_SNAPSHOT, + PXL8_MSG_EVENT +} pxl8_msg_type; + +typedef struct pxl8_msg_header { + u32 sequence; + u16 size; + u8 type; + u8 version; +} pxl8_msg_header; + +typedef enum pxl8_cmd_type { + PXL8_CMD_NONE = 0, + PXL8_CMD_SPAWN_ENTITY, +} pxl8_cmd_type; + +typedef struct pxl8_input_msg { + u32 buttons; + f32 look_dx; + f32 look_dy; + f32 move_x; + f32 move_y; + f32 yaw; + u64 tick; + u64 timestamp; +} pxl8_input_msg; + +typedef struct pxl8_command_msg { + u16 cmd_type; + u8 payload[PXL8_COMMAND_PAYLOAD_SIZE]; + u16 payload_size; + u64 tick; +} pxl8_command_msg; + +typedef struct pxl8_entity_state { + u64 entity_id; + u8 userdata[56]; +} pxl8_entity_state; + +typedef struct pxl8_event_msg { + u8 event_type; + u8 payload[PXL8_EVENT_PAYLOAD_SIZE]; +} pxl8_event_msg; + +typedef struct pxl8_snapshot_header { + u16 entity_count; + u16 event_count; + u64 player_id; + u64 tick; + 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); + +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); + +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); + +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); + +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); + +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); + +#ifdef __cplusplus +} +#endif diff --git a/src/procgen/pxl8_graph.c b/src/procgen/pxl8_graph.c new file mode 100644 index 0000000..9777f06 --- /dev/null +++ b/src/procgen/pxl8_graph.c @@ -0,0 +1,331 @@ +#include "pxl8_graph.h" + +#include +#include +#include + +#include "pxl8_math.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 = calloc(1, sizeof(pxl8_graph)); + if (!graph) return NULL; + + graph->nodes = calloc(capacity, sizeof(pxl8_node)); + if (!graph->nodes) { + 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; + free(graph->nodes); + 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/client/src/script/pxl8_repl.c b/src/script/pxl8_repl.c similarity index 95% rename from client/src/script/pxl8_repl.c rename to src/script/pxl8_repl.c index 5c0d3e0..7df3ab7 100644 --- a/client/src/script/pxl8_repl.c +++ b/src/script/pxl8_repl.c @@ -1,14 +1,13 @@ #include "pxl8_repl.h" #include -#include #include #include #include #include -#include #include +#include #include #define PXL8_MAX_REPL_COMMAND_SIZE 4096 @@ -29,7 +28,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; }; @@ -105,7 +104,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 +203,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,7 +212,7 @@ static void* pxl8_repl_thread(void* arg) { pxl8_repl_flush_logs(repl); - return NULL; + return 0; } pxl8_repl* pxl8_repl_create(void) { @@ -237,7 +235,8 @@ pxl8_repl* pxl8_repl_create(void) { g_repl = repl; - if (pthread_create(&repl->thread, NULL, pxl8_repl_thread, repl) != 0) { + repl->thread = SDL_CreateThread(pxl8_repl_thread, "pxl8-repl", repl); + if (!repl->thread) { free(repl); g_repl = NULL; return NULL; @@ -251,13 +250,12 @@ 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; diff --git a/client/src/script/pxl8_repl.h b/src/script/pxl8_repl.h similarity index 100% rename from client/src/script/pxl8_repl.h rename to src/script/pxl8_repl.h diff --git a/client/src/script/pxl8_script.c b/src/script/pxl8_script.c similarity index 100% rename from client/src/script/pxl8_script.c rename to src/script/pxl8_script.c diff --git a/client/src/script/pxl8_script.h b/src/script/pxl8_script.h similarity index 100% rename from client/src/script/pxl8_script.h rename to src/script/pxl8_script.h diff --git a/client/src/script/pxl8_script_ffi.h b/src/script/pxl8_script_ffi.h similarity index 70% rename from client/src/script/pxl8_script_ffi.h rename to src/script/pxl8_script_ffi.h index 66e1189..63bae74 100644 --- a/client/src/script/pxl8_script_ffi.h +++ b/src/script/pxl8_script_ffi.h @@ -27,10 +27,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" @@ -189,10 +195,23 @@ static const char* pxl8_ffi_cdefs = "typedef struct { float x, y, z, w; } pxl8_vec4;\n" "typedef struct { float m[16]; } pxl8_mat4;\n" "\n" +"typedef struct pxl8_light {\n" +" pxl8_vec3 position;\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_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" @@ -210,6 +229,27 @@ 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" +" u8 color;\n" +" u16 depth;\n" +" u8 height;\n" +" u16 intensity;\n" +" u8 radius;\n" +" pxl8_glow_shape shape;\n" +" i16 x;\n" +" i16 y;\n" +"} pxl8_glow_source;\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" +"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_clear(pxl8_gfx* gfx, u8 color);\n" @@ -219,8 +259,9 @@ static const char* pxl8_ffi_cdefs = "\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" " u32 texture_id;\n" +" u32 lightmap_id;\n" " u8 alpha;\n" " u8 blend_mode;\n" " bool dither;\n" @@ -228,13 +269,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" @@ -254,7 +297,10 @@ 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, pxl8_mat4 model, 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" +"void pxl8_3d_draw_mesh_wireframe(pxl8_gfx* gfx, const pxl8_mesh* mesh, pxl8_mat4 model, u8 color);\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" @@ -283,18 +329,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" @@ -317,12 +421,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, u8 color);\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" @@ -386,4 +491,107 @@ static const char* pxl8_ffi_cdefs = "void pxl8_sfx_reverb_set_mix(pxl8_sfx_node* node, f32 mix);\n" "void pxl8_sfx_reverb_set_room(pxl8_sfx_node* node, f32 room);\n" "void pxl8_sfx_stop_all(pxl8_sfx_context* ctx);\n" -"void pxl8_sfx_stop_voice(pxl8_sfx_context* ctx, u16 voice_id);\n"; +"void pxl8_sfx_stop_voice(pxl8_sfx_context* ctx, u16 voice_id);\n" +"\n" +"typedef struct pxl8_net pxl8_net;\n" +"typedef enum pxl8_net_mode { PXL8_NET_LOCAL = 0, PXL8_NET_REMOTE } pxl8_net_mode;\n" +"typedef struct pxl8_net_config { const char* address; pxl8_net_mode mode; u16 port; } pxl8_net_config;\n" +"typedef enum pxl8_cmd_type { PXL8_CMD_NONE = 0, PXL8_CMD_SPAWN_ENTITY } pxl8_cmd_type;\n" +"\n" +"typedef struct pxl8_command_msg {\n" +" u16 cmd_type;\n" +" u8 payload[64];\n" +" u16 payload_size;\n" +" u64 tick;\n" +"} pxl8_command_msg;\n" +"\n" +"typedef struct pxl8_input_msg {\n" +" u32 buttons;\n" +" f32 look_dx;\n" +" f32 look_dy;\n" +" f32 move_x;\n" +" f32 move_y;\n" +" f32 yaw;\n" +" u64 tick;\n" +" u64 timestamp;\n" +"} pxl8_input_msg;\n" +"\n" +"typedef struct pxl8_entity_state {\n" +" u64 entity_id;\n" +" u8 userdata[56];\n" +"} pxl8_entity_state;\n" +"\n" +"typedef struct pxl8_snapshot_header {\n" +" u16 entity_count;\n" +" u16 event_count;\n" +" u64 player_id;\n" +" u64 tick;\n" +" f32 time;\n" +"} pxl8_snapshot_header;\n" +"\n" +"i32 pxl8_net_connect(pxl8_net* net);\n" +"bool pxl8_net_connected(const pxl8_net* net);\n" +"pxl8_net* pxl8_net_create(const pxl8_net_config* config);\n" +"void pxl8_net_destroy(pxl8_net* net);\n" +"void pxl8_net_disconnect(pxl8_net* net);\n" +"const pxl8_entity_state* pxl8_net_entities(const pxl8_net* net);\n" +"const u8* pxl8_net_entity_prev_userdata(const pxl8_net* net, u64 entity_id);\n" +"const u8* pxl8_net_entity_userdata(const pxl8_net* net, u64 entity_id);\n" +"const pxl8_input_msg* pxl8_net_input_at(const pxl8_net* net, u64 tick);\n" +"u64 pxl8_net_input_oldest_tick(const pxl8_net* net);\n" +"void pxl8_net_input_push(pxl8_net* net, const pxl8_input_msg* input);\n" +"f32 pxl8_net_lerp_alpha(const pxl8_net* net);\n" +"bool pxl8_net_needs_correction(const pxl8_net* net);\n" +"u64 pxl8_net_player_id(const pxl8_net* net);\n" +"bool pxl8_net_poll(pxl8_net* net);\n" +"u8* pxl8_net_predicted_state(pxl8_net* net);\n" +"void pxl8_net_predicted_tick_set(pxl8_net* net, u64 tick);\n" +"i32 pxl8_net_send_command(pxl8_net* net, const pxl8_command_msg* cmd);\n" +"i32 pxl8_net_send_input(pxl8_net* net, const pxl8_input_msg* input);\n" +"const pxl8_snapshot_header* pxl8_net_snapshot(const pxl8_net* net);\n" +"u64 pxl8_net_tick(const pxl8_net* net);\n" +"void pxl8_net_update(pxl8_net* net, f32 dt);\n" +"\n" +"void pxl8_bit_clear(u32* val, u8 bit);\n" +"u32 pxl8_bit_count(u32 val);\n" +"void pxl8_bit_set(u32* val, u8 bit);\n" +"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" +"\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"; diff --git a/client/src/sfx/pxl8_sfx.c b/src/sfx/pxl8_sfx.c similarity index 99% rename from client/src/sfx/pxl8_sfx.c rename to src/sfx/pxl8_sfx.c index 02357fe..75c7937 100644 --- a/client/src/sfx/pxl8_sfx.c +++ b/src/sfx/pxl8_sfx.c @@ -9,6 +9,11 @@ #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, @@ -716,8 +721,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; diff --git a/client/src/sfx/pxl8_sfx.h b/src/sfx/pxl8_sfx.h similarity index 100% rename from client/src/sfx/pxl8_sfx.h rename to src/sfx/pxl8_sfx.h diff --git a/client/src/world/pxl8_bsp.c b/src/world/pxl8_bsp.c similarity index 86% rename from client/src/world/pxl8_bsp.c rename to src/world/pxl8_bsp.c index 5beacd2..f3e9485 100644 --- a/client/src/world/pxl8_bsp.c +++ b/src/world/pxl8_bsp.c @@ -345,6 +345,7 @@ void pxl8_bsp_destroy(pxl8_bsp* bsp) { free(bsp->planes); free(bsp->surfedges); free(bsp->texinfo); + free(bsp->vertex_lights); free(bsp->vertices); free(bsp->visdata); @@ -377,26 +378,24 @@ bool pxl8_bsp_is_leaf_visible(const pxl8_bsp* bsp, i32 leaf_from, i32 leaf_to) { u32 target_byte = leaf_to >> 3; u32 target_bit = leaf_to & 7; - u32 pvs_size = (bsp->num_leafs + 7) / 8; u32 pos = (u32)visofs; - u32 current_byte = 0; + u32 out_pos = 0; - while (current_byte < pvs_size && pos < bsp->visdata_size) { + while (out_pos <= target_byte && pos < bsp->visdata_size) { u8 b = bsp->visdata[pos++]; - if (b != 0) { - if (current_byte == target_byte) { + if (out_pos == target_byte) { return (b & (1 << target_bit)) != 0; } - current_byte++; + out_pos++; } else { - if (pos >= bsp->visdata_size) return false; + if (pos >= bsp->visdata_size) break; u32 count = bsp->visdata[pos++]; - if (target_byte < current_byte + count) { + if (out_pos + count > target_byte) { return false; } - current_byte += count; + out_pos += count; } } @@ -546,6 +545,12 @@ 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 void collect_face_to_mesh( const pxl8_bsp* bsp, u32 face_id, @@ -572,15 +577,12 @@ static void collect_face_to_mesh( u16 base_idx = (u16)mesh->vertex_count; u32 num_verts = 0; - static int face_debug = 0; - bool debug_this = (face_debug++ < 3); for (u32 i = 0; i < face->num_edges && num_verts < 64; i++) { i32 surfedge_idx = face->first_edge + i; u32 vert_idx; if (!pxl8_bsp_get_edge_vertex(bsp, surfedge_idx, &vert_idx)) { - if (debug_this) pxl8_debug("face %u: edge %u failed to get vertex (surfedge_idx=%d)", face_id, i, surfedge_idx); continue; } @@ -609,11 +611,6 @@ static void collect_face_to_mesh( num_verts++; } - if (debug_this) { - pxl8_debug("face %u: num_edges=%u, collected %u verts, texinfo_id=%u", - face_id, face->num_edges, num_verts, face->texinfo_id); - } - if (num_verts < 3) return; for (u32 i = 1; i < num_verts - 1; i++) { @@ -630,8 +627,14 @@ void pxl8_bsp_render_face(pxl8_gfx* gfx, const pxl8_bsp* bsp, u32 face_id, u32 t collect_face_to_mesh(bsp, face_id, mesh); if (mesh->index_count > 0) { - pxl8_material mat = pxl8_material_new(texture_id); - pxl8_3d_draw_mesh(gfx, mesh, pxl8_mat4_identity(), mat); + pxl8_mat4 identity = pxl8_mat4_identity(); + pxl8_gfx_material mat = { + .texture_id = texture_id, + .alpha = 255, + .dither = true, + .dynamic_lighting = true, + }; + pxl8_3d_draw_mesh(gfx, mesh, &identity, &mat); } pxl8_mesh_destroy(mesh); @@ -657,6 +660,32 @@ void pxl8_bsp_render_textured(pxl8_gfx* gfx, const pxl8_bsp* bsp, pxl8_vec3 came i32 camera_leaf = pxl8_bsp_find_leaf(bsp, camera_pos); + static u32 debug_counter = 0; + bool do_debug = (debug_counter++ % 300 == 0); + u32 visible_leafs = 0; + u32 visible_faces = 0; + u32 total_faces_in_visible_leafs = 0; + static bool dumped_camera_leaf = false; + if (do_debug) { + bool self_visible = (camera_leaf < 0) || pxl8_bsp_is_leaf_visible(bsp, camera_leaf, camera_leaf); + if (!self_visible) { + pxl8_debug("WARNING: Camera leaf %d is NOT visible from itself!", camera_leaf); + } + if (!dumped_camera_leaf && camera_leaf >= 0) { + const pxl8_bsp_leaf* cl = &bsp->leafs[camera_leaf]; + pxl8_debug("Camera leaf %d: contents=%d, marksurfaces=%u-%u (%u faces)", + camera_leaf, cl->contents, cl->first_marksurface, + cl->first_marksurface + cl->num_marksurfaces, cl->num_marksurfaces); + dumped_camera_leaf = true; + } + for (u32 i = 0; i < bsp->num_leafs; i++) { + if (camera_leaf < 0 || pxl8_bsp_is_leaf_visible(bsp, camera_leaf, i)) { + visible_leafs++; + total_faces_in_visible_leafs += bsp->leafs[i].num_marksurfaces; + } + } + } + static u8* rendered_faces = NULL; static u32 rendered_faces_capacity = 0; @@ -674,14 +703,25 @@ void pxl8_bsp_render_textured(pxl8_gfx* gfx, const pxl8_bsp* bsp, pxl8_vec3 came u32 current_texture = 0xFFFFFFFF; - static int debug_cull = 0; - u32 faces_checked = 0, faces_culled = 0, faces_passed = 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; const pxl8_bsp_leaf* leaf = &bsp->leafs[leaf_id]; + bool is_camera_leaf = ((i32)leaf_id == camera_leaf); + + f32 cx = ((f32)leaf->mins[0] + (f32)leaf->maxs[0]) * 0.5f; + f32 cy = ((f32)leaf->mins[1] + (f32)leaf->maxs[1]) * 0.5f; + f32 cz = ((f32)leaf->mins[2] + (f32)leaf->maxs[2]) * 0.5f; + f32 dx = camera_pos.x - cx; + f32 dy = camera_pos.y - cy; + f32 dz = camera_pos.z - cz; + f32 dist_sq = dx*dx + dy*dy + dz*dz; + bool camera_near_leaf = dist_sq < (512.0f * 512.0f); + + bool skip_frustum = is_camera_leaf || camera_near_leaf; + if (!skip_frustum && !leaf_in_frustum(leaf, frustum)) continue; + for (u32 i = 0; i < leaf->num_marksurfaces; i++) { u32 surf_idx = leaf->first_marksurface + i; if (surf_idx >= bsp->num_marksurfaces) continue; @@ -691,13 +731,11 @@ void pxl8_bsp_render_textured(pxl8_gfx* gfx, const pxl8_bsp* bsp, pxl8_vec3 came if (rendered_faces[face_id]) continue; rendered_faces[face_id] = 1; + if (do_debug) visible_faces++; - faces_checked++; - if (!face_in_frustum(bsp, face_id, frustum)) { - faces_culled++; + if (!skip_frustum && !face_in_frustum(bsp, face_id, frustum)) { continue; } - faces_passed++; const pxl8_bsp_face* face = &bsp->faces[face_id]; u32 texture_id = 0; @@ -706,39 +744,38 @@ void pxl8_bsp_render_textured(pxl8_gfx* gfx, const pxl8_bsp* bsp, pxl8_vec3 came } if (texture_id != current_texture && mesh->index_count > 0) { - pxl8_material mat = pxl8_material_with_double_sided(pxl8_material_new(current_texture)); - pxl8_3d_draw_mesh(gfx, mesh, pxl8_mat4_identity(), mat); + pxl8_mat4 identity = pxl8_mat4_identity(); + pxl8_gfx_material mat = { + .texture_id = current_texture, + .alpha = 255, + .dither = true, + .dynamic_lighting = true, + }; + pxl8_3d_draw_mesh(gfx, mesh, &identity, &mat); pxl8_mesh_clear(mesh); } current_texture = texture_id; - u32 before = mesh->index_count; collect_face_to_mesh(bsp, face_id, mesh); - if (debug_cull < 3 && mesh->index_count > before) { - pxl8_debug("Added face %u: mesh now has %u indices (was %u)", face_id, mesh->index_count, before); - } } } - static int draw_count = 0; - if (debug_cull < 3) { - pxl8_debug("Final mesh: %u indices, %u vertices", mesh->index_count, mesh->vertex_count); - } if (mesh->index_count > 0) { - pxl8_material mat = pxl8_material_with_double_sided(pxl8_material_new(current_texture)); - pxl8_3d_draw_mesh(gfx, mesh, pxl8_mat4_identity(), mat); - if (draw_count++ < 5) { - pxl8_debug("bsp_render_textured: drew mesh with %u indices, camera_leaf=%d", - mesh->index_count, camera_leaf); - } - } else if (draw_count < 5) { - pxl8_debug("bsp_render_textured: mesh is empty, camera_leaf=%d, num_leafs=%u", - camera_leaf, bsp->num_leafs); - draw_count++; + pxl8_mat4 identity = pxl8_mat4_identity(); + pxl8_gfx_material mat = { + .texture_id = current_texture, + .alpha = 255, + .dither = true, + .dynamic_lighting = true, + }; + pxl8_3d_draw_mesh(gfx, mesh, &identity, &mat); } - if (debug_cull++ < 5) { - pxl8_debug("bsp_render: checked=%u, culled=%u, passed=%u", faces_checked, faces_culled, faces_passed); + if (do_debug) { + pxl8_debug("Camera at (%.1f, %.1f, %.1f) -> leaf %d, %u/%u leafs, %u/%u faces (expected %u)", + camera_pos.x, camera_pos.y, camera_pos.z, + camera_leaf, visible_leafs, bsp->num_leafs, + visible_faces, bsp->num_faces, total_faces_in_visible_leafs); } pxl8_mesh_destroy(mesh); diff --git a/client/src/world/pxl8_bsp.h b/src/world/pxl8_bsp.h similarity index 100% rename from client/src/world/pxl8_bsp.h rename to src/world/pxl8_bsp.h diff --git a/src/world/pxl8_gen.c b/src/world/pxl8_gen.c new file mode 100644 index 0000000..a8b90b4 --- /dev/null +++ b/src/world/pxl8_gen.c @@ -0,0 +1,1022 @@ +#include "pxl8_gen.h" + +#include +#include +#include + +#include "pxl8_log.h" +#include "pxl8_rng.h" + +#define CELL_SIZE 64.0f +#define PVS_MAX_DEPTH 40 +#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 portal { + f32 x0, z0; + f32 x1, z1; + u32 target_leaf; +} portal; + +typedef struct cell_portals { + portal portals[4]; + u8 num_portals; +} cell_portals; + +typedef struct vis_window { + f32 left_x, left_z; + f32 right_x, right_z; +} vis_window; + +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)); + + return grid->cells != NULL; +} + +static u8 room_grid_get(const room_grid* grid, i32 x, i32 y) { + if (x < 0 || x >= grid->width || y < 0 || y >= grid->height) { + return 1; + } + return grid->cells[y * grid->width + x]; +} + +static void room_grid_set(room_grid* grid, i32 x, i32 y, u8 value) { + if (x < 0 || x >= grid->width || y < 0 || y >= grid->height) { + return; + } + grid->cells[y * grid->width + x] = value; +} + +static inline void compute_face_aabb(pxl8_bsp_face* face, const pxl8_bsp_vertex* verts, u32 vert_idx) { + face->aabb_min = (pxl8_vec3){1e30f, 1e30f, 1e30f}; + face->aabb_max = (pxl8_vec3){-1e30f, -1e30f, -1e30f}; + + for (u32 i = 0; i < 4; i++) { + pxl8_vec3 v = verts[vert_idx + i].position; + if (v.x < face->aabb_min.x) face->aabb_min.x = v.x; + if (v.x > face->aabb_max.x) face->aabb_max.x = v.x; + if (v.y < face->aabb_min.y) face->aabb_min.y = v.y; + if (v.y > face->aabb_max.y) face->aabb_max.y = v.y; + if (v.z < face->aabb_min.z) face->aabb_min.z = v.z; + if (v.z > face->aabb_max.z) face->aabb_max.z = v.z; + } +} + +static void room_grid_fill(room_grid* grid, u8 value) { + for (i32 y = 0; y < grid->height; y++) { + for (i32 x = 0; x < grid->width; x++) { + room_grid_set(grid, x, y, 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 = 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 cell_portals* build_cell_portals(const room_grid* grid, f32 cell_size) { + i32 total_cells = grid->width * grid->height; + cell_portals* portals = calloc(total_cells, sizeof(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) { + 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) { + 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) { + 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) { + 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; +} + +static inline f32 cross_2d(f32 ax, f32 az, f32 bx, f32 bz) { + return ax * bz - az * bx; +} + +static bool clip_window_through_portal( + f32 src_x, f32 src_z, + const vis_window* window, + const portal* p, + vis_window* clipped +) { + f32 wl_x = window->left_x - src_x; + f32 wl_z = window->left_z - src_z; + f32 wr_x = window->right_x - src_x; + f32 wr_z = window->right_z - src_z; + + f32 p0_x = p->x0 - src_x; + f32 p0_z = p->z0 - src_z; + f32 p1_x = p->x1 - src_x; + f32 p1_z = p->z1 - src_z; + + f32 p0_vs_wl = cross_2d(p0_x, p0_z, wl_x, wl_z); + f32 p1_vs_wl = cross_2d(p1_x, p1_z, wl_x, wl_z); + f32 p0_vs_wr = cross_2d(p0_x, p0_z, wr_x, wr_z); + f32 p1_vs_wr = cross_2d(p1_x, p1_z, wr_x, wr_z); + + if (p1_vs_wl <= 0.0f || p0_vs_wr >= 0.0f) { + return false; + } + + if (p0_vs_wl > 0.0f) { + clipped->left_x = p->x0; + clipped->left_z = p->z0; + } else { + clipped->left_x = window->left_x; + clipped->left_z = window->left_z; + } + + if (p1_vs_wr < 0.0f) { + clipped->right_x = p->x1; + clipped->right_z = p->z1; + } else { + clipped->right_x = window->right_x; + clipped->right_z = window->right_z; + } + + f32 cl_x = clipped->left_x - src_x; + f32 cl_z = clipped->left_z - src_z; + f32 cr_x = clipped->right_x - src_x; + f32 cr_z = clipped->right_z - src_z; + + if (cross_2d(cl_x, cl_z, cr_x, cr_z) >= -0.0001f) { + return false; + } + + return true; +} + +typedef struct portal_vis_context { + u8* pvs; + u8* visited; + const cell_portals* portals; + const pxl8_bsp_leaf* leafs; + f32 src_x; + f32 src_z; + u32 num_leafs; + u32 max_depth; +} portal_vis_context; + +static void portal_flood_recursive( + portal_vis_context* ctx, + u32 current_leaf, + const vis_window* window, + u32 depth +) { + if (depth > ctx->max_depth) return; + + u32 byte = current_leaf >> 3; + u32 bit = current_leaf & 7; + + if (ctx->visited[byte] & (1 << bit)) return; + ctx->visited[byte] |= (1 << bit); + + if (ctx->leafs[current_leaf].contents == -1) return; + + ctx->pvs[byte] |= (1 << bit); + + const cell_portals* cp = &ctx->portals[current_leaf]; + for (u8 i = 0; i < cp->num_portals; i++) { + const portal* p = &cp->portals[i]; + + u32 target_byte = p->target_leaf >> 3; + u32 target_bit = p->target_leaf & 7; + if (ctx->visited[target_byte] & (1 << target_bit)) continue; + + vis_window clipped; + if (clip_window_through_portal(ctx->src_x, ctx->src_z, window, p, &clipped)) { + portal_flood_recursive(ctx, p->target_leaf, &clipped, depth + 1); + } + } +} + +typedef struct vis_entry { + u32 leaf; + vis_window window; +} vis_entry; + +static void portal_flood_bfs( + u32 start_leaf, + const cell_portals* portals, + const pxl8_bsp_leaf* leafs, + u8* pvs, + u32 num_leafs, + f32 cell_size, + i32 grid_width +) { + u32 pvs_bytes = (num_leafs + 7) / 8; + u8* visited = calloc(pvs_bytes, 1); + vis_entry* queue = malloc(num_leafs * 4 * sizeof(vis_entry)); + if (!visited || !queue) { + free(visited); + free(queue); + return; + } + + i32 start_x = start_leaf % grid_width; + i32 start_y = start_leaf / grid_width; + f32 src_x = (start_x + 0.5f) * cell_size; + f32 src_z = (start_y + 0.5f) * cell_size; + + u32 head = 0, tail = 0; + + pvs[start_leaf >> 3] |= (1 << (start_leaf & 7)); + visited[start_leaf >> 3] |= (1 << (start_leaf & 7)); + + const cell_portals* start_cp = &portals[start_leaf]; + for (u8 i = 0; i < start_cp->num_portals; i++) { + const portal* p = &start_cp->portals[i]; + vis_window initial = {p->x0, p->z0, p->x1, p->z1}; + queue[tail++] = (vis_entry){p->target_leaf, initial}; + } + + while (head < tail) { + vis_entry e = queue[head++]; + + if (leafs[e.leaf].contents == -1) continue; + + u32 byte = e.leaf >> 3; + u32 bit = e.leaf & 7; + + pvs[byte] |= (1 << bit); + + if (visited[byte] & (1 << bit)) continue; + visited[byte] |= (1 << bit); + + const cell_portals* cp = &portals[e.leaf]; + for (u8 i = 0; i < cp->num_portals; i++) { + const portal* p = &cp->portals[i]; + + vis_window clipped; + if (clip_window_through_portal(src_x, src_z, &e.window, p, &clipped)) { + queue[tail++] = (vis_entry){p->target_leaf, clipped}; + } + } + } + + free(visited); + free(queue); +} + +static u8* compute_leaf_pvs(u32 start_leaf, const 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 = 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 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 = malloc(max_visdata); + if (!visdata) return PXL8_ERROR_OUT_OF_MEMORY; + + u32 visdata_pos = 0; + + u8* compressed = malloc(pvs_bytes * 2); + if (!compressed) { + 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) { + free(compressed); + 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; + + free(pvs); + } + + free(compressed); + bsp->visdata = 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; + i32 floor_ceiling_count = 0; + + for (i32 y = 0; y < grid->height; y++) { + for (i32 x = 0; x < grid->width; x++) { + if (room_grid_get(grid, x, y) == 0) { + if (room_grid_get(grid, x - 1, y) == 1) face_count++; + if (room_grid_get(grid, x + 1, y) == 1) face_count++; + if (room_grid_get(grid, x, y - 1) == 1) face_count++; + if (room_grid_get(grid, x, y + 1) == 1) face_count++; + floor_ceiling_count++; + } + } + } + + face_count += floor_ceiling_count; + vertex_count = face_count * 4; + + pxl8_debug("Level generation: %dx%d grid -> %d faces, %d vertices", + grid->width, grid->height, face_count, vertex_count); + + i32 total_cells = grid->width * grid->height; + u32 max_nodes = 2 * total_cells; + u32 total_planes = face_count + max_nodes; + + bsp->vertices = calloc(vertex_count, sizeof(pxl8_bsp_vertex)); + bsp->faces = calloc(face_count, sizeof(pxl8_bsp_face)); + bsp->planes = calloc(total_planes, sizeof(pxl8_bsp_plane)); + bsp->edges = calloc(vertex_count, sizeof(pxl8_bsp_edge)); + bsp->surfedges = calloc(vertex_count, sizeof(i32)); + bsp->nodes = calloc(max_nodes, sizeof(pxl8_bsp_node)); + + u32* face_cell = calloc(face_count, sizeof(u32)); + + if (!bsp->vertices || !bsp->faces || !bsp->planes || !bsp->edges || + !bsp->surfedges || !bsp->nodes || !face_cell) { + free(face_cell); + return PXL8_ERROR_OUT_OF_MEMORY; + } + + bsp->texinfo = NULL; + bsp->num_texinfo = 0; + + i32 vert_idx = 0; + i32 face_idx = 0; + i32 edge_idx = 0; + + 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}; + bsp->vertices[vert_idx + 1].position = (pxl8_vec3){fx, wall_height, fy}; + 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->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); + face_cell[face_idx] = cell_idx; + + vert_idx += 4; + edge_idx += 4; + face_idx++; + } + + if (room_grid_get(grid, x + 1, y) == 1) { + bsp->vertices[vert_idx + 0].position = (pxl8_vec3){fx + cell_size, 0, fy}; + bsp->vertices[vert_idx + 1].position = (pxl8_vec3){fx + cell_size, 0, fy + cell_size}; + 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->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); + face_cell[face_idx] = cell_idx; + + vert_idx += 4; + edge_idx += 4; + face_idx++; + } + + if (room_grid_get(grid, x, y - 1) == 1) { + bsp->vertices[vert_idx + 0].position = (pxl8_vec3){fx, 0, fy}; + bsp->vertices[vert_idx + 1].position = (pxl8_vec3){fx + cell_size, 0, fy}; + 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->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); + face_cell[face_idx] = cell_idx; + + vert_idx += 4; + edge_idx += 4; + face_idx++; + } + + if (room_grid_get(grid, x, y + 1) == 1) { + bsp->vertices[vert_idx + 0].position = (pxl8_vec3){fx, 0, fy + cell_size}; + bsp->vertices[vert_idx + 1].position = (pxl8_vec3){fx, wall_height, fy + cell_size}; + 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->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); + face_cell[face_idx] = cell_idx; + + vert_idx += 4; + edge_idx += 4; + face_idx++; + } + } + } + } + + 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; + + bsp->vertices[vert_idx + 0].position = (pxl8_vec3){fx, 0, fy}; + bsp->vertices[vert_idx + 1].position = (pxl8_vec3){fx, 0, fy + cell_size}; + bsp->vertices[vert_idx + 2].position = (pxl8_vec3){fx + cell_size, 0, fy + cell_size}; + bsp->vertices[vert_idx + 3].position = (pxl8_vec3){fx + cell_size, 0, fy}; + + bsp->planes[face_idx].normal = (pxl8_vec3){0, 1, 0}; + bsp->planes[face_idx].dist = 0; + + 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); + face_cell[face_idx] = cell_idx; + + vert_idx += 4; + edge_idx += 4; + face_idx++; + } + } + } + + bsp->num_vertices = vertex_count; + bsp->num_faces = face_count; + bsp->num_edges = vertex_count; + bsp->num_surfedges = vertex_count; + + bsp->leafs = calloc(total_cells, sizeof(pxl8_bsp_leaf)); + bsp->marksurfaces = calloc(face_count, sizeof(u16)); + + if (!bsp->leafs || !bsp->marksurfaces) { + free(face_cell); + return PXL8_ERROR_OUT_OF_MEMORY; + } + + bsp->num_leafs = total_cells; + bsp->num_marksurfaces = face_count; + + u32* faces_per_cell = calloc(total_cells, sizeof(u32)); + u32* cell_offset = calloc(total_cells, sizeof(u32)); + u32* cell_cursor = calloc(total_cells, sizeof(u32)); + + if (!faces_per_cell || !cell_offset || !cell_cursor) { + free(faces_per_cell); + free(cell_offset); + free(cell_cursor); + free(face_cell); + return PXL8_ERROR_OUT_OF_MEMORY; + } + + for (i32 i = 0; i < face_count; 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; + } + } + + free(faces_per_cell); + free(cell_offset); + free(cell_cursor); + 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); + + cell_portals* portals = build_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 = calloc(pvs_bytes, 1); + u8* queue = 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); + free(visited); + free(queue); + } + + pxl8_result pvs_result = build_pvs_data(bsp, portals, grid, cell_size); + free(portals); + + if (pvs_result != PXL8_OK) { + return pvs_result; + } + + return PXL8_OK; +} + +static bool bounds_intersects(const pxl8_bounds* a, const pxl8_bounds* b) { + return !(a->x + a->w <= b->x || b->x + b->w <= a->x || + a->y + a->h <= b->y || b->y + b->h <= a->y); +} + +static void carve_corridor_h(room_grid* grid, i32 x1, i32 x2, i32 y) { + i32 start = (x1 < x2) ? x1 : x2; + i32 end = (x1 > x2) ? x1 : x2; + for (i32 x = start; x <= end; x++) { + room_grid_set(grid, x, y, 0); + room_grid_set(grid, x, y - 1, 0); + room_grid_set(grid, x, y + 1, 0); + } +} + +static void carve_corridor_v(room_grid* grid, i32 y1, i32 y2, i32 x) { + i32 start = (y1 < y2) ? y1 : y2; + i32 end = (y1 > y2) ? y1 : y2; + for (i32 y = start; y <= end; y++) { + room_grid_set(grid, x, y, 0); + room_grid_set(grid, x - 1, y, 0); + room_grid_set(grid, x + 1, y, 0); + } +} + +static pxl8_result procgen_rooms(pxl8_bsp* bsp, const pxl8_procgen_params* params) { + pxl8_debug("procgen_rooms called: %dx%d, seed=%u, min=%d, max=%d, num=%d", + params->width, params->height, params->seed, + params->min_room_size, params->max_room_size, params->num_rooms); + + pxl8_rng rng; + pxl8_rng_seed(&rng, params->seed); + + room_grid grid; + if (!room_grid_init(&grid, params->width, params->height)) { + pxl8_error("Failed to allocate room grid"); + return PXL8_ERROR_OUT_OF_MEMORY; + } + + room_grid_fill(&grid, 1); + + pxl8_bounds rooms[256]; + 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)); + i32 x = 1 + (pxl8_rng_next(&rng) % (params->width - w - 2)); + i32 y = 1 + (pxl8_rng_next(&rng) % (params->height - h - 2)); + + pxl8_bounds new_room = {x, y, w, h}; + + bool overlaps = false; + for (i32 i = 0; i < room_count; i++) { + if (bounds_intersects(&new_room, &rooms[i])) { + overlaps = true; + break; + } + } + + if (!overlaps) { + for (i32 ry = y; ry < y + h; ry++) { + for (i32 rx = x; rx < x + w; rx++) { + room_grid_set(&grid, rx, ry, 0); + } + } + + if (room_count > 0) { + i32 new_cx = x + w / 2; + i32 new_cy = y + h / 2; + i32 prev_cx = rooms[room_count - 1].x + rooms[room_count - 1].w / 2; + i32 prev_cy = rooms[room_count - 1].y + rooms[room_count - 1].h / 2; + + if (pxl8_rng_next(&rng) % 2 == 0) { + carve_corridor_h(&grid, prev_cx, new_cx, prev_cy); + carve_corridor_v(&grid, prev_cy, new_cy, new_cx); + } else { + carve_corridor_v(&grid, prev_cy, new_cy, prev_cx); + carve_corridor_h(&grid, prev_cx, new_cx, new_cy); + } + } + + rooms[room_count++] = new_room; + } + } + + pxl8_debug("Room generation: %dx%d grid -> %d rooms created", + params->width, params->height, room_count); + + pxl8_result result = grid_to_bsp(bsp, &grid); + 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; +} + +pxl8_result pxl8_procgen(pxl8_bsp* bsp, const pxl8_procgen_params* params) { + if (!bsp || !params) { + return PXL8_ERROR_NULL_POINTER; + } + + switch (params->type) { + case PXL8_PROCGEN_ROOMS: + return procgen_rooms(bsp, params); + + case PXL8_PROCGEN_TERRAIN: + pxl8_error("Terrain generation not yet implemented"); + return PXL8_ERROR_NOT_INITIALIZED; + + default: + pxl8_error("Unknown procgen type: %d", params->type); + return PXL8_ERROR_INVALID_ARGUMENT; + } +} diff --git a/client/src/world/pxl8_gen.h b/src/world/pxl8_gen.h similarity index 63% rename from client/src/world/pxl8_gen.h rename to src/world/pxl8_gen.h index a887eb1..bef83b0 100644 --- a/client/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/client/src/world/pxl8_world.c b/src/world/pxl8_world.c similarity index 98% rename from client/src/world/pxl8_world.c rename to src/world/pxl8_world.c index 3f96b74..90fee37 100644 --- a/client/src/world/pxl8_world.c +++ b/src/world/pxl8_world.c @@ -398,15 +398,15 @@ void pxl8_world_render(pxl8_world* world, pxl8_gfx* gfx, pxl8_vec3 camera_pos) { return; } - static int render_count = 0; - if (render_count++ < 5) { - pxl8_debug("world_render: camera_pos=(%.1f, %.1f, %.1f), num_faces=%u", - camera_pos.x, camera_pos.y, camera_pos.z, world->bsp.num_faces); - } - 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); } } + +void pxl8_world_set_wireframe(pxl8_world* world, bool enabled, u8 color) { + if (!world) return; + world->wireframe = enabled; + world->wireframe_color = color; +} diff --git a/client/src/world/pxl8_world.h b/src/world/pxl8_world.h similarity index 94% rename from client/src/world/pxl8_world.h rename to src/world/pxl8_world.h index 5388a12..e2a1f1e 100644 --- a/client/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, u8 color); #ifdef __cplusplus }