summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore3
-rw-r--r--Fuse/allocators.c303
-rw-r--r--Fuse/allocators.h60
-rw-r--r--Fuse/demos/fuse.slang31
-rw-r--r--Fuse/demos/fuse_demo.c280
-rw-r--r--Fuse/fuse.c436
-rw-r--r--Fuse/fuse.h138
-rw-r--r--Fuse/fuse_backend.h42
-rw-r--r--Fuse/fuse_backend_rend.c0
-rw-r--r--Fuse/fuse_components.c3
-rw-r--r--Fuse/fuse_hash.c2
-rw-r--r--Fuse/fuse_internal.h63
-rw-r--r--Fuse/fuse_positioning.c14
-rwxr-xr-xFuse/fuse_testbin0 -> 35776 bytes
-rw-r--r--Fuse/fuse_test.c25
-rw-r--r--Fuse/fuse_tween.c68
-rw-r--r--LICENSE39
-rw-r--r--Peak/README.md3
-rw-r--r--Peak/demos/demo.c65
-rw-r--r--Peak/demos/demo_replace_main.c67
-rw-r--r--Peak/peak.h895
-rw-r--r--Peak/src/p_emscripten.c38
-rw-r--r--Peak/src/p_linux.c295
-rw-r--r--Peak/src/p_win32.c21
-rw-r--r--Peak/src/peak.c254
-rw-r--r--Peak/src/peak_header.h283
-rw-r--r--Peak/src/peak_header.h.out895
-rw-r--r--Podium/README.md9
-rw-r--r--Podium/p_allocators.c301
-rw-r--r--Podium/p_allocators.h44
-rw-r--r--Podium/p_ds.h52
-rw-r--r--Podium/p_log.h186
-rw-r--r--Podium/p_math.c255
-rw-r--r--Podium/p_math.h33
-rw-r--r--Podium/p_platform_linux.c404
-rw-r--r--Podium/p_platform_win32.c402
-rw-r--r--Podium/p_string.c201
-rw-r--r--Podium/p_string.h38
-rw-r--r--Podium/p_types.h88
-rw-r--r--Podium/podium.c1
-rw-r--r--Podium/podium.h2269
-rw-r--r--Podium/podium_header.h258
-rw-r--r--Poof/poof.h875
-rw-r--r--README.md32
-rw-r--r--Rend/README.md28
-rw-r--r--Rend/demos/build.c85
-rw-r--r--Rend/demos/compute/frag.spvbin0 -> 376 bytes
-rw-r--r--Rend/demos/compute/particle.spvbin0 -> 1876 bytes
-rwxr-xr-xRend/demos/compute/rend_compute_demobin0 -> 424800 bytes
-rwxr-xr-xRend/demos/compute/rend_compute_fastbin0 -> 450512 bytes
-rw-r--r--Rend/demos/compute/sand.spvbin0 -> 5548 bytes
-rw-r--r--Rend/demos/compute/vert.spvbin0 -> 3704 bytes
-rw-r--r--Rend/demos/poof.h874
-rw-r--r--Rend/demos/rend_compute.c214
-rw-r--r--Rend/demos/rend_compute.slang146
-rw-r--r--Rend/demos/rend_teapot.c172
-rw-r--r--Rend/demos/teapot.h17273
-rw-r--r--Rend/demos/teapot/shaders/basic.slang36
-rw-r--r--Rend/demos/teapot/shaders/texture.slang28
-rw-r--r--Rend/demos/teapot/stb_image.h7988
-rw-r--r--Rend/demos/teapot/texture.frag.spvbin0 -> 684 bytes
-rw-r--r--Rend/demos/teapot/texture.vert.spvbin0 -> 844 bytes
-rw-r--r--Rend/demos/teapot/wal.jpgbin0 -> 21110 bytes
-rw-r--r--Rend/nogl.h141
-rw-r--r--Rend/podium.h2282
-rw-r--r--Rend/rend.c617
-rw-r--r--Rend/rend.h331
-rw-r--r--Rend/rend_internal.h205
-rw-r--r--Rend/rend_vk.c2149
-rw-r--r--Rend/rend_vk_allocator.c118
-rw-r--r--Rend/rend_vk_arena.c264
-rw-r--r--Rend/rend_vk_device.c383
-rw-r--r--Rend/rend_vk_image.c125
-rw-r--r--Rend/rend_vk_internal.h177
-rw-r--r--Rend/unused code/rend_vk_buffer.c116
-rw-r--r--Rend/unused code/rend_vk_command_queue.c153
-rw-r--r--Rend/unused code/rend_vk_memory.c100
-rw-r--r--Rend/unused code/rend_vk_pool.c221
-rw-r--r--Rend/unused code/rend_vk_sbta.c331
-rw-r--r--build.c33
-rw-r--r--bundle_header.py46
81 files changed, 44407 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..54fc00b
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,3 @@
+*.old
+build
+build.exe
diff --git a/Fuse/allocators.c b/Fuse/allocators.c
new file mode 100644
index 0000000..f2c6a67
--- /dev/null
+++ b/Fuse/allocators.c
@@ -0,0 +1,303 @@
+#pragma once
+
+#include "allocators.h"
+
+static inline bool is_power_of_two(uintptr_t x) {
+ return (x & (x-1)) == 0;
+}
+
+static inline uintptr_t align_forward(uintptr_t ptr, size_t align) {
+ uintptr_t p, a, remainder;
+ assert(is_power_of_two(align));
+
+ p = ptr;
+ a = (uintptr_t)align;
+ remainder = p & (a-1);
+
+ return (remainder != 0) ? p + a - remainder : p;
+}
+
+
+void
+al_arena_create(Arena *a, void *backing_buffer, size_t backing_buffer_length)
+{
+ a->buf = (unsigned char *)backing_buffer;
+ a->buf_len = backing_buffer_length;
+ a->curr_offset = 0;
+ a->prev_offset = 0;
+}
+
+void*
+al_arena_alloc_align(Arena *a, size_t s, size_t align)
+{
+
+ // Align 'curr_offset' forward to the specified alignment
+ uintptr_t curr_ptr = (uintptr_t)a->buf + (uintptr_t)a->curr_offset;
+ uintptr_t offset = align_forward(curr_ptr, align);
+ offset -= (uintptr_t)a->buf; // Change to relative offset
+
+ // Check to see if the backing memory has space left
+ if (offset+s <= a->buf_len) {
+ void *ptr = &a->buf[offset];
+ a->prev_offset = offset;
+ a->curr_offset = offset+s;
+
+ memset(ptr, 0, s);
+ return ptr;
+ }
+
+ return NULL;
+}
+
+void*
+al_arena_alloc(Arena *a, size_t s) {
+ return al_arena_alloc_align(a, s, DEFAULT_ALIGNMENT);
+}
+
+void*
+al_arena_resize_align(Arena *a, void *old_memory, size_t old_size, size_t new_size, size_t align)
+{
+ assert(is_power_of_two(align));
+ unsigned char *old_mem = (unsigned char *)old_memory;
+
+ if (old_mem == NULL || old_size == 0) {
+ return al_arena_alloc_align(a, new_size, align);
+ } else if (a->buf <= old_mem && old_mem < a->buf+a->buf_len) {
+ if (a->buf+a->prev_offset == old_mem) {
+ a->curr_offset = a->prev_offset + new_size;
+ if (new_size > old_size) {
+ // Zero the new memory by default
+ memset(&a->buf[a->curr_offset], 0, new_size-old_size);
+ }
+ return old_memory;
+ } else {
+ void *new_memory = al_arena_alloc_align(a, new_size, align);
+ size_t copy_size = old_size < new_size ? old_size : new_size;
+ memmove(new_memory, old_memory, copy_size);
+ return new_memory;
+ }
+
+ } else {
+ assert(0 && "Memory is out of bounds of the buffer in this arena");
+ return NULL;
+ }
+}
+
+void*
+al_arena_resize(Arena *a, void *old_memory, size_t old_size, size_t new_size)
+{
+ return al_arena_resize_align(a, old_memory, old_size, new_size, DEFAULT_ALIGNMENT);
+}
+
+void
+al_arena_free_all(Arena *a)
+{
+ a->curr_offset = 0;
+ a->prev_offset = 0;
+}
+
+void
+al_arena_destroy(Arena* a)
+{
+ a->buf_len = 0;
+ a->curr_offset = 0;
+ a->prev_offset = 0;
+}
+
+void
+al_stack_create(Stack *s, void *backing_buffer, size_t backing_buffer_length)
+{
+ s->buf = (unsigned char*) backing_buffer;
+ s->buf_len = backing_buffer_length;
+ s->offset = 0;
+}
+
+size_t
+al_calc_padding_with_header(uintptr_t ptr, uintptr_t alignment, size_t header_size)
+{
+ uintptr_t p, a, modulo, padding, needed_space;
+
+ assert(is_power_of_two(alignment));
+
+ p = ptr;
+ a = alignment;
+ modulo = p & (a-1); // (p % a) as it assumes alignment is a power of two
+
+ padding = 0;
+ needed_space = 0;
+
+ if (modulo != 0) { // Same logic as 'align_forward'
+ padding = a - modulo;
+ }
+
+ needed_space = (uintptr_t)header_size;
+
+ if (padding < needed_space) {
+ needed_space -= padding;
+
+ if ((needed_space & (a-1)) != 0) {
+ padding += a * (1+(needed_space/a));
+ } else {
+ padding += a * (needed_space/a);
+ }
+ }
+
+ return (size_t)padding;
+}
+
+void*
+al_stack_alloc(Stack *s, size_t len, size_t alignment)
+{
+ uintptr_t curr_addr, next_addr;
+ size_t padding;
+ Stack_Allocation_Header *header;
+
+ assert(is_power_of_two(alignment));
+
+ if (alignment > 128) {
+ // As the padding is 8 bits (1 byte), the largest alignment that can
+ // be used is 128 bytes
+ alignment = 128;
+ }
+
+ curr_addr = (uintptr_t)s->buf + (uintptr_t)s->offset;
+ padding = al_calc_padding_with_header(curr_addr, (uintptr_t)alignment, sizeof(Stack_Allocation_Header));
+ if (s->offset + padding + len > s->buf_len) {
+ // Stack allocator is out of memory
+ return NULL;
+ }
+ s->offset += padding;
+
+ next_addr = curr_addr + (uintptr_t)padding;
+ header = (Stack_Allocation_Header *)(next_addr - sizeof(Stack_Allocation_Header));
+ header->padding = (uint8_t)padding;
+
+ s->offset += len;
+
+ return memset((void *)next_addr, 0, len);
+}
+
+void
+al_stack_free(Stack *s, void *ptr)
+{
+ if (ptr != NULL) {
+ uintptr_t start, end, curr_addr;
+ Stack_Allocation_Header *header;
+ size_t prev_offset;
+
+ start = (uintptr_t)s->buf;
+ end = start + (uintptr_t)s->buf_len;
+ curr_addr = (uintptr_t)ptr;
+
+ if (!(start <= curr_addr && curr_addr < end)) {
+ assert(0 && "Out of bounds memory address passed to stack allocator (free)");
+ return;
+ }
+
+ if (curr_addr >= start+(uintptr_t)s->offset) {
+ // Allow double frees
+ return;
+ }
+
+ header = (Stack_Allocation_Header *)(curr_addr - sizeof(Stack_Allocation_Header));
+ prev_offset = (size_t)(curr_addr - (uintptr_t)header->padding - start);
+
+ s->offset = prev_offset;
+ }
+}
+
+void
+al_stack_free_all(Stack* s)
+{
+ s->offset = 0;
+}
+
+void
+al_stack_destroy(Stack* s)
+{
+ s->buf = 0;
+ s->buf_len = 0;
+ s->offset = 0;
+}
+
+void
+al_pool_create(Pool *p, void *buf, size_t buf_len, size_t chunk_size, size_t chunk_align)
+{
+ /* align start */
+ uintptr_t start = (uintptr_t) buf;
+ uintptr_t aligned = align_forward(start, chunk_align);
+ buf_len -= (aligned - start);
+
+ /* align chunk size_t */
+ chunk_size = (size_t) align_forward(chunk_size, chunk_align);
+
+ assert(chunk_size >= sizeof(Pool_Free_Node) && "Chunk size_t is too small");
+ assert(buf_len >= chunk_size && "Backing buffer length is smaller than the chunk size");
+
+ p->buf = (unsigned char *) buf;
+ p->pool_size = buf_len;
+ p->chunk_size = chunk_size;
+ p->head = NULL;
+
+ al_pool_free_all(p);
+}
+
+void*
+al_pool_alloc(Pool *p)
+{
+ Pool_Free_Node *node = p->head;
+
+ assert(node != NULL && "Pool allocator has no free memory");
+
+ p->head = p->head->next;
+
+ return memset(node, 0 , p->chunk_size);
+}
+
+void
+al_pool_free(Pool *p, void *ptr)
+{
+ Pool_Free_Node *node;
+
+ void *start = p->buf;
+ void *end = &p->buf[p->pool_size];
+
+ if (ptr == NULL) {
+ return;
+ }
+
+ if (!(start <= ptr && ptr < end)) {
+ assert(0 && "Memory is out of bounds of the buffer in this pool");
+ return;
+ }
+
+ node = (Pool_Free_Node *)ptr;
+ node->next = p->head;
+ p->head = node;
+}
+
+void
+al_pool_free_all(Pool *p)
+{
+ size_t chunk_count = p->pool_size / p->chunk_size;
+ size_t i;
+
+ for (i = 0; i < chunk_count; i++) {
+ void *ptr = &p->buf[i * p->chunk_size];
+ Pool_Free_Node *node = (Pool_Free_Node *)ptr;
+
+ // Push free node onto thte free list
+ node->next = p->head;
+ p->head = node;
+ }
+}
+
+void
+al_pool_destroy(Pool *p)
+{
+ p->buf = NULL;
+ p->pool_size = 0;
+ p->chunk_size = 0;
+ p->head = NULL;
+}
+
diff --git a/Fuse/allocators.h b/Fuse/allocators.h
new file mode 100644
index 0000000..d029558
--- /dev/null
+++ b/Fuse/allocators.h
@@ -0,0 +1,60 @@
+#ifndef ALLOCATORS_H
+#define ALLOCATORS_H
+
+#include <stddef.h>
+#include <stdint.h>
+#include <assert.h>
+#include <string.h>
+
+#ifndef DEFAULT_ALIGNMENT
+#define DEFAULT_ALIGNMENT (2*sizeof(void *))
+#endif
+
+typedef struct Arena {
+ unsigned char *buf;
+ size_t buf_len;
+ size_t curr_offset;
+ size_t prev_offset;
+} Arena;
+
+typedef struct { uint8_t padding; } Stack_Allocation_Header;
+typedef struct Stack {
+ unsigned char *buf;
+ size_t buf_len;
+ size_t offset;
+} Stack;
+
+typedef struct Pool_Free_Node Pool_Free_Node;
+
+typedef struct Pool {
+ unsigned char *buf;
+ size_t chunk_size;
+ size_t pool_size;
+ Pool_Free_Node *head;
+} Pool;
+
+struct Pool_Free_Node { struct Pool_Free_Node *next; };
+
+void al_arena_create(Arena *a, void *backing_buffer, size_t backing_buffer_length);
+void* al_arena_alloc_align(Arena *a, size_t s, size_t align);
+void* al_arena_alloc(Arena *a, size_t s);
+void* al_arena_resize_align(Arena *a, void *old_memory, size_t old_size, size_t new_size, size_t align);
+void* al_arena_resize(Arena *a, void *old_memory, size_t old_size, size_t new_size);
+void al_arena_free_all(Arena *a);
+void al_arena_destroy(Arena* a);
+
+void al_stack_create(Stack *s, void *backing_buffer, size_t backing_buffer_length);
+size_t al_calc_padding_with_header(uintptr_t ptr, uintptr_t alignment, size_t header_size);
+void* al_stack_alloc(Stack *s, size_t len, size_t alignment);
+void al_stack_free(Stack *s, void *ptr);
+void al_stack_free_all(Stack* s);
+void al_stack_destroy(Stack* s);
+
+void al_pool_create(Pool *p, void *buf, size_t buf_len, size_t chunk_size, size_t chunk_align);
+void* al_pool_alloc(Pool *p);
+void al_pool_free(Pool *p, void *ptr);
+void al_pool_free_all(Pool *p);
+void al_pool_destroy(Pool *p);
+
+
+#endif
diff --git a/Fuse/demos/fuse.slang b/Fuse/demos/fuse.slang
new file mode 100644
index 0000000..837a3dc
--- /dev/null
+++ b/Fuse/demos/fuse.slang
@@ -0,0 +1,31 @@
+struct VertexInput {
+ [[vk::location(0)]] float2 pos : POSITION;
+ [[vk::location(1)]] float4 col : COLOR;
+};
+
+struct VertexOutput {
+ float4 col : COLOR;
+ float4 pos : SV_Position;
+};
+
+struct UBO {
+ float2 viewport;
+};
+
+[[vk::binding(0, 0)]]
+ConstantBuffer<UBO> ubo;
+
+[shader("vertex")]
+VertexOutput vertMain(VertexInput input)
+{
+ VertexOutput output;
+ output.col = input.col;
+ output.pos = float4(input.pos*2.0/ubo.viewport - 1.0, 0.0, 1.0);
+ return output;
+}
+
+[shader("fragment")]
+float4 fragMain(VertexOutput input) : SV_Target
+{
+ return input.col;
+}
diff --git a/Fuse/demos/fuse_demo.c b/Fuse/demos/fuse_demo.c
new file mode 100644
index 0000000..60128bd
--- /dev/null
+++ b/Fuse/demos/fuse_demo.c
@@ -0,0 +1,280 @@
+#include "rend.h"
+#include "rend.c"
+#include "fuse.h"
+#include "fuse.c"
+#include <stddef.h>
+#include <stdio.h>
+
+/* has to be included last because rend will ask for certain modules */
+#define PODIUM_IMPLEMENTATION
+#include "podium.h"
+
+typedef struct { float x, y; } FuseVec2;
+typedef struct { float x, y, z, w; } FuseVec4;
+
+#pragma pack(push, 1)
+typedef struct {
+ FuseVec2 pos;
+ FuseVec4 color;
+} FuseVertex;
+#pragma pack(pop)
+
+static FuseVertex fuse_renderer_data[1024];
+static size_t fuse_renderer_idx = 0;
+
+struct data_t { float offset_x; float padding = 0 };
+struct data_t button_data = { .offset_x = 0, .padding = 0};
+
+void stretch_button_op(void *data) {
+ struct data_t* ptr = (struct data_t*) data;
+ data->offset_x += 10;
+ data->padding += 10;
+}
+
+
+static inline FuseVec4
+fuse__unpack_color(uint32_t c)
+{
+ FuseVec4 v;
+ v.x = (float) ((c >> 24) & 0xFF) / 255.0f; // Red
+ v.y = (float) ((c >> 16) & 0xFF) / 255.0f; // Green
+ v.z = (float) ((c >> 8) & 0xFF) / 255.0f; // Blue
+ v.w = (float) ( c & 0xFF) / 255.0f; // Alpha
+ return v;
+}
+
+void fuse_handler(FuseCanvas canvas, FuseCmd *cmd, void *data) {
+ switch (cmd->type) {
+ case FUSE_CMD_RECT:
+ FuseRect rect = cmd->rect;
+ FuseVec4 color = fuse__unpack_color(rect.color);
+ FuseVertex c0 = {
+ .pos = { rect.x, rect.y },
+ .color = color
+ };
+
+ FuseVertex c1 = {
+ .pos = { rect.x + rect.w, rect.y },
+ .color = color
+ };
+
+ FuseVertex c2 = {
+ .pos = { rect.x + rect.w, rect.y + rect.h },
+ .color = color
+ };
+
+ FuseVertex c3 = {
+ .pos = { rect.x, rect.y + rect.h },
+ .color = color
+ };
+
+ fuse_renderer_data[fuse_renderer_idx++] = c0;
+ fuse_renderer_data[fuse_renderer_idx++] = c1;
+ fuse_renderer_data[fuse_renderer_idx++] = c2;
+
+ fuse_renderer_data[fuse_renderer_idx++] = c2;
+ fuse_renderer_data[fuse_renderer_idx++] = c3;
+ fuse_renderer_data[fuse_renderer_idx++] = c0;
+ break;
+ }
+}
+
+#define SCREEN_WIDTH 800
+#define SCREEN_HEIGHT 600
+
+int main() {
+
+ P_Window window;
+ if (!p_window_open(&window, 800, 600, "fuse_demo")) {
+ PFATAL("Failed to open window!");
+ return 1;
+ }
+
+ if (!rend_init(REND_BACKEND_AUTO)) {
+ PFATAL("Failed to initialize backend!");
+ return 1;
+ }
+
+ RendRenderer renderer = rend_renderer_create(&window, true);
+ RendShader vert = rend_shader_from_spv_path(REND_SHADER_VERTEX, "fuse.vert.spv");
+ RendShader frag = rend_shader_from_spv_path(REND_SHADER_FRAG, "fuse.frag.spv");
+
+ RendPipelineConfig ui_cfg = rend_pipeline_config_create(
+ REND_TOPOLOGY_TRIANGLE_LIST,
+ REND_POLYGON_MODE_FILL,
+ REND_CULL_MODE_BACK);
+ rend_pipeline_config_depth_test(ui_cfg, false);
+
+ /* configure vertex input */
+ int b0 = rend_pipeline_config_vertex_binding_add(ui_cfg, sizeof (FuseVertex), REND_INPUT_RATE_VERTEX);
+ rend_pipeline_config_vertex_attribute_add(ui_cfg, b0, 0, REND_FORMAT_R32G32_SFLOAT, offsetof(FuseVertex, pos));
+ rend_pipeline_config_vertex_attribute_add(ui_cfg, b0, 1, REND_FORMAT_R32G32B32A32_SFLOAT, offsetof(FuseVertex, color));
+ rend_pipeline_config_resource_binding_add(ui_cfg, 0, 0, REND_BUFFER_UNIFORM, REND_SHADER_VERTEX, 1);
+
+ /* add the shaders */
+ rend_pipeline_config_shader_add(ui_cfg, vert);
+ rend_pipeline_config_shader_add(ui_cfg, frag);
+
+ RendPipeline ui_pipeline = rend_pipeline_create(renderer, ui_cfg);
+
+ RendResourceSet ui_resources = rend_resource_set_create(renderer, ui_pipeline, 0);
+
+ FuseCanvas canvas = fuse_canvas_create(1024, NULL);
+
+ u64 frame_t = NANOS_PER_SEC / 60;
+
+ bool running = true;
+ P_Event ev;
+ float pev = 0, px = 0, py = 0;
+
+ float nob = 0.3;
+
+ float target_screen[2] = { SCREEN_WIDTH, SCREEN_HEIGHT };
+ rend_resource_set_write_buffer(ui_resources, 0, REND_BUFFER_UNIFORM, target_screen, 2 * sizeof *target_screen, 0);
+
+ float real_screen_width = 0;
+ float real_screen_heigth = 0;
+
+ enum UI_State {
+ UI_START_MENU,
+ UI_OPTIONS,
+ };
+
+ int ui_state = UI_START_MENU;
+
+ while (running) {
+
+ u64 start = p_get_time();
+
+ pev = 0;
+ /* event loop */
+ while (p_window_poll_event(&window, &ev)) {
+ if (ev.type == P_EVENT_WINDOW_CLOSE) {
+ running = false;
+ break;
+ }
+
+ switch (ev.type) {
+ case P_EVENT_WINDOW_RESIZE:
+ real_screen_width = ev.resize.width;
+ real_screen_heigth = ev.resize.height;
+ break;
+ case P_EVENT_POINTER:
+ px = ev.pointer.x;
+ py = ev.pointer.y;
+ switch (ev.pointer.state) {
+ case P_POINTER_PRESSED:
+ if (ev.pointer.button == 1 || ev.pointer.button == 0)
+ pev = FUSE_POINTER_PRESSED;
+ break;
+ case P_POINTER_RELEASED:
+ if (ev.pointer.button == 1 || ev.pointer.button == 0)
+ pev = FUSE_POINTER_RELEASED;
+ break;
+ default:
+ case P_POINTER_MOVED:
+ break;
+ }
+
+ fuse_canvas_pointer(pev, px * SCREEN_WIDTH / real_screen_width, py * SCREEN_HEIGHT / real_screen_heigth);
+ break;
+ }
+ }
+
+ /* Clears the Screen */
+ fuse_canvas_clear(canvas, 0x000000);
+
+ /* Inside a div, children no longer have fixed positions,
+ * instead x, y represent an offset so that they can still be animated!
+ * Width and height represent min width and min height instead! */
+ if (ui_state == UI_START_MENU) {
+ // NOTE: brackets for legibility only
+ FUSE_LAYOUT_DIRECTION(FUSE_DIRECTION_COLUMN);
+ fuse_div_begin(0, 0, SCREEN_WIDTH / 4, SCREEN_HEIGHT, 0xFFFFFFaa);
+ {
+
+ fuse_hovered(stretch_button_op, data);
+
+ if (fuse_button_text("Start New Game", button_data.offset_x, 0, 100, 0, 0xFF0000FF, 0x000000FF)) {
+ printf("start new game");
+ }
+
+
+ if (fuse_button_text("Options", 0, 0, 100, 0, 0xFF0000FF, 0x000000FF)) {
+ ui_state = UI_OPTIONS;
+ }
+
+
+ if (fuse_button_text("Credits", 0, 0, 100, 0, 0xFF0000FF, 0x000000FF)) {
+ printf("awesome credits");
+ }
+
+ if (fuse_button_text("Quit Game")) {
+ running = false;
+ break;
+ }
+
+ fuse_hovered_clear();
+
+ }
+ fuse_div_end();
+
+ /* back to global layouting */
+ fuse_3d_object();
+ fuse_3d_point_at();
+
+
+ } else if (ui_state == UI_OPTIONS) {
+
+ /* Inside a flex the same x,y as offsets and width and height as minimums rules apply
+ * The difference is that a flex is flexible, by default it does not have a fixed size
+ * but you may specify minimums and maximus for it to work around.
+ */
+
+ FUSE(
+ .max_width = 300,
+ .max_height = 600,
+ .direction = FUSE_DIRECTION_COLUMN,
+ .gap = 32
+ );
+
+ fuse_flex_begin(0, 0, SCREEN_WIDTH / 4, SCREEN_HEIGHT, 0xFFFFFFaa);
+ {
+ if (fuse_checkbox_text("VSYNC", &vsync)) {
+ vsync = ~vsync;
+ }
+ }
+ }
+
+ fuse_slider(100, 200, 300, 600, 0xFFFF00FF, 0xFF0000FF, &nob);
+
+ fuse_canvas_draw(canvas, fuse_handler, NULL);
+
+ /* call renderer */
+ if (rend_renderer_frame_begin(renderer)) {
+ rend_pipeline_bind(ui_pipeline);
+ rend_resource_set_bind(ui_pipeline, 0, ui_resources);
+
+ rend_pipeline_push_data(ui_pipeline, fuse_renderer_data, fuse_renderer_idx, sizeof *fuse_renderer_data);
+ rend_pipeline_draw(ui_pipeline);
+
+ rend_renderer_frame_end(renderer, NULL);
+ }
+
+ fuse_renderer_idx = 0;
+
+ u64 elapsed = p_get_time() - start;
+
+ /* the renderer should already be forcing vsync */
+ if (elapsed < frame_t)
+ p_sleep_ns(frame_t - elapsed);
+ }
+
+
+ fuse_canvas_destroy(canvas);
+
+ rend_quit();
+
+ p_window_close(&window);
+ return 0;
+}
diff --git a/Fuse/fuse.c b/Fuse/fuse.c
new file mode 100644
index 0000000..401b06e
--- /dev/null
+++ b/Fuse/fuse.c
@@ -0,0 +1,436 @@
+#ifndef _FUSE_C_
+#define _FUSE_C_
+ /* __________________________________________________________________________
+ * | CmdType | CmdRect | CmdType | CmdRectBorder | ...
+ * --------------------------------------------------------------------------
+ */
+
+
+#include "fuse.h"
+#include "fuse_internal.h"
+#include "fuse_backend.h"
+
+#include "fuse_tween.c"
+
+#include "allocators.c"
+#include <stdint.h>
+#include <string.h>
+
+#define FUSE_MIN(a, b) ((a < b) ? a : b)
+#define FUSE_MAX(a, b) ((a > b) ? a : b)
+#define FUSE_LIMIT(n, a, b) (FUSE_MAX(a, FUSE_MIN(b, n)))
+#define FUSE_IS_HOVERED(x, y, w, h) (\
+ f__canvas->pointer_x >= x && f__canvas->pointer_x <= x + w &&\
+ f__canvas->pointer_y >= y && f__canvas->pointer_y <= y + h)
+
+static inline size_t fuse__element(); // "base class" of all UI widgets
+static inline void fuse__cmdbuffer_push(FuseCmd cmd);
+static void fuse__cmdbuffer_print();
+
+static const char* fuse__cmd_name(uint8_t type);
+
+extern FuseCanvas
+fuse_canvas_create(size_t memory_limit, FuseStyle base_style)
+{
+ (void) base_style;
+
+ FuseCanvas new = malloc(sizeof *new);
+ memset(new, 0, sizeof *new);
+
+ new->memory = malloc(memory_limit);
+
+ al_arena_create(&new->arena, new->memory, memory_limit);
+
+ size_t cmdbuffer_mem = (memory_limit * 8) / 10;
+ cmdbuffer_mem -= (cmdbuffer_mem % sizeof *new->cmdbuffer_ptr); // remove remainder
+
+ FuseCmd *cmdbuffer_ptr = al_arena_alloc(&new->arena, cmdbuffer_mem);
+ new->cmdbuffer_ptr = cmdbuffer_ptr;
+ new->cmdbuffer_size = cmdbuffer_mem / sizeof (*cmdbuffer_ptr);
+ new->cmdbuffer_head = 0;
+
+ size_t element_data_mem = memory_limit - cmdbuffer_mem;
+ void *element_data_ptr = al_arena_alloc(&new->arena, element_data_mem);
+
+ al_arena_create(&new->element_data_arena, element_data_ptr, element_data_mem);
+
+ fuse_canvas_set(new);
+ return new;
+}
+
+extern void
+fuse_canvas_set(FuseCanvas canvas)
+{
+ f__canvas = canvas;
+}
+
+extern void
+fuse_canvas_debug(FuseCanvas canvas, bool debug)
+{
+ canvas->debug = debug;
+}
+
+extern void
+fuse_canvas_clear(FuseCanvas canvas)
+{
+ canvas->cmdbuffer_head = 0;
+ canvas->current_id = 0;
+ canvas->current_frame++;
+}
+
+extern void
+fuse_canvas_draw(FuseCanvas canvas, FuseRendererCallback callback, void* data)
+{
+ for (size_t u = 0; u < f__canvas->cmdbuffer_head; u++) {
+ FuseCmd cmd = f__canvas->cmdbuffer_ptr[u];
+ assert(cmd.type < FUSE_CMD_COUNT && "[FUSE] WARN: INVALID TYPE IN COMMAND BUFFER");
+ callback(canvas, &cmd, data);
+ }
+}
+
+extern void
+fuse_canvas_resize(FuseCanvas canvas, float w, float h)
+{
+ canvas->width = w;
+ canvas->height = h;
+}
+
+extern void
+fuse_canvas_pointer(FuseCanvas canvas, int pointer_state, float x, float y)
+{
+ canvas->pointer_state = pointer_state;
+ canvas->pointer_x = x;
+ canvas->pointer_y = y;
+#ifdef FUSE_DEBUG
+ const char *pstate[] = {
+ [FUSE_POINTER_NONE] = "NONE",
+ [FUSE_POINTER_PRESSED] = "PRESSED",
+ [FUSE_POINTER_RELEASED] = "RELEASED",
+ [FUSE_POINTER_ALT] = "ALT"
+ };
+ printf("[DEBUG] [FUSE] px=%f py=%f ps=%s\n", canvas->pointer_x, canvas->pointer_y, pstate[pointer_state]);
+#endif
+}
+
+extern void
+fuse_canvas_destroy(FuseCanvas canvas)
+{
+ free(canvas->memory);
+ free(canvas);
+}
+
+extern bool
+fuse_button(float x, float y, float width, float height, uint32_t selected, uint32_t hovered)
+{
+ size_t id = fuse__element();
+ bool clicked = false;
+
+ bool hot = FUSE_IS_HOVERED(x, y, width, height);
+
+ if (hot) f__canvas->hot = id;
+
+ /* are we the active component? */
+ if (f__canvas->active == id) {
+ if (f__canvas->pointer_state == FUSE_POINTER_RELEASED) {
+ if (hot) clicked = true;
+ f__canvas->active = 0;
+ }
+ } else if (hot && f__canvas->pointer_state == FUSE_POINTER_PRESSED) {
+ f__canvas->active = id;
+ }
+
+ FuseCmd cmd = {
+ .type = FUSE_CMD_RECT,
+ .rect = {
+ .color = (hot) ? hovered : selected,
+ .x = x,
+ .y = y,
+ .w = width,
+ .h = height,
+ }
+ };
+
+ fuse__cmdbuffer_push(cmd);
+
+ return clicked;
+}
+
+extern void
+fuse_slider(float x, float y, float width, float height, uint32_t slider, uint32_t nob, float *nob_pos)
+{
+ size_t id = fuse__element();
+
+ /* are we the hot component? */
+ bool hot = FUSE_IS_HOVERED(x, y, width, height);
+
+ if (hot) f__canvas->hot = id;
+
+ bool is_vert = (width < height);
+ float nob_width = is_vert ? width : height;
+ float nob_height = is_vert ? width : height;
+ float track_len = is_vert ? (height - nob_height) : (width - nob_width);
+ float p_off = is_vert ? (f__canvas->pointer_y - (y + nob_height * 0.5f)) : (f__canvas->pointer_x - (x + nob_width * 0.5f));
+ float val = (track_len > 0.0f) ? (p_off / track_len) : 0.0f;
+
+ /* calculate nob_pos from pointer */
+ if (f__canvas->active == id) {
+ if (f__canvas->pointer_state == FUSE_POINTER_RELEASED) {
+ if (hot) { /* clicked */ }
+ f__canvas->active = 0;
+ }
+ *nob_pos = FUSE_MAX(0.0f, FUSE_MIN(1.0f, val));
+
+ } else if (hot && f__canvas->pointer_state == FUSE_POINTER_PRESSED) {
+ f__canvas->active = id;
+ *nob_pos = FUSE_MAX(0.0f, FUSE_MIN(1.0f, val));
+
+ }
+
+ /* clamp nob_pos */
+ *nob_pos = FUSE_LIMIT(*nob_pos, 0.0f, 1.0f);
+
+ float nob_x = is_vert ? 0.0f : (*nob_pos * (width - nob_width));
+ float nob_y = is_vert ? (*nob_pos * (height - nob_height)) : 0.0f;
+
+ FuseCmd cmd = {
+ .type = FUSE_CMD_RECT,
+ .rect = {
+ .color = slider,
+ .x = x,
+ .y = y,
+ .w = width,
+ .h = height,
+ }
+ };
+
+ FuseCmd nob_rect = {
+ .type = FUSE_CMD_RECT,
+ .rect = {
+ .color = nob,
+ .x = x + nob_x,
+ .y = y + nob_y,
+ .w = nob_width,
+ .h = nob_height,
+ }
+ };
+
+ fuse__cmdbuffer_push(cmd);
+ fuse__cmdbuffer_push(nob_rect);
+}
+
+extern int
+fuse_tooltip(const char *text)
+{
+ FUSE_TODO;
+ /* NOTE(vasco): this is supposed to add a tooltip when the last element was hovered...
+ * will probably need to grab the last element's box?
+ * I mean i need to know it's bounds and add an element that
+ * shows up after being hovered over a few frames
+ * so we will need to retain some data via the hashmap
+ *
+ * that's the plan for now
+ */
+ (void) text;
+}
+
+static inline size_t
+fuse__element()
+{
+ // we increment first because 0 is used for when no element is
+ // selected
+ size_t id = ++f__canvas->current_id;
+ return id;
+}
+
+static inline void
+fuse__cmdbuffer_push(FuseCmd cmd)
+{
+ if (f__canvas->cmdbuffer_head < f__canvas->cmdbuffer_size)
+ f__canvas->cmdbuffer_ptr[f__canvas->cmdbuffer_head++] = cmd;
+}
+
+static void
+fuse__cmdbuffer_print()
+{
+ for (size_t u = 0; u < f__canvas->cmdbuffer_head; u++) {
+ FuseCmd cmd = f__canvas->cmdbuffer_ptr[u];
+ assert(cmd.type < FUSE_CMD_COUNT && "[FUSE] WARN: INVALID TYPE IN COMMAND BUFFER");
+
+ printf("CMD: %s - ", fuse__cmd_name(cmd.type));
+ switch (cmd.type) {
+ case FUSE_CMD_RECT:
+ printf("x=%f y=%f w=%f h=%f col=%x", cmd.rect.x, cmd.rect.y, cmd.rect.w, cmd.rect.h, cmd.rect.color);
+ break;
+ }
+ printf("\n");
+ }
+}
+
+static const char*
+fuse__cmd_name(uint8_t type)
+{
+ assert(type < FUSE_CMD_COUNT);
+ return fuse_cmd_name[type];
+}
+
+
+extern bool
+fuse_button_text(const char *text, float x, float y, float width, float height, uint32_t selected, uint32_t hovered)
+{
+ (void) text; (void) x; (void) y; (void) width; (void) height; (void) selected; (void) hovered;
+ FUSE_TODO;
+ return false;
+}
+
+extern bool
+fuse_checkbox_text(const char *text, bool *value)
+{
+ (void) text; (void) value;
+ FUSE_TODO;
+ return false;
+}
+
+extern bool
+fuse_element_is_hovered(const char *text)
+{
+ (void) text;
+ FUSE_TODO;
+ return false;
+}
+
+extern void
+fuse_hovered(void (*op)(void*), void *data)
+{
+ (void) op; (void) data;
+ FUSE_TODO;
+}
+
+extern void
+fuse_hovered_clear()
+{
+ FUSE_TODO;
+}
+
+extern void
+fuse_rotate_rad()
+{
+ FUSE_TODO;
+}
+
+extern void
+fuse_rotate_deg()
+{
+ FUSE_TODO;
+}
+
+extern void
+fuse_layout(FuseLayoutInfo info)
+{
+ (void) info;
+ FUSE_TODO;
+}
+
+extern void
+fuse_div_begin(float x, float y, float width, float height, uint32_t color)
+{
+ (void) x; (void) y; (void) width; (void) height; (void) color;
+ FUSE_TODO;
+}
+
+extern void
+fuse_div_end()
+{
+ FUSE_TODO;
+}
+
+extern void
+fuse_flex_begin(float x, float y, float width, float height, uint32_t color)
+{
+ (void) x; (void) y; (void) width; (void) height; (void) color;
+ FUSE_TODO;
+}
+
+extern void
+fuse_flex_end()
+{
+ FUSE_TODO;
+}
+
+extern FuseStyle
+fuse_style_save(const char *path)
+{
+ (void) path;
+ FUSE_TODO;
+ return NULL;
+}
+
+extern void
+fuse_style_set(FuseStyle style)
+{
+ (void) style;
+ FUSE_TODO;
+}
+
+extern void
+fuse_style_load(const char *path)
+{
+ (void) path;
+ FUSE_TODO;
+}
+
+extern void
+fuse_window_begin(char *name, float width, float height, uint32_t border_color, uint32_t border_width)
+{
+ (void) name; (void) width; (void) height; (void) border_color; (void) border_width;
+ FUSE_TODO;
+}
+
+extern void
+fuse_window_end()
+{
+ FUSE_TODO;
+}
+
+extern void
+fuse_grid_begin(uint32_t cols, uint32_t rows, const float *col_ratios, const float *row_ratios)
+{
+ (void) cols; (void) rows; (void) col_ratios; (void) row_ratios;
+ FUSE_TODO;
+}
+
+extern void fuse_grid_next_row() { FUSE_TODO; }
+extern void fuse_grid_next_col() { FUSE_TODO; }
+extern void fuse_grid_prev_row() { FUSE_TODO; }
+extern void fuse_grid_prev_col() { FUSE_TODO; }
+extern void fuse_grid_next() { FUSE_TODO; }
+extern void fuse_grid_prev() { FUSE_TODO; }
+
+extern void
+fuse_grid_goto(uint32_t col, uint32_t row)
+{
+ (void) col; (void) row;
+ FUSE_TODO;
+}
+
+extern void fuse_grid_end() { FUSE_TODO; }
+
+extern void fuse_3d_object() { FUSE_TODO; }
+extern void fuse_3d_point_at() { FUSE_TODO; }
+
+extern int
+fuse_animate_i(FuseAnimation anim, int i1, int i2)
+{
+ (void) anim; (void) i1; (void) i2;
+ FUSE_TODO;
+ return 0;
+}
+
+extern float
+fuse_animate_f(FuseAnimation anim, float f1, float f2, float f, bool loop)
+{
+ (void) anim; (void) f1; (void) f2; (void) f; (void) loop;
+ FUSE_TODO;
+ return 0.0f;
+}
+
+#endif // _FUSE_C_
diff --git a/Fuse/fuse.h b/Fuse/fuse.h
new file mode 100644
index 0000000..9b1540e
--- /dev/null
+++ b/Fuse/fuse.h
@@ -0,0 +1,138 @@
+/* ===========================================================================
+ * FUSE - Zero Dependency UI Library - Copyright (c) 2025-2026 Vasco Alves
+ * See LICENCE file for license info.
+ *
+ * DESCRIPTION:
+ * A UI library that outputs a buffer of draw commands (or vertices) for
+ * you to render via a desired backend. By default all components have
+ * "fixed" positioning and fixed size because we assume the user has
+ * more knowledge of the final layout than we do. Tweening and relative
+ * positioning are achieved by running helper functions on the
+ * parameters you want to tween / be relative.
+ *
+ * EXAMPLE:
+ * float tween_y = fuse_tween_f(FUSE_ANIMATION_EASE_IN, 0.1, 0.3, 1, start);
+ * float rel_x = fuse_percent_x(30.45);
+ * if (fuse_button(rel_x, tween_y, 0.5, 0.3, 0xFFFF00FF, 0xFF0000FF)) {
+ * printf("pressed\n");
+ * }
+ *
+ * =========================================================================== */
+
+#ifndef _FUSE_H_
+#define _FUSE_H_
+
+#define FUSE_MAJOR "0"
+#define FUSE_MINOR "0"
+#define FUSE_PATCH "1"
+
+/* CHANGE LOG
+ * 0.0.1 - @vasco - slider
+ */
+
+
+#include <stdint.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "allocators.h"
+#include "fuse_backend.h"
+
+/* NOTE(vasco):
+ * It's important that we make the API really good and future-proof.
+ * Functions should take as many arguments as possible.
+ * We can add shorthands later.
+ */
+
+typedef struct fuse_canvas_t* FuseCanvas; // Basically the main context of each "surface" you want to draw on.
+typedef struct fuse_window_t* FuseWindow; // A floating window / panel to separate your UI.
+typedef struct fuse_font_t* FuseFont;
+typedef struct fuse_style_t* FuseStyle; // Configurable style for your application.
+typedef void(*FuseRendererCallback)(FuseCanvas, FuseCmd *cmd, void *data);
+typedef void(*FuseOpCallback)(void *data);
+
+typedef struct FuseLayoutInfo {
+ float min_width, min_height;
+ float max_width, max_height;
+ float gap;
+ uint8_t direction;
+} FuseLayoutInfo;
+
+typedef enum {
+ FUSE_ANIMATION_LINEAR = 0,
+ FUSE_ANIMATION_EASE_IN,
+ FUSE_ANIMATION_EASE_OUT
+} FuseAnimation;
+
+typedef enum {
+ FUSE_POINTER_NONE = 0,
+ FUSE_POINTER_RELEASED,
+ FUSE_POINTER_PRESSED,
+ FUSE_POINTER_ALT
+} FusePointerState;
+
+typedef enum {
+ FUSE_DIRECTION_ROW = 0,
+ FUSE_DIRECTION_COLUMN,
+} FuseDirection;
+
+/* canvas creation and drawing */
+extern FuseCanvas fuse_canvas_create(size_t memory_limit, FuseStyle base_style); // Canvas initialization. Contains all the context needed to draws. Doesn't care about what you're drawing to since the library emits normalizer coordinates.
+extern void fuse_canvas_set(FuseCanvas); // Changes the canvas that the rest of the API outputs to by default. Normally you will only be drawing to a single instance at a time.
+extern void fuse_canvas_debug(FuseCanvas, bool); // Enable debugging for a specific canvas.
+extern void fuse_canvas_clear(FuseCanvas canvas); // Clears canvas to begin drawing the next frame.
+extern void fuse_canvas_draw(FuseCanvas, FuseRendererCallback, void* data); // Sends all the draw commands to the renderer callback function.
+extern void fuse_canvas_resize(FuseCanvas, float w, float h); // Updates the width and height of the active canvas.
+extern void fuse_canvas_pointer(FuseCanvas, int pointer_state, float x, float y); // Update pointer state on active canvas.
+extern void fuse_canvas_destroy(FuseCanvas); // Clear all the context and free all the memory.
+
+/* components */
+extern bool fuse_button(float x, float y, float width, float height, uint32_t selected, uint32_t hovered); // Base button component. Returns true if clicked on that frame.
+extern void fuse_slider(float x, float y, float width, float height, uint32_t slider, uint32_t nob, float *nob_pos);
+extern bool fuse_button_text(const char *text, float x, float y, float width, float height, uint32_t selected, uint32_t hovered);
+extern bool fuse_checkbox_text(const char *text, bool *value);
+
+/* conditionals */
+extern bool fuse_element_is_hovered(const char *text);
+
+/* hover callbacks */
+extern void fuse_hovered(void (*op)(void*), void *data); // Register hover callback for subsequent elements.
+extern void fuse_hovered_clear(); // Clear hover callback.
+
+
+/* operations */
+extern int fuse_tooltip(const char *text); // Adds tooltip to the NEXT element.
+extern void fuse_rotate_rad(); // Rotate next element by x radians
+extern void fuse_rotate_deg(); // Rotate next element by x degrees.
+extern float fuse_percent_x(float p); // Get percentage of width of the parent. Left of the secreen is 0%.
+extern float fuse_percent_y(float p); // Get percentage of height of the screen. Top of the screen is 0%.
+extern float fuse_tween_f(FuseAnimation anim, float f1, float f2, float duration, uint64_t time_ns); // Interpolates between floats. Takes in the animation duration in seconds and the current time in nanoseconds.
+extern int fuse_tween_i(FuseAnimation anim, int i1, int i2, float duration, uint64_t time_ns); // Interpolates between integers. Takes in the animation duration in seconds and the current time in nanoseconds.
+extern uint32_t fuse_tween_color(FuseAnimation anim, uint32_t c1, uint32_t c2, float duration, uint64_t time_ns); // Interpolates between colors. Takes in the animation duration in seconds and the current time in nanoseconds.
+
+/* layouting */
+#define FUSE(...) fuse_layout((FuseLayoutInfo){ __VA_ARGS__ })
+#define FUSE_LAYOUT_DIRECTION(dir) fuse_layout((FuseLayoutInfo){ .direction = (dir) })
+extern void fuse_layout(FuseLayoutInfo);
+extern void fuse_div_begin(float x, float y, float width, float height, uint32_t color);
+extern void fuse_div_end();
+extern void fuse_flex_begin(float x, float y, float width, float height, uint32_t color);
+extern void fuse_flex_end();
+
+/* 3d */
+extern void fuse_3d_object();
+extern void fuse_3d_point_at();
+
+/* do we need this? im pretty sure the user can figure it out by using a step function
+ * you know like the Heaviside step function u(t) where u(t) = 1, t >= 0, u(t) = 0 otherwise
+ *
+ * animation function a(t) = f(t - t0) * (u(t1) - u(t0))
+ *
+ * in fact we already have the tween functions, all we need it u(t) and boom
+ */
+extern int fuse_animate_i(FuseAnimation, int i1, int i2);
+extern float fuse_animate_f(FuseAnimation, float f1, float f2, float f, bool loop);
+
+
+#endif // _FUSE_H_
diff --git a/Fuse/fuse_backend.h b/Fuse/fuse_backend.h
new file mode 100644
index 0000000..57f9f80
--- /dev/null
+++ b/Fuse/fuse_backend.h
@@ -0,0 +1,42 @@
+#ifndef FUSE_BACKEND_H
+#define FUSE_BACKEND_H
+
+typedef enum {
+ FUSE_CMD_CLIP = 0,
+ FUSE_CMD_RECT,
+ FUSE_CMD_LINE,
+ FUSE_CMD_COUNT
+} FuseCmdType;
+
+typedef struct {
+ float x, y, w, h;
+} FuseClip;
+
+typedef struct {
+ float x, y, w, h;
+ uint32_t color;
+} FuseRect;
+
+typedef struct {
+ float x1, y1, x2, y2;
+ float thickness;
+ uint32_t color;
+} FuseLine;
+
+typedef struct {
+ union {
+ FuseClip clip;
+ FuseRect rect;
+ FuseLine line;
+ };
+ uint8_t type;
+} FuseCmd;
+
+
+static const char* fuse_cmd_name[] = {
+ [FUSE_CMD_RECT] = "RECT",
+ [FUSE_CMD_CLIP] = "CLIP",
+ [FUSE_CMD_LINE] = "LINE",
+};
+
+#endif
diff --git a/Fuse/fuse_backend_rend.c b/Fuse/fuse_backend_rend.c
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/Fuse/fuse_backend_rend.c
diff --git a/Fuse/fuse_components.c b/Fuse/fuse_components.c
new file mode 100644
index 0000000..22cc394
--- /dev/null
+++ b/Fuse/fuse_components.c
@@ -0,0 +1,3 @@
+#pragma once
+#include "fuse.h"
+
diff --git a/Fuse/fuse_hash.c b/Fuse/fuse_hash.c
new file mode 100644
index 0000000..666915b
--- /dev/null
+++ b/Fuse/fuse_hash.c
@@ -0,0 +1,2 @@
+#pragma once
+#include "fuse_internal.h" \ No newline at end of file
diff --git a/Fuse/fuse_internal.h b/Fuse/fuse_internal.h
new file mode 100644
index 0000000..31fe702
--- /dev/null
+++ b/Fuse/fuse_internal.h
@@ -0,0 +1,63 @@
+#ifndef FUSE_INTERNAL_H
+#define FUSE_INTERNAL_H
+
+#include "fuse.h"
+#include "fuse_backend.h"
+
+#define FUSE_TODO \
+ do { \
+ fprintf(stderr, "FUSE TODO: %s() in %s:%d\n", __func__, __FILE__, __LINE__); \
+ abort(); \
+ } while(0)
+
+
+typedef struct {
+ void *data;
+ size_t idk;
+} FuseHash;
+
+struct fuse_canvas_t {
+ void *memory; // memory pointer to be slit into separate arenas
+ Arena arena; // arena the manages all our memory and will be split into smaller arenas
+
+ FuseCmd *cmdbuffer_ptr;
+
+ Arena element_data_arena;
+ FuseHash element_data; // persistent element data
+
+ size_t cmdbuffer_head;
+ size_t cmdbuffer_size;
+
+ size_t hot;
+ size_t active;
+
+ size_t current_frame;
+ size_t current_id;
+
+ float width;
+ float height;
+
+ float pointer_x;
+ float pointer_y;
+
+ uint64_t current_time_ns;
+
+ int pointer_state;
+
+ bool debug;
+};
+
+struct fuse_font_t {
+ int x;
+};
+
+struct fuse_style_t {
+ int x;
+};
+struct fuse_window_t {
+ int x;
+};
+
+static FuseCanvas f__canvas;
+
+#endif
diff --git a/Fuse/fuse_positioning.c b/Fuse/fuse_positioning.c
new file mode 100644
index 0000000..3f22a0e
--- /dev/null
+++ b/Fuse/fuse_positioning.c
@@ -0,0 +1,14 @@
+#pragma once
+#include "fuse_internal.h"
+
+extern float
+fuse_percent_x(float p)
+{
+ return p * f__canvas->width / 100;
+}
+
+extern float
+fuse_percent_y(float p)
+{
+ return p * f__canvas->height / 100;
+}
diff --git a/Fuse/fuse_test b/Fuse/fuse_test
new file mode 100755
index 0000000..2188db0
--- /dev/null
+++ b/Fuse/fuse_test
Binary files differ
diff --git a/Fuse/fuse_test.c b/Fuse/fuse_test.c
new file mode 100644
index 0000000..a4b383d
--- /dev/null
+++ b/Fuse/fuse_test.c
@@ -0,0 +1,25 @@
+#define FUSE_DEBUG
+#include "fuse.h"
+#include "fuse.c"
+
+#include "allocators.c"
+#include <stdio.h>
+
+float nob = 0.5;
+int main() {
+
+ FuseCanvas canvas = fuse_canvas_create(1024, NULL); /* lowk 1kb enough? */
+
+ fuse_canvas_clear(canvas, 400, 400, FUSE_POINTER_RELEASED, 50, 50);
+
+ if (fuse_button(0, 0, 100, 100, 0xFF00FF, 0xFF0000)) {
+ printf("pressed\n");
+ }
+
+ fuse_slider(0, 0, 100, 100, 0xFF00FF, 0xFF0000, &nob);
+
+ fuse__cmdbuffer_print();
+
+ fuse_canvas_destroy(canvas);
+ return 0;
+}
diff --git a/Fuse/fuse_tween.c b/Fuse/fuse_tween.c
new file mode 100644
index 0000000..2b47f41
--- /dev/null
+++ b/Fuse/fuse_tween.c
@@ -0,0 +1,68 @@
+#pragma once
+
+#include "fuse.h"
+#include "fuse_internal.h"
+
+static inline float
+fuse__get_coef(FuseAnimation anim, float t)
+{
+ switch (anim) {
+ case FUSE_ANIMATION_EASE_IN: return t * t;
+ case FUSE_ANIMATION_EASE_OUT: return t * (2.0f - t);
+ case FUSE_ANIMATION_LINEAR:
+ default: return t;
+ }
+}
+
+static inline float
+fuse__ping_pong(float duration_sec, uint64_t time_ns)
+{
+ if (duration_sec <= 0.0f) return 1.0f;
+
+ uint64_t duration_ns = (uint64_t)(duration_sec * 1000000000.0f);
+
+ // modulo against DOUBLE the duration to handle reversing
+ uint64_t loop_time_ns = time_ns % (duration_ns * 2);
+
+ // in the second half REVERSE the clock direction
+ if (loop_time_ns > duration_ns) {
+ loop_time_ns = (duration_ns * 2) - loop_time_ns;
+ }
+
+ return (float)loop_time_ns / (float)duration_ns;
+}
+
+extern float
+fuse_tween_f(FuseAnimation anim, float f1, float f2, float duration, uint64_t time_ns)
+{
+ float t = fuse__ping_pong(duration, time_ns);
+ float coef = fuse__get_coef(anim, t);
+ return f1 + coef * (f2 - f1);
+}
+
+extern int
+fuse_tween_i(FuseAnimation anim, int i1, int i2, float duration, uint64_t time_ns)
+{
+ float t = fuse__ping_pong(duration, time_ns);
+ float coef = fuse__get_coef(anim, t);
+ return (int)(i1 + coef * (i2 - i1));
+}
+
+extern uint32_t
+fuse_tween_color(FuseAnimation anim, uint32_t c1, uint32_t c2, float duration, uint64_t time_ns)
+{
+ float t = fuse__ping_pong(duration, time_ns);
+ float coef = fuse__get_coef(anim, t);
+
+ int r1 = (c1 >> 24) & 0xFF, r2 = (c2 >> 24) & 0xFF;
+ int g1 = (c1 >> 16) & 0xFF, g2 = (c2 >> 16) & 0xFF;
+ int b1 = (c1 >> 8) & 0xFF, b2 = (c2 >> 8) & 0xFF;
+ int a1 = c1 & 0xFF, a2 = c2 & 0xFF;
+
+ uint32_t r = (uint32_t)(r1 + coef * (r2 - r1));
+ uint32_t g = (uint32_t)(g1 + coef * (g2 - g1));
+ uint32_t b = (uint32_t)(b1 + coef * (b2 - b1));
+ uint32_t a = (uint32_t)(a1 + coef * (a2 - a1));
+
+ return (r << 24) | (g << 16) | (b << 8) | a;
+}
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..1910a7a
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,39 @@
+------------------------------------------------------------------------------
+This software is available under 2 licenses -- choose whichever you prefer.
+------------------------------------------------------------------------------
+ALTERNATIVE A - MIT License
+Copyright (c) 2026 Vasco Alves
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+of the Software, and to permit persons to whom the Software is furnished to do
+so, subject to the following conditions:
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+------------------------------------------------------------------------------
+ALTERNATIVE B - Public Domain (www.unlicense.org)
+This is free and unencumbered software released into the public domain.
+Anyone is free to copy, modify, publish, use, compile, sell, or distribute this
+software, either in source code form or as a compiled binary, for any purpose,
+commercial or non-commercial, and by any means.
+In jurisdictions that recognize copyright laws, the author or authors of this
+software dedicate any and all copyright interest in the software to the public
+domain. We make this dedication for the benefit of the public at large and to
+the detriment of our heirs and successors. We intend this dedication to be an
+overt act of relinquishment in perpetuity of all present and future rights to
+this software under copyright law.
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+------------------------------------------------------------------------------
diff --git a/Peak/README.md b/Peak/README.md
new file mode 100644
index 0000000..ce16444
--- /dev/null
+++ b/Peak/README.md
@@ -0,0 +1,3 @@
+Single file platform library.
+
+MIT or Public Domain License.
diff --git a/Peak/demos/demo.c b/Peak/demos/demo.c
new file mode 100644
index 0000000..7aec9b3
--- /dev/null
+++ b/Peak/demos/demo.c
@@ -0,0 +1,65 @@
+#include <stdio.h>
+#include <math.h>
+#include <unistd.h>
+
+#define PEAK_IMPLEMENTATION
+#include "../peak.h"
+
+
+void print_window_resize(PeakEvent ev) {
+ printf("window: %u %u\n", ev.resize.width, ev.resize.height);
+}
+
+void print_window_close(PeakEvent ev) {
+ printf("WINDOW CLOSE!!!!!!\nWOWWWOWAAAAAAAAAAAAAAAAAAAAAAAAh\n");
+}
+
+void print_mouse(PeakEvent ev) {
+ printf("mouse: state=%d type=%d pos=(%f, %f)\n", ev.pointer.state, ev.pointer.type, ev.pointer.x, ev.pointer.y);
+}
+
+void print_key(PeakEvent ev) {
+ printf("key: key=%d mod=%d\n", ev.key.key, ev.key.mod);
+}
+
+typedef void (*print_event_func)(PeakEvent ev);
+print_event_func print_event[PEAK_EVENT_LAST] = {
+ [PEAK_EVENT_NONE] = print_mouse,
+ [PEAK_EVENT_WINDOW_RESIZE] = print_window_resize,
+ [PEAK_EVENT_WINDOW_CLOSE] = print_window_close,
+ [PEAK_EVENT_POINTER] = print_mouse,
+ [PEAK_EVENT_POINTER_CONNECTED] = print_mouse,
+ [PEAK_EVENT_POINTER_DISCONNECTED] = print_mouse,
+ [PEAK_EVENT_KEY_DOWN] = print_key,
+ [PEAK_EVENT_KEY_UP] = print_key,
+};
+
+
+typedef struct {
+ char *msg;
+} AppData;
+
+static AppData data;
+
+int main(int argc, char**argv) {
+ peak_init();
+ int running = 1000000;
+ PeakEvent ev;
+ data.msg = "hello world";
+ while (running--) {
+ while (peak_poll_events(&ev)) {
+ if (ev.type == PEAK_EVENT_NONE)
+ continue;
+ print_event[ev.type](ev);
+ switch (ev.type) {
+ case PEAK_EVENT_WINDOW_CLOSE:
+ printf("STOPPPPEEED\n");
+ return 1;
+ }
+ }
+ // printf("frame: %d - %s\n", running, data.msg);
+ }
+ peak_quit();
+ return 0;
+}
+
diff --git a/Peak/demos/demo_replace_main.c b/Peak/demos/demo_replace_main.c
new file mode 100644
index 0000000..3aedfaa
--- /dev/null
+++ b/Peak/demos/demo_replace_main.c
@@ -0,0 +1,67 @@
+#include <stdio.h>
+#include <math.h>
+#include <unistd.h>
+
+#define PEAK_REPLACE_MAIN
+#define PEAK_IMPLEMENTATION
+#include "../peak.h"
+
+
+void print_window_resize(PeakEvent ev) {
+ printf("window: %u %u\n", ev.resize.width, ev.resize.height);
+}
+
+void print_window_close(PeakEvent ev) {
+ printf("WINDOW CLOSE!!!!!!\nWOWWWOWAAAAAAAAAAAAAAAAAAAAAAAAh\n");
+}
+
+void print_mouse(PeakEvent ev) {
+ printf("mouse: state=%d type=%d pos=(%f, %f)\n", ev.pointer.state, ev.pointer.type, ev.pointer.x, ev.pointer.y);
+}
+
+void print_key(PeakEvent ev) {
+ printf("key: key=%d mod=%d\n", ev.key.key, ev.key.mod);
+}
+
+typedef void (*print_event_func)(PeakEvent ev);
+print_event_func print_event[PEAK_EVENT_LAST] = {
+ [PEAK_EVENT_NONE] = print_mouse,
+ [PEAK_EVENT_WINDOW_RESIZE] = print_window_resize,
+ [PEAK_EVENT_WINDOW_CLOSE] = print_window_close,
+ [PEAK_EVENT_POINTER] = print_mouse,
+ [PEAK_EVENT_POINTER_CONNECTED] = print_mouse,
+ [PEAK_EVENT_POINTER_DISCONNECTED] = print_mouse,
+ [PEAK_EVENT_KEY_DOWN] = print_key,
+ [PEAK_EVENT_KEY_UP] = print_key,
+};
+
+
+typedef struct {
+ char *msg;
+} AppData;
+
+static AppData data;
+
+int main(int argc, char**argv) {
+ data.msg = "Hello World";
+ return PEAK_CONTINUE;
+}
+
+void
+peak_events(PeakEvent ev)
+{
+ print_event[ev.type](ev);
+ switch (ev.type) {
+ case PEAK_EVENT_WINDOW_CLOSE:
+ printf("stoppppeeed\n");
+ peak_stop();
+ break;
+ }
+}
+
+void
+peak_tick()
+{
+ printf("%s\n",data.msg);
+ sleep(1);
+}
diff --git a/Peak/peak.h b/Peak/peak.h
new file mode 100644
index 0000000..581aa74
--- /dev/null
+++ b/Peak/peak.h
@@ -0,0 +1,895 @@
+/* ===========================================================================
+ * PEAK - Copyright @ Vasco Alves - See LICENSE at the end of file.
+ *
+ * Platform layer.
+ * It just works, don't think about it too much.
+ *
+ * =========================================================================== */
+
+#ifndef PEAK_H
+#define PEAK_H
+
+#define PEAK_MAJOR "0"
+#define PEAK_MINOR "1"
+#define PEAK_PATCH "1"
+
+/* CHANGE LOG
+ * 0.0.0 - @vasco - prototyping
+ * 0.1.0 - @vasco - linux x11 that automagically loads X11 DLL
+ * 0.1.1 - @vasco - fixed event handling on linux
+ *
+ * TODO: demo that stress tests the whole API
+ */
+
+#include <assert.h>
+#include <stdarg.h>
+#include <stdint.h>
+#include <stddef.h>
+#include <stdbool.h>
+
+#if !( \
+ (defined(__STDC__) && __STDC__ == 1 && defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L)\
+)
+#error "Peak requires C99."
+#endif
+
+/*
+ * Detecting a platform does not mean it's supported.
+ * Feel free to use these macros if you need them.
+ */
+#if defined(__wasm__) || defined(__wasm32__) || defined(__wasm64__) || defined(__EMSCRIPTEN__)
+ #define PEAK_WEB
+#elif defined(_WIN32) || defined(_WIN64) || defined(__WIN32__) || defined(__TOS_WIN__)
+ #define PEAK_WIN32
+ #ifndef WIN32_LEAN_AND_MEAN
+ #define WIN32_LEAN_AND_MEAN
+ #endif
+#elif defined(__APPLE__) || defined(__MACH__)
+ #include <TargetConditionals.h>
+ #define PEAK_APPLE
+ #if TARGET_OS_IPHONE
+ #define PEAK_IOS
+ #else
+ #define PEAK_MACOS
+ #endif
+#elif defined(__linux__)
+ #define PEAK_LINUX
+#elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__bsdi__) || defined(__DragonFly__)
+ #define PEAK_BSD
+#elif defined(__ANDROID__)
+ #define PEAK_ANDROID
+ #define PEAK_LINUX
+#elif defined(__linux__)
+ #define PEAK_LINUX
+#endif
+
+#if defined(PEAK_LINUX) || defined(PEAK_BSD) || defined(PEAK_APPLE)
+ #define PEAK_UNIX
+ #if !defined(PEAK_APPLE) && !defined(_POSIX_C_SOURCE)
+ #define _POSIX_C_SOURCE 200112L
+ #endif
+#endif
+
+#ifdef PEAK_WEB
+ #define PEAK static inline
+#else
+ #define PEAK extern
+#endif
+
+typedef enum {
+ PEAK_KEYMOD_ALT = 0,
+ PEAK_KEYMOD_SHIFT,
+ PEAK_KEYMOD_CTRL,
+ PEAK_KEYMOD_CAPS,
+} PeakKeyMod;
+
+typedef enum {
+ PEAK_KEY_UNKNOWN = 0,
+ PEAK_KEY_UP, PEAK_KEY_DOWN, PEAK_KEY_LEFT, PEAK_KEY_RIGHT,
+ PEAK_KEY_SPACE, PEAK_KEY_ESCAPE, PEAK_KEY_ENTER,
+ PEAK_KEY_A, PEAK_KEY_B, PEAK_KEY_C, PEAK_KEY_D, PEAK_KEY_E, PEAK_KEY_F, PEAK_KEY_G, PEAK_KEY_H, PEAK_KEY_I,
+ PEAK_KEY_J, PEAK_KEY_K, PEAK_KEY_L, PEAK_KEY_M, PEAK_KEY_N, PEAK_KEY_O, PEAK_KEY_P, PEAK_KEY_Q, PEAK_KEY_R,
+ PEAK_KEY_S, PEAK_KEY_T, PEAK_KEY_U, PEAK_KEY_V, PEAK_KEY_W, PEAK_KEY_X, PEAK_KEY_Y, PEAK_KEY_Z,
+} PeakKeyCode;
+
+typedef enum {
+ PEAK_EVENT_NONE = 0,
+ PEAK_EVENT_KEY_DOWN,
+ PEAK_EVENT_KEY_UP,
+ PEAK_EVENT_WINDOW_CLOSE,
+ PEAK_EVENT_WINDOW_RESIZE,
+ PEAK_EVENT_POINTER,
+ PEAK_EVENT_POINTER_CONNECTED,
+ PEAK_EVENT_POINTER_DISCONNECTED,
+ PEAK_EVENT_LAST
+} PeakEvenType;
+
+typedef enum {
+ PEAK_POINTER_MOVED = 0,
+ PEAK_POINTER_PRESSED,
+ PEAK_POINTER_RELEASED
+} PeakPointerState;
+
+typedef enum {
+ PEAK_POINTER_LEFT = 0,
+ PEAK_POINTER_RIGHT,
+ PEAK_POINTER_MIDDLE,
+ PEAK_POINTER_TOUCH,
+} PeakPointerType;
+
+typedef struct {
+ PeakEvenType type;
+ union {
+ struct { PeakKeyCode key; PeakKeyMod mod; } key;
+ struct { uint32_t width, height; } resize;
+ struct { PeakPointerState state; PeakPointerType type; float x, y; } pointer;
+ };
+} PeakEvent;
+
+/* Public API */
+PEAK void peak_init(void); // open a window and initialize graphics. called automatically if using peak_setup().
+PEAK void peak_quit(void); // close the window and release resources. called automatically if using peak_setup().
+PEAK bool peak_poll_events(PeakEvent *ev); // Poll the next event from the window queue. Returns true if an event was retrieved.
+PEAK void peak_extensions(void); // retrieve gpu window surface extensions for native api access (e.g., vulkan/opengl).
+PEAK void peak_blit(int offset_x, int offset_y, const uint32_t *rgba, size_t width, size_t height); // blit rgba pixels to the screen.
+PEAK void peak_clip(int x, int y, size_t w, size_t h); // restrict all subsequent rendering operations to this bounding rectangle.
+PEAK void peak_clip_reset(void); // reset clipping plane to window size.
+PEAK void peak_draw_rectangle(int x, int y, size_t w, size_t h, uint32_t color); // draw a solid-color filled rectangle.
+PEAK void peak_draw_rectangle_gradient(int x, int y, size_t w, size_t h, uint32_t c0, uint32_t c1, uint32_t c2, uint32_t c3); // fill rectangle interpolating four corner colors in clock-wise order.
+PEAK void peak_draw_triangle(int x0, int y0, int x1, int y1, int x2, int y2, uint32_t color); // draw a solid-color filled triangle.
+PEAK void peak_draw_triangle_gradient(int x0, int y0, int x1, int y1, int x2, int y2, uint32_t c0, uint32_t c1, uint32_t c2); // fill triangle with color interpolation clock-wise across its three vertices.
+PEAK void peak_draw_line(int x0, int y0, int x1, int y1, size_t width, uint32_t color); // draw a line between two points.
+PEAK void peak_draw_line_gradient(int x0, int y0, int x1, int y1, size_t width, uint32_t c0, uint32_t c1); // draw a line with a color gradient.
+
+/* Implemented by the platform */
+PEAK void peak_platform_window_open();
+PEAK void peak_platform_window_close();
+PEAK uint32_t *peak_platform_window_buffer(size_t *width, size_t *height);
+PEAK bool peak_platform_epoll(PeakEvent *ev);
+
+/*
+ * He was wipping up amazing foods, like making happiness.
+ * Actual happiness?
+ * Actual happiness and joy.
+ * Oh the smell, it was so divine.
+ * He was making happiness!?
+ * Happiness in the kettle!
+ */
+#ifdef PEAK_REPLACE_MAIN
+enum PeakReturn { PEAK_CONTINUE = 0, PEAK_STOP = 1 };
+extern int peak__main(int argc, char**argv);
+extern void peak_events(PeakEvent ev);
+extern void peak_tick();
+static bool running = true;
+static inline void peak_stop() { running = false; }
+#ifndef PEAK_WEB
+#define main(...)\
+main(int argc, char **argv) {\
+ assert(peak_events != 0 && "Declare peak_events() to handle window events.");\
+ assert(peak_tick != 0 && "Declare peak_tick() to handle each frame ticks.");\
+ peak_init();\
+ int ret = peak__main(argc, argv);\
+ if (ret != PEAK_CONTINUE) return ret;\
+ PeakEvent ev;\
+ while (running) {\
+ while (running && peak_poll_events(&ev)) {\
+ peak_events(ev);\
+ }\
+ peak_tick();\
+ }\
+ peak_quit();\
+}\
+int peak__main(__VA_ARGS__)
+#else
+#include <emscripten.h>
+/*
+ * He was wipping up agony in the kettle.
+ * Actual pain?
+ * Boiling hatred in the kettle.
+ * The smell, it's pain.
+ * Boiling anger!?
+ * Yes, boiling anger.
+ */
+
+static inline void
+peak__emscripten_loop_step(void *arg)
+{
+ (void)arg;
+ PeakEvent ev;
+ while (peak_poll_events(&ev)) {
+ peak_events(ev);
+ }
+
+ if (running) {
+ peak_tick();
+ } else {
+ emscripten_cancel_main_loop();
+ peak_quit();
+ }
+}
+
+#define main(...)\
+ main(int argc, char **argv) {\
+ _Static_assert(peak_events != 0, "When using peak_setup, declare peak_events() to handle window events.");\
+ _Static_assert(peak_tick != 0, "When using peak_setup, declare peak_tick() to handle frame ticks.");\
+ peak_init();\
+ int ret = peak__main(argc, argv);\
+ if (ret != PEAK_CONTINUE) return ret;\
+ emscripten_set_main_loop_arg(peak__emscripten_loop_step, NULL, 0, 1);\
+ return 0;\
+ }\
+ int peak__main(__VA_ARGS__)
+#endif
+#endif // PEAK_DONT_REPLACE_MAIN
+
+#endif // PEAK_H
+
+#ifdef PEAK_IMPLEMENTATION
+#undef PEAK_IMPLEMENTATION
+
+#if defined(PEAK_WIN32)
+/* --- Start of p_win32.c --- */
+#include <windows.h>
+
+void
+peak_platform_window_open()
+{
+}
+
+void
+peak_platform_window_close()
+{
+}
+
+uint32_t*
+peak_platform_window_buffer(size_t *width, size_t *height)
+{
+}
+
+bool
+peak_platform_epoll(PeakEvent *ev)
+{
+}
+/* --- End of p_win32.c --- */
+#elif defined(PEAK_LINUX)
+/* --- Start of p_linux.c --- */
+#include <dlfcn.h>
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+#include <X11/Xatom.h>
+#include <X11/keysym.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define PEAK_X11_LINUX "/usr/lib/libX11.so.6"
+
+#define PEAK_LINUX_DEFAULT_WIDTH 800
+#define PEAK_LINUX_DEFAULT_HEIGHT 600
+
+typedef Display* (*XOpenDisplay_t)(const char*);
+typedef int (*XCloseDisplay_t)(Display*);
+typedef Window (*XCreateSimpleWindow_t)(Display*, Window, int, int, unsigned int, unsigned int, unsigned int, unsigned long, unsigned long);
+typedef int (*XStoreName_t)(Display*, Window, const char*);
+typedef Atom (*XInternAtom_t)(Display*, const char*, Bool);
+typedef Status (*XSetWMProtocols_t)(Display*, Window, Atom*, int);
+typedef int (*XSelectInput_t)(Display*, Window, long);
+typedef GC (*XCreateGC_t)(Display*, Window, unsigned long, XGCValues*);
+typedef XImage* (*XCreateImage_t)(Display*, Visual*, unsigned int, int, int, char*, unsigned int, unsigned int, int, int);
+typedef int (*XMapRaised_t)(Display*, Window);
+typedef int (*XFlush_t)(Display*);
+typedef int (*XFreeGC_t)(Display*, GC);
+typedef int (*XDestroyWindow_t)(Display*, Window);
+typedef int (*XPending_t)(Display*);
+typedef int (*XNextEvent_t)(Display*, XEvent*);
+typedef KeySym (*XLookupKeysym_t)(XKeyEvent*, int);
+typedef int (*XPutImage_t)(Display*, Drawable, GC, XImage*, int, int, int, int, unsigned int, unsigned int);
+typedef int (*XDefaultScreen_t)(Display*);
+typedef Window (*XRootWindow_t)(Display*, int);
+typedef unsigned long (*XBlackPixel_t)(Display*, int);
+typedef Visual* (*XDefaultVisual_t)(Display*, int);
+typedef int (*XDefaultDepth_t)(Display*, int);
+
+typedef struct {
+ XOpenDisplay_t XOpenDisplay;
+ XCloseDisplay_t XCloseDisplay;
+ XCreateSimpleWindow_t XCreateSimpleWindow;
+ XStoreName_t XStoreName;
+ XInternAtom_t XInternAtom;
+ XSetWMProtocols_t XSetWMProtocols;
+ XSelectInput_t XSelectInput;
+ XCreateGC_t XCreateGC;
+ XCreateImage_t XCreateImage;
+ XMapRaised_t XMapRaised;
+ XFlush_t XFlush;
+ XFreeGC_t XFreeGC;
+ XDestroyWindow_t XDestroyWindow;
+ XPending_t XPending;
+ XNextEvent_t XNextEvent;
+ XLookupKeysym_t XLookupKeysym;
+ XPutImage_t XPutImage;
+ XDefaultScreen_t XDefaultScreen;
+ XRootWindow_t XRootWindow;
+ XBlackPixel_t XBlackPixel;
+ XDefaultVisual_t XDefaultVisual;
+ XDefaultDepth_t XDefaultDepth;
+} PeakX11Api;
+
+static PeakX11Api peak_x11;
+
+static int peak_load_x11(void *handle) {
+ peak_x11.XOpenDisplay = (XOpenDisplay_t)dlsym(handle, "XOpenDisplay");
+ peak_x11.XCloseDisplay = (XCloseDisplay_t)dlsym(handle, "XCloseDisplay");
+ peak_x11.XCreateSimpleWindow = (XCreateSimpleWindow_t)dlsym(handle, "XCreateSimpleWindow");
+ peak_x11.XStoreName = (XStoreName_t)dlsym(handle, "XStoreName");
+ peak_x11.XInternAtom = (XInternAtom_t)dlsym(handle, "XInternAtom");
+ peak_x11.XSetWMProtocols = (XSetWMProtocols_t)dlsym(handle, "XSetWMProtocols");
+ peak_x11.XSelectInput = (XSelectInput_t)dlsym(handle, "XSelectInput");
+ peak_x11.XCreateGC = (XCreateGC_t)dlsym(handle, "XCreateGC");
+ peak_x11.XCreateImage = (XCreateImage_t)dlsym(handle, "XCreateImage");
+ peak_x11.XMapRaised = (XMapRaised_t)dlsym(handle, "XMapRaised");
+ peak_x11.XFlush = (XFlush_t)dlsym(handle, "XFlush");
+ peak_x11.XFreeGC = (XFreeGC_t)dlsym(handle, "XFreeGC");
+ peak_x11.XDestroyWindow = (XDestroyWindow_t)dlsym(handle, "XDestroyWindow");
+ peak_x11.XPending = (XPending_t)dlsym(handle, "XPending");
+ peak_x11.XNextEvent = (XNextEvent_t)dlsym(handle, "XNextEvent");
+ peak_x11.XLookupKeysym = (XLookupKeysym_t)dlsym(handle, "XLookupKeysym");
+ peak_x11.XPutImage = (XPutImage_t)dlsym(handle, "XPutImage");
+ peak_x11.XDefaultScreen = (XDefaultScreen_t)dlsym(handle, "XDefaultScreen");
+ peak_x11.XRootWindow = (XRootWindow_t)dlsym(handle, "XRootWindow");
+ peak_x11.XBlackPixel = (XBlackPixel_t)dlsym(handle, "XBlackPixel");
+ peak_x11.XDefaultVisual = (XDefaultVisual_t)dlsym(handle, "XDefaultVisual");
+ peak_x11.XDefaultDepth = (XDefaultDepth_t)dlsym(handle, "XDefaultDepth");
+
+ if (!peak_x11.XOpenDisplay || !peak_x11.XCloseDisplay || !peak_x11.XCreateSimpleWindow ||
+ !peak_x11.XStoreName || !peak_x11.XInternAtom || !peak_x11.XSetWMProtocols ||
+ !peak_x11.XSelectInput || !peak_x11.XCreateGC || !peak_x11.XCreateImage ||
+ !peak_x11.XMapRaised || !peak_x11.XFlush ||
+ !peak_x11.XFreeGC || !peak_x11.XDestroyWindow || !peak_x11.XPending ||
+ !peak_x11.XNextEvent || !peak_x11.XLookupKeysym || !peak_x11.XPutImage ||
+ !peak_x11.XDefaultScreen || !peak_x11.XRootWindow || !peak_x11.XBlackPixel ||
+ !peak_x11.XDefaultVisual || !peak_x11.XDefaultDepth) {
+ return 0;
+ }
+ return 1;
+}
+
+
+typedef struct {
+ Display *display;
+ Atom wm_delete_window;
+ bool initialized;
+} PeakLinux;
+
+typedef struct {
+ Window window;
+ GC gfx_ctx; /* GRAPHICS CONTEXT, not garbage collector lol */
+} PeakLinuxWindow;
+
+static PeakLinux peak_linux = {0};
+static PeakLinuxWindow peak_linux_window = {0};
+static XImage *peak_linux_ximage = NULL;
+static uint32_t *peak_linux_buffer = NULL;
+static size_t peak_linux_width = PEAK_LINUX_DEFAULT_WIDTH;
+static size_t peak_linux_height = PEAK_LINUX_DEFAULT_HEIGHT;
+
+static PeakKeyCode
+peak__x11_map_key(KeySym sym)
+{
+ if (sym >= XK_a && sym <= XK_z) return (PeakKeyCode)(PEAK_KEY_A + (int)(sym - XK_a));
+ if (sym >= XK_A && sym <= XK_Z) return (PeakKeyCode)(PEAK_KEY_A + (int)(sym - XK_A));
+ switch (sym) {
+ case XK_Up: return PEAK_KEY_UP;
+ case XK_Down: return PEAK_KEY_DOWN;
+ case XK_Left: return PEAK_KEY_LEFT;
+ case XK_Right: return PEAK_KEY_RIGHT;
+ case XK_space: return PEAK_KEY_SPACE;
+ case XK_Escape: return PEAK_KEY_ESCAPE;
+ case XK_Return: return PEAK_KEY_ENTER;
+ default: return PEAK_KEY_UNKNOWN;
+ }
+}
+
+static PeakKeyMod
+peak__x11_map_mod(unsigned int state)
+{
+ if (state & ControlMask) return PEAK_KEYMOD_CTRL;
+ if (state & Mod1Mask) return PEAK_KEYMOD_ALT;
+ if (state & ShiftMask) return PEAK_KEYMOD_SHIFT;
+ if (state & LockMask) return PEAK_KEYMOD_CAPS;
+ return (PeakKeyMod)0;
+}
+
+void
+peak_platform_window_open()
+{
+ void *x11_handle = dlopen(PEAK_X11_LINUX, RTLD_LOCAL | RTLD_NOW);
+ assert(x11_handle && "Failed to load X11 library. What system are you fucking using and abusing?");
+
+ int success = peak_load_x11(x11_handle);
+ assert(success && "Failed to open X11 display");
+
+ peak_linux.display = peak_x11.XOpenDisplay(NULL);
+ assert(peak_linux.display && "Failed to open X11 display");
+
+ /* Who design this API??? */
+ int screen = DefaultScreen(peak_linux.display);
+ peak_linux_window.window = peak_x11.XCreateSimpleWindow(peak_linux.display, RootWindow(peak_linux.display, screen), 0, 0, peak_linux_width, peak_linux_height, 0, BlackPixel(peak_linux.display, screen), BlackPixel(peak_linux.display, screen));
+ peak_x11.XStoreName(peak_linux.display, peak_linux_window.window, "Peak");
+ peak_linux.wm_delete_window = peak_x11.XInternAtom(peak_linux.display, "WM_DELETE_WINDOW", False);
+ peak_x11.XSetWMProtocols(peak_linux.display, peak_linux_window.window, &peak_linux.wm_delete_window, 1);
+ peak_x11.XSelectInput(peak_linux.display, peak_linux_window.window, ExposureMask | KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask | PointerMotionMask | StructureNotifyMask);
+ peak_linux_window.gfx_ctx = peak_x11.XCreateGC(peak_linux.display, peak_linux_window.window, 0, NULL);
+ peak_linux_buffer = (uint32_t *)calloc(peak_linux_width * peak_linux_height, sizeof(uint32_t));
+ assert(peak_linux_buffer && "Failed to allocate framebuffer");
+
+ /* Wrap the buffer in an XImage for XPutImage blitting */
+ Visual *visual = DefaultVisual(peak_linux.display, screen);
+ int depth = DefaultDepth(peak_linux.display, screen);
+
+ peak_linux_ximage = peak_x11.XCreateImage(peak_linux.display, visual, depth, ZPixmap, 0, (char *)peak_linux_buffer, peak_linux_width, peak_linux_height, 32, 0);
+ assert(peak_linux_ximage && "Failed to create XImage");
+
+ peak_x11.XMapRaised(peak_linux.display, peak_linux_window.window);
+ peak_x11.XFlush(peak_linux.display);
+
+ peak_linux.initialized = true;
+}
+
+void
+peak_platform_window_close()
+{
+ if (!peak_linux.initialized) return;
+
+ if (peak_linux_ximage) {
+ peak_linux_ximage->data = NULL;
+ XDestroyImage(peak_linux_ximage);
+ peak_linux_ximage = NULL;
+ }
+
+ free(peak_linux_buffer);
+ peak_linux_buffer = NULL;
+
+ peak_x11.XFreeGC(peak_linux.display, peak_linux_window.gfx_ctx);
+ peak_x11.XDestroyWindow(peak_linux.display, peak_linux_window.window);
+ peak_x11.XCloseDisplay(peak_linux.display);
+
+ peak_linux.initialized = false;
+}
+
+uint32_t *
+peak_platform_window_buffer(size_t *width, size_t *height)
+{
+ *width = peak_linux_width;
+ *height = peak_linux_height;
+ return peak_linux_buffer;
+}
+
+bool
+peak_platform_epoll(PeakEvent *ev)
+{
+ if (!peak_linux.initialized) return false;
+
+ Display *dpy = peak_linux.display;
+
+ while (peak_x11.XPending(dpy) > 0) {
+ XEvent xev;
+ peak_x11.XNextEvent(dpy, &xev);
+
+ switch (xev.type) {
+
+ case ClientMessage:
+ if ((Atom)xev.xclient.data.l[0] == peak_linux.wm_delete_window) {
+ ev->type = PEAK_EVENT_WINDOW_CLOSE;
+ printf("CLLOOOOOOOSEEEE");
+ return true;
+ }
+ continue;
+
+ case KeyPress:
+ case KeyRelease: {
+ KeySym sym = peak_x11.XLookupKeysym(&xev.xkey, 0);
+ ev->type = (xev.type == KeyPress) ? PEAK_EVENT_KEY_DOWN : PEAK_EVENT_KEY_UP;
+ ev->key.key = peak__x11_map_key(sym);
+ ev->key.mod = peak__x11_map_mod(xev.xkey.state);
+ return true;
+ }
+
+ case ButtonPress:
+ case ButtonRelease: {
+ ev->type = PEAK_EVENT_POINTER;
+ ev->pointer.state = (xev.type == ButtonPress) ? PEAK_POINTER_PRESSED : PEAK_POINTER_RELEASED;
+ ev->pointer.x = (float)xev.xbutton.x;
+ ev->pointer.y = (float)xev.xbutton.y;
+ switch (xev.xbutton.button) {
+ case Button1: ev->pointer.type = PEAK_POINTER_LEFT; break;
+ case Button2: ev->pointer.type = PEAK_POINTER_MIDDLE; break;
+ case Button3: ev->pointer.type = PEAK_POINTER_RIGHT; break;
+ default: ev->pointer.type = PEAK_POINTER_LEFT; break;
+ }
+ return true;
+ }
+
+ case MotionNotify:
+ ev->type = PEAK_EVENT_POINTER;
+ ev->pointer.state = PEAK_POINTER_MOVED;
+ ev->pointer.x = (float)xev.xmotion.x;
+ ev->pointer.y = (float)xev.xmotion.y;
+ if (xev.xmotion.state & Button3Mask)
+ ev->pointer.type = PEAK_POINTER_RIGHT;
+ else if (xev.xmotion.state & Button2Mask)
+ ev->pointer.type = PEAK_POINTER_MIDDLE;
+ else
+ ev->pointer.type = PEAK_POINTER_LEFT;
+ return true;
+
+ case ConfigureNotify:
+ if ((size_t)xev.xconfigure.width != peak_linux_width ||
+ (size_t)xev.xconfigure.height != peak_linux_height) {
+ ev->type = PEAK_EVENT_WINDOW_RESIZE;
+ ev->resize.width = (uint32_t)xev.xconfigure.width;
+ ev->resize.height = (uint32_t)xev.xconfigure.height;
+ return true;
+ }
+ continue;
+
+ case Expose:
+ if (xev.xexpose.count == 0) {
+ peak_x11.XPutImage(dpy, peak_linux_window.window, peak_linux_window.gfx_ctx, peak_linux_ximage, 0, 0, 0, 0, peak_linux_width, peak_linux_height);
+ }
+ continue;
+
+ default:
+ continue;
+ }
+ }
+
+ peak_x11.XPutImage(dpy, peak_linux_window.window, peak_linux_window.gfx_ctx, peak_linux_ximage, 0, 0, 0, 0, peak_linux_width, peak_linux_height);
+ peak_x11.XFlush(dpy);
+ return false;
+}
+/* --- End of p_linux.c --- */
+#elif defined(PEAK_WEB)
+/* --- Start of p_emscripten.c --- */
+#include <stdlib.h>
+#include <string.h>
+#include <stdbool.h>
+
+#define PEAK_CANVAS "#PeakCanvas"
+
+static PeakKeyCode map_key(const char *code);
+static PeakKeyMod map_mod(const EmscriptenKeyboardEvent *keyEvent);
+static EM_BOOL key_callback(int eventType, const EmscriptenKeyboardEvent *keyEvent, void *userData);
+static EM_BOOL mouse_callback(int eventType, const EmscriptenMouseEvent *mouseEvent, void *userData);
+static EM_BOOL resize_callback(int eventType, const EmscriptenUiEvent *uiEvent, void *userData);
+
+void
+peak_platform_window_open()
+{
+ emscripten_set_keydown_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, NULL, EM_TRUE, key_callback);
+ emscripten_set_keyup_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, NULL, EM_TRUE, key_callback);
+ emscripten_set_mousedown_callback(PEAK_CANVAS, NULL, EM_TRUE, mouse_callback);
+ emscripten_set_mouseup_callback(PEAK_CANVAS, NULL, EM_TRUE, mouse_callback);
+ emscripten_set_mousemove_callback(PEAK_CANVAS, NULL, EM_TRUE, mouse_callback);
+ emscripten_set_resize_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, NULL, EM_TRUE, resize_callback);
+}
+
+void
+peak_platform_window_close()
+{
+}
+
+uint32_t*
+peak_platform_window_buffer(size_t *width, size_t *height)
+{
+}
+
+bool
+peak_platform_epoll(PeakEvent *ev)
+{
+ return 0;
+}
+/* --- End of p_emscripten.c --- */
+#endif
+
+/* --- Start of peak.c --- */
+static inline void peak__put_pixel(int x, int y, uint32_t color);
+static inline uint32_t peak__lerp_color(uint32_t c0, uint32_t c1, float t);
+static inline float peak__edge_cross(float ax, float ay, float bx, float by, float cx, float cy);
+
+static uint32_t *peak_window_buffer;
+static size_t peak_window_width;
+static size_t peak_window_height;
+static int peak_clip_x;
+static int peak_clip_y;
+static size_t peak_clip_width;
+static size_t peak_clip_height;
+
+void
+peak__put_pixel(int x, int y, uint32_t color)
+{
+ if (x < peak_clip_x || x >= (int)(peak_clip_x + peak_clip_width) ||
+ y < peak_clip_y || y >= (int)(peak_clip_y + peak_clip_height)) {
+ return;
+ }
+ if (x < 0 || x >= (int)peak_window_width || y < 0 || y >= (int)peak_window_height) {
+ return;
+ }
+ peak_window_buffer[y * peak_window_width + x] = color;
+}
+
+uint32_t
+peak__lerp_color(uint32_t c0, uint32_t c1, float t)
+{
+ if (t <= 0.0f) return c0;
+ if (t >= 1.0f) return c1;
+
+ uint32_t a0 = (c0 >> 24) & 0xFF, a1 = (c1 >> 24) & 0xFF;
+ uint32_t r0 = (c0 >> 16) & 0xFF, r1 = (c1 >> 16) & 0xFF;
+ uint32_t g0 = (c0 >> 8) & 0xFF, g1 = (c1 >> 8) & 0xFF;
+ uint32_t b0 = c0 & 0xFF, b1 = c1 & 0xFF;
+
+ uint32_t a = (uint32_t)(a0 + t * ((float)a1 - (float)a0));
+ uint32_t r = (uint32_t)(r0 + t * ((float)r1 - (float)r0));
+ uint32_t g = (uint32_t)(g0 + t * ((float)g1 - (float)g0));
+ uint32_t b = (uint32_t)(b0 + t * ((float)b1 - (float)b0));
+
+ return (a << 24) | (r << 16) | (g << 8) | b;
+}
+
+float
+peak__edge_cross(float ax, float ay, float bx, float by, float cx, float cy)
+{
+ return (cx - ax) * (by - ay) - (cy - ay) * (bx - ax);
+}
+
+void
+peak_init(void)
+{
+ peak_platform_window_open();
+ peak_window_buffer = peak_platform_window_buffer(&peak_window_width, &peak_window_height);
+ peak_clip_x = 0;
+ peak_clip_y = 0;
+ peak_clip_width = peak_window_width;
+ peak_clip_height = peak_window_height;
+}
+
+void
+peak_quit(void)
+{
+ peak_platform_window_close();
+}
+
+void
+peak_extensions(void)
+{
+ // TODO
+}
+
+bool
+peak_poll_events(PeakEvent *ev)
+{
+ return peak_platform_epoll(ev);
+}
+
+void
+peak_blit(int offset_x, int offset_y, const uint32_t *rgba, size_t width, size_t height)
+{
+ for (size_t y = 0; y < height; ++y) {
+ int target_y = offset_y + (int)y;
+ if (target_y < peak_clip_y || target_y >= (int)(peak_clip_y + peak_clip_height) ||
+ target_y < 0 || target_y >= (int)peak_window_height) continue;
+
+ int start_x = offset_x < peak_clip_x ? peak_clip_x : offset_x;
+ int end_x = (offset_x + (int)width) > (int)(peak_clip_x + peak_clip_width)
+ ? (int)(peak_clip_x + peak_clip_width)
+ : (offset_x + (int)width);
+
+ if (start_x >= end_x) continue;
+
+ size_t src_offset_x = (size_t)(start_x - offset_x);
+ size_t copy_pixels = (size_t)(end_x - start_x);
+
+ memcpy(&peak_window_buffer[target_y * peak_window_width + start_x], &rgba[y * width + src_offset_x], copy_pixels * sizeof(uint32_t));
+ }
+}
+
+void
+peak_clip(int x, int y, size_t w, size_t h)
+{
+ peak_clip_x = x;
+ peak_clip_y = y;
+ peak_clip_width = w;
+ peak_clip_height = h;
+}
+
+void
+peak_clip_reset(void)
+{
+ peak_clip_x = 0;
+ peak_clip_y = 0;
+ peak_clip_width = peak_window_width;
+ peak_clip_height = peak_window_height;
+}
+
+void
+peak_draw_rectangle(int x, int y, size_t w, size_t h, uint32_t color)
+{
+ int start_x = (x < peak_clip_x) ? peak_clip_x : x;
+ int start_y = (y < peak_clip_y) ? peak_clip_y : y;
+ int end_x = (x + (int)w > (int)(peak_clip_x + peak_clip_width)) ? (int)(peak_clip_x + peak_clip_width) : x + (int)w;
+ int end_y = (y + (int)h > (int)(peak_clip_y + peak_clip_height)) ? (int)(peak_clip_y + peak_clip_height) : y + (int)h;
+
+ for (int py = start_y; py < end_y; ++py) {
+ if (py < 0 || py >= (int)peak_window_height) continue;
+ for (int px = start_x; px < end_x; ++px) {
+ if (px < 0 || px >= (int)peak_window_width) continue;
+ peak_window_buffer[py * peak_window_width + px] = color;
+ }
+ }
+}
+
+void
+peak_draw_rectangle_gradient(int x, int y, size_t w, size_t h, uint32_t c0, uint32_t c1, uint32_t c2, uint32_t c3)
+{
+ for (size_t ry = 0; ry < h; ++ry) {
+ float ty = (h > 1) ? (float)ry / (float)(h - 1) : 0.0f;
+ uint32_t left_color = peak__lerp_color(c0, c3, ty);
+ uint32_t right_color = peak__lerp_color(c1, c2, ty);
+
+ for (size_t rx = 0; rx < w; ++rx) {
+ float tx = (w > 1) ? (float)rx / (float)(w - 1) : 0.0f;
+ uint32_t final_color = peak__lerp_color(left_color, right_color, tx);
+ peak__put_pixel(x + (int)rx, y + (int)ry, final_color);
+ }
+ }
+}
+
+void
+peak_draw_triangle(int x0, int y0, int x1, int y1, int x2, int y2, uint32_t color)
+{
+ int min_x = (x0 < x1) ? ((x0 < x2) ? x0 : x2) : ((x1 < x2) ? x1 : x2);
+ int max_x = (x0 > x1) ? ((x0 > x2) ? x0 : x2) : ((x1 > x2) ? x1 : x2);
+ int min_y = (y0 < y1) ? ((y0 < y2) ? y0 : y2) : ((y1 < y2) ? y1 : y2);
+ int max_y = (y0 > y1) ? ((y0 > y2) ? y0 : y2) : ((y1 > y2) ? y1 : y2);
+
+ float area = peak__edge_cross((float)x0, (float)y0, (float)x1, (float)y1, (float)x2, (float)y2);
+ if (area == 0.0f) return;
+
+ for (int y = min_y; y <= max_y; ++y) {
+ for (int x = min_x; x <= max_x; ++x) {
+ float w0 = peak__edge_cross((float)x1, (float)y1, (float)x2, (float)y2, (float)x, (float)y);
+ float w1 = peak__edge_cross((float)x2, (float)y2, (float)x0, (float)y0, (float)x, (float)y);
+ float w2 = peak__edge_cross((float)x0, (float)y0, (float)x1, (float)y1, (float)x, (float)y);
+
+ if ((w0 >= 0 && w1 >= 0 && w2 >= 0) || (w0 <= 0 && w1 <= 0 && w2 <= 0)) {
+ peak__put_pixel(x, y, color);
+ }
+ }
+ }
+}
+
+void
+peak_draw_triangle_gradient(int x0, int y0, int x1, int y1, int x2, int y2, uint32_t c0, uint32_t c1, uint32_t c2)
+{
+ int min_x = (x0 < x1) ? ((x0 < x2) ? x0 : x2) : ((x1 < x2) ? x1 : x2);
+ int max_x = (x0 > x1) ? ((x0 > x2) ? x0 : x2) : ((x1 > x2) ? x1 : x2);
+ int min_y = (y0 < y1) ? ((y0 < y2) ? y0 : y2) : ((y1 < y2) ? y1 : y2);
+ int max_y = (y0 > y1) ? ((y0 > y2) ? y0 : y2) : ((y1 > y2) ? y1 : y2);
+
+ float area = peak__edge_cross((float)x0, (float)y0, (float)x1, (float)y1, (float)x2, (float)y2);
+ if (area == 0.0f) return;
+
+ for (int y = min_y; y <= max_y; ++y) {
+ for (int x = min_x; x <= max_x; ++x) {
+ float w0 = peak__edge_cross((float)x1, (float)y1, (float)x2, (float)y2, (float)x, (float)y) / area;
+ float w1 = peak__edge_cross((float)x2, (float)y2, (float)x0, (float)y0, (float)x, (float)y) / area;
+ float w2 = peak__edge_cross((float)x0, (float)y0, (float)x1, (float)y1, (float)x, (float)y) / area;
+
+ if (w0 >= 0.0f && w1 >= 0.0f && w2 >= 0.0f) {
+ uint32_t col_a = peak__lerp_color(c0, c1, w1 / (w0 + w1 + 1e-6f));
+ uint32_t final_color = peak__lerp_color(col_a, c2, w2);
+ peak__put_pixel(x, y, final_color);
+ }
+ }
+ }
+}
+
+void
+peak_draw_line(int x0, int y0, int x1, int y1, size_t width, uint32_t color)
+{
+ int dx = abs(x1 - x0), sx = x0 < x1 ? 1 : -1;
+ int dy = -abs(y1 - y0), sy = y0 < y1 ? 1 : -1;
+ int err = dx + dy, e2;
+
+ int half_w = (int)width / 2;
+
+ while (1) {
+ /* Draw square footprint for line thickness */
+ for (int ox = -half_w; ox <= half_w; ++ox) {
+ for (int oy = -half_w; oy <= half_w; ++oy) {
+ peak__put_pixel(x0 + ox, y0 + oy, color);
+ }
+ }
+ if (x0 == x1 && y0 == y1) break;
+ e2 = 2 * err;
+ if (e2 >= dy) { err += dy; x0 += sx; }
+ if (e2 <= dx) { err += dx; y0 += sy; }
+ }
+}
+
+void
+peak_draw_line_gradient(int x0, int y0, int x1, int y1, size_t width, uint32_t c0, uint32_t c1)
+{
+ float total_dist = sqrtf((float)((x1 - x0)*(x1 - x0) + (y1 - y0)*(y1 - y0)));
+ int dx = abs(x1 - x0), sx = x0 < x1 ? 1 : -1;
+ int dy = -abs(y1 - y0), sy = y0 < y1 ? 1 : -1;
+ int err = dx + dy, e2;
+
+ int orig_x0 = x0, orig_y0 = y0;
+ int half_w = (int)width / 2;
+
+ while (1) {
+ float current_dist = sqrtf((float)((x0 - orig_x0)*(x0 - orig_x0) + (y0 - orig_y0)*(y0 - orig_y0)));
+ float t = (total_dist > 0.0f) ? (current_dist / total_dist) : 0.0f;
+ uint32_t color = peak__lerp_color(c0, c1, t);
+
+ for (int ox = -half_w; ox <= half_w; ++ox) {
+ for (int oy = -half_w; oy <= half_w; ++oy) {
+ peak__put_pixel(x0 + ox, y0 + oy, color);
+ }
+ }
+
+ if (x0 == x1 && y0 == y1) break;
+ e2 = 2 * err;
+ if (e2 >= dy) { err += dy; x0 += sx; }
+ if (e2 <= dx) { err += dx; y0 += sy; }
+ }
+}
+
+/* --- End of peak.c --- */
+
+#endif // PEAK_IMPLEMENTATION
+
+
+/*
+------------------------------------------------------------------------------
+This software is available under 2 licenses -- choose whichever you prefer.
+------------------------------------------------------------------------------
+ALTERNATIVE A - MIT License
+Copyright (c) 2026 Vasco Alves
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+of the Software, and to permit persons to whom the Software is furnished to do
+so, subject to the following conditions:
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+------------------------------------------------------------------------------
+ALTERNATIVE B - Public Domain (www.unlicense.org)
+This is free and unencumbered software released into the public domain.
+Anyone is free to copy, modify, publish, use, compile, sell, or distribute this
+software, either in source code form or as a compiled binary, for any purpose,
+commercial or non-commercial, and by any means.
+In jurisdictions that recognize copyright laws, the author or authors of this
+software dedicate any and all copyright interest in the software to the public
+domain. We make this dedication for the benefit of the public at large and to
+the detriment of our heirs and successors. We intend this dedication to be an
+overt act of relinquishment in perpetuity of all present and future rights to
+this software under copyright law.
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+------------------------------------------------------------------------------
+*/
diff --git a/Peak/src/p_emscripten.c b/Peak/src/p_emscripten.c
new file mode 100644
index 0000000..dc558f5
--- /dev/null
+++ b/Peak/src/p_emscripten.c
@@ -0,0 +1,38 @@
+#include <stdlib.h>
+#include <string.h>
+#include <stdbool.h>
+
+#define PEAK_CANVAS "#PeakCanvas"
+
+static PeakKeyCode map_key(const char *code);
+static PeakKeyMod map_mod(const EmscriptenKeyboardEvent *keyEvent);
+static EM_BOOL key_callback(int eventType, const EmscriptenKeyboardEvent *keyEvent, void *userData);
+static EM_BOOL mouse_callback(int eventType, const EmscriptenMouseEvent *mouseEvent, void *userData);
+static EM_BOOL resize_callback(int eventType, const EmscriptenUiEvent *uiEvent, void *userData);
+
+void
+peak_platform_window_open()
+{
+ emscripten_set_keydown_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, NULL, EM_TRUE, key_callback);
+ emscripten_set_keyup_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, NULL, EM_TRUE, key_callback);
+ emscripten_set_mousedown_callback(PEAK_CANVAS, NULL, EM_TRUE, mouse_callback);
+ emscripten_set_mouseup_callback(PEAK_CANVAS, NULL, EM_TRUE, mouse_callback);
+ emscripten_set_mousemove_callback(PEAK_CANVAS, NULL, EM_TRUE, mouse_callback);
+ emscripten_set_resize_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, NULL, EM_TRUE, resize_callback);
+}
+
+void
+peak_platform_window_close()
+{
+}
+
+uint32_t*
+peak_platform_window_buffer(size_t *width, size_t *height)
+{
+}
+
+bool
+peak_platform_epoll(PeakEvent *ev)
+{
+ return 0;
+}
diff --git a/Peak/src/p_linux.c b/Peak/src/p_linux.c
new file mode 100644
index 0000000..c3d70bf
--- /dev/null
+++ b/Peak/src/p_linux.c
@@ -0,0 +1,295 @@
+#include <dlfcn.h>
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+#include <X11/Xatom.h>
+#include <X11/keysym.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define PEAK_X11_LINUX "/usr/lib/libX11.so.6"
+
+#define PEAK_LINUX_DEFAULT_WIDTH 800
+#define PEAK_LINUX_DEFAULT_HEIGHT 600
+
+typedef Display* (*XOpenDisplay_t)(const char*);
+typedef int (*XCloseDisplay_t)(Display*);
+typedef Window (*XCreateSimpleWindow_t)(Display*, Window, int, int, unsigned int, unsigned int, unsigned int, unsigned long, unsigned long);
+typedef int (*XStoreName_t)(Display*, Window, const char*);
+typedef Atom (*XInternAtom_t)(Display*, const char*, Bool);
+typedef Status (*XSetWMProtocols_t)(Display*, Window, Atom*, int);
+typedef int (*XSelectInput_t)(Display*, Window, long);
+typedef GC (*XCreateGC_t)(Display*, Window, unsigned long, XGCValues*);
+typedef XImage* (*XCreateImage_t)(Display*, Visual*, unsigned int, int, int, char*, unsigned int, unsigned int, int, int);
+typedef int (*XMapRaised_t)(Display*, Window);
+typedef int (*XFlush_t)(Display*);
+typedef int (*XFreeGC_t)(Display*, GC);
+typedef int (*XDestroyWindow_t)(Display*, Window);
+typedef int (*XPending_t)(Display*);
+typedef int (*XNextEvent_t)(Display*, XEvent*);
+typedef KeySym (*XLookupKeysym_t)(XKeyEvent*, int);
+typedef int (*XPutImage_t)(Display*, Drawable, GC, XImage*, int, int, int, int, unsigned int, unsigned int);
+typedef int (*XDefaultScreen_t)(Display*);
+typedef Window (*XRootWindow_t)(Display*, int);
+typedef unsigned long (*XBlackPixel_t)(Display*, int);
+typedef Visual* (*XDefaultVisual_t)(Display*, int);
+typedef int (*XDefaultDepth_t)(Display*, int);
+
+typedef struct {
+ XOpenDisplay_t XOpenDisplay;
+ XCloseDisplay_t XCloseDisplay;
+ XCreateSimpleWindow_t XCreateSimpleWindow;
+ XStoreName_t XStoreName;
+ XInternAtom_t XInternAtom;
+ XSetWMProtocols_t XSetWMProtocols;
+ XSelectInput_t XSelectInput;
+ XCreateGC_t XCreateGC;
+ XCreateImage_t XCreateImage;
+ XMapRaised_t XMapRaised;
+ XFlush_t XFlush;
+ XFreeGC_t XFreeGC;
+ XDestroyWindow_t XDestroyWindow;
+ XPending_t XPending;
+ XNextEvent_t XNextEvent;
+ XLookupKeysym_t XLookupKeysym;
+ XPutImage_t XPutImage;
+ XDefaultScreen_t XDefaultScreen;
+ XRootWindow_t XRootWindow;
+ XBlackPixel_t XBlackPixel;
+ XDefaultVisual_t XDefaultVisual;
+ XDefaultDepth_t XDefaultDepth;
+} PeakX11Api;
+
+static PeakX11Api peak_x11;
+
+static int peak_load_x11(void *handle) {
+ peak_x11.XOpenDisplay = (XOpenDisplay_t)dlsym(handle, "XOpenDisplay");
+ peak_x11.XCloseDisplay = (XCloseDisplay_t)dlsym(handle, "XCloseDisplay");
+ peak_x11.XCreateSimpleWindow = (XCreateSimpleWindow_t)dlsym(handle, "XCreateSimpleWindow");
+ peak_x11.XStoreName = (XStoreName_t)dlsym(handle, "XStoreName");
+ peak_x11.XInternAtom = (XInternAtom_t)dlsym(handle, "XInternAtom");
+ peak_x11.XSetWMProtocols = (XSetWMProtocols_t)dlsym(handle, "XSetWMProtocols");
+ peak_x11.XSelectInput = (XSelectInput_t)dlsym(handle, "XSelectInput");
+ peak_x11.XCreateGC = (XCreateGC_t)dlsym(handle, "XCreateGC");
+ peak_x11.XCreateImage = (XCreateImage_t)dlsym(handle, "XCreateImage");
+ peak_x11.XMapRaised = (XMapRaised_t)dlsym(handle, "XMapRaised");
+ peak_x11.XFlush = (XFlush_t)dlsym(handle, "XFlush");
+ peak_x11.XFreeGC = (XFreeGC_t)dlsym(handle, "XFreeGC");
+ peak_x11.XDestroyWindow = (XDestroyWindow_t)dlsym(handle, "XDestroyWindow");
+ peak_x11.XPending = (XPending_t)dlsym(handle, "XPending");
+ peak_x11.XNextEvent = (XNextEvent_t)dlsym(handle, "XNextEvent");
+ peak_x11.XLookupKeysym = (XLookupKeysym_t)dlsym(handle, "XLookupKeysym");
+ peak_x11.XPutImage = (XPutImage_t)dlsym(handle, "XPutImage");
+ peak_x11.XDefaultScreen = (XDefaultScreen_t)dlsym(handle, "XDefaultScreen");
+ peak_x11.XRootWindow = (XRootWindow_t)dlsym(handle, "XRootWindow");
+ peak_x11.XBlackPixel = (XBlackPixel_t)dlsym(handle, "XBlackPixel");
+ peak_x11.XDefaultVisual = (XDefaultVisual_t)dlsym(handle, "XDefaultVisual");
+ peak_x11.XDefaultDepth = (XDefaultDepth_t)dlsym(handle, "XDefaultDepth");
+
+ if (!peak_x11.XOpenDisplay || !peak_x11.XCloseDisplay || !peak_x11.XCreateSimpleWindow ||
+ !peak_x11.XStoreName || !peak_x11.XInternAtom || !peak_x11.XSetWMProtocols ||
+ !peak_x11.XSelectInput || !peak_x11.XCreateGC || !peak_x11.XCreateImage ||
+ !peak_x11.XMapRaised || !peak_x11.XFlush ||
+ !peak_x11.XFreeGC || !peak_x11.XDestroyWindow || !peak_x11.XPending ||
+ !peak_x11.XNextEvent || !peak_x11.XLookupKeysym || !peak_x11.XPutImage ||
+ !peak_x11.XDefaultScreen || !peak_x11.XRootWindow || !peak_x11.XBlackPixel ||
+ !peak_x11.XDefaultVisual || !peak_x11.XDefaultDepth) {
+ return 0;
+ }
+ return 1;
+}
+
+
+typedef struct {
+ Display *display;
+ Atom wm_delete_window;
+ bool initialized;
+} PeakLinux;
+
+typedef struct {
+ Window window;
+ GC gfx_ctx; /* GRAPHICS CONTEXT, not garbage collector lol */
+} PeakLinuxWindow;
+
+static PeakLinux peak_linux = {0};
+static PeakLinuxWindow peak_linux_window = {0};
+static XImage *peak_linux_ximage = NULL;
+static uint32_t *peak_linux_buffer = NULL;
+static size_t peak_linux_width = PEAK_LINUX_DEFAULT_WIDTH;
+static size_t peak_linux_height = PEAK_LINUX_DEFAULT_HEIGHT;
+
+static PeakKeyCode
+peak__x11_map_key(KeySym sym)
+{
+ if (sym >= XK_a && sym <= XK_z) return (PeakKeyCode)(PEAK_KEY_A + (int)(sym - XK_a));
+ if (sym >= XK_A && sym <= XK_Z) return (PeakKeyCode)(PEAK_KEY_A + (int)(sym - XK_A));
+ switch (sym) {
+ case XK_Up: return PEAK_KEY_UP;
+ case XK_Down: return PEAK_KEY_DOWN;
+ case XK_Left: return PEAK_KEY_LEFT;
+ case XK_Right: return PEAK_KEY_RIGHT;
+ case XK_space: return PEAK_KEY_SPACE;
+ case XK_Escape: return PEAK_KEY_ESCAPE;
+ case XK_Return: return PEAK_KEY_ENTER;
+ default: return PEAK_KEY_UNKNOWN;
+ }
+}
+
+static PeakKeyMod
+peak__x11_map_mod(unsigned int state)
+{
+ if (state & ControlMask) return PEAK_KEYMOD_CTRL;
+ if (state & Mod1Mask) return PEAK_KEYMOD_ALT;
+ if (state & ShiftMask) return PEAK_KEYMOD_SHIFT;
+ if (state & LockMask) return PEAK_KEYMOD_CAPS;
+ return (PeakKeyMod)0;
+}
+
+void
+peak_platform_window_open()
+{
+ void *x11_handle = dlopen(PEAK_X11_LINUX, RTLD_LOCAL | RTLD_NOW);
+ assert(x11_handle && "Failed to load X11 library. What system are you fucking using and abusing?");
+
+ int success = peak_load_x11(x11_handle);
+ assert(success && "Failed to open X11 display");
+
+ peak_linux.display = peak_x11.XOpenDisplay(NULL);
+ assert(peak_linux.display && "Failed to open X11 display");
+
+ /* Who design this API??? */
+ int screen = DefaultScreen(peak_linux.display);
+ peak_linux_window.window = peak_x11.XCreateSimpleWindow(peak_linux.display, RootWindow(peak_linux.display, screen), 0, 0, peak_linux_width, peak_linux_height, 0, BlackPixel(peak_linux.display, screen), BlackPixel(peak_linux.display, screen));
+ peak_x11.XStoreName(peak_linux.display, peak_linux_window.window, "Peak");
+ peak_linux.wm_delete_window = peak_x11.XInternAtom(peak_linux.display, "WM_DELETE_WINDOW", False);
+ peak_x11.XSetWMProtocols(peak_linux.display, peak_linux_window.window, &peak_linux.wm_delete_window, 1);
+ peak_x11.XSelectInput(peak_linux.display, peak_linux_window.window, ExposureMask | KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask | PointerMotionMask | StructureNotifyMask);
+ peak_linux_window.gfx_ctx = peak_x11.XCreateGC(peak_linux.display, peak_linux_window.window, 0, NULL);
+ peak_linux_buffer = (uint32_t *)calloc(peak_linux_width * peak_linux_height, sizeof(uint32_t));
+ assert(peak_linux_buffer && "Failed to allocate framebuffer");
+
+ /* Wrap the buffer in an XImage for XPutImage blitting */
+ Visual *visual = DefaultVisual(peak_linux.display, screen);
+ int depth = DefaultDepth(peak_linux.display, screen);
+
+ peak_linux_ximage = peak_x11.XCreateImage(peak_linux.display, visual, depth, ZPixmap, 0, (char *)peak_linux_buffer, peak_linux_width, peak_linux_height, 32, 0);
+ assert(peak_linux_ximage && "Failed to create XImage");
+
+ peak_x11.XMapRaised(peak_linux.display, peak_linux_window.window);
+ peak_x11.XFlush(peak_linux.display);
+
+ peak_linux.initialized = true;
+}
+
+void
+peak_platform_window_close()
+{
+ if (!peak_linux.initialized) return;
+
+ if (peak_linux_ximage) {
+ peak_linux_ximage->data = NULL;
+ XDestroyImage(peak_linux_ximage);
+ peak_linux_ximage = NULL;
+ }
+
+ free(peak_linux_buffer);
+ peak_linux_buffer = NULL;
+
+ peak_x11.XFreeGC(peak_linux.display, peak_linux_window.gfx_ctx);
+ peak_x11.XDestroyWindow(peak_linux.display, peak_linux_window.window);
+ peak_x11.XCloseDisplay(peak_linux.display);
+
+ peak_linux.initialized = false;
+}
+
+uint32_t *
+peak_platform_window_buffer(size_t *width, size_t *height)
+{
+ *width = peak_linux_width;
+ *height = peak_linux_height;
+ return peak_linux_buffer;
+}
+
+bool
+peak_platform_epoll(PeakEvent *ev)
+{
+ if (!peak_linux.initialized) return false;
+
+ Display *dpy = peak_linux.display;
+
+ while (peak_x11.XPending(dpy) > 0) {
+ XEvent xev;
+ peak_x11.XNextEvent(dpy, &xev);
+
+ switch (xev.type) {
+
+ case ClientMessage:
+ if ((Atom)xev.xclient.data.l[0] == peak_linux.wm_delete_window) {
+ ev->type = PEAK_EVENT_WINDOW_CLOSE;
+ printf("CLLOOOOOOOSEEEE");
+ return true;
+ }
+ continue;
+
+ case KeyPress:
+ case KeyRelease: {
+ KeySym sym = peak_x11.XLookupKeysym(&xev.xkey, 0);
+ ev->type = (xev.type == KeyPress) ? PEAK_EVENT_KEY_DOWN : PEAK_EVENT_KEY_UP;
+ ev->key.key = peak__x11_map_key(sym);
+ ev->key.mod = peak__x11_map_mod(xev.xkey.state);
+ return true;
+ }
+
+ case ButtonPress:
+ case ButtonRelease: {
+ ev->type = PEAK_EVENT_POINTER;
+ ev->pointer.state = (xev.type == ButtonPress) ? PEAK_POINTER_PRESSED : PEAK_POINTER_RELEASED;
+ ev->pointer.x = (float)xev.xbutton.x;
+ ev->pointer.y = (float)xev.xbutton.y;
+ switch (xev.xbutton.button) {
+ case Button1: ev->pointer.type = PEAK_POINTER_LEFT; break;
+ case Button2: ev->pointer.type = PEAK_POINTER_MIDDLE; break;
+ case Button3: ev->pointer.type = PEAK_POINTER_RIGHT; break;
+ default: ev->pointer.type = PEAK_POINTER_LEFT; break;
+ }
+ return true;
+ }
+
+ case MotionNotify:
+ ev->type = PEAK_EVENT_POINTER;
+ ev->pointer.state = PEAK_POINTER_MOVED;
+ ev->pointer.x = (float)xev.xmotion.x;
+ ev->pointer.y = (float)xev.xmotion.y;
+ if (xev.xmotion.state & Button3Mask)
+ ev->pointer.type = PEAK_POINTER_RIGHT;
+ else if (xev.xmotion.state & Button2Mask)
+ ev->pointer.type = PEAK_POINTER_MIDDLE;
+ else
+ ev->pointer.type = PEAK_POINTER_LEFT;
+ return true;
+
+ case ConfigureNotify:
+ if ((size_t)xev.xconfigure.width != peak_linux_width ||
+ (size_t)xev.xconfigure.height != peak_linux_height) {
+ ev->type = PEAK_EVENT_WINDOW_RESIZE;
+ ev->resize.width = (uint32_t)xev.xconfigure.width;
+ ev->resize.height = (uint32_t)xev.xconfigure.height;
+ return true;
+ }
+ continue;
+
+ case Expose:
+ if (xev.xexpose.count == 0) {
+ peak_x11.XPutImage(dpy, peak_linux_window.window, peak_linux_window.gfx_ctx, peak_linux_ximage, 0, 0, 0, 0, peak_linux_width, peak_linux_height);
+ }
+ continue;
+
+ default:
+ continue;
+ }
+ }
+
+ peak_x11.XPutImage(dpy, peak_linux_window.window, peak_linux_window.gfx_ctx, peak_linux_ximage, 0, 0, 0, 0, peak_linux_width, peak_linux_height);
+ peak_x11.XFlush(dpy);
+ return false;
+}
diff --git a/Peak/src/p_win32.c b/Peak/src/p_win32.c
new file mode 100644
index 0000000..16fab7f
--- /dev/null
+++ b/Peak/src/p_win32.c
@@ -0,0 +1,21 @@
+#include <windows.h>
+
+void
+peak_platform_window_open()
+{
+}
+
+void
+peak_platform_window_close()
+{
+}
+
+uint32_t*
+peak_platform_window_buffer(size_t *width, size_t *height)
+{
+}
+
+bool
+peak_platform_epoll(PeakEvent *ev)
+{
+}
diff --git a/Peak/src/peak.c b/Peak/src/peak.c
new file mode 100644
index 0000000..5e09070
--- /dev/null
+++ b/Peak/src/peak.c
@@ -0,0 +1,254 @@
+static inline void peak__put_pixel(int x, int y, uint32_t color);
+static inline uint32_t peak__lerp_color(uint32_t c0, uint32_t c1, float t);
+static inline float peak__edge_cross(float ax, float ay, float bx, float by, float cx, float cy);
+
+static uint32_t *peak_window_buffer;
+static size_t peak_window_width;
+static size_t peak_window_height;
+static int peak_clip_x;
+static int peak_clip_y;
+static size_t peak_clip_width;
+static size_t peak_clip_height;
+
+void
+peak__put_pixel(int x, int y, uint32_t color)
+{
+ if (x < peak_clip_x || x >= (int)(peak_clip_x + peak_clip_width) ||
+ y < peak_clip_y || y >= (int)(peak_clip_y + peak_clip_height)) {
+ return;
+ }
+ if (x < 0 || x >= (int)peak_window_width || y < 0 || y >= (int)peak_window_height) {
+ return;
+ }
+ peak_window_buffer[y * peak_window_width + x] = color;
+}
+
+uint32_t
+peak__lerp_color(uint32_t c0, uint32_t c1, float t)
+{
+ if (t <= 0.0f) return c0;
+ if (t >= 1.0f) return c1;
+
+ uint32_t a0 = (c0 >> 24) & 0xFF, a1 = (c1 >> 24) & 0xFF;
+ uint32_t r0 = (c0 >> 16) & 0xFF, r1 = (c1 >> 16) & 0xFF;
+ uint32_t g0 = (c0 >> 8) & 0xFF, g1 = (c1 >> 8) & 0xFF;
+ uint32_t b0 = c0 & 0xFF, b1 = c1 & 0xFF;
+
+ uint32_t a = (uint32_t)(a0 + t * ((float)a1 - (float)a0));
+ uint32_t r = (uint32_t)(r0 + t * ((float)r1 - (float)r0));
+ uint32_t g = (uint32_t)(g0 + t * ((float)g1 - (float)g0));
+ uint32_t b = (uint32_t)(b0 + t * ((float)b1 - (float)b0));
+
+ return (a << 24) | (r << 16) | (g << 8) | b;
+}
+
+float
+peak__edge_cross(float ax, float ay, float bx, float by, float cx, float cy)
+{
+ return (cx - ax) * (by - ay) - (cy - ay) * (bx - ax);
+}
+
+void
+peak_init(void)
+{
+ peak_platform_window_open();
+ peak_window_buffer = peak_platform_window_buffer(&peak_window_width, &peak_window_height);
+ peak_clip_x = 0;
+ peak_clip_y = 0;
+ peak_clip_width = peak_window_width;
+ peak_clip_height = peak_window_height;
+}
+
+void
+peak_quit(void)
+{
+ peak_platform_window_close();
+}
+
+void
+peak_extensions(void)
+{
+ // TODO
+}
+
+bool
+peak_poll_events(PeakEvent *ev)
+{
+ return peak_platform_epoll(ev);
+}
+
+void
+peak_blit(int offset_x, int offset_y, const uint32_t *rgba, size_t width, size_t height)
+{
+ for (size_t y = 0; y < height; ++y) {
+ int target_y = offset_y + (int)y;
+ if (target_y < peak_clip_y || target_y >= (int)(peak_clip_y + peak_clip_height) ||
+ target_y < 0 || target_y >= (int)peak_window_height) continue;
+
+ int start_x = offset_x < peak_clip_x ? peak_clip_x : offset_x;
+ int end_x = (offset_x + (int)width) > (int)(peak_clip_x + peak_clip_width)
+ ? (int)(peak_clip_x + peak_clip_width)
+ : (offset_x + (int)width);
+
+ if (start_x >= end_x) continue;
+
+ size_t src_offset_x = (size_t)(start_x - offset_x);
+ size_t copy_pixels = (size_t)(end_x - start_x);
+
+ memcpy(&peak_window_buffer[target_y * peak_window_width + start_x], &rgba[y * width + src_offset_x], copy_pixels * sizeof(uint32_t));
+ }
+}
+
+void
+peak_clip(int x, int y, size_t w, size_t h)
+{
+ peak_clip_x = x;
+ peak_clip_y = y;
+ peak_clip_width = w;
+ peak_clip_height = h;
+}
+
+void
+peak_clip_reset(void)
+{
+ peak_clip_x = 0;
+ peak_clip_y = 0;
+ peak_clip_width = peak_window_width;
+ peak_clip_height = peak_window_height;
+}
+
+void
+peak_draw_rectangle(int x, int y, size_t w, size_t h, uint32_t color)
+{
+ int start_x = (x < peak_clip_x) ? peak_clip_x : x;
+ int start_y = (y < peak_clip_y) ? peak_clip_y : y;
+ int end_x = (x + (int)w > (int)(peak_clip_x + peak_clip_width)) ? (int)(peak_clip_x + peak_clip_width) : x + (int)w;
+ int end_y = (y + (int)h > (int)(peak_clip_y + peak_clip_height)) ? (int)(peak_clip_y + peak_clip_height) : y + (int)h;
+
+ for (int py = start_y; py < end_y; ++py) {
+ if (py < 0 || py >= (int)peak_window_height) continue;
+ for (int px = start_x; px < end_x; ++px) {
+ if (px < 0 || px >= (int)peak_window_width) continue;
+ peak_window_buffer[py * peak_window_width + px] = color;
+ }
+ }
+}
+
+void
+peak_draw_rectangle_gradient(int x, int y, size_t w, size_t h, uint32_t c0, uint32_t c1, uint32_t c2, uint32_t c3)
+{
+ for (size_t ry = 0; ry < h; ++ry) {
+ float ty = (h > 1) ? (float)ry / (float)(h - 1) : 0.0f;
+ uint32_t left_color = peak__lerp_color(c0, c3, ty);
+ uint32_t right_color = peak__lerp_color(c1, c2, ty);
+
+ for (size_t rx = 0; rx < w; ++rx) {
+ float tx = (w > 1) ? (float)rx / (float)(w - 1) : 0.0f;
+ uint32_t final_color = peak__lerp_color(left_color, right_color, tx);
+ peak__put_pixel(x + (int)rx, y + (int)ry, final_color);
+ }
+ }
+}
+
+void
+peak_draw_triangle(int x0, int y0, int x1, int y1, int x2, int y2, uint32_t color)
+{
+ int min_x = (x0 < x1) ? ((x0 < x2) ? x0 : x2) : ((x1 < x2) ? x1 : x2);
+ int max_x = (x0 > x1) ? ((x0 > x2) ? x0 : x2) : ((x1 > x2) ? x1 : x2);
+ int min_y = (y0 < y1) ? ((y0 < y2) ? y0 : y2) : ((y1 < y2) ? y1 : y2);
+ int max_y = (y0 > y1) ? ((y0 > y2) ? y0 : y2) : ((y1 > y2) ? y1 : y2);
+
+ float area = peak__edge_cross((float)x0, (float)y0, (float)x1, (float)y1, (float)x2, (float)y2);
+ if (area == 0.0f) return;
+
+ for (int y = min_y; y <= max_y; ++y) {
+ for (int x = min_x; x <= max_x; ++x) {
+ float w0 = peak__edge_cross((float)x1, (float)y1, (float)x2, (float)y2, (float)x, (float)y);
+ float w1 = peak__edge_cross((float)x2, (float)y2, (float)x0, (float)y0, (float)x, (float)y);
+ float w2 = peak__edge_cross((float)x0, (float)y0, (float)x1, (float)y1, (float)x, (float)y);
+
+ if ((w0 >= 0 && w1 >= 0 && w2 >= 0) || (w0 <= 0 && w1 <= 0 && w2 <= 0)) {
+ peak__put_pixel(x, y, color);
+ }
+ }
+ }
+}
+
+void
+peak_draw_triangle_gradient(int x0, int y0, int x1, int y1, int x2, int y2, uint32_t c0, uint32_t c1, uint32_t c2)
+{
+ int min_x = (x0 < x1) ? ((x0 < x2) ? x0 : x2) : ((x1 < x2) ? x1 : x2);
+ int max_x = (x0 > x1) ? ((x0 > x2) ? x0 : x2) : ((x1 > x2) ? x1 : x2);
+ int min_y = (y0 < y1) ? ((y0 < y2) ? y0 : y2) : ((y1 < y2) ? y1 : y2);
+ int max_y = (y0 > y1) ? ((y0 > y2) ? y0 : y2) : ((y1 > y2) ? y1 : y2);
+
+ float area = peak__edge_cross((float)x0, (float)y0, (float)x1, (float)y1, (float)x2, (float)y2);
+ if (area == 0.0f) return;
+
+ for (int y = min_y; y <= max_y; ++y) {
+ for (int x = min_x; x <= max_x; ++x) {
+ float w0 = peak__edge_cross((float)x1, (float)y1, (float)x2, (float)y2, (float)x, (float)y) / area;
+ float w1 = peak__edge_cross((float)x2, (float)y2, (float)x0, (float)y0, (float)x, (float)y) / area;
+ float w2 = peak__edge_cross((float)x0, (float)y0, (float)x1, (float)y1, (float)x, (float)y) / area;
+
+ if (w0 >= 0.0f && w1 >= 0.0f && w2 >= 0.0f) {
+ uint32_t col_a = peak__lerp_color(c0, c1, w1 / (w0 + w1 + 1e-6f));
+ uint32_t final_color = peak__lerp_color(col_a, c2, w2);
+ peak__put_pixel(x, y, final_color);
+ }
+ }
+ }
+}
+
+void
+peak_draw_line(int x0, int y0, int x1, int y1, size_t width, uint32_t color)
+{
+ int dx = abs(x1 - x0), sx = x0 < x1 ? 1 : -1;
+ int dy = -abs(y1 - y0), sy = y0 < y1 ? 1 : -1;
+ int err = dx + dy, e2;
+
+ int half_w = (int)width / 2;
+
+ while (1) {
+ /* Draw square footprint for line thickness */
+ for (int ox = -half_w; ox <= half_w; ++ox) {
+ for (int oy = -half_w; oy <= half_w; ++oy) {
+ peak__put_pixel(x0 + ox, y0 + oy, color);
+ }
+ }
+ if (x0 == x1 && y0 == y1) break;
+ e2 = 2 * err;
+ if (e2 >= dy) { err += dy; x0 += sx; }
+ if (e2 <= dx) { err += dx; y0 += sy; }
+ }
+}
+
+void
+peak_draw_line_gradient(int x0, int y0, int x1, int y1, size_t width, uint32_t c0, uint32_t c1)
+{
+ float total_dist = sqrtf((float)((x1 - x0)*(x1 - x0) + (y1 - y0)*(y1 - y0)));
+ int dx = abs(x1 - x0), sx = x0 < x1 ? 1 : -1;
+ int dy = -abs(y1 - y0), sy = y0 < y1 ? 1 : -1;
+ int err = dx + dy, e2;
+
+ int orig_x0 = x0, orig_y0 = y0;
+ int half_w = (int)width / 2;
+
+ while (1) {
+ float current_dist = sqrtf((float)((x0 - orig_x0)*(x0 - orig_x0) + (y0 - orig_y0)*(y0 - orig_y0)));
+ float t = (total_dist > 0.0f) ? (current_dist / total_dist) : 0.0f;
+ uint32_t color = peak__lerp_color(c0, c1, t);
+
+ for (int ox = -half_w; ox <= half_w; ++ox) {
+ for (int oy = -half_w; oy <= half_w; ++oy) {
+ peak__put_pixel(x0 + ox, y0 + oy, color);
+ }
+ }
+
+ if (x0 == x1 && y0 == y1) break;
+ e2 = 2 * err;
+ if (e2 >= dy) { err += dy; x0 += sx; }
+ if (e2 <= dx) { err += dx; y0 += sy; }
+ }
+}
+
diff --git a/Peak/src/peak_header.h b/Peak/src/peak_header.h
new file mode 100644
index 0000000..9521abb
--- /dev/null
+++ b/Peak/src/peak_header.h
@@ -0,0 +1,283 @@
+/* ===========================================================================
+ * PEAK - Copyright @ Vasco Alves - See LICENSE at the end of file.
+ *
+ * Platform layer.
+ * It just works, don't think about it too much.
+ *
+ * =========================================================================== */
+
+#ifndef PEAK_H
+#define PEAK_H
+
+#define PEAK_MAJOR "0"
+#define PEAK_MINOR "1"
+#define PEAK_PATCH "1"
+
+/* CHANGE LOG
+ * 0.0.0 - @vasco - prototyping
+ * 0.1.0 - @vasco - linux x11 that automagically loads X11 DLL
+ * 0.1.1 - @vasco - fixed event handling on linux
+ *
+ * TODO: demo that stress tests the whole API
+ */
+
+#include <assert.h>
+#include <stdarg.h>
+#include <stdint.h>
+#include <stddef.h>
+#include <stdbool.h>
+
+#if !( \
+ (defined(__STDC__) && __STDC__ == 1 && defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L)\
+)
+#error "Peak requires C99."
+#endif
+
+/*
+ * Detecting a platform does not mean it's supported.
+ * Feel free to use these macros if you need them.
+ */
+#if defined(__wasm__) || defined(__wasm32__) || defined(__wasm64__) || defined(__EMSCRIPTEN__)
+ #define PEAK_WEB
+#elif defined(_WIN32) || defined(_WIN64) || defined(__WIN32__) || defined(__TOS_WIN__)
+ #define PEAK_WIN32
+ #ifndef WIN32_LEAN_AND_MEAN
+ #define WIN32_LEAN_AND_MEAN
+ #endif
+#elif defined(__APPLE__) || defined(__MACH__)
+ #include <TargetConditionals.h>
+ #define PEAK_APPLE
+ #if TARGET_OS_IPHONE
+ #define PEAK_IOS
+ #else
+ #define PEAK_MACOS
+ #endif
+#elif defined(__linux__)
+ #define PEAK_LINUX
+#elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__bsdi__) || defined(__DragonFly__)
+ #define PEAK_BSD
+#elif defined(__ANDROID__)
+ #define PEAK_ANDROID
+ #define PEAK_LINUX
+#elif defined(__linux__)
+ #define PEAK_LINUX
+#endif
+
+#if defined(PEAK_LINUX) || defined(PEAK_BSD) || defined(PEAK_APPLE)
+ #define PEAK_UNIX
+ #if !defined(PEAK_APPLE) && !defined(_POSIX_C_SOURCE)
+ #define _POSIX_C_SOURCE 200112L
+ #endif
+#endif
+
+#ifdef PEAK_WEB
+ #define PEAK static inline
+#else
+ #define PEAK extern
+#endif
+
+typedef enum {
+ PEAK_KEYMOD_ALT = 0,
+ PEAK_KEYMOD_SHIFT,
+ PEAK_KEYMOD_CTRL,
+ PEAK_KEYMOD_CAPS,
+} PeakKeyMod;
+
+typedef enum {
+ PEAK_KEY_UNKNOWN = 0,
+ PEAK_KEY_UP, PEAK_KEY_DOWN, PEAK_KEY_LEFT, PEAK_KEY_RIGHT,
+ PEAK_KEY_SPACE, PEAK_KEY_ESCAPE, PEAK_KEY_ENTER,
+ PEAK_KEY_A, PEAK_KEY_B, PEAK_KEY_C, PEAK_KEY_D, PEAK_KEY_E, PEAK_KEY_F, PEAK_KEY_G, PEAK_KEY_H, PEAK_KEY_I,
+ PEAK_KEY_J, PEAK_KEY_K, PEAK_KEY_L, PEAK_KEY_M, PEAK_KEY_N, PEAK_KEY_O, PEAK_KEY_P, PEAK_KEY_Q, PEAK_KEY_R,
+ PEAK_KEY_S, PEAK_KEY_T, PEAK_KEY_U, PEAK_KEY_V, PEAK_KEY_W, PEAK_KEY_X, PEAK_KEY_Y, PEAK_KEY_Z,
+} PeakKeyCode;
+
+typedef enum {
+ PEAK_EVENT_NONE = 0,
+ PEAK_EVENT_KEY_DOWN,
+ PEAK_EVENT_KEY_UP,
+ PEAK_EVENT_WINDOW_CLOSE,
+ PEAK_EVENT_WINDOW_RESIZE,
+ PEAK_EVENT_POINTER,
+ PEAK_EVENT_POINTER_CONNECTED,
+ PEAK_EVENT_POINTER_DISCONNECTED,
+ PEAK_EVENT_LAST
+} PeakEvenType;
+
+typedef enum {
+ PEAK_POINTER_MOVED = 0,
+ PEAK_POINTER_PRESSED,
+ PEAK_POINTER_RELEASED
+} PeakPointerState;
+
+typedef enum {
+ PEAK_POINTER_LEFT = 0,
+ PEAK_POINTER_RIGHT,
+ PEAK_POINTER_MIDDLE,
+ PEAK_POINTER_TOUCH,
+} PeakPointerType;
+
+typedef struct {
+ PeakEvenType type;
+ union {
+ struct { PeakKeyCode key; PeakKeyMod mod; } key;
+ struct { uint32_t width, height; } resize;
+ struct { PeakPointerState state; PeakPointerType type; float x, y; } pointer;
+ };
+} PeakEvent;
+
+/* Public API */
+PEAK void peak_init(void); // open a window and initialize graphics. called automatically if using peak_setup().
+PEAK void peak_quit(void); // close the window and release resources. called automatically if using peak_setup().
+PEAK bool peak_poll_events(PeakEvent *ev); // Poll the next event from the window queue. Returns true if an event was retrieved.
+PEAK void peak_extensions(void); // retrieve gpu window surface extensions for native api access (e.g., vulkan/opengl).
+PEAK void peak_blit(int offset_x, int offset_y, const uint32_t *rgba, size_t width, size_t height); // blit rgba pixels to the screen.
+PEAK void peak_clip(int x, int y, size_t w, size_t h); // restrict all subsequent rendering operations to this bounding rectangle.
+PEAK void peak_clip_reset(void); // reset clipping plane to window size.
+PEAK void peak_draw_rectangle(int x, int y, size_t w, size_t h, uint32_t color); // draw a solid-color filled rectangle.
+PEAK void peak_draw_rectangle_gradient(int x, int y, size_t w, size_t h, uint32_t c0, uint32_t c1, uint32_t c2, uint32_t c3); // fill rectangle interpolating four corner colors in clock-wise order.
+PEAK void peak_draw_triangle(int x0, int y0, int x1, int y1, int x2, int y2, uint32_t color); // draw a solid-color filled triangle.
+PEAK void peak_draw_triangle_gradient(int x0, int y0, int x1, int y1, int x2, int y2, uint32_t c0, uint32_t c1, uint32_t c2); // fill triangle with color interpolation clock-wise across its three vertices.
+PEAK void peak_draw_line(int x0, int y0, int x1, int y1, size_t width, uint32_t color); // draw a line between two points.
+PEAK void peak_draw_line_gradient(int x0, int y0, int x1, int y1, size_t width, uint32_t c0, uint32_t c1); // draw a line with a color gradient.
+
+/* Implemented by the platform */
+PEAK void peak_platform_window_open();
+PEAK void peak_platform_window_close();
+PEAK uint32_t *peak_platform_window_buffer(size_t *width, size_t *height);
+PEAK bool peak_platform_epoll(PeakEvent *ev);
+
+/*
+ * He was wipping up amazing foods, like making happiness.
+ * Actual happiness?
+ * Actual happiness and joy.
+ * Oh the smell, it was so divine.
+ * He was making happiness!?
+ * Happiness in the kettle!
+ */
+#ifdef PEAK_REPLACE_MAIN
+enum PeakReturn { PEAK_CONTINUE = 0, PEAK_STOP = 1 };
+extern int peak__main(int argc, char**argv);
+extern void peak_events(PeakEvent ev);
+extern void peak_tick();
+static bool running = true;
+static inline void peak_stop() { running = false; }
+#ifndef PEAK_WEB
+#define main(...)\
+main(int argc, char **argv) {\
+ assert(peak_events != 0 && "Declare peak_events() to handle window events.");\
+ assert(peak_tick != 0 && "Declare peak_tick() to handle each frame ticks.");\
+ peak_init();\
+ int ret = peak__main(argc, argv);\
+ if (ret != PEAK_CONTINUE) return ret;\
+ PeakEvent ev;\
+ while (running) {\
+ while (running && peak_poll_events(&ev)) {\
+ peak_events(ev);\
+ }\
+ peak_tick();\
+ }\
+ peak_quit();\
+}\
+int peak__main(__VA_ARGS__)
+#else
+#include <emscripten.h>
+/*
+ * He was wipping up agony in the kettle.
+ * Actual pain?
+ * Boiling hatred in the kettle.
+ * The smell, it's pain.
+ * Boiling anger!?
+ * Yes, boiling anger.
+ */
+
+static inline void
+peak__emscripten_loop_step(void *arg)
+{
+ (void)arg;
+ PeakEvent ev;
+ while (peak_poll_events(&ev)) {
+ peak_events(ev);
+ }
+
+ if (running) {
+ peak_tick();
+ } else {
+ emscripten_cancel_main_loop();
+ peak_quit();
+ }
+}
+
+#define main(...)\
+ main(int argc, char **argv) {\
+ _Static_assert(peak_events != 0, "When using peak_setup, declare peak_events() to handle window events.");\
+ _Static_assert(peak_tick != 0, "When using peak_setup, declare peak_tick() to handle frame ticks.");\
+ peak_init();\
+ int ret = peak__main(argc, argv);\
+ if (ret != PEAK_CONTINUE) return ret;\
+ emscripten_set_main_loop_arg(peak__emscripten_loop_step, NULL, 0, 1);\
+ return 0;\
+ }\
+ int peak__main(__VA_ARGS__)
+#endif
+#endif // PEAK_DONT_REPLACE_MAIN
+
+#endif // PEAK_H
+
+#ifdef PEAK_IMPLEMENTATION
+#undef PEAK_IMPLEMENTATION
+
+#if defined(PEAK_WIN32)
+#include "p_win32.c" // <REPLACE>
+#elif defined(PEAK_LINUX)
+#include "p_linux.c" // <REPLACE>
+#elif defined(PEAK_WEB)
+#include "p_emscripten.c" // <REPLACE>
+#endif
+
+#include "peak.c" // <REPLACE>
+
+#endif // PEAK_IMPLEMENTATION
+
+
+/*
+------------------------------------------------------------------------------
+This software is available under 2 licenses -- choose whichever you prefer.
+------------------------------------------------------------------------------
+ALTERNATIVE A - MIT License
+Copyright (c) 2026 Vasco Alves
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+of the Software, and to permit persons to whom the Software is furnished to do
+so, subject to the following conditions:
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+------------------------------------------------------------------------------
+ALTERNATIVE B - Public Domain (www.unlicense.org)
+This is free and unencumbered software released into the public domain.
+Anyone is free to copy, modify, publish, use, compile, sell, or distribute this
+software, either in source code form or as a compiled binary, for any purpose,
+commercial or non-commercial, and by any means.
+In jurisdictions that recognize copyright laws, the author or authors of this
+software dedicate any and all copyright interest in the software to the public
+domain. We make this dedication for the benefit of the public at large and to
+the detriment of our heirs and successors. We intend this dedication to be an
+overt act of relinquishment in perpetuity of all present and future rights to
+this software under copyright law.
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+------------------------------------------------------------------------------
+*/
diff --git a/Peak/src/peak_header.h.out b/Peak/src/peak_header.h.out
new file mode 100644
index 0000000..581aa74
--- /dev/null
+++ b/Peak/src/peak_header.h.out
@@ -0,0 +1,895 @@
+/* ===========================================================================
+ * PEAK - Copyright @ Vasco Alves - See LICENSE at the end of file.
+ *
+ * Platform layer.
+ * It just works, don't think about it too much.
+ *
+ * =========================================================================== */
+
+#ifndef PEAK_H
+#define PEAK_H
+
+#define PEAK_MAJOR "0"
+#define PEAK_MINOR "1"
+#define PEAK_PATCH "1"
+
+/* CHANGE LOG
+ * 0.0.0 - @vasco - prototyping
+ * 0.1.0 - @vasco - linux x11 that automagically loads X11 DLL
+ * 0.1.1 - @vasco - fixed event handling on linux
+ *
+ * TODO: demo that stress tests the whole API
+ */
+
+#include <assert.h>
+#include <stdarg.h>
+#include <stdint.h>
+#include <stddef.h>
+#include <stdbool.h>
+
+#if !( \
+ (defined(__STDC__) && __STDC__ == 1 && defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L)\
+)
+#error "Peak requires C99."
+#endif
+
+/*
+ * Detecting a platform does not mean it's supported.
+ * Feel free to use these macros if you need them.
+ */
+#if defined(__wasm__) || defined(__wasm32__) || defined(__wasm64__) || defined(__EMSCRIPTEN__)
+ #define PEAK_WEB
+#elif defined(_WIN32) || defined(_WIN64) || defined(__WIN32__) || defined(__TOS_WIN__)
+ #define PEAK_WIN32
+ #ifndef WIN32_LEAN_AND_MEAN
+ #define WIN32_LEAN_AND_MEAN
+ #endif
+#elif defined(__APPLE__) || defined(__MACH__)
+ #include <TargetConditionals.h>
+ #define PEAK_APPLE
+ #if TARGET_OS_IPHONE
+ #define PEAK_IOS
+ #else
+ #define PEAK_MACOS
+ #endif
+#elif defined(__linux__)
+ #define PEAK_LINUX
+#elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__bsdi__) || defined(__DragonFly__)
+ #define PEAK_BSD
+#elif defined(__ANDROID__)
+ #define PEAK_ANDROID
+ #define PEAK_LINUX
+#elif defined(__linux__)
+ #define PEAK_LINUX
+#endif
+
+#if defined(PEAK_LINUX) || defined(PEAK_BSD) || defined(PEAK_APPLE)
+ #define PEAK_UNIX
+ #if !defined(PEAK_APPLE) && !defined(_POSIX_C_SOURCE)
+ #define _POSIX_C_SOURCE 200112L
+ #endif
+#endif
+
+#ifdef PEAK_WEB
+ #define PEAK static inline
+#else
+ #define PEAK extern
+#endif
+
+typedef enum {
+ PEAK_KEYMOD_ALT = 0,
+ PEAK_KEYMOD_SHIFT,
+ PEAK_KEYMOD_CTRL,
+ PEAK_KEYMOD_CAPS,
+} PeakKeyMod;
+
+typedef enum {
+ PEAK_KEY_UNKNOWN = 0,
+ PEAK_KEY_UP, PEAK_KEY_DOWN, PEAK_KEY_LEFT, PEAK_KEY_RIGHT,
+ PEAK_KEY_SPACE, PEAK_KEY_ESCAPE, PEAK_KEY_ENTER,
+ PEAK_KEY_A, PEAK_KEY_B, PEAK_KEY_C, PEAK_KEY_D, PEAK_KEY_E, PEAK_KEY_F, PEAK_KEY_G, PEAK_KEY_H, PEAK_KEY_I,
+ PEAK_KEY_J, PEAK_KEY_K, PEAK_KEY_L, PEAK_KEY_M, PEAK_KEY_N, PEAK_KEY_O, PEAK_KEY_P, PEAK_KEY_Q, PEAK_KEY_R,
+ PEAK_KEY_S, PEAK_KEY_T, PEAK_KEY_U, PEAK_KEY_V, PEAK_KEY_W, PEAK_KEY_X, PEAK_KEY_Y, PEAK_KEY_Z,
+} PeakKeyCode;
+
+typedef enum {
+ PEAK_EVENT_NONE = 0,
+ PEAK_EVENT_KEY_DOWN,
+ PEAK_EVENT_KEY_UP,
+ PEAK_EVENT_WINDOW_CLOSE,
+ PEAK_EVENT_WINDOW_RESIZE,
+ PEAK_EVENT_POINTER,
+ PEAK_EVENT_POINTER_CONNECTED,
+ PEAK_EVENT_POINTER_DISCONNECTED,
+ PEAK_EVENT_LAST
+} PeakEvenType;
+
+typedef enum {
+ PEAK_POINTER_MOVED = 0,
+ PEAK_POINTER_PRESSED,
+ PEAK_POINTER_RELEASED
+} PeakPointerState;
+
+typedef enum {
+ PEAK_POINTER_LEFT = 0,
+ PEAK_POINTER_RIGHT,
+ PEAK_POINTER_MIDDLE,
+ PEAK_POINTER_TOUCH,
+} PeakPointerType;
+
+typedef struct {
+ PeakEvenType type;
+ union {
+ struct { PeakKeyCode key; PeakKeyMod mod; } key;
+ struct { uint32_t width, height; } resize;
+ struct { PeakPointerState state; PeakPointerType type; float x, y; } pointer;
+ };
+} PeakEvent;
+
+/* Public API */
+PEAK void peak_init(void); // open a window and initialize graphics. called automatically if using peak_setup().
+PEAK void peak_quit(void); // close the window and release resources. called automatically if using peak_setup().
+PEAK bool peak_poll_events(PeakEvent *ev); // Poll the next event from the window queue. Returns true if an event was retrieved.
+PEAK void peak_extensions(void); // retrieve gpu window surface extensions for native api access (e.g., vulkan/opengl).
+PEAK void peak_blit(int offset_x, int offset_y, const uint32_t *rgba, size_t width, size_t height); // blit rgba pixels to the screen.
+PEAK void peak_clip(int x, int y, size_t w, size_t h); // restrict all subsequent rendering operations to this bounding rectangle.
+PEAK void peak_clip_reset(void); // reset clipping plane to window size.
+PEAK void peak_draw_rectangle(int x, int y, size_t w, size_t h, uint32_t color); // draw a solid-color filled rectangle.
+PEAK void peak_draw_rectangle_gradient(int x, int y, size_t w, size_t h, uint32_t c0, uint32_t c1, uint32_t c2, uint32_t c3); // fill rectangle interpolating four corner colors in clock-wise order.
+PEAK void peak_draw_triangle(int x0, int y0, int x1, int y1, int x2, int y2, uint32_t color); // draw a solid-color filled triangle.
+PEAK void peak_draw_triangle_gradient(int x0, int y0, int x1, int y1, int x2, int y2, uint32_t c0, uint32_t c1, uint32_t c2); // fill triangle with color interpolation clock-wise across its three vertices.
+PEAK void peak_draw_line(int x0, int y0, int x1, int y1, size_t width, uint32_t color); // draw a line between two points.
+PEAK void peak_draw_line_gradient(int x0, int y0, int x1, int y1, size_t width, uint32_t c0, uint32_t c1); // draw a line with a color gradient.
+
+/* Implemented by the platform */
+PEAK void peak_platform_window_open();
+PEAK void peak_platform_window_close();
+PEAK uint32_t *peak_platform_window_buffer(size_t *width, size_t *height);
+PEAK bool peak_platform_epoll(PeakEvent *ev);
+
+/*
+ * He was wipping up amazing foods, like making happiness.
+ * Actual happiness?
+ * Actual happiness and joy.
+ * Oh the smell, it was so divine.
+ * He was making happiness!?
+ * Happiness in the kettle!
+ */
+#ifdef PEAK_REPLACE_MAIN
+enum PeakReturn { PEAK_CONTINUE = 0, PEAK_STOP = 1 };
+extern int peak__main(int argc, char**argv);
+extern void peak_events(PeakEvent ev);
+extern void peak_tick();
+static bool running = true;
+static inline void peak_stop() { running = false; }
+#ifndef PEAK_WEB
+#define main(...)\
+main(int argc, char **argv) {\
+ assert(peak_events != 0 && "Declare peak_events() to handle window events.");\
+ assert(peak_tick != 0 && "Declare peak_tick() to handle each frame ticks.");\
+ peak_init();\
+ int ret = peak__main(argc, argv);\
+ if (ret != PEAK_CONTINUE) return ret;\
+ PeakEvent ev;\
+ while (running) {\
+ while (running && peak_poll_events(&ev)) {\
+ peak_events(ev);\
+ }\
+ peak_tick();\
+ }\
+ peak_quit();\
+}\
+int peak__main(__VA_ARGS__)
+#else
+#include <emscripten.h>
+/*
+ * He was wipping up agony in the kettle.
+ * Actual pain?
+ * Boiling hatred in the kettle.
+ * The smell, it's pain.
+ * Boiling anger!?
+ * Yes, boiling anger.
+ */
+
+static inline void
+peak__emscripten_loop_step(void *arg)
+{
+ (void)arg;
+ PeakEvent ev;
+ while (peak_poll_events(&ev)) {
+ peak_events(ev);
+ }
+
+ if (running) {
+ peak_tick();
+ } else {
+ emscripten_cancel_main_loop();
+ peak_quit();
+ }
+}
+
+#define main(...)\
+ main(int argc, char **argv) {\
+ _Static_assert(peak_events != 0, "When using peak_setup, declare peak_events() to handle window events.");\
+ _Static_assert(peak_tick != 0, "When using peak_setup, declare peak_tick() to handle frame ticks.");\
+ peak_init();\
+ int ret = peak__main(argc, argv);\
+ if (ret != PEAK_CONTINUE) return ret;\
+ emscripten_set_main_loop_arg(peak__emscripten_loop_step, NULL, 0, 1);\
+ return 0;\
+ }\
+ int peak__main(__VA_ARGS__)
+#endif
+#endif // PEAK_DONT_REPLACE_MAIN
+
+#endif // PEAK_H
+
+#ifdef PEAK_IMPLEMENTATION
+#undef PEAK_IMPLEMENTATION
+
+#if defined(PEAK_WIN32)
+/* --- Start of p_win32.c --- */
+#include <windows.h>
+
+void
+peak_platform_window_open()
+{
+}
+
+void
+peak_platform_window_close()
+{
+}
+
+uint32_t*
+peak_platform_window_buffer(size_t *width, size_t *height)
+{
+}
+
+bool
+peak_platform_epoll(PeakEvent *ev)
+{
+}
+/* --- End of p_win32.c --- */
+#elif defined(PEAK_LINUX)
+/* --- Start of p_linux.c --- */
+#include <dlfcn.h>
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+#include <X11/Xatom.h>
+#include <X11/keysym.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define PEAK_X11_LINUX "/usr/lib/libX11.so.6"
+
+#define PEAK_LINUX_DEFAULT_WIDTH 800
+#define PEAK_LINUX_DEFAULT_HEIGHT 600
+
+typedef Display* (*XOpenDisplay_t)(const char*);
+typedef int (*XCloseDisplay_t)(Display*);
+typedef Window (*XCreateSimpleWindow_t)(Display*, Window, int, int, unsigned int, unsigned int, unsigned int, unsigned long, unsigned long);
+typedef int (*XStoreName_t)(Display*, Window, const char*);
+typedef Atom (*XInternAtom_t)(Display*, const char*, Bool);
+typedef Status (*XSetWMProtocols_t)(Display*, Window, Atom*, int);
+typedef int (*XSelectInput_t)(Display*, Window, long);
+typedef GC (*XCreateGC_t)(Display*, Window, unsigned long, XGCValues*);
+typedef XImage* (*XCreateImage_t)(Display*, Visual*, unsigned int, int, int, char*, unsigned int, unsigned int, int, int);
+typedef int (*XMapRaised_t)(Display*, Window);
+typedef int (*XFlush_t)(Display*);
+typedef int (*XFreeGC_t)(Display*, GC);
+typedef int (*XDestroyWindow_t)(Display*, Window);
+typedef int (*XPending_t)(Display*);
+typedef int (*XNextEvent_t)(Display*, XEvent*);
+typedef KeySym (*XLookupKeysym_t)(XKeyEvent*, int);
+typedef int (*XPutImage_t)(Display*, Drawable, GC, XImage*, int, int, int, int, unsigned int, unsigned int);
+typedef int (*XDefaultScreen_t)(Display*);
+typedef Window (*XRootWindow_t)(Display*, int);
+typedef unsigned long (*XBlackPixel_t)(Display*, int);
+typedef Visual* (*XDefaultVisual_t)(Display*, int);
+typedef int (*XDefaultDepth_t)(Display*, int);
+
+typedef struct {
+ XOpenDisplay_t XOpenDisplay;
+ XCloseDisplay_t XCloseDisplay;
+ XCreateSimpleWindow_t XCreateSimpleWindow;
+ XStoreName_t XStoreName;
+ XInternAtom_t XInternAtom;
+ XSetWMProtocols_t XSetWMProtocols;
+ XSelectInput_t XSelectInput;
+ XCreateGC_t XCreateGC;
+ XCreateImage_t XCreateImage;
+ XMapRaised_t XMapRaised;
+ XFlush_t XFlush;
+ XFreeGC_t XFreeGC;
+ XDestroyWindow_t XDestroyWindow;
+ XPending_t XPending;
+ XNextEvent_t XNextEvent;
+ XLookupKeysym_t XLookupKeysym;
+ XPutImage_t XPutImage;
+ XDefaultScreen_t XDefaultScreen;
+ XRootWindow_t XRootWindow;
+ XBlackPixel_t XBlackPixel;
+ XDefaultVisual_t XDefaultVisual;
+ XDefaultDepth_t XDefaultDepth;
+} PeakX11Api;
+
+static PeakX11Api peak_x11;
+
+static int peak_load_x11(void *handle) {
+ peak_x11.XOpenDisplay = (XOpenDisplay_t)dlsym(handle, "XOpenDisplay");
+ peak_x11.XCloseDisplay = (XCloseDisplay_t)dlsym(handle, "XCloseDisplay");
+ peak_x11.XCreateSimpleWindow = (XCreateSimpleWindow_t)dlsym(handle, "XCreateSimpleWindow");
+ peak_x11.XStoreName = (XStoreName_t)dlsym(handle, "XStoreName");
+ peak_x11.XInternAtom = (XInternAtom_t)dlsym(handle, "XInternAtom");
+ peak_x11.XSetWMProtocols = (XSetWMProtocols_t)dlsym(handle, "XSetWMProtocols");
+ peak_x11.XSelectInput = (XSelectInput_t)dlsym(handle, "XSelectInput");
+ peak_x11.XCreateGC = (XCreateGC_t)dlsym(handle, "XCreateGC");
+ peak_x11.XCreateImage = (XCreateImage_t)dlsym(handle, "XCreateImage");
+ peak_x11.XMapRaised = (XMapRaised_t)dlsym(handle, "XMapRaised");
+ peak_x11.XFlush = (XFlush_t)dlsym(handle, "XFlush");
+ peak_x11.XFreeGC = (XFreeGC_t)dlsym(handle, "XFreeGC");
+ peak_x11.XDestroyWindow = (XDestroyWindow_t)dlsym(handle, "XDestroyWindow");
+ peak_x11.XPending = (XPending_t)dlsym(handle, "XPending");
+ peak_x11.XNextEvent = (XNextEvent_t)dlsym(handle, "XNextEvent");
+ peak_x11.XLookupKeysym = (XLookupKeysym_t)dlsym(handle, "XLookupKeysym");
+ peak_x11.XPutImage = (XPutImage_t)dlsym(handle, "XPutImage");
+ peak_x11.XDefaultScreen = (XDefaultScreen_t)dlsym(handle, "XDefaultScreen");
+ peak_x11.XRootWindow = (XRootWindow_t)dlsym(handle, "XRootWindow");
+ peak_x11.XBlackPixel = (XBlackPixel_t)dlsym(handle, "XBlackPixel");
+ peak_x11.XDefaultVisual = (XDefaultVisual_t)dlsym(handle, "XDefaultVisual");
+ peak_x11.XDefaultDepth = (XDefaultDepth_t)dlsym(handle, "XDefaultDepth");
+
+ if (!peak_x11.XOpenDisplay || !peak_x11.XCloseDisplay || !peak_x11.XCreateSimpleWindow ||
+ !peak_x11.XStoreName || !peak_x11.XInternAtom || !peak_x11.XSetWMProtocols ||
+ !peak_x11.XSelectInput || !peak_x11.XCreateGC || !peak_x11.XCreateImage ||
+ !peak_x11.XMapRaised || !peak_x11.XFlush ||
+ !peak_x11.XFreeGC || !peak_x11.XDestroyWindow || !peak_x11.XPending ||
+ !peak_x11.XNextEvent || !peak_x11.XLookupKeysym || !peak_x11.XPutImage ||
+ !peak_x11.XDefaultScreen || !peak_x11.XRootWindow || !peak_x11.XBlackPixel ||
+ !peak_x11.XDefaultVisual || !peak_x11.XDefaultDepth) {
+ return 0;
+ }
+ return 1;
+}
+
+
+typedef struct {
+ Display *display;
+ Atom wm_delete_window;
+ bool initialized;
+} PeakLinux;
+
+typedef struct {
+ Window window;
+ GC gfx_ctx; /* GRAPHICS CONTEXT, not garbage collector lol */
+} PeakLinuxWindow;
+
+static PeakLinux peak_linux = {0};
+static PeakLinuxWindow peak_linux_window = {0};
+static XImage *peak_linux_ximage = NULL;
+static uint32_t *peak_linux_buffer = NULL;
+static size_t peak_linux_width = PEAK_LINUX_DEFAULT_WIDTH;
+static size_t peak_linux_height = PEAK_LINUX_DEFAULT_HEIGHT;
+
+static PeakKeyCode
+peak__x11_map_key(KeySym sym)
+{
+ if (sym >= XK_a && sym <= XK_z) return (PeakKeyCode)(PEAK_KEY_A + (int)(sym - XK_a));
+ if (sym >= XK_A && sym <= XK_Z) return (PeakKeyCode)(PEAK_KEY_A + (int)(sym - XK_A));
+ switch (sym) {
+ case XK_Up: return PEAK_KEY_UP;
+ case XK_Down: return PEAK_KEY_DOWN;
+ case XK_Left: return PEAK_KEY_LEFT;
+ case XK_Right: return PEAK_KEY_RIGHT;
+ case XK_space: return PEAK_KEY_SPACE;
+ case XK_Escape: return PEAK_KEY_ESCAPE;
+ case XK_Return: return PEAK_KEY_ENTER;
+ default: return PEAK_KEY_UNKNOWN;
+ }
+}
+
+static PeakKeyMod
+peak__x11_map_mod(unsigned int state)
+{
+ if (state & ControlMask) return PEAK_KEYMOD_CTRL;
+ if (state & Mod1Mask) return PEAK_KEYMOD_ALT;
+ if (state & ShiftMask) return PEAK_KEYMOD_SHIFT;
+ if (state & LockMask) return PEAK_KEYMOD_CAPS;
+ return (PeakKeyMod)0;
+}
+
+void
+peak_platform_window_open()
+{
+ void *x11_handle = dlopen(PEAK_X11_LINUX, RTLD_LOCAL | RTLD_NOW);
+ assert(x11_handle && "Failed to load X11 library. What system are you fucking using and abusing?");
+
+ int success = peak_load_x11(x11_handle);
+ assert(success && "Failed to open X11 display");
+
+ peak_linux.display = peak_x11.XOpenDisplay(NULL);
+ assert(peak_linux.display && "Failed to open X11 display");
+
+ /* Who design this API??? */
+ int screen = DefaultScreen(peak_linux.display);
+ peak_linux_window.window = peak_x11.XCreateSimpleWindow(peak_linux.display, RootWindow(peak_linux.display, screen), 0, 0, peak_linux_width, peak_linux_height, 0, BlackPixel(peak_linux.display, screen), BlackPixel(peak_linux.display, screen));
+ peak_x11.XStoreName(peak_linux.display, peak_linux_window.window, "Peak");
+ peak_linux.wm_delete_window = peak_x11.XInternAtom(peak_linux.display, "WM_DELETE_WINDOW", False);
+ peak_x11.XSetWMProtocols(peak_linux.display, peak_linux_window.window, &peak_linux.wm_delete_window, 1);
+ peak_x11.XSelectInput(peak_linux.display, peak_linux_window.window, ExposureMask | KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask | PointerMotionMask | StructureNotifyMask);
+ peak_linux_window.gfx_ctx = peak_x11.XCreateGC(peak_linux.display, peak_linux_window.window, 0, NULL);
+ peak_linux_buffer = (uint32_t *)calloc(peak_linux_width * peak_linux_height, sizeof(uint32_t));
+ assert(peak_linux_buffer && "Failed to allocate framebuffer");
+
+ /* Wrap the buffer in an XImage for XPutImage blitting */
+ Visual *visual = DefaultVisual(peak_linux.display, screen);
+ int depth = DefaultDepth(peak_linux.display, screen);
+
+ peak_linux_ximage = peak_x11.XCreateImage(peak_linux.display, visual, depth, ZPixmap, 0, (char *)peak_linux_buffer, peak_linux_width, peak_linux_height, 32, 0);
+ assert(peak_linux_ximage && "Failed to create XImage");
+
+ peak_x11.XMapRaised(peak_linux.display, peak_linux_window.window);
+ peak_x11.XFlush(peak_linux.display);
+
+ peak_linux.initialized = true;
+}
+
+void
+peak_platform_window_close()
+{
+ if (!peak_linux.initialized) return;
+
+ if (peak_linux_ximage) {
+ peak_linux_ximage->data = NULL;
+ XDestroyImage(peak_linux_ximage);
+ peak_linux_ximage = NULL;
+ }
+
+ free(peak_linux_buffer);
+ peak_linux_buffer = NULL;
+
+ peak_x11.XFreeGC(peak_linux.display, peak_linux_window.gfx_ctx);
+ peak_x11.XDestroyWindow(peak_linux.display, peak_linux_window.window);
+ peak_x11.XCloseDisplay(peak_linux.display);
+
+ peak_linux.initialized = false;
+}
+
+uint32_t *
+peak_platform_window_buffer(size_t *width, size_t *height)
+{
+ *width = peak_linux_width;
+ *height = peak_linux_height;
+ return peak_linux_buffer;
+}
+
+bool
+peak_platform_epoll(PeakEvent *ev)
+{
+ if (!peak_linux.initialized) return false;
+
+ Display *dpy = peak_linux.display;
+
+ while (peak_x11.XPending(dpy) > 0) {
+ XEvent xev;
+ peak_x11.XNextEvent(dpy, &xev);
+
+ switch (xev.type) {
+
+ case ClientMessage:
+ if ((Atom)xev.xclient.data.l[0] == peak_linux.wm_delete_window) {
+ ev->type = PEAK_EVENT_WINDOW_CLOSE;
+ printf("CLLOOOOOOOSEEEE");
+ return true;
+ }
+ continue;
+
+ case KeyPress:
+ case KeyRelease: {
+ KeySym sym = peak_x11.XLookupKeysym(&xev.xkey, 0);
+ ev->type = (xev.type == KeyPress) ? PEAK_EVENT_KEY_DOWN : PEAK_EVENT_KEY_UP;
+ ev->key.key = peak__x11_map_key(sym);
+ ev->key.mod = peak__x11_map_mod(xev.xkey.state);
+ return true;
+ }
+
+ case ButtonPress:
+ case ButtonRelease: {
+ ev->type = PEAK_EVENT_POINTER;
+ ev->pointer.state = (xev.type == ButtonPress) ? PEAK_POINTER_PRESSED : PEAK_POINTER_RELEASED;
+ ev->pointer.x = (float)xev.xbutton.x;
+ ev->pointer.y = (float)xev.xbutton.y;
+ switch (xev.xbutton.button) {
+ case Button1: ev->pointer.type = PEAK_POINTER_LEFT; break;
+ case Button2: ev->pointer.type = PEAK_POINTER_MIDDLE; break;
+ case Button3: ev->pointer.type = PEAK_POINTER_RIGHT; break;
+ default: ev->pointer.type = PEAK_POINTER_LEFT; break;
+ }
+ return true;
+ }
+
+ case MotionNotify:
+ ev->type = PEAK_EVENT_POINTER;
+ ev->pointer.state = PEAK_POINTER_MOVED;
+ ev->pointer.x = (float)xev.xmotion.x;
+ ev->pointer.y = (float)xev.xmotion.y;
+ if (xev.xmotion.state & Button3Mask)
+ ev->pointer.type = PEAK_POINTER_RIGHT;
+ else if (xev.xmotion.state & Button2Mask)
+ ev->pointer.type = PEAK_POINTER_MIDDLE;
+ else
+ ev->pointer.type = PEAK_POINTER_LEFT;
+ return true;
+
+ case ConfigureNotify:
+ if ((size_t)xev.xconfigure.width != peak_linux_width ||
+ (size_t)xev.xconfigure.height != peak_linux_height) {
+ ev->type = PEAK_EVENT_WINDOW_RESIZE;
+ ev->resize.width = (uint32_t)xev.xconfigure.width;
+ ev->resize.height = (uint32_t)xev.xconfigure.height;
+ return true;
+ }
+ continue;
+
+ case Expose:
+ if (xev.xexpose.count == 0) {
+ peak_x11.XPutImage(dpy, peak_linux_window.window, peak_linux_window.gfx_ctx, peak_linux_ximage, 0, 0, 0, 0, peak_linux_width, peak_linux_height);
+ }
+ continue;
+
+ default:
+ continue;
+ }
+ }
+
+ peak_x11.XPutImage(dpy, peak_linux_window.window, peak_linux_window.gfx_ctx, peak_linux_ximage, 0, 0, 0, 0, peak_linux_width, peak_linux_height);
+ peak_x11.XFlush(dpy);
+ return false;
+}
+/* --- End of p_linux.c --- */
+#elif defined(PEAK_WEB)
+/* --- Start of p_emscripten.c --- */
+#include <stdlib.h>
+#include <string.h>
+#include <stdbool.h>
+
+#define PEAK_CANVAS "#PeakCanvas"
+
+static PeakKeyCode map_key(const char *code);
+static PeakKeyMod map_mod(const EmscriptenKeyboardEvent *keyEvent);
+static EM_BOOL key_callback(int eventType, const EmscriptenKeyboardEvent *keyEvent, void *userData);
+static EM_BOOL mouse_callback(int eventType, const EmscriptenMouseEvent *mouseEvent, void *userData);
+static EM_BOOL resize_callback(int eventType, const EmscriptenUiEvent *uiEvent, void *userData);
+
+void
+peak_platform_window_open()
+{
+ emscripten_set_keydown_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, NULL, EM_TRUE, key_callback);
+ emscripten_set_keyup_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, NULL, EM_TRUE, key_callback);
+ emscripten_set_mousedown_callback(PEAK_CANVAS, NULL, EM_TRUE, mouse_callback);
+ emscripten_set_mouseup_callback(PEAK_CANVAS, NULL, EM_TRUE, mouse_callback);
+ emscripten_set_mousemove_callback(PEAK_CANVAS, NULL, EM_TRUE, mouse_callback);
+ emscripten_set_resize_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, NULL, EM_TRUE, resize_callback);
+}
+
+void
+peak_platform_window_close()
+{
+}
+
+uint32_t*
+peak_platform_window_buffer(size_t *width, size_t *height)
+{
+}
+
+bool
+peak_platform_epoll(PeakEvent *ev)
+{
+ return 0;
+}
+/* --- End of p_emscripten.c --- */
+#endif
+
+/* --- Start of peak.c --- */
+static inline void peak__put_pixel(int x, int y, uint32_t color);
+static inline uint32_t peak__lerp_color(uint32_t c0, uint32_t c1, float t);
+static inline float peak__edge_cross(float ax, float ay, float bx, float by, float cx, float cy);
+
+static uint32_t *peak_window_buffer;
+static size_t peak_window_width;
+static size_t peak_window_height;
+static int peak_clip_x;
+static int peak_clip_y;
+static size_t peak_clip_width;
+static size_t peak_clip_height;
+
+void
+peak__put_pixel(int x, int y, uint32_t color)
+{
+ if (x < peak_clip_x || x >= (int)(peak_clip_x + peak_clip_width) ||
+ y < peak_clip_y || y >= (int)(peak_clip_y + peak_clip_height)) {
+ return;
+ }
+ if (x < 0 || x >= (int)peak_window_width || y < 0 || y >= (int)peak_window_height) {
+ return;
+ }
+ peak_window_buffer[y * peak_window_width + x] = color;
+}
+
+uint32_t
+peak__lerp_color(uint32_t c0, uint32_t c1, float t)
+{
+ if (t <= 0.0f) return c0;
+ if (t >= 1.0f) return c1;
+
+ uint32_t a0 = (c0 >> 24) & 0xFF, a1 = (c1 >> 24) & 0xFF;
+ uint32_t r0 = (c0 >> 16) & 0xFF, r1 = (c1 >> 16) & 0xFF;
+ uint32_t g0 = (c0 >> 8) & 0xFF, g1 = (c1 >> 8) & 0xFF;
+ uint32_t b0 = c0 & 0xFF, b1 = c1 & 0xFF;
+
+ uint32_t a = (uint32_t)(a0 + t * ((float)a1 - (float)a0));
+ uint32_t r = (uint32_t)(r0 + t * ((float)r1 - (float)r0));
+ uint32_t g = (uint32_t)(g0 + t * ((float)g1 - (float)g0));
+ uint32_t b = (uint32_t)(b0 + t * ((float)b1 - (float)b0));
+
+ return (a << 24) | (r << 16) | (g << 8) | b;
+}
+
+float
+peak__edge_cross(float ax, float ay, float bx, float by, float cx, float cy)
+{
+ return (cx - ax) * (by - ay) - (cy - ay) * (bx - ax);
+}
+
+void
+peak_init(void)
+{
+ peak_platform_window_open();
+ peak_window_buffer = peak_platform_window_buffer(&peak_window_width, &peak_window_height);
+ peak_clip_x = 0;
+ peak_clip_y = 0;
+ peak_clip_width = peak_window_width;
+ peak_clip_height = peak_window_height;
+}
+
+void
+peak_quit(void)
+{
+ peak_platform_window_close();
+}
+
+void
+peak_extensions(void)
+{
+ // TODO
+}
+
+bool
+peak_poll_events(PeakEvent *ev)
+{
+ return peak_platform_epoll(ev);
+}
+
+void
+peak_blit(int offset_x, int offset_y, const uint32_t *rgba, size_t width, size_t height)
+{
+ for (size_t y = 0; y < height; ++y) {
+ int target_y = offset_y + (int)y;
+ if (target_y < peak_clip_y || target_y >= (int)(peak_clip_y + peak_clip_height) ||
+ target_y < 0 || target_y >= (int)peak_window_height) continue;
+
+ int start_x = offset_x < peak_clip_x ? peak_clip_x : offset_x;
+ int end_x = (offset_x + (int)width) > (int)(peak_clip_x + peak_clip_width)
+ ? (int)(peak_clip_x + peak_clip_width)
+ : (offset_x + (int)width);
+
+ if (start_x >= end_x) continue;
+
+ size_t src_offset_x = (size_t)(start_x - offset_x);
+ size_t copy_pixels = (size_t)(end_x - start_x);
+
+ memcpy(&peak_window_buffer[target_y * peak_window_width + start_x], &rgba[y * width + src_offset_x], copy_pixels * sizeof(uint32_t));
+ }
+}
+
+void
+peak_clip(int x, int y, size_t w, size_t h)
+{
+ peak_clip_x = x;
+ peak_clip_y = y;
+ peak_clip_width = w;
+ peak_clip_height = h;
+}
+
+void
+peak_clip_reset(void)
+{
+ peak_clip_x = 0;
+ peak_clip_y = 0;
+ peak_clip_width = peak_window_width;
+ peak_clip_height = peak_window_height;
+}
+
+void
+peak_draw_rectangle(int x, int y, size_t w, size_t h, uint32_t color)
+{
+ int start_x = (x < peak_clip_x) ? peak_clip_x : x;
+ int start_y = (y < peak_clip_y) ? peak_clip_y : y;
+ int end_x = (x + (int)w > (int)(peak_clip_x + peak_clip_width)) ? (int)(peak_clip_x + peak_clip_width) : x + (int)w;
+ int end_y = (y + (int)h > (int)(peak_clip_y + peak_clip_height)) ? (int)(peak_clip_y + peak_clip_height) : y + (int)h;
+
+ for (int py = start_y; py < end_y; ++py) {
+ if (py < 0 || py >= (int)peak_window_height) continue;
+ for (int px = start_x; px < end_x; ++px) {
+ if (px < 0 || px >= (int)peak_window_width) continue;
+ peak_window_buffer[py * peak_window_width + px] = color;
+ }
+ }
+}
+
+void
+peak_draw_rectangle_gradient(int x, int y, size_t w, size_t h, uint32_t c0, uint32_t c1, uint32_t c2, uint32_t c3)
+{
+ for (size_t ry = 0; ry < h; ++ry) {
+ float ty = (h > 1) ? (float)ry / (float)(h - 1) : 0.0f;
+ uint32_t left_color = peak__lerp_color(c0, c3, ty);
+ uint32_t right_color = peak__lerp_color(c1, c2, ty);
+
+ for (size_t rx = 0; rx < w; ++rx) {
+ float tx = (w > 1) ? (float)rx / (float)(w - 1) : 0.0f;
+ uint32_t final_color = peak__lerp_color(left_color, right_color, tx);
+ peak__put_pixel(x + (int)rx, y + (int)ry, final_color);
+ }
+ }
+}
+
+void
+peak_draw_triangle(int x0, int y0, int x1, int y1, int x2, int y2, uint32_t color)
+{
+ int min_x = (x0 < x1) ? ((x0 < x2) ? x0 : x2) : ((x1 < x2) ? x1 : x2);
+ int max_x = (x0 > x1) ? ((x0 > x2) ? x0 : x2) : ((x1 > x2) ? x1 : x2);
+ int min_y = (y0 < y1) ? ((y0 < y2) ? y0 : y2) : ((y1 < y2) ? y1 : y2);
+ int max_y = (y0 > y1) ? ((y0 > y2) ? y0 : y2) : ((y1 > y2) ? y1 : y2);
+
+ float area = peak__edge_cross((float)x0, (float)y0, (float)x1, (float)y1, (float)x2, (float)y2);
+ if (area == 0.0f) return;
+
+ for (int y = min_y; y <= max_y; ++y) {
+ for (int x = min_x; x <= max_x; ++x) {
+ float w0 = peak__edge_cross((float)x1, (float)y1, (float)x2, (float)y2, (float)x, (float)y);
+ float w1 = peak__edge_cross((float)x2, (float)y2, (float)x0, (float)y0, (float)x, (float)y);
+ float w2 = peak__edge_cross((float)x0, (float)y0, (float)x1, (float)y1, (float)x, (float)y);
+
+ if ((w0 >= 0 && w1 >= 0 && w2 >= 0) || (w0 <= 0 && w1 <= 0 && w2 <= 0)) {
+ peak__put_pixel(x, y, color);
+ }
+ }
+ }
+}
+
+void
+peak_draw_triangle_gradient(int x0, int y0, int x1, int y1, int x2, int y2, uint32_t c0, uint32_t c1, uint32_t c2)
+{
+ int min_x = (x0 < x1) ? ((x0 < x2) ? x0 : x2) : ((x1 < x2) ? x1 : x2);
+ int max_x = (x0 > x1) ? ((x0 > x2) ? x0 : x2) : ((x1 > x2) ? x1 : x2);
+ int min_y = (y0 < y1) ? ((y0 < y2) ? y0 : y2) : ((y1 < y2) ? y1 : y2);
+ int max_y = (y0 > y1) ? ((y0 > y2) ? y0 : y2) : ((y1 > y2) ? y1 : y2);
+
+ float area = peak__edge_cross((float)x0, (float)y0, (float)x1, (float)y1, (float)x2, (float)y2);
+ if (area == 0.0f) return;
+
+ for (int y = min_y; y <= max_y; ++y) {
+ for (int x = min_x; x <= max_x; ++x) {
+ float w0 = peak__edge_cross((float)x1, (float)y1, (float)x2, (float)y2, (float)x, (float)y) / area;
+ float w1 = peak__edge_cross((float)x2, (float)y2, (float)x0, (float)y0, (float)x, (float)y) / area;
+ float w2 = peak__edge_cross((float)x0, (float)y0, (float)x1, (float)y1, (float)x, (float)y) / area;
+
+ if (w0 >= 0.0f && w1 >= 0.0f && w2 >= 0.0f) {
+ uint32_t col_a = peak__lerp_color(c0, c1, w1 / (w0 + w1 + 1e-6f));
+ uint32_t final_color = peak__lerp_color(col_a, c2, w2);
+ peak__put_pixel(x, y, final_color);
+ }
+ }
+ }
+}
+
+void
+peak_draw_line(int x0, int y0, int x1, int y1, size_t width, uint32_t color)
+{
+ int dx = abs(x1 - x0), sx = x0 < x1 ? 1 : -1;
+ int dy = -abs(y1 - y0), sy = y0 < y1 ? 1 : -1;
+ int err = dx + dy, e2;
+
+ int half_w = (int)width / 2;
+
+ while (1) {
+ /* Draw square footprint for line thickness */
+ for (int ox = -half_w; ox <= half_w; ++ox) {
+ for (int oy = -half_w; oy <= half_w; ++oy) {
+ peak__put_pixel(x0 + ox, y0 + oy, color);
+ }
+ }
+ if (x0 == x1 && y0 == y1) break;
+ e2 = 2 * err;
+ if (e2 >= dy) { err += dy; x0 += sx; }
+ if (e2 <= dx) { err += dx; y0 += sy; }
+ }
+}
+
+void
+peak_draw_line_gradient(int x0, int y0, int x1, int y1, size_t width, uint32_t c0, uint32_t c1)
+{
+ float total_dist = sqrtf((float)((x1 - x0)*(x1 - x0) + (y1 - y0)*(y1 - y0)));
+ int dx = abs(x1 - x0), sx = x0 < x1 ? 1 : -1;
+ int dy = -abs(y1 - y0), sy = y0 < y1 ? 1 : -1;
+ int err = dx + dy, e2;
+
+ int orig_x0 = x0, orig_y0 = y0;
+ int half_w = (int)width / 2;
+
+ while (1) {
+ float current_dist = sqrtf((float)((x0 - orig_x0)*(x0 - orig_x0) + (y0 - orig_y0)*(y0 - orig_y0)));
+ float t = (total_dist > 0.0f) ? (current_dist / total_dist) : 0.0f;
+ uint32_t color = peak__lerp_color(c0, c1, t);
+
+ for (int ox = -half_w; ox <= half_w; ++ox) {
+ for (int oy = -half_w; oy <= half_w; ++oy) {
+ peak__put_pixel(x0 + ox, y0 + oy, color);
+ }
+ }
+
+ if (x0 == x1 && y0 == y1) break;
+ e2 = 2 * err;
+ if (e2 >= dy) { err += dy; x0 += sx; }
+ if (e2 <= dx) { err += dx; y0 += sy; }
+ }
+}
+
+/* --- End of peak.c --- */
+
+#endif // PEAK_IMPLEMENTATION
+
+
+/*
+------------------------------------------------------------------------------
+This software is available under 2 licenses -- choose whichever you prefer.
+------------------------------------------------------------------------------
+ALTERNATIVE A - MIT License
+Copyright (c) 2026 Vasco Alves
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+of the Software, and to permit persons to whom the Software is furnished to do
+so, subject to the following conditions:
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+------------------------------------------------------------------------------
+ALTERNATIVE B - Public Domain (www.unlicense.org)
+This is free and unencumbered software released into the public domain.
+Anyone is free to copy, modify, publish, use, compile, sell, or distribute this
+software, either in source code form or as a compiled binary, for any purpose,
+commercial or non-commercial, and by any means.
+In jurisdictions that recognize copyright laws, the author or authors of this
+software dedicate any and all copyright interest in the software to the public
+domain. We make this dedication for the benefit of the public at large and to
+the detriment of our heirs and successors. We intend this dedication to be an
+overt act of relinquishment in perpetuity of all present and future rights to
+this software under copyright law.
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+------------------------------------------------------------------------------
+*/
diff --git a/Podium/README.md b/Podium/README.md
new file mode 100644
index 0000000..fccb70d
--- /dev/null
+++ b/Podium/README.md
@@ -0,0 +1,9 @@
+# Podium
+
+Single header platform library with batteries included.
+
+NOTE TO SELF: Stop trying to redesign your own library!
+This shit works! Podium stands on business!!!
+
+The library does it's best to auto-detect your operating system
+and the include the correct OS code for that platform.
diff --git a/Podium/p_allocators.c b/Podium/p_allocators.c
new file mode 100644
index 0000000..7e59807
--- /dev/null
+++ b/Podium/p_allocators.c
@@ -0,0 +1,301 @@
+PODEF bool
+is_power_of_two(uintptr x) {
+ return (x & (x-1)) == 0;
+}
+
+PODEF uintptr
+align_forward(uintptr ptr, usize align)
+{
+ uintptr p, a, remainder;
+ assert(is_power_of_two(align));
+
+ p = ptr;
+ a = (uintptr)align;
+ remainder = p & (a-1);
+
+ return (remainder != 0) ? p + a - remainder : p;
+}
+
+PODEF void
+p_arena_create(Arena *a, void *backing_buffer, usize backing_buffer_length)
+{
+ a->buf = (unsigned char *)backing_buffer;
+ a->buf_len = backing_buffer_length;
+ a->curr_offset = 0;
+ a->prev_offset = 0;
+}
+
+PODEF void*
+p_arena_alloc_align(Arena *a, usize s, usize align)
+{
+
+ // Align 'curr_offset' forward to the specified alignment
+ uintptr curr_ptr = (uintptr)a->buf + (uintptr)a->curr_offset;
+ uintptr offset = align_forward(curr_ptr, align);
+ offset -= (uintptr)a->buf; // Change to relative offset
+
+ // Check to see if the backing memory has space left
+ if (offset+s <= a->buf_len) {
+ void *ptr = &a->buf[offset];
+ a->prev_offset = offset;
+ a->curr_offset = offset+s;
+
+ memset(ptr, 0, s);
+ return ptr;
+ }
+
+ return NULL;
+}
+
+PODEF void*
+p_arena_alloc(Arena *a, usize s) {
+ return p_arena_alloc_align(a, s, DEFAULT_ALIGNMENT);
+}
+
+PODEF void*
+p_arena_resize_align(Arena *a, void *old_memory, usize old_size, usize new_size, usize align)
+{
+ assert(is_power_of_two(align));
+ unsigned char *old_mem = (unsigned char *)old_memory;
+
+ if (old_mem == NULL || old_size == 0) {
+ return p_arena_alloc_align(a, new_size, align);
+ } else if (a->buf <= old_mem && old_mem < a->buf+a->buf_len) {
+ if (a->buf+a->prev_offset == old_mem) {
+ a->curr_offset = a->prev_offset + new_size;
+ if (new_size > old_size) {
+ // Zero the new memory by default
+ memset(&a->buf[a->curr_offset], 0, new_size-old_size);
+ }
+ return old_memory;
+ } else {
+ void *new_memory = p_arena_alloc_align(a, new_size, align);
+ size_t copy_size = old_size < new_size ? old_size : new_size;
+ memmove(new_memory, old_memory, copy_size);
+ return new_memory;
+ }
+
+ } else {
+ assert(0 && "Memory is out of bounds of the buffer in this arena");
+ return NULL;
+ }
+}
+
+PODEF void*
+p_arena_resize(Arena *a, void *old_memory, usize old_size, usize new_size)
+{
+ return p_arena_resize_align(a, old_memory, old_size, new_size, DEFAULT_ALIGNMENT);
+}
+
+PODEF void
+p_arena_free_all(Arena *a)
+{
+ a->curr_offset = 0;
+ a->prev_offset = 0;
+}
+
+PODEF void
+p_arena_destroy(Arena* a)
+{
+ a->buf_len = 0;
+ a->curr_offset = 0;
+ a->prev_offset = 0;
+}
+
+PODEF void
+p_stack_create(Stack *s, void *backing_buffer, usize backing_buffer_length)
+{
+ s->buf = (unsigned char*) backing_buffer;
+ s->buf_len = backing_buffer_length;
+ s->offset = 0;
+}
+
+PODEF usize
+calc_padding_with_header(uintptr ptr, uintptr alignment, usize header_size)
+{
+ uintptr p, a, modulo, padding, needed_space;
+
+ assert(is_power_of_two(alignment));
+
+ p = ptr;
+ a = alignment;
+ modulo = p & (a-1); // (p % a) as it assumes alignment is a power of two
+
+ padding = 0;
+ needed_space = 0;
+
+ if (modulo != 0) { // Same logic as 'align_forward'
+ padding = a - modulo;
+ }
+
+ needed_space = (uintptr)header_size;
+
+ if (padding < needed_space) {
+ needed_space -= padding;
+
+ if ((needed_space & (a-1)) != 0) {
+ padding += a * (1+(needed_space/a));
+ } else {
+ padding += a * (needed_space/a);
+ }
+ }
+
+ return (usize)padding;
+}
+
+PODEF void*
+p_stack_alloc(Stack *s, usize len, usize alignment)
+{
+ uintptr curr_addr, next_addr;
+ usize padding;
+ Stack_Allocation_Header *header;
+
+ assert(is_power_of_two(alignment));
+
+ if (alignment > 128) {
+ // As the padding is 8 bits (1 byte), the largest alignment that can
+ // be used is 128 bytes
+ alignment = 128;
+ }
+
+ curr_addr = (uintptr)s->buf + (uintptr)s->offset;
+ padding = calc_padding_with_header(curr_addr, (uintptr)alignment, sizeof(Stack_Allocation_Header));
+ if (s->offset + padding + len > s->buf_len) {
+ // Stack allocator is out of memory
+ return NULL;
+ }
+ s->offset += padding;
+
+ next_addr = curr_addr + (uintptr)padding;
+ header = (Stack_Allocation_Header *)(next_addr - sizeof(Stack_Allocation_Header));
+ header->padding = (u8)padding;
+
+ s->offset += len;
+
+ return memset((void *)next_addr, 0, len);
+}
+
+PODEF void
+p_stack_free(Stack *s, void *ptr)
+{
+ if (ptr != NULL) {
+ uintptr start, end, curr_addr;
+ Stack_Allocation_Header *header;
+ usize prev_offset;
+
+ start = (uintptr)s->buf;
+ end = start + (uintptr)s->buf_len;
+ curr_addr = (uintptr)ptr;
+
+ if (!(start <= curr_addr && curr_addr < end)) {
+ assert(0 && "Out of bounds memory address passed to stack allocator (free)");
+ return;
+ }
+
+ if (curr_addr >= start+(uintptr)s->offset) {
+ // Allow double frees
+ return;
+ }
+
+ header = (Stack_Allocation_Header *)(curr_addr - sizeof(Stack_Allocation_Header));
+ prev_offset = (usize)(curr_addr - (uintptr)header->padding - start);
+
+ s->offset = prev_offset;
+ }
+}
+
+PODEF void
+p_stack_free_all(Stack* s)
+{
+ s->offset = 0;
+}
+
+PODEF void
+p_stack_destroy(Stack* s)
+{
+ s->buf = 0;
+ s->buf_len = 0;
+ s->offset = 0;
+}
+
+PODEF void
+p_pool_create(Pool *p, void *buf, usize buf_len, usize chunk_size, usize chunk_align)
+{
+ /* align start */
+ uintptr start = (uintptr) buf;
+ uintptr aligned = align_forward(start, chunk_align);
+ buf_len -= (aligned - start);
+
+ /* align chunk usize */
+ chunk_size = (usize) align_forward(chunk_size, chunk_align);
+
+ assert(chunk_size >= sizeof(Pool_Free_Node) && "Chunk usize is too small");
+ assert(buf_len >= chunk_size && "Backing buffer length is smaller than the chunk size");
+
+ p->buf = (unsigned char *) buf;
+ p->pool_size = buf_len;
+ p->chunk_size = chunk_size;
+ p->head = NULL;
+
+ p_pool_free_all(p);
+}
+
+PODEF void*
+p_pool_alloc(Pool *p)
+{
+ Pool_Free_Node *node = p->head;
+
+ assert(node != NULL && "Pool allocator has no free memory");
+
+ p->head = p->head->next;
+
+ return memset(node, 0 , p->chunk_size);
+}
+
+PODEF void
+p_pool_free(Pool *p, void *ptr)
+{
+ Pool_Free_Node *node;
+
+ void *start = p->buf;
+ void *end = &p->buf[p->pool_size];
+
+ if (ptr == NULL) {
+ return;
+ }
+
+ if (!(start <= ptr && ptr < end)) {
+ assert(0 && "Memory is out of bounds of the buffer in this pool");
+ return;
+ }
+
+ node = (Pool_Free_Node *)ptr;
+ node->next = p->head;
+ p->head = node;
+}
+
+PODEF void
+p_pool_free_all(Pool *p)
+{
+ usize chunk_count = p->pool_size / p->chunk_size;
+ usize i;
+
+ for (i = 0; i < chunk_count; i++) {
+ void *ptr = &p->buf[i * p->chunk_size];
+ Pool_Free_Node *node = (Pool_Free_Node *)ptr;
+
+ // Push free node onto thte free list
+ node->next = p->head;
+ p->head = node;
+ }
+}
+
+PODEF void
+p_pool_destroy(Pool *p)
+{
+ p->buf = NULL;
+ p->pool_size = 0;
+ p->chunk_size = 0;
+ p->head = NULL;
+}
+
diff --git a/Podium/p_allocators.h b/Podium/p_allocators.h
new file mode 100644
index 0000000..72bae56
--- /dev/null
+++ b/Podium/p_allocators.h
@@ -0,0 +1,44 @@
+typedef struct Arena {
+ unsigned char *buf;
+ usize buf_len;
+ usize curr_offset;
+ usize prev_offset;
+} Arena;
+
+PODEF void p_arena_create(Arena *a, void *backing_buffer, usize backing_buffer_length);
+PODEF void* p_arena_alloc_align(Arena *a, usize s, usize align);
+PODEF void* p_arena_alloc(Arena *a, usize s);
+PODEF void* p_arena_resize_align(Arena *a, void *old_memory, usize old_size, usize new_size, usize align);
+PODEF void* p_arena_resize(Arena *a, void *old_memory, usize old_size, usize new_size);
+PODEF void p_arena_free_all(Arena *a);
+PODEF void p_arena_destroy(Arena* a);
+
+typedef struct { u8 padding; } Stack_Allocation_Header;
+typedef struct Stack {
+ unsigned char *buf;
+ usize buf_len;
+ usize offset;
+} Stack;
+
+PODEF void p_stack_create(Stack *s, void *backing_buffer, usize backing_buffer_length);
+PODEF usize calc_padding_with_header(uintptr ptr, uintptr alignment, usize header_size);
+PODEF void* p_stack_alloc(Stack *s, usize len, usize alignment);
+PODEF void p_stack_free(Stack *s, void *ptr);
+PODEF void p_stack_free_all(Stack* s);
+PODEF void p_stack_destroy(Stack* s);
+
+typedef struct Pool_Free_Node Pool_Free_Node;
+
+typedef struct Pool {
+ unsigned char *buf;
+ usize chunk_size;
+ usize pool_size;
+ Pool_Free_Node *head;
+} Pool;
+
+struct Pool_Free_Node { struct Pool_Free_Node *next; };
+PODEF void p_pool_create(Pool *p, void *buf, usize buf_len, usize chunk_size, usize chunk_align);
+PODEF void* p_pool_alloc(Pool *p);
+PODEF void p_pool_free(Pool *p, void *ptr);
+PODEF void p_pool_free_all(Pool *p);
+PODEF void p_pool_destroy(Pool *p);
diff --git a/Podium/p_ds.h b/Podium/p_ds.h
new file mode 100644
index 0000000..8731975
--- /dev/null
+++ b/Podium/p_ds.h
@@ -0,0 +1,52 @@
+#define DEFAULT_ALIGNMENT (2 * sizeof(void *))
+#define ARRAY_GROW_FACTOR 2
+
+typedef struct {
+ u32 size;
+ u32 capacity;
+} DynamicArrayHeader;
+
+#define DARRAY_INIT_CAPACITY 64
+#define p_darray_push(array, var) \
+ do { \
+ if (array == NULL) { \
+ DynamicArrayHeader *header = \
+ malloc(DARRAY_INIT_CAPACITY * sizeof *array + sizeof *header); \
+ header->size = 0; \
+ header->capacity = DARRAY_INIT_CAPACITY; \
+ array = (void *)(header + 1); \
+ } \
+ DynamicArrayHeader *header = (DynamicArrayHeader *)(array) - 1; \
+ if (header->size >= header->capacity - 1) { \
+ unsigned long new_capacity = header->capacity * 2; \
+ DynamicArrayHeader *new_header = \
+ realloc(header, new_capacity * sizeof *array + sizeof *header); \
+ if (!new_header) \
+ break; \
+ header = new_header; \
+ array = (void *)(header + 1); \
+ header->capacity = new_capacity; \
+ } \
+ (array)[header->size++] = var; \
+ } while (0)
+
+#define p_darray_len(array) ((array) ? ((DynamicArrayHeader *)(array) - 1)->size : 0)
+#define p_darray_destroy(array) \
+{ \
+ free((DynamicArrayHeader *)(array) - 1); \
+}
+
+#define p_darray_shrink(array) \
+ do { \
+ DynamicArrayHeader *header = (array) ? ((DynamicArrayHeader *)(array) - 1) : 0;\
+ if (header) {\
+ if (header->capacity > 4) {\
+ unsigned long new_capacity = (header->capacity >> 1) + (header->capacity & 1); \
+ void *new_header = realloc(header, new_capacity * sizeof *array + sizeof *header); \
+ if (!new_header) break; \
+ header = new_header; \
+ array = (void *)(header + 1); \
+ header->capacity = new_capacity; \
+ }\
+ }\
+ } while (0)
diff --git a/Podium/p_log.h b/Podium/p_log.h
new file mode 100644
index 0000000..0f6ce6c
--- /dev/null
+++ b/Podium/p_log.h
@@ -0,0 +1,186 @@
+/*
+ * Logging!
+ */
+
+#include <stdlib.h>
+
+#ifdef DEBUG
+#define LOG_DEBUG(...) PRINTF(__VA_ARGS__)
+#else
+#define LOG_DEBUG(...) ((void)0)
+#endif
+
+/* fatal and error always enabled */
+#define PFATAL(message, ...) p_log_printf(P_LOG_LEVEL_FATAL, message, ##__VA_ARGS__)
+#define PERROR(message, ...) p_log_printf(P_LOG_LEVEL_ERROR, message, ##__VA_ARGS__)
+
+/* warn and info enabled by default but can be disabled */
+#define P_LOG_WARN_ENABLED 1
+#define P_LOG_INFO_ENABLED 1
+
+#if P_LOG_WARN_ENABLED == 1
+#define PWARN(message, ...) p_log_printf(P_LOG_LEVEL_WARN, message, ##__VA_ARGS__)
+#else
+#define PWARN(message, ...)
+#endif
+
+#if P_LOG_INFO_ENABLED == 1
+#define PINFO(message, ...) p_log_printf(P_LOG_LEVEL_INFO, message, ##__VA_ARGS__)
+#else
+#define PINFO(message, ...)
+#endif
+
+#if P_LOG_DEBUG_ENABLED == 1
+#define PDEBUG(message, ...) p_log_printf(P_LOG_LEVEL_DEBUG, message, ##__VA_ARGS__)
+#else
+#define PDEBUG(message, ...)
+#endif
+
+#if P_LOG_TRACE_ENABLED == 1
+#define PTRACE(message, ...) p_log_printf(P_LOG_LEVEL_TRACE, message, ##__VA_ARGS__)
+#else
+#define PTRACE(message, ...)
+#endif
+
+typedef enum P_Log_Level {
+ P_LOG_LEVEL_FATAL = 0,
+ P_LOG_LEVEL_ERROR,
+ P_LOG_LEVEL_WARN,
+ P_LOG_LEVEL_INFO,
+ P_LOG_LEVEL_DEBUG,
+ P_LOG_LEVEL_TRACE,
+ P_COUNT_LOG_LEVEL
+} P_Log_Level;
+
+#define P_PREFIX_LEN 7
+static const char *p_prefix[P_COUNT_LOG_LEVEL] = {
+ [P_LOG_LEVEL_FATAL] = "[FATAL]",
+ [P_LOG_LEVEL_ERROR] = "[ERROR]",
+ [P_LOG_LEVEL_WARN] = "[WARNI]",
+ [P_LOG_LEVEL_INFO] = "[INFOR]",
+ [P_LOG_LEVEL_DEBUG] = "[DEBUG]",
+ [P_LOG_LEVEL_TRACE] = "[TRACE]",
+};
+
+#define P_MAX_ALLOCS 512
+
+typedef struct P_DebugMemoryInfo {
+ void *ptr;
+ size_t size;
+ const char *file;
+ const char *func;
+ int line;
+} P_DebugMemoryInfo;
+
+static uint64_t p_alloc_count = 0;
+static P_DebugMemoryInfo p_ptr_array[P_MAX_ALLOCS];
+
+static inline void *
+p_debug_malloc_impl(size_t size, const char *file, int line, const char *func)
+{
+ void *ptr = malloc(size);
+ printf("[ALLOC] %p (%zu bytes) -> %s:%d %s()\n", ptr, size, file, line, func);
+
+ if (ptr) {
+ if (p_alloc_count < P_MAX_ALLOCS) {
+ p_ptr_array[p_alloc_count++] = (P_DebugMemoryInfo){
+ .ptr = ptr,
+ .size = size,
+ .file = file,
+ .func = func,
+ .line = line
+ };
+ } else {
+ fprintf(stderr, "[ERROR] Debug allocator tracking capacity (%d) exceeded!\n", P_MAX_ALLOCS);
+ }
+ }
+ return ptr;
+}
+
+static inline void
+p_debug_free_impl(void *ptr, const char *file, int line, const char *func)
+{
+ printf("[FREE] %p -> %s:%d %s()\n", ptr, file, line, func);
+
+ if (!ptr) return; // Standard C allows free(NULL)
+
+ bool found = false;
+ uint64_t index = 0;
+
+ /* Find allocation metadata */
+ for (index = 0; index < p_alloc_count; ++index) {
+ if (p_ptr_array[index].ptr == ptr) {
+ found = true;
+ break;
+ }
+ }
+
+ if (found) {
+ /* Shift array left to remove tracked struct */
+ for (uint64_t j = index; j < p_alloc_count - 1; ++j) {
+ p_ptr_array[j] = p_ptr_array[j + 1];
+ }
+ p_alloc_count--;
+ } else {
+ fprintf(stderr, "[WARNING] Attempted to free untracked/double-freed pointer %p at %s:%d %s()\n",
+ ptr, file, line, func);
+ }
+
+ free(ptr);
+}
+
+static inline void *
+p_debug_realloc_impl(void *ptr, size_t size, const char *file, int line, const char *func)
+{
+ if (!ptr) {
+ return p_debug_malloc_impl(size, file, line, func);
+ }
+ if (size == 0) {
+ p_debug_free_impl(ptr, file, line, func);
+ return NULL;
+ }
+
+ void *new_ptr = realloc(ptr, size);
+ printf("[REALLOC] %p -> %p (%zu bytes) -> %s:%d %s()\n", ptr, new_ptr, size, file, line, func);
+
+ if (new_ptr) {
+ bool found = false;
+ for (uint64_t i = 0; i < p_alloc_count; ++i) {
+ if (p_ptr_array[i].ptr == ptr) {
+ p_ptr_array[i].ptr = new_ptr;
+ p_ptr_array[i].size = size;
+ p_ptr_array[i].file = file;
+ p_ptr_array[i].line = line;
+ p_ptr_array[i].func = func;
+ found = true;
+ break;
+ }
+ }
+ if (!found) {
+ if (p_alloc_count < P_MAX_ALLOCS) {
+ p_ptr_array[p_alloc_count++] = (P_DebugMemoryInfo){
+ .ptr = new_ptr,
+ .size = size,
+ .file = file,
+ .func = func,
+ .line = line
+ };
+ }
+ }
+ }
+ return new_ptr;
+}
+
+static void
+p_debug_memory_report(void)
+{
+ printf("\n==================== MEMORY REPORT ====================\n");
+ printf("Remaining unfreed allocations: %lu\n", (unsigned long)p_alloc_count);
+
+ for (uint64_t i = 0; i < p_alloc_count; ++i) {
+ P_DebugMemoryInfo *info = &p_ptr_array[i];
+ printf("[LEAK] %p (%zu bytes) allocated at %s:%d in %s()\n",
+ info->ptr, info->size, info->file, info->line, info->func);
+ }
+ printf("=======================================================\n");
+}
diff --git a/Podium/p_math.c b/Podium/p_math.c
new file mode 100644
index 0000000..928738b
--- /dev/null
+++ b/Podium/p_math.c
@@ -0,0 +1,255 @@
+PODEF
+int p_ceil(float x)
+{
+ int base = (int) x;
+ return (x > base) ? base + 1 : base;
+}
+
+PODEF float
+p_cosf(float x)
+{
+ x += 1.57079632679f;
+
+ while (x > P_PI) x -= P_PI2;
+ while (x < -P_PI) x += P_PI2;
+
+ const float B = 4.0f / P_PI;
+ const float C = -4.0f / P_PI_POW2;
+
+ float y = B * x + C * x * (x < 0 ? -x : x);
+
+ const float P = 0.225f;
+ y = P * (y * (y < 0 ? -y : y) - y) + y;
+
+ return y;
+}
+
+PODEF float
+p_sinf(float x)
+{
+ while (x > P_PI) x -= P_PI2;
+ while (x < -P_PI) x += P_PI2;
+
+ const float B = 4.0f / P_PI;
+ const float C = -4.0f / (P_PI_POW2);
+
+ float y = B * x + C * x * (x < 0 ? -x : x);
+
+ const float P = 0.225f;
+ y = P * (y * (y < 0 ? -y : y) - y) + y;
+
+ return y;
+}
+
+PODEF Vec2f
+p_vec2f(float x, float y)
+{
+ return (Vec2f) { .x = x, .y = y };
+}
+
+PODEF Vec2f
+p_vec2f_add(Vec2f a, Vec2f b)
+{
+ return (Vec2f) {
+ .x = a.x + b.x,
+ .y = a.y + b.y,
+ };
+}
+
+PODEF float
+p_vec2f_cross(Vec2f a, Vec2f b)
+{
+ // axby − aybx
+ return a.x * b.y - a.y * b.x;
+}
+
+PODEF float
+p_vec2f_dot(Vec2f a, Vec2f b)
+{
+ // a · b = ax × bx + ay × by
+ return a.x * b.x + a.y * b.y;
+}
+
+PODEF Vec2f
+p_vec2f_mult(Vec2f a, float b)
+{
+ return (Vec2f) {
+ .x = a.x * b,
+ .y = a.y * b,
+ };
+}
+
+PODEF Vec2f
+p_vec2f_sub(Vec2f a, Vec2f b)
+{
+ return (Vec2f) {
+ .x = a.x - b.x,
+ .y = a.y - b.y,
+ };
+}
+
+PODEF Vec2i
+p_vec2i(float x, float y)
+{
+ return (Vec2i) { .x = x, .y = y };
+}
+
+PODEF Vec2i
+p_vec2i_add(Vec2i a, Vec2i b)
+{
+ return (Vec2i) {
+ .x = a.x + b.x,
+ .y = a.y + b.y,
+ };
+}
+
+PODEF float
+p_vec2i_cross(Vec2i a, Vec2i b)
+{
+ // axby − aybx
+ return a.x * b.y - a.y * b.x;
+}
+
+PODEF float
+p_vec2i_dot(Vec2i a, Vec2i b)
+{
+ // a · b = ax × bx + ay × by
+ return a.x * b.x + a.y * b.y;
+}
+
+PODEF Vec2i
+p_vec2i_mult(Vec2i a, float b)
+{
+ return (Vec2i) {
+ .x = a.x * b,
+ .y = a.y * b,
+ };
+}
+
+PODEF Vec2i
+p_vec2i_sub(Vec2i a, Vec2i b)
+{
+ return (Vec2i) {
+ .x = a.x - b.x,
+ .y = a.y - b.y,
+ };
+}
+
+PODEF Vec3f
+p_vec3f(float x, float y, float z)
+{
+ return (Vec3f) { .x = x, .y = y, .z = z };
+}
+
+PODEF P_Mat4
+p_mat4_identity(void)
+{
+ P_Mat4 res = {0};
+ res.m[0] = 1.0f;
+ res.m[5] = 1.0f;
+ res.m[10] = 1.0f;
+ res.m[15] = 1.0f;
+ return res;
+}
+
+PODEF P_Mat4
+p_mat4_mul(P_Mat4 a, P_Mat4 b)
+{
+ P_Mat4 res = {0};
+ for (int col = 0; col < 4; ++col) {
+ for (int row = 0; row < 4; ++row) {
+ float sum = 0.0f;
+ for (int k = 0; k < 4; ++k) {
+ sum += a.m[k * 4 + row] * b.m[col * 4 + k];
+ }
+ res.m[col * 4 + row] = sum;
+ }
+ }
+ return res;
+}
+
+PODEF P_Mat4
+p_mat4_translate(Vec3f v)
+{
+ P_Mat4 res = p_mat4_identity();
+ res.m[12] = v.x;
+ res.m[13] = v.y;
+ res.m[14] = v.z;
+ return res;
+}
+
+PODEF P_Mat4
+p_mat4_translate_by(P_Mat4 m, Vec3f v)
+{
+ P_Mat4 res = m;
+ res.m[12] = m.m[0] * v.x + m.m[4] * v.y + m.m[8] * v.z + m.m[12];
+ res.m[13] = m.m[1] * v.x + m.m[5] * v.y + m.m[9] * v.z + m.m[13];
+ res.m[14] = m.m[2] * v.x + m.m[6] * v.y + m.m[10] * v.z + m.m[14];
+ res.m[15] = m.m[3] * v.x + m.m[7] * v.y + m.m[11] * v.z + m.m[15];
+ return res;
+}
+
+PODEF P_Mat4
+p_mat4_rotate_x(float rad)
+{
+ P_Mat4 res = p_mat4_identity();
+ float c = p_cosf(rad);
+ float s = p_sinf(rad);
+ res.m[5] = c;
+ res.m[6] = s;
+ res.m[9] = -s;
+ res.m[10] = c;
+ return res;
+}
+
+PODEF P_Mat4
+p_mat4_rotate_x_by(P_Mat4 m, float rad)
+{
+ return p_mat4_mul(m, p_mat4_rotate_x(rad));
+}
+
+PODEF P_Mat4
+p_mat4_rotate_y(float rad)
+{
+ P_Mat4 res = p_mat4_identity();
+ float c = p_cosf(rad);
+ float s = p_sinf(rad);
+ res.m[0] = c;
+ res.m[2] = -s;
+ res.m[8] = s;
+ res.m[10] = c;
+ return res;
+}
+
+PODEF P_Mat4
+p_mat4_rotate_y_by(P_Mat4 m, float rad)
+{
+ return p_mat4_mul(m, p_mat4_rotate_y(rad));
+}
+
+PODEF P_Mat4
+p_mat4_rotate_z(float rad)
+{
+ P_Mat4 res = p_mat4_identity();
+ float c = p_cosf(rad);
+ float s = p_sinf(rad);
+ res.m[0] = c;
+ res.m[1] = s;
+ res.m[4] = -s;
+ res.m[5] = c;
+ return res;
+}
+
+PODEF P_Mat4
+p_mat4_perspective(float fov_rad, float aspect, float near_z, float far_z)
+{
+ P_Mat4 res = {0};
+ float tan_half_fov = p_sinf(fov_rad * 0.5f) / p_cosf(fov_rad * 0.5f);
+
+ res.m[0] = 1.0f / (aspect * tan_half_fov);
+ res.m[5] = 1.0f / tan_half_fov;
+ res.m[10] = far_z / (near_z - far_z);
+ res.m[11] = -1.0f;
+ res.m[14] = (near_z * far_z) / (near_z - far_z);
+ return res;
+}
diff --git a/Podium/p_math.h b/Podium/p_math.h
new file mode 100644
index 0000000..1dad6ec
--- /dev/null
+++ b/Podium/p_math.h
@@ -0,0 +1,33 @@
+typedef struct {int x, y; } Vec2i;
+typedef struct {float x, y; } Vec2f;
+typedef struct {float x, y, z; } Vec3f;
+typedef struct { float m[16];} P_Mat4; // column-major: m[col * 4 + row]
+PODEF int p_ceil(float x);
+PODEF float p_cosf(float x);
+PODEF float p_sinf(float x);
+
+PODEF Vec2f p_vec2f(float, float);
+PODEF Vec2f p_vec2f_add(Vec2f, Vec2f);
+PODEF float p_vec2f_cross(Vec2f, Vec2f);
+PODEF float p_vec2f_dot(Vec2f, Vec2f);
+PODEF Vec2f p_vec2f_mult(Vec2f a, float b);
+PODEF Vec2f p_vec2f_sub(Vec2f, Vec2f);
+PODEF Vec2i p_vec2i(float, float);
+PODEF Vec2i p_vec2i_add(Vec2i, Vec2i);
+PODEF float p_vec2i_cross(Vec2i, Vec2i);
+PODEF float p_vec2i_dot(Vec2i, Vec2i);
+PODEF Vec2i p_vec2i_mult(Vec2i a, float b);
+PODEF Vec2i p_vec2i_sub(Vec2i, Vec2i);
+
+PODEF Vec3f p_vec3f(float, float, float);
+
+PODEF P_Mat4 p_mat4_identity(void);
+PODEF P_Mat4 p_mat4_mul(P_Mat4 a, P_Mat4 b);
+PODEF P_Mat4 p_mat4_translate(Vec3f v);
+PODEF P_Mat4 p_mat4_translate_by(P_Mat4 m, Vec3f v);
+PODEF P_Mat4 p_mat4_rotate_x(float rad);
+PODEF P_Mat4 p_mat4_rotate_x_by(P_Mat4 m, float rad);
+PODEF P_Mat4 p_mat4_rotate_y(float rad);
+PODEF P_Mat4 p_mat4_rotate_y_by(P_Mat4 m, float rad);
+PODEF P_Mat4 p_mat4_rotate_z(float rad);
+PODEF P_Mat4 p_mat4_perspective(float fov_rad, float aspect, float near_z, float far_z);
diff --git a/Podium/p_platform_linux.c b/Podium/p_platform_linux.c
new file mode 100644
index 0000000..366e3d7
--- /dev/null
+++ b/Podium/p_platform_linux.c
@@ -0,0 +1,404 @@
+/* linux */
+#include <time.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <dirent.h>
+#include <sys/stat.h>
+#include <errno.h>
+/* x11 */
+#include <X11/Xlib.h>
+#include <X11/keysym.h>
+/* pulse audio */
+#include <pulse/pulseaudio.h>
+#include <pulse/simple.h>
+#include <pulse/error.h>
+/* joystick */
+#include <linux/joystick.h>
+
+typedef struct {
+ pa_simple *audio_stream;
+} P_LinuxCtx;
+
+struct P_Window_Impl {
+ Display *display;
+ XImage *image;
+ Window window;
+ GC gc;
+ int screen;
+ int width;
+ int height;
+};
+
+P_LinuxCtx p_ctx = {0};
+
+static inline P_KeyCode
+_x11_translate_keycode(XEvent xev)
+{
+ static KeySym ks;
+ ks = XLookupKeysym(&xev.xkey, 0);
+ switch (ks) {
+ /* Arrow keys */
+ case XK_Left: return P_KEY_LEFT;
+ case XK_Right: return P_KEY_RIGHT;
+ case XK_Up: return P_KEY_UP;
+ case XK_Down: return P_KEY_DOWN;
+ /* Common keys */
+ case XK_space: return P_KEY_SPACE;
+ case XK_Escape: return P_KEY_ESCAPE;
+ case XK_Return: return P_KEY_ENTER;
+ case XK_A: case XK_a: return P_KEY_A;
+ case XK_B: case XK_b: return P_KEY_B;
+ case XK_C: case XK_c: return P_KEY_C;
+ case XK_D: case XK_d: return P_KEY_D;
+ case XK_E: case XK_e: return P_KEY_E;
+ case XK_F: case XK_f: return P_KEY_F;
+ case XK_G: case XK_g: return P_KEY_G;
+ case XK_H: case XK_h: return P_KEY_H;
+ case XK_I: case XK_i: return P_KEY_I;
+ case XK_J: case XK_j: return P_KEY_J;
+ case XK_K: case XK_k: return P_KEY_K;
+ case XK_L: case XK_l: return P_KEY_L;
+ case XK_M: case XK_m: return P_KEY_M;
+ case XK_N: case XK_n: return P_KEY_N;
+ case XK_O: case XK_o: return P_KEY_O;
+ case XK_P: case XK_p: return P_KEY_P;
+ case XK_Q: case XK_q: return P_KEY_Q;
+ case XK_R: case XK_r: return P_KEY_R;
+ case XK_S: case XK_s: return P_KEY_S;
+ case XK_T: case XK_t: return P_KEY_T;
+ case XK_U: case XK_u: return P_KEY_U;
+ case XK_V: case XK_v: return P_KEY_V;
+ case XK_W: case XK_w: return P_KEY_W;
+ case XK_X: case XK_x: return P_KEY_X;
+ case XK_Y: case XK_y: return P_KEY_Y;
+ case XK_Z: case XK_z: return P_KEY_Z;
+ default: return P_KEY_UNKNOWN;
+ }
+}
+
+POAPI u64
+p_get_time(void)
+{
+ struct timespec ts;
+ clock_gettime(CLOCK_MONOTONIC, &ts);
+ return NANOS_PER_SEC * ts.tv_sec + ts.tv_nsec;
+}
+
+POAPI void
+p_sleep_ns(i64 ns)
+{
+ struct timespec ts;
+ ts.tv_sec = ns / 1000000000L;
+ ts.tv_nsec = ns % 1000000000L;
+ clock_nanosleep(CLOCK_MONOTONIC, 0, &ts, NULL);
+}
+
+POAPI void
+p_stdout(void *msg, usize bytes)
+{
+ write(1, msg, bytes);
+}
+
+POAPI bool
+p_file_exists(const char *path)
+{
+ return (access(path, F_OK) == 0);
+}
+
+POAPI usize
+p_file_size(const char *path)
+{
+ struct stat st;
+ if (stat(path, &st) == 0) {
+ return st.st_size;
+ }
+ return 0;
+}
+
+PODEF void
+p_file_load(const char *path, void *buf_ptr, unsigned long buf_size)
+{
+ int fd = open(path, O_RDONLY);
+ if (fd >= 0) {
+ read(fd, buf_ptr, (size_t)buf_size);
+ close(fd);
+ }
+}
+
+PODEF void
+p_file_write(const char *path, void *buf_ptr, unsigned long buf_size)
+{
+ int fd = open(path, O_WRONLY | O_CREAT | O_APPEND, 0644);
+ if (fd >= 0) {
+ write(fd, buf_ptr, (size_t)buf_size);
+ close(fd);
+ }
+}
+
+POAPI bool
+p_window_open(P_Window *win, int width, int height, const char *title)
+{
+ win->width = width;
+ win->height = height;
+
+ XInitThreads();
+
+ win->display = XOpenDisplay(NULL);
+ if (win->display == NULL) {
+ PERROR("Cannot open display!");
+ return false;
+ }
+
+ int screen = DefaultScreen(win->display);
+ win->window = XCreateSimpleWindow(
+ win->display,
+ RootWindow(win->display, screen),
+ 0, 0, width, height,
+ 1,
+ BlackPixel(win->display, screen),
+ BlackPixel(win->display, screen)
+ );
+
+ win->screen = screen;
+
+ XStoreName(win->display, win->window, title);
+ XSelectInput(win->display, win->window,
+ KeyPressMask | KeyReleaseMask |
+ ButtonPressMask | ButtonReleaseMask |
+ PointerMotionMask | StructureNotifyMask);
+ XMapWindow(win->display, win->window);
+
+ win->gc = DefaultGC(win->display, screen);
+
+ Atom wm_delete = XInternAtom(win->display, "WM_DELETE_WINDOW", False);
+ XSetWMProtocols(win->display, win->window, &wm_delete, 1);
+
+ return true;
+}
+
+POAPI void
+p_window_close(P_Window *win)
+{
+ if (!win) return;
+
+ if (win->image) {
+ // XDestroyImage(win->image);
+ win->image = NULL;
+ }
+
+ if (win->display) {
+ Display *dpy = win->display;
+ Window w = win->window;
+ win->display = NULL;
+ win->window = 0;
+
+ if (w) {
+ XDestroyWindow(dpy, w);
+ }
+ XSync(dpy, False);
+ }
+}
+
+POAPI bool
+p_window_is_open(P_Window *win)
+{
+ return win && win->display != NULL;
+}
+
+POAPI void
+p_window_size(P_Window *win, int *window_width, int *window_height)
+{
+ if (!win) return;
+
+ XWindowAttributes attr;
+ XGetWindowAttributes(win->display, win->window, &attr);
+ *window_width = attr.width;
+ *window_height = attr.height;
+
+ win->width = attr.width;
+ win->height = attr.height;
+}
+
+POAPI void
+p_window_draw(P_Window *win, u32 *pixels, int width, int height)
+{
+ int screen = win->screen;
+
+ win->image = XCreateImage(
+ win->display,
+ DefaultVisual(win->display, screen),
+ DefaultDepth(win->display, screen),
+ ZPixmap,
+ 0,
+ (char*)pixels,
+ width,
+ height,
+ 32,
+ width * 4
+ );
+
+ int window_width, window_height;
+ p_window_size(win, &window_width, &window_height);
+
+ XPutImage(
+ win->display,
+ win->window,
+ win->gc,
+ win->image,
+ 0, 0,
+ 0, 0,
+ win->width,
+ win->height);
+
+ XFlush(win->display);
+}
+
+POAPI bool
+p_window_poll_event(P_Window *win, P_Event *ev)
+{
+ if (XPending(win->display)) {
+ static XEvent xev;
+ XNextEvent(win->display, &xev);
+
+ switch (xev.type) {
+
+ case KeyPress:
+ ev->type = P_EVENT_KEY_DOWN;
+ ev->key.key = _x11_translate_keycode(xev);
+ return true;
+
+ case KeyRelease:
+ ev->type = P_EVENT_KEY_UP;
+ ev->key.key = _x11_translate_keycode(xev);
+ return true;
+
+ case ConfigureNotify:
+ ev->type = P_EVENT_WINDOW_RESIZE;
+ ev->resize.width = xev.xconfigure.width;
+ ev->resize.height = xev.xconfigure.height;
+ return true;
+
+ case ClientMessage:
+ if ((Atom)xev.xclient.data.l[0] ==
+ XInternAtom(win->display, "WM_DELETE_WINDOW", False)) {
+ ev->type = P_EVENT_WINDOW_CLOSE;
+ return true;
+ }
+ break;
+
+ case MotionNotify:
+ ev->type = P_EVENT_POINTER;
+ ev->pointer.state = P_POINTER_MOVED;
+ ev->pointer.button = 0;
+ ev->pointer.x = xev.xmotion.x;
+ ev->pointer.y = xev.xmotion.y;
+ return true;
+
+ case ButtonPress:
+ ev->type = P_EVENT_POINTER;
+ ev->pointer.state = P_POINTER_PRESSED;
+ ev->pointer.button = xev.xbutton.button; /* 1=LMB, 2=MMB, 3=RMB */
+ ev->pointer.x = xev.xbutton.x;
+ ev->pointer.y = xev.xbutton.y;
+ return true;
+
+ case ButtonRelease:
+ ev->type = P_EVENT_POINTER;
+ ev->pointer.state = P_POINTER_RELEASED;
+ ev->pointer.button = xev.xbutton.button;
+ ev->pointer.x = xev.xbutton.x;
+ ev->pointer.y = xev.xbutton.y;
+ return true;
+ }
+ }
+
+ ev->type = P_EVENT_NONE;
+ return false;
+}
+
+POAPI void
+p_audio_init(const int sample_rate, const int channels, const char *name, const char *desc)
+{
+ pa_sample_spec ss = {
+ .format = PA_SAMPLE_S16LE,
+ .rate = sample_rate,
+ .channels = channels,
+ };
+
+ int error;
+ p_ctx.audio_stream = pa_simple_new(
+ NULL,
+ name,
+ PA_STREAM_PLAYBACK,
+ NULL,
+ desc,
+ &ss,
+ NULL,
+ NULL,
+ &error
+ );
+
+ if (!p_ctx.audio_stream) {
+ PERROR("PulseAudio init failed: %s\n", pa_strerror(error));
+ exit(1);
+ }
+}
+
+POAPI void
+p_audio_quit()
+{
+ if (p_ctx.audio_stream) {
+ pa_simple_free(p_ctx.audio_stream);
+ p_ctx.audio_stream = NULL;
+ }
+}
+
+POAPI void
+p_audio_write(const i16 *samples, usize count)
+{
+ if (!p_ctx.audio_stream) return;
+
+ int error;
+ if (pa_simple_write(p_ctx.audio_stream, samples, count * sizeof(i16), &error) < 0) {
+ PERROR("PulseAudio write failed: %s\n", pa_strerror(error));
+ }
+
+ pa_simple_drain(p_ctx.audio_stream, &error);
+}
+
+#ifdef P_MODULE_VULKAN
+
+#ifndef VK_USE_PLATFORM_XLIB_KHR
+#define VK_USE_PLATFORM_XLIB_KHR
+#endif
+#include <vulkan/vulkan_xlib.h>
+
+POAPI char**
+p_vulkan_get_extensions()
+{
+ char **darr = NULL;
+ p_darray_push(darr, "VK_KHR_surface");
+ p_darray_push(darr, "VK_KHR_xcb_surface");
+ p_darray_push(darr, "VK_KHR_xlib_surface");
+ return darr;
+}
+
+POAPI bool
+p_vulkan_create_surface(P_Window *window, VkInstance instance, const VkAllocationCallbacks* allocator, VkSurfaceKHR* out_surface)
+{
+ if (!instance || !window || !window->display || !window->window || !out_surface) {
+ return false;
+ }
+
+ VkXlibSurfaceCreateInfoKHR create_info = {0};
+ create_info.sType = VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR;
+ create_info.pNext = NULL;
+ create_info.flags = 0;
+ create_info.dpy = window->display;
+ create_info.window = window->window;
+
+ VkResult result = vkCreateXlibSurfaceKHR(instance, &create_info, allocator, out_surface);
+
+ return (result == VK_SUCCESS);
+}
+#endif
diff --git a/Podium/p_platform_win32.c b/Podium/p_platform_win32.c
new file mode 100644
index 0000000..556b43b
--- /dev/null
+++ b/Podium/p_platform_win32.c
@@ -0,0 +1,402 @@
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#include <mmsystem.h>
+#include <xinput.h> /* gamepad support */
+
+typedef struct {
+ HWAVEOUT wave_out;
+ WAVEHDR wave_header;
+} P_Win32Ctx;
+
+struct P_Window_Impl {
+ HWND hwnd;
+ HDC hdc;
+ BITMAPINFO bitmap_info;
+ int width;
+ int height;
+ bool closed;
+};
+
+P_Win32Ctx p_ctx = {0};
+
+static inline P_KeyCode
+_win32_translate_vkey(WPARAM vk)
+{
+ switch (vk) {
+ case VK_LEFT: return P_KEY_LEFT;
+ case VK_RIGHT: return P_KEY_RIGHT;
+ case VK_UP: return P_KEY_UP;
+ case VK_DOWN: return P_KEY_DOWN;
+ case VK_SPACE: return P_KEY_SPACE;
+ case VK_ESCAPE: return P_KEY_ESCAPE;
+ case VK_RETURN: return P_KEY_ENTER;
+ case 'A': return P_KEY_A;
+ case 'B': return P_KEY_B;
+ case 'C': return P_KEY_C;
+ case 'D': return P_KEY_D;
+ case 'E': return P_KEY_E;
+ case 'F': return P_KEY_F;
+ case 'G': return P_KEY_G;
+ case 'H': return P_KEY_H;
+ case 'I': return P_KEY_I;
+ case 'J': return P_KEY_J;
+ case 'K': return P_KEY_K;
+ case 'L': return P_KEY_L;
+ case 'M': return P_KEY_M;
+ case 'N': return P_KEY_N;
+ case 'O': return P_KEY_O;
+ case 'P': return P_KEY_P;
+ case 'Q': return P_KEY_Q;
+ case 'R': return P_KEY_R;
+ case 'S': return P_KEY_S;
+ case 'T': return P_KEY_T;
+ case 'U': return P_KEY_U;
+ case 'V': return P_KEY_V;
+ case 'W': return P_KEY_W;
+ case 'X': return P_KEY_X;
+ case 'Y': return P_KEY_Y;
+ case 'Z': return P_KEY_Z;
+ default: return P_KEY_UNKNOWN;
+ }
+}
+
+POAPI u64
+p_get_time(void)
+{
+ LARGE_INTEGER count, freq;
+ QueryPerformanceCounter(&count);
+ QueryPerformanceFrequency(&freq);
+ return (u64)((count.QuadPart * 1000000000ULL) / freq.QuadPart);
+}
+
+POAPI void
+p_sleep_ns(i64 ns)
+{
+ /* windows sleep is millisecond-based........ */
+ Sleep((DWORD)(ns / 1000000));
+}
+
+POAPI void
+p_stdout(void *msg, usize bytes)
+{
+ HANDLE stdout_handle = GetStdHandle(STD_OUTPUT_HANDLE);
+ DWORD bytes_written;
+ WriteFile(stdout_handle, msg, bytes, &bytes_written, NULL);
+}
+
+POAPI bool
+p_file_exists(const char *path)
+{
+ DWORD attr = GetFileAttributesA(path);
+ return (attr != INVALID_FILE_ATTRIBUTES && !(attr & FILE_ATTRIBUTE_DIRECTORY));
+}
+
+POAPI usize
+p_file_size(const char *path)
+{
+ WIN32_FILE_ATTRIBUTE_DATA data;
+ if (GetFileAttributesExA(path, GetFileExInfoStandard, &data)) {
+ return data.nFileSizeLow;
+ }
+ return 0;
+}
+
+PODEF void
+p_file_load(const char *path, void *buf_ptr, unsigned long buf_size)
+{
+ HANDLE file = CreateFileA(path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
+ if (file != INVALID_HANDLE_VALUE) {
+ DWORD bytes_read;
+ ReadFile(file, buf_ptr, buf_size, &bytes_read, NULL);
+ CloseHandle(file);
+ }
+}
+
+PODEF void
+p_file_write(const char *path, void *buf_ptr, unsigned long buf_size)
+{
+ HANDLE file = CreateFileA(path, GENERIC_WRITE, 0, NULL,
+ CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
+ if (file != INVALID_HANDLE_VALUE) {
+ DWORD bytes_written;
+ WriteFile(file, buf_ptr, buf_size, &bytes_written, NULL);
+ CloseHandle(file);
+ }
+}
+
+static LRESULT CALLBACK
+_win32_wnd_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
+ P_Window *win = (P_Window*)GetWindowLongPtrA(hwnd, GWLP_USERDATA);
+ switch (msg) {
+ case WM_CLOSE:
+ /* Handled in poll_event; mark as closed */
+ if (win) win->closed = true;
+ return 0;
+ }
+ return DefWindowProcA(hwnd, msg, wparam, lparam);
+}
+
+POAPI bool
+p_window_open(P_Window *win, int width, int height, const char *title)
+{
+ HINSTANCE instance = GetModuleHandleA(NULL);
+
+ WNDCLASSA wc = {0};
+ wc.lpfnWndProc = _win32_wnd_proc;
+ wc.hInstance = instance;
+ wc.lpszClassName = "P_Window_Class";
+ wc.hCursor = LoadCursor(NULL, IDC_ARROW);
+
+ RegisterClassA(&wc);
+
+ win->hwnd = CreateWindowExA(0, wc.lpszClassName, title,
+ WS_OVERLAPPEDWINDOW | WS_VISIBLE,
+ CW_USEDEFAULT, CW_USEDEFAULT, width, height,
+ NULL, NULL, instance, NULL);
+
+ if (!win->hwnd) return false;
+
+ SetWindowLongPtrA(win->hwnd, GWLP_USERDATA, (LONG_PTR)win);
+ win->hdc = GetDC(win->hwnd);
+ win->width = width;
+ win->height = height;
+ win->closed = false;
+
+ return true;
+}
+
+POAPI void
+p_window_close(P_Window *win)
+{
+ if (!win) return;
+ if (win->hdc) ReleaseDC(win->hwnd, win->hdc);
+ if (win->hwnd) DestroyWindow(win->hwnd);
+ win->hdc = NULL;
+ win->hwnd = NULL;
+}
+
+POAPI bool
+p_window_is_open(P_Window *win)
+{
+ return win && win->hwnd != NULL;
+}
+
+POAPI void
+p_window_size(P_Window *win, int *window_width, int *window_height)
+{
+ if (!win) return;
+ RECT rect;
+ GetClientRect(win->hwnd, &rect);
+ *window_width = rect.right - rect.left;
+ *window_height = rect.bottom - rect.top;
+ win->width = *window_width;
+ win->height = *window_height;
+}
+
+POAPI void
+p_window_draw(P_Window *win, u32 *pixels, int width, int height)
+{
+ BITMAPINFO bmi = {0};
+ bmi.bmiHeader.biSize = sizeof(bmi.bmiHeader);
+ bmi.bmiHeader.biWidth = width;
+ bmi.bmiHeader.biHeight = -height; /* top-down */
+ bmi.bmiHeader.biPlanes = 1;
+ bmi.bmiHeader.biBitCount = 32;
+ bmi.bmiHeader.biCompression = BI_RGB;
+
+ StretchDIBits(win->hdc,
+ 0, 0, win->width, win->height,
+ 0, 0, width, height,
+ pixels, &bmi, DIB_RGB_COLORS, SRCCOPY);
+}
+
+POAPI bool
+p_window_poll_event(P_Window *win, P_Event *ev)
+{
+ if (win->closed) {
+ win->closed = false;
+ ev->type = P_EVENT_WINDOW_CLOSE;
+ return true;
+ }
+
+ MSG msg;
+ while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) {
+ switch (msg.message) {
+
+ case WM_QUIT:
+ ev->type = P_EVENT_WINDOW_CLOSE;
+ return true;
+
+ /* Key press */
+ case WM_KEYDOWN:
+ case WM_SYSKEYDOWN:
+ ev->type = P_EVENT_KEY_DOWN;
+ ev->key.key = _win32_translate_vkey(msg.wParam);
+ return true;
+
+ /* Key release */
+ case WM_KEYUP:
+ case WM_SYSKEYUP:
+ ev->type = P_EVENT_KEY_UP;
+ ev->key.key = _win32_translate_vkey(msg.wParam);
+ return true;
+
+ /* Mouse movement */
+ case WM_MOUSEMOVE:
+ ev->type = P_EVENT_POINTER;
+ ev->pointer.state = P_POINTER_MOVED;
+ ev->pointer.button = 0;
+ ev->pointer.x = (u32)(msg.lParam & 0xFFFF);
+ ev->pointer.y = (u32)((msg.lParam >> 16) & 0xFFFF);
+ return true;
+
+ /* Mouse buttons */
+ case WM_LBUTTONDOWN:
+ ev->type = P_EVENT_POINTER;
+ ev->pointer.state = P_POINTER_PRESSED;
+ ev->pointer.button = 1; /* 1 = LMB, matching X11 convention */
+ ev->pointer.x = (u32)(msg.lParam & 0xFFFF);
+ ev->pointer.y = (u32)((msg.lParam >> 16) & 0xFFFF);
+ return true;
+
+ case WM_LBUTTONUP:
+ ev->type = P_EVENT_POINTER;
+ ev->pointer.state = P_POINTER_RELEASED;
+ ev->pointer.button = 1;
+ ev->pointer.x = (u32)(msg.lParam & 0xFFFF);
+ ev->pointer.y = (u32)((msg.lParam >> 16) & 0xFFFF);
+ return true;
+
+ case WM_RBUTTONDOWN:
+ ev->type = P_EVENT_POINTER;
+ ev->pointer.state = P_POINTER_PRESSED;
+ ev->pointer.button = 3; /* 3 = RMB */
+ ev->pointer.x = (u32)(msg.lParam & 0xFFFF);
+ ev->pointer.y = (u32)((msg.lParam >> 16) & 0xFFFF);
+ return true;
+
+ case WM_RBUTTONUP:
+ ev->type = P_EVENT_POINTER;
+ ev->pointer.state = P_POINTER_RELEASED;
+ ev->pointer.button = 3;
+ ev->pointer.x = (u32)(msg.lParam & 0xFFFF);
+ ev->pointer.y = (u32)((msg.lParam >> 16) & 0xFFFF);
+ return true;
+
+ case WM_MBUTTONDOWN:
+ ev->type = P_EVENT_POINTER;
+ ev->pointer.state = P_POINTER_PRESSED;
+ ev->pointer.button = 2; /* 2 = MMB */
+ ev->pointer.x = (u32)(msg.lParam & 0xFFFF);
+ ev->pointer.y = (u32)((msg.lParam >> 16) & 0xFFFF);
+ return true;
+
+ case WM_MBUTTONUP:
+ ev->type = P_EVENT_POINTER;
+ ev->pointer.state = P_POINTER_RELEASED;
+ ev->pointer.button = 2;
+ ev->pointer.x = (u32)(msg.lParam & 0xFFFF);
+ ev->pointer.y = (u32)((msg.lParam >> 16) & 0xFFFF);
+ return true;
+
+ /* Window resize */
+ case WM_SIZE:
+ ev->type = P_EVENT_WINDOW_RESIZE;
+ ev->resize.width = (u32)(msg.lParam & 0xFFFF);
+ ev->resize.height = (u32)((msg.lParam >> 16) & 0xFFFF);
+ win->width = ev->resize.width;
+ win->height = ev->resize.height;
+ return true;
+
+ default:
+ TranslateMessage(&msg);
+ DispatchMessageA(&msg);
+ break;
+ }
+ }
+
+ ev->type = P_EVENT_NONE;
+ return false;
+}
+
+
+POAPI void
+p_audio_init(const int sample_rate, const int channels, const char *name, const char *desc)
+{
+ (void)name; (void)desc; /* WinMM doesn't use a stream name */
+
+ WAVEFORMATEX wfx = {0};
+ wfx.wFormatTag = WAVE_FORMAT_PCM;
+ wfx.nChannels = channels;
+ wfx.nSamplesPerSec = sample_rate;
+ wfx.wBitsPerSample = 16;
+ wfx.nBlockAlign = (wfx.nChannels * wfx.wBitsPerSample) / 8;
+ wfx.nAvgBytesPerSec = wfx.nSamplesPerSec * wfx.nBlockAlign;
+
+ if (waveOutOpen(&p_ctx.wave_out, WAVE_MAPPER, &wfx, 0, 0, CALLBACK_NULL) != MMSYSERR_NOERROR) {
+ exit(1);
+ }
+}
+
+POAPI void
+p_audio_quit()
+{
+ if (p_ctx.wave_out) {
+ waveOutReset(p_ctx.wave_out);
+ waveOutClose(p_ctx.wave_out);
+ p_ctx.wave_out = NULL;
+ }
+}
+
+POAPI void
+p_audio_write(const i16 *samples, usize count)
+{
+ if (!p_ctx.wave_out) return;
+
+ WAVEHDR header = {0};
+ header.lpData = (LPSTR)samples;
+ header.dwBufferLength = (DWORD)(count * sizeof(i16));
+
+ waveOutPrepareHeader(p_ctx.wave_out, &header, sizeof(WAVEHDR));
+ waveOutWrite(p_ctx.wave_out, &header, sizeof(WAVEHDR));
+
+ /* wait for playback to finish (synchronous, mirrors pa_simple_drain) */
+ while (!(header.dwFlags & WHDR_DONE)) Sleep(1);
+
+ waveOutUnprepareHeader(p_ctx.wave_out, &header, sizeof(WAVEHDR));
+}
+
+#ifdef P_MODULE_VULKAN
+
+#ifndef VK_USE_PLATFORM_WIN32_KHR
+#define VK_USE_PLATFORM_WIN32_KHR
+#endif
+#include <vulkan/vulkan_win32.h>
+
+POAPI char**
+p_vulkan_get_extensions()
+{
+ char **darr = NULL;
+ p_darray_push(darr, "VK_KHR_surface");
+ p_darray_push(darr, "VK_KHR_win32_surface");
+ return darr;
+}
+
+POAPI bool
+p_vulkan_create_surface(P_Window *window, VkInstance instance, const VkAllocationCallbacks* allocator, VkSurfaceKHR* out_surface)
+{
+ if (!instance || !window || !window->hwnd || !out_surface) {
+ return false;
+ }
+
+ VkWin32SurfaceCreateInfoKHR create_info = {0};
+ create_info.sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR;
+ create_info.pNext = NULL;
+ create_info.flags = 0;
+ create_info.hwnd = window->hwnd;
+ create_info.hinstance = GetModuleHandleA(NULL);
+
+ VkResult result = vkCreateWin32SurfaceKHR(instance, &create_info, allocator, out_surface);
+ return (result == VK_SUCCESS);
+}
+#endif
diff --git a/Podium/p_string.c b/Podium/p_string.c
new file mode 100644
index 0000000..73cb0ea
--- /dev/null
+++ b/Podium/p_string.c
@@ -0,0 +1,201 @@
+PODEF char*
+p_find_char(char *buf, char needle)
+{
+ while (buf && *buf != needle) buf++;
+ return buf;
+}
+
+PODEF bool
+p_strcmp(const char *a, const char *b)
+{
+ if (p_strlen(a) != p_strlen(b))
+ return false;
+
+ while (a && b && *a != '\0') {
+ if (*(a++) != *(b++)) return false;
+ }
+
+ return true;
+}
+
+PODEF int
+p_strlen(const char *a)
+{
+ int i = 0;
+ while (*a++ != '\0') i++;
+ return i;
+}
+
+PODEF int
+p_strtoi(const char *str)
+{
+ int res = 0;
+
+ while (*str) {
+ if (*str >= '0' && *str <= '9') {
+ res = res * 10 + (*str - '0');
+ } else {
+ return res;
+ }
+ str++;
+ }
+
+ return res;
+}
+
+PODEF char*
+p_strtok(const char *str, char c)
+{
+ while (*str != c && *str++ != '\0');
+ return (*str == c) ? (char*) ++str : 0;
+}
+
+PODEF P_StringView
+p_strview(const char *cstr)
+{
+ P_StringView sv = {0};
+ sv.cstr = cstr;
+ sv.len = p_strlen(cstr);
+ return sv;
+}
+
+PODEF void
+p_strview_chop_left(P_StringView *sv, u32 n)
+{
+ if (n > sv->len) n = sv->len;
+ sv->cstr += n;
+ sv->len -= n;
+}
+
+PODEF void
+p_strview_chop_right(P_StringView *sv, u32 n)
+{
+ if (n > sv->len) n = sv->len;
+ sv->len -= n;
+}
+
+PODEF P_StringView
+p_strview_chop_delim(P_StringView *sv, char delim)
+{
+ u32 i = 0;
+ while (i < sv->len && sv->cstr[i] != delim) {
+ i++;
+ }
+
+ P_StringView tok;
+ if (i < sv->len) {
+ tok.cstr = sv->cstr;
+ tok.len = i;
+ p_strview_chop_left(sv, i + 1);
+ return tok;
+ }
+
+ tok = *sv;
+ p_strview_chop_left(sv, sv->len);
+ return tok;
+}
+
+PODEF P_StringView
+p_strview_chop_type(P_StringView *sv, int(*istype)(int))
+{
+ u32 i = 0;
+ while (i < sv->len && istype(sv->cstr[i])) {
+ i++;
+ }
+
+ P_StringView tok;
+ if (i < sv->len) {
+ tok.cstr = sv->cstr;
+ tok.len = i;
+ p_strview_chop_left(sv, i + 1);
+ return tok;
+ }
+
+ tok = *sv;
+ p_strview_chop_left(sv, sv->len);
+ return tok;
+}
+
+
+PODEF void
+p_strview_trim_left(P_StringView *sv)
+{
+ while (sv->len > 0 && p_is_space(sv->cstr[0])) {
+ p_strview_chop_left(sv, 1);
+ }
+}
+
+PODEF void
+p_strview_trim_right(P_StringView *sv)
+{
+ while (sv->len > 0 && p_is_space(sv->cstr[sv->len-1])) {
+ p_strview_chop_right(sv, 1);
+ }
+}
+
+PODEF void
+p_strview_trim(P_StringView *sv)
+{
+ p_strview_trim_left(sv);
+ p_strview_trim_right(sv);
+}
+
+PODEF int
+p_is_space(int c)
+{
+ /* Checks for: space, form feed (\f), line feed (\n),
+ * carriage return (\r), horizontal tab (\t), vertical tab (\v) */
+ return (c == ' ' || (c >= '\t' && c <= '\r'));
+}
+
+PODEF int
+p_is_digit(int c)
+{
+ return (c >= '0' && c <= '9');
+}
+
+PODEF int
+p_is_alpha(int c)
+{
+ return ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'));
+}
+
+PODEF int
+p_is_alnum(int c)
+{
+ return (p_is_alpha(c) || p_is_digit(c));
+}
+
+PODEF int
+p_is_hex(int c)
+{
+ return (p_is_digit(c) ||
+ (c >= 'a' && c <= 'f') ||
+ (c >= 'A' && c <= 'F'));
+}
+
+PODEF int
+p_is_upper(int c)
+{
+ return (c >= 'A' && c <= 'Z');
+}
+
+PODEF int
+p_is_lower(int c)
+{
+ return (c >= 'a' && c <= 'z');
+}
+
+PODEF int
+p_to_lower(int c)
+{
+ if (p_is_upper(c)) return (c + ('a' - 'A'));
+ return c;
+}
+
+PODEF int
+p_to_upper(int c)
+{
+ if (p_is_lower(c)) return (c - ('a' - 'A'));
+ return c;
+}
diff --git a/Podium/p_string.h b/Podium/p_string.h
new file mode 100644
index 0000000..5c4077b
--- /dev/null
+++ b/Podium/p_string.h
@@ -0,0 +1,38 @@
+typedef struct {
+ const char *cstr;
+ u32 len;
+} P_StringView;
+
+typedef struct {
+ P_StringView sv;
+} P_StringBuilder;
+
+/* Classic C string functions */
+PODEF char* p_find_char(char *buf, char needle);
+PODEF bool p_strcmp(const char *a, const char *b);
+PODEF int p_strlen(const char *a);
+PODEF int p_strtoi(const char *str);
+PODEF char* p_strtok(const char *str, char c);
+
+/* String views */
+PODEF P_StringView p_strview(const char *cstr);
+PODEF void p_strview_chop_left(P_StringView *sv, u32 n);
+PODEF void p_strview_chop_right(P_StringView *sv, u32 n);
+PODEF P_StringView p_strview_chop_delim(P_StringView *sv, char delim);
+PODEF P_StringView p_strview_chop_type(P_StringView *sv, int(*istype)(int));
+PODEF void p_strview_trim_left(P_StringView *sv);
+PODEF void p_strview_trim_right(P_StringView *sv);
+PODEF void p_strview_trim(P_StringView *sv);
+
+/* Classification */
+PODEF int p_is_space(int c);
+PODEF int p_is_digit(int c);
+PODEF int p_is_alpha(int c);
+PODEF int p_is_alnum(int c);
+PODEF int p_is_upper(int c);
+PODEF int p_is_lower(int c);
+PODEF int p_is_hex(int c);
+
+/* Transformation */
+PODEF int p_to_lower(int c);
+PODEF int p_to_upper(int c);
diff --git a/Podium/p_types.h b/Podium/p_types.h
new file mode 100644
index 0000000..1da81be
--- /dev/null
+++ b/Podium/p_types.h
@@ -0,0 +1,88 @@
+#ifndef _PODIUM_TYPES_
+#define _PODIUM_TYPES_
+
+#define NANOS_PER_SEC (1000*1000*1000)
+#define P_PI_HALF 1.57079632679f
+#define P_PI 3.14159265f
+#define P_PI2 6.28318531f
+#define P_PI_POW2 9.86960440f
+
+#ifdef NDEBUG
+ #define assert(x) ((void)0)
+#else
+ #ifndef assert
+ #define assert(x) \
+ do { \
+ if (!(x)) { \
+ __builtin_trap(); \
+ } \
+ } while (0)
+ #endif
+#endif
+
+#ifndef BUFSIZ
+ #define BUFSIZ 8192
+#endif
+
+typedef unsigned char u8;
+typedef signed char i8;
+typedef unsigned short u16;
+typedef short i16;
+typedef unsigned int u32;
+typedef int i32;
+typedef unsigned long long u64;
+typedef long long i64;
+typedef float f32;
+typedef double f64;
+
+#ifndef __cplusplus
+#define bool _Bool
+#define false 0
+#define true 1
+#endif
+
+/* C++ uses static_assert, C11 uses _Static_assert */
+#ifdef __cplusplus
+ #define STATIC_ASSERT static_assert
+#else
+ #define STATIC_ASSERT _Static_assert
+#endif
+
+STATIC_ASSERT(sizeof(u8) == 1, "u8 must be 1 byte");
+STATIC_ASSERT(sizeof(u16) == 2, "u16 must be 2 bytes");
+STATIC_ASSERT(sizeof(u32) == 4, "u32 must be 4 bytes");
+STATIC_ASSERT(sizeof(u64) == 8, "u64 must be 8 bytes");
+
+STATIC_ASSERT(sizeof(i8) == 1, "i8 must be 1 byte");
+STATIC_ASSERT(sizeof(i16) == 2, "i16 must be 2 bytes");
+STATIC_ASSERT(sizeof(i32) == 4, "i32 must be 4 bytes");
+STATIC_ASSERT(sizeof(i64) == 8, "i64 must be 8 bytes");
+
+STATIC_ASSERT(sizeof(f32) == 4, "f32 must be 4 bytes");
+STATIC_ASSERT(sizeof(f64) == 8, "f64 must be 8 bytes");
+#define U8_MAX 255
+#define U16_MAX 65535
+#define U32_MAX 4294967295
+
+/* Architecture specific sizing */
+#if defined(__x86_64__) || defined(__aarch64__) || defined(_M_X64)
+ typedef u64 usize;
+ typedef u64 uintptr;
+ typedef u32 idx;
+ STATIC_ASSERT(sizeof(usize) == 8, "usize must be 8 bytes on 64-bit");
+#else
+ typedef u32 usize;
+ typedef u32 uintptr;
+ typedef u16 idx;
+ STATIC_ASSERT(sizeof(usize) == 4, "usize must be 4 bytes on 32-bit");
+#endif
+
+#ifndef NULL
+ #ifdef __cplusplus
+ #define NULL 0
+ #else
+ #define NULL ((void*)0)
+ #endif
+#endif
+
+#endif // _PODIUM_TYPES_
diff --git a/Podium/podium.c b/Podium/podium.c
new file mode 100644
index 0000000..306e337
--- /dev/null
+++ b/Podium/podium.c
@@ -0,0 +1 @@
+#define PODIUM_IMPLEMENTATION
diff --git a/Podium/podium.h b/Podium/podium.h
new file mode 100644
index 0000000..d94b4e5
--- /dev/null
+++ b/Podium/podium.h
@@ -0,0 +1,2269 @@
+/* ===========================================================================
+ * PODIUM - Kitchen Sink - Copyright (c) 2026 Vasco Alves
+ *
+ * ---------------------------------------------------------------------------
+ * To stand on the shoulders of giants...
+ * Giants must stand still!"
+ * - Eskil Steenberg - "You should finish your software" – BSC 2025
+ * ---------------------------------------------------------------------------
+ *
+ * PREFIX: P_ (types) or p_ (functions & variables)
+ *
+ * COMPILE TIME FLAGS
+ * | Name | Description |
+ * |-----------------|---------------------------------------------------------|
+ * | PODIUM_WIN32 | Used to explicitly compile for Windows. |
+ * | PODIUM_LINUX | Used to explicitly compile for Linux and FreeBSD. |
+ *
+ * MODULES
+ * | Name | Description |
+ * |-----------------|---------------------------------------------------------|
+ * | P_MODULE_VULKAN | Gives access to vulkan related utilities. |
+ * | P_MODULE_STRING | Include string manipulation utilities. |
+ * | P_MODULE_MATH | Trigonometry and linear algebra functions. |
+ * | P_MODULE_ALLOC | Memory allocators: Arena, Stack & Pool. |
+ *
+ * =========================================================================== */
+
+#ifndef _PODIUM_H_
+#define _PODIUM_H_
+
+#define PODIUM_MAJOR "0" // needs more revisions and use to reach 1.0 status
+#define PODIUM_MINOR "2" // vulkan module
+#define PODIUM_PATCH "2" // gamepad
+
+#define POAPI static inline
+#define PODEF static inline
+
+/*
+ * Auto-detect platforms.
+ */
+
+/* Windows */
+#if defined(_WIN32) || defined(_WIN64) || defined(__WIN32__) || defined(__TOS_WIN__)
+ #define PODIUM_WIN32
+ #ifndef WIN32_LEAN_AND_MEAN
+ #define WIN32_LEAN_AND_MEAN
+ #endif
+/* Apple */
+#elif defined(__APPLE__) || defined(__MACH__)
+ #include <TargetConditionals.h>
+ #define PODIUM_APPLE
+ #if TARGET_OS_IPHONE
+ #define PODIUM_IOS
+ #else
+ #define PODIUM_MACOS
+ #endif
+/* Linux / BSD */
+#elif defined(__linux__) || defined(__FreeBSD__)
+ #define PODIUM_LINUX
+ #ifndef _POSIX_C_SOURCE
+ #define _POSIX_C_SOURCE 200112L
+ #endif
+#endif
+
+#include <stdarg.h>
+#include <stdint.h>
+#include <stddef.h>
+#include <string.h> /* memcpy */
+#include <stdio.h> /* vsnprintf */
+
+/*
+ * NOTE: The <REPLACE> comments are used by the build
+ * script to know what includes to inline into the
+ * final single header file!
+ */
+
+/* --- Start of p_types.h --- */
+#ifndef _PODIUM_TYPES_
+#define _PODIUM_TYPES_
+
+#define NANOS_PER_SEC (1000*1000*1000)
+#define P_PI_HALF 1.57079632679f
+#define P_PI 3.14159265f
+#define P_PI2 6.28318531f
+#define P_PI_POW2 9.86960440f
+
+#ifdef NDEBUG
+ #define assert(x) ((void)0)
+#else
+ #ifndef assert
+ #define assert(x) \
+ do { \
+ if (!(x)) { \
+ __builtin_trap(); \
+ } \
+ } while (0)
+ #endif
+#endif
+
+#ifndef BUFSIZ
+ #define BUFSIZ 8192
+#endif
+
+typedef unsigned char u8;
+typedef signed char i8;
+typedef unsigned short u16;
+typedef short i16;
+typedef unsigned int u32;
+typedef int i32;
+typedef unsigned long long u64;
+typedef long long i64;
+typedef float f32;
+typedef double f64;
+
+#ifndef __cplusplus
+#define bool _Bool
+#define false 0
+#define true 1
+#endif
+
+/* C++ uses static_assert, C11 uses _Static_assert */
+#ifdef __cplusplus
+ #define STATIC_ASSERT static_assert
+#else
+ #define STATIC_ASSERT _Static_assert
+#endif
+
+STATIC_ASSERT(sizeof(u8) == 1, "u8 must be 1 byte");
+STATIC_ASSERT(sizeof(u16) == 2, "u16 must be 2 bytes");
+STATIC_ASSERT(sizeof(u32) == 4, "u32 must be 4 bytes");
+STATIC_ASSERT(sizeof(u64) == 8, "u64 must be 8 bytes");
+
+STATIC_ASSERT(sizeof(i8) == 1, "i8 must be 1 byte");
+STATIC_ASSERT(sizeof(i16) == 2, "i16 must be 2 bytes");
+STATIC_ASSERT(sizeof(i32) == 4, "i32 must be 4 bytes");
+STATIC_ASSERT(sizeof(i64) == 8, "i64 must be 8 bytes");
+
+STATIC_ASSERT(sizeof(f32) == 4, "f32 must be 4 bytes");
+STATIC_ASSERT(sizeof(f64) == 8, "f64 must be 8 bytes");
+#define U8_MAX 255
+#define U16_MAX 65535
+#define U32_MAX 4294967295
+
+/* Architecture specific sizing */
+#if defined(__x86_64__) || defined(__aarch64__) || defined(_M_X64)
+ typedef u64 usize;
+ typedef u64 uintptr;
+ typedef u32 idx;
+ STATIC_ASSERT(sizeof(usize) == 8, "usize must be 8 bytes on 64-bit");
+#else
+ typedef u32 usize;
+ typedef u32 uintptr;
+ typedef u16 idx;
+ STATIC_ASSERT(sizeof(usize) == 4, "usize must be 4 bytes on 32-bit");
+#endif
+
+#ifndef NULL
+ #ifdef __cplusplus
+ #define NULL 0
+ #else
+ #define NULL ((void*)0)
+ #endif
+#endif
+
+#endif // _PODIUM_TYPES_
+/* --- End of p_types.h --- */
+/* --- Start of p_log.h --- */
+/*
+ * Logging!
+ */
+
+#include <stdlib.h>
+
+#ifdef DEBUG
+#define LOG_DEBUG(...) PRINTF(__VA_ARGS__)
+#else
+#define LOG_DEBUG(...) ((void)0)
+#endif
+
+/* fatal and error always enabled */
+#define PFATAL(message, ...) p_log_printf(P_LOG_LEVEL_FATAL, message, ##__VA_ARGS__)
+#define PERROR(message, ...) p_log_printf(P_LOG_LEVEL_ERROR, message, ##__VA_ARGS__)
+
+/* warn and info enabled by default but can be disabled */
+#define P_LOG_WARN_ENABLED 1
+#define P_LOG_INFO_ENABLED 1
+
+#if P_LOG_WARN_ENABLED == 1
+#define PWARN(message, ...) p_log_printf(P_LOG_LEVEL_WARN, message, ##__VA_ARGS__)
+#else
+#define PWARN(message, ...)
+#endif
+
+#if P_LOG_INFO_ENABLED == 1
+#define PINFO(message, ...) p_log_printf(P_LOG_LEVEL_INFO, message, ##__VA_ARGS__)
+#else
+#define PINFO(message, ...)
+#endif
+
+#if P_LOG_DEBUG_ENABLED == 1
+#define PDEBUG(message, ...) p_log_printf(P_LOG_LEVEL_DEBUG, message, ##__VA_ARGS__)
+#else
+#define PDEBUG(message, ...)
+#endif
+
+#if P_LOG_TRACE_ENABLED == 1
+#define PTRACE(message, ...) p_log_printf(P_LOG_LEVEL_TRACE, message, ##__VA_ARGS__)
+#else
+#define PTRACE(message, ...)
+#endif
+
+typedef enum P_Log_Level {
+ P_LOG_LEVEL_FATAL = 0,
+ P_LOG_LEVEL_ERROR,
+ P_LOG_LEVEL_WARN,
+ P_LOG_LEVEL_INFO,
+ P_LOG_LEVEL_DEBUG,
+ P_LOG_LEVEL_TRACE,
+ P_COUNT_LOG_LEVEL
+} P_Log_Level;
+
+#define P_PREFIX_LEN 7
+static const char *p_prefix[P_COUNT_LOG_LEVEL] = {
+ [P_LOG_LEVEL_FATAL] = "[FATAL]",
+ [P_LOG_LEVEL_ERROR] = "[ERROR]",
+ [P_LOG_LEVEL_WARN] = "[WARNI]",
+ [P_LOG_LEVEL_INFO] = "[INFOR]",
+ [P_LOG_LEVEL_DEBUG] = "[DEBUG]",
+ [P_LOG_LEVEL_TRACE] = "[TRACE]",
+};
+
+#define P_MAX_ALLOCS 512
+
+typedef struct P_DebugMemoryInfo {
+ void *ptr;
+ size_t size;
+ const char *file;
+ const char *func;
+ int line;
+} P_DebugMemoryInfo;
+
+static uint64_t p_alloc_count = 0;
+static P_DebugMemoryInfo p_ptr_array[P_MAX_ALLOCS];
+
+static inline void *
+p_debug_malloc_impl(size_t size, const char *file, int line, const char *func)
+{
+ void *ptr = malloc(size);
+ printf("[ALLOC] %p (%zu bytes) -> %s:%d %s()\n", ptr, size, file, line, func);
+
+ if (ptr) {
+ if (p_alloc_count < P_MAX_ALLOCS) {
+ p_ptr_array[p_alloc_count++] = (P_DebugMemoryInfo){
+ .ptr = ptr,
+ .size = size,
+ .file = file,
+ .func = func,
+ .line = line
+ };
+ } else {
+ fprintf(stderr, "[ERROR] Debug allocator tracking capacity (%d) exceeded!\n", P_MAX_ALLOCS);
+ }
+ }
+ return ptr;
+}
+
+static inline void
+p_debug_free_impl(void *ptr, const char *file, int line, const char *func)
+{
+ printf("[FREE] %p -> %s:%d %s()\n", ptr, file, line, func);
+
+ if (!ptr) return; // Standard C allows free(NULL)
+
+ bool found = false;
+ uint64_t index = 0;
+
+ /* Find allocation metadata */
+ for (index = 0; index < p_alloc_count; ++index) {
+ if (p_ptr_array[index].ptr == ptr) {
+ found = true;
+ break;
+ }
+ }
+
+ if (found) {
+ /* Shift array left to remove tracked struct */
+ for (uint64_t j = index; j < p_alloc_count - 1; ++j) {
+ p_ptr_array[j] = p_ptr_array[j + 1];
+ }
+ p_alloc_count--;
+ } else {
+ fprintf(stderr, "[WARNING] Attempted to free untracked/double-freed pointer %p at %s:%d %s()\n",
+ ptr, file, line, func);
+ }
+
+ free(ptr);
+}
+
+static inline void *
+p_debug_realloc_impl(void *ptr, size_t size, const char *file, int line, const char *func)
+{
+ if (!ptr) {
+ return p_debug_malloc_impl(size, file, line, func);
+ }
+ if (size == 0) {
+ p_debug_free_impl(ptr, file, line, func);
+ return NULL;
+ }
+
+ void *new_ptr = realloc(ptr, size);
+ printf("[REALLOC] %p -> %p (%zu bytes) -> %s:%d %s()\n", ptr, new_ptr, size, file, line, func);
+
+ if (new_ptr) {
+ bool found = false;
+ for (uint64_t i = 0; i < p_alloc_count; ++i) {
+ if (p_ptr_array[i].ptr == ptr) {
+ p_ptr_array[i].ptr = new_ptr;
+ p_ptr_array[i].size = size;
+ p_ptr_array[i].file = file;
+ p_ptr_array[i].line = line;
+ p_ptr_array[i].func = func;
+ found = true;
+ break;
+ }
+ }
+ if (!found) {
+ if (p_alloc_count < P_MAX_ALLOCS) {
+ p_ptr_array[p_alloc_count++] = (P_DebugMemoryInfo){
+ .ptr = new_ptr,
+ .size = size,
+ .file = file,
+ .func = func,
+ .line = line
+ };
+ }
+ }
+ }
+ return new_ptr;
+}
+
+static void
+p_debug_memory_report(void)
+{
+ printf("\n==================== MEMORY REPORT ====================\n");
+ printf("Remaining unfreed allocations: %lu\n", (unsigned long)p_alloc_count);
+
+ for (uint64_t i = 0; i < p_alloc_count; ++i) {
+ P_DebugMemoryInfo *info = &p_ptr_array[i];
+ printf("[LEAK] %p (%zu bytes) allocated at %s:%d in %s()\n",
+ info->ptr, info->size, info->file, info->line, info->func);
+ }
+ printf("=======================================================\n");
+}
+/* --- End of p_log.h --- */
+/* --- Start of p_ds.h --- */
+#define DEFAULT_ALIGNMENT (2 * sizeof(void *))
+#define ARRAY_GROW_FACTOR 2
+
+typedef struct {
+ u32 size;
+ u32 capacity;
+} DynamicArrayHeader;
+
+#define DARRAY_INIT_CAPACITY 64
+#define p_darray_push(array, var) \
+ do { \
+ if (array == NULL) { \
+ DynamicArrayHeader *header = \
+ malloc(DARRAY_INIT_CAPACITY * sizeof *array + sizeof *header); \
+ header->size = 0; \
+ header->capacity = DARRAY_INIT_CAPACITY; \
+ array = (void *)(header + 1); \
+ } \
+ DynamicArrayHeader *header = (DynamicArrayHeader *)(array) - 1; \
+ if (header->size >= header->capacity - 1) { \
+ unsigned long new_capacity = header->capacity * 2; \
+ DynamicArrayHeader *new_header = \
+ realloc(header, new_capacity * sizeof *array + sizeof *header); \
+ if (!new_header) \
+ break; \
+ header = new_header; \
+ array = (void *)(header + 1); \
+ header->capacity = new_capacity; \
+ } \
+ (array)[header->size++] = var; \
+ } while (0)
+
+#define p_darray_len(array) ((array) ? ((DynamicArrayHeader *)(array) - 1)->size : 0)
+#define p_darray_destroy(array) \
+{ \
+ free((DynamicArrayHeader *)(array) - 1); \
+}
+
+#define p_darray_shrink(array) \
+ do { \
+ DynamicArrayHeader *header = (array) ? ((DynamicArrayHeader *)(array) - 1) : 0;\
+ if (header) {\
+ if (header->capacity > 4) {\
+ unsigned long new_capacity = (header->capacity >> 1) + (header->capacity & 1); \
+ void *new_header = realloc(header, new_capacity * sizeof *array + sizeof *header); \
+ if (!new_header) break; \
+ header = new_header; \
+ array = (void *)(header + 1); \
+ header->capacity = new_capacity; \
+ }\
+ }\
+ } while (0)
+/* --- End of p_ds.h --- */
+
+/*
+ * Main Platform Types (Keyboard, Events, Context, etc.)
+ */
+
+typedef enum {
+ P_KEYMOD_ALT = 0,
+ P_KEYMOD_SHIFT,
+ P_KEYMOD_CTRL,
+ P_KEYMOD_CAPS,
+} P_KeyMod;
+
+typedef enum {
+ P_KEY_UNKNOWN = 0,
+ P_KEY_UP, P_KEY_DOWN, P_KEY_LEFT, P_KEY_RIGHT,
+ P_KEY_SPACE, P_KEY_ESCAPE, P_KEY_ENTER,
+ P_KEY_A, P_KEY_B, P_KEY_C, P_KEY_D, P_KEY_E, P_KEY_F, P_KEY_G, P_KEY_H, P_KEY_I,
+ P_KEY_J, P_KEY_K, P_KEY_L, P_KEY_M, P_KEY_N, P_KEY_O, P_KEY_P, P_KEY_Q, P_KEY_R,
+ P_KEY_S, P_KEY_T, P_KEY_U, P_KEY_V, P_KEY_W, P_KEY_X, P_KEY_Y, P_KEY_Z,
+} P_KeyCode;
+
+/* Platform event type */
+typedef enum {
+ P_EVENT_NONE = 0,
+ P_EVENT_KEY_DOWN,
+ P_EVENT_KEY_UP,
+ P_EVENT_WINDOW_CLOSE,
+ P_EVENT_WINDOW_RESIZE,
+ P_EVENT_POINTER,
+ P_EVENT_CONTROLLER_CONNECTED,
+ P_EVENT_CONTROLLER_DISCONNECTED,
+} P_EvenType;
+
+typedef enum {
+ P_POINTER_MOVED = 0,
+ P_POINTER_PRESSED,
+ P_POINTER_RELEASED
+} P_PointerState;
+
+typedef struct {
+ P_EvenType type;
+ union {
+ struct {P_KeyCode key; P_KeyMod mod; } key;
+ struct { u32 width, height; } resize;
+ struct { P_PointerState state; u32 button; u32 x, y; } pointer;
+ };
+} P_Event;
+
+/*
+ * Platform dependent functions to be implemented by each layer.
+ */
+
+POAPI u64 p_get_time(void); // Get time in nanoseconds.
+POAPI void p_sleep_ns(i64 ns); // Sleep for nanoseconds.
+
+POAPI void p_stdout(void *msg, usize bytes); // Print buffer to stdout.
+PODEF void p_log_printf(P_Log_Level level, const char* src, ...); // Print buffer to stdout.
+
+
+POAPI void* p_file_alloc(const char *path, unsigned long *buf_size);
+POAPI bool p_file_exists(const char *path); // Check if file exists.
+POAPI usize p_file_size(const char *path); // Check file size.
+POAPI void p_file_load(const char *path, void *buf_ptr, unsigned long buf_size); // Load file to buffer.
+PODEF void p_file_write(const char *path, void *buf_ptr, unsigned long buf_size); // Write buffer to file.
+
+typedef struct P_Window_Impl P_Window;
+POAPI bool p_window_open(P_Window *win, int width, int height, const char *title); // Opens a window. Returns false on failure.
+POAPI void p_window_close(P_Window *win); // Close window.
+POAPI bool p_window_is_open(P_Window *win); // Check if window is open.
+POAPI void p_window_size(P_Window *win, int *window_width, int *window_height); // Get window size.
+POAPI void p_window_draw(P_Window *win, u32 *pixels, int width, int height); // Draw directly to the window's buffer. Normally much slower than using the GPU.
+POAPI bool p_window_poll_event(P_Window *win, P_Event *ev); // Returns true while there are events to poll. Write event data to a pointer.
+
+POAPI void p_audio_init(const int sample_rate, const int channels, const char *name, const char *desc);
+POAPI void p_audio_quit();
+POAPI void p_audio_write(const i16 *samples, usize count);
+
+/*
+ * The Vulkan Module is platform specific
+ */
+
+#ifdef P_MODULE_VULKAN
+#include <vulkan/vulkan.h>
+POAPI char** p_vulkan_get_extensions();
+POAPI bool p_vulkan_create_surface(P_Window *window, VkInstance instance, const VkAllocationCallbacks* allocator, VkSurfaceKHR* out_surface);
+#endif
+
+/*
+ * The Remaining Modules are PLATFORM INDEPENDENT!
+ */
+
+#ifdef P_MODULE_STRING
+/* --- Start of p_string.h --- */
+typedef struct {
+ const char *cstr;
+ u32 len;
+} P_StringView;
+
+typedef struct {
+ P_StringView sv;
+} P_StringBuilder;
+
+/* Classic C string functions */
+PODEF char* p_find_char(char *buf, char needle);
+PODEF bool p_strcmp(const char *a, const char *b);
+PODEF int p_strlen(const char *a);
+PODEF int p_strtoi(const char *str);
+PODEF char* p_strtok(const char *str, char c);
+
+/* String views */
+PODEF P_StringView p_strview(const char *cstr);
+PODEF void p_strview_chop_left(P_StringView *sv, u32 n);
+PODEF void p_strview_chop_right(P_StringView *sv, u32 n);
+PODEF P_StringView p_strview_chop_delim(P_StringView *sv, char delim);
+PODEF P_StringView p_strview_chop_type(P_StringView *sv, int(*istype)(int));
+PODEF void p_strview_trim_left(P_StringView *sv);
+PODEF void p_strview_trim_right(P_StringView *sv);
+PODEF void p_strview_trim(P_StringView *sv);
+
+/* Classification */
+PODEF int p_is_space(int c);
+PODEF int p_is_digit(int c);
+PODEF int p_is_alpha(int c);
+PODEF int p_is_alnum(int c);
+PODEF int p_is_upper(int c);
+PODEF int p_is_lower(int c);
+PODEF int p_is_hex(int c);
+
+/* Transformation */
+PODEF int p_to_lower(int c);
+PODEF int p_to_upper(int c);
+/* --- End of p_string.h --- */
+#endif
+
+#ifdef P_MODULE_MATH
+/* --- Start of p_math.h --- */
+typedef struct {int x, y; } Vec2i;
+typedef struct {float x, y; } Vec2f;
+typedef struct {float x, y, z; } Vec3f;
+typedef struct { float m[16];} P_Mat4; // column-major: m[col * 4 + row]
+PODEF int p_ceil(float x);
+PODEF float p_cosf(float x);
+PODEF float p_sinf(float x);
+
+PODEF Vec2f p_vec2f(float, float);
+PODEF Vec2f p_vec2f_add(Vec2f, Vec2f);
+PODEF float p_vec2f_cross(Vec2f, Vec2f);
+PODEF float p_vec2f_dot(Vec2f, Vec2f);
+PODEF Vec2f p_vec2f_mult(Vec2f a, float b);
+PODEF Vec2f p_vec2f_sub(Vec2f, Vec2f);
+PODEF Vec2i p_vec2i(float, float);
+PODEF Vec2i p_vec2i_add(Vec2i, Vec2i);
+PODEF float p_vec2i_cross(Vec2i, Vec2i);
+PODEF float p_vec2i_dot(Vec2i, Vec2i);
+PODEF Vec2i p_vec2i_mult(Vec2i a, float b);
+PODEF Vec2i p_vec2i_sub(Vec2i, Vec2i);
+
+PODEF Vec3f p_vec3f(float, float, float);
+
+PODEF P_Mat4 p_mat4_identity(void);
+PODEF P_Mat4 p_mat4_mul(P_Mat4 a, P_Mat4 b);
+PODEF P_Mat4 p_mat4_translate(Vec3f v);
+PODEF P_Mat4 p_mat4_translate_by(P_Mat4 m, Vec3f v);
+PODEF P_Mat4 p_mat4_rotate_x(float rad);
+PODEF P_Mat4 p_mat4_rotate_x_by(P_Mat4 m, float rad);
+PODEF P_Mat4 p_mat4_rotate_y(float rad);
+PODEF P_Mat4 p_mat4_rotate_y_by(P_Mat4 m, float rad);
+PODEF P_Mat4 p_mat4_rotate_z(float rad);
+PODEF P_Mat4 p_mat4_perspective(float fov_rad, float aspect, float near_z, float far_z);
+/* --- End of p_math.h --- */
+#endif
+
+#ifdef P_MODULE_ALLOC
+/* --- Start of p_allocators.h --- */
+typedef struct Arena {
+ unsigned char *buf;
+ usize buf_len;
+ usize curr_offset;
+ usize prev_offset;
+} Arena;
+
+PODEF void p_arena_create(Arena *a, void *backing_buffer, usize backing_buffer_length);
+PODEF void* p_arena_alloc_align(Arena *a, usize s, usize align);
+PODEF void* p_arena_alloc(Arena *a, usize s);
+PODEF void* p_arena_resize_align(Arena *a, void *old_memory, usize old_size, usize new_size, usize align);
+PODEF void* p_arena_resize(Arena *a, void *old_memory, usize old_size, usize new_size);
+PODEF void p_arena_free_all(Arena *a);
+PODEF void p_arena_destroy(Arena* a);
+
+typedef struct { u8 padding; } Stack_Allocation_Header;
+typedef struct Stack {
+ unsigned char *buf;
+ usize buf_len;
+ usize offset;
+} Stack;
+
+PODEF void p_stack_create(Stack *s, void *backing_buffer, usize backing_buffer_length);
+PODEF usize calc_padding_with_header(uintptr ptr, uintptr alignment, usize header_size);
+PODEF void* p_stack_alloc(Stack *s, usize len, usize alignment);
+PODEF void p_stack_free(Stack *s, void *ptr);
+PODEF void p_stack_free_all(Stack* s);
+PODEF void p_stack_destroy(Stack* s);
+
+typedef struct Pool_Free_Node Pool_Free_Node;
+
+typedef struct Pool {
+ unsigned char *buf;
+ usize chunk_size;
+ usize pool_size;
+ Pool_Free_Node *head;
+} Pool;
+
+struct Pool_Free_Node { struct Pool_Free_Node *next; };
+PODEF void p_pool_create(Pool *p, void *buf, usize buf_len, usize chunk_size, usize chunk_align);
+PODEF void* p_pool_alloc(Pool *p);
+PODEF void p_pool_free(Pool *p, void *ptr);
+PODEF void p_pool_free_all(Pool *p);
+PODEF void p_pool_destroy(Pool *p);
+/* --- End of p_allocators.h --- */
+#endif
+
+#endif /* _PODIUM_H_ */
+
+#ifdef PODIUM_IMPLEMENTATION
+#undef PODIUM_IMPLEMENTATION
+
+#if defined(PODIUM_SDL)
+/* #include "p_platform_sdl.c" */
+#elif defined(PODIUM_WIN32)
+/* --- Start of p_platform_win32.c --- */
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#include <mmsystem.h>
+#include <xinput.h> /* gamepad support */
+
+typedef struct {
+ HWAVEOUT wave_out;
+ WAVEHDR wave_header;
+} P_Win32Ctx;
+
+struct P_Window_Impl {
+ HWND hwnd;
+ HDC hdc;
+ BITMAPINFO bitmap_info;
+ int width;
+ int height;
+ bool closed;
+};
+
+P_Win32Ctx p_ctx = {0};
+
+static inline P_KeyCode
+_win32_translate_vkey(WPARAM vk)
+{
+ switch (vk) {
+ case VK_LEFT: return P_KEY_LEFT;
+ case VK_RIGHT: return P_KEY_RIGHT;
+ case VK_UP: return P_KEY_UP;
+ case VK_DOWN: return P_KEY_DOWN;
+ case VK_SPACE: return P_KEY_SPACE;
+ case VK_ESCAPE: return P_KEY_ESCAPE;
+ case VK_RETURN: return P_KEY_ENTER;
+ case 'A': return P_KEY_A;
+ case 'B': return P_KEY_B;
+ case 'C': return P_KEY_C;
+ case 'D': return P_KEY_D;
+ case 'E': return P_KEY_E;
+ case 'F': return P_KEY_F;
+ case 'G': return P_KEY_G;
+ case 'H': return P_KEY_H;
+ case 'I': return P_KEY_I;
+ case 'J': return P_KEY_J;
+ case 'K': return P_KEY_K;
+ case 'L': return P_KEY_L;
+ case 'M': return P_KEY_M;
+ case 'N': return P_KEY_N;
+ case 'O': return P_KEY_O;
+ case 'P': return P_KEY_P;
+ case 'Q': return P_KEY_Q;
+ case 'R': return P_KEY_R;
+ case 'S': return P_KEY_S;
+ case 'T': return P_KEY_T;
+ case 'U': return P_KEY_U;
+ case 'V': return P_KEY_V;
+ case 'W': return P_KEY_W;
+ case 'X': return P_KEY_X;
+ case 'Y': return P_KEY_Y;
+ case 'Z': return P_KEY_Z;
+ default: return P_KEY_UNKNOWN;
+ }
+}
+
+POAPI u64
+p_get_time(void)
+{
+ LARGE_INTEGER count, freq;
+ QueryPerformanceCounter(&count);
+ QueryPerformanceFrequency(&freq);
+ return (u64)((count.QuadPart * 1000000000ULL) / freq.QuadPart);
+}
+
+POAPI void
+p_sleep_ns(i64 ns)
+{
+ /* windows sleep is millisecond-based........ */
+ Sleep((DWORD)(ns / 1000000));
+}
+
+POAPI void
+p_stdout(void *msg, usize bytes)
+{
+ HANDLE stdout_handle = GetStdHandle(STD_OUTPUT_HANDLE);
+ DWORD bytes_written;
+ WriteFile(stdout_handle, msg, bytes, &bytes_written, NULL);
+}
+
+POAPI bool
+p_file_exists(const char *path)
+{
+ DWORD attr = GetFileAttributesA(path);
+ return (attr != INVALID_FILE_ATTRIBUTES && !(attr & FILE_ATTRIBUTE_DIRECTORY));
+}
+
+POAPI usize
+p_file_size(const char *path)
+{
+ WIN32_FILE_ATTRIBUTE_DATA data;
+ if (GetFileAttributesExA(path, GetFileExInfoStandard, &data)) {
+ return data.nFileSizeLow;
+ }
+ return 0;
+}
+
+PODEF void
+p_file_load(const char *path, void *buf_ptr, unsigned long buf_size)
+{
+ HANDLE file = CreateFileA(path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
+ if (file != INVALID_HANDLE_VALUE) {
+ DWORD bytes_read;
+ ReadFile(file, buf_ptr, buf_size, &bytes_read, NULL);
+ CloseHandle(file);
+ }
+}
+
+PODEF void
+p_file_write(const char *path, void *buf_ptr, unsigned long buf_size)
+{
+ HANDLE file = CreateFileA(path, GENERIC_WRITE, 0, NULL,
+ CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
+ if (file != INVALID_HANDLE_VALUE) {
+ DWORD bytes_written;
+ WriteFile(file, buf_ptr, buf_size, &bytes_written, NULL);
+ CloseHandle(file);
+ }
+}
+
+static LRESULT CALLBACK
+_win32_wnd_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
+ P_Window *win = (P_Window*)GetWindowLongPtrA(hwnd, GWLP_USERDATA);
+ switch (msg) {
+ case WM_CLOSE:
+ /* Handled in poll_event; mark as closed */
+ if (win) win->closed = true;
+ return 0;
+ }
+ return DefWindowProcA(hwnd, msg, wparam, lparam);
+}
+
+POAPI bool
+p_window_open(P_Window *win, int width, int height, const char *title)
+{
+ HINSTANCE instance = GetModuleHandleA(NULL);
+
+ WNDCLASSA wc = {0};
+ wc.lpfnWndProc = _win32_wnd_proc;
+ wc.hInstance = instance;
+ wc.lpszClassName = "P_Window_Class";
+ wc.hCursor = LoadCursor(NULL, IDC_ARROW);
+
+ RegisterClassA(&wc);
+
+ win->hwnd = CreateWindowExA(0, wc.lpszClassName, title,
+ WS_OVERLAPPEDWINDOW | WS_VISIBLE,
+ CW_USEDEFAULT, CW_USEDEFAULT, width, height,
+ NULL, NULL, instance, NULL);
+
+ if (!win->hwnd) return false;
+
+ SetWindowLongPtrA(win->hwnd, GWLP_USERDATA, (LONG_PTR)win);
+ win->hdc = GetDC(win->hwnd);
+ win->width = width;
+ win->height = height;
+ win->closed = false;
+
+ return true;
+}
+
+POAPI void
+p_window_close(P_Window *win)
+{
+ if (!win) return;
+ if (win->hdc) ReleaseDC(win->hwnd, win->hdc);
+ if (win->hwnd) DestroyWindow(win->hwnd);
+ win->hdc = NULL;
+ win->hwnd = NULL;
+}
+
+POAPI bool
+p_window_is_open(P_Window *win)
+{
+ return win && win->hwnd != NULL;
+}
+
+POAPI void
+p_window_size(P_Window *win, int *window_width, int *window_height)
+{
+ if (!win) return;
+ RECT rect;
+ GetClientRect(win->hwnd, &rect);
+ *window_width = rect.right - rect.left;
+ *window_height = rect.bottom - rect.top;
+ win->width = *window_width;
+ win->height = *window_height;
+}
+
+POAPI void
+p_window_draw(P_Window *win, u32 *pixels, int width, int height)
+{
+ BITMAPINFO bmi = {0};
+ bmi.bmiHeader.biSize = sizeof(bmi.bmiHeader);
+ bmi.bmiHeader.biWidth = width;
+ bmi.bmiHeader.biHeight = -height; /* top-down */
+ bmi.bmiHeader.biPlanes = 1;
+ bmi.bmiHeader.biBitCount = 32;
+ bmi.bmiHeader.biCompression = BI_RGB;
+
+ StretchDIBits(win->hdc,
+ 0, 0, win->width, win->height,
+ 0, 0, width, height,
+ pixels, &bmi, DIB_RGB_COLORS, SRCCOPY);
+}
+
+POAPI bool
+p_window_poll_event(P_Window *win, P_Event *ev)
+{
+ if (win->closed) {
+ win->closed = false;
+ ev->type = P_EVENT_WINDOW_CLOSE;
+ return true;
+ }
+
+ MSG msg;
+ while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) {
+ switch (msg.message) {
+
+ case WM_QUIT:
+ ev->type = P_EVENT_WINDOW_CLOSE;
+ return true;
+
+ /* Key press */
+ case WM_KEYDOWN:
+ case WM_SYSKEYDOWN:
+ ev->type = P_EVENT_KEY_DOWN;
+ ev->key.key = _win32_translate_vkey(msg.wParam);
+ return true;
+
+ /* Key release */
+ case WM_KEYUP:
+ case WM_SYSKEYUP:
+ ev->type = P_EVENT_KEY_UP;
+ ev->key.key = _win32_translate_vkey(msg.wParam);
+ return true;
+
+ /* Mouse movement */
+ case WM_MOUSEMOVE:
+ ev->type = P_EVENT_POINTER;
+ ev->pointer.state = P_POINTER_MOVED;
+ ev->pointer.button = 0;
+ ev->pointer.x = (u32)(msg.lParam & 0xFFFF);
+ ev->pointer.y = (u32)((msg.lParam >> 16) & 0xFFFF);
+ return true;
+
+ /* Mouse buttons */
+ case WM_LBUTTONDOWN:
+ ev->type = P_EVENT_POINTER;
+ ev->pointer.state = P_POINTER_PRESSED;
+ ev->pointer.button = 1; /* 1 = LMB, matching X11 convention */
+ ev->pointer.x = (u32)(msg.lParam & 0xFFFF);
+ ev->pointer.y = (u32)((msg.lParam >> 16) & 0xFFFF);
+ return true;
+
+ case WM_LBUTTONUP:
+ ev->type = P_EVENT_POINTER;
+ ev->pointer.state = P_POINTER_RELEASED;
+ ev->pointer.button = 1;
+ ev->pointer.x = (u32)(msg.lParam & 0xFFFF);
+ ev->pointer.y = (u32)((msg.lParam >> 16) & 0xFFFF);
+ return true;
+
+ case WM_RBUTTONDOWN:
+ ev->type = P_EVENT_POINTER;
+ ev->pointer.state = P_POINTER_PRESSED;
+ ev->pointer.button = 3; /* 3 = RMB */
+ ev->pointer.x = (u32)(msg.lParam & 0xFFFF);
+ ev->pointer.y = (u32)((msg.lParam >> 16) & 0xFFFF);
+ return true;
+
+ case WM_RBUTTONUP:
+ ev->type = P_EVENT_POINTER;
+ ev->pointer.state = P_POINTER_RELEASED;
+ ev->pointer.button = 3;
+ ev->pointer.x = (u32)(msg.lParam & 0xFFFF);
+ ev->pointer.y = (u32)((msg.lParam >> 16) & 0xFFFF);
+ return true;
+
+ case WM_MBUTTONDOWN:
+ ev->type = P_EVENT_POINTER;
+ ev->pointer.state = P_POINTER_PRESSED;
+ ev->pointer.button = 2; /* 2 = MMB */
+ ev->pointer.x = (u32)(msg.lParam & 0xFFFF);
+ ev->pointer.y = (u32)((msg.lParam >> 16) & 0xFFFF);
+ return true;
+
+ case WM_MBUTTONUP:
+ ev->type = P_EVENT_POINTER;
+ ev->pointer.state = P_POINTER_RELEASED;
+ ev->pointer.button = 2;
+ ev->pointer.x = (u32)(msg.lParam & 0xFFFF);
+ ev->pointer.y = (u32)((msg.lParam >> 16) & 0xFFFF);
+ return true;
+
+ /* Window resize */
+ case WM_SIZE:
+ ev->type = P_EVENT_WINDOW_RESIZE;
+ ev->resize.width = (u32)(msg.lParam & 0xFFFF);
+ ev->resize.height = (u32)((msg.lParam >> 16) & 0xFFFF);
+ win->width = ev->resize.width;
+ win->height = ev->resize.height;
+ return true;
+
+ default:
+ TranslateMessage(&msg);
+ DispatchMessageA(&msg);
+ break;
+ }
+ }
+
+ ev->type = P_EVENT_NONE;
+ return false;
+}
+
+
+POAPI void
+p_audio_init(const int sample_rate, const int channels, const char *name, const char *desc)
+{
+ (void)name; (void)desc; /* WinMM doesn't use a stream name */
+
+ WAVEFORMATEX wfx = {0};
+ wfx.wFormatTag = WAVE_FORMAT_PCM;
+ wfx.nChannels = channels;
+ wfx.nSamplesPerSec = sample_rate;
+ wfx.wBitsPerSample = 16;
+ wfx.nBlockAlign = (wfx.nChannels * wfx.wBitsPerSample) / 8;
+ wfx.nAvgBytesPerSec = wfx.nSamplesPerSec * wfx.nBlockAlign;
+
+ if (waveOutOpen(&p_ctx.wave_out, WAVE_MAPPER, &wfx, 0, 0, CALLBACK_NULL) != MMSYSERR_NOERROR) {
+ exit(1);
+ }
+}
+
+POAPI void
+p_audio_quit()
+{
+ if (p_ctx.wave_out) {
+ waveOutReset(p_ctx.wave_out);
+ waveOutClose(p_ctx.wave_out);
+ p_ctx.wave_out = NULL;
+ }
+}
+
+POAPI void
+p_audio_write(const i16 *samples, usize count)
+{
+ if (!p_ctx.wave_out) return;
+
+ WAVEHDR header = {0};
+ header.lpData = (LPSTR)samples;
+ header.dwBufferLength = (DWORD)(count * sizeof(i16));
+
+ waveOutPrepareHeader(p_ctx.wave_out, &header, sizeof(WAVEHDR));
+ waveOutWrite(p_ctx.wave_out, &header, sizeof(WAVEHDR));
+
+ /* wait for playback to finish (synchronous, mirrors pa_simple_drain) */
+ while (!(header.dwFlags & WHDR_DONE)) Sleep(1);
+
+ waveOutUnprepareHeader(p_ctx.wave_out, &header, sizeof(WAVEHDR));
+}
+
+#ifdef P_MODULE_VULKAN
+
+#ifndef VK_USE_PLATFORM_WIN32_KHR
+#define VK_USE_PLATFORM_WIN32_KHR
+#endif
+#include <vulkan/vulkan_win32.h>
+
+POAPI char**
+p_vulkan_get_extensions()
+{
+ char **darr = NULL;
+ p_darray_push(darr, "VK_KHR_surface");
+ p_darray_push(darr, "VK_KHR_win32_surface");
+ return darr;
+}
+
+POAPI bool
+p_vulkan_create_surface(P_Window *window, VkInstance instance, const VkAllocationCallbacks* allocator, VkSurfaceKHR* out_surface)
+{
+ if (!instance || !window || !window->hwnd || !out_surface) {
+ return false;
+ }
+
+ VkWin32SurfaceCreateInfoKHR create_info = {0};
+ create_info.sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR;
+ create_info.pNext = NULL;
+ create_info.flags = 0;
+ create_info.hwnd = window->hwnd;
+ create_info.hinstance = GetModuleHandleA(NULL);
+
+ VkResult result = vkCreateWin32SurfaceKHR(instance, &create_info, allocator, out_surface);
+ return (result == VK_SUCCESS);
+}
+#endif
+/* --- End of p_platform_win32.c --- */
+#elif defined(PODIUM_LINUX)
+/* --- Start of p_platform_linux.c --- */
+/* linux */
+#include <time.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <dirent.h>
+#include <sys/stat.h>
+#include <errno.h>
+/* x11 */
+#include <X11/Xlib.h>
+#include <X11/keysym.h>
+/* pulse audio */
+#include <pulse/pulseaudio.h>
+#include <pulse/simple.h>
+#include <pulse/error.h>
+/* joystick */
+#include <linux/joystick.h>
+
+typedef struct {
+ pa_simple *audio_stream;
+} P_LinuxCtx;
+
+struct P_Window_Impl {
+ Display *display;
+ XImage *image;
+ Window window;
+ GC gc;
+ int screen;
+ int width;
+ int height;
+};
+
+P_LinuxCtx p_ctx = {0};
+
+static inline P_KeyCode
+_x11_translate_keycode(XEvent xev)
+{
+ static KeySym ks;
+ ks = XLookupKeysym(&xev.xkey, 0);
+ switch (ks) {
+ /* Arrow keys */
+ case XK_Left: return P_KEY_LEFT;
+ case XK_Right: return P_KEY_RIGHT;
+ case XK_Up: return P_KEY_UP;
+ case XK_Down: return P_KEY_DOWN;
+ /* Common keys */
+ case XK_space: return P_KEY_SPACE;
+ case XK_Escape: return P_KEY_ESCAPE;
+ case XK_Return: return P_KEY_ENTER;
+ case XK_A: case XK_a: return P_KEY_A;
+ case XK_B: case XK_b: return P_KEY_B;
+ case XK_C: case XK_c: return P_KEY_C;
+ case XK_D: case XK_d: return P_KEY_D;
+ case XK_E: case XK_e: return P_KEY_E;
+ case XK_F: case XK_f: return P_KEY_F;
+ case XK_G: case XK_g: return P_KEY_G;
+ case XK_H: case XK_h: return P_KEY_H;
+ case XK_I: case XK_i: return P_KEY_I;
+ case XK_J: case XK_j: return P_KEY_J;
+ case XK_K: case XK_k: return P_KEY_K;
+ case XK_L: case XK_l: return P_KEY_L;
+ case XK_M: case XK_m: return P_KEY_M;
+ case XK_N: case XK_n: return P_KEY_N;
+ case XK_O: case XK_o: return P_KEY_O;
+ case XK_P: case XK_p: return P_KEY_P;
+ case XK_Q: case XK_q: return P_KEY_Q;
+ case XK_R: case XK_r: return P_KEY_R;
+ case XK_S: case XK_s: return P_KEY_S;
+ case XK_T: case XK_t: return P_KEY_T;
+ case XK_U: case XK_u: return P_KEY_U;
+ case XK_V: case XK_v: return P_KEY_V;
+ case XK_W: case XK_w: return P_KEY_W;
+ case XK_X: case XK_x: return P_KEY_X;
+ case XK_Y: case XK_y: return P_KEY_Y;
+ case XK_Z: case XK_z: return P_KEY_Z;
+ default: return P_KEY_UNKNOWN;
+ }
+}
+
+POAPI u64
+p_get_time(void)
+{
+ struct timespec ts;
+ clock_gettime(CLOCK_MONOTONIC, &ts);
+ return NANOS_PER_SEC * ts.tv_sec + ts.tv_nsec;
+}
+
+POAPI void
+p_sleep_ns(i64 ns)
+{
+ struct timespec ts;
+ ts.tv_sec = ns / 1000000000L;
+ ts.tv_nsec = ns % 1000000000L;
+ clock_nanosleep(CLOCK_MONOTONIC, 0, &ts, NULL);
+}
+
+POAPI void
+p_stdout(void *msg, usize bytes)
+{
+ write(1, msg, bytes);
+}
+
+POAPI bool
+p_file_exists(const char *path)
+{
+ return (access(path, F_OK) == 0);
+}
+
+POAPI usize
+p_file_size(const char *path)
+{
+ struct stat st;
+ if (stat(path, &st) == 0) {
+ return st.st_size;
+ }
+ return 0;
+}
+
+PODEF void
+p_file_load(const char *path, void *buf_ptr, unsigned long buf_size)
+{
+ int fd = open(path, O_RDONLY);
+ if (fd >= 0) {
+ read(fd, buf_ptr, (size_t)buf_size);
+ close(fd);
+ }
+}
+
+PODEF void
+p_file_write(const char *path, void *buf_ptr, unsigned long buf_size)
+{
+ int fd = open(path, O_WRONLY | O_CREAT | O_APPEND, 0644);
+ if (fd >= 0) {
+ write(fd, buf_ptr, (size_t)buf_size);
+ close(fd);
+ }
+}
+
+POAPI bool
+p_window_open(P_Window *win, int width, int height, const char *title)
+{
+ win->width = width;
+ win->height = height;
+
+ XInitThreads();
+
+ win->display = XOpenDisplay(NULL);
+ if (win->display == NULL) {
+ PERROR("Cannot open display!");
+ return false;
+ }
+
+ int screen = DefaultScreen(win->display);
+ win->window = XCreateSimpleWindow(
+ win->display,
+ RootWindow(win->display, screen),
+ 0, 0, width, height,
+ 1,
+ BlackPixel(win->display, screen),
+ BlackPixel(win->display, screen)
+ );
+
+ win->screen = screen;
+
+ XStoreName(win->display, win->window, title);
+ XSelectInput(win->display, win->window,
+ KeyPressMask | KeyReleaseMask |
+ ButtonPressMask | ButtonReleaseMask |
+ PointerMotionMask | StructureNotifyMask);
+ XMapWindow(win->display, win->window);
+
+ win->gc = DefaultGC(win->display, screen);
+
+ Atom wm_delete = XInternAtom(win->display, "WM_DELETE_WINDOW", False);
+ XSetWMProtocols(win->display, win->window, &wm_delete, 1);
+
+ return true;
+}
+
+POAPI void
+p_window_close(P_Window *win)
+{
+ if (!win) return;
+
+ if (win->image) {
+ // XDestroyImage(win->image);
+ win->image = NULL;
+ }
+
+ if (win->display) {
+ Display *dpy = win->display;
+ Window w = win->window;
+ win->display = NULL;
+ win->window = 0;
+
+ if (w) {
+ XDestroyWindow(dpy, w);
+ }
+ XSync(dpy, False);
+ }
+}
+
+POAPI bool
+p_window_is_open(P_Window *win)
+{
+ return win && win->display != NULL;
+}
+
+POAPI void
+p_window_size(P_Window *win, int *window_width, int *window_height)
+{
+ if (!win) return;
+
+ XWindowAttributes attr;
+ XGetWindowAttributes(win->display, win->window, &attr);
+ *window_width = attr.width;
+ *window_height = attr.height;
+
+ win->width = attr.width;
+ win->height = attr.height;
+}
+
+POAPI void
+p_window_draw(P_Window *win, u32 *pixels, int width, int height)
+{
+ int screen = win->screen;
+
+ win->image = XCreateImage(
+ win->display,
+ DefaultVisual(win->display, screen),
+ DefaultDepth(win->display, screen),
+ ZPixmap,
+ 0,
+ (char*)pixels,
+ width,
+ height,
+ 32,
+ width * 4
+ );
+
+ int window_width, window_height;
+ p_window_size(win, &window_width, &window_height);
+
+ XPutImage(
+ win->display,
+ win->window,
+ win->gc,
+ win->image,
+ 0, 0,
+ 0, 0,
+ win->width,
+ win->height);
+
+ XFlush(win->display);
+}
+
+POAPI bool
+p_window_poll_event(P_Window *win, P_Event *ev)
+{
+ if (XPending(win->display)) {
+ static XEvent xev;
+ XNextEvent(win->display, &xev);
+
+ switch (xev.type) {
+
+ case KeyPress:
+ ev->type = P_EVENT_KEY_DOWN;
+ ev->key.key = _x11_translate_keycode(xev);
+ return true;
+
+ case KeyRelease:
+ ev->type = P_EVENT_KEY_UP;
+ ev->key.key = _x11_translate_keycode(xev);
+ return true;
+
+ case ConfigureNotify:
+ ev->type = P_EVENT_WINDOW_RESIZE;
+ ev->resize.width = xev.xconfigure.width;
+ ev->resize.height = xev.xconfigure.height;
+ return true;
+
+ case ClientMessage:
+ if ((Atom)xev.xclient.data.l[0] ==
+ XInternAtom(win->display, "WM_DELETE_WINDOW", False)) {
+ ev->type = P_EVENT_WINDOW_CLOSE;
+ return true;
+ }
+ break;
+
+ case MotionNotify:
+ ev->type = P_EVENT_POINTER;
+ ev->pointer.state = P_POINTER_MOVED;
+ ev->pointer.button = 0;
+ ev->pointer.x = xev.xmotion.x;
+ ev->pointer.y = xev.xmotion.y;
+ return true;
+
+ case ButtonPress:
+ ev->type = P_EVENT_POINTER;
+ ev->pointer.state = P_POINTER_PRESSED;
+ ev->pointer.button = xev.xbutton.button; /* 1=LMB, 2=MMB, 3=RMB */
+ ev->pointer.x = xev.xbutton.x;
+ ev->pointer.y = xev.xbutton.y;
+ return true;
+
+ case ButtonRelease:
+ ev->type = P_EVENT_POINTER;
+ ev->pointer.state = P_POINTER_RELEASED;
+ ev->pointer.button = xev.xbutton.button;
+ ev->pointer.x = xev.xbutton.x;
+ ev->pointer.y = xev.xbutton.y;
+ return true;
+ }
+ }
+
+ ev->type = P_EVENT_NONE;
+ return false;
+}
+
+POAPI void
+p_audio_init(const int sample_rate, const int channels, const char *name, const char *desc)
+{
+ pa_sample_spec ss = {
+ .format = PA_SAMPLE_S16LE,
+ .rate = sample_rate,
+ .channels = channels,
+ };
+
+ int error;
+ p_ctx.audio_stream = pa_simple_new(
+ NULL,
+ name,
+ PA_STREAM_PLAYBACK,
+ NULL,
+ desc,
+ &ss,
+ NULL,
+ NULL,
+ &error
+ );
+
+ if (!p_ctx.audio_stream) {
+ PERROR("PulseAudio init failed: %s\n", pa_strerror(error));
+ exit(1);
+ }
+}
+
+POAPI void
+p_audio_quit()
+{
+ if (p_ctx.audio_stream) {
+ pa_simple_free(p_ctx.audio_stream);
+ p_ctx.audio_stream = NULL;
+ }
+}
+
+POAPI void
+p_audio_write(const i16 *samples, usize count)
+{
+ if (!p_ctx.audio_stream) return;
+
+ int error;
+ if (pa_simple_write(p_ctx.audio_stream, samples, count * sizeof(i16), &error) < 0) {
+ PERROR("PulseAudio write failed: %s\n", pa_strerror(error));
+ }
+
+ pa_simple_drain(p_ctx.audio_stream, &error);
+}
+
+#ifdef P_MODULE_VULKAN
+
+#ifndef VK_USE_PLATFORM_XLIB_KHR
+#define VK_USE_PLATFORM_XLIB_KHR
+#endif
+#include <vulkan/vulkan_xlib.h>
+
+POAPI char**
+p_vulkan_get_extensions()
+{
+ char **darr = NULL;
+ p_darray_push(darr, "VK_KHR_surface");
+ p_darray_push(darr, "VK_KHR_xcb_surface");
+ p_darray_push(darr, "VK_KHR_xlib_surface");
+ return darr;
+}
+
+POAPI bool
+p_vulkan_create_surface(P_Window *window, VkInstance instance, const VkAllocationCallbacks* allocator, VkSurfaceKHR* out_surface)
+{
+ if (!instance || !window || !window->display || !window->window || !out_surface) {
+ return false;
+ }
+
+ VkXlibSurfaceCreateInfoKHR create_info = {0};
+ create_info.sType = VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR;
+ create_info.pNext = NULL;
+ create_info.flags = 0;
+ create_info.dpy = window->display;
+ create_info.window = window->window;
+
+ VkResult result = vkCreateXlibSurfaceKHR(instance, &create_info, allocator, out_surface);
+
+ return (result == VK_SUCCESS);
+}
+#endif
+/* --- End of p_platform_linux.c --- */
+#endif /* linux */
+
+
+POAPI void* p_file_alloc(const char *path, unsigned long *buf_size) {
+ if (p_file_exists(path) == false) {
+ return NULL;
+ }
+
+ usize file_size = p_file_size(path);
+ *buf_size = file_size;
+
+ void *ptr = malloc(file_size);
+ if (ptr) {
+ p_file_load(path, ptr, file_size); // Load file to buffer.
+ }
+ return ptr;
+}
+
+
+/*
+ * Import Module Code
+ */
+
+#ifdef P_MODULE_STRING
+/* --- Start of p_string.c --- */
+PODEF char*
+p_find_char(char *buf, char needle)
+{
+ while (buf && *buf != needle) buf++;
+ return buf;
+}
+
+PODEF bool
+p_strcmp(const char *a, const char *b)
+{
+ if (p_strlen(a) != p_strlen(b))
+ return false;
+
+ while (a && b && *a != '\0') {
+ if (*(a++) != *(b++)) return false;
+ }
+
+ return true;
+}
+
+PODEF int
+p_strlen(const char *a)
+{
+ int i = 0;
+ while (*a++ != '\0') i++;
+ return i;
+}
+
+PODEF int
+p_strtoi(const char *str)
+{
+ int res = 0;
+
+ while (*str) {
+ if (*str >= '0' && *str <= '9') {
+ res = res * 10 + (*str - '0');
+ } else {
+ return res;
+ }
+ str++;
+ }
+
+ return res;
+}
+
+PODEF char*
+p_strtok(const char *str, char c)
+{
+ while (*str != c && *str++ != '\0');
+ return (*str == c) ? (char*) ++str : 0;
+}
+
+PODEF P_StringView
+p_strview(const char *cstr)
+{
+ P_StringView sv = {0};
+ sv.cstr = cstr;
+ sv.len = p_strlen(cstr);
+ return sv;
+}
+
+PODEF void
+p_strview_chop_left(P_StringView *sv, u32 n)
+{
+ if (n > sv->len) n = sv->len;
+ sv->cstr += n;
+ sv->len -= n;
+}
+
+PODEF void
+p_strview_chop_right(P_StringView *sv, u32 n)
+{
+ if (n > sv->len) n = sv->len;
+ sv->len -= n;
+}
+
+PODEF P_StringView
+p_strview_chop_delim(P_StringView *sv, char delim)
+{
+ u32 i = 0;
+ while (i < sv->len && sv->cstr[i] != delim) {
+ i++;
+ }
+
+ P_StringView tok;
+ if (i < sv->len) {
+ tok.cstr = sv->cstr;
+ tok.len = i;
+ p_strview_chop_left(sv, i + 1);
+ return tok;
+ }
+
+ tok = *sv;
+ p_strview_chop_left(sv, sv->len);
+ return tok;
+}
+
+PODEF P_StringView
+p_strview_chop_type(P_StringView *sv, int(*istype)(int))
+{
+ u32 i = 0;
+ while (i < sv->len && istype(sv->cstr[i])) {
+ i++;
+ }
+
+ P_StringView tok;
+ if (i < sv->len) {
+ tok.cstr = sv->cstr;
+ tok.len = i;
+ p_strview_chop_left(sv, i + 1);
+ return tok;
+ }
+
+ tok = *sv;
+ p_strview_chop_left(sv, sv->len);
+ return tok;
+}
+
+
+PODEF void
+p_strview_trim_left(P_StringView *sv)
+{
+ while (sv->len > 0 && p_is_space(sv->cstr[0])) {
+ p_strview_chop_left(sv, 1);
+ }
+}
+
+PODEF void
+p_strview_trim_right(P_StringView *sv)
+{
+ while (sv->len > 0 && p_is_space(sv->cstr[sv->len-1])) {
+ p_strview_chop_right(sv, 1);
+ }
+}
+
+PODEF void
+p_strview_trim(P_StringView *sv)
+{
+ p_strview_trim_left(sv);
+ p_strview_trim_right(sv);
+}
+
+PODEF int
+p_is_space(int c)
+{
+ /* Checks for: space, form feed (\f), line feed (\n),
+ * carriage return (\r), horizontal tab (\t), vertical tab (\v) */
+ return (c == ' ' || (c >= '\t' && c <= '\r'));
+}
+
+PODEF int
+p_is_digit(int c)
+{
+ return (c >= '0' && c <= '9');
+}
+
+PODEF int
+p_is_alpha(int c)
+{
+ return ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'));
+}
+
+PODEF int
+p_is_alnum(int c)
+{
+ return (p_is_alpha(c) || p_is_digit(c));
+}
+
+PODEF int
+p_is_hex(int c)
+{
+ return (p_is_digit(c) ||
+ (c >= 'a' && c <= 'f') ||
+ (c >= 'A' && c <= 'F'));
+}
+
+PODEF int
+p_is_upper(int c)
+{
+ return (c >= 'A' && c <= 'Z');
+}
+
+PODEF int
+p_is_lower(int c)
+{
+ return (c >= 'a' && c <= 'z');
+}
+
+PODEF int
+p_to_lower(int c)
+{
+ if (p_is_upper(c)) return (c + ('a' - 'A'));
+ return c;
+}
+
+PODEF int
+p_to_upper(int c)
+{
+ if (p_is_lower(c)) return (c - ('a' - 'A'));
+ return c;
+}
+/* --- End of p_string.c --- */
+#endif
+
+#ifdef P_MODULE_MATH
+/* --- Start of p_math.c --- */
+PODEF
+int p_ceil(float x)
+{
+ int base = (int) x;
+ return (x > base) ? base + 1 : base;
+}
+
+PODEF float
+p_cosf(float x)
+{
+ x += 1.57079632679f;
+
+ while (x > P_PI) x -= P_PI2;
+ while (x < -P_PI) x += P_PI2;
+
+ const float B = 4.0f / P_PI;
+ const float C = -4.0f / P_PI_POW2;
+
+ float y = B * x + C * x * (x < 0 ? -x : x);
+
+ const float P = 0.225f;
+ y = P * (y * (y < 0 ? -y : y) - y) + y;
+
+ return y;
+}
+
+PODEF float
+p_sinf(float x)
+{
+ while (x > P_PI) x -= P_PI2;
+ while (x < -P_PI) x += P_PI2;
+
+ const float B = 4.0f / P_PI;
+ const float C = -4.0f / (P_PI_POW2);
+
+ float y = B * x + C * x * (x < 0 ? -x : x);
+
+ const float P = 0.225f;
+ y = P * (y * (y < 0 ? -y : y) - y) + y;
+
+ return y;
+}
+
+PODEF Vec2f
+p_vec2f(float x, float y)
+{
+ return (Vec2f) { .x = x, .y = y };
+}
+
+PODEF Vec2f
+p_vec2f_add(Vec2f a, Vec2f b)
+{
+ return (Vec2f) {
+ .x = a.x + b.x,
+ .y = a.y + b.y,
+ };
+}
+
+PODEF float
+p_vec2f_cross(Vec2f a, Vec2f b)
+{
+ // axby − aybx
+ return a.x * b.y - a.y * b.x;
+}
+
+PODEF float
+p_vec2f_dot(Vec2f a, Vec2f b)
+{
+ // a · b = ax × bx + ay × by
+ return a.x * b.x + a.y * b.y;
+}
+
+PODEF Vec2f
+p_vec2f_mult(Vec2f a, float b)
+{
+ return (Vec2f) {
+ .x = a.x * b,
+ .y = a.y * b,
+ };
+}
+
+PODEF Vec2f
+p_vec2f_sub(Vec2f a, Vec2f b)
+{
+ return (Vec2f) {
+ .x = a.x - b.x,
+ .y = a.y - b.y,
+ };
+}
+
+PODEF Vec2i
+p_vec2i(float x, float y)
+{
+ return (Vec2i) { .x = x, .y = y };
+}
+
+PODEF Vec2i
+p_vec2i_add(Vec2i a, Vec2i b)
+{
+ return (Vec2i) {
+ .x = a.x + b.x,
+ .y = a.y + b.y,
+ };
+}
+
+PODEF float
+p_vec2i_cross(Vec2i a, Vec2i b)
+{
+ // axby − aybx
+ return a.x * b.y - a.y * b.x;
+}
+
+PODEF float
+p_vec2i_dot(Vec2i a, Vec2i b)
+{
+ // a · b = ax × bx + ay × by
+ return a.x * b.x + a.y * b.y;
+}
+
+PODEF Vec2i
+p_vec2i_mult(Vec2i a, float b)
+{
+ return (Vec2i) {
+ .x = a.x * b,
+ .y = a.y * b,
+ };
+}
+
+PODEF Vec2i
+p_vec2i_sub(Vec2i a, Vec2i b)
+{
+ return (Vec2i) {
+ .x = a.x - b.x,
+ .y = a.y - b.y,
+ };
+}
+
+PODEF Vec3f
+p_vec3f(float x, float y, float z)
+{
+ return (Vec3f) { .x = x, .y = y, .z = z };
+}
+
+PODEF P_Mat4
+p_mat4_identity(void)
+{
+ P_Mat4 res = {0};
+ res.m[0] = 1.0f;
+ res.m[5] = 1.0f;
+ res.m[10] = 1.0f;
+ res.m[15] = 1.0f;
+ return res;
+}
+
+PODEF P_Mat4
+p_mat4_mul(P_Mat4 a, P_Mat4 b)
+{
+ P_Mat4 res = {0};
+ for (int col = 0; col < 4; ++col) {
+ for (int row = 0; row < 4; ++row) {
+ float sum = 0.0f;
+ for (int k = 0; k < 4; ++k) {
+ sum += a.m[k * 4 + row] * b.m[col * 4 + k];
+ }
+ res.m[col * 4 + row] = sum;
+ }
+ }
+ return res;
+}
+
+PODEF P_Mat4
+p_mat4_translate(Vec3f v)
+{
+ P_Mat4 res = p_mat4_identity();
+ res.m[12] = v.x;
+ res.m[13] = v.y;
+ res.m[14] = v.z;
+ return res;
+}
+
+PODEF P_Mat4
+p_mat4_translate_by(P_Mat4 m, Vec3f v)
+{
+ P_Mat4 res = m;
+ res.m[12] = m.m[0] * v.x + m.m[4] * v.y + m.m[8] * v.z + m.m[12];
+ res.m[13] = m.m[1] * v.x + m.m[5] * v.y + m.m[9] * v.z + m.m[13];
+ res.m[14] = m.m[2] * v.x + m.m[6] * v.y + m.m[10] * v.z + m.m[14];
+ res.m[15] = m.m[3] * v.x + m.m[7] * v.y + m.m[11] * v.z + m.m[15];
+ return res;
+}
+
+PODEF P_Mat4
+p_mat4_rotate_x(float rad)
+{
+ P_Mat4 res = p_mat4_identity();
+ float c = p_cosf(rad);
+ float s = p_sinf(rad);
+ res.m[5] = c;
+ res.m[6] = s;
+ res.m[9] = -s;
+ res.m[10] = c;
+ return res;
+}
+
+PODEF P_Mat4
+p_mat4_rotate_x_by(P_Mat4 m, float rad)
+{
+ return p_mat4_mul(m, p_mat4_rotate_x(rad));
+}
+
+PODEF P_Mat4
+p_mat4_rotate_y(float rad)
+{
+ P_Mat4 res = p_mat4_identity();
+ float c = p_cosf(rad);
+ float s = p_sinf(rad);
+ res.m[0] = c;
+ res.m[2] = -s;
+ res.m[8] = s;
+ res.m[10] = c;
+ return res;
+}
+
+PODEF P_Mat4
+p_mat4_rotate_y_by(P_Mat4 m, float rad)
+{
+ return p_mat4_mul(m, p_mat4_rotate_y(rad));
+}
+
+PODEF P_Mat4
+p_mat4_rotate_z(float rad)
+{
+ P_Mat4 res = p_mat4_identity();
+ float c = p_cosf(rad);
+ float s = p_sinf(rad);
+ res.m[0] = c;
+ res.m[1] = s;
+ res.m[4] = -s;
+ res.m[5] = c;
+ return res;
+}
+
+PODEF P_Mat4
+p_mat4_perspective(float fov_rad, float aspect, float near_z, float far_z)
+{
+ P_Mat4 res = {0};
+ float tan_half_fov = p_sinf(fov_rad * 0.5f) / p_cosf(fov_rad * 0.5f);
+
+ res.m[0] = 1.0f / (aspect * tan_half_fov);
+ res.m[5] = 1.0f / tan_half_fov;
+ res.m[10] = far_z / (near_z - far_z);
+ res.m[11] = -1.0f;
+ res.m[14] = (near_z * far_z) / (near_z - far_z);
+ return res;
+}
+/* --- End of p_math.c --- */
+#endif
+
+#ifdef P_MODULE_ALLOC
+/* --- Start of p_allocators.c --- */
+PODEF bool
+is_power_of_two(uintptr x) {
+ return (x & (x-1)) == 0;
+}
+
+PODEF uintptr
+align_forward(uintptr ptr, usize align)
+{
+ uintptr p, a, remainder;
+ assert(is_power_of_two(align));
+
+ p = ptr;
+ a = (uintptr)align;
+ remainder = p & (a-1);
+
+ return (remainder != 0) ? p + a - remainder : p;
+}
+
+PODEF void
+p_arena_create(Arena *a, void *backing_buffer, usize backing_buffer_length)
+{
+ a->buf = (unsigned char *)backing_buffer;
+ a->buf_len = backing_buffer_length;
+ a->curr_offset = 0;
+ a->prev_offset = 0;
+}
+
+PODEF void*
+p_arena_alloc_align(Arena *a, usize s, usize align)
+{
+
+ // Align 'curr_offset' forward to the specified alignment
+ uintptr curr_ptr = (uintptr)a->buf + (uintptr)a->curr_offset;
+ uintptr offset = align_forward(curr_ptr, align);
+ offset -= (uintptr)a->buf; // Change to relative offset
+
+ // Check to see if the backing memory has space left
+ if (offset+s <= a->buf_len) {
+ void *ptr = &a->buf[offset];
+ a->prev_offset = offset;
+ a->curr_offset = offset+s;
+
+ memset(ptr, 0, s);
+ return ptr;
+ }
+
+ return NULL;
+}
+
+PODEF void*
+p_arena_alloc(Arena *a, usize s) {
+ return p_arena_alloc_align(a, s, DEFAULT_ALIGNMENT);
+}
+
+PODEF void*
+p_arena_resize_align(Arena *a, void *old_memory, usize old_size, usize new_size, usize align)
+{
+ assert(is_power_of_two(align));
+ unsigned char *old_mem = (unsigned char *)old_memory;
+
+ if (old_mem == NULL || old_size == 0) {
+ return p_arena_alloc_align(a, new_size, align);
+ } else if (a->buf <= old_mem && old_mem < a->buf+a->buf_len) {
+ if (a->buf+a->prev_offset == old_mem) {
+ a->curr_offset = a->prev_offset + new_size;
+ if (new_size > old_size) {
+ // Zero the new memory by default
+ memset(&a->buf[a->curr_offset], 0, new_size-old_size);
+ }
+ return old_memory;
+ } else {
+ void *new_memory = p_arena_alloc_align(a, new_size, align);
+ size_t copy_size = old_size < new_size ? old_size : new_size;
+ memmove(new_memory, old_memory, copy_size);
+ return new_memory;
+ }
+
+ } else {
+ assert(0 && "Memory is out of bounds of the buffer in this arena");
+ return NULL;
+ }
+}
+
+PODEF void*
+p_arena_resize(Arena *a, void *old_memory, usize old_size, usize new_size)
+{
+ return p_arena_resize_align(a, old_memory, old_size, new_size, DEFAULT_ALIGNMENT);
+}
+
+PODEF void
+p_arena_free_all(Arena *a)
+{
+ a->curr_offset = 0;
+ a->prev_offset = 0;
+}
+
+PODEF void
+p_arena_destroy(Arena* a)
+{
+ a->buf_len = 0;
+ a->curr_offset = 0;
+ a->prev_offset = 0;
+}
+
+PODEF void
+p_stack_create(Stack *s, void *backing_buffer, usize backing_buffer_length)
+{
+ s->buf = (unsigned char*) backing_buffer;
+ s->buf_len = backing_buffer_length;
+ s->offset = 0;
+}
+
+PODEF usize
+calc_padding_with_header(uintptr ptr, uintptr alignment, usize header_size)
+{
+ uintptr p, a, modulo, padding, needed_space;
+
+ assert(is_power_of_two(alignment));
+
+ p = ptr;
+ a = alignment;
+ modulo = p & (a-1); // (p % a) as it assumes alignment is a power of two
+
+ padding = 0;
+ needed_space = 0;
+
+ if (modulo != 0) { // Same logic as 'align_forward'
+ padding = a - modulo;
+ }
+
+ needed_space = (uintptr)header_size;
+
+ if (padding < needed_space) {
+ needed_space -= padding;
+
+ if ((needed_space & (a-1)) != 0) {
+ padding += a * (1+(needed_space/a));
+ } else {
+ padding += a * (needed_space/a);
+ }
+ }
+
+ return (usize)padding;
+}
+
+PODEF void*
+p_stack_alloc(Stack *s, usize len, usize alignment)
+{
+ uintptr curr_addr, next_addr;
+ usize padding;
+ Stack_Allocation_Header *header;
+
+ assert(is_power_of_two(alignment));
+
+ if (alignment > 128) {
+ // As the padding is 8 bits (1 byte), the largest alignment that can
+ // be used is 128 bytes
+ alignment = 128;
+ }
+
+ curr_addr = (uintptr)s->buf + (uintptr)s->offset;
+ padding = calc_padding_with_header(curr_addr, (uintptr)alignment, sizeof(Stack_Allocation_Header));
+ if (s->offset + padding + len > s->buf_len) {
+ // Stack allocator is out of memory
+ return NULL;
+ }
+ s->offset += padding;
+
+ next_addr = curr_addr + (uintptr)padding;
+ header = (Stack_Allocation_Header *)(next_addr - sizeof(Stack_Allocation_Header));
+ header->padding = (u8)padding;
+
+ s->offset += len;
+
+ return memset((void *)next_addr, 0, len);
+}
+
+PODEF void
+p_stack_free(Stack *s, void *ptr)
+{
+ if (ptr != NULL) {
+ uintptr start, end, curr_addr;
+ Stack_Allocation_Header *header;
+ usize prev_offset;
+
+ start = (uintptr)s->buf;
+ end = start + (uintptr)s->buf_len;
+ curr_addr = (uintptr)ptr;
+
+ if (!(start <= curr_addr && curr_addr < end)) {
+ assert(0 && "Out of bounds memory address passed to stack allocator (free)");
+ return;
+ }
+
+ if (curr_addr >= start+(uintptr)s->offset) {
+ // Allow double frees
+ return;
+ }
+
+ header = (Stack_Allocation_Header *)(curr_addr - sizeof(Stack_Allocation_Header));
+ prev_offset = (usize)(curr_addr - (uintptr)header->padding - start);
+
+ s->offset = prev_offset;
+ }
+}
+
+PODEF void
+p_stack_free_all(Stack* s)
+{
+ s->offset = 0;
+}
+
+PODEF void
+p_stack_destroy(Stack* s)
+{
+ s->buf = 0;
+ s->buf_len = 0;
+ s->offset = 0;
+}
+
+PODEF void
+p_pool_create(Pool *p, void *buf, usize buf_len, usize chunk_size, usize chunk_align)
+{
+ /* align start */
+ uintptr start = (uintptr) buf;
+ uintptr aligned = align_forward(start, chunk_align);
+ buf_len -= (aligned - start);
+
+ /* align chunk usize */
+ chunk_size = (usize) align_forward(chunk_size, chunk_align);
+
+ assert(chunk_size >= sizeof(Pool_Free_Node) && "Chunk usize is too small");
+ assert(buf_len >= chunk_size && "Backing buffer length is smaller than the chunk size");
+
+ p->buf = (unsigned char *) buf;
+ p->pool_size = buf_len;
+ p->chunk_size = chunk_size;
+ p->head = NULL;
+
+ p_pool_free_all(p);
+}
+
+PODEF void*
+p_pool_alloc(Pool *p)
+{
+ Pool_Free_Node *node = p->head;
+
+ assert(node != NULL && "Pool allocator has no free memory");
+
+ p->head = p->head->next;
+
+ return memset(node, 0 , p->chunk_size);
+}
+
+PODEF void
+p_pool_free(Pool *p, void *ptr)
+{
+ Pool_Free_Node *node;
+
+ void *start = p->buf;
+ void *end = &p->buf[p->pool_size];
+
+ if (ptr == NULL) {
+ return;
+ }
+
+ if (!(start <= ptr && ptr < end)) {
+ assert(0 && "Memory is out of bounds of the buffer in this pool");
+ return;
+ }
+
+ node = (Pool_Free_Node *)ptr;
+ node->next = p->head;
+ p->head = node;
+}
+
+PODEF void
+p_pool_free_all(Pool *p)
+{
+ usize chunk_count = p->pool_size / p->chunk_size;
+ usize i;
+
+ for (i = 0; i < chunk_count; i++) {
+ void *ptr = &p->buf[i * p->chunk_size];
+ Pool_Free_Node *node = (Pool_Free_Node *)ptr;
+
+ // Push free node onto thte free list
+ node->next = p->head;
+ p->head = node;
+ }
+}
+
+PODEF void
+p_pool_destroy(Pool *p)
+{
+ p->buf = NULL;
+ p->pool_size = 0;
+ p->chunk_size = 0;
+ p->head = NULL;
+}
+
+/* --- End of p_allocators.c --- */
+#endif
+
+#define P_MAX_PRINTF_SIZE 1024
+PODEF void
+p_log_printf(P_Log_Level level, const char* src, ...)
+{
+ static char out_message[P_MAX_PRINTF_SIZE];
+ static u32 offset = P_PREFIX_LEN + 1;
+
+ memcpy(out_message, p_prefix[level], P_PREFIX_LEN); /* prefixes have a fixed len */
+ out_message[P_PREFIX_LEN] = ' '; /* write space */
+
+ __builtin_va_list arg_ptr;
+ va_start(arg_ptr, src);
+ int len = vsnprintf(out_message+offset, P_MAX_PRINTF_SIZE-offset, src, arg_ptr); // append message
+ va_end(arg_ptr);
+
+ if (len < 0) len = 0;
+ usize total_len = offset + len;
+ if (total_len > P_MAX_PRINTF_SIZE) {
+ total_len = P_MAX_PRINTF_SIZE;
+ }
+
+ p_stdout(out_message, total_len);
+ p_stdout("\n", 1);
+}
+
+#endif // PODIUM_IMPLEMENTATION
diff --git a/Podium/podium_header.h b/Podium/podium_header.h
new file mode 100644
index 0000000..6407f62
--- /dev/null
+++ b/Podium/podium_header.h
@@ -0,0 +1,258 @@
+/* ===========================================================================
+ * PODIUM - Kitchen Sink - Copyright (c) 2026 Vasco Alves
+ * ---------------------------------------------------------------------------
+ * To stand on the shoulders of giants... Giants must stand still!"
+ * ---------------------------------------------------------------------------
+ * PREFIX: P_ (types) or p_ (functions & variables)
+ * ---------------------------------------------------------------------------
+ * COMPILE TIME FLAGS
+ * ._________________________________________________________________________,
+ * | Name | Description |
+ * |-----------------|-------------------------------------------------------|
+ * | PODIUM_WIN32 | Used to explicitly compile for Windows |
+ * | PODIUM_LINUX | Used to explicitly compile for Linux and FreeBSD. |
+ * '-------------------------------------------------------------------------'
+ * MODULES
+ * ._________________________________________________________________________,
+ * | Name | Description |
+ * |-----------------|-------------------------------------------------------|
+ * | P_MODULE_VULKAN | Gives access to vulkan related utilities. |
+ * | P_MODULE_STRING | Include string manipulation utilities. |
+ * | P_MODULE_MATH | Trigonometry and linear algebra functions. |
+ * | P_MODULE_ALLOC | Memory allocators: Arena, Stack & Pool. |
+ * '-------------------------------------------------------------------------'
+ * =========================================================================== */
+
+#ifndef _PODIUM_H_
+#define _PODIUM_H_
+
+#define PODIUM_MAJOR "0" // needs more revisions and use to reach 1.0 status
+#define PODIUM_MINOR "2" // vulkan module
+#define PODIUM_PATCH "2" // gamepad
+
+#define POAPI static inline
+#define PODEF static inline
+
+/*
+ * Auto-detect platforms.
+ */
+
+/* Windows */
+#if defined(_WIN32) || defined(_WIN64) || defined(__WIN32__) || defined(__TOS_WIN__)
+ #ifndef PODIUM_WIN32
+ #define PODIUM_WIN32
+ #endif
+ #ifndef WIN32_LEAN_AND_MEAN
+ #define WIN32_LEAN_AND_MEAN
+ #endif
+/* Apple */
+#elif defined(__APPLE__) || defined(__MACH__)
+ #include <TargetConditionals.h>
+ #ifndef PODIUM_APPLE
+ #define PODIUM_APPLE
+ #endif
+ #if TARGET_OS_IPHONE
+ #define PODIUM_IOS
+ #else
+ #define PODIUM_MACOS
+ #endif
+/* Linux / BSD */
+#elif defined(__linux__) || defined(__FreeBSD__)
+ #ifndef PODIUM_LINUX
+ #define PODIUM_LINUX
+ #endif
+ #ifndef _POSIX_C_SOURCE
+ #define _POSIX_C_SOURCE 200112L
+ #endif
+#endif
+
+#include <stdarg.h>
+#include <stdint.h>
+#include <stddef.h>
+#include <string.h> /* memcpy */
+#include <stdio.h> /* vsnprintf */
+
+/*
+ * NOTE: The <REPLACE> comments are used by the build
+ * script to know what includes to inline into the
+ * final single header file!
+ */
+
+#include "p_types.h" // <REPLACE>
+#include "p_log.h" // <REPLACE>
+#include "p_ds.h" // <REPLACE>
+
+/*
+ * Main Platform Types (Keyboard, Events, Context, etc.)
+ */
+
+typedef enum {
+ P_KEYMOD_ALT = 0,
+ P_KEYMOD_SHIFT,
+ P_KEYMOD_CTRL,
+ P_KEYMOD_CAPS,
+} P_KeyMod;
+
+typedef enum {
+ P_KEY_UNKNOWN = 0,
+ P_KEY_UP, P_KEY_DOWN, P_KEY_LEFT, P_KEY_RIGHT,
+ P_KEY_SPACE, P_KEY_ESCAPE, P_KEY_ENTER,
+ P_KEY_A, P_KEY_B, P_KEY_C, P_KEY_D, P_KEY_E, P_KEY_F, P_KEY_G, P_KEY_H, P_KEY_I,
+ P_KEY_J, P_KEY_K, P_KEY_L, P_KEY_M, P_KEY_N, P_KEY_O, P_KEY_P, P_KEY_Q, P_KEY_R,
+ P_KEY_S, P_KEY_T, P_KEY_U, P_KEY_V, P_KEY_W, P_KEY_X, P_KEY_Y, P_KEY_Z,
+} P_KeyCode;
+
+/* Platform event type */
+typedef enum {
+ P_EVENT_NONE = 0,
+ P_EVENT_KEY_DOWN,
+ P_EVENT_KEY_UP,
+ P_EVENT_WINDOW_CLOSE,
+ P_EVENT_WINDOW_RESIZE,
+ P_EVENT_POINTER,
+ P_EVENT_CONTROLLER_CONNECTED,
+ P_EVENT_CONTROLLER_DISCONNECTED,
+} P_EvenType;
+
+typedef enum {
+ P_POINTER_MOVED = 0,
+ P_POINTER_PRESSED,
+ P_POINTER_RELEASED
+} P_PointerState;
+
+typedef struct {
+ P_EvenType type;
+ union {
+ struct {P_KeyCode key; P_KeyMod mod; } key;
+ struct { u32 width, height; } resize;
+ struct { P_PointerState state; u32 button; u32 x, y; } pointer;
+ };
+} P_Event;
+
+/*
+ * Platform dependent functions to be implemented by each layer.
+ */
+
+POAPI u64 p_get_time(void); // Get time in nanoseconds.
+POAPI void p_sleep_ns(i64 ns); // Sleep for nanoseconds.
+
+POAPI void p_stdout(void *msg, usize bytes); // Print buffer to stdout.
+PODEF void p_log_printf(P_Log_Level level, const char* src, ...); // Print buffer to stdout.
+
+
+POAPI void* p_file_alloc(const char *path, unsigned long *buf_size);
+POAPI bool p_file_exists(const char *path); // Check if file exists.
+POAPI usize p_file_size(const char *path); // Check file size.
+POAPI void p_file_load(const char *path, void *buf_ptr, unsigned long buf_size); // Load file to buffer.
+PODEF void p_file_write(const char *path, void *buf_ptr, unsigned long buf_size); // Write buffer to file.
+
+typedef struct P_Window_Impl P_Window;
+POAPI bool p_window_open(P_Window *win, int width, int height, const char *title); // Opens a window. Returns false on failure.
+POAPI void p_window_close(P_Window *win); // Close window.
+POAPI bool p_window_is_open(P_Window *win); // Check if window is open.
+POAPI void p_window_size(P_Window *win, int *window_width, int *window_height); // Get window size.
+POAPI void p_window_draw(P_Window *win, u32 *pixels, int width, int height); // Draw directly to the window's buffer. Normally much slower than using the GPU.
+POAPI bool p_window_poll_event(P_Window *win, P_Event *ev); // Returns true while there are events to poll. Write event data to a pointer.
+
+POAPI void p_audio_init(const int sample_rate, const int channels, const char *name, const char *desc);
+POAPI void p_audio_quit();
+POAPI void p_audio_write(const i16 *samples, usize count);
+
+/*
+ * The Vulkan Module is platform specific
+ */
+
+#ifdef P_MODULE_VULKAN
+#include <vulkan/vulkan.h>
+POAPI char** p_vulkan_get_extensions();
+POAPI bool p_vulkan_create_surface(P_Window *window, VkInstance instance, const VkAllocationCallbacks* allocator, VkSurfaceKHR* out_surface);
+#endif
+
+/*
+ * The Remaining Modules are PLATFORM INDEPENDENT!
+ */
+
+#ifdef P_MODULE_STRING
+#include <p_string.h> // <REPLACE>
+#endif
+
+#ifdef P_MODULE_MATH
+#include <p_math.h> // <REPLACE>
+#endif
+
+#ifdef P_MODULE_ALLOC
+#include <p_allocators.h> // <REPLACE>
+#endif
+
+#endif /* _PODIUM_H_ */
+
+#ifdef PODIUM_IMPLEMENTATION
+#undef PODIUM_IMPLEMENTATION
+
+#if defined(PODIUM_SDL)
+/* #include "p_platform_sdl.c" */
+#elif defined(PODIUM_WIN32)
+#include "p_platform_win32.c" // <REPLACE>
+#elif defined(PODIUM_LINUX)
+#include "p_platform_linux.c" // <REPLACE>
+#endif /* linux */
+
+
+POAPI void* p_file_alloc(const char *path, unsigned long *buf_size) {
+ if (p_file_exists(path) == false) {
+ return NULL;
+ }
+
+ usize file_size = p_file_size(path);
+ *buf_size = file_size;
+
+ void *ptr = malloc(file_size);
+ if (ptr) {
+ p_file_load(path, ptr, file_size); // Load file to buffer.
+ }
+ return ptr;
+}
+
+
+/*
+ * Import Module Code
+ */
+
+#ifdef P_MODULE_STRING
+#include <p_string.c> // <REPLACE>
+#endif
+
+#ifdef P_MODULE_MATH
+#include <p_math.c> // <REPLACE>
+#endif
+
+#ifdef P_MODULE_ALLOC
+#include <p_allocators.c> // <REPLACE>
+#endif
+
+#define P_MAX_PRINTF_SIZE 1024
+PODEF void
+p_log_printf(P_Log_Level level, const char* src, ...)
+{
+ static char out_message[P_MAX_PRINTF_SIZE];
+ static u32 offset = P_PREFIX_LEN + 1;
+
+ memcpy(out_message, p_prefix[level], P_PREFIX_LEN); /* prefixes have a fixed len */
+ out_message[P_PREFIX_LEN] = ' '; /* write space */
+
+ __builtin_va_list arg_ptr;
+ va_start(arg_ptr, src);
+ int len = vsnprintf(out_message+offset, P_MAX_PRINTF_SIZE-offset, src, arg_ptr); // append message
+ va_end(arg_ptr);
+
+ if (len < 0) len = 0;
+ usize total_len = offset + len;
+ if (total_len > P_MAX_PRINTF_SIZE) {
+ total_len = P_MAX_PRINTF_SIZE;
+ }
+
+ p_stdout(out_message, total_len);
+ p_stdout("\n", 1);
+}
+
+#endif // PODIUM_IMPLEMENTATION
diff --git a/Poof/poof.h b/Poof/poof.h
new file mode 100644
index 0000000..55e18ef
--- /dev/null
+++ b/Poof/poof.h
@@ -0,0 +1,875 @@
+/* ===========================================================================
+ * POOF - The Universal Build System - Copyright (c) 2026 Vasco Alves
+ *
+ * PREFIX: Poof_ (types) or poof_ (functions & variables)
+ *
+ * DESCRIPTION:
+ * Platform independent-ish build system!
+ * Performant, multi-threaded and mesmerizing.
+ *
+ * See LICENSE at the end of the file.
+ * =========================================================================== */
+
+#ifndef _POOF_H_
+#define _POOF_H_
+
+#define POOF_MAJOR 0
+#define POOF_MINOR 1
+#define POOF_PATCH 0
+
+#include <stdint.h>
+#include <stdbool.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <sys/stat.h>
+
+#if defined(_WIN32)
+ #include <windows.h>
+ #include <direct.h>
+ #include <io.h>
+#else
+ #include <unistd.h>
+ #include <sys/wait.h>
+ #include <sys/types.h>
+ #include <dirent.h>
+ #include <errno.h>
+#endif
+
+enum PoofTargetPlatform {
+ POOF_TARGET_HOST = 0,
+ POOF_TARGET_WIN32 = 1,
+ POOF_TARGET_LINUX = 1 << 1,
+ POOF_TARGET_MACOS = 1 << 2,
+};
+
+enum PoofCCFlags {
+ POOF_CC_GCC = 1,
+ POOF_CC_CLANG = 1 << 1,
+ POOF_CC_MSVC = 1 << 2,
+ POOF_CC_MINGW = 1 << 3,
+};
+
+enum PoofOptimizationFlags {
+ POOF_O0 = 0,
+ POOF_O1 = 1,
+ POOF_O2 = 2,
+ POOF_O3 = 3,
+ POOF_MSSE = 1 << 3,
+ POOF_MSSE2 = 1 << 4,
+ POOF_AVX = 1 << 5,
+ POOF_AVX2 = 1 << 6,
+ POOF_AVX512F = 1 << 7,
+};
+
+#define POOF_IS_SET(var, flag) (((var) & (flag)) != 0)
+
+typedef struct Poof_Cmd {
+ const char **items;
+ size_t capacity;
+ size_t count;
+} Poof_Cmd;
+
+typedef struct Poof_CC {
+ uint8_t compiler; // enum PoofCCFlags
+ uint8_t target_platform; // enum PoofTargetPlatform
+ uint32_t optimization; // bitwise PoofOptimizationFlags
+ bool debug_mode;
+ Poof_Cmd inputs;
+ const char *output;
+ Poof_Cmd includes;
+ Poof_Cmd lib_paths;
+ Poof_Cmd libs;
+ Poof_Cmd defines;
+ Poof_Cmd extra_flags;
+
+ /* Platform specific flags */
+ Poof_Cmd win32_flags;
+ Poof_Cmd linux_flags;
+ Poof_Cmd macos_flags;
+} Poof_CC;
+
+typedef struct Poof_Batch {
+ Poof_Cmd *cmds;
+ size_t capacity;
+ size_t count;
+} Poof_Batch;
+
+/* Command operations */
+extern void poof_cmd_append_internal(Poof_Cmd *cmd, ...);
+#define poof_cmd_append(cmd, ...) poof_cmd_append_internal((cmd), __VA_ARGS__, NULL)
+ #define poof_cc_append(cc, ...) poof_cmd_append_internal((cc), __VA_ARGS__, NULL)
+
+#define poof_cc_append_win32(cc, ...) poof_cmd_append_internal(&((cc)->win32_flags), __VA_ARGS__, NULL)
+#define poof_cc_append_linux(cc, ...) poof_cmd_append_internal(&((cc)->linux_flags), __VA_ARGS__, NULL)
+#define poof_cc_append_macos(cc, ...) poof_cmd_append_internal(&((cc)->macos_flags), __VA_ARGS__, NULL)
+
+extern void poof_cmd_free(Poof_Cmd *cmd);
+extern void poof_cmd_clear(Poof_Cmd *cmd);
+extern bool poof_cmd_run(Poof_Cmd *cmd);
+
+/* Batch operations */
+extern void poof_batch_append_cmd(Poof_Batch *batch, Poof_Cmd cmd);
+extern void poof_batch_append_cc(Poof_Batch *batch, Poof_CC *cc);
+#define poof_batch_append(batch, cmd) poof_batch_append_cmd((batch), (cmd))
+extern void poof_batch_free(Poof_Batch *batch);
+extern bool poof_batch_run(Poof_Batch *batch, const char *label);
+extern bool poof_batch_run_parallel(Poof_Batch *batch, const char *label, size_t max_jobs);
+
+/* Compiler abstraction */
+extern uint8_t poof_cc_available(void);
+extern void poof_cc_init(Poof_CC *cc, uint8_t compiler, uint8_t target_platform);
+extern void poof_cc_free(Poof_CC *cc);
+extern bool poof_cc_run(Poof_CC *cc);
+
+/* File and directory utilities */
+extern bool poof_mkdir(const char *path);
+extern bool poof_touch(const char *path);
+extern bool poof_rm(const char *path);
+extern bool poof_rm_recursive(const char *path);
+extern bool poof_copy_file(const char *src, const char *dst);
+extern bool poof_needs_rebuild(const char *target, const char **sources, size_t source_count);
+
+/* Output and pretty printing */
+extern int poof_print(uint32_t col, const char *text, ...);
+extern int poof_progress_bar(const char *label, float value, float min, float max, float width);
+
+/* Rebuild self macro */
+extern void poof_go_rebuild_urself_impl(int argc, char **argv, const char *source_file);
+
+#define POOF_GO_REBUILD_URSELF(argc, argv) poof_go_rebuild_urself_impl(argc, argv, __FILE__)
+
+#endif // _POOF_H_
+
+#ifdef POOF_IMPLEMENTATION
+#undef POOF_IMPLEMENTATION
+
+#if defined(_WIN32)
+#define POOF_DEV_NULL "nul 2>&1"
+#else
+#define POOF_DEV_NULL "/dev/null 2>&1"
+#endif
+
+static bool
+poof__probe_cmd(const char *cmd)
+{
+ char buffer[256];
+ snprintf(buffer, sizeof(buffer), "%s > " POOF_DEV_NULL, cmd);
+ return (system(buffer) == 0);
+}
+
+extern uint8_t
+poof_cc_available(void)
+{
+ uint8_t available = 0;
+
+ poof_print(0x00FF88, "[POOF] Probing available compilers:\n");
+ if (poof__probe_cmd("gcc --version")) {
+ available |= POOF_CC_GCC;
+ poof_print(0x00FF88, " - GCC: available\n");
+ }
+
+ if (poof__probe_cmd("clang --version")) {
+ available |= POOF_CC_CLANG;
+ poof_print(0x00FF88, " - CLANG: available\n");
+ }
+
+ if (poof__probe_cmd("x86_64-w64-mingw32-gcc --version") || poof__probe_cmd("mingw32-gcc --version")) {
+ available |= POOF_CC_MINGW;
+ poof_print(0x00FF88, " - MinGW: available\n");
+ }
+
+ if (poof__probe_cmd("cl")) {
+ available |= POOF_CC_MSVC;
+ poof_print(0x00FF88, " - MSVC: available\n");
+ }
+
+ return available;
+}
+
+extern void
+poof_cmd_append_internal(Poof_Cmd *cmd, ...)
+{
+ va_list args;
+ va_start(args, cmd);
+ const char *arg = NULL;
+ while ((arg = va_arg(args, const char *)) != NULL) {
+
+ if (cmd->count >= cmd->capacity) {
+ size_t new_cap = cmd->capacity == 0 ? 16 : cmd->capacity * 2;
+ const char **new_items = (const char **)realloc(cmd->items, new_cap * sizeof(const char *));
+ if (!new_items) return;
+ cmd->items = new_items;
+ cmd->capacity = new_cap;
+ }
+ cmd->items[cmd->count++] = arg;
+ }
+ va_end(args);
+}
+
+
+extern void
+poof_cmd_clear(Poof_Cmd *cmd)
+{
+ /* clear count while keeping capacity */
+ cmd->count = 0;
+}
+
+extern void
+poof_cmd_free(Poof_Cmd *cmd)
+{
+ if (cmd->items) {
+ free(cmd->items);
+ cmd->items = NULL;
+ }
+ cmd->capacity = 0;
+ cmd->count = 0;
+}
+
+static char *
+poof__cmd_to_string(const Poof_Cmd *cmd)
+{
+ if (!cmd || cmd->count == 0) return NULL;
+
+ size_t total_len = 0;
+ for (size_t i = 0; i < cmd->count; ++i) {
+ total_len += strlen(cmd->items[i]) + 3; // quotes and space
+ }
+
+ char *cmdline = (char *)malloc(total_len + 1);
+ if (!cmdline) return NULL;
+ cmdline[0] = '\0';
+
+ for (size_t i = 0; i < cmd->count; ++i) {
+ if (i > 0) strcat(cmdline, " ");
+ bool need_quote = (strchr(cmd->items[i], ' ') != NULL);
+ if (need_quote) strcat(cmdline, "\"");
+ strcat(cmdline, cmd->items[i]);
+ if (need_quote) strcat(cmdline, "\"");
+ }
+
+ return cmdline;
+}
+
+extern bool
+poof_cmd_run(Poof_Cmd *cmd)
+{
+ char *cmdline = poof__cmd_to_string(cmd);
+ if (!cmdline) return false;
+
+ printf("[POOF] Executing: ");
+ poof_print(0xA9B665, "%s\n", cmdline);
+
+ int status = system(cmdline);
+ free(cmdline);
+ poof_cmd_clear(cmd);
+ return (status == 0);
+}
+
+extern void
+poof_cc_init(Poof_CC *cc, uint8_t compiler, uint8_t target_platform)
+{
+ memset(cc, 0, sizeof(Poof_CC));
+ cc->compiler = compiler;
+ cc->target_platform = target_platform;
+ cc->optimization = POOF_O0;
+ cc->debug_mode = true;
+}
+
+extern void
+poof_cc_free(Poof_CC *cc)
+{
+ poof_cmd_free(&cc->inputs);
+ poof_cmd_free(&cc->includes);
+ poof_cmd_free(&cc->lib_paths);
+ poof_cmd_free(&cc->libs);
+ poof_cmd_free(&cc->defines);
+ poof_cmd_free(&cc->extra_flags);
+ poof_cmd_free(&cc->win32_flags);
+ poof_cmd_free(&cc->linux_flags);
+ poof_cmd_free(&cc->macos_flags);
+}
+
+extern void
+poof_batch_append_cmd(Poof_Batch *batch, Poof_Cmd cmd)
+{
+ if (batch->count >= batch->capacity) {
+ size_t new_cap = batch->capacity == 0 ? 16 : batch->capacity * 2;
+ Poof_Cmd *new_cmds = (Poof_Cmd *)realloc(batch->cmds, new_cap * sizeof(Poof_Cmd));
+ if (!new_cmds) return;
+ batch->cmds = new_cmds;
+ batch->capacity = new_cap;
+ }
+ batch->cmds[batch->count++] = cmd;
+}
+
+static Poof_Cmd
+poof__cc_build_cmd(const Poof_CC *cc, uint8_t target_platform, bool multi_target)
+{
+ Poof_Cmd cmd = {0};
+
+ // Pick compiler binary
+ if (cc->compiler & POOF_CC_GCC) {
+ if (target_platform == POOF_TARGET_WIN32) {
+ poof_cmd_append(&cmd, "x86_64-w64-mingw32-gcc");
+ } else {
+ poof_cmd_append(&cmd, "gcc");
+ }
+ } else if (cc->compiler & POOF_CC_CLANG) {
+ poof_cmd_append(&cmd, "clang");
+ if (target_platform == POOF_TARGET_WIN32) {
+ poof_cmd_append(&cmd, "-target");
+ poof_cmd_append(&cmd, "x86_64-pc-windows-gnu");
+ } else if (target_platform == POOF_TARGET_LINUX) {
+ poof_cmd_append(&cmd, "-target");
+ poof_cmd_append(&cmd, "x86_64-unknown-linux-gnu");
+ } else if (target_platform == POOF_TARGET_MACOS) {
+ poof_cmd_append(&cmd, "-target");
+ poof_cmd_append(&cmd, "x86_64-apple-darwin");
+ }
+ } else if (cc->compiler & POOF_CC_MINGW) {
+ poof_cmd_append(&cmd, "x86_64-w64-mingw32-gcc");
+ } else if (cc->compiler & POOF_CC_MSVC) {
+ poof_cmd_append(&cmd, "cl");
+ } else {
+ poof_cmd_append(&cmd, "gcc");
+ }
+
+ bool is_msvc = (cc->compiler & POOF_CC_MSVC) != 0;
+
+ // Debug flags
+ if (cc->debug_mode) {
+ poof_cmd_append(&cmd, is_msvc ? "/Zi" : "-g");
+ }
+
+ // Optimization flags
+ uint32_t opt_level = cc->optimization & 3;
+ if (opt_level == POOF_O1) poof_cmd_append(&cmd, is_msvc ? "/O1" : "-O1");
+ else if (opt_level == POOF_O2) poof_cmd_append(&cmd, is_msvc ? "/O2" : "-O2");
+ else if (opt_level == POOF_O3) poof_cmd_append(&cmd, is_msvc ? "/O2" : "-O3");
+ else poof_cmd_append(&cmd, is_msvc ? "/Od" : "-O0");
+
+ // SIMD / Arch extensions
+ if (POOF_IS_SET(cc->optimization, POOF_MSSE)) poof_cmd_append(&cmd, is_msvc ? "/arch:SSE" : "-msse");
+ if (POOF_IS_SET(cc->optimization, POOF_MSSE2)) poof_cmd_append(&cmd, is_msvc ? "/arch:SSE2" : "-msse2");
+ if (POOF_IS_SET(cc->optimization, POOF_AVX)) poof_cmd_append(&cmd, is_msvc ? "/arch:AVX" : "-mavx");
+ if (POOF_IS_SET(cc->optimization, POOF_AVX2)) poof_cmd_append(&cmd, is_msvc ? "/arch:AVX2" : "-mavx2");
+ if (POOF_IS_SET(cc->optimization, POOF_AVX512F)) poof_cmd_append(&cmd, is_msvc ? "/arch:AVX512" : "-mavx512f");
+
+ // Defines
+ for (size_t i = 0; i < cc->defines.count; ++i) {
+ char buf[256];
+ snprintf(buf, sizeof(buf), "%s%s", is_msvc ? "/D" : "-D", cc->defines.items[i]);
+ poof_cmd_append(&cmd, strdup(buf));
+ }
+
+ // Include dirs
+ for (size_t i = 0; i < cc->includes.count; ++i) {
+ char buf[512];
+ snprintf(buf, sizeof(buf), "%s%s", is_msvc ? "/I" : "-I", cc->includes.items[i]);
+ poof_cmd_append(&cmd, strdup(buf));
+ }
+
+ // Input files
+ for (size_t i = 0; i < cc->inputs.count; ++i) {
+ poof_cmd_append(&cmd, cc->inputs.items[i]);
+ }
+
+ // Output target
+ if (cc->output) {
+ char out_path[512];
+ if (target_platform == POOF_TARGET_WIN32) {
+ if (strstr(cc->output, ".exe")) {
+ snprintf(out_path, sizeof(out_path), "%s", cc->output);
+ } else {
+ snprintf(out_path, sizeof(out_path), multi_target ? "%s_win32.exe" : "%s.exe", cc->output);
+ }
+ } else if (target_platform == POOF_TARGET_MACOS) {
+ snprintf(out_path, sizeof(out_path), multi_target ? "%s_macos" : "%s", cc->output);
+ } else if (target_platform == POOF_TARGET_LINUX) {
+ snprintf(out_path, sizeof(out_path), multi_target ? "%s_linux" : "%s", cc->output);
+ } else {
+ snprintf(out_path, sizeof(out_path), "%s", cc->output);
+ }
+
+ if (is_msvc) {
+ char buf[512];
+ snprintf(buf, sizeof(buf), "/Fe:%s", out_path);
+ poof_cmd_append(&cmd, strdup(buf));
+ } else {
+ poof_cmd_append(&cmd, "-o");
+ poof_cmd_append(&cmd, strdup(out_path));
+ }
+ }
+
+ // Lib paths & libs
+ for (size_t i = 0; i < cc->lib_paths.count; ++i) {
+ char buf[512];
+ snprintf(buf, sizeof(buf), "%s%s", is_msvc ? "/LIBPATH:" : "-L", cc->lib_paths.items[i]);
+ poof_cmd_append(&cmd, strdup(buf));
+ }
+
+ for (size_t i = 0; i < cc->libs.count; ++i) {
+ if (is_msvc) {
+ char buf[256];
+ snprintf(buf, sizeof(buf), "%s.lib", cc->libs.items[i]);
+ poof_cmd_append(&cmd, strdup(buf));
+ } else {
+ char buf[256];
+ snprintf(buf, sizeof(buf), "-l%s", cc->libs.items[i]);
+ poof_cmd_append(&cmd, strdup(buf));
+ }
+ }
+
+ // Extra flags
+ for (size_t i = 0; i < cc->extra_flags.count; ++i) {
+ poof_cmd_append(&cmd, cc->extra_flags.items[i]);
+ }
+
+ // Platform specific flags
+ const Poof_Cmd *plat_cmd = NULL;
+ if (target_platform == POOF_TARGET_WIN32) plat_cmd = &cc->win32_flags;
+ else if (target_platform == POOF_TARGET_LINUX) plat_cmd = &cc->linux_flags;
+ else if (target_platform == POOF_TARGET_MACOS) plat_cmd = &cc->macos_flags;
+
+ if (plat_cmd) {
+ for (size_t i = 0; i < plat_cmd->count; ++i) {
+ poof_cmd_append(&cmd, plat_cmd->items[i]);
+ }
+ }
+
+ return cmd;
+}
+
+extern void
+poof_batch_append_cc(Poof_Batch *batch, Poof_CC *cc)
+{
+ uint8_t mask = cc->target_platform;
+ if (mask == 0) {
+#if defined(_WIN32)
+ mask = POOF_TARGET_WIN32;
+#elif defined(__APPLE__)
+ mask = POOF_TARGET_MACOS;
+#else
+ mask = POOF_TARGET_LINUX;
+#endif
+ }
+
+ uint8_t targets[3] = { POOF_TARGET_WIN32, POOF_TARGET_LINUX, POOF_TARGET_MACOS };
+ int target_count = 0;
+ for (int i = 0; i < 3; ++i) {
+ if (mask & targets[i]) target_count++;
+ }
+
+ bool multi_target = target_count > 1;
+
+ for (int i = 0; i < 3; ++i) {
+ if (mask & targets[i]) {
+ Poof_Cmd cmd = poof__cc_build_cmd(cc, targets[i], multi_target);
+ poof_batch_append_cmd(batch, cmd);
+ }
+ }
+
+ poof_cc_free(cc);
+}
+
+extern void
+poof_batch_free(Poof_Batch *batch)
+{
+ if (batch->cmds) {
+ for (size_t i = 0; i < batch->count; ++i) {
+ poof_cmd_free(&batch->cmds[i]);
+ }
+ free(batch->cmds);
+ batch->cmds = NULL;
+ }
+ batch->capacity = 0;
+ batch->count = 0;
+}
+
+extern bool
+poof_batch_run_parallel(Poof_Batch *batch, const char *label, size_t max_jobs)
+{
+ if (!batch || batch->count == 0) return true;
+ if (!label) label = "BATCH";
+
+#if defined(_WIN32)
+ if (max_jobs == 0) {
+ SYSTEM_INFO sysinfo;
+ GetSystemInfo(&sysinfo);
+ max_jobs = sysinfo.dwNumberOfProcessors > 0 ? sysinfo.dwNumberOfProcessors : 4;
+ }
+ if (max_jobs > MAXIMUM_WAIT_OBJECTS) max_jobs = MAXIMUM_WAIT_OBJECTS;
+
+ size_t total = batch->count;
+ size_t next_job = 0;
+ size_t completed = 0;
+ bool success = true;
+
+ HANDLE *handles = (HANDLE *)calloc(max_jobs, sizeof(HANDLE));
+ if (!handles) return false;
+ size_t active_jobs = 0;
+
+ poof_progress_bar(label, 0.0f, 0.0f, (float)total, 30.0f);
+
+ while (completed < total) {
+ while (active_jobs < max_jobs && next_job < total) {
+ char *cmdline = poof__cmd_to_string(&batch->cmds[next_job]);
+ if (cmdline) {
+ char win_cmd[1024];
+ snprintf(win_cmd, sizeof(win_cmd), "cmd.exe /c \"%s\"", cmdline);
+
+ STARTUPINFOA si = { sizeof(si) };
+ PROCESS_INFORMATION pi = {0};
+
+ if (CreateProcessA(NULL, win_cmd, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi)) {
+ CloseHandle(pi.hThread);
+ handles[active_jobs++] = pi.hProcess;
+ } else {
+ success = false;
+ }
+ free(cmdline);
+ }
+ next_job++;
+ }
+
+ if (active_jobs == 0) break;
+
+ DWORD dwWait = WaitForMultipleObjects((DWORD)active_jobs, handles, FALSE, INFINITE);
+ if (dwWait >= WAIT_OBJECT_0 && dwWait < WAIT_OBJECT_0 + active_jobs) {
+ DWORD idx = dwWait - WAIT_OBJECT_0;
+ DWORD exit_code = 0;
+ GetExitCodeProcess(handles[idx], &exit_code);
+ if (exit_code != 0) success = false;
+ CloseHandle(handles[idx]);
+
+ for (size_t i = idx; i < active_jobs - 1; ++i) {
+ handles[i] = handles[i + 1];
+ }
+ active_jobs--;
+ completed++;
+ poof_progress_bar(label, (float)completed, 0.0f, (float)total, 30.0f);
+ } else {
+ break;
+ }
+ }
+
+ free(handles);
+ poof_batch_free(batch);
+ return success;
+#else
+ if (max_jobs == 0) {
+ long nprocs = sysconf(_SC_NPROCESSORS_ONLN);
+ max_jobs = (nprocs > 0) ? (size_t)nprocs : 4;
+ }
+
+ size_t total = batch->count;
+ size_t next_job = 0;
+ size_t active_jobs = 0;
+ size_t completed = 0;
+ bool success = true;
+
+ poof_progress_bar(label, 0.0f, 0.0f, (float)total, 30.0f);
+
+ while (completed < total) {
+ while (active_jobs < max_jobs && next_job < total) {
+ char *cmdline = poof__cmd_to_string(&batch->cmds[next_job]);
+ if (cmdline) {
+ pid_t pid = fork();
+ if (pid == 0) {
+ execl("/bin/sh", "sh", "-c", cmdline, (char *)NULL);
+ _exit(127);
+ } else if (pid > 0) {
+ active_jobs++;
+ } else {
+ success = false;
+ }
+ free(cmdline);
+ }
+ next_job++;
+ }
+
+ if (active_jobs == 0) break;
+
+ int status = 0;
+ pid_t done_pid = wait(&status);
+ if (done_pid > 0) {
+ active_jobs--;
+ completed++;
+ if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
+ success = false;
+ }
+ poof_progress_bar(label, (float)completed, 0.0f, (float)total, 30.0f);
+ } else if (done_pid < 0 && errno == ECHILD) {
+ break;
+ }
+ }
+
+ poof_batch_free(batch);
+ return success;
+#endif
+}
+
+extern bool
+poof_batch_run(Poof_Batch *batch, const char *label)
+{
+ return poof_batch_run_parallel(batch, label, 0);
+}
+
+static bool
+poof__cc_run_single(const Poof_CC *cc, uint8_t target_platform, bool multi_target)
+{
+ Poof_Cmd cmd = poof__cc_build_cmd(cc, target_platform, multi_target);
+ bool result = poof_cmd_run(&cmd);
+ poof_cmd_free(&cmd);
+ return result;
+}
+
+extern bool
+poof_cc_run(Poof_CC *cc)
+{
+ uint8_t mask = cc->target_platform;
+ if (mask == 0) {
+#if defined(_WIN32)
+ mask = POOF_TARGET_WIN32;
+#elif defined(__APPLE__)
+ mask = POOF_TARGET_MACOS;
+#else
+ mask = POOF_TARGET_LINUX;
+#endif
+ }
+
+ uint8_t targets[3] = { POOF_TARGET_WIN32, POOF_TARGET_LINUX, POOF_TARGET_MACOS };
+ int target_count = 0;
+ for (int i = 0; i < 3; ++i) {
+ if (mask & targets[i]) target_count++;
+ }
+
+ bool multi_target = target_count > 1;
+ bool success = true;
+
+ for (int i = 0; i < 3; ++i) {
+ if (mask & targets[i]) {
+ if (!poof__cc_run_single(cc, targets[i], multi_target)) {
+ success = false;
+ }
+ }
+ }
+
+ poof_cc_free(cc);
+ return success;
+}
+
+
+extern bool
+poof_mkdir(const char *path)
+{
+#if defined(_WIN32)
+ return _mkdir(path) == 0 || errno == EEXIST;
+#else
+ return mkdir(path, 0755) == 0 || errno == EEXIST;
+#endif
+}
+
+extern bool
+poof_touch(const char *path)
+{
+ FILE *f = fopen(path, "a");
+ if (!f) return false;
+ fclose(f);
+ return true;
+}
+
+extern bool
+poof_rm(const char *path)
+{
+ return remove(path) == 0;
+}
+
+extern bool
+poof_rm_recursive(const char *path)
+{
+#if defined(_WIN32)
+ char cmd[512];
+ snprintf(cmd, sizeof(cmd), "rmdir /s /q \"%s\"", path);
+ return system(cmd) == 0;
+#else
+ char cmd[512];
+ snprintf(cmd, sizeof(cmd), "rm -rf \"%s\"", path);
+ return system(cmd) == 0;
+#endif
+}
+
+extern bool
+poof_copy_file(const char *src, const char *dst)
+{
+ FILE *in = fopen(src, "rb");
+ if (!in) return false;
+ FILE *out = fopen(dst, "wb");
+ if (!out) {
+ fclose(in);
+ return false;
+ }
+
+ char buffer[8192];
+ size_t bytes;
+ while ((bytes = fread(buffer, 1, sizeof(buffer), in)) > 0) {
+ fwrite(buffer, 1, bytes, out);
+ }
+
+ fclose(in);
+ fclose(out);
+ return true;
+}
+
+static time_t
+poof__get_mtime(const char *path)
+{
+ struct stat attr;
+ if (stat(path, &attr) != 0) return 0;
+ return attr.st_mtime;
+}
+
+extern bool
+poof_needs_rebuild(const char *target, const char **sources, size_t source_count)
+{
+ time_t target_mtime = poof__get_mtime(target);
+ if (target_mtime == 0) return true; // Target does not exist
+
+ for (size_t i = 0; i < source_count; ++i) {
+ time_t src_mtime = poof__get_mtime(sources[i]);
+ if (src_mtime > target_mtime) return true;
+ }
+ return false;
+}
+
+extern int
+poof_print(uint32_t col, const char *text, ...)
+{
+ uint8_t r = (col >> 16) & 0xFF;
+ uint8_t g = (col >> 8) & 0xFF;
+ uint8_t b = col & 0xFF;
+
+ printf("\033[38;2;%d;%d;%dm", r, g, b);
+
+ va_list args;
+ va_start(args, text);
+ int res = vprintf(text, args);
+ va_end(args);
+
+ printf("\033[0m");
+ fflush(stdout);
+ return res;
+}
+
+extern int
+poof_progress_bar(const char *label, float value, float min, float max, float width)
+{
+ float norm = (value - min) / (max - min);
+ if (norm < 0.0f) norm = 0.0f;
+ if (norm > 1.0f) norm = 1.0f;
+
+ int filled = (int)(norm * width);
+ int total = (int)width;
+
+ char bar[256];
+ int pos = 0;
+ for (int i = 0; i < total && pos < (int)sizeof(bar) - 1; ++i) {
+ if (i < filled) bar[pos++] = '|';
+ else bar[pos++] = ' ';
+ }
+ bar[pos] = '\0';
+
+ printf("\r[%s] [", label ? label : "PROGRESS");
+ poof_print(0xFE9900, "%s", bar);
+ printf("] %d/%d jobs", (int)value, (int)max);
+ if (norm >= 1.0f) printf("\n");
+ fflush(stdout);
+ return 0;
+}
+
+extern void
+poof_go_rebuild_urself_impl(int argc, char **argv, const char *source_file)
+{
+ const char *binary_file = argv[0];
+ const char *sources[] = { source_file, "Poof/poof.h" };
+
+ if (!poof_needs_rebuild(binary_file, sources, 2)) {
+ return;
+ }
+
+ char binary_old[4096];
+ snprintf(binary_old, sizeof(binary_old), "%s.old", binary_file);
+
+ poof_print(0xFF8800, "[POOF] Source changed. Rebuilding %s...\n", binary_file);
+
+ poof_rm(binary_old);
+ rename(binary_file, binary_old);
+
+ Poof_Cmd cmd = {0};
+ poof_cmd_append(&cmd, "gcc", "-o", binary_file, source_file, "-IPodium", "-IPoof");
+
+ if (!poof_cmd_run(&cmd)) {
+ poof_print(0xFF0000, "[POOF] Rebuild failed!\n");
+ rename(binary_old, binary_file);
+ exit(1);
+ }
+ poof_cmd_free(&cmd);
+
+ poof_print(0x00FF00, "[POOF] Rebuild successful! Re-launching binary...\n");
+
+ #if defined(_WIN32)
+ // Windows restart
+ int status = system(binary_file);
+ exit(status);
+ #else
+ execv(binary_file, argv);
+ perror("execv");
+ exit(1);
+ #endif
+}
+#endif
+
+/*
+------------------------------------------------------------------------------
+This software is available under 2 licenses -- choose whichever you prefer.
+------------------------------------------------------------------------------
+ALTERNATIVE A - MIT License
+Copyright (c) 2026 Vasco Alves
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+of the Software, and to permit persons to whom the Software is furnished to do
+so, subject to the following conditions:
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+------------------------------------------------------------------------------
+ALTERNATIVE B - Public Domain (www.unlicense.org)
+This is free and unencumbered software released into the public domain.
+Anyone is free to copy, modify, publish, use, compile, sell, or distribute this
+software, either in source code form or as a compiled binary, for any purpose,
+commercial or non-commercial, and by any means.
+In jurisdictions that recognize copyright laws, the author or authors of this
+software dedicate any and all copyright interest in the software to the public
+domain. We make this dedication for the benefit of the public at large and to
+the detriment of our heirs and successors. We intend this dedication to be an
+overt act of relinquishment in perpetuity of all present and future rights to
+this software under copyright law.
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+------------------------------------------------------------------------------
+*/
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..dfde148
--- /dev/null
+++ b/README.md
@@ -0,0 +1,32 @@
+```
+ ▄▄ • ▄• ▄▌ ▐ ▄ .▄▄ · ▄▄▄▄▄ ▄▄▄· ▄▄· ▄ •▄
+▐█ ▀ ▪█▪██▌•█▌▐█▐█ ▀. •██ ▐█ ▀█ ▐█ ▌▪█▌▄▌▪
+▄█ ▀█▄█▌▐█▌▐█▐▐▌▄▀▀▀█▄ ▐█.▪▄█▀▀█ ██ ▄▄▐▀▀▄·
+▐█▄▪▐█▐█▄█▌██▐█▌▐█▄▪▐█ ▐█▌·▐█ ▪▐▌▐███▌▐█.█▌
+·▀▀▀▀ ▀▀▀ ▀▀ █▪ ▀▀▀▀ ▀▀▀ ▀ ▀ ·▀▀▀ ·▀ ▀
+```
+
+Collection of modular and minimal libraries used by our games. These libraries are designed to be
+"vendored in" aka. copy-and-pasted into a project's folder. Some libraries may depend on each other.
+Each library should contain a license in the header.
+
+Use at your own risk.
+
+| Name | Description |
+| ------ | ------------------------------------------ |
+| Podium | Platform layer & kitchen sink. |
+| Peak | Automagic cross-platform dark magic. |
+| Poof | Build software without going insane. |
+| Rend | Modern graphics API layer. |
+| Cool | Render HTML by calling functions. |
+
+## Maturity
+
+Rend and Podium are the most mature. Some libraries are still in development. Check the version
+included in each header file. Be encouraged and not discouraged if a library "isn't updated," it's probably
+because it works.
+
+## Documentation
+
+Documentation can be found on [godgun.net](https://godgun.net/docs) (results may vary).
+We recommend just reading the header files. It's all there.
diff --git a/Rend/README.md b/Rend/README.md
new file mode 100644
index 0000000..2655f98
--- /dev/null
+++ b/Rend/README.md
@@ -0,0 +1,28 @@
+# Rend
+
+Send data to the GPU in a stable cross-platform and cross-graphics-API way.
+
+Here's an example render loop used in my game!
+
+```c
+ if (rend_renderer_frame_begin(renderer)) {
+
+ // First pass: draw to a texture representing the in-game pixel art dimentions.
+ rend_cmd_render_begin_texture(renderer, &canvas); { // brackets for style
+ rend_cmd_bind_pipeline(ui_pipeline);
+ rend_cmd_push_constants(ui_pipeline, &push_constants, sizeof(push_constants));
+ rend_cmd_draw(ui_pipeline, vert_count, 1); // a vertex buffer is not bound because it's passed via push constants
+ } rend_cmd_render_end_texture(renderer, &canvas);
+
+ // Second pass: apply post processing using the native swapchain
+ rend_cmd_render_begin(renderer, 1.0, 0.5, 0.0, 1.0); { // RGBA clear colors
+ rend_cmd_bind_pipeline(present_pipeline);
+ rend_cmd_push_constants(present_pipeline, &present_pc, sizeof(present_pc));
+ rend_cmd_draw(present_pipeline, 4, 1); // 4 vertices and one instance
+ } rend_cmd_render_end(renderer);
+
+ rend_renderer_frame_end(renderer, &delta);
+ }
+
+ }
+```
diff --git a/Rend/demos/build.c b/Rend/demos/build.c
new file mode 100644
index 0000000..3d67006
--- /dev/null
+++ b/Rend/demos/build.c
@@ -0,0 +1,85 @@
+#define POOF_IMPLEMENTATION
+#include "poof.h"
+
+void add_podium_config(Poof_CC *cc) {
+ poof_cmd_append(&cc->includes, "Podium");
+
+#if defined(PODIUM_WIN32)
+ poof_cc_append_win32(cc, "-DPODIUM_WIN32", "-luser32", "-lgdi32");
+ const char *vulkan_sdk = getenv("VULKAN_SDK");
+ if (vulkan_sdk) {
+ char inc_buf[512], lib_buf[512];
+ snprintf(inc_buf, sizeof(inc_buf), "-I%s/Include", vulkan_sdk);
+ snprintf(lib_buf, sizeof(lib_buf), "-L%s/Lib", vulkan_sdk);
+ poof_cc_append_win32(cc, strdup(inc_buf), strdup(lib_buf));
+ }
+ poof_cc_append_win32(cc, "-lvulkan-1");
+#else
+ poof_cc_append_linux(cc, "-lX11", "-D_REENTRANT", "-lpulse", "-lpulse-simple", "-pthread", "-lvulkan");
+#endif
+}
+
+int main(int argc, char **argv) {
+ POOF_GO_REBUILD_URSELF(argc, argv);
+
+ Poof_Batch batch = {0};
+
+ {
+ Poof_Cmd cmd = {0};
+ poof_cmd_append(&cmd, "slangc", "rend_compute.slang", "-target", "spirv", "-entry", "particleMain", "-stage", "compute", "-o", "compute/particle.spv");
+ poof_batch_append_cmd(&batch, cmd);
+ }
+
+ {
+ Poof_Cmd cmd = {0};
+ poof_cmd_append(&cmd, "slangc", "rend_compute.slang", "-target", "spirv", "-entry", "sandMain", "-stage", "compute", "-o", "compute/sand.spv");
+ poof_batch_append_cmd(&batch, cmd);
+ }
+
+ {
+ Poof_Cmd cmd = {0};
+ poof_cmd_append(&cmd, "slangc", "rend_compute.slang", "-target", "spirv", "-entry", "vertMain", "-stage", "vertex", "-o", "compute/vert.spv");
+ poof_batch_append_cmd(&batch, cmd);
+ }
+
+ {
+ Poof_Cmd cmd = {0};
+ poof_cmd_append(&cmd, "slangc", "rend_compute.slang", "-target", "spirv", "-entry", "fragMain", "-stage", "fragment", "-o", "compute/frag.spv");
+ poof_batch_append_cmd(&batch, cmd);
+ }
+
+ // Debug build
+ {
+ Poof_CC cc;
+ poof_cc_init(&cc, POOF_CC_GCC, POOF_TARGET_HOST);
+ cc.debug_mode = true;
+ cc.optimization = POOF_O0;
+ cc.output = "compute/rend_compute_demo";
+ poof_cmd_append(&cc.inputs, "rend_compute.c");
+ poof_cmd_append(&cc.includes, "..", ".");
+ poof_cmd_append(&cc.defines, "REND_DEBUG");
+ poof_cmd_append(&cc.libs, "m");
+ poof_cmd_append(&cc.extra_flags, "-ggdb");
+ add_podium_config(&cc);
+
+ poof_batch_append_cc(&batch, &cc);
+ }
+
+ // Debug build
+ {
+ Poof_CC cc;
+ poof_cc_init(&cc, POOF_CC_GCC, POOF_TARGET_HOST);
+ cc.debug_mode = true;
+ cc.optimization = POOF_O3 | POOF_MSSE2;
+ cc.output = "compute/rend_compute_fast";
+ poof_cmd_append(&cc.inputs, "rend_compute.c");
+ poof_cmd_append(&cc.includes, "..");
+ poof_cmd_append(&cc.libs, "m");
+ add_podium_config(&cc);
+
+ poof_batch_append_cc(&batch, &cc);
+ }
+
+ poof_batch_run(&batch, "Rend Demos");
+ return 0;
+}
diff --git a/Rend/demos/compute/frag.spv b/Rend/demos/compute/frag.spv
new file mode 100644
index 0000000..5366c51
--- /dev/null
+++ b/Rend/demos/compute/frag.spv
Binary files differ
diff --git a/Rend/demos/compute/particle.spv b/Rend/demos/compute/particle.spv
new file mode 100644
index 0000000..6547772
--- /dev/null
+++ b/Rend/demos/compute/particle.spv
Binary files differ
diff --git a/Rend/demos/compute/rend_compute_demo b/Rend/demos/compute/rend_compute_demo
new file mode 100755
index 0000000..071b495
--- /dev/null
+++ b/Rend/demos/compute/rend_compute_demo
Binary files differ
diff --git a/Rend/demos/compute/rend_compute_fast b/Rend/demos/compute/rend_compute_fast
new file mode 100755
index 0000000..b9dac67
--- /dev/null
+++ b/Rend/demos/compute/rend_compute_fast
Binary files differ
diff --git a/Rend/demos/compute/sand.spv b/Rend/demos/compute/sand.spv
new file mode 100644
index 0000000..9dcac4d
--- /dev/null
+++ b/Rend/demos/compute/sand.spv
Binary files differ
diff --git a/Rend/demos/compute/vert.spv b/Rend/demos/compute/vert.spv
new file mode 100644
index 0000000..e5d2970
--- /dev/null
+++ b/Rend/demos/compute/vert.spv
Binary files differ
diff --git a/Rend/demos/poof.h b/Rend/demos/poof.h
new file mode 100644
index 0000000..3480557
--- /dev/null
+++ b/Rend/demos/poof.h
@@ -0,0 +1,874 @@
+/* ===========================================================================
+ * POOF - The Universal Build System - Copyright (c) 2026 Vasco Alves
+ *
+ * PREFIX: Poof_ (types) or poof_ (functions & variables)
+ *
+ * DESCRIPTION:
+ * Platform independent-ish build system!
+ * Performant, multi-threaded and mesmerizing.
+ *
+ * See LICENSE at the end of the file.
+ * =========================================================================== */
+
+#ifndef _POOF_H_
+#define _POOF_H_
+
+#define POOF_MAJOR 0
+#define POOF_MINOR 1
+#define POOF_PATCH 0
+
+#include <stdint.h>
+#include <stdbool.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <sys/stat.h>
+
+#if defined(_WIN32)
+ #include <windows.h>
+ #include <direct.h>
+ #include <io.h>
+#else
+ #include <unistd.h>
+ #include <sys/wait.h>
+ #include <sys/types.h>
+ #include <dirent.h>
+ #include <errno.h>
+#endif
+
+enum PoofTargetPlatform {
+ POOF_TARGET_HOST = 0,
+ POOF_TARGET_WIN32 = 1,
+ POOF_TARGET_LINUX = 1 << 1,
+ POOF_TARGET_MACOS = 1 << 2,
+};
+
+enum PoofCCFlags {
+ POOF_CC_GCC = 1,
+ POOF_CC_CLANG = 1 << 1,
+ POOF_CC_MSVC = 1 << 2,
+ POOF_CC_MINGW = 1 << 3,
+};
+
+enum PoofOptimizationFlags {
+ POOF_O0 = 0,
+ POOF_O1 = 1,
+ POOF_O2 = 2,
+ POOF_O3 = 3,
+ POOF_MSSE = 1 << 3,
+ POOF_MSSE2 = 1 << 4,
+ POOF_AVX = 1 << 5,
+ POOF_AVX2 = 1 << 6,
+ POOF_AVX512F = 1 << 7,
+};
+
+#define POOF_IS_SET(var, flag) (((var) & (flag)) != 0)
+
+typedef struct Poof_Cmd {
+ const char **items;
+ size_t capacity;
+ size_t count;
+} Poof_Cmd;
+
+typedef struct Poof_CC {
+ uint8_t compiler; // enum PoofCCFlags
+ uint8_t target_platform; // enum PoofTargetPlatform
+ uint32_t optimization; // bitwise PoofOptimizationFlags
+ bool debug_mode;
+ Poof_Cmd inputs;
+ const char *output;
+ Poof_Cmd includes;
+ Poof_Cmd lib_paths;
+ Poof_Cmd libs;
+ Poof_Cmd defines;
+ Poof_Cmd extra_flags;
+
+ /* Platform specific flags */
+ Poof_Cmd win32_flags;
+ Poof_Cmd linux_flags;
+ Poof_Cmd macos_flags;
+} Poof_CC;
+
+typedef struct Poof_Batch {
+ Poof_Cmd *cmds;
+ size_t capacity;
+ size_t count;
+} Poof_Batch;
+
+/* Command operations */
+extern void poof_cmd_append_internal(Poof_Cmd *cmd, ...);
+#define poof_cmd_append(cmd, ...) poof_cmd_append_internal((cmd), __VA_ARGS__, NULL)
+
+#define poof_cc_append_win32(cc, ...) poof_cmd_append_internal(&((cc)->win32_flags), __VA_ARGS__, NULL)
+#define poof_cc_append_linux(cc, ...) poof_cmd_append_internal(&((cc)->linux_flags), __VA_ARGS__, NULL)
+#define poof_cc_append_macos(cc, ...) poof_cmd_append_internal(&((cc)->macos_flags), __VA_ARGS__, NULL)
+
+extern void poof_cmd_free(Poof_Cmd *cmd);
+extern void poof_cmd_clear(Poof_Cmd *cmd);
+extern bool poof_cmd_run(Poof_Cmd *cmd);
+
+/* Batch operations */
+extern void poof_batch_append_cmd(Poof_Batch *batch, Poof_Cmd cmd);
+extern void poof_batch_append_cc(Poof_Batch *batch, Poof_CC *cc);
+#define poof_batch_append(batch, cmd) poof_batch_append_cmd((batch), (cmd))
+extern void poof_batch_free(Poof_Batch *batch);
+extern bool poof_batch_run(Poof_Batch *batch, const char *label);
+extern bool poof_batch_run_parallel(Poof_Batch *batch, const char *label, size_t max_jobs);
+
+/* Compiler abstraction */
+extern uint8_t poof_cc_available(void);
+extern void poof_cc_init(Poof_CC *cc, uint8_t compiler, uint8_t target_platform);
+extern void poof_cc_free(Poof_CC *cc);
+extern bool poof_cc_run(Poof_CC *cc);
+
+/* File and directory utilities */
+extern bool poof_mkdir(const char *path);
+extern bool poof_touch(const char *path);
+extern bool poof_rm(const char *path);
+extern bool poof_rm_recursive(const char *path);
+extern bool poof_copy_file(const char *src, const char *dst);
+extern bool poof_needs_rebuild(const char *target, const char **sources, size_t source_count);
+
+/* Output and pretty printing */
+extern int poof_print(uint32_t col, const char *text, ...);
+extern int poof_progress_bar(const char *label, float value, float min, float max, float width);
+
+/* Rebuild self macro */
+extern void poof_go_rebuild_urself_impl(int argc, char **argv, const char *source_file);
+
+#define POOF_GO_REBUILD_URSELF(argc, argv) poof_go_rebuild_urself_impl(argc, argv, __FILE__)
+
+#endif // _POOF_H_
+
+#ifdef POOF_IMPLEMENTATION
+#undef POOF_IMPLEMENTATION
+
+#if defined(_WIN32)
+#define POOF_DEV_NULL "nul 2>&1"
+#else
+#define POOF_DEV_NULL "/dev/null 2>&1"
+#endif
+
+static bool
+poof__probe_cmd(const char *cmd)
+{
+ char buffer[256];
+ snprintf(buffer, sizeof(buffer), "%s > " POOF_DEV_NULL, cmd);
+ return (system(buffer) == 0);
+}
+
+extern uint8_t
+poof_cc_available(void)
+{
+ uint8_t available = 0;
+
+ poof_print(0x00FF88, "[POOF] Probing available compilers:\n");
+ if (poof__probe_cmd("gcc --version")) {
+ available |= POOF_CC_GCC;
+ poof_print(0x00FF88, " - GCC: available\n");
+ }
+
+ if (poof__probe_cmd("clang --version")) {
+ available |= POOF_CC_CLANG;
+ poof_print(0x00FF88, " - CLANG: available\n");
+ }
+
+ if (poof__probe_cmd("x86_64-w64-mingw32-gcc --version") || poof__probe_cmd("mingw32-gcc --version")) {
+ available |= POOF_CC_MINGW;
+ poof_print(0x00FF88, " - MinGW: available\n");
+ }
+
+ if (poof__probe_cmd("cl")) {
+ available |= POOF_CC_MSVC;
+ poof_print(0x00FF88, " - MSVC: available\n");
+ }
+
+ return available;
+}
+
+extern void
+poof_cmd_append_internal(Poof_Cmd *cmd, ...)
+{
+ va_list args;
+ va_start(args, cmd);
+ const char *arg = NULL;
+ while ((arg = va_arg(args, const char *)) != NULL) {
+
+ if (cmd->count >= cmd->capacity) {
+ size_t new_cap = cmd->capacity == 0 ? 16 : cmd->capacity * 2;
+ const char **new_items = (const char **)realloc(cmd->items, new_cap * sizeof(const char *));
+ if (!new_items) return;
+ cmd->items = new_items;
+ cmd->capacity = new_cap;
+ }
+ cmd->items[cmd->count++] = arg;
+ }
+ va_end(args);
+}
+
+
+extern void
+poof_cmd_clear(Poof_Cmd *cmd)
+{
+ /* clear count while keeping capacity */
+ cmd->count = 0;
+}
+
+extern void
+poof_cmd_free(Poof_Cmd *cmd)
+{
+ if (cmd->items) {
+ free(cmd->items);
+ cmd->items = NULL;
+ }
+ cmd->capacity = 0;
+ cmd->count = 0;
+}
+
+static char *
+poof__cmd_to_string(const Poof_Cmd *cmd)
+{
+ if (!cmd || cmd->count == 0) return NULL;
+
+ size_t total_len = 0;
+ for (size_t i = 0; i < cmd->count; ++i) {
+ total_len += strlen(cmd->items[i]) + 3; // quotes and space
+ }
+
+ char *cmdline = (char *)malloc(total_len + 1);
+ if (!cmdline) return NULL;
+ cmdline[0] = '\0';
+
+ for (size_t i = 0; i < cmd->count; ++i) {
+ if (i > 0) strcat(cmdline, " ");
+ bool need_quote = (strchr(cmd->items[i], ' ') != NULL);
+ if (need_quote) strcat(cmdline, "\"");
+ strcat(cmdline, cmd->items[i]);
+ if (need_quote) strcat(cmdline, "\"");
+ }
+
+ return cmdline;
+}
+
+extern bool
+poof_cmd_run(Poof_Cmd *cmd)
+{
+ char *cmdline = poof__cmd_to_string(cmd);
+ if (!cmdline) return false;
+
+ printf("[POOF] Executing: ");
+ poof_print(0xA9B665, "%s\n", cmdline);
+
+ int status = system(cmdline);
+ free(cmdline);
+ poof_cmd_clear(cmd);
+ return (status == 0);
+}
+
+extern void
+poof_cc_init(Poof_CC *cc, uint8_t compiler, uint8_t target_platform)
+{
+ memset(cc, 0, sizeof(Poof_CC));
+ cc->compiler = compiler;
+ cc->target_platform = target_platform;
+ cc->optimization = POOF_O0;
+ cc->debug_mode = true;
+}
+
+extern void
+poof_cc_free(Poof_CC *cc)
+{
+ poof_cmd_free(&cc->inputs);
+ poof_cmd_free(&cc->includes);
+ poof_cmd_free(&cc->lib_paths);
+ poof_cmd_free(&cc->libs);
+ poof_cmd_free(&cc->defines);
+ poof_cmd_free(&cc->extra_flags);
+ poof_cmd_free(&cc->win32_flags);
+ poof_cmd_free(&cc->linux_flags);
+ poof_cmd_free(&cc->macos_flags);
+}
+
+extern void
+poof_batch_append_cmd(Poof_Batch *batch, Poof_Cmd cmd)
+{
+ if (batch->count >= batch->capacity) {
+ size_t new_cap = batch->capacity == 0 ? 16 : batch->capacity * 2;
+ Poof_Cmd *new_cmds = (Poof_Cmd *)realloc(batch->cmds, new_cap * sizeof(Poof_Cmd));
+ if (!new_cmds) return;
+ batch->cmds = new_cmds;
+ batch->capacity = new_cap;
+ }
+ batch->cmds[batch->count++] = cmd;
+}
+
+static Poof_Cmd
+poof__cc_build_cmd(const Poof_CC *cc, uint8_t target_platform, bool multi_target)
+{
+ Poof_Cmd cmd = {0};
+
+ // Pick compiler binary
+ if (cc->compiler & POOF_CC_GCC) {
+ if (target_platform == POOF_TARGET_WIN32) {
+ poof_cmd_append(&cmd, "x86_64-w64-mingw32-gcc");
+ } else {
+ poof_cmd_append(&cmd, "gcc");
+ }
+ } else if (cc->compiler & POOF_CC_CLANG) {
+ poof_cmd_append(&cmd, "clang");
+ if (target_platform == POOF_TARGET_WIN32) {
+ poof_cmd_append(&cmd, "-target");
+ poof_cmd_append(&cmd, "x86_64-pc-windows-gnu");
+ } else if (target_platform == POOF_TARGET_LINUX) {
+ poof_cmd_append(&cmd, "-target");
+ poof_cmd_append(&cmd, "x86_64-unknown-linux-gnu");
+ } else if (target_platform == POOF_TARGET_MACOS) {
+ poof_cmd_append(&cmd, "-target");
+ poof_cmd_append(&cmd, "x86_64-apple-darwin");
+ }
+ } else if (cc->compiler & POOF_CC_MINGW) {
+ poof_cmd_append(&cmd, "x86_64-w64-mingw32-gcc");
+ } else if (cc->compiler & POOF_CC_MSVC) {
+ poof_cmd_append(&cmd, "cl");
+ } else {
+ poof_cmd_append(&cmd, "gcc");
+ }
+
+ bool is_msvc = (cc->compiler & POOF_CC_MSVC) != 0;
+
+ // Debug flags
+ if (cc->debug_mode) {
+ poof_cmd_append(&cmd, is_msvc ? "/Zi" : "-g");
+ }
+
+ // Optimization flags
+ uint32_t opt_level = cc->optimization & 3;
+ if (opt_level == POOF_O1) poof_cmd_append(&cmd, is_msvc ? "/O1" : "-O1");
+ else if (opt_level == POOF_O2) poof_cmd_append(&cmd, is_msvc ? "/O2" : "-O2");
+ else if (opt_level == POOF_O3) poof_cmd_append(&cmd, is_msvc ? "/O2" : "-O3");
+ else poof_cmd_append(&cmd, is_msvc ? "/Od" : "-O0");
+
+ // SIMD / Arch extensions
+ if (POOF_IS_SET(cc->optimization, POOF_MSSE)) poof_cmd_append(&cmd, is_msvc ? "/arch:SSE" : "-msse");
+ if (POOF_IS_SET(cc->optimization, POOF_MSSE2)) poof_cmd_append(&cmd, is_msvc ? "/arch:SSE2" : "-msse2");
+ if (POOF_IS_SET(cc->optimization, POOF_AVX)) poof_cmd_append(&cmd, is_msvc ? "/arch:AVX" : "-mavx");
+ if (POOF_IS_SET(cc->optimization, POOF_AVX2)) poof_cmd_append(&cmd, is_msvc ? "/arch:AVX2" : "-mavx2");
+ if (POOF_IS_SET(cc->optimization, POOF_AVX512F)) poof_cmd_append(&cmd, is_msvc ? "/arch:AVX512" : "-mavx512f");
+
+ // Defines
+ for (size_t i = 0; i < cc->defines.count; ++i) {
+ char buf[256];
+ snprintf(buf, sizeof(buf), "%s%s", is_msvc ? "/D" : "-D", cc->defines.items[i]);
+ poof_cmd_append(&cmd, strdup(buf));
+ }
+
+ // Include dirs
+ for (size_t i = 0; i < cc->includes.count; ++i) {
+ char buf[512];
+ snprintf(buf, sizeof(buf), "%s%s", is_msvc ? "/I" : "-I", cc->includes.items[i]);
+ poof_cmd_append(&cmd, strdup(buf));
+ }
+
+ // Input files
+ for (size_t i = 0; i < cc->inputs.count; ++i) {
+ poof_cmd_append(&cmd, cc->inputs.items[i]);
+ }
+
+ // Output target
+ if (cc->output) {
+ char out_path[512];
+ if (target_platform == POOF_TARGET_WIN32) {
+ if (strstr(cc->output, ".exe")) {
+ snprintf(out_path, sizeof(out_path), "%s", cc->output);
+ } else {
+ snprintf(out_path, sizeof(out_path), multi_target ? "%s_win32.exe" : "%s.exe", cc->output);
+ }
+ } else if (target_platform == POOF_TARGET_MACOS) {
+ snprintf(out_path, sizeof(out_path), multi_target ? "%s_macos" : "%s", cc->output);
+ } else if (target_platform == POOF_TARGET_LINUX) {
+ snprintf(out_path, sizeof(out_path), multi_target ? "%s_linux" : "%s", cc->output);
+ } else {
+ snprintf(out_path, sizeof(out_path), "%s", cc->output);
+ }
+
+ if (is_msvc) {
+ char buf[512];
+ snprintf(buf, sizeof(buf), "/Fe:%s", out_path);
+ poof_cmd_append(&cmd, strdup(buf));
+ } else {
+ poof_cmd_append(&cmd, "-o");
+ poof_cmd_append(&cmd, strdup(out_path));
+ }
+ }
+
+ // Lib paths & libs
+ for (size_t i = 0; i < cc->lib_paths.count; ++i) {
+ char buf[512];
+ snprintf(buf, sizeof(buf), "%s%s", is_msvc ? "/LIBPATH:" : "-L", cc->lib_paths.items[i]);
+ poof_cmd_append(&cmd, strdup(buf));
+ }
+
+ for (size_t i = 0; i < cc->libs.count; ++i) {
+ if (is_msvc) {
+ char buf[256];
+ snprintf(buf, sizeof(buf), "%s.lib", cc->libs.items[i]);
+ poof_cmd_append(&cmd, strdup(buf));
+ } else {
+ char buf[256];
+ snprintf(buf, sizeof(buf), "-l%s", cc->libs.items[i]);
+ poof_cmd_append(&cmd, strdup(buf));
+ }
+ }
+
+ // Extra flags
+ for (size_t i = 0; i < cc->extra_flags.count; ++i) {
+ poof_cmd_append(&cmd, cc->extra_flags.items[i]);
+ }
+
+ // Platform specific flags
+ const Poof_Cmd *plat_cmd = NULL;
+ if (target_platform == POOF_TARGET_WIN32) plat_cmd = &cc->win32_flags;
+ else if (target_platform == POOF_TARGET_LINUX) plat_cmd = &cc->linux_flags;
+ else if (target_platform == POOF_TARGET_MACOS) plat_cmd = &cc->macos_flags;
+
+ if (plat_cmd) {
+ for (size_t i = 0; i < plat_cmd->count; ++i) {
+ poof_cmd_append(&cmd, plat_cmd->items[i]);
+ }
+ }
+
+ return cmd;
+}
+
+extern void
+poof_batch_append_cc(Poof_Batch *batch, Poof_CC *cc)
+{
+ uint8_t mask = cc->target_platform;
+ if (mask == 0) {
+#if defined(_WIN32)
+ mask = POOF_TARGET_WIN32;
+#elif defined(__APPLE__)
+ mask = POOF_TARGET_MACOS;
+#else
+ mask = POOF_TARGET_LINUX;
+#endif
+ }
+
+ uint8_t targets[3] = { POOF_TARGET_WIN32, POOF_TARGET_LINUX, POOF_TARGET_MACOS };
+ int target_count = 0;
+ for (int i = 0; i < 3; ++i) {
+ if (mask & targets[i]) target_count++;
+ }
+
+ bool multi_target = target_count > 1;
+
+ for (int i = 0; i < 3; ++i) {
+ if (mask & targets[i]) {
+ Poof_Cmd cmd = poof__cc_build_cmd(cc, targets[i], multi_target);
+ poof_batch_append_cmd(batch, cmd);
+ }
+ }
+
+ poof_cc_free(cc);
+}
+
+extern void
+poof_batch_free(Poof_Batch *batch)
+{
+ if (batch->cmds) {
+ for (size_t i = 0; i < batch->count; ++i) {
+ poof_cmd_free(&batch->cmds[i]);
+ }
+ free(batch->cmds);
+ batch->cmds = NULL;
+ }
+ batch->capacity = 0;
+ batch->count = 0;
+}
+
+extern bool
+poof_batch_run_parallel(Poof_Batch *batch, const char *label, size_t max_jobs)
+{
+ if (!batch || batch->count == 0) return true;
+ if (!label) label = "BATCH";
+
+#if defined(_WIN32)
+ if (max_jobs == 0) {
+ SYSTEM_INFO sysinfo;
+ GetSystemInfo(&sysinfo);
+ max_jobs = sysinfo.dwNumberOfProcessors > 0 ? sysinfo.dwNumberOfProcessors : 4;
+ }
+ if (max_jobs > MAXIMUM_WAIT_OBJECTS) max_jobs = MAXIMUM_WAIT_OBJECTS;
+
+ size_t total = batch->count;
+ size_t next_job = 0;
+ size_t completed = 0;
+ bool success = true;
+
+ HANDLE *handles = (HANDLE *)calloc(max_jobs, sizeof(HANDLE));
+ if (!handles) return false;
+ size_t active_jobs = 0;
+
+ poof_progress_bar(label, 0.0f, 0.0f, (float)total, 30.0f);
+
+ while (completed < total) {
+ while (active_jobs < max_jobs && next_job < total) {
+ char *cmdline = poof__cmd_to_string(&batch->cmds[next_job]);
+ if (cmdline) {
+ char win_cmd[1024];
+ snprintf(win_cmd, sizeof(win_cmd), "cmd.exe /c \"%s\"", cmdline);
+
+ STARTUPINFOA si = { sizeof(si) };
+ PROCESS_INFORMATION pi = {0};
+
+ if (CreateProcessA(NULL, win_cmd, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi)) {
+ CloseHandle(pi.hThread);
+ handles[active_jobs++] = pi.hProcess;
+ } else {
+ success = false;
+ }
+ free(cmdline);
+ }
+ next_job++;
+ }
+
+ if (active_jobs == 0) break;
+
+ DWORD dwWait = WaitForMultipleObjects((DWORD)active_jobs, handles, FALSE, INFINITE);
+ if (dwWait >= WAIT_OBJECT_0 && dwWait < WAIT_OBJECT_0 + active_jobs) {
+ DWORD idx = dwWait - WAIT_OBJECT_0;
+ DWORD exit_code = 0;
+ GetExitCodeProcess(handles[idx], &exit_code);
+ if (exit_code != 0) success = false;
+ CloseHandle(handles[idx]);
+
+ for (size_t i = idx; i < active_jobs - 1; ++i) {
+ handles[i] = handles[i + 1];
+ }
+ active_jobs--;
+ completed++;
+ poof_progress_bar(label, (float)completed, 0.0f, (float)total, 30.0f);
+ } else {
+ break;
+ }
+ }
+
+ free(handles);
+ poof_batch_free(batch);
+ return success;
+#else
+ if (max_jobs == 0) {
+ long nprocs = sysconf(_SC_NPROCESSORS_ONLN);
+ max_jobs = (nprocs > 0) ? (size_t)nprocs : 4;
+ }
+
+ size_t total = batch->count;
+ size_t next_job = 0;
+ size_t active_jobs = 0;
+ size_t completed = 0;
+ bool success = true;
+
+ poof_progress_bar(label, 0.0f, 0.0f, (float)total, 30.0f);
+
+ while (completed < total) {
+ while (active_jobs < max_jobs && next_job < total) {
+ char *cmdline = poof__cmd_to_string(&batch->cmds[next_job]);
+ if (cmdline) {
+ pid_t pid = fork();
+ if (pid == 0) {
+ execl("/bin/sh", "sh", "-c", cmdline, (char *)NULL);
+ _exit(127);
+ } else if (pid > 0) {
+ active_jobs++;
+ } else {
+ success = false;
+ }
+ free(cmdline);
+ }
+ next_job++;
+ }
+
+ if (active_jobs == 0) break;
+
+ int status = 0;
+ pid_t done_pid = wait(&status);
+ if (done_pid > 0) {
+ active_jobs--;
+ completed++;
+ if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
+ success = false;
+ }
+ poof_progress_bar(label, (float)completed, 0.0f, (float)total, 30.0f);
+ } else if (done_pid < 0 && errno == ECHILD) {
+ break;
+ }
+ }
+
+ poof_batch_free(batch);
+ return success;
+#endif
+}
+
+extern bool
+poof_batch_run(Poof_Batch *batch, const char *label)
+{
+ return poof_batch_run_parallel(batch, label, 0);
+}
+
+static bool
+poof__cc_run_single(const Poof_CC *cc, uint8_t target_platform, bool multi_target)
+{
+ Poof_Cmd cmd = poof__cc_build_cmd(cc, target_platform, multi_target);
+ bool result = poof_cmd_run(&cmd);
+ poof_cmd_free(&cmd);
+ return result;
+}
+
+extern bool
+poof_cc_run(Poof_CC *cc)
+{
+ uint8_t mask = cc->target_platform;
+ if (mask == 0) {
+#if defined(_WIN32)
+ mask = POOF_TARGET_WIN32;
+#elif defined(__APPLE__)
+ mask = POOF_TARGET_MACOS;
+#else
+ mask = POOF_TARGET_LINUX;
+#endif
+ }
+
+ uint8_t targets[3] = { POOF_TARGET_WIN32, POOF_TARGET_LINUX, POOF_TARGET_MACOS };
+ int target_count = 0;
+ for (int i = 0; i < 3; ++i) {
+ if (mask & targets[i]) target_count++;
+ }
+
+ bool multi_target = target_count > 1;
+ bool success = true;
+
+ for (int i = 0; i < 3; ++i) {
+ if (mask & targets[i]) {
+ if (!poof__cc_run_single(cc, targets[i], multi_target)) {
+ success = false;
+ }
+ }
+ }
+
+ poof_cc_free(cc);
+ return success;
+}
+
+
+extern bool
+poof_mkdir(const char *path)
+{
+#if defined(_WIN32)
+ return _mkdir(path) == 0 || errno == EEXIST;
+#else
+ return mkdir(path, 0755) == 0 || errno == EEXIST;
+#endif
+}
+
+extern bool
+poof_touch(const char *path)
+{
+ FILE *f = fopen(path, "a");
+ if (!f) return false;
+ fclose(f);
+ return true;
+}
+
+extern bool
+poof_rm(const char *path)
+{
+ return remove(path) == 0;
+}
+
+extern bool
+poof_rm_recursive(const char *path)
+{
+#if defined(_WIN32)
+ char cmd[512];
+ snprintf(cmd, sizeof(cmd), "rmdir /s /q \"%s\"", path);
+ return system(cmd) == 0;
+#else
+ char cmd[512];
+ snprintf(cmd, sizeof(cmd), "rm -rf \"%s\"", path);
+ return system(cmd) == 0;
+#endif
+}
+
+extern bool
+poof_copy_file(const char *src, const char *dst)
+{
+ FILE *in = fopen(src, "rb");
+ if (!in) return false;
+ FILE *out = fopen(dst, "wb");
+ if (!out) {
+ fclose(in);
+ return false;
+ }
+
+ char buffer[8192];
+ size_t bytes;
+ while ((bytes = fread(buffer, 1, sizeof(buffer), in)) > 0) {
+ fwrite(buffer, 1, bytes, out);
+ }
+
+ fclose(in);
+ fclose(out);
+ return true;
+}
+
+static time_t
+poof__get_mtime(const char *path)
+{
+ struct stat attr;
+ if (stat(path, &attr) != 0) return 0;
+ return attr.st_mtime;
+}
+
+extern bool
+poof_needs_rebuild(const char *target, const char **sources, size_t source_count)
+{
+ time_t target_mtime = poof__get_mtime(target);
+ if (target_mtime == 0) return true; // Target does not exist
+
+ for (size_t i = 0; i < source_count; ++i) {
+ time_t src_mtime = poof__get_mtime(sources[i]);
+ if (src_mtime > target_mtime) return true;
+ }
+ return false;
+}
+
+extern int
+poof_print(uint32_t col, const char *text, ...)
+{
+ uint8_t r = (col >> 16) & 0xFF;
+ uint8_t g = (col >> 8) & 0xFF;
+ uint8_t b = col & 0xFF;
+
+ printf("\033[38;2;%d;%d;%dm", r, g, b);
+
+ va_list args;
+ va_start(args, text);
+ int res = vprintf(text, args);
+ va_end(args);
+
+ printf("\033[0m");
+ fflush(stdout);
+ return res;
+}
+
+extern int
+poof_progress_bar(const char *label, float value, float min, float max, float width)
+{
+ float norm = (value - min) / (max - min);
+ if (norm < 0.0f) norm = 0.0f;
+ if (norm > 1.0f) norm = 1.0f;
+
+ int filled = (int)(norm * width);
+ int total = (int)width;
+
+ char bar[256];
+ int pos = 0;
+ for (int i = 0; i < total && pos < (int)sizeof(bar) - 1; ++i) {
+ if (i < filled) bar[pos++] = '|';
+ else bar[pos++] = ' ';
+ }
+ bar[pos] = '\0';
+
+ printf("\r[%s] [", label ? label : "PROGRESS");
+ poof_print(0xFE9900, "%s", bar);
+ printf("] %d/%d jobs", (int)value, (int)max);
+ if (norm >= 1.0f) printf("\n");
+ fflush(stdout);
+ return 0;
+}
+
+extern void
+poof_go_rebuild_urself_impl(int argc, char **argv, const char *source_file)
+{
+ const char *binary_file = argv[0];
+ const char *sources[] = { source_file, "Poof/poof.h" };
+
+ if (!poof_needs_rebuild(binary_file, sources, 2)) {
+ return;
+ }
+
+ char binary_old[4096];
+ snprintf(binary_old, sizeof(binary_old), "%s.old", binary_file);
+
+ poof_print(0xFF8800, "[POOF] Source changed. Rebuilding %s...\n", binary_file);
+
+ poof_rm(binary_old);
+ rename(binary_file, binary_old);
+
+ Poof_Cmd cmd = {0};
+ poof_cmd_append(&cmd, "gcc", "-o", binary_file, source_file, "-IPodium", "-IPoof");
+
+ if (!poof_cmd_run(&cmd)) {
+ poof_print(0xFF0000, "[POOF] Rebuild failed!\n");
+ rename(binary_old, binary_file);
+ exit(1);
+ }
+ poof_cmd_free(&cmd);
+
+ poof_print(0x00FF00, "[POOF] Rebuild successful! Re-launching binary...\n");
+
+ #if defined(_WIN32)
+ // Windows restart
+ int status = system(binary_file);
+ exit(status);
+ #else
+ execv(binary_file, argv);
+ perror("execv");
+ exit(1);
+ #endif
+}
+#endif
+
+/*
+------------------------------------------------------------------------------
+This software is available under 2 licenses -- choose whichever you prefer.
+------------------------------------------------------------------------------
+ALTERNATIVE A - MIT License
+Copyright (c) 2026 Vasco Alves
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+of the Software, and to permit persons to whom the Software is furnished to do
+so, subject to the following conditions:
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+------------------------------------------------------------------------------
+ALTERNATIVE B - Public Domain (www.unlicense.org)
+This is free and unencumbered software released into the public domain.
+Anyone is free to copy, modify, publish, use, compile, sell, or distribute this
+software, either in source code form or as a compiled binary, for any purpose,
+commercial or non-commercial, and by any means.
+In jurisdictions that recognize copyright laws, the author or authors of this
+software dedicate any and all copyright interest in the software to the public
+domain. We make this dedication for the benefit of the public at large and to
+the detriment of our heirs and successors. We intend this dedication to be an
+overt act of relinquishment in perpetuity of all present and future rights to
+this software under copyright law.
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+------------------------------------------------------------------------------
+*/
diff --git a/Rend/demos/rend_compute.c b/Rend/demos/rend_compute.c
new file mode 100644
index 0000000..7d5e407
--- /dev/null
+++ b/Rend/demos/rend_compute.c
@@ -0,0 +1,214 @@
+#include <string.h>
+
+#ifdef DEBUG_MEMORY
+#define malloc(size) p_debug_malloc_impl((size), __FILE__, __LINE__, __func__)
+#define realloc(ptr, size) p_debug_realloc_impl((ptr), (size), __FILE__, __LINE__, __func__)
+#define free(ptr) p_debug_free_impl((ptr), __FILE__, __LINE__, __func__)
+#endif
+
+#include "../rend.h"
+#include "../rend.c"
+#include <stddef.h>
+
+#define PODIUM_IMPLEMENTATION
+#define P_MODULE_MATH
+#define P_MODULE_VULKAN
+#include "podium.h"
+
+float delta = 0;
+P_Window win;
+P_Event ev;
+
+bool vsync = true;
+
+#define PARTICLE_COUNT 1024 * 10
+#define GRID_WIDTH 512
+#define GRID_HEIGHT 512
+
+typedef struct {
+ uint64_t particles;
+ uint64_t src_grid;
+ uint64_t dst_grid;
+ uint32_t particle_count;
+ uint32_t width;
+ uint32_t height;
+ float delta_time;
+ uint32_t render_mode;
+} PushConstants;
+
+typedef struct Particle {
+ float pos[2];
+ float vel[2];
+} Particle;
+
+uint32_t pcg_hash(uint32_t seed) {
+ uint32_t state = seed * 747796405u + 2891336453u;
+ uint32_t word = ((state >> ((state >> 28u) + 4u)) ^ state) * 277803737u;
+ return (word >> 22u) ^ word;
+}
+
+float cool_beans(uint32_t *seed) {
+ *seed = pcg_hash(*seed);
+ return (float) *seed / 4294967295.0;
+}
+
+int main() {
+
+ if (!p_window_open(&win, 800, 600, "demo")) {
+ PFATAL("Failed to open a window!");
+ return 1;
+ }
+
+ // bindless setup
+ RendBindingInfo bind_info = {0};
+ RendRenderer renderer = rend_renderer_create(&win, REND_BACKEND_AUTO, NULL, vsync, &bind_info);
+
+ unsigned long particles_bytes = 0;
+ uint8_t *particles_shader = p_file_alloc("particle.spv", &particles_bytes);
+
+ unsigned long sand_bytes = 0;
+ uint8_t *sand_shader = p_file_alloc("sand.spv", &sand_bytes);
+
+ unsigned long vert_size = 0;
+ uint8_t *vert = p_file_alloc("vert.spv", &vert_size);
+
+ unsigned long frag_size = 0;
+ uint8_t *frag = p_file_alloc("frag.spv", &frag_size);
+
+ uint32_t seed = 0xC0FFEE;
+
+ Particle *initial_particles = malloc(PARTICLE_COUNT * sizeof *initial_particles);
+ for (int i = 0; i < PARTICLE_COUNT; i++) {
+ initial_particles[i].pos[0] = cool_beans(&seed) * 2.0f - 1.0f;
+ initial_particles[i].pos[1] = cool_beans(&seed) * 2.0f - 1.0f;
+ initial_particles[i].vel[0] = cool_beans(&seed) * 0.4f - 0.2f;
+ initial_particles[i].vel[1] = cool_beans(&seed) * 0.4f - 0.2f;
+ }
+
+ size_t buffer_size = PARTICLE_COUNT * sizeof(Particle);
+ RendBuffer particle_buf = rend_buffer_create(renderer, buffer_size, REND_BUFFER_STORAGE, true);
+ rend_buffer_write(renderer, &particle_buf, initial_particles, buffer_size, 0);
+
+ size_t grid_buffer_size = GRID_WIDTH * GRID_HEIGHT * sizeof(uint32_t);
+ uint32_t *initial_grid = calloc(GRID_WIDTH * GRID_HEIGHT, sizeof(uint32_t));
+
+ for (int y = 0; y < 100; y++) {
+ for (int x = 150; x < 362; x++) {
+ initial_grid[y * GRID_WIDTH + x] = 1; // 1 = sand
+ }
+ }
+
+ RendBuffer src_buf = rend_buffer_create(renderer, GRID_WIDTH * GRID_HEIGHT * sizeof(uint32_t), REND_BUFFER_STORAGE, false);
+ RendBuffer dst_buf = rend_buffer_create(renderer, GRID_WIDTH * GRID_HEIGHT * sizeof(uint32_t), REND_BUFFER_STORAGE, false);
+ rend_buffer_write(renderer, &src_buf, initial_grid, grid_buffer_size, 0);
+ rend_buffer_write(renderer, &dst_buf, initial_grid, grid_buffer_size, 0);
+
+ uint64_t particles_address = rend_buffer_address(&particle_buf);
+
+ RendBuffer *src_grid = &src_buf;
+ RendBuffer *dst_grid = &dst_buf;
+
+ RendPushConstantInfo pc = { .offset = 0, .size = sizeof(PushConstants) };
+ RendPipeline particle_compute = rend_pipeline_create_compute_spirv(renderer, particles_shader, particles_bytes, &pc, 1);
+ RendPipeline sand_compute = rend_pipeline_create_compute_spirv(renderer, sand_shader, sand_bytes, &pc, 1);
+ free(particles_shader);
+ free(sand_shader);
+
+ RendPipeline graphics_pipeline = rend_pipeline_create_graphics_bindless_spirv(renderer, vert, vert_size, frag, frag_size, &pc, 1, REND_POLYGON_MODE_FILL, REND_CULL_MODE_NONE, REND_TOPOLOGY_TRIANGLE_LIST, 0, true);
+
+ free(vert);
+ free(frag);
+
+ float dt = 1.0f / 60.0f;
+ uint64_t dt_ns = (uint64_t) (dt * NANOS_PER_SEC);
+
+ uint32_t mode = 2;
+ while (mode > 0) {
+
+ uint64_t start = p_get_time();
+
+ P_Event ev;
+ while (p_window_poll_event(&win, &ev)) {
+ if (ev.type == P_EVENT_WINDOW_CLOSE) {
+ mode -= 1;
+ break;
+ }
+ }
+
+ if (rend_renderer_frame_begin(renderer)) {
+
+ PushConstants pc = {0};
+
+ if (mode == 2) {
+ /*
+ * Sand Simulation
+ */
+ pc.delta_time = dt;
+ pc.width = GRID_WIDTH;
+ pc.height = GRID_HEIGHT;
+ pc.render_mode = 1;
+ pc.src_grid = src_grid->gpu_address;
+ pc.dst_grid = dst_grid->gpu_address;
+
+ rend_pipeline_bind(sand_compute);
+ rend_pipeline_push_constants(sand_compute, &pc, sizeof(pc));
+
+ uint32_t x = (GRID_WIDTH + 15) / 16;
+ uint32_t y = (GRID_HEIGHT + 15) / 16;
+ rend_pipeline_dispatch(sand_compute, x, y, 1);
+
+ RendBuffer *temp = src_grid;
+ src_grid = dst_grid;
+ dst_grid = temp;
+
+ memset(src_grid->mapped_memory, 0, grid_buffer_size);
+
+ } else {
+ /*
+ * Particles Simulation
+ */
+ pc.particles = particles_address;
+ pc.delta_time = dt;
+ pc.particle_count = PARTICLE_COUNT;
+ pc.render_mode = 0;
+
+ rend_pipeline_bind(particle_compute);
+ rend_pipeline_push_constants(particle_compute, &pc, sizeof(pc));
+ rend_pipeline_dispatch(particle_compute, (PARTICLE_COUNT + 255) / 256, 1, 1);
+ }
+
+ rend_renderer_render_pass_begin(renderer, 0.5f, 0.5f, 0.5f, 0.0f); {
+ rend_pipeline_bind(graphics_pipeline);
+ rend_pipeline_push_constants(graphics_pipeline, &pc, sizeof(pc));
+
+ uint32_t vertex_count = (mode == 2) ? (6 * GRID_WIDTH * GRID_HEIGHT) : (6 * PARTICLE_COUNT);
+ rend_pipeline_draw(graphics_pipeline, vertex_count, 1);
+
+ } rend_renderer_render_pass_end(renderer);
+
+ rend_renderer_frame_end(renderer, NULL);
+ }
+
+ uint64_t delta_ns = p_get_time() - start;
+ if (delta_ns < dt_ns) {
+ p_sleep_ns(dt_ns - delta_ns);
+ }
+ }
+
+ free(initial_particles);
+ free(initial_grid);
+
+ rend_buffer_destroy(&particle_buf);
+ rend_buffer_destroy(&src_buf);
+ rend_buffer_destroy(&dst_buf);
+
+ rend_renderer_destroy(renderer);
+ rend_quit();
+
+ p_window_close(&win);
+
+#if DEBUG_MEMORY
+ p_debug_memory_report();
+#endif
+ return 0;
+}
diff --git a/Rend/demos/rend_compute.slang b/Rend/demos/rend_compute.slang
new file mode 100644
index 0000000..5fb124b
--- /dev/null
+++ b/Rend/demos/rend_compute.slang
@@ -0,0 +1,146 @@
+struct Particle {
+ float2 position;
+ float2 velocity;
+};
+
+struct PushConstants {
+ Particle* particles;
+ uint* srcGrid;
+ uint* dstGrid;
+ uint particleCount;
+ uint width;
+ uint height;
+ float deltaTime;
+ uint renderMode; // 0 = particles, 1 = sand
+};
+
+struct VSOutput {
+ float4 position : SV_Position;
+ float4 color : COLOR0;
+};
+
+[[vk::push_constant]]
+PushConstants pc;
+
+uint getIndex(uint x, uint y) {
+ return y * pc.width + x;
+}
+
+bool isEmpty(uint x, uint y) {
+ if (x >= pc.width || y >= pc.height) return false;
+ return pc.srcGrid[getIndex(x, y)] == 0;
+}
+
+[shader("compute")]
+[numthreads(256, 1, 1)]
+void particleMain(uint3 threadId : SV_DispatchThreadID) {
+ uint index = threadId.x;
+ if (index >= pc.particleCount) return;
+
+ Particle p = pc.particles[index];
+
+ p.position += p.velocity * pc.deltaTime;
+ p.velocity *= exp(-0.005 * pc.deltaTime);
+
+ pc.particles[index] = p;
+}
+
+[shader("compute")]
+[numthreads(16, 16, 1)]
+void sandMain(uint3 threadId : SV_DispatchThreadID) {
+ uint x = threadId.x;
+ uint y = threadId.y;
+
+ if (x >= pc.width || y >= pc.height) return;
+
+ uint currentIdx = getIndex(x, y);
+ uint cellState = pc.srcGrid[currentIdx];
+
+ if (cellState == 1) { // Sand
+ if (y + 1 < pc.height && isEmpty(x, y + 1)) {
+ pc.dstGrid[getIndex(x, y + 1)] = 1;
+ pc.dstGrid[currentIdx] = 0;
+ return;
+ }
+
+ bool fallLeftFirst = ((x + y) % 2) == 0;
+ int dir1 = fallLeftFirst ? -1 : 1;
+ int dir2 = fallLeftFirst ? 1 : -1;
+
+ if (y + 1 < pc.height && isEmpty(x + dir1, y + 1)) {
+ pc.dstGrid[getIndex(x + dir1, y + 1)] = 1;
+ pc.dstGrid[currentIdx] = 0;
+ return;
+ }
+ else if (y + 1 < pc.height && isEmpty(x + dir2, y + 1)) {
+ pc.dstGrid[getIndex(x + dir2, y + 1)] = 1;
+ pc.dstGrid[currentIdx] = 0;
+ return;
+ }
+
+ pc.dstGrid[currentIdx] = 1;
+ }
+}
+
+static const float2 QUAD_OFFSETS[6] = {
+ float2(-0.5, -0.5), float2( 0.5, -0.5), float2(-0.5, 0.5),
+ float2(-0.5, 0.5), float2( 0.5, -0.5), float2( 0.5, 0.5)
+};
+
+float3 cosinePalette(float t, float3 a, float3 b, float3 c, float3 d) {
+ return a + b * cos(6.28318 * (c * t + d));
+}
+
+[shader("vertex")]
+VSOutput vertMain(uint vertexID : SV_VertexID) {
+ VSOutput output;
+
+ uint elementIdx = vertexID / 6;
+ uint cornerIdx = vertexID % 6;
+
+ float2 worldPos = float2(0.0, 0.0);
+ float3 color = float3(0.0, 0.0, 0.0);
+
+ if (pc.renderMode == 0) {
+ Particle p = pc.particles[elementIdx];
+ worldPos = p.position;
+
+ float speed = length(p.velocity);
+ color = cosinePalette(
+ speed * 0.8,
+ float3(0.5, 0.5, 0.5),
+ float3(0.5, 0.5, 0.5),
+ float3(1.0, 1.0, 1.0),
+ float3(0.0, 0.33, 0.67)
+ );
+ }
+
+ else {
+ uint x = elementIdx % pc.width;
+ uint y = elementIdx / pc.width;
+
+ uint cellState = pc.srcGrid[elementIdx];
+
+ if (cellState == 0) {
+ output.position = float4(0, 0, 0, 0);
+ output.color = float4(0, 0, 0, 0);
+ return output;
+ }
+
+ worldPos.x = ((float)x / (float)pc.width) * 2.0 - 1.0;
+ worldPos.y = ((float)y / (float)pc.height) * 2.0 - 1.0;
+
+ color = float3(0.94, 0.82, 0.53);
+ }
+
+ float2 quadOffset = QUAD_OFFSETS[cornerIdx] * 0.01;
+ output.position = float4(worldPos + quadOffset, 0.0, 1.0);
+ output.color = float4(color, 1.0);
+
+ return output;
+}
+
+[shader("fragment")]
+float4 fragMain(VSOutput input) : SV_Target {
+ return input.color;
+}
diff --git a/Rend/demos/rend_teapot.c b/Rend/demos/rend_teapot.c
new file mode 100644
index 0000000..63f96ee
--- /dev/null
+++ b/Rend/demos/rend_teapot.c
@@ -0,0 +1,172 @@
+
+#include "teapot.h"
+
+#include "../rend.h"
+#include "../rend.c"
+#include <stddef.h>
+
+#define PODIUM_IMPLEMENTATION
+#define P_MODULE_MATH
+#define P_MODULE_VULKAN
+#include "podium.h"
+
+int main() {
+
+ const char *texture_path = "wal.jpg";
+ if (!p_file_exists(texture_path)) {
+ texture_path = "demos/wal.jpg";
+ }
+ typedef struct CoolPushConstants {
+ P_Mat4 MVP;
+ } CoolPushConstants;
+
+ typedef struct CoolVertex {
+ float pos[3];
+ float uv[2];
+ } CoolVertex;
+
+ CoolVertex cool_array[TEAPOT_VERTEX_COUNT];
+
+ for (uint32_t i = 0; i < TEAPOT_VERTEX_COUNT; ++i) {
+ cool_array[i].pos[0] = teapot_positions[i][0];
+ cool_array[i].pos[1] = teapot_positions[i][1];
+ cool_array[i].pos[2] = teapot_positions[i][2];
+
+ float u = teapot_positions[i][0] / teapot_positions[i][2];
+ float v = teapot_positions[i][1] / teapot_positions[i][2];
+
+ cool_array[i].uv[0] = u;
+ cool_array[i].uv[1] = v;
+ }
+
+ size_t vert_size = TEAPOT_VERTEX_COUNT * sizeof *cool_array;
+ size_t ind_size = TEAPOT_INDEX_COUNT * sizeof *teapot_indices;
+
+ RendBuffer vert_buf = rend_buffer_create(renderer, vert_size, REND_BUFFER_VERTEX, true);
+ RendBuffer ind_buf = rend_buffer_create(renderer, ind_size, REND_BUFFER_INDEX, true);
+ rend_buffer_write(renderer, &vert_buf, cool_array, vert_size, 0);
+ rend_buffer_write(renderer, &ind_buf, teapot_indices, ind_size, 0);
+
+ int tex_w, tex_h, tex_channels;
+ unsigned char *pixels = stbi_load(texture_path, &tex_w, &tex_h, &tex_channels, 4);
+ RendTexture texture = rend_texture_create(renderer, tex_w, tex_h, 1, 0, 1, REND_FORMAT_R8G8B8A8_SRGB);
+ if (pixels) {
+ rend_texture_copy_data(renderer, &texture, pixels, (size_t)tex_w * tex_h * 4);
+ stbi_image_free(pixels);
+ }
+
+ RendPipeline basic_pipeline = rend_pipeline_create_graphics_spirv(
+ renderer,
+ basic_vert, basic_vert_bytes,
+ basic_frag, basic_frag_bytes,
+ &(RendVertexBinding){ .binding = 0, .stride = sizeof(CoolVertex), .input_rate = REND_INPUT_RATE_VERTEX }, 1,
+ (RendVertexAttributes[]){
+ { .binding = 0, .location = 0, .format = REND_FORMAT_3_SFLOAT32, .offset = offsetof(CoolVertex, pos) },
+ { .binding = 0, .location = 1, .format = REND_FORMAT_2_SFLOAT32, .offset = offsetof(CoolVertex, uv) }
+ }, 2,
+ &(RendPushConstantInfo){ .offset = 0, .size = sizeof(CoolPushConstants) }, 1,
+ REND_POLYGON_MODE_FILL,
+ REND_CULL_MODE_NONE,
+ REND_TOPOLOGY_TRIANGLE_STRIP,
+ REND_FORMAT_UNDEFINED,
+ true
+ );
+
+ P_Mat4 view = p_mat4_translate((Vec3f){0.0f, 0.0f, -3.0f});
+ P_Mat4 proj = p_mat4_perspective(P_PI_HALF, 800.0f / 600.0f, 0.1f, 100.0f);
+ proj.m[1 * 4 + 1] *= -1.0f; /* Vulkan clip space Y inversion fix */
+
+ bool running = true;
+ uint64_t frame_count = 0;
+ float angle = 0;
+
+ bool pointer_down = false;
+ uint32_t last_pointer_x = 0;
+ uint32_t last_pointer_y = 0;
+
+ uint16_t frames = 3;
+ while (running) {
+
+ P_Event ev;
+ while (p_window_poll_event(win, &ev)) {
+ if (ev.type == P_EVENT_WINDOW_CLOSE) {
+ running = false;
+ break;
+ }
+ if (ev.type == P_EVENT_KEY_DOWN) {
+ switch (ev.key.key) {
+ case P_KEY_W:
+ view = p_mat4_translate_by(view, (Vec3f){0.0f, 0.0f, 0.1f});
+ break;
+ case P_KEY_S:
+ view = p_mat4_translate_by(view, (Vec3f){0.0f, 0.0f, -0.1f});
+ break;
+ case P_KEY_A:
+ view = p_mat4_translate_by(view, (Vec3f){0.1f, 0.0f, 0.0f});
+ break;
+ case P_KEY_D:
+ view = p_mat4_translate_by(view, (Vec3f){-0.1f, 0.0f, 0.0f});
+ break;
+
+ }
+ break;
+ }
+ if (ev.type == P_EVENT_POINTER) {
+ if (ev.pointer.state == P_POINTER_PRESSED && ev.pointer.button == 1) {
+ pointer_down = true;
+ last_pointer_x = ev.pointer.x;
+ last_pointer_y = ev.pointer.y;
+ } else if (ev.pointer.state == P_POINTER_RELEASED && ev.pointer.button == 1) {
+ pointer_down = false;
+ } else if (ev.pointer.state == P_POINTER_MOVED) {
+ if (pointer_down) {
+ float dx = (float)((int)ev.pointer.x - (int)last_pointer_x);
+ float dy = (float)((int)ev.pointer.y - (int)last_pointer_y);
+
+ float sensitivity = 0.005f;
+ float yaw = dx * sensitivity;
+ float pitch = dy * sensitivity;
+
+ view = p_mat4_rotate_y_by(view, yaw);
+ view = p_mat4_mul(p_mat4_rotate_x(pitch), view);
+
+ last_pointer_x = ev.pointer.x;
+ last_pointer_y = ev.pointer.y;
+ }
+ }
+ }
+ }
+
+ angle += 0.05;
+
+ P_Mat4 model = p_mat4_identity();
+ model = p_mat4_rotate_y_by(model, angle * 0.5f);
+
+ P_Mat4 mvp = p_mat4_mul(proj, p_mat4_mul(view, model));
+
+ CoolPushConstants pc = {
+ .MVP = mvp,
+ };
+
+ if (rend_renderer_frame_begin(renderer)) {
+
+ rend_renderer_render_pass_begin(renderer, 0.5, 0.5, 0.5, 0.0); {
+ rend_pipeline_bind(basic_pipeline);
+ rend_pipeline_push_constants(basic_pipeline, &pc, sizeof pc);
+ rend_pipeline_bind_texture(basic_pipeline, &texture, 1, 0);
+ rend_pipeline_bind_vertex_buffer(basic_pipeline, 0, vert_buf, 0);
+ rend_pipeline_bind_index_buffer(basic_pipeline, ind_buf, 0, REND_INDEX_UINT16);
+ rend_pipeline_draw_indexed(basic_pipeline, TEAPOT_INDEX_COUNT, 0, 0, 1);
+ } rend_renderer_render_pass_end(renderer);
+
+ rend_renderer_frame_end(renderer, NULL);
+ }
+
+ }
+
+ rend_texture_destroy(renderer, &texture);
+ rend_buffer_destroy(&vert_buf);
+ rend_buffer_destroy(&ind_buf);
+
+ return 0;
+}
diff --git a/Rend/demos/teapot.h b/Rend/demos/teapot.h
new file mode 100644
index 0000000..dfde9be
--- /dev/null
+++ b/Rend/demos/teapot.h
@@ -0,0 +1,17273 @@
+#ifndef TEAPOT_H
+#define TEAPOT_H
+
+#include <stdint.h>
+
+#define TEAPOT_VERTEX_COUNT 3644
+#define TEAPOT_INDEX_COUNT 18960
+
+static const float teapot_positions[TEAPOT_VERTEX_COUNT][3] = {
+ {1.368074f, 2.435437f, -0.227403f},
+ {1.381968f, 2.400000f, -0.229712f},
+ {1.400000f, 2.400000f, 0.000000f},
+ {1.385925f, 2.435437f, 0.000000f},
+ {1.316296f, 2.435437f, -0.442166f},
+ {1.329664f, 2.400000f, -0.446656f},
+ {1.233252f, 2.435437f, -0.641628f},
+ {1.245776f, 2.400000f, -0.648144f},
+ {1.121601f, 2.435437f, -0.823129f},
+ {1.132992f, 2.400000f, -0.831488f},
+ {0.984007f, 2.435437f, -0.984007f},
+ {0.994000f, 2.400000f, -0.994000f},
+ {0.823129f, 2.435437f, -1.121601f},
+ {0.831488f, 2.400000f, -1.132992f},
+ {0.641628f, 2.435437f, -1.233252f},
+ {0.648144f, 2.400000f, -1.245776f},
+ {0.442166f, 2.435437f, -1.316296f},
+ {0.446656f, 2.400000f, -1.329664f},
+ {0.227403f, 2.435437f, -1.368074f},
+ {0.229712f, 2.400000f, -1.381968f},
+ {-0.000000f, 2.435437f, -1.385925f},
+ {0.000000f, 2.400000f, -1.400000f},
+ {1.362620f, 2.463000f, -0.226496f},
+ {1.380400f, 2.463000f, 0.000000f},
+ {1.311049f, 2.463000f, -0.440403f},
+ {1.228335f, 2.463000f, -0.639070f},
+ {1.117130f, 2.463000f, -0.819847f},
+ {0.980084f, 2.463000f, -0.980084f},
+ {0.819847f, 2.463000f, -1.117130f},
+ {0.639070f, 2.463000f, -1.228335f},
+ {0.440403f, 2.463000f, -1.311049f},
+ {0.226496f, 2.463000f, -1.362620f},
+ {-0.000000f, 2.463000f, -1.380400f},
+ {1.364422f, 2.482687f, -0.226795f},
+ {1.382225f, 2.482687f, 0.000000f},
+ {1.312782f, 2.482687f, -0.440985f},
+ {1.229959f, 2.482687f, -0.639915f},
+ {1.118607f, 2.482687f, -0.820931f},
+ {0.981380f, 2.482687f, -0.981380f},
+ {0.820931f, 2.482687f, -1.118607f},
+ {0.639915f, 2.482687f, -1.229959f},
+ {0.440985f, 2.482687f, -1.312782f},
+ {0.226795f, 2.482687f, -1.364422f},
+ {0.000000f, 2.482687f, -1.382225f},
+ {1.372294f, 2.494500f, -0.228104f},
+ {1.390200f, 2.494500f, 0.000000f},
+ {1.320356f, 2.494500f, -0.443529f},
+ {1.237056f, 2.494500f, -0.643607f},
+ {1.125061f, 2.494500f, -0.825668f},
+ {0.987042f, 2.494500f, -0.987042f},
+ {0.825668f, 2.494500f, -1.125061f},
+ {0.643607f, 2.494500f, -1.237056f},
+ {0.443529f, 2.494500f, -1.320356f},
+ {0.228104f, 2.494500f, -1.372294f},
+ {-0.000000f, 2.494500f, -1.390200f},
+ {1.385053f, 2.498438f, -0.230225f},
+ {1.403125f, 2.498438f, 0.000000f},
+ {1.332632f, 2.498438f, -0.447653f},
+ {1.248557f, 2.498438f, -0.649591f},
+ {1.135521f, 2.498438f, -0.833344f},
+ {0.996219f, 2.498438f, -0.996219f},
+ {0.833344f, 2.498438f, -1.135521f},
+ {0.649591f, 2.498438f, -1.248557f},
+ {0.447653f, 2.498438f, -1.332632f},
+ {0.230225f, 2.498438f, -1.385053f},
+ {0.000000f, 2.498438f, -1.403125f},
+ {1.401513f, 2.494500f, -0.232961f},
+ {1.419800f, 2.494500f, 0.000000f},
+ {1.348469f, 2.494500f, -0.452973f},
+ {1.263395f, 2.494500f, -0.657311f},
+ {1.149016f, 2.494500f, -0.843248f},
+ {1.008058f, 2.494500f, -1.008058f},
+ {0.843248f, 2.494500f, -1.149016f},
+ {0.657311f, 2.494500f, -1.263395f},
+ {0.452973f, 2.494500f, -1.348469f},
+ {0.232961f, 2.494500f, -1.401513f},
+ {-0.000000f, 2.494500f, -1.419800f},
+ {1.420490f, 2.482687f, -0.236115f},
+ {1.439025f, 2.482687f, 0.000000f},
+ {1.366728f, 2.482687f, -0.459107f},
+ {1.280502f, 2.482687f, -0.666211f},
+ {1.164574f, 2.482687f, -0.854666f},
+ {1.021708f, 2.482687f, -1.021708f},
+ {0.854666f, 2.482687f, -1.164574f},
+ {0.666211f, 2.482687f, -1.280502f},
+ {0.459107f, 2.482687f, -1.366728f},
+ {0.236115f, 2.482687f, -1.420490f},
+ {0.000000f, 2.482687f, -1.439025f},
+ {1.440800f, 2.463000f, -0.239491f},
+ {1.459600f, 2.463000f, 0.000000f},
+ {1.386270f, 2.463000f, -0.465671f},
+ {1.298810f, 2.463000f, -0.675736f},
+ {1.181225f, 2.463000f, -0.866886f},
+ {1.036316f, 2.463000f, -1.036316f},
+ {0.866886f, 2.463000f, -1.181225f},
+ {0.675736f, 2.463000f, -1.298810f},
+ {0.465671f, 2.463000f, -1.386270f},
+ {0.239491f, 2.463000f, -1.440800f},
+ {-0.000000f, 2.463000f, -1.459600f},
+ {1.461258f, 2.435437f, -0.242892f},
+ {1.480325f, 2.435437f, 0.000000f},
+ {1.405953f, 2.435437f, -0.472283f},
+ {1.317252f, 2.435437f, -0.685331f},
+ {1.197997f, 2.435437f, -0.879195f},
+ {1.051031f, 2.435437f, -1.051031f},
+ {0.879195f, 2.435437f, -1.197997f},
+ {0.685331f, 2.435437f, -1.317252f},
+ {0.472283f, 2.435437f, -1.405953f},
+ {0.242892f, 2.435437f, -1.461258f},
+ {-0.000000f, 2.435437f, -1.480325f},
+ {1.480680f, 2.400000f, -0.246120f},
+ {1.500000f, 2.400000f, 0.000000f},
+ {1.424640f, 2.400000f, -0.478560f},
+ {1.334760f, 2.400000f, -0.694440f},
+ {1.213920f, 2.400000f, -0.890880f},
+ {1.065000f, 2.400000f, -1.065000f},
+ {0.890880f, 2.400000f, -1.213920f},
+ {0.694440f, 2.400000f, -1.334760f},
+ {0.478560f, 2.400000f, -1.424640f},
+ {0.246120f, 2.400000f, -1.480680f},
+ {0.000000f, 2.400000f, -1.500000f},
+ {-0.227403f, 2.435437f, -1.368074f},
+ {-0.229712f, 2.400000f, -1.381968f},
+ {0.000000f, 2.400000f, -1.400000f},
+ {0.000000f, 2.435437f, -1.385925f},
+ {-0.442166f, 2.435437f, -1.316296f},
+ {-0.446656f, 2.400000f, -1.329664f},
+ {-0.641628f, 2.435437f, -1.233252f},
+ {-0.648144f, 2.400000f, -1.245776f},
+ {-0.823129f, 2.435437f, -1.121601f},
+ {-0.831488f, 2.400000f, -1.132992f},
+ {-0.984007f, 2.435437f, -0.984007f},
+ {-0.994000f, 2.400000f, -0.994000f},
+ {-1.121601f, 2.435437f, -0.823129f},
+ {-1.132992f, 2.400000f, -0.831488f},
+ {-1.233252f, 2.435437f, -0.641628f},
+ {-1.245776f, 2.400000f, -0.648144f},
+ {-1.316296f, 2.435437f, -0.442166f},
+ {-1.329664f, 2.400000f, -0.446656f},
+ {-1.368074f, 2.435437f, -0.227403f},
+ {-1.381968f, 2.400000f, -0.229712f},
+ {-1.385925f, 2.435437f, 0.000000f},
+ {-1.400000f, 2.400000f, 0.000000f},
+ {-0.226496f, 2.463000f, -1.362620f},
+ {0.000000f, 2.463000f, -1.380400f},
+ {-0.440403f, 2.463000f, -1.311049f},
+ {-0.639070f, 2.463000f, -1.228335f},
+ {-0.819847f, 2.463000f, -1.117130f},
+ {-0.980084f, 2.463000f, -0.980084f},
+ {-1.117130f, 2.463000f, -0.819847f},
+ {-1.228335f, 2.463000f, -0.639070f},
+ {-1.311049f, 2.463000f, -0.440403f},
+ {-1.362620f, 2.463000f, -0.226496f},
+ {-1.380400f, 2.463000f, 0.000000f},
+ {-0.226795f, 2.482687f, -1.364422f},
+ {0.000000f, 2.482687f, -1.382225f},
+ {-0.440985f, 2.482687f, -1.312782f},
+ {-0.639915f, 2.482687f, -1.229959f},
+ {-0.820931f, 2.482687f, -1.118607f},
+ {-0.981380f, 2.482687f, -0.981380f},
+ {-1.118607f, 2.482687f, -0.820931f},
+ {-1.229959f, 2.482687f, -0.639915f},
+ {-1.312782f, 2.482687f, -0.440985f},
+ {-1.364422f, 2.482687f, -0.226795f},
+ {-1.382225f, 2.482687f, -0.000000f},
+ {-0.228104f, 2.494500f, -1.372294f},
+ {0.000000f, 2.494500f, -1.390200f},
+ {-0.443529f, 2.494500f, -1.320356f},
+ {-0.643607f, 2.494500f, -1.237056f},
+ {-0.825668f, 2.494500f, -1.125061f},
+ {-0.987042f, 2.494500f, -0.987042f},
+ {-1.125061f, 2.494500f, -0.825668f},
+ {-1.237056f, 2.494500f, -0.643607f},
+ {-1.320356f, 2.494500f, -0.443529f},
+ {-1.372294f, 2.494500f, -0.228104f},
+ {-1.390200f, 2.494500f, 0.000000f},
+ {-0.230225f, 2.498438f, -1.385053f},
+ {0.000000f, 2.498438f, -1.403125f},
+ {-0.447653f, 2.498438f, -1.332632f},
+ {-0.649591f, 2.498438f, -1.248557f},
+ {-0.833344f, 2.498438f, -1.135521f},
+ {-0.996219f, 2.498438f, -0.996219f},
+ {-1.135521f, 2.498438f, -0.833344f},
+ {-1.248557f, 2.498438f, -0.649591f},
+ {-1.332632f, 2.498438f, -0.447653f},
+ {-1.385053f, 2.498438f, -0.230225f},
+ {-1.403125f, 2.498438f, 0.000000f},
+ {-0.232961f, 2.494500f, -1.401513f},
+ {0.000000f, 2.494500f, -1.419800f},
+ {-0.452973f, 2.494500f, -1.348469f},
+ {-0.657311f, 2.494500f, -1.263395f},
+ {-0.843248f, 2.494500f, -1.149016f},
+ {-1.008058f, 2.494500f, -1.008058f},
+ {-1.149016f, 2.494500f, -0.843248f},
+ {-1.263395f, 2.494500f, -0.657311f},
+ {-1.348469f, 2.494500f, -0.452973f},
+ {-1.401513f, 2.494500f, -0.232961f},
+ {-1.419800f, 2.494500f, 0.000000f},
+ {-0.236115f, 2.482687f, -1.420490f},
+ {-0.459107f, 2.482687f, -1.366728f},
+ {-0.666211f, 2.482687f, -1.280502f},
+ {-0.854666f, 2.482687f, -1.164574f},
+ {-1.021708f, 2.482687f, -1.021708f},
+ {-1.164574f, 2.482687f, -0.854666f},
+ {-1.280502f, 2.482687f, -0.666211f},
+ {-1.366728f, 2.482687f, -0.459107f},
+ {-1.420490f, 2.482687f, -0.236115f},
+ {-1.439025f, 2.482687f, 0.000000f},
+ {-0.239491f, 2.463000f, -1.440800f},
+ {0.000000f, 2.463000f, -1.459600f},
+ {-0.465671f, 2.463000f, -1.386270f},
+ {-0.675736f, 2.463000f, -1.298810f},
+ {-0.866886f, 2.463000f, -1.181225f},
+ {-1.036316f, 2.463000f, -1.036316f},
+ {-1.181225f, 2.463000f, -0.866886f},
+ {-1.298810f, 2.463000f, -0.675736f},
+ {-1.386270f, 2.463000f, -0.465671f},
+ {-1.440800f, 2.463000f, -0.239491f},
+ {-1.459600f, 2.463000f, 0.000000f},
+ {-0.242892f, 2.435437f, -1.461258f},
+ {0.000000f, 2.435437f, -1.480325f},
+ {-0.472283f, 2.435437f, -1.405953f},
+ {-0.685331f, 2.435437f, -1.317252f},
+ {-0.879195f, 2.435437f, -1.197997f},
+ {-1.051031f, 2.435437f, -1.051031f},
+ {-1.197997f, 2.435437f, -0.879195f},
+ {-1.317252f, 2.435437f, -0.685331f},
+ {-1.405953f, 2.435437f, -0.472283f},
+ {-1.461258f, 2.435437f, -0.242892f},
+ {-1.480325f, 2.435437f, 0.000000f},
+ {-0.246120f, 2.400000f, -1.480680f},
+ {0.000000f, 2.400000f, -1.500000f},
+ {-0.478560f, 2.400000f, -1.424640f},
+ {-0.694440f, 2.400000f, -1.334760f},
+ {-0.890880f, 2.400000f, -1.213920f},
+ {-1.065000f, 2.400000f, -1.065000f},
+ {-1.213920f, 2.400000f, -0.890880f},
+ {-1.334760f, 2.400000f, -0.694440f},
+ {-1.424640f, 2.400000f, -0.478560f},
+ {-1.480680f, 2.400000f, -0.246120f},
+ {-1.500000f, 2.400000f, 0.000000f},
+ {-1.368074f, 2.435437f, 0.227403f},
+ {-1.381968f, 2.400000f, 0.229712f},
+ {-1.400000f, 2.400000f, 0.000000f},
+ {-1.385925f, 2.435437f, 0.000000f},
+ {-1.316296f, 2.435437f, 0.442166f},
+ {-1.329664f, 2.400000f, 0.446656f},
+ {-1.233252f, 2.435437f, 0.641628f},
+ {-1.245776f, 2.400000f, 0.648144f},
+ {-1.121601f, 2.435437f, 0.823129f},
+ {-1.132992f, 2.400000f, 0.831488f},
+ {-0.984007f, 2.435437f, 0.984007f},
+ {-0.994000f, 2.400000f, 0.994000f},
+ {-0.823129f, 2.435437f, 1.121601f},
+ {-0.831488f, 2.400000f, 1.132992f},
+ {-0.641628f, 2.435437f, 1.233252f},
+ {-0.648144f, 2.400000f, 1.245776f},
+ {-0.442166f, 2.435437f, 1.316296f},
+ {-0.446656f, 2.400000f, 1.329664f},
+ {-0.227403f, 2.435437f, 1.368074f},
+ {-0.229712f, 2.400000f, 1.381968f},
+ {0.000000f, 2.435437f, 1.385925f},
+ {0.000000f, 2.400000f, 1.400000f},
+ {-1.362620f, 2.463000f, 0.226496f},
+ {-1.380400f, 2.463000f, 0.000000f},
+ {-1.311049f, 2.463000f, 0.440403f},
+ {-1.228335f, 2.463000f, 0.639070f},
+ {-1.117130f, 2.463000f, 0.819847f},
+ {-0.980084f, 2.463000f, 0.980084f},
+ {-0.819847f, 2.463000f, 1.117130f},
+ {-0.639070f, 2.463000f, 1.228335f},
+ {-0.440403f, 2.463000f, 1.311049f},
+ {-0.226496f, 2.463000f, 1.362620f},
+ {0.000000f, 2.463000f, 1.380400f},
+ {-1.364422f, 2.482687f, 0.226795f},
+ {-1.382225f, 2.482687f, 0.000000f},
+ {-1.312782f, 2.482687f, 0.440985f},
+ {-1.229959f, 2.482687f, 0.639915f},
+ {-1.118607f, 2.482687f, 0.820931f},
+ {-0.981380f, 2.482687f, 0.981380f},
+ {-0.820931f, 2.482687f, 1.118607f},
+ {-0.639915f, 2.482687f, 1.229959f},
+ {-0.440985f, 2.482687f, 1.312782f},
+ {-0.226795f, 2.482687f, 1.364422f},
+ {-0.000000f, 2.482687f, 1.382225f},
+ {-1.372294f, 2.494500f, 0.228104f},
+ {-1.390200f, 2.494500f, 0.000000f},
+ {-1.320356f, 2.494500f, 0.443529f},
+ {-1.237056f, 2.494500f, 0.643607f},
+ {-1.125061f, 2.494500f, 0.825668f},
+ {-0.987042f, 2.494500f, 0.987042f},
+ {-0.825668f, 2.494500f, 1.125061f},
+ {-0.643607f, 2.494500f, 1.237056f},
+ {-0.443529f, 2.494500f, 1.320356f},
+ {-0.228104f, 2.494500f, 1.372294f},
+ {0.000000f, 2.494500f, 1.390200f},
+ {-1.385053f, 2.498438f, 0.230225f},
+ {-1.403125f, 2.498438f, 0.000000f},
+ {-1.332632f, 2.498438f, 0.447653f},
+ {-1.248557f, 2.498438f, 0.649591f},
+ {-1.135521f, 2.498438f, 0.833344f},
+ {-0.996219f, 2.498438f, 0.996219f},
+ {-0.833344f, 2.498438f, 1.135521f},
+ {-0.649591f, 2.498438f, 1.248557f},
+ {-0.447653f, 2.498438f, 1.332632f},
+ {-0.230225f, 2.498438f, 1.385053f},
+ {0.000000f, 2.498438f, 1.403125f},
+ {-1.401513f, 2.494500f, 0.232961f},
+ {-1.419800f, 2.494500f, 0.000000f},
+ {-1.348469f, 2.494500f, 0.452973f},
+ {-1.263395f, 2.494500f, 0.657311f},
+ {-1.149016f, 2.494500f, 0.843248f},
+ {-1.008058f, 2.494500f, 1.008058f},
+ {-0.843248f, 2.494500f, 1.149016f},
+ {-0.657311f, 2.494500f, 1.263395f},
+ {-0.452973f, 2.494500f, 1.348469f},
+ {-0.232961f, 2.494500f, 1.401513f},
+ {0.000000f, 2.494500f, 1.419800f},
+ {-1.420490f, 2.482687f, 0.236115f},
+ {-1.366728f, 2.482687f, 0.459107f},
+ {-1.280502f, 2.482687f, 0.666211f},
+ {-1.164574f, 2.482687f, 0.854666f},
+ {-1.021708f, 2.482687f, 1.021708f},
+ {-0.854666f, 2.482687f, 1.164574f},
+ {-0.666211f, 2.482687f, 1.280502f},
+ {-0.459107f, 2.482687f, 1.366728f},
+ {-0.236115f, 2.482687f, 1.420490f},
+ {0.000000f, 2.482687f, 1.439025f},
+ {-1.440800f, 2.463000f, 0.239491f},
+ {-1.459600f, 2.463000f, 0.000000f},
+ {-1.386270f, 2.463000f, 0.465671f},
+ {-1.298810f, 2.463000f, 0.675736f},
+ {-1.181225f, 2.463000f, 0.866886f},
+ {-1.036316f, 2.463000f, 1.036316f},
+ {-0.866886f, 2.463000f, 1.181225f},
+ {-0.675736f, 2.463000f, 1.298810f},
+ {-0.465671f, 2.463000f, 1.386270f},
+ {-0.239491f, 2.463000f, 1.440800f},
+ {0.000000f, 2.463000f, 1.459600f},
+ {-1.461258f, 2.435437f, 0.242892f},
+ {-1.480325f, 2.435437f, 0.000000f},
+ {-1.405953f, 2.435437f, 0.472283f},
+ {-1.317252f, 2.435437f, 0.685331f},
+ {-1.197997f, 2.435437f, 0.879195f},
+ {-1.051031f, 2.435437f, 1.051031f},
+ {-0.879195f, 2.435437f, 1.197997f},
+ {-0.685331f, 2.435437f, 1.317252f},
+ {-0.472283f, 2.435437f, 1.405953f},
+ {-0.242892f, 2.435437f, 1.461258f},
+ {0.000000f, 2.435437f, 1.480325f},
+ {-1.480680f, 2.400000f, 0.246120f},
+ {-1.500000f, 2.400000f, 0.000000f},
+ {-1.424640f, 2.400000f, 0.478560f},
+ {-1.334760f, 2.400000f, 0.694440f},
+ {-1.213920f, 2.400000f, 0.890880f},
+ {-1.065000f, 2.400000f, 1.065000f},
+ {-0.890880f, 2.400000f, 1.213920f},
+ {-0.694440f, 2.400000f, 1.334760f},
+ {-0.478560f, 2.400000f, 1.424640f},
+ {-0.246120f, 2.400000f, 1.480680f},
+ {0.000000f, 2.400000f, 1.500000f},
+ {0.227403f, 2.435437f, 1.368074f},
+ {0.229712f, 2.400000f, 1.381968f},
+ {0.000000f, 2.400000f, 1.400000f},
+ {0.000000f, 2.435437f, 1.385925f},
+ {0.442166f, 2.435437f, 1.316296f},
+ {0.446656f, 2.400000f, 1.329664f},
+ {0.641628f, 2.435437f, 1.233252f},
+ {0.648144f, 2.400000f, 1.245776f},
+ {0.823129f, 2.435437f, 1.121601f},
+ {0.831488f, 2.400000f, 1.132992f},
+ {0.984007f, 2.435437f, 0.984007f},
+ {0.994000f, 2.400000f, 0.994000f},
+ {1.121601f, 2.435437f, 0.823129f},
+ {1.132992f, 2.400000f, 0.831488f},
+ {1.233252f, 2.435437f, 0.641628f},
+ {1.245776f, 2.400000f, 0.648144f},
+ {1.316296f, 2.435437f, 0.442166f},
+ {1.329664f, 2.400000f, 0.446656f},
+ {1.368074f, 2.435437f, 0.227403f},
+ {1.381968f, 2.400000f, 0.229712f},
+ {1.385925f, 2.435437f, -0.000000f},
+ {1.400000f, 2.400000f, 0.000000f},
+ {0.226496f, 2.463000f, 1.362620f},
+ {0.000000f, 2.463000f, 1.380400f},
+ {0.440403f, 2.463000f, 1.311049f},
+ {0.639070f, 2.463000f, 1.228335f},
+ {0.819847f, 2.463000f, 1.117130f},
+ {0.980084f, 2.463000f, 0.980084f},
+ {1.117130f, 2.463000f, 0.819847f},
+ {1.228335f, 2.463000f, 0.639070f},
+ {1.311049f, 2.463000f, 0.440403f},
+ {1.362620f, 2.463000f, 0.226496f},
+ {1.380400f, 2.463000f, -0.000000f},
+ {0.226795f, 2.482687f, 1.364422f},
+ {0.000000f, 2.482687f, 1.382225f},
+ {0.440985f, 2.482687f, 1.312782f},
+ {0.639915f, 2.482687f, 1.229959f},
+ {0.820931f, 2.482687f, 1.118607f},
+ {0.981380f, 2.482687f, 0.981380f},
+ {1.118607f, 2.482687f, 0.820931f},
+ {1.229959f, 2.482687f, 0.639915f},
+ {1.312782f, 2.482687f, 0.440985f},
+ {1.364422f, 2.482687f, 0.226795f},
+ {1.382225f, 2.482687f, 0.000000f},
+ {0.228104f, 2.494500f, 1.372294f},
+ {0.000000f, 2.494500f, 1.390200f},
+ {0.443529f, 2.494500f, 1.320356f},
+ {0.643607f, 2.494500f, 1.237056f},
+ {0.825668f, 2.494500f, 1.125061f},
+ {0.987042f, 2.494500f, 0.987042f},
+ {1.125061f, 2.494500f, 0.825668f},
+ {1.237056f, 2.494500f, 0.643607f},
+ {1.320356f, 2.494500f, 0.443529f},
+ {1.372294f, 2.494500f, 0.228104f},
+ {1.390200f, 2.494500f, -0.000000f},
+ {0.230225f, 2.498438f, 1.385053f},
+ {0.000000f, 2.498438f, 1.403125f},
+ {0.447653f, 2.498438f, 1.332632f},
+ {0.649591f, 2.498438f, 1.248557f},
+ {0.833344f, 2.498438f, 1.135521f},
+ {0.996219f, 2.498438f, 0.996219f},
+ {1.135521f, 2.498438f, 0.833344f},
+ {1.248557f, 2.498438f, 0.649591f},
+ {1.332632f, 2.498438f, 0.447653f},
+ {1.385053f, 2.498438f, 0.230225f},
+ {1.403125f, 2.498438f, 0.000000f},
+ {0.232961f, 2.494500f, 1.401513f},
+ {0.000000f, 2.494500f, 1.419800f},
+ {0.452973f, 2.494500f, 1.348469f},
+ {0.657311f, 2.494500f, 1.263395f},
+ {0.843248f, 2.494500f, 1.149016f},
+ {1.008058f, 2.494500f, 1.008058f},
+ {1.149016f, 2.494500f, 0.843248f},
+ {1.263395f, 2.494500f, 0.657311f},
+ {1.348469f, 2.494500f, 0.452973f},
+ {1.401513f, 2.494500f, 0.232961f},
+ {1.419800f, 2.494500f, -0.000000f},
+ {0.236115f, 2.482687f, 1.420490f},
+ {0.459107f, 2.482687f, 1.366728f},
+ {0.666211f, 2.482687f, 1.280502f},
+ {0.854666f, 2.482687f, 1.164574f},
+ {1.021708f, 2.482687f, 1.021708f},
+ {1.164574f, 2.482687f, 0.854666f},
+ {1.280502f, 2.482687f, 0.666211f},
+ {1.366728f, 2.482687f, 0.459107f},
+ {1.420490f, 2.482687f, 0.236115f},
+ {0.239491f, 2.463000f, 1.440800f},
+ {0.000000f, 2.463000f, 1.459600f},
+ {0.465671f, 2.463000f, 1.386270f},
+ {0.675736f, 2.463000f, 1.298810f},
+ {0.866886f, 2.463000f, 1.181225f},
+ {1.036316f, 2.463000f, 1.036316f},
+ {1.181225f, 2.463000f, 0.866886f},
+ {1.298810f, 2.463000f, 0.675736f},
+ {1.386270f, 2.463000f, 0.465671f},
+ {1.440800f, 2.463000f, 0.239491f},
+ {1.459600f, 2.463000f, -0.000000f},
+ {0.242892f, 2.435437f, 1.461258f},
+ {0.000000f, 2.435437f, 1.480325f},
+ {0.472283f, 2.435437f, 1.405953f},
+ {0.685331f, 2.435437f, 1.317252f},
+ {0.879195f, 2.435437f, 1.197997f},
+ {1.051031f, 2.435437f, 1.051031f},
+ {1.197997f, 2.435437f, 0.879195f},
+ {1.317252f, 2.435437f, 0.685331f},
+ {1.405953f, 2.435437f, 0.472283f},
+ {1.461258f, 2.435437f, 0.242892f},
+ {1.480325f, 2.435437f, -0.000000f},
+ {0.246120f, 2.400000f, 1.480680f},
+ {0.000000f, 2.400000f, 1.500000f},
+ {0.478560f, 2.400000f, 1.424640f},
+ {0.694440f, 2.400000f, 1.334760f},
+ {0.890880f, 2.400000f, 1.213920f},
+ {1.065000f, 2.400000f, 1.065000f},
+ {1.213920f, 2.400000f, 0.890880f},
+ {1.334760f, 2.400000f, 0.694440f},
+ {1.424640f, 2.400000f, 0.478560f},
+ {1.480680f, 2.400000f, 0.246120f},
+ {1.500000f, 2.400000f, 0.000000f},
+ {1.554467f, 2.242575f, -0.258385f},
+ {1.574750f, 2.242575f, 0.000000f},
+ {1.495635f, 2.242575f, -0.502408f},
+ {1.401276f, 2.242575f, -0.729046f},
+ {1.274414f, 2.242575f, -0.935276f},
+ {1.118073f, 2.242575f, -1.118073f},
+ {0.935276f, 2.242575f, -1.274414f},
+ {0.729046f, 2.242575f, -1.401276f},
+ {0.502408f, 2.242575f, -1.495635f},
+ {0.258385f, 2.242575f, -1.554467f},
+ {0.000000f, 2.242575f, -1.574750f},
+ {1.626774f, 2.085600f, -0.270404f},
+ {1.648000f, 2.085600f, 0.000000f},
+ {1.565204f, 2.085600f, -0.525778f},
+ {1.466456f, 2.085600f, -0.762958f},
+ {1.333693f, 2.085600f, -0.978780f},
+ {1.170080f, 2.085600f, -1.170080f},
+ {0.978780f, 2.085600f, -1.333693f},
+ {0.762958f, 2.085600f, -1.466456f},
+ {0.525778f, 2.085600f, -1.565204f},
+ {0.270404f, 2.085600f, -1.626774f},
+ {-0.000000f, 2.085600f, -1.648000f},
+ {1.696119f, 1.929525f, -0.281930f},
+ {1.718250f, 1.929525f, 0.000000f},
+ {1.631925f, 1.929525f, -0.548190f},
+ {1.528968f, 1.929525f, -0.795481f},
+ {1.390545f, 1.929525f, -1.020503f},
+ {1.219958f, 1.929525f, -1.219958f},
+ {1.020503f, 1.929525f, -1.390545f},
+ {0.795481f, 1.929525f, -1.528968f},
+ {0.548190f, 1.929525f, -1.631925f},
+ {0.281930f, 1.929525f, -1.696119f},
+ {0.000000f, 1.929525f, -1.718250f},
+ {1.761022f, 1.774800f, -0.292719f},
+ {1.784000f, 1.774800f, 0.000000f},
+ {1.694372f, 1.774800f, -0.569167f},
+ {1.587475f, 1.774800f, -0.825921f},
+ {1.443756f, 1.774800f, -1.059553f},
+ {1.266640f, 1.774800f, -1.266640f},
+ {1.059553f, 1.774800f, -1.443756f},
+ {0.825921f, 1.774800f, -1.587475f},
+ {0.569167f, 1.774800f, -1.694372f},
+ {0.292719f, 1.774800f, -1.761022f},
+ {0.000000f, 1.774800f, -1.784000f},
+ {1.820003f, 1.621875f, -0.302523f},
+ {1.843750f, 1.621875f, 0.000000f},
+ {1.751120f, 1.621875f, -0.588230f},
+ {1.640643f, 1.621875f, -0.853583f},
+ {1.492110f, 1.621875f, -1.095040f},
+ {1.309063f, 1.621875f, -1.309063f},
+ {1.095040f, 1.621875f, -1.492110f},
+ {0.853583f, 1.621875f, -1.640643f},
+ {0.588230f, 1.621875f, -1.751120f},
+ {0.302522f, 1.621875f, -1.820003f},
+ {-0.000000f, 1.621875f, -1.843750f},
+ {1.871580f, 1.471200f, -0.311096f},
+ {1.896000f, 1.471200f, 0.000000f},
+ {1.800745f, 1.471200f, -0.604900f},
+ {1.687137f, 1.471200f, -0.877772f},
+ {1.534395f, 1.471200f, -1.126072f},
+ {1.346160f, 1.471200f, -1.346160f},
+ {1.126072f, 1.471200f, -1.534395f},
+ {0.877772f, 1.471200f, -1.687137f},
+ {0.604900f, 1.471200f, -1.800745f},
+ {0.311096f, 1.471200f, -1.871580f},
+ {0.000000f, 1.471200f, -1.896000f},
+ {1.914272f, 1.323225f, -0.318192f},
+ {1.939250f, 1.323225f, 0.000000f},
+ {1.841822f, 1.323225f, -0.618698f},
+ {1.725622f, 1.323225f, -0.897795f},
+ {1.569396f, 1.323225f, -1.151759f},
+ {1.376867f, 1.323225f, -1.376868f},
+ {1.151759f, 1.323225f, -1.569396f},
+ {0.897795f, 1.323225f, -1.725622f},
+ {0.618698f, 1.323225f, -1.841822f},
+ {0.318192f, 1.323225f, -1.914272f},
+ {-0.000000f, 1.323225f, -1.939250f},
+ {1.946601f, 1.178400f, -0.323566f},
+ {1.972000f, 1.178400f, 0.000000f},
+ {1.872927f, 1.178400f, -0.629147f},
+ {1.754764f, 1.178400f, -0.912957f},
+ {1.595900f, 1.178400f, -1.171210f},
+ {1.400120f, 1.178400f, -1.400120f},
+ {1.171210f, 1.178400f, -1.595900f},
+ {0.912957f, 1.178400f, -1.754764f},
+ {0.629147f, 1.178400f, -1.872927f},
+ {0.323566f, 1.178400f, -1.946601f},
+ {0.000000f, 1.178400f, -1.972000f},
+ {1.967083f, 1.037175f, -0.326970f},
+ {1.992750f, 1.037175f, 0.000000f},
+ {1.892634f, 1.037175f, -0.635767f},
+ {1.773229f, 1.037175f, -0.922564f},
+ {1.612693f, 1.037175f, -1.183534f},
+ {1.414853f, 1.037175f, -1.414853f},
+ {1.183534f, 1.037175f, -1.612693f},
+ {0.922564f, 1.037175f, -1.773229f},
+ {0.635767f, 1.037175f, -1.892634f},
+ {0.326970f, 1.037175f, -1.967083f},
+ {0.000000f, 1.037175f, -1.992750f},
+ {1.974240f, 0.900000f, -0.328160f},
+ {2.000000f, 0.900000f, 0.000000f},
+ {1.899520f, 0.900000f, -0.638080f},
+ {1.779680f, 0.900000f, -0.925920f},
+ {1.618560f, 0.900000f, -1.187840f},
+ {1.420000f, 0.900000f, -1.420000f},
+ {1.187840f, 0.900000f, -1.618560f},
+ {0.925920f, 0.900000f, -1.779680f},
+ {0.638080f, 0.900000f, -1.899520f},
+ {0.328160f, 0.900000f, -1.974240f},
+ {0.000000f, 0.900000f, -2.000000f},
+ {-0.258385f, 2.242575f, -1.554467f},
+ {0.000000f, 2.242575f, -1.574750f},
+ {-0.502408f, 2.242575f, -1.495635f},
+ {-0.729046f, 2.242575f, -1.401276f},
+ {-0.935276f, 2.242575f, -1.274414f},
+ {-1.118073f, 2.242575f, -1.118073f},
+ {-1.274414f, 2.242575f, -0.935276f},
+ {-1.401276f, 2.242575f, -0.729046f},
+ {-1.495635f, 2.242575f, -0.502408f},
+ {-1.554467f, 2.242575f, -0.258385f},
+ {-1.574750f, 2.242575f, 0.000000f},
+ {-0.270404f, 2.085600f, -1.626774f},
+ {0.000000f, 2.085600f, -1.648000f},
+ {-0.525778f, 2.085600f, -1.565204f},
+ {-0.762958f, 2.085600f, -1.466456f},
+ {-0.978780f, 2.085600f, -1.333693f},
+ {-1.170080f, 2.085600f, -1.170080f},
+ {-1.333693f, 2.085600f, -0.978780f},
+ {-1.466456f, 2.085600f, -0.762958f},
+ {-1.565204f, 2.085600f, -0.525778f},
+ {-1.626774f, 2.085600f, -0.270404f},
+ {-1.648000f, 2.085600f, 0.000000f},
+ {-0.281930f, 1.929525f, -1.696119f},
+ {0.000000f, 1.929525f, -1.718250f},
+ {-0.548190f, 1.929525f, -1.631925f},
+ {-0.795481f, 1.929525f, -1.528968f},
+ {-1.020503f, 1.929525f, -1.390545f},
+ {-1.219958f, 1.929525f, -1.219958f},
+ {-1.390545f, 1.929525f, -1.020503f},
+ {-1.528968f, 1.929525f, -0.795481f},
+ {-1.631925f, 1.929525f, -0.548190f},
+ {-1.696119f, 1.929525f, -0.281930f},
+ {-1.718250f, 1.929525f, -0.000000f},
+ {-0.292719f, 1.774800f, -1.761022f},
+ {0.000000f, 1.774800f, -1.784000f},
+ {-0.569167f, 1.774800f, -1.694372f},
+ {-0.825921f, 1.774800f, -1.587475f},
+ {-1.059553f, 1.774800f, -1.443756f},
+ {-1.266640f, 1.774800f, -1.266640f},
+ {-1.443756f, 1.774800f, -1.059553f},
+ {-1.587475f, 1.774800f, -0.825921f},
+ {-1.694372f, 1.774800f, -0.569167f},
+ {-1.761022f, 1.774800f, -0.292719f},
+ {-1.784000f, 1.774800f, -0.000000f},
+ {-0.302523f, 1.621875f, -1.820003f},
+ {0.000000f, 1.621875f, -1.843750f},
+ {-0.588230f, 1.621875f, -1.751120f},
+ {-0.853583f, 1.621875f, -1.640643f},
+ {-1.095040f, 1.621875f, -1.492110f},
+ {-1.309063f, 1.621875f, -1.309063f},
+ {-1.492110f, 1.621875f, -1.095040f},
+ {-1.640643f, 1.621875f, -0.853583f},
+ {-1.751120f, 1.621875f, -0.588230f},
+ {-1.820003f, 1.621875f, -0.302522f},
+ {-1.843750f, 1.621875f, 0.000000f},
+ {-0.311096f, 1.471200f, -1.871580f},
+ {0.000000f, 1.471200f, -1.896000f},
+ {-0.604900f, 1.471200f, -1.800745f},
+ {-0.877772f, 1.471200f, -1.687137f},
+ {-1.126072f, 1.471200f, -1.534395f},
+ {-1.346160f, 1.471200f, -1.346160f},
+ {-1.534395f, 1.471200f, -1.126072f},
+ {-1.687137f, 1.471200f, -0.877772f},
+ {-1.800745f, 1.471200f, -0.604900f},
+ {-1.871580f, 1.471200f, -0.311096f},
+ {-1.896000f, 1.471200f, 0.000000f},
+ {-0.318192f, 1.323225f, -1.914272f},
+ {0.000000f, 1.323225f, -1.939250f},
+ {-0.618698f, 1.323225f, -1.841822f},
+ {-0.897795f, 1.323225f, -1.725622f},
+ {-1.151759f, 1.323225f, -1.569396f},
+ {-1.376868f, 1.323225f, -1.376867f},
+ {-1.569396f, 1.323225f, -1.151759f},
+ {-1.725622f, 1.323225f, -0.897795f},
+ {-1.841822f, 1.323225f, -0.618698f},
+ {-1.914272f, 1.323225f, -0.318192f},
+ {-1.939250f, 1.323225f, 0.000000f},
+ {-0.323566f, 1.178400f, -1.946601f},
+ {0.000000f, 1.178400f, -1.972000f},
+ {-0.629147f, 1.178400f, -1.872927f},
+ {-0.912957f, 1.178400f, -1.754764f},
+ {-1.171210f, 1.178400f, -1.595900f},
+ {-1.400120f, 1.178400f, -1.400120f},
+ {-1.595900f, 1.178400f, -1.171210f},
+ {-1.754764f, 1.178400f, -0.912957f},
+ {-1.872927f, 1.178400f, -0.629147f},
+ {-1.946601f, 1.178400f, -0.323566f},
+ {-1.972000f, 1.178400f, -0.000000f},
+ {-0.326970f, 1.037175f, -1.967083f},
+ {0.000000f, 1.037175f, -1.992750f},
+ {-0.635767f, 1.037175f, -1.892634f},
+ {-0.922564f, 1.037175f, -1.773229f},
+ {-1.183534f, 1.037175f, -1.612693f},
+ {-1.414853f, 1.037175f, -1.414853f},
+ {-1.612693f, 1.037175f, -1.183534f},
+ {-1.773229f, 1.037175f, -0.922564f},
+ {-1.892634f, 1.037175f, -0.635767f},
+ {-1.967083f, 1.037175f, -0.326970f},
+ {-1.992750f, 1.037175f, -0.000000f},
+ {-0.328160f, 0.900000f, -1.974240f},
+ {0.000000f, 0.900000f, -2.000000f},
+ {-0.638080f, 0.900000f, -1.899520f},
+ {-0.925920f, 0.900000f, -1.779680f},
+ {-1.187840f, 0.900000f, -1.618560f},
+ {-1.420000f, 0.900000f, -1.420000f},
+ {-1.618560f, 0.900000f, -1.187840f},
+ {-1.779680f, 0.900000f, -0.925920f},
+ {-1.899520f, 0.900000f, -0.638080f},
+ {-1.974240f, 0.900000f, -0.328160f},
+ {-2.000000f, 0.900000f, 0.000000f},
+ {-1.554467f, 2.242575f, 0.258385f},
+ {-1.574750f, 2.242575f, 0.000000f},
+ {-1.495635f, 2.242575f, 0.502408f},
+ {-1.401276f, 2.242575f, 0.729046f},
+ {-1.274414f, 2.242575f, 0.935276f},
+ {-1.118073f, 2.242575f, 1.118073f},
+ {-0.935276f, 2.242575f, 1.274414f},
+ {-0.729046f, 2.242575f, 1.401276f},
+ {-0.502408f, 2.242575f, 1.495635f},
+ {-0.258385f, 2.242575f, 1.554467f},
+ {0.000000f, 2.242575f, 1.574750f},
+ {-1.626774f, 2.085600f, 0.270404f},
+ {-1.648000f, 2.085600f, 0.000000f},
+ {-1.565204f, 2.085600f, 0.525778f},
+ {-1.466456f, 2.085600f, 0.762958f},
+ {-1.333693f, 2.085600f, 0.978780f},
+ {-1.170080f, 2.085600f, 1.170080f},
+ {-0.978780f, 2.085600f, 1.333693f},
+ {-0.762958f, 2.085600f, 1.466456f},
+ {-0.525778f, 2.085600f, 1.565204f},
+ {-0.270404f, 2.085600f, 1.626774f},
+ {0.000000f, 2.085600f, 1.648000f},
+ {-1.696119f, 1.929525f, 0.281930f},
+ {-1.718250f, 1.929525f, 0.000000f},
+ {-1.631925f, 1.929525f, 0.548190f},
+ {-1.528968f, 1.929525f, 0.795481f},
+ {-1.390545f, 1.929525f, 1.020503f},
+ {-1.219958f, 1.929525f, 1.219958f},
+ {-1.020503f, 1.929525f, 1.390545f},
+ {-0.795481f, 1.929525f, 1.528968f},
+ {-0.548190f, 1.929525f, 1.631925f},
+ {-0.281930f, 1.929525f, 1.696119f},
+ {-0.000000f, 1.929525f, 1.718250f},
+ {-1.761022f, 1.774800f, 0.292719f},
+ {-1.784000f, 1.774800f, 0.000000f},
+ {-1.694372f, 1.774800f, 0.569167f},
+ {-1.587475f, 1.774800f, 0.825921f},
+ {-1.443756f, 1.774800f, 1.059553f},
+ {-1.266640f, 1.774800f, 1.266640f},
+ {-1.059553f, 1.774800f, 1.443756f},
+ {-0.825921f, 1.774800f, 1.587475f},
+ {-0.569167f, 1.774800f, 1.694372f},
+ {-0.292719f, 1.774800f, 1.761022f},
+ {-0.000000f, 1.774800f, 1.784000f},
+ {-1.820003f, 1.621875f, 0.302523f},
+ {-1.843750f, 1.621875f, 0.000000f},
+ {-1.751120f, 1.621875f, 0.588230f},
+ {-1.640643f, 1.621875f, 0.853583f},
+ {-1.492110f, 1.621875f, 1.095040f},
+ {-1.309063f, 1.621875f, 1.309063f},
+ {-1.095040f, 1.621875f, 1.492110f},
+ {-0.853583f, 1.621875f, 1.640643f},
+ {-0.588230f, 1.621875f, 1.751120f},
+ {-0.302522f, 1.621875f, 1.820003f},
+ {0.000000f, 1.621875f, 1.843750f},
+ {-1.871580f, 1.471200f, 0.311096f},
+ {-1.896000f, 1.471200f, 0.000000f},
+ {-1.800745f, 1.471200f, 0.604900f},
+ {-1.687137f, 1.471200f, 0.877772f},
+ {-1.534395f, 1.471200f, 1.126072f},
+ {-1.346160f, 1.471200f, 1.346160f},
+ {-1.126072f, 1.471200f, 1.534395f},
+ {-0.877772f, 1.471200f, 1.687137f},
+ {-0.604900f, 1.471200f, 1.800745f},
+ {-0.311096f, 1.471200f, 1.871580f},
+ {0.000000f, 1.471200f, 1.896000f},
+ {-1.914272f, 1.323225f, 0.318192f},
+ {-1.939250f, 1.323225f, 0.000000f},
+ {-1.841822f, 1.323225f, 0.618698f},
+ {-1.725622f, 1.323225f, 0.897795f},
+ {-1.569396f, 1.323225f, 1.151759f},
+ {-1.376867f, 1.323225f, 1.376868f},
+ {-1.151759f, 1.323225f, 1.569396f},
+ {-0.897795f, 1.323225f, 1.725622f},
+ {-0.618698f, 1.323225f, 1.841822f},
+ {-0.318192f, 1.323225f, 1.914272f},
+ {0.000000f, 1.323225f, 1.939250f},
+ {-1.946601f, 1.178400f, 0.323566f},
+ {-1.972000f, 1.178400f, 0.000000f},
+ {-1.872927f, 1.178400f, 0.629147f},
+ {-1.754764f, 1.178400f, 0.912957f},
+ {-1.595900f, 1.178400f, 1.171210f},
+ {-1.400120f, 1.178400f, 1.400120f},
+ {-1.171210f, 1.178400f, 1.595900f},
+ {-0.912957f, 1.178400f, 1.754764f},
+ {-0.629147f, 1.178400f, 1.872927f},
+ {-0.323566f, 1.178400f, 1.946601f},
+ {-0.000000f, 1.178400f, 1.972000f},
+ {-1.967083f, 1.037175f, 0.326970f},
+ {-1.992750f, 1.037175f, 0.000000f},
+ {-1.892634f, 1.037175f, 0.635767f},
+ {-1.773229f, 1.037175f, 0.922564f},
+ {-1.612693f, 1.037175f, 1.183534f},
+ {-1.414853f, 1.037175f, 1.414853f},
+ {-1.183534f, 1.037175f, 1.612693f},
+ {-0.922564f, 1.037175f, 1.773229f},
+ {-0.635767f, 1.037175f, 1.892634f},
+ {-0.326970f, 1.037175f, 1.967083f},
+ {-0.000000f, 1.037175f, 1.992750f},
+ {-1.974240f, 0.900000f, 0.328160f},
+ {-2.000000f, 0.900000f, 0.000000f},
+ {-1.899520f, 0.900000f, 0.638080f},
+ {-1.779680f, 0.900000f, 0.925920f},
+ {-1.618560f, 0.900000f, 1.187840f},
+ {-1.420000f, 0.900000f, 1.420000f},
+ {-1.187840f, 0.900000f, 1.618560f},
+ {-0.925920f, 0.900000f, 1.779680f},
+ {-0.638080f, 0.900000f, 1.899520f},
+ {-0.328160f, 0.900000f, 1.974240f},
+ {0.000000f, 0.900000f, 2.000000f},
+ {0.258385f, 2.242575f, 1.554467f},
+ {0.000000f, 2.242575f, 1.574750f},
+ {0.502408f, 2.242575f, 1.495635f},
+ {0.729046f, 2.242575f, 1.401276f},
+ {0.935276f, 2.242575f, 1.274414f},
+ {1.118073f, 2.242575f, 1.118073f},
+ {1.274414f, 2.242575f, 0.935276f},
+ {1.401276f, 2.242575f, 0.729046f},
+ {1.495635f, 2.242575f, 0.502408f},
+ {1.554467f, 2.242575f, 0.258385f},
+ {1.574750f, 2.242575f, 0.000000f},
+ {0.270404f, 2.085600f, 1.626774f},
+ {0.000000f, 2.085600f, 1.648000f},
+ {0.525778f, 2.085600f, 1.565204f},
+ {0.762958f, 2.085600f, 1.466456f},
+ {0.978780f, 2.085600f, 1.333693f},
+ {1.170080f, 2.085600f, 1.170080f},
+ {1.333693f, 2.085600f, 0.978780f},
+ {1.466456f, 2.085600f, 0.762958f},
+ {1.565204f, 2.085600f, 0.525778f},
+ {1.626774f, 2.085600f, 0.270404f},
+ {1.648000f, 2.085600f, -0.000000f},
+ {0.281930f, 1.929525f, 1.696119f},
+ {0.000000f, 1.929525f, 1.718250f},
+ {0.548190f, 1.929525f, 1.631925f},
+ {0.795481f, 1.929525f, 1.528968f},
+ {1.020503f, 1.929525f, 1.390545f},
+ {1.219958f, 1.929525f, 1.219958f},
+ {1.390545f, 1.929525f, 1.020503f},
+ {1.528968f, 1.929525f, 0.795481f},
+ {1.631925f, 1.929525f, 0.548190f},
+ {1.696119f, 1.929525f, 0.281930f},
+ {1.718250f, 1.929525f, 0.000000f},
+ {0.292719f, 1.774800f, 1.761022f},
+ {0.000000f, 1.774800f, 1.784000f},
+ {0.569167f, 1.774800f, 1.694372f},
+ {0.825921f, 1.774800f, 1.587475f},
+ {1.059553f, 1.774800f, 1.443756f},
+ {1.266640f, 1.774800f, 1.266640f},
+ {1.443756f, 1.774800f, 1.059553f},
+ {1.587475f, 1.774800f, 0.825921f},
+ {1.694372f, 1.774800f, 0.569167f},
+ {1.761022f, 1.774800f, 0.292719f},
+ {1.784000f, 1.774800f, 0.000000f},
+ {0.302523f, 1.621875f, 1.820003f},
+ {0.000000f, 1.621875f, 1.843750f},
+ {0.588230f, 1.621875f, 1.751120f},
+ {0.853583f, 1.621875f, 1.640643f},
+ {1.095040f, 1.621875f, 1.492110f},
+ {1.309063f, 1.621875f, 1.309063f},
+ {1.492110f, 1.621875f, 1.095040f},
+ {1.640643f, 1.621875f, 0.853583f},
+ {1.751120f, 1.621875f, 0.588230f},
+ {1.820003f, 1.621875f, 0.302522f},
+ {1.843750f, 1.621875f, -0.000000f},
+ {0.311096f, 1.471200f, 1.871580f},
+ {0.000000f, 1.471200f, 1.896000f},
+ {0.604900f, 1.471200f, 1.800745f},
+ {0.877772f, 1.471200f, 1.687137f},
+ {1.126072f, 1.471200f, 1.534395f},
+ {1.346160f, 1.471200f, 1.346160f},
+ {1.534395f, 1.471200f, 1.126072f},
+ {1.687137f, 1.471200f, 0.877772f},
+ {1.800745f, 1.471200f, 0.604900f},
+ {1.871580f, 1.471200f, 0.311096f},
+ {1.896000f, 1.471200f, 0.000000f},
+ {0.318192f, 1.323225f, 1.914272f},
+ {0.000000f, 1.323225f, 1.939250f},
+ {0.618698f, 1.323225f, 1.841822f},
+ {0.897795f, 1.323225f, 1.725622f},
+ {1.151759f, 1.323225f, 1.569396f},
+ {1.376868f, 1.323225f, 1.376867f},
+ {1.569396f, 1.323225f, 1.151759f},
+ {1.725622f, 1.323225f, 0.897795f},
+ {1.841822f, 1.323225f, 0.618698f},
+ {1.914272f, 1.323225f, 0.318192f},
+ {1.939250f, 1.323225f, -0.000000f},
+ {0.323566f, 1.178400f, 1.946601f},
+ {0.000000f, 1.178400f, 1.972000f},
+ {0.629147f, 1.178400f, 1.872927f},
+ {0.912957f, 1.178400f, 1.754764f},
+ {1.171210f, 1.178400f, 1.595900f},
+ {1.400120f, 1.178400f, 1.400120f},
+ {1.595900f, 1.178400f, 1.171210f},
+ {1.754764f, 1.178400f, 0.912957f},
+ {1.872927f, 1.178400f, 0.629147f},
+ {1.946601f, 1.178400f, 0.323566f},
+ {1.972000f, 1.178400f, 0.000000f},
+ {0.326970f, 1.037175f, 1.967083f},
+ {0.000000f, 1.037175f, 1.992750f},
+ {0.635767f, 1.037175f, 1.892634f},
+ {0.922564f, 1.037175f, 1.773229f},
+ {1.183534f, 1.037175f, 1.612693f},
+ {1.414853f, 1.037175f, 1.414853f},
+ {1.612693f, 1.037175f, 1.183534f},
+ {1.773229f, 1.037175f, 0.922564f},
+ {1.892634f, 1.037175f, 0.635767f},
+ {1.967083f, 1.037175f, 0.326970f},
+ {1.992750f, 1.037175f, 0.000000f},
+ {0.328160f, 0.900000f, 1.974240f},
+ {0.000000f, 0.900000f, 2.000000f},
+ {0.638080f, 0.900000f, 1.899520f},
+ {0.925920f, 0.900000f, 1.779680f},
+ {1.187840f, 0.900000f, 1.618560f},
+ {1.420000f, 0.900000f, 1.420000f},
+ {1.618560f, 0.900000f, 1.187840f},
+ {1.779680f, 0.900000f, 0.925920f},
+ {1.899520f, 0.900000f, 0.638080f},
+ {1.974240f, 0.900000f, 0.328160f},
+ {2.000000f, 0.900000f, 0.000000f},
+ {1.960420f, 0.771675f, -0.325863f},
+ {1.986000f, 0.771675f, 0.000000f},
+ {1.886223f, 0.771675f, -0.633613f},
+ {1.899520f, 0.900000f, -0.638080f},
+ {1.767222f, 0.771675f, -0.919439f},
+ {1.779680f, 0.900000f, -0.925920f},
+ {1.607230f, 0.771675f, -1.179525f},
+ {1.618560f, 0.900000f, -1.187840f},
+ {1.410060f, 0.771675f, -1.410060f},
+ {1.420000f, 0.900000f, -1.420000f},
+ {1.179525f, 0.771675f, -1.607230f},
+ {1.187840f, 0.900000f, -1.618560f},
+ {0.919439f, 0.771675f, -1.767222f},
+ {0.925920f, 0.900000f, -1.779680f},
+ {0.633613f, 0.771675f, -1.886223f},
+ {0.638080f, 0.900000f, -1.899520f},
+ {0.325863f, 0.771675f, -1.960420f},
+ {0.328160f, 0.900000f, -1.974240f},
+ {-0.000000f, 0.771675f, -1.986000f},
+ {1.922910f, 0.656400f, -0.319628f},
+ {1.948000f, 0.656400f, 0.000000f},
+ {1.850132f, 0.656400f, -0.621490f},
+ {1.733408f, 0.656400f, -0.901846f},
+ {1.576477f, 0.656400f, -1.156956f},
+ {1.383080f, 0.656400f, -1.383080f},
+ {1.156956f, 0.656400f, -1.576477f},
+ {0.901846f, 0.656400f, -1.733408f},
+ {0.621490f, 0.656400f, -1.850132f},
+ {0.319628f, 0.656400f, -1.922910f},
+ {-0.000000f, 0.656400f, -1.948000f},
+ {1.867631f, 0.553725f, -0.310439f},
+ {1.892000f, 0.553725f, 0.000000f},
+ {1.796946f, 0.553725f, -0.603624f},
+ {1.683577f, 0.553725f, -0.875920f},
+ {1.531158f, 0.553725f, -1.123697f},
+ {1.343320f, 0.553725f, -1.343320f},
+ {1.123697f, 0.553725f, -1.531158f},
+ {0.875920f, 0.553725f, -1.683577f},
+ {0.603624f, 0.553725f, -1.796946f},
+ {0.310439f, 0.553725f, -1.867631f},
+ {-0.000000f, 0.553725f, -1.892000f},
+ {1.800507f, 0.463200f, -0.299282f},
+ {1.824000f, 0.463200f, 0.000000f},
+ {1.732362f, 0.463200f, -0.581929f},
+ {1.623068f, 0.463200f, -0.844439f},
+ {1.476127f, 0.463200f, -1.083310f},
+ {1.295040f, 0.463200f, -1.295040f},
+ {1.083310f, 0.463200f, -1.476127f},
+ {0.844439f, 0.463200f, -1.623068f},
+ {0.581929f, 0.463200f, -1.732362f},
+ {0.299282f, 0.463200f, -1.800507f},
+ {0.000000f, 0.463200f, -1.824000f},
+ {1.727460f, 0.384375f, -0.287140f},
+ {1.750000f, 0.384375f, 0.000000f},
+ {1.662080f, 0.384375f, -0.558320f},
+ {1.557220f, 0.384375f, -0.810180f},
+ {1.416240f, 0.384375f, -1.039360f},
+ {1.242500f, 0.384375f, -1.242500f},
+ {1.039360f, 0.384375f, -1.416240f},
+ {0.810180f, 0.384375f, -1.557220f},
+ {0.558320f, 0.384375f, -1.662080f},
+ {0.287140f, 0.384375f, -1.727460f},
+ {0.000000f, 0.384375f, -1.750000f},
+ {1.654413f, 0.316800f, -0.274998f},
+ {1.676000f, 0.316800f, 0.000000f},
+ {1.591798f, 0.316800f, -0.534711f},
+ {1.491372f, 0.316800f, -0.775921f},
+ {1.356353f, 0.316800f, -0.995410f},
+ {1.189960f, 0.316800f, -1.189960f},
+ {0.995410f, 0.316800f, -1.356353f},
+ {0.775921f, 0.316800f, -1.491372f},
+ {0.534711f, 0.316800f, -1.591798f},
+ {0.274998f, 0.316800f, -1.654413f},
+ {0.000000f, 0.316800f, -1.676000f},
+ {1.587289f, 0.260025f, -0.263841f},
+ {1.608000f, 0.260025f, 0.000000f},
+ {1.527214f, 0.260025f, -0.513016f},
+ {1.430863f, 0.260025f, -0.744440f},
+ {1.301322f, 0.260025f, -0.955023f},
+ {1.141680f, 0.260025f, -1.141680f},
+ {0.955023f, 0.260025f, -1.301322f},
+ {0.744440f, 0.260025f, -1.430863f},
+ {0.513016f, 0.260025f, -1.527214f},
+ {0.263841f, 0.260025f, -1.587289f},
+ {0.000000f, 0.260025f, -1.608000f},
+ {1.532010f, 0.213600f, -0.254652f},
+ {1.552000f, 0.213600f, 0.000000f},
+ {1.474028f, 0.213600f, -0.495150f},
+ {1.381032f, 0.213600f, -0.718514f},
+ {1.256003f, 0.213600f, -0.921764f},
+ {1.101920f, 0.213600f, -1.101920f},
+ {0.921764f, 0.213600f, -1.256003f},
+ {0.718514f, 0.213600f, -1.381032f},
+ {0.495150f, 0.213600f, -1.474028f},
+ {0.254652f, 0.213600f, -1.532010f},
+ {0.000000f, 0.213600f, -1.552000f},
+ {1.494500f, 0.177075f, -0.248417f},
+ {1.514000f, 0.177075f, 0.000000f},
+ {1.437937f, 0.177075f, -0.483027f},
+ {1.347218f, 0.177075f, -0.700921f},
+ {1.225250f, 0.177075f, -0.899195f},
+ {1.074940f, 0.177075f, -1.074940f},
+ {0.899195f, 0.177075f, -1.225250f},
+ {0.700921f, 0.177075f, -1.347218f},
+ {0.483027f, 0.177075f, -1.437937f},
+ {0.248417f, 0.177075f, -1.494500f},
+ {-0.000000f, 0.177075f, -1.514000f},
+ {1.480680f, 0.150000f, -0.246120f},
+ {1.500000f, 0.150000f, 0.000000f},
+ {1.424640f, 0.150000f, -0.478560f},
+ {1.334760f, 0.150000f, -0.694440f},
+ {1.213920f, 0.150000f, -0.890880f},
+ {1.065000f, 0.150000f, -1.065000f},
+ {0.890880f, 0.150000f, -1.213920f},
+ {0.694440f, 0.150000f, -1.334760f},
+ {0.478560f, 0.150000f, -1.424640f},
+ {0.246120f, 0.150000f, -1.480680f},
+ {0.000000f, 0.150000f, -1.500000f},
+ {-0.325863f, 0.771675f, -1.960420f},
+ {0.000000f, 0.771675f, -1.986000f},
+ {-0.633613f, 0.771675f, -1.886223f},
+ {-0.638080f, 0.900000f, -1.899520f},
+ {-0.919439f, 0.771675f, -1.767222f},
+ {-0.925920f, 0.900000f, -1.779680f},
+ {-1.179525f, 0.771675f, -1.607230f},
+ {-1.187840f, 0.900000f, -1.618560f},
+ {-1.410060f, 0.771675f, -1.410060f},
+ {-1.420000f, 0.900000f, -1.420000f},
+ {-1.607230f, 0.771675f, -1.179525f},
+ {-1.618560f, 0.900000f, -1.187840f},
+ {-1.767222f, 0.771675f, -0.919439f},
+ {-1.779680f, 0.900000f, -0.925920f},
+ {-1.886223f, 0.771675f, -0.633613f},
+ {-1.899520f, 0.900000f, -0.638080f},
+ {-1.960420f, 0.771675f, -0.325863f},
+ {-1.974240f, 0.900000f, -0.328160f},
+ {-1.986000f, 0.771675f, 0.000000f},
+ {-0.319628f, 0.656400f, -1.922910f},
+ {0.000000f, 0.656400f, -1.948000f},
+ {-0.621490f, 0.656400f, -1.850132f},
+ {-0.901846f, 0.656400f, -1.733408f},
+ {-1.156956f, 0.656400f, -1.576477f},
+ {-1.383080f, 0.656400f, -1.383080f},
+ {-1.576477f, 0.656400f, -1.156956f},
+ {-1.733408f, 0.656400f, -0.901846f},
+ {-1.850132f, 0.656400f, -0.621490f},
+ {-1.922910f, 0.656400f, -0.319628f},
+ {-1.948000f, 0.656400f, 0.000000f},
+ {-0.310439f, 0.553725f, -1.867631f},
+ {0.000000f, 0.553725f, -1.892000f},
+ {-0.603624f, 0.553725f, -1.796946f},
+ {-0.875920f, 0.553725f, -1.683577f},
+ {-1.123697f, 0.553725f, -1.531158f},
+ {-1.343320f, 0.553725f, -1.343320f},
+ {-1.531158f, 0.553725f, -1.123697f},
+ {-1.683577f, 0.553725f, -0.875920f},
+ {-1.796946f, 0.553725f, -0.603624f},
+ {-1.867631f, 0.553725f, -0.310439f},
+ {-1.892000f, 0.553725f, 0.000000f},
+ {-0.299282f, 0.463200f, -1.800507f},
+ {0.000000f, 0.463200f, -1.824000f},
+ {-0.581929f, 0.463200f, -1.732362f},
+ {-0.844439f, 0.463200f, -1.623068f},
+ {-1.083310f, 0.463200f, -1.476127f},
+ {-1.295040f, 0.463200f, -1.295040f},
+ {-1.476127f, 0.463200f, -1.083310f},
+ {-1.623068f, 0.463200f, -0.844439f},
+ {-1.732362f, 0.463200f, -0.581929f},
+ {-1.800507f, 0.463200f, -0.299282f},
+ {-1.824000f, 0.463200f, -0.000000f},
+ {-0.287140f, 0.384375f, -1.727460f},
+ {0.000000f, 0.384375f, -1.750000f},
+ {-0.558320f, 0.384375f, -1.662080f},
+ {-0.810180f, 0.384375f, -1.557220f},
+ {-1.039360f, 0.384375f, -1.416240f},
+ {-1.242500f, 0.384375f, -1.242500f},
+ {-1.416240f, 0.384375f, -1.039360f},
+ {-1.557220f, 0.384375f, -0.810180f},
+ {-1.662080f, 0.384375f, -0.558320f},
+ {-1.727460f, 0.384375f, -0.287140f},
+ {-1.750000f, 0.384375f, -0.000000f},
+ {-0.274998f, 0.316800f, -1.654413f},
+ {0.000000f, 0.316800f, -1.676000f},
+ {-0.534711f, 0.316800f, -1.591798f},
+ {-0.775921f, 0.316800f, -1.491372f},
+ {-0.995410f, 0.316800f, -1.356353f},
+ {-1.189960f, 0.316800f, -1.189960f},
+ {-1.356353f, 0.316800f, -0.995410f},
+ {-1.491372f, 0.316800f, -0.775921f},
+ {-1.591798f, 0.316800f, -0.534711f},
+ {-1.654413f, 0.316800f, -0.274998f},
+ {-1.676000f, 0.316800f, 0.000000f},
+ {-0.263841f, 0.260025f, -1.587289f},
+ {0.000000f, 0.260025f, -1.608000f},
+ {-0.513016f, 0.260025f, -1.527214f},
+ {-0.744440f, 0.260025f, -1.430863f},
+ {-0.955023f, 0.260025f, -1.301322f},
+ {-1.141680f, 0.260025f, -1.141680f},
+ {-1.301322f, 0.260025f, -0.955023f},
+ {-1.430863f, 0.260025f, -0.744440f},
+ {-1.527214f, 0.260025f, -0.513016f},
+ {-1.587289f, 0.260025f, -0.263841f},
+ {-1.608000f, 0.260025f, -0.000000f},
+ {-0.254652f, 0.213600f, -1.532010f},
+ {0.000000f, 0.213600f, -1.552000f},
+ {-0.495150f, 0.213600f, -1.474028f},
+ {-0.718514f, 0.213600f, -1.381032f},
+ {-0.921764f, 0.213600f, -1.256003f},
+ {-1.101920f, 0.213600f, -1.101920f},
+ {-1.256003f, 0.213600f, -0.921764f},
+ {-1.381032f, 0.213600f, -0.718514f},
+ {-1.474028f, 0.213600f, -0.495150f},
+ {-1.532010f, 0.213600f, -0.254652f},
+ {-1.552000f, 0.213600f, 0.000000f},
+ {-0.248417f, 0.177075f, -1.494500f},
+ {0.000000f, 0.177075f, -1.514000f},
+ {-0.483027f, 0.177075f, -1.437937f},
+ {-0.700921f, 0.177075f, -1.347218f},
+ {-0.899195f, 0.177075f, -1.225250f},
+ {-1.074940f, 0.177075f, -1.074940f},
+ {-1.225250f, 0.177075f, -0.899195f},
+ {-1.347218f, 0.177075f, -0.700921f},
+ {-1.437937f, 0.177075f, -0.483027f},
+ {-1.494500f, 0.177075f, -0.248417f},
+ {-1.514000f, 0.177075f, 0.000000f},
+ {-0.246120f, 0.150000f, -1.480680f},
+ {0.000000f, 0.150000f, -1.500000f},
+ {-0.478560f, 0.150000f, -1.424640f},
+ {-0.694440f, 0.150000f, -1.334760f},
+ {-0.890880f, 0.150000f, -1.213920f},
+ {-1.065000f, 0.150000f, -1.065000f},
+ {-1.213920f, 0.150000f, -0.890880f},
+ {-1.334760f, 0.150000f, -0.694440f},
+ {-1.424640f, 0.150000f, -0.478560f},
+ {-1.480680f, 0.150000f, -0.246120f},
+ {-1.500000f, 0.150000f, 0.000000f},
+ {-1.960420f, 0.771675f, 0.325863f},
+ {-1.986000f, 0.771675f, 0.000000f},
+ {-1.886223f, 0.771675f, 0.633613f},
+ {-1.899520f, 0.900000f, 0.638080f},
+ {-1.767222f, 0.771675f, 0.919439f},
+ {-1.779680f, 0.900000f, 0.925920f},
+ {-1.607230f, 0.771675f, 1.179525f},
+ {-1.618560f, 0.900000f, 1.187840f},
+ {-1.410060f, 0.771675f, 1.410060f},
+ {-1.420000f, 0.900000f, 1.420000f},
+ {-1.179525f, 0.771675f, 1.607230f},
+ {-1.187840f, 0.900000f, 1.618560f},
+ {-0.919439f, 0.771675f, 1.767222f},
+ {-0.925920f, 0.900000f, 1.779680f},
+ {-0.633613f, 0.771675f, 1.886223f},
+ {-0.638080f, 0.900000f, 1.899520f},
+ {-0.325863f, 0.771675f, 1.960420f},
+ {-0.328160f, 0.900000f, 1.974240f},
+ {0.000000f, 0.771675f, 1.986000f},
+ {-1.922910f, 0.656400f, 0.319628f},
+ {-1.948000f, 0.656400f, 0.000000f},
+ {-1.850132f, 0.656400f, 0.621490f},
+ {-1.733408f, 0.656400f, 0.901846f},
+ {-1.576477f, 0.656400f, 1.156956f},
+ {-1.383080f, 0.656400f, 1.383080f},
+ {-1.156956f, 0.656400f, 1.576477f},
+ {-0.901846f, 0.656400f, 1.733408f},
+ {-0.621490f, 0.656400f, 1.850132f},
+ {-0.319628f, 0.656400f, 1.922910f},
+ {0.000000f, 0.656400f, 1.948000f},
+ {-1.867631f, 0.553725f, 0.310439f},
+ {-1.892000f, 0.553725f, 0.000000f},
+ {-1.796946f, 0.553725f, 0.603624f},
+ {-1.683577f, 0.553725f, 0.875920f},
+ {-1.531158f, 0.553725f, 1.123697f},
+ {-1.343320f, 0.553725f, 1.343320f},
+ {-1.123697f, 0.553725f, 1.531158f},
+ {-0.875920f, 0.553725f, 1.683577f},
+ {-0.603624f, 0.553725f, 1.796946f},
+ {-0.310439f, 0.553725f, 1.867631f},
+ {0.000000f, 0.553725f, 1.892000f},
+ {-1.800507f, 0.463200f, 0.299282f},
+ {-1.824000f, 0.463200f, 0.000000f},
+ {-1.732362f, 0.463200f, 0.581929f},
+ {-1.623068f, 0.463200f, 0.844439f},
+ {-1.476127f, 0.463200f, 1.083310f},
+ {-1.295040f, 0.463200f, 1.295040f},
+ {-1.083310f, 0.463200f, 1.476127f},
+ {-0.844439f, 0.463200f, 1.623068f},
+ {-0.581929f, 0.463200f, 1.732362f},
+ {-0.299282f, 0.463200f, 1.800507f},
+ {-0.000000f, 0.463200f, 1.824000f},
+ {-1.727460f, 0.384375f, 0.287140f},
+ {-1.750000f, 0.384375f, 0.000000f},
+ {-1.662080f, 0.384375f, 0.558320f},
+ {-1.557220f, 0.384375f, 0.810180f},
+ {-1.416240f, 0.384375f, 1.039360f},
+ {-1.242500f, 0.384375f, 1.242500f},
+ {-1.039360f, 0.384375f, 1.416240f},
+ {-0.810180f, 0.384375f, 1.557220f},
+ {-0.558320f, 0.384375f, 1.662080f},
+ {-0.287140f, 0.384375f, 1.727460f},
+ {-0.000000f, 0.384375f, 1.750000f},
+ {-1.654413f, 0.316800f, 0.274998f},
+ {-1.676000f, 0.316800f, 0.000000f},
+ {-1.591798f, 0.316800f, 0.534711f},
+ {-1.491372f, 0.316800f, 0.775921f},
+ {-1.356353f, 0.316800f, 0.995410f},
+ {-1.189960f, 0.316800f, 1.189960f},
+ {-0.995410f, 0.316800f, 1.356353f},
+ {-0.775921f, 0.316800f, 1.491372f},
+ {-0.534711f, 0.316800f, 1.591798f},
+ {-0.274998f, 0.316800f, 1.654413f},
+ {0.000000f, 0.316800f, 1.676000f},
+ {-1.587289f, 0.260025f, 0.263841f},
+ {-1.608000f, 0.260025f, 0.000000f},
+ {-1.527214f, 0.260025f, 0.513016f},
+ {-1.430863f, 0.260025f, 0.744440f},
+ {-1.301322f, 0.260025f, 0.955023f},
+ {-1.141680f, 0.260025f, 1.141680f},
+ {-0.955023f, 0.260025f, 1.301322f},
+ {-0.744440f, 0.260025f, 1.430863f},
+ {-0.513016f, 0.260025f, 1.527214f},
+ {-0.263841f, 0.260025f, 1.587289f},
+ {-0.000000f, 0.260025f, 1.608000f},
+ {-1.532010f, 0.213600f, 0.254652f},
+ {-1.552000f, 0.213600f, 0.000000f},
+ {-1.474028f, 0.213600f, 0.495150f},
+ {-1.381032f, 0.213600f, 0.718514f},
+ {-1.256003f, 0.213600f, 0.921764f},
+ {-1.101920f, 0.213600f, 1.101920f},
+ {-0.921764f, 0.213600f, 1.256003f},
+ {-0.718514f, 0.213600f, 1.381032f},
+ {-0.495150f, 0.213600f, 1.474028f},
+ {-0.254652f, 0.213600f, 1.532010f},
+ {0.000000f, 0.213600f, 1.552000f},
+ {-1.494500f, 0.177075f, 0.248417f},
+ {-1.514000f, 0.177075f, 0.000000f},
+ {-1.437937f, 0.177075f, 0.483027f},
+ {-1.347218f, 0.177075f, 0.700921f},
+ {-1.225250f, 0.177075f, 0.899195f},
+ {-1.074940f, 0.177075f, 1.074940f},
+ {-0.899195f, 0.177075f, 1.225250f},
+ {-0.700921f, 0.177075f, 1.347218f},
+ {-0.483027f, 0.177075f, 1.437937f},
+ {-0.248417f, 0.177075f, 1.494500f},
+ {0.000000f, 0.177075f, 1.514000f},
+ {-1.480680f, 0.150000f, 0.246120f},
+ {-1.500000f, 0.150000f, 0.000000f},
+ {-1.424640f, 0.150000f, 0.478560f},
+ {-1.334760f, 0.150000f, 0.694440f},
+ {-1.213920f, 0.150000f, 0.890880f},
+ {-1.065000f, 0.150000f, 1.065000f},
+ {-0.890880f, 0.150000f, 1.213920f},
+ {-0.694440f, 0.150000f, 1.334760f},
+ {-0.478560f, 0.150000f, 1.424640f},
+ {-0.246120f, 0.150000f, 1.480680f},
+ {0.000000f, 0.150000f, 1.500000f},
+ {0.325863f, 0.771675f, 1.960420f},
+ {0.000000f, 0.771675f, 1.986000f},
+ {0.633613f, 0.771675f, 1.886223f},
+ {0.638080f, 0.900000f, 1.899520f},
+ {0.919439f, 0.771675f, 1.767222f},
+ {0.925920f, 0.900000f, 1.779680f},
+ {1.179525f, 0.771675f, 1.607230f},
+ {1.187840f, 0.900000f, 1.618560f},
+ {1.410060f, 0.771675f, 1.410060f},
+ {1.420000f, 0.900000f, 1.420000f},
+ {1.607230f, 0.771675f, 1.179525f},
+ {1.618560f, 0.900000f, 1.187840f},
+ {1.767222f, 0.771675f, 0.919439f},
+ {1.779680f, 0.900000f, 0.925920f},
+ {1.886223f, 0.771675f, 0.633613f},
+ {1.899520f, 0.900000f, 0.638080f},
+ {1.960420f, 0.771675f, 0.325863f},
+ {1.974240f, 0.900000f, 0.328160f},
+ {1.986000f, 0.771675f, -0.000000f},
+ {0.319628f, 0.656400f, 1.922910f},
+ {0.000000f, 0.656400f, 1.948000f},
+ {0.621490f, 0.656400f, 1.850132f},
+ {0.901846f, 0.656400f, 1.733408f},
+ {1.156956f, 0.656400f, 1.576477f},
+ {1.383080f, 0.656400f, 1.383080f},
+ {1.576477f, 0.656400f, 1.156956f},
+ {1.733408f, 0.656400f, 0.901846f},
+ {1.850132f, 0.656400f, 0.621490f},
+ {1.922910f, 0.656400f, 0.319628f},
+ {1.948000f, 0.656400f, -0.000000f},
+ {0.310439f, 0.553725f, 1.867631f},
+ {0.000000f, 0.553725f, 1.892000f},
+ {0.603624f, 0.553725f, 1.796946f},
+ {0.875920f, 0.553725f, 1.683577f},
+ {1.123697f, 0.553725f, 1.531158f},
+ {1.343320f, 0.553725f, 1.343320f},
+ {1.531158f, 0.553725f, 1.123697f},
+ {1.683577f, 0.553725f, 0.875920f},
+ {1.796946f, 0.553725f, 0.603624f},
+ {1.867631f, 0.553725f, 0.310439f},
+ {1.892000f, 0.553725f, -0.000000f},
+ {0.299282f, 0.463200f, 1.800507f},
+ {0.000000f, 0.463200f, 1.824000f},
+ {0.581929f, 0.463200f, 1.732362f},
+ {0.844439f, 0.463200f, 1.623068f},
+ {1.083310f, 0.463200f, 1.476127f},
+ {1.295040f, 0.463200f, 1.295040f},
+ {1.476127f, 0.463200f, 1.083310f},
+ {1.623068f, 0.463200f, 0.844439f},
+ {1.732362f, 0.463200f, 0.581929f},
+ {1.800507f, 0.463200f, 0.299282f},
+ {1.824000f, 0.463200f, 0.000000f},
+ {0.287140f, 0.384375f, 1.727460f},
+ {0.000000f, 0.384375f, 1.750000f},
+ {0.558320f, 0.384375f, 1.662080f},
+ {0.810180f, 0.384375f, 1.557220f},
+ {1.039360f, 0.384375f, 1.416240f},
+ {1.242500f, 0.384375f, 1.242500f},
+ {1.416240f, 0.384375f, 1.039360f},
+ {1.557220f, 0.384375f, 0.810180f},
+ {1.662080f, 0.384375f, 0.558320f},
+ {1.727460f, 0.384375f, 0.287140f},
+ {1.750000f, 0.384375f, 0.000000f},
+ {0.274998f, 0.316800f, 1.654413f},
+ {0.000000f, 0.316800f, 1.676000f},
+ {0.534711f, 0.316800f, 1.591798f},
+ {0.775921f, 0.316800f, 1.491372f},
+ {0.995410f, 0.316800f, 1.356353f},
+ {1.189960f, 0.316800f, 1.189960f},
+ {1.356353f, 0.316800f, 0.995410f},
+ {1.491372f, 0.316800f, 0.775921f},
+ {1.591798f, 0.316800f, 0.534711f},
+ {1.654413f, 0.316800f, 0.274998f},
+ {1.676000f, 0.316800f, 0.000000f},
+ {0.263841f, 0.260025f, 1.587289f},
+ {0.000000f, 0.260025f, 1.608000f},
+ {0.513016f, 0.260025f, 1.527214f},
+ {0.744440f, 0.260025f, 1.430863f},
+ {0.955023f, 0.260025f, 1.301322f},
+ {1.141680f, 0.260025f, 1.141680f},
+ {1.301322f, 0.260025f, 0.955023f},
+ {1.430863f, 0.260025f, 0.744440f},
+ {1.527214f, 0.260025f, 0.513016f},
+ {1.587289f, 0.260025f, 0.263841f},
+ {1.608000f, 0.260025f, 0.000000f},
+ {0.254652f, 0.213600f, 1.532010f},
+ {0.000000f, 0.213600f, 1.552000f},
+ {0.495150f, 0.213600f, 1.474028f},
+ {0.718514f, 0.213600f, 1.381032f},
+ {0.921764f, 0.213600f, 1.256003f},
+ {1.101920f, 0.213600f, 1.101920f},
+ {1.256003f, 0.213600f, 0.921764f},
+ {1.381032f, 0.213600f, 0.718514f},
+ {1.474028f, 0.213600f, 0.495150f},
+ {1.532010f, 0.213600f, 0.254652f},
+ {1.552000f, 0.213600f, 0.000000f},
+ {0.248417f, 0.177075f, 1.494500f},
+ {0.000000f, 0.177075f, 1.514000f},
+ {0.483027f, 0.177075f, 1.437937f},
+ {0.700921f, 0.177075f, 1.347218f},
+ {0.899195f, 0.177075f, 1.225250f},
+ {1.074940f, 0.177075f, 1.074940f},
+ {1.225250f, 0.177075f, 0.899195f},
+ {1.347218f, 0.177075f, 0.700921f},
+ {1.437937f, 0.177075f, 0.483027f},
+ {1.494500f, 0.177075f, 0.248417f},
+ {1.514000f, 0.177075f, -0.000000f},
+ {0.246120f, 0.150000f, 1.480680f},
+ {0.000000f, 0.150000f, 1.500000f},
+ {0.478560f, 0.150000f, 1.424640f},
+ {0.694440f, 0.150000f, 1.334760f},
+ {0.890880f, 0.150000f, 1.213920f},
+ {1.065000f, 0.150000f, 1.065000f},
+ {1.213920f, 0.150000f, 0.890880f},
+ {1.334760f, 0.150000f, 0.694440f},
+ {1.424640f, 0.150000f, 0.478560f},
+ {1.480680f, 0.150000f, 0.246120f},
+ {1.500000f, 0.150000f, 0.000000f},
+ {-1.800455f, 2.031069f, -0.081000f},
+ {-1.597200f, 2.031300f, -0.081000f},
+ {-1.600000f, 2.025000f, 0.000000f},
+ {-1.800900f, 2.024775f, 0.000000f},
+ {-1.799246f, 2.048152f, -0.144000f},
+ {-1.589600f, 2.048400f, -0.144000f},
+ {-1.797466f, 2.073326f, -0.189000f},
+ {-1.578400f, 2.073600f, -0.189000f},
+ {-1.795303f, 2.103896f, -0.216000f},
+ {-1.564800f, 2.104200f, -0.216000f},
+ {-1.792950f, 2.137163f, -0.225000f},
+ {-1.550000f, 2.137500f, -0.225000f},
+ {-1.790597f, 2.170429f, -0.216000f},
+ {-1.535200f, 2.170800f, -0.216000f},
+ {-1.788434f, 2.200999f, -0.189000f},
+ {-1.521600f, 2.201400f, -0.189000f},
+ {-1.786654f, 2.226173f, -0.144000f},
+ {-1.510400f, 2.226600f, -0.144000f},
+ {-1.785445f, 2.243256f, -0.081000f},
+ {-1.502800f, 2.243700f, -0.081000f},
+ {-1.785000f, 2.249550f, 0.000000f},
+ {-1.500000f, 2.250000f, 0.000000f},
+ {-1.984790f, 2.029450f, -0.081000f},
+ {-1.983200f, 2.023200f, 0.000000f},
+ {-1.989107f, 2.046413f, -0.144000f},
+ {-1.995469f, 2.071411f, -0.189000f},
+ {-2.003194f, 2.101766f, -0.216000f},
+ {-2.011600f, 2.134800f, -0.225000f},
+ {-2.020006f, 2.167834f, -0.216000f},
+ {-2.027731f, 2.198189f, -0.189000f},
+ {-2.034093f, 2.223187f, -0.144000f},
+ {-2.038410f, 2.240150f, -0.081000f},
+ {-2.040000f, 2.246400f, 0.000000f},
+ {-2.149624f, 2.025055f, -0.081000f},
+ {-2.146300f, 2.018925f, 0.000000f},
+ {-2.158645f, 2.041693f, -0.144000f},
+ {-2.171939f, 2.066213f, -0.189000f},
+ {-2.188082f, 2.095987f, -0.216000f},
+ {-2.205650f, 2.128388f, -0.225000f},
+ {-2.223218f, 2.160788f, -0.216000f},
+ {-2.239361f, 2.190562f, -0.189000f},
+ {-2.252655f, 2.215082f, -0.144000f},
+ {-2.261676f, 2.231720f, -0.081000f},
+ {-2.265000f, 2.237850f, 0.000000f},
+ {-2.294371f, 2.016497f, -0.081000f},
+ {-2.289600f, 2.010600f, 0.000000f},
+ {-2.307322f, 2.032502f, -0.144000f},
+ {-2.326406f, 2.056090f, -0.189000f},
+ {-2.349581f, 2.084731f, -0.216000f},
+ {-2.374800f, 2.115900f, -0.225000f},
+ {-2.400019f, 2.147069f, -0.216000f},
+ {-2.423194f, 2.175710f, -0.189000f},
+ {-2.442278f, 2.199298f, -0.144000f},
+ {-2.455229f, 2.215303f, -0.081000f},
+ {-2.460000f, 2.221200f, 0.000000f},
+ {-2.418450f, 2.002387f, -0.081000f},
+ {-2.412500f, 1.996875f, 0.000000f},
+ {-2.434600f, 2.017350f, -0.144000f},
+ {-2.458400f, 2.039400f, -0.189000f},
+ {-2.487300f, 2.066175f, -0.216000f},
+ {-2.518750f, 2.095312f, -0.225000f},
+ {-2.550200f, 2.124450f, -0.216000f},
+ {-2.579100f, 2.151225f, -0.189000f},
+ {-2.602900f, 2.173275f, -0.144000f},
+ {-2.619050f, 2.188238f, -0.081000f},
+ {-2.625000f, 2.193750f, 0.000000f},
+ {-2.521277f, 1.981339f, -0.081000f},
+ {-2.514400f, 1.976400f, 0.000000f},
+ {-2.539942f, 1.994746f, -0.144000f},
+ {-2.567450f, 2.014502f, -0.189000f},
+ {-2.600851f, 2.038493f, -0.216000f},
+ {-2.637200f, 2.064600f, -0.225000f},
+ {-2.673549f, 2.090707f, -0.216000f},
+ {-2.706950f, 2.114698f, -0.189000f},
+ {-2.734458f, 2.134454f, -0.144000f},
+ {-2.753123f, 2.147861f, -0.081000f},
+ {-2.760000f, 2.152800f, 0.000000f},
+ {-2.602268f, 1.951964f, -0.081000f},
+ {-2.594700f, 1.947825f, 0.000000f},
+ {-2.622811f, 1.963199f, -0.144000f},
+ {-2.653085f, 1.979755f, -0.189000f},
+ {-2.689846f, 1.999859f, -0.216000f},
+ {-2.729850f, 2.021737f, -0.225000f},
+ {-2.769854f, 2.043616f, -0.216000f},
+ {-2.806615f, 2.063720f, -0.189000f},
+ {-2.836889f, 2.080276f, -0.144000f},
+ {-2.857432f, 2.091511f, -0.081000f},
+ {-2.865000f, 2.095650f, 0.000000f},
+ {-2.660842f, 1.912874f, -0.081000f},
+ {-2.652800f, 1.909800f, 0.000000f},
+ {-2.682669f, 1.921219f, -0.144000f},
+ {-2.714835f, 1.933517f, -0.189000f},
+ {-2.753894f, 1.948450f, -0.216000f},
+ {-2.796400f, 1.964700f, -0.225000f},
+ {-2.838906f, 1.980950f, -0.216000f},
+ {-2.877965f, 1.995883f, -0.189000f},
+ {-2.910131f, 2.008181f, -0.144000f},
+ {-2.931958f, 2.016526f, -0.081000f},
+ {-2.940000f, 2.019600f, 0.000000f},
+ {-2.696413f, 1.862682f, -0.081000f},
+ {-2.688100f, 1.860975f, 0.000000f},
+ {-2.718978f, 1.867316f, -0.144000f},
+ {-2.752230f, 1.874146f, -0.189000f},
+ {-2.792609f, 1.882438f, -0.216000f},
+ {-2.836550f, 1.891463f, -0.225000f},
+ {-2.880491f, 1.900487f, -0.216000f},
+ {-2.920870f, 1.908779f, -0.189000f},
+ {-2.954122f, 1.915609f, -0.144000f},
+ {-2.976687f, 1.920243f, -0.081000f},
+ {-2.985000f, 1.921950f, 0.000000f},
+ {-2.708400f, 1.800000f, -0.081000f},
+ {-2.700000f, 1.800000f, 0.000000f},
+ {-2.731200f, 1.800000f, -0.144000f},
+ {-2.764800f, 1.800000f, -0.189000f},
+ {-2.805600f, 1.800000f, -0.216000f},
+ {-2.850000f, 1.800000f, -0.225000f},
+ {-2.894400f, 1.800000f, -0.216000f},
+ {-2.935200f, 1.800000f, -0.189000f},
+ {-2.968800f, 1.800000f, -0.144000f},
+ {-2.991600f, 1.800000f, -0.081000f},
+ {-3.000000f, 1.800000f, 0.000000f},
+ {-1.785445f, 2.243256f, 0.081000f},
+ {-1.502800f, 2.243700f, 0.081000f},
+ {-1.786654f, 2.226173f, 0.144000f},
+ {-1.510400f, 2.226600f, 0.144000f},
+ {-1.788434f, 2.200999f, 0.189000f},
+ {-1.521600f, 2.201400f, 0.189000f},
+ {-1.790597f, 2.170429f, 0.216000f},
+ {-1.535200f, 2.170800f, 0.216000f},
+ {-1.792950f, 2.137163f, 0.225000f},
+ {-1.550000f, 2.137500f, 0.225000f},
+ {-1.795303f, 2.103896f, 0.216000f},
+ {-1.564800f, 2.104200f, 0.216000f},
+ {-1.797466f, 2.073326f, 0.189000f},
+ {-1.578400f, 2.073600f, 0.189000f},
+ {-1.799246f, 2.048152f, 0.144000f},
+ {-1.589600f, 2.048400f, 0.144000f},
+ {-1.800455f, 2.031069f, 0.081000f},
+ {-1.597200f, 2.031300f, 0.081000f},
+ {-2.038410f, 2.240150f, 0.081000f},
+ {-2.040000f, 2.246400f, 0.000000f},
+ {-2.034093f, 2.223187f, 0.144000f},
+ {-2.027731f, 2.198189f, 0.189000f},
+ {-2.020006f, 2.167834f, 0.216000f},
+ {-2.011600f, 2.134800f, 0.225000f},
+ {-2.003194f, 2.101766f, 0.216000f},
+ {-1.995469f, 2.071411f, 0.189000f},
+ {-1.989107f, 2.046413f, 0.144000f},
+ {-1.984790f, 2.029450f, 0.081000f},
+ {-1.983200f, 2.023200f, 0.000000f},
+ {-2.261676f, 2.231720f, 0.081000f},
+ {-2.252655f, 2.215082f, 0.144000f},
+ {-2.239361f, 2.190562f, 0.189000f},
+ {-2.223218f, 2.160788f, 0.216000f},
+ {-2.205650f, 2.128387f, 0.225000f},
+ {-2.188082f, 2.095987f, 0.216000f},
+ {-2.171939f, 2.066213f, 0.189000f},
+ {-2.158645f, 2.041693f, 0.144000f},
+ {-2.149624f, 2.025055f, 0.081000f},
+ {-2.455229f, 2.215303f, 0.081000f},
+ {-2.460000f, 2.221200f, 0.000000f},
+ {-2.442278f, 2.199298f, 0.144000f},
+ {-2.423194f, 2.175710f, 0.189000f},
+ {-2.400019f, 2.147069f, 0.216000f},
+ {-2.374800f, 2.115900f, 0.225000f},
+ {-2.349581f, 2.084731f, 0.216000f},
+ {-2.326406f, 2.056090f, 0.189000f},
+ {-2.307322f, 2.032502f, 0.144000f},
+ {-2.294371f, 2.016497f, 0.081000f},
+ {-2.289600f, 2.010600f, 0.000000f},
+ {-2.619050f, 2.188238f, 0.081000f},
+ {-2.602900f, 2.173275f, 0.144000f},
+ {-2.579100f, 2.151225f, 0.189000f},
+ {-2.550200f, 2.124450f, 0.216000f},
+ {-2.518750f, 2.095312f, 0.225000f},
+ {-2.487300f, 2.066175f, 0.216000f},
+ {-2.458400f, 2.039400f, 0.189000f},
+ {-2.434600f, 2.017350f, 0.144000f},
+ {-2.418450f, 2.002388f, 0.081000f},
+ {-2.412500f, 1.996875f, 0.000000f},
+ {-2.753123f, 2.147861f, 0.081000f},
+ {-2.760000f, 2.152800f, 0.000000f},
+ {-2.734458f, 2.134454f, 0.144000f},
+ {-2.706950f, 2.114698f, 0.189000f},
+ {-2.673549f, 2.090707f, 0.216000f},
+ {-2.637200f, 2.064600f, 0.225000f},
+ {-2.600851f, 2.038493f, 0.216000f},
+ {-2.567450f, 2.014502f, 0.189000f},
+ {-2.539942f, 1.994746f, 0.144000f},
+ {-2.521277f, 1.981339f, 0.081000f},
+ {-2.514400f, 1.976400f, 0.000000f},
+ {-2.857432f, 2.091511f, 0.081000f},
+ {-2.836889f, 2.080276f, 0.144000f},
+ {-2.806615f, 2.063720f, 0.189000f},
+ {-2.769854f, 2.043616f, 0.216000f},
+ {-2.729850f, 2.021737f, 0.225000f},
+ {-2.689846f, 1.999859f, 0.216000f},
+ {-2.653085f, 1.979755f, 0.189000f},
+ {-2.622811f, 1.963199f, 0.144000f},
+ {-2.602268f, 1.951964f, 0.081000f},
+ {-2.931958f, 2.016526f, 0.081000f},
+ {-2.910131f, 2.008181f, 0.144000f},
+ {-2.877965f, 1.995883f, 0.189000f},
+ {-2.838906f, 1.980950f, 0.216000f},
+ {-2.796400f, 1.964700f, 0.225000f},
+ {-2.753894f, 1.948450f, 0.216000f},
+ {-2.714835f, 1.933517f, 0.189000f},
+ {-2.682669f, 1.921219f, 0.144000f},
+ {-2.660842f, 1.912874f, 0.081000f},
+ {-2.652800f, 1.909800f, 0.000000f},
+ {-2.976687f, 1.920243f, 0.081000f},
+ {-2.985000f, 1.921950f, 0.000000f},
+ {-2.954122f, 1.915609f, 0.144000f},
+ {-2.920870f, 1.908779f, 0.189000f},
+ {-2.880491f, 1.900487f, 0.216000f},
+ {-2.836550f, 1.891463f, 0.225000f},
+ {-2.792609f, 1.882438f, 0.216000f},
+ {-2.752230f, 1.874146f, 0.189000f},
+ {-2.718978f, 1.867316f, 0.144000f},
+ {-2.696413f, 1.862682f, 0.081000f},
+ {-2.688100f, 1.860975f, 0.000000f},
+ {-2.991600f, 1.800000f, 0.081000f},
+ {-2.968800f, 1.800000f, 0.144000f},
+ {-2.935200f, 1.800000f, 0.189000f},
+ {-2.894400f, 1.800000f, 0.216000f},
+ {-2.850000f, 1.800000f, 0.225000f},
+ {-2.805600f, 1.800000f, 0.216000f},
+ {-2.764800f, 1.800000f, 0.189000f},
+ {-2.731200f, 1.800000f, 0.144000f},
+ {-2.708400f, 1.800000f, 0.081000f},
+ {-2.702175f, 1.724519f, -0.081000f},
+ {-2.693900f, 1.726200f, 0.000000f},
+ {-2.724637f, 1.719956f, -0.144000f},
+ {-2.757739f, 1.713232f, -0.189000f},
+ {-2.797934f, 1.705067f, -0.216000f},
+ {-2.841675f, 1.696181f, -0.225000f},
+ {-2.885416f, 1.687296f, -0.216000f},
+ {-2.925611f, 1.679131f, -0.189000f},
+ {-2.958713f, 1.672406f, -0.144000f},
+ {-2.981175f, 1.667844f, -0.081000f},
+ {-2.989450f, 1.666162f, 0.000000f},
+ {-2.683107f, 1.638610f, -0.081000f},
+ {-2.675200f, 1.641600f, 0.000000f},
+ {-2.704570f, 1.630493f, -0.144000f},
+ {-2.736198f, 1.618531f, -0.189000f},
+ {-2.774605f, 1.604006f, -0.216000f},
+ {-2.816400f, 1.588200f, -0.225000f},
+ {-2.858195f, 1.572394f, -0.216000f},
+ {-2.896602f, 1.557869f, -0.189000f},
+ {-2.928230f, 1.545907f, -0.144000f},
+ {-2.949693f, 1.537790f, -0.081000f},
+ {-2.957600f, 1.534800f, 0.000000f},
+ {-2.650604f, 1.544903f, -0.081000f},
+ {-2.643300f, 1.548900f, 0.000000f},
+ {-2.670428f, 1.534053f, -0.144000f},
+ {-2.699644f, 1.518063f, -0.189000f},
+ {-2.735119f, 1.498648f, -0.216000f},
+ {-2.773725f, 1.477519f, -0.225000f},
+ {-2.812331f, 1.456390f, -0.216000f},
+ {-2.847806f, 1.436974f, -0.189000f},
+ {-2.877022f, 1.420985f, -0.144000f},
+ {-2.896846f, 1.410135f, -0.081000f},
+ {-2.904150f, 1.406137f, 0.000000f},
+ {-2.604074f, 1.446029f, -0.081000f},
+ {-2.597600f, 1.450800f, 0.000000f},
+ {-2.621645f, 1.433078f, -0.144000f},
+ {-2.647539f, 1.413994f, -0.189000f},
+ {-2.678982f, 1.390819f, -0.216000f},
+ {-2.713200f, 1.365600f, -0.225000f},
+ {-2.747418f, 1.340381f, -0.216000f},
+ {-2.778861f, 1.317206f, -0.189000f},
+ {-2.804755f, 1.298122f, -0.144000f},
+ {-2.822326f, 1.285171f, -0.081000f},
+ {-2.828800f, 1.280400f, 0.000000f},
+ {-2.542925f, 1.344619f, -0.081000f},
+ {-2.537500f, 1.350000f, 0.000000f},
+ {-2.557650f, 1.330013f, -0.144000f},
+ {-2.579350f, 1.308488f, -0.189000f},
+ {-2.605700f, 1.282350f, -0.216000f},
+ {-2.634375f, 1.253906f, -0.225000f},
+ {-2.663050f, 1.225463f, -0.216000f},
+ {-2.689400f, 1.199325f, -0.189000f},
+ {-2.711100f, 1.177800f, -0.144000f},
+ {-2.725825f, 1.163194f, -0.081000f},
+ {-2.731250f, 1.157813f, 0.000000f},
+ {-2.466566f, 1.243303f, -0.081000f},
+ {-2.462400f, 1.249200f, 0.000000f},
+ {-2.477875f, 1.227298f, -0.144000f},
+ {-2.494541f, 1.203710f, -0.189000f},
+ {-2.514778f, 1.175069f, -0.216000f},
+ {-2.536800f, 1.143900f, -0.225000f},
+ {-2.558822f, 1.112731f, -0.216000f},
+ {-2.579059f, 1.084090f, -0.189000f},
+ {-2.595725f, 1.060502f, -0.144000f},
+ {-2.607034f, 1.044497f, -0.081000f},
+ {-2.611200f, 1.038600f, 0.000000f},
+ {-2.374406f, 1.144713f, -0.081000f},
+ {-2.371700f, 1.151100f, 0.000000f},
+ {-2.381752f, 1.127376f, -0.144000f},
+ {-2.392576f, 1.101828f, -0.189000f},
+ {-2.405721f, 1.070804f, -0.216000f},
+ {-2.420025f, 1.037044f, -0.225000f},
+ {-2.434329f, 1.003283f, -0.216000f},
+ {-2.447474f, 0.972260f, -0.189000f},
+ {-2.458298f, 0.946711f, -0.144000f},
+ {-2.465644f, 0.929375f, -0.081000f},
+ {-2.468350f, 0.922987f, 0.000000f},
+ {-2.265853f, 1.051478f, -0.081000f},
+ {-2.264800f, 1.058400f, 0.000000f},
+ {-2.268710f, 1.032691f, -0.144000f},
+ {-2.272922f, 1.005005f, -0.189000f},
+ {-2.278035f, 0.971386f, -0.216000f},
+ {-2.283600f, 0.934800f, -0.225000f},
+ {-2.289165f, 0.898214f, -0.216000f},
+ {-2.294278f, 0.864595f, -0.189000f},
+ {-2.298490f, 0.836909f, -0.144000f},
+ {-2.301347f, 0.818122f, -0.081000f},
+ {-2.302400f, 0.811200f, 0.000000f},
+ {-2.140315f, 0.966231f, -0.081000f},
+ {-2.141100f, 0.973800f, 0.000000f},
+ {-2.138183f, 0.945685f, -0.144000f},
+ {-2.135041f, 0.915407f, -0.189000f},
+ {-2.131226f, 0.878641f, -0.216000f},
+ {-2.127075f, 0.838631f, -0.225000f},
+ {-2.122924f, 0.798621f, -0.216000f},
+ {-2.119109f, 0.761855f, -0.189000f},
+ {-2.115967f, 0.731578f, -0.144000f},
+ {-2.113835f, 0.711032f, -0.081000f},
+ {-2.113050f, 0.703463f, 0.000000f},
+ {-1.997200f, 0.891600f, -0.081000f},
+ {-1.989600f, 0.868800f, -0.144000f},
+ {-1.978400f, 0.835200f, -0.189000f},
+ {-1.964800f, 0.794400f, -0.216000f},
+ {-1.950000f, 0.750000f, -0.225000f},
+ {-1.935200f, 0.705600f, -0.216000f},
+ {-1.921600f, 0.664800f, -0.189000f},
+ {-1.910400f, 0.631200f, -0.144000f},
+ {-1.902800f, 0.608400f, -0.081000f},
+ {-1.900000f, 0.600000f, 0.000000f},
+ {-2.981175f, 1.667844f, 0.081000f},
+ {-2.958713f, 1.672406f, 0.144000f},
+ {-2.925611f, 1.679131f, 0.189000f},
+ {-2.885416f, 1.687296f, 0.216000f},
+ {-2.841675f, 1.696181f, 0.225000f},
+ {-2.797934f, 1.705067f, 0.216000f},
+ {-2.757739f, 1.713232f, 0.189000f},
+ {-2.724637f, 1.719956f, 0.144000f},
+ {-2.702175f, 1.724519f, 0.081000f},
+ {-2.949693f, 1.537790f, 0.081000f},
+ {-2.957600f, 1.534800f, 0.000000f},
+ {-2.928230f, 1.545907f, 0.144000f},
+ {-2.896602f, 1.557869f, 0.189000f},
+ {-2.858195f, 1.572394f, 0.216000f},
+ {-2.816400f, 1.588200f, 0.225000f},
+ {-2.774605f, 1.604006f, 0.216000f},
+ {-2.736198f, 1.618531f, 0.189000f},
+ {-2.704570f, 1.630493f, 0.144000f},
+ {-2.683107f, 1.638610f, 0.081000f},
+ {-2.675200f, 1.641600f, 0.000000f},
+ {-2.896846f, 1.410135f, 0.081000f},
+ {-2.904150f, 1.406137f, 0.000000f},
+ {-2.877022f, 1.420985f, 0.144000f},
+ {-2.847806f, 1.436974f, 0.189000f},
+ {-2.812331f, 1.456390f, 0.216000f},
+ {-2.773725f, 1.477519f, 0.225000f},
+ {-2.735119f, 1.498648f, 0.216000f},
+ {-2.699644f, 1.518063f, 0.189000f},
+ {-2.670428f, 1.534053f, 0.144000f},
+ {-2.650604f, 1.544903f, 0.081000f},
+ {-2.822326f, 1.285171f, 0.081000f},
+ {-2.804755f, 1.298122f, 0.144000f},
+ {-2.778861f, 1.317206f, 0.189000f},
+ {-2.747418f, 1.340381f, 0.216000f},
+ {-2.713200f, 1.365600f, 0.225000f},
+ {-2.678982f, 1.390819f, 0.216000f},
+ {-2.647539f, 1.413994f, 0.189000f},
+ {-2.621645f, 1.433078f, 0.144000f},
+ {-2.604074f, 1.446029f, 0.081000f},
+ {-2.725825f, 1.163194f, 0.081000f},
+ {-2.731250f, 1.157813f, 0.000000f},
+ {-2.711100f, 1.177800f, 0.144000f},
+ {-2.689400f, 1.199325f, 0.189000f},
+ {-2.663050f, 1.225463f, 0.216000f},
+ {-2.634375f, 1.253906f, 0.225000f},
+ {-2.605700f, 1.282350f, 0.216000f},
+ {-2.579350f, 1.308488f, 0.189000f},
+ {-2.557650f, 1.330013f, 0.144000f},
+ {-2.542925f, 1.344619f, 0.081000f},
+ {-2.537500f, 1.350000f, 0.000000f},
+ {-2.607034f, 1.044497f, 0.081000f},
+ {-2.611200f, 1.038600f, 0.000000f},
+ {-2.595725f, 1.060502f, 0.144000f},
+ {-2.579059f, 1.084090f, 0.189000f},
+ {-2.558822f, 1.112731f, 0.216000f},
+ {-2.536800f, 1.143900f, 0.225000f},
+ {-2.514778f, 1.175069f, 0.216000f},
+ {-2.494541f, 1.203710f, 0.189000f},
+ {-2.477875f, 1.227298f, 0.144000f},
+ {-2.466566f, 1.243303f, 0.081000f},
+ {-2.462400f, 1.249200f, 0.000000f},
+ {-2.465644f, 0.929375f, 0.081000f},
+ {-2.458298f, 0.946711f, 0.144000f},
+ {-2.447474f, 0.972260f, 0.189000f},
+ {-2.434329f, 1.003283f, 0.216000f},
+ {-2.420025f, 1.037044f, 0.225000f},
+ {-2.405721f, 1.070804f, 0.216000f},
+ {-2.392576f, 1.101828f, 0.189000f},
+ {-2.381752f, 1.127376f, 0.144000f},
+ {-2.374406f, 1.144713f, 0.081000f},
+ {-2.301347f, 0.818122f, 0.081000f},
+ {-2.302400f, 0.811200f, 0.000000f},
+ {-2.298490f, 0.836909f, 0.144000f},
+ {-2.294278f, 0.864595f, 0.189000f},
+ {-2.289165f, 0.898214f, 0.216000f},
+ {-2.283600f, 0.934800f, 0.225000f},
+ {-2.278035f, 0.971386f, 0.216000f},
+ {-2.272922f, 1.005005f, 0.189000f},
+ {-2.268710f, 1.032691f, 0.144000f},
+ {-2.265853f, 1.051478f, 0.081000f},
+ {-2.264800f, 1.058400f, 0.000000f},
+ {-2.113835f, 0.711032f, 0.081000f},
+ {-2.113050f, 0.703463f, 0.000000f},
+ {-2.115967f, 0.731578f, 0.144000f},
+ {-2.119109f, 0.761855f, 0.189000f},
+ {-2.122924f, 0.798621f, 0.216000f},
+ {-2.127075f, 0.838631f, 0.225000f},
+ {-2.131226f, 0.878641f, 0.216000f},
+ {-2.135041f, 0.915407f, 0.189000f},
+ {-2.138183f, 0.945685f, 0.144000f},
+ {-2.140315f, 0.966231f, 0.081000f},
+ {-2.141100f, 0.973800f, 0.000000f},
+ {-1.902800f, 0.608400f, 0.081000f},
+ {-1.900000f, 0.600000f, 0.000000f},
+ {-1.910400f, 0.631200f, 0.144000f},
+ {-1.921600f, 0.664800f, 0.189000f},
+ {-1.935200f, 0.705600f, 0.216000f},
+ {-1.950000f, 0.750000f, 0.225000f},
+ {-1.964800f, 0.794400f, 0.216000f},
+ {-1.978400f, 0.835200f, 0.189000f},
+ {-1.989600f, 0.868800f, 0.144000f},
+ {-1.997200f, 0.891600f, 0.081000f},
+ {-2.000000f, 0.900000f, 0.000000f},
+ {1.939394f, 1.423221f, -0.175100f},
+ {1.700000f, 1.401900f, -0.178200f},
+ {1.700000f, 1.425000f, 0.000000f},
+ {1.935900f, 1.444200f, 0.000000f},
+ {1.948879f, 1.366278f, -0.311290f},
+ {1.700000f, 1.339200f, -0.316800f},
+ {1.962857f, 1.282362f, -0.408568f},
+ {1.700000f, 1.246800f, -0.415800f},
+ {1.979830f, 1.180464f, -0.466934f},
+ {1.700000f, 1.134600f, -0.475200f},
+ {1.998300f, 1.069575f, -0.486390f},
+ {1.700000f, 1.012500f, -0.495000f},
+ {2.016770f, 0.958686f, -0.466934f},
+ {1.700000f, 0.890400f, -0.475200f},
+ {2.033743f, 0.856788f, -0.408568f},
+ {1.700000f, 0.778200f, -0.415800f},
+ {2.047721f, 0.772872f, -0.311290f},
+ {1.700000f, 0.685800f, -0.316800f},
+ {2.057206f, 0.715929f, -0.175100f},
+ {1.700000f, 0.623100f, -0.178200f},
+ {2.060700f, 0.694950f, 0.000000f},
+ {1.700000f, 0.600000f, 0.000000f},
+ {2.116979f, 1.479120f, -0.166687f},
+ {2.111200f, 1.497600f, 0.000000f},
+ {2.132666f, 1.428960f, -0.296333f},
+ {2.155782f, 1.355040f, -0.388937f},
+ {2.183853f, 1.265280f, -0.444499f},
+ {2.214400f, 1.167600f, -0.463020f},
+ {2.244947f, 1.069920f, -0.444499f},
+ {2.273018f, 0.980160f, -0.388937f},
+ {2.296134f, 0.906240f, -0.296333f},
+ {2.311821f, 0.856080f, -0.166687f},
+ {2.317600f, 0.837600f, 0.000000f},
+ {2.244457f, 1.563171f, -0.154289f},
+ {2.237300f, 1.578900f, 0.000000f},
+ {2.263882f, 1.520478f, -0.274291f},
+ {2.292510f, 1.457562f, -0.360007f},
+ {2.327271f, 1.381164f, -0.411437f},
+ {2.365100f, 1.298025f, -0.428580f},
+ {2.402929f, 1.214886f, -0.411437f},
+ {2.437690f, 1.138488f, -0.360007f},
+ {2.466318f, 1.075572f, -0.274291f},
+ {2.485743f, 1.032879f, -0.154289f},
+ {2.492900f, 1.017150f, 0.000000f},
+ {2.333530f, 1.668948f, -0.139234f},
+ {2.325600f, 1.681800f, 0.000000f},
+ {2.355053f, 1.634064f, -0.247526f},
+ {2.386771f, 1.582656f, -0.324878f},
+ {2.425286f, 1.520232f, -0.371290f},
+ {2.467200f, 1.452300f, -0.386760f},
+ {2.509114f, 1.384368f, -0.371290f},
+ {2.547629f, 1.321944f, -0.324878f},
+ {2.579347f, 1.270536f, -0.247526f},
+ {2.600870f, 1.235652f, -0.139234f},
+ {2.608800f, 1.222800f, 0.000000f},
+ {2.395900f, 1.790025f, -0.122850f},
+ {2.387500f, 1.800000f, 0.000000f},
+ {2.418700f, 1.762950f, -0.218400f},
+ {2.452300f, 1.723050f, -0.286650f},
+ {2.493100f, 1.674600f, -0.327600f},
+ {2.537500f, 1.621875f, -0.341250f},
+ {2.581900f, 1.569150f, -0.327600f},
+ {2.622700f, 1.520700f, -0.286650f},
+ {2.656300f, 1.480800f, -0.218400f},
+ {2.679100f, 1.453725f, -0.122850f},
+ {2.687500f, 1.443750f, 0.000000f},
+ {2.443270f, 1.919976f, -0.106466f},
+ {2.434400f, 1.927200f, 0.000000f},
+ {2.467347f, 1.900368f, -0.189274f},
+ {2.502829f, 1.871472f, -0.248422f},
+ {2.545914f, 1.836384f, -0.283910f},
+ {2.592800f, 1.798200f, -0.295740f},
+ {2.639686f, 1.760016f, -0.283910f},
+ {2.682771f, 1.724928f, -0.248422f},
+ {2.718253f, 1.696032f, -0.189274f},
+ {2.742330f, 1.676424f, -0.106466f},
+ {2.751200f, 1.669200f, 0.000000f},
+ {2.487343f, 2.052375f, -0.091411f},
+ {2.477700f, 2.057100f, 0.000000f},
+ {2.513518f, 2.039550f, -0.162509f},
+ {2.552090f, 2.020650f, -0.213293f},
+ {2.598929f, 1.997700f, -0.243763f},
+ {2.649900f, 1.972725f, -0.253920f},
+ {2.700871f, 1.947750f, -0.243763f},
+ {2.747710f, 1.924800f, -0.213293f},
+ {2.786282f, 1.905900f, -0.162509f},
+ {2.812457f, 1.893075f, -0.091411f},
+ {2.822100f, 1.888350f, 0.000000f},
+ {2.539821f, 2.180796f, -0.079013f},
+ {2.528800f, 2.183400f, 0.000000f},
+ {2.569734f, 2.173728f, -0.140467f},
+ {2.613818f, 2.163312f, -0.184363f},
+ {2.667347f, 2.150664f, -0.210701f},
+ {2.725600f, 2.136900f, -0.219480f},
+ {2.783853f, 2.123136f, -0.210701f},
+ {2.837382f, 2.110488f, -0.184363f},
+ {2.881466f, 2.100072f, -0.140467f},
+ {2.911379f, 2.093004f, -0.079013f},
+ {2.922400f, 2.090400f, 0.000000f},
+ {2.612406f, 2.298813f, -0.070600f},
+ {2.599100f, 2.299800f, 0.000000f},
+ {2.648521f, 2.296134f, -0.125510f},
+ {2.701743f, 2.292186f, -0.164732f},
+ {2.766370f, 2.287392f, -0.188266f},
+ {2.836700f, 2.282175f, -0.196110f},
+ {2.907030f, 2.276958f, -0.188266f},
+ {2.971657f, 2.272164f, -0.164732f},
+ {3.024879f, 2.268216f, -0.125510f},
+ {3.060994f, 2.265537f, -0.070600f},
+ {3.074300f, 2.264550f, 0.000000f},
+ {2.716800f, 2.400000f, -0.067500f},
+ {2.700000f, 2.400000f, 0.000000f},
+ {2.762400f, 2.400000f, -0.120000f},
+ {2.829600f, 2.400000f, -0.157500f},
+ {2.911200f, 2.400000f, -0.180000f},
+ {3.000000f, 2.400000f, -0.187500f},
+ {3.088800f, 2.400000f, -0.180000f},
+ {3.170400f, 2.400000f, -0.157500f},
+ {3.237600f, 2.400000f, -0.120000f},
+ {3.283200f, 2.400000f, -0.067500f},
+ {3.300000f, 2.400000f, 0.000000f},
+ {2.057206f, 0.715929f, 0.175100f},
+ {1.700000f, 0.623100f, 0.178200f},
+ {1.700000f, 0.600000f, 0.000000f},
+ {2.060700f, 0.694950f, 0.000000f},
+ {2.047721f, 0.772872f, 0.311290f},
+ {1.700000f, 0.685800f, 0.316800f},
+ {2.033743f, 0.856788f, 0.408568f},
+ {1.700000f, 0.778200f, 0.415800f},
+ {2.016770f, 0.958686f, 0.466934f},
+ {1.700000f, 0.890400f, 0.475200f},
+ {1.998300f, 1.069575f, 0.486390f},
+ {1.700000f, 1.012500f, 0.495000f},
+ {1.979830f, 1.180464f, 0.466934f},
+ {1.700000f, 1.134600f, 0.475200f},
+ {1.962857f, 1.282362f, 0.408568f},
+ {1.700000f, 1.246800f, 0.415800f},
+ {1.948879f, 1.366278f, 0.311290f},
+ {1.700000f, 1.339200f, 0.316800f},
+ {1.939394f, 1.423221f, 0.175100f},
+ {1.700000f, 1.401900f, 0.178200f},
+ {1.935900f, 1.444200f, 0.000000f},
+ {1.700000f, 1.425000f, 0.000000f},
+ {2.311821f, 0.856080f, 0.166687f},
+ {2.317600f, 0.837600f, 0.000000f},
+ {2.296134f, 0.906240f, 0.296333f},
+ {2.273018f, 0.980160f, 0.388937f},
+ {2.244947f, 1.069920f, 0.444499f},
+ {2.214400f, 1.167600f, 0.463020f},
+ {2.183853f, 1.265280f, 0.444499f},
+ {2.155782f, 1.355040f, 0.388937f},
+ {2.132666f, 1.428960f, 0.296333f},
+ {2.116979f, 1.479120f, 0.166687f},
+ {2.111200f, 1.497600f, 0.000000f},
+ {2.485743f, 1.032879f, 0.154289f},
+ {2.492900f, 1.017150f, 0.000000f},
+ {2.466318f, 1.075572f, 0.274291f},
+ {2.437690f, 1.138488f, 0.360007f},
+ {2.402929f, 1.214886f, 0.411437f},
+ {2.365100f, 1.298025f, 0.428580f},
+ {2.327271f, 1.381164f, 0.411437f},
+ {2.292510f, 1.457562f, 0.360007f},
+ {2.263882f, 1.520478f, 0.274291f},
+ {2.244457f, 1.563171f, 0.154289f},
+ {2.237300f, 1.578900f, 0.000000f},
+ {2.600870f, 1.235652f, 0.139234f},
+ {2.608800f, 1.222800f, 0.000000f},
+ {2.579347f, 1.270536f, 0.247526f},
+ {2.547629f, 1.321944f, 0.324878f},
+ {2.509114f, 1.384368f, 0.371290f},
+ {2.467200f, 1.452300f, 0.386760f},
+ {2.425286f, 1.520232f, 0.371290f},
+ {2.386771f, 1.582656f, 0.324878f},
+ {2.355053f, 1.634064f, 0.247526f},
+ {2.333530f, 1.668948f, 0.139234f},
+ {2.325600f, 1.681800f, 0.000000f},
+ {2.679100f, 1.453725f, 0.122850f},
+ {2.687500f, 1.443750f, 0.000000f},
+ {2.656300f, 1.480800f, 0.218400f},
+ {2.622700f, 1.520700f, 0.286650f},
+ {2.581900f, 1.569150f, 0.327600f},
+ {2.537500f, 1.621875f, 0.341250f},
+ {2.493100f, 1.674600f, 0.327600f},
+ {2.452300f, 1.723050f, 0.286650f},
+ {2.418700f, 1.762950f, 0.218400f},
+ {2.395900f, 1.790025f, 0.122850f},
+ {2.387500f, 1.800000f, 0.000000f},
+ {2.742330f, 1.676424f, 0.106466f},
+ {2.751200f, 1.669200f, 0.000000f},
+ {2.718253f, 1.696032f, 0.189274f},
+ {2.682771f, 1.724928f, 0.248422f},
+ {2.639686f, 1.760016f, 0.283910f},
+ {2.592800f, 1.798200f, 0.295740f},
+ {2.545914f, 1.836384f, 0.283910f},
+ {2.502829f, 1.871472f, 0.248422f},
+ {2.467347f, 1.900368f, 0.189274f},
+ {2.443270f, 1.919976f, 0.106466f},
+ {2.434400f, 1.927200f, 0.000000f},
+ {2.812457f, 1.893075f, 0.091411f},
+ {2.822100f, 1.888350f, 0.000000f},
+ {2.786282f, 1.905900f, 0.162509f},
+ {2.747710f, 1.924800f, 0.213293f},
+ {2.700871f, 1.947750f, 0.243763f},
+ {2.649900f, 1.972725f, 0.253920f},
+ {2.598929f, 1.997700f, 0.243763f},
+ {2.552090f, 2.020650f, 0.213293f},
+ {2.513518f, 2.039550f, 0.162509f},
+ {2.487343f, 2.052375f, 0.091411f},
+ {2.477700f, 2.057100f, 0.000000f},
+ {2.911379f, 2.093004f, 0.079013f},
+ {2.881466f, 2.100072f, 0.140467f},
+ {2.837382f, 2.110488f, 0.184363f},
+ {2.783853f, 2.123136f, 0.210701f},
+ {2.725600f, 2.136900f, 0.219480f},
+ {2.667347f, 2.150664f, 0.210701f},
+ {2.613818f, 2.163312f, 0.184363f},
+ {2.569734f, 2.173728f, 0.140467f},
+ {2.539821f, 2.180796f, 0.079013f},
+ {3.060994f, 2.265537f, 0.070600f},
+ {3.074300f, 2.264550f, 0.000000f},
+ {3.024879f, 2.268216f, 0.125510f},
+ {2.971657f, 2.272164f, 0.164732f},
+ {2.907030f, 2.276958f, 0.188266f},
+ {2.836700f, 2.282175f, 0.196110f},
+ {2.766370f, 2.287392f, 0.188266f},
+ {2.701743f, 2.292186f, 0.164732f},
+ {2.648521f, 2.296134f, 0.125510f},
+ {2.612406f, 2.298813f, 0.070600f},
+ {2.599100f, 2.299800f, 0.000000f},
+ {3.283200f, 2.400000f, 0.067500f},
+ {3.300000f, 2.400000f, 0.000000f},
+ {3.237600f, 2.400000f, 0.120000f},
+ {3.170400f, 2.400000f, 0.157500f},
+ {3.088800f, 2.400000f, 0.180000f},
+ {3.000000f, 2.400000f, 0.187500f},
+ {2.911200f, 2.400000f, 0.180000f},
+ {2.829600f, 2.400000f, 0.157500f},
+ {2.762400f, 2.400000f, 0.120000f},
+ {2.716800f, 2.400000f, 0.067500f},
+ {2.700000f, 2.400000f, 0.000000f},
+ {2.747407f, 2.420406f, -0.066744f},
+ {2.716800f, 2.400000f, -0.067500f},
+ {2.700000f, 2.400000f, 0.000000f},
+ {2.729800f, 2.420250f, 0.000000f},
+ {2.795198f, 2.420829f, -0.118656f},
+ {2.762400f, 2.400000f, -0.120000f},
+ {2.865626f, 2.421453f, -0.155736f},
+ {2.829600f, 2.400000f, -0.157500f},
+ {2.951146f, 2.422210f, -0.177984f},
+ {2.911200f, 2.400000f, -0.180000f},
+ {3.044212f, 2.423034f, -0.185400f},
+ {3.000000f, 2.400000f, -0.187500f},
+ {3.137279f, 2.423859f, -0.177984f},
+ {3.088800f, 2.400000f, -0.180000f},
+ {3.222799f, 2.424616f, -0.155736f},
+ {3.170400f, 2.400000f, -0.157500f},
+ {3.293227f, 2.425240f, -0.118656f},
+ {3.237600f, 2.400000f, -0.120000f},
+ {3.341018f, 2.425663f, -0.066744f},
+ {3.283200f, 2.400000f, -0.067500f},
+ {3.358625f, 2.425819f, 0.000000f},
+ {2.776365f, 2.436302f, -0.064692f},
+ {2.758400f, 2.436000f, 0.000000f},
+ {2.825126f, 2.437123f, -0.115008f},
+ {2.896986f, 2.438333f, -0.150948f},
+ {2.984243f, 2.439802f, -0.172512f},
+ {3.079200f, 2.441400f, -0.179700f},
+ {3.174157f, 2.442998f, -0.172512f},
+ {3.261414f, 2.444467f, -0.150948f},
+ {3.333274f, 2.445677f, -0.115008f},
+ {3.382035f, 2.446498f, -0.064692f},
+ {3.400000f, 2.446800f, 0.000000f},
+ {2.802528f, 2.447680f, -0.061668f},
+ {2.784600f, 2.447250f, 0.000000f},
+ {2.851189f, 2.448847f, -0.109632f},
+ {2.922899f, 2.450567f, -0.143892f},
+ {3.009977f, 2.452655f, -0.164448f},
+ {3.104737f, 2.454928f, -0.171300f},
+ {3.199498f, 2.457201f, -0.164448f},
+ {3.286576f, 2.459289f, -0.143892f},
+ {3.358286f, 2.461009f, -0.109632f},
+ {3.406947f, 2.462176f, -0.061668f},
+ {3.424875f, 2.462606f, 0.000000f},
+ {2.824750f, 2.454529f, -0.057996f},
+ {2.807200f, 2.454000f, 0.000000f},
+ {2.872387f, 2.455966f, -0.103104f},
+ {2.942589f, 2.458082f, -0.135324f},
+ {3.027834f, 2.460653f, -0.154656f},
+ {3.120600f, 2.463450f, -0.161100f},
+ {3.213366f, 2.466247f, -0.154656f},
+ {3.298611f, 2.468818f, -0.135324f},
+ {3.368813f, 2.470934f, -0.103104f},
+ {3.416450f, 2.472371f, -0.057996f},
+ {3.434000f, 2.472900f, 0.000000f},
+ {2.841887f, 2.456841f, -0.054000f},
+ {2.825000f, 2.456250f, 0.000000f},
+ {2.887725f, 2.458444f, -0.096000f},
+ {2.955275f, 2.460806f, -0.126000f},
+ {3.037300f, 2.463675f, -0.144000f},
+ {3.126562f, 2.466797f, -0.150000f},
+ {3.215825f, 2.469919f, -0.144000f},
+ {3.297850f, 2.472787f, -0.126000f},
+ {3.365400f, 2.475150f, -0.096000f},
+ {3.411237f, 2.476753f, -0.054000f},
+ {3.428125f, 2.477344f, 0.000000f},
+ {2.852794f, 2.454605f, -0.050004f},
+ {2.836800f, 2.454000f, 0.000000f},
+ {2.896205f, 2.456246f, -0.088896f},
+ {2.960179f, 2.458666f, -0.116676f},
+ {3.037862f, 2.461603f, -0.133344f},
+ {3.122400f, 2.464800f, -0.138900f},
+ {3.206938f, 2.467997f, -0.133344f},
+ {3.284621f, 2.470934f, -0.116676f},
+ {3.348595f, 2.473354f, -0.088896f},
+ {3.392006f, 2.474995f, -0.050004f},
+ {3.408000f, 2.475600f, 0.000000f},
+ {2.856323f, 2.447812f, -0.046332f},
+ {2.841400f, 2.447250f, 0.000000f},
+ {2.896829f, 2.449338f, -0.082368f},
+ {2.956523f, 2.451588f, -0.108108f},
+ {3.029007f, 2.454319f, -0.123552f},
+ {3.107887f, 2.457291f, -0.128700f},
+ {3.186768f, 2.460263f, -0.123552f},
+ {3.259252f, 2.462994f, -0.108108f},
+ {3.318946f, 2.465243f, -0.082368f},
+ {3.359452f, 2.466769f, -0.046332f},
+ {3.374375f, 2.467331f, 0.000000f},
+ {2.851331f, 2.436454f, -0.043308f},
+ {2.837600f, 2.436000f, 0.000000f},
+ {2.888602f, 2.437685f, -0.076992f},
+ {2.943526f, 2.439499f, -0.101052f},
+ {3.010221f, 2.441702f, -0.115488f},
+ {3.082800f, 2.444100f, -0.120300f},
+ {3.155379f, 2.446498f, -0.115488f},
+ {3.222074f, 2.448701f, -0.101052f},
+ {3.276998f, 2.450515f, -0.076992f},
+ {3.314269f, 2.451746f, -0.043308f},
+ {3.328000f, 2.452200f, 0.000000f},
+ {2.836672f, 2.420519f, -0.041256f},
+ {2.824200f, 2.420250f, 0.000000f},
+ {2.870524f, 2.421250f, -0.073344f},
+ {2.920412f, 2.422328f, -0.096264f},
+ {2.980990f, 2.423636f, -0.110016f},
+ {3.046912f, 2.425059f, -0.114600f},
+ {3.112835f, 2.426483f, -0.110016f},
+ {3.173413f, 2.427791f, -0.096264f},
+ {3.223301f, 2.428868f, -0.073344f},
+ {3.257153f, 2.429599f, -0.041256f},
+ {3.269625f, 2.429869f, 0.000000f},
+ {2.811200f, 2.400000f, -0.040500f},
+ {2.800000f, 2.400000f, 0.000000f},
+ {2.841600f, 2.400000f, -0.072000f},
+ {2.886400f, 2.400000f, -0.094500f},
+ {2.940800f, 2.400000f, -0.108000f},
+ {3.000000f, 2.400000f, -0.112500f},
+ {3.059200f, 2.400000f, -0.108000f},
+ {3.113600f, 2.400000f, -0.094500f},
+ {3.158400f, 2.400000f, -0.072000f},
+ {3.188800f, 2.400000f, -0.040500f},
+ {3.200000f, 2.400000f, 0.000000f},
+ {3.341018f, 2.425663f, 0.066744f},
+ {3.293227f, 2.425240f, 0.118656f},
+ {3.222799f, 2.424616f, 0.155736f},
+ {3.137279f, 2.423859f, 0.177984f},
+ {3.044212f, 2.423034f, 0.185400f},
+ {2.951146f, 2.422210f, 0.177984f},
+ {2.865626f, 2.421453f, 0.155736f},
+ {2.829600f, 2.400000f, 0.157500f},
+ {2.795198f, 2.420829f, 0.118656f},
+ {2.762400f, 2.400000f, 0.120000f},
+ {2.747407f, 2.420406f, 0.066744f},
+ {2.716800f, 2.400000f, 0.067500f},
+ {3.382035f, 2.446498f, 0.064692f},
+ {3.333274f, 2.445677f, 0.115008f},
+ {3.261414f, 2.444467f, 0.150948f},
+ {3.174157f, 2.442998f, 0.172512f},
+ {3.079200f, 2.441400f, 0.179700f},
+ {2.984243f, 2.439802f, 0.172512f},
+ {2.896986f, 2.438333f, 0.150948f},
+ {2.825126f, 2.437123f, 0.115008f},
+ {2.776365f, 2.436302f, 0.064692f},
+ {3.406947f, 2.462176f, 0.061668f},
+ {3.358286f, 2.461009f, 0.109632f},
+ {3.286576f, 2.459289f, 0.143892f},
+ {3.199498f, 2.457201f, 0.164448f},
+ {3.104738f, 2.454928f, 0.171300f},
+ {3.009977f, 2.452655f, 0.164448f},
+ {2.922899f, 2.450567f, 0.143892f},
+ {2.851189f, 2.448847f, 0.109632f},
+ {2.802528f, 2.447680f, 0.061668f},
+ {2.784600f, 2.447250f, 0.000000f},
+ {3.416450f, 2.472371f, 0.057996f},
+ {3.368813f, 2.470934f, 0.103104f},
+ {3.298611f, 2.468818f, 0.135324f},
+ {3.213366f, 2.466247f, 0.154656f},
+ {3.120600f, 2.463450f, 0.161100f},
+ {3.027834f, 2.460653f, 0.154656f},
+ {2.942589f, 2.458082f, 0.135324f},
+ {2.872387f, 2.455966f, 0.103104f},
+ {2.824750f, 2.454529f, 0.057996f},
+ {3.411237f, 2.476753f, 0.054000f},
+ {3.428125f, 2.477344f, 0.000000f},
+ {3.365400f, 2.475150f, 0.096000f},
+ {3.297850f, 2.472788f, 0.126000f},
+ {3.215825f, 2.469919f, 0.144000f},
+ {3.126562f, 2.466797f, 0.150000f},
+ {3.037300f, 2.463675f, 0.144000f},
+ {2.955275f, 2.460806f, 0.126000f},
+ {2.887725f, 2.458444f, 0.096000f},
+ {2.841887f, 2.456841f, 0.054000f},
+ {2.825000f, 2.456250f, 0.000000f},
+ {3.392006f, 2.474995f, 0.050004f},
+ {3.408000f, 2.475600f, 0.000000f},
+ {3.348595f, 2.473354f, 0.088896f},
+ {3.284621f, 2.470934f, 0.116676f},
+ {3.206938f, 2.467997f, 0.133344f},
+ {3.122400f, 2.464800f, 0.138900f},
+ {3.037862f, 2.461603f, 0.133344f},
+ {2.960179f, 2.458666f, 0.116676f},
+ {2.896205f, 2.456246f, 0.088896f},
+ {2.852794f, 2.454605f, 0.050004f},
+ {2.836800f, 2.454000f, 0.000000f},
+ {3.359452f, 2.466769f, 0.046332f},
+ {3.374375f, 2.467331f, 0.000000f},
+ {3.318946f, 2.465243f, 0.082368f},
+ {3.259252f, 2.462994f, 0.108108f},
+ {3.186768f, 2.460263f, 0.123552f},
+ {3.107887f, 2.457291f, 0.128700f},
+ {3.029007f, 2.454319f, 0.123552f},
+ {2.956523f, 2.451588f, 0.108108f},
+ {2.896829f, 2.449338f, 0.082368f},
+ {2.856323f, 2.447812f, 0.046332f},
+ {2.841400f, 2.447250f, 0.000000f},
+ {3.314269f, 2.451746f, 0.043308f},
+ {3.328000f, 2.452200f, 0.000000f},
+ {3.276998f, 2.450515f, 0.076992f},
+ {3.222074f, 2.448701f, 0.101052f},
+ {3.155379f, 2.446498f, 0.115488f},
+ {3.082800f, 2.444100f, 0.120300f},
+ {3.010221f, 2.441702f, 0.115488f},
+ {2.943526f, 2.439499f, 0.101052f},
+ {2.888602f, 2.437685f, 0.076992f},
+ {2.851331f, 2.436454f, 0.043308f},
+ {2.837600f, 2.436000f, 0.000000f},
+ {3.257153f, 2.429599f, 0.041256f},
+ {3.269625f, 2.429869f, 0.000000f},
+ {3.223301f, 2.428868f, 0.073344f},
+ {3.173413f, 2.427791f, 0.096264f},
+ {3.112835f, 2.426483f, 0.110016f},
+ {3.046912f, 2.425059f, 0.114600f},
+ {2.980990f, 2.423636f, 0.110016f},
+ {2.920412f, 2.422328f, 0.096264f},
+ {2.870524f, 2.421250f, 0.073344f},
+ {2.836672f, 2.420519f, 0.041256f},
+ {2.824200f, 2.420250f, 0.000000f},
+ {3.188800f, 2.400000f, 0.040500f},
+ {3.158400f, 2.400000f, 0.072000f},
+ {3.113600f, 2.400000f, 0.094500f},
+ {3.059200f, 2.400000f, 0.108000f},
+ {3.000000f, 2.400000f, 0.112500f},
+ {2.940800f, 2.400000f, 0.108000f},
+ {2.886400f, 2.400000f, 0.094500f},
+ {2.841600f, 2.400000f, 0.072000f},
+ {2.811200f, 2.400000f, 0.040500f},
+ {0.000000f, 3.150000f, 0.000000f},
+ {0.194600f, 3.141450f, 0.000000f},
+ {0.192107f, 3.141450f, -0.032048f},
+ {0.184870f, 3.141450f, -0.062272f},
+ {0.173255f, 3.141450f, -0.090306f},
+ {0.157626f, 3.141450f, -0.115787f},
+ {0.138348f, 3.141450f, -0.138348f},
+ {0.115787f, 3.141450f, -0.157626f},
+ {0.090306f, 3.141450f, -0.173255f},
+ {0.062272f, 3.141450f, -0.184870f},
+ {0.032048f, 3.141450f, -0.192107f},
+ {-0.000000f, 3.141450f, -0.194600f},
+ {0.304843f, 3.117600f, -0.050855f},
+ {0.308800f, 3.117600f, 0.000000f},
+ {0.293360f, 3.117600f, -0.098814f},
+ {0.274928f, 3.117600f, -0.143301f},
+ {0.250127f, 3.117600f, -0.183734f},
+ {0.219536f, 3.117600f, -0.219536f},
+ {0.183734f, 3.117600f, -0.250127f},
+ {0.143301f, 3.117600f, -0.274928f},
+ {0.098814f, 3.117600f, -0.293360f},
+ {0.050855f, 3.117600f, -0.304843f},
+ {-0.000000f, 3.117600f, -0.308800f},
+ {0.353610f, 3.081150f, -0.058988f},
+ {0.358200f, 3.081150f, 0.000000f},
+ {0.340289f, 3.081150f, -0.114619f},
+ {0.318907f, 3.081150f, -0.166221f},
+ {0.290138f, 3.081150f, -0.213123f},
+ {0.254653f, 3.081150f, -0.254653f},
+ {0.213123f, 3.081150f, -0.290138f},
+ {0.166221f, 3.081150f, -0.318907f},
+ {0.114619f, 3.081150f, -0.340289f},
+ {0.058988f, 3.081150f, -0.353610f},
+ {-0.000000f, 3.081150f, -0.358200f},
+ {0.353807f, 3.034800f, -0.059016f},
+ {0.358400f, 3.034800f, 0.000000f},
+ {0.340477f, 3.034800f, -0.114676f},
+ {0.319082f, 3.034800f, -0.166306f},
+ {0.290295f, 3.034800f, -0.213234f},
+ {0.254788f, 3.034800f, -0.254788f},
+ {0.213234f, 3.034800f, -0.290295f},
+ {0.166306f, 3.034800f, -0.319082f},
+ {0.114676f, 3.034800f, -0.340477f},
+ {0.059016f, 3.034800f, -0.353807f},
+ {0.000000f, 3.034800f, -0.358400f},
+ {0.320834f, 2.981250f, -0.053508f},
+ {0.325000f, 2.981250f, 0.000000f},
+ {0.308744f, 2.981250f, -0.103976f},
+ {0.289340f, 2.981250f, -0.150793f},
+ {0.263232f, 2.981250f, -0.193348f},
+ {0.231031f, 2.981250f, -0.231031f},
+ {0.193348f, 2.981250f, -0.263232f},
+ {0.150793f, 2.981250f, -0.289340f},
+ {0.103976f, 2.981250f, -0.308744f},
+ {0.053508f, 2.981250f, -0.320834f},
+ {-0.000000f, 2.981250f, -0.325000f},
+ {0.270092f, 2.923200f, -0.045032f},
+ {0.273600f, 2.923200f, 0.000000f},
+ {0.259910f, 2.923200f, -0.087511f},
+ {0.243569f, 2.923200f, -0.126920f},
+ {0.221585f, 2.923200f, -0.162745f},
+ {0.194472f, 2.923200f, -0.194472f},
+ {0.162745f, 2.923200f, -0.221585f},
+ {0.126920f, 2.923200f, -0.243569f},
+ {0.087511f, 2.923200f, -0.259910f},
+ {0.045032f, 2.923200f, -0.270092f},
+ {-0.000000f, 2.923200f, -0.273600f},
+ {0.216979f, 2.863350f, -0.036157f},
+ {0.219800f, 2.863350f, 0.000000f},
+ {0.208794f, 2.863350f, -0.070270f},
+ {0.195658f, 2.863350f, -0.101925f},
+ {0.177989f, 2.863350f, -0.130707f},
+ {0.156200f, 2.863350f, -0.156200f},
+ {0.130707f, 2.863350f, -0.177989f},
+ {0.101925f, 2.863350f, -0.195658f},
+ {0.070270f, 2.863350f, -0.208794f},
+ {0.036157f, 2.863350f, -0.216979f},
+ {-0.000000f, 2.863350f, -0.219800f},
+ {0.176897f, 2.804400f, -0.029450f},
+ {0.179200f, 2.804400f, 0.000000f},
+ {0.170215f, 2.804400f, -0.057246f},
+ {0.159496f, 2.804400f, -0.083047f},
+ {0.145078f, 2.804400f, -0.106513f},
+ {0.127304f, 2.804400f, -0.127304f},
+ {0.106513f, 2.804400f, -0.145078f},
+ {0.083047f, 2.804400f, -0.159496f},
+ {0.057246f, 2.804400f, -0.170215f},
+ {0.029450f, 2.804400f, -0.176897f},
+ {-0.000000f, 2.804400f, -0.179200f},
+ {0.165245f, 2.749050f, -0.027480f},
+ {0.167400f, 2.749050f, 0.000000f},
+ {0.158995f, 2.749050f, -0.053428f},
+ {0.148969f, 2.749050f, -0.077523f},
+ {0.135489f, 2.749050f, -0.099446f},
+ {0.118874f, 2.749050f, -0.118874f},
+ {0.099446f, 2.749050f, -0.135489f},
+ {0.077523f, 2.749050f, -0.148969f},
+ {0.053428f, 2.749050f, -0.158995f},
+ {0.027480f, 2.749050f, -0.165245f},
+ {-0.000000f, 2.749050f, -0.167400f},
+ {0.197424f, 2.700000f, -0.032816f},
+ {0.200000f, 2.700000f, 0.000000f},
+ {0.189952f, 2.700000f, -0.063808f},
+ {0.177968f, 2.700000f, -0.092592f},
+ {0.161856f, 2.700000f, -0.118784f},
+ {0.142000f, 2.700000f, -0.142000f},
+ {0.118784f, 2.700000f, -0.161856f},
+ {0.092592f, 2.700000f, -0.177968f},
+ {0.063808f, 2.700000f, -0.189952f},
+ {0.032816f, 2.700000f, -0.197424f},
+ {-0.000000f, 2.700000f, -0.200000f},
+ {0.000000f, 3.141450f, -0.194600f},
+ {-0.032048f, 3.141450f, -0.192107f},
+ {-0.062272f, 3.141450f, -0.184870f},
+ {-0.090306f, 3.141450f, -0.173255f},
+ {-0.115787f, 3.141450f, -0.157626f},
+ {-0.138348f, 3.141450f, -0.138348f},
+ {-0.157626f, 3.141450f, -0.115787f},
+ {-0.173255f, 3.141450f, -0.090306f},
+ {-0.184870f, 3.141450f, -0.062272f},
+ {-0.192107f, 3.141450f, -0.032048f},
+ {-0.194600f, 3.141450f, 0.000000f},
+ {-0.050855f, 3.117600f, -0.304843f},
+ {0.000000f, 3.117600f, -0.308800f},
+ {-0.098814f, 3.117600f, -0.293360f},
+ {-0.143301f, 3.117600f, -0.274928f},
+ {-0.183734f, 3.117600f, -0.250127f},
+ {-0.219536f, 3.117600f, -0.219536f},
+ {-0.250127f, 3.117600f, -0.183734f},
+ {-0.274928f, 3.117600f, -0.143301f},
+ {-0.293360f, 3.117600f, -0.098814f},
+ {-0.304843f, 3.117600f, -0.050855f},
+ {-0.308800f, 3.117600f, 0.000000f},
+ {-0.058988f, 3.081150f, -0.353610f},
+ {0.000000f, 3.081150f, -0.358200f},
+ {-0.114619f, 3.081150f, -0.340289f},
+ {-0.166221f, 3.081150f, -0.318907f},
+ {-0.213123f, 3.081150f, -0.290138f},
+ {-0.254653f, 3.081150f, -0.254653f},
+ {-0.290138f, 3.081150f, -0.213123f},
+ {-0.318907f, 3.081150f, -0.166221f},
+ {-0.340289f, 3.081150f, -0.114619f},
+ {-0.353610f, 3.081150f, -0.058988f},
+ {-0.358200f, 3.081150f, 0.000000f},
+ {-0.059016f, 3.034800f, -0.353807f},
+ {0.000000f, 3.034800f, -0.358400f},
+ {-0.114676f, 3.034800f, -0.340477f},
+ {-0.166306f, 3.034800f, -0.319082f},
+ {-0.213234f, 3.034800f, -0.290295f},
+ {-0.254788f, 3.034800f, -0.254788f},
+ {-0.290295f, 3.034800f, -0.213234f},
+ {-0.319082f, 3.034800f, -0.166306f},
+ {-0.340477f, 3.034800f, -0.114676f},
+ {-0.353807f, 3.034800f, -0.059016f},
+ {-0.358400f, 3.034800f, 0.000000f},
+ {-0.053508f, 2.981250f, -0.320834f},
+ {0.000000f, 2.981250f, -0.325000f},
+ {-0.103976f, 2.981250f, -0.308744f},
+ {-0.150793f, 2.981250f, -0.289340f},
+ {-0.193348f, 2.981250f, -0.263232f},
+ {-0.231031f, 2.981250f, -0.231031f},
+ {-0.263232f, 2.981250f, -0.193348f},
+ {-0.289340f, 2.981250f, -0.150793f},
+ {-0.308744f, 2.981250f, -0.103976f},
+ {-0.320834f, 2.981250f, -0.053508f},
+ {-0.325000f, 2.981250f, 0.000000f},
+ {-0.045032f, 2.923200f, -0.270092f},
+ {0.000000f, 2.923200f, -0.273600f},
+ {-0.087511f, 2.923200f, -0.259910f},
+ {-0.126920f, 2.923200f, -0.243569f},
+ {-0.162745f, 2.923200f, -0.221585f},
+ {-0.194472f, 2.923200f, -0.194472f},
+ {-0.221585f, 2.923200f, -0.162745f},
+ {-0.243569f, 2.923200f, -0.126920f},
+ {-0.259910f, 2.923200f, -0.087511f},
+ {-0.270092f, 2.923200f, -0.045032f},
+ {-0.273600f, 2.923200f, 0.000000f},
+ {-0.036157f, 2.863350f, -0.216979f},
+ {0.000000f, 2.863350f, -0.219800f},
+ {-0.070270f, 2.863350f, -0.208794f},
+ {-0.101925f, 2.863350f, -0.195658f},
+ {-0.130707f, 2.863350f, -0.177989f},
+ {-0.156200f, 2.863350f, -0.156200f},
+ {-0.177989f, 2.863350f, -0.130707f},
+ {-0.195658f, 2.863350f, -0.101925f},
+ {-0.208794f, 2.863350f, -0.070270f},
+ {-0.216979f, 2.863350f, -0.036157f},
+ {-0.219800f, 2.863350f, 0.000000f},
+ {-0.029450f, 2.804400f, -0.176897f},
+ {0.000000f, 2.804400f, -0.179200f},
+ {-0.057246f, 2.804400f, -0.170215f},
+ {-0.083047f, 2.804400f, -0.159496f},
+ {-0.106513f, 2.804400f, -0.145078f},
+ {-0.127304f, 2.804400f, -0.127304f},
+ {-0.145078f, 2.804400f, -0.106513f},
+ {-0.159496f, 2.804400f, -0.083047f},
+ {-0.170215f, 2.804400f, -0.057246f},
+ {-0.176897f, 2.804400f, -0.029450f},
+ {-0.179200f, 2.804400f, 0.000000f},
+ {-0.027480f, 2.749050f, -0.165245f},
+ {0.000000f, 2.749050f, -0.167400f},
+ {-0.053428f, 2.749050f, -0.158995f},
+ {-0.077523f, 2.749050f, -0.148969f},
+ {-0.099446f, 2.749050f, -0.135489f},
+ {-0.118874f, 2.749050f, -0.118874f},
+ {-0.135489f, 2.749050f, -0.099446f},
+ {-0.148969f, 2.749050f, -0.077523f},
+ {-0.158995f, 2.749050f, -0.053428f},
+ {-0.165245f, 2.749050f, -0.027480f},
+ {-0.167400f, 2.749050f, 0.000000f},
+ {-0.032816f, 2.700000f, -0.197424f},
+ {0.000000f, 2.700000f, -0.200000f},
+ {-0.063808f, 2.700000f, -0.189952f},
+ {-0.092592f, 2.700000f, -0.177968f},
+ {-0.118784f, 2.700000f, -0.161856f},
+ {-0.142000f, 2.700000f, -0.142000f},
+ {-0.161856f, 2.700000f, -0.118784f},
+ {-0.177968f, 2.700000f, -0.092592f},
+ {-0.189952f, 2.700000f, -0.063808f},
+ {-0.197424f, 2.700000f, -0.032816f},
+ {-0.200000f, 2.700000f, 0.000000f},
+ {-0.194600f, 3.141450f, 0.000000f},
+ {-0.192107f, 3.141450f, 0.032048f},
+ {-0.184870f, 3.141450f, 0.062272f},
+ {-0.173255f, 3.141450f, 0.090306f},
+ {-0.157626f, 3.141450f, 0.115787f},
+ {-0.138348f, 3.141450f, 0.138348f},
+ {-0.115787f, 3.141450f, 0.157626f},
+ {-0.090306f, 3.141450f, 0.173255f},
+ {-0.062272f, 3.141450f, 0.184870f},
+ {-0.032048f, 3.141450f, 0.192107f},
+ {0.000000f, 3.141450f, 0.194600f},
+ {-0.304843f, 3.117600f, 0.050855f},
+ {-0.308800f, 3.117600f, 0.000000f},
+ {-0.293360f, 3.117600f, 0.098814f},
+ {-0.274928f, 3.117600f, 0.143301f},
+ {-0.250127f, 3.117600f, 0.183734f},
+ {-0.219536f, 3.117600f, 0.219536f},
+ {-0.183734f, 3.117600f, 0.250127f},
+ {-0.143301f, 3.117600f, 0.274928f},
+ {-0.098814f, 3.117600f, 0.293360f},
+ {-0.050855f, 3.117600f, 0.304843f},
+ {0.000000f, 3.117600f, 0.308800f},
+ {-0.353610f, 3.081150f, 0.058988f},
+ {-0.358200f, 3.081150f, 0.000000f},
+ {-0.340289f, 3.081150f, 0.114619f},
+ {-0.318907f, 3.081150f, 0.166221f},
+ {-0.290138f, 3.081150f, 0.213123f},
+ {-0.254653f, 3.081150f, 0.254653f},
+ {-0.213123f, 3.081150f, 0.290138f},
+ {-0.166221f, 3.081150f, 0.318907f},
+ {-0.114619f, 3.081150f, 0.340289f},
+ {-0.058988f, 3.081150f, 0.353610f},
+ {0.000000f, 3.081150f, 0.358200f},
+ {-0.353807f, 3.034800f, 0.059016f},
+ {-0.358400f, 3.034800f, 0.000000f},
+ {-0.340477f, 3.034800f, 0.114676f},
+ {-0.319082f, 3.034800f, 0.166306f},
+ {-0.290295f, 3.034800f, 0.213234f},
+ {-0.254788f, 3.034800f, 0.254788f},
+ {-0.213234f, 3.034800f, 0.290295f},
+ {-0.166306f, 3.034800f, 0.319082f},
+ {-0.114676f, 3.034800f, 0.340477f},
+ {-0.059016f, 3.034800f, 0.353807f},
+ {0.000000f, 3.034800f, 0.358400f},
+ {-0.320834f, 2.981250f, 0.053508f},
+ {-0.325000f, 2.981250f, 0.000000f},
+ {-0.308744f, 2.981250f, 0.103976f},
+ {-0.289340f, 2.981250f, 0.150793f},
+ {-0.263232f, 2.981250f, 0.193348f},
+ {-0.231031f, 2.981250f, 0.231031f},
+ {-0.193348f, 2.981250f, 0.263232f},
+ {-0.150793f, 2.981250f, 0.289340f},
+ {-0.103976f, 2.981250f, 0.308744f},
+ {-0.053508f, 2.981250f, 0.320834f},
+ {0.000000f, 2.981250f, 0.325000f},
+ {-0.270092f, 2.923200f, 0.045032f},
+ {-0.273600f, 2.923200f, 0.000000f},
+ {-0.259910f, 2.923200f, 0.087511f},
+ {-0.243569f, 2.923200f, 0.126920f},
+ {-0.221585f, 2.923200f, 0.162745f},
+ {-0.194472f, 2.923200f, 0.194472f},
+ {-0.162745f, 2.923200f, 0.221585f},
+ {-0.126920f, 2.923200f, 0.243569f},
+ {-0.087511f, 2.923200f, 0.259910f},
+ {-0.045032f, 2.923200f, 0.270092f},
+ {0.000000f, 2.923200f, 0.273600f},
+ {-0.216979f, 2.863350f, 0.036157f},
+ {-0.219800f, 2.863350f, 0.000000f},
+ {-0.208794f, 2.863350f, 0.070270f},
+ {-0.195658f, 2.863350f, 0.101925f},
+ {-0.177989f, 2.863350f, 0.130707f},
+ {-0.156200f, 2.863350f, 0.156200f},
+ {-0.130707f, 2.863350f, 0.177989f},
+ {-0.101925f, 2.863350f, 0.195658f},
+ {-0.070270f, 2.863350f, 0.208794f},
+ {-0.036157f, 2.863350f, 0.216979f},
+ {0.000000f, 2.863350f, 0.219800f},
+ {-0.176897f, 2.804400f, 0.029450f},
+ {-0.179200f, 2.804400f, 0.000000f},
+ {-0.170215f, 2.804400f, 0.057246f},
+ {-0.159496f, 2.804400f, 0.083047f},
+ {-0.145078f, 2.804400f, 0.106513f},
+ {-0.127304f, 2.804400f, 0.127304f},
+ {-0.106513f, 2.804400f, 0.145078f},
+ {-0.083047f, 2.804400f, 0.159496f},
+ {-0.057246f, 2.804400f, 0.170215f},
+ {-0.029450f, 2.804400f, 0.176897f},
+ {0.000000f, 2.804400f, 0.179200f},
+ {-0.165245f, 2.749050f, 0.027480f},
+ {-0.167400f, 2.749050f, 0.000000f},
+ {-0.158995f, 2.749050f, 0.053428f},
+ {-0.148969f, 2.749050f, 0.077523f},
+ {-0.135489f, 2.749050f, 0.099446f},
+ {-0.118874f, 2.749050f, 0.118874f},
+ {-0.099446f, 2.749050f, 0.135489f},
+ {-0.077523f, 2.749050f, 0.148969f},
+ {-0.053428f, 2.749050f, 0.158995f},
+ {-0.027480f, 2.749050f, 0.165245f},
+ {0.000000f, 2.749050f, 0.167400f},
+ {-0.197424f, 2.700000f, 0.032816f},
+ {-0.200000f, 2.700000f, 0.000000f},
+ {-0.189952f, 2.700000f, 0.063808f},
+ {-0.177968f, 2.700000f, 0.092592f},
+ {-0.161856f, 2.700000f, 0.118784f},
+ {-0.142000f, 2.700000f, 0.142000f},
+ {-0.118784f, 2.700000f, 0.161856f},
+ {-0.092592f, 2.700000f, 0.177968f},
+ {-0.063808f, 2.700000f, 0.189952f},
+ {-0.032816f, 2.700000f, 0.197424f},
+ {0.000000f, 2.700000f, 0.200000f},
+ {0.000000f, 3.141450f, 0.194600f},
+ {0.032048f, 3.141450f, 0.192107f},
+ {0.062272f, 3.141450f, 0.184870f},
+ {0.090306f, 3.141450f, 0.173255f},
+ {0.115787f, 3.141450f, 0.157626f},
+ {0.138348f, 3.141450f, 0.138348f},
+ {0.157626f, 3.141450f, 0.115787f},
+ {0.173255f, 3.141450f, 0.090306f},
+ {0.184870f, 3.141450f, 0.062272f},
+ {0.192107f, 3.141450f, 0.032048f},
+ {0.194600f, 3.141450f, -0.000000f},
+ {0.050855f, 3.117600f, 0.304843f},
+ {0.000000f, 3.117600f, 0.308800f},
+ {0.098814f, 3.117600f, 0.293360f},
+ {0.143301f, 3.117600f, 0.274928f},
+ {0.183734f, 3.117600f, 0.250127f},
+ {0.219536f, 3.117600f, 0.219536f},
+ {0.250127f, 3.117600f, 0.183734f},
+ {0.274928f, 3.117600f, 0.143301f},
+ {0.293360f, 3.117600f, 0.098814f},
+ {0.304843f, 3.117600f, 0.050855f},
+ {0.308800f, 3.117600f, -0.000000f},
+ {0.058988f, 3.081150f, 0.353610f},
+ {0.000000f, 3.081150f, 0.358200f},
+ {0.114619f, 3.081150f, 0.340289f},
+ {0.166221f, 3.081150f, 0.318907f},
+ {0.213123f, 3.081150f, 0.290138f},
+ {0.254653f, 3.081150f, 0.254653f},
+ {0.290138f, 3.081150f, 0.213123f},
+ {0.318907f, 3.081150f, 0.166221f},
+ {0.340289f, 3.081150f, 0.114619f},
+ {0.353610f, 3.081150f, 0.058988f},
+ {0.358200f, 3.081150f, -0.000000f},
+ {0.059016f, 3.034800f, 0.353807f},
+ {0.000000f, 3.034800f, 0.358400f},
+ {0.114676f, 3.034800f, 0.340477f},
+ {0.166306f, 3.034800f, 0.319082f},
+ {0.213234f, 3.034800f, 0.290295f},
+ {0.254788f, 3.034800f, 0.254788f},
+ {0.290295f, 3.034800f, 0.213234f},
+ {0.319082f, 3.034800f, 0.166306f},
+ {0.340477f, 3.034800f, 0.114676f},
+ {0.353807f, 3.034800f, 0.059016f},
+ {0.358400f, 3.034800f, 0.000000f},
+ {0.053508f, 2.981250f, 0.320834f},
+ {0.000000f, 2.981250f, 0.325000f},
+ {0.103976f, 2.981250f, 0.308744f},
+ {0.150793f, 2.981250f, 0.289340f},
+ {0.193348f, 2.981250f, 0.263232f},
+ {0.231031f, 2.981250f, 0.231031f},
+ {0.263232f, 2.981250f, 0.193348f},
+ {0.289340f, 2.981250f, 0.150793f},
+ {0.308744f, 2.981250f, 0.103976f},
+ {0.320834f, 2.981250f, 0.053508f},
+ {0.325000f, 2.981250f, -0.000000f},
+ {0.045032f, 2.923200f, 0.270092f},
+ {0.000000f, 2.923200f, 0.273600f},
+ {0.087511f, 2.923200f, 0.259910f},
+ {0.126920f, 2.923200f, 0.243569f},
+ {0.162745f, 2.923200f, 0.221585f},
+ {0.194472f, 2.923200f, 0.194472f},
+ {0.221585f, 2.923200f, 0.162745f},
+ {0.243569f, 2.923200f, 0.126920f},
+ {0.259910f, 2.923200f, 0.087511f},
+ {0.270092f, 2.923200f, 0.045032f},
+ {0.273600f, 2.923200f, -0.000000f},
+ {0.036157f, 2.863350f, 0.216979f},
+ {0.000000f, 2.863350f, 0.219800f},
+ {0.070270f, 2.863350f, 0.208794f},
+ {0.101925f, 2.863350f, 0.195658f},
+ {0.130707f, 2.863350f, 0.177989f},
+ {0.156200f, 2.863350f, 0.156200f},
+ {0.177989f, 2.863350f, 0.130707f},
+ {0.195658f, 2.863350f, 0.101925f},
+ {0.208794f, 2.863350f, 0.070270f},
+ {0.216979f, 2.863350f, 0.036157f},
+ {0.219800f, 2.863350f, -0.000000f},
+ {0.029450f, 2.804400f, 0.176897f},
+ {0.000000f, 2.804400f, 0.179200f},
+ {0.057246f, 2.804400f, 0.170215f},
+ {0.083047f, 2.804400f, 0.159496f},
+ {0.106513f, 2.804400f, 0.145078f},
+ {0.127304f, 2.804400f, 0.127304f},
+ {0.145078f, 2.804400f, 0.106513f},
+ {0.159496f, 2.804400f, 0.083047f},
+ {0.170215f, 2.804400f, 0.057246f},
+ {0.176897f, 2.804400f, 0.029450f},
+ {0.179200f, 2.804400f, -0.000000f},
+ {0.027480f, 2.749050f, 0.165245f},
+ {0.000000f, 2.749050f, 0.167400f},
+ {0.053428f, 2.749050f, 0.158995f},
+ {0.077523f, 2.749050f, 0.148969f},
+ {0.099446f, 2.749050f, 0.135489f},
+ {0.118874f, 2.749050f, 0.118874f},
+ {0.135489f, 2.749050f, 0.099446f},
+ {0.148969f, 2.749050f, 0.077523f},
+ {0.158995f, 2.749050f, 0.053428f},
+ {0.165245f, 2.749050f, 0.027480f},
+ {0.167400f, 2.749050f, -0.000000f},
+ {0.032816f, 2.700000f, 0.197424f},
+ {0.000000f, 2.700000f, 0.200000f},
+ {0.063808f, 2.700000f, 0.189952f},
+ {0.092592f, 2.700000f, 0.177968f},
+ {0.118784f, 2.700000f, 0.161856f},
+ {0.142000f, 2.700000f, 0.142000f},
+ {0.161856f, 2.700000f, 0.118784f},
+ {0.177968f, 2.700000f, 0.092592f},
+ {0.189952f, 2.700000f, 0.063808f},
+ {0.197424f, 2.700000f, 0.032816f},
+ {0.200000f, 2.700000f, -0.000000f},
+ {0.275801f, 2.659200f, -0.045844f},
+ {0.197424f, 2.700000f, -0.032816f},
+ {0.200000f, 2.700000f, 0.000000f},
+ {0.279400f, 2.659200f, 0.000000f},
+ {0.265363f, 2.659200f, -0.089140f},
+ {0.189952f, 2.700000f, -0.063808f},
+ {0.248621f, 2.659200f, -0.129351f},
+ {0.177968f, 2.700000f, -0.092592f},
+ {0.226113f, 2.659200f, -0.165941f},
+ {0.161856f, 2.700000f, -0.118784f},
+ {0.198374f, 2.659200f, -0.198374f},
+ {0.142000f, 2.700000f, -0.142000f},
+ {0.165941f, 2.659200f, -0.226113f},
+ {0.118784f, 2.700000f, -0.161856f},
+ {0.129351f, 2.659200f, -0.248621f},
+ {0.092592f, 2.700000f, -0.177968f},
+ {0.089140f, 2.659200f, -0.265363f},
+ {0.063808f, 2.700000f, -0.189952f},
+ {0.045844f, 2.659200f, -0.275801f},
+ {0.032816f, 2.700000f, -0.197424f},
+ {0.000000f, 2.659200f, -0.279400f},
+ {-0.000000f, 2.700000f, -0.200000f},
+ {0.386161f, 2.625600f, -0.064188f},
+ {0.391200f, 2.625600f, 0.000000f},
+ {0.371546f, 2.625600f, -0.124808f},
+ {0.348105f, 2.625600f, -0.181110f},
+ {0.316590f, 2.625600f, -0.232342f},
+ {0.277752f, 2.625600f, -0.277752f},
+ {0.232342f, 2.625600f, -0.316590f},
+ {0.181110f, 2.625600f, -0.348105f},
+ {0.124808f, 2.625600f, -0.371546f},
+ {0.064188f, 2.625600f, -0.386161f},
+ {0.000000f, 2.625600f, -0.391200f},
+ {0.519028f, 2.597400f, -0.086273f},
+ {0.525800f, 2.597400f, 0.000000f},
+ {0.499384f, 2.597400f, -0.167751f},
+ {0.467878f, 2.597400f, -0.243424f},
+ {0.425519f, 2.597400f, -0.312283f},
+ {0.373318f, 2.597400f, -0.373318f},
+ {0.312283f, 2.597400f, -0.425519f},
+ {0.243424f, 2.597400f, -0.467878f},
+ {0.167751f, 2.597400f, -0.499384f},
+ {0.086273f, 2.597400f, -0.519028f},
+ {-0.000000f, 2.597400f, -0.525800f},
+ {0.664924f, 2.572800f, -0.110524f},
+ {0.673600f, 2.572800f, 0.000000f},
+ {0.639758f, 2.572800f, -0.214905f},
+ {0.599396f, 2.572800f, -0.311850f},
+ {0.545131f, 2.572800f, -0.400065f},
+ {0.478256f, 2.572800f, -0.478256f},
+ {0.400065f, 2.572800f, -0.545131f},
+ {0.311850f, 2.572800f, -0.599396f},
+ {0.214905f, 2.572800f, -0.639758f},
+ {0.110524f, 2.572800f, -0.664924f},
+ {-0.000000f, 2.572800f, -0.673600f},
+ {0.814374f, 2.550000f, -0.135366f},
+ {0.825000f, 2.550000f, 0.000000f},
+ {0.783552f, 2.550000f, -0.263208f},
+ {0.734118f, 2.550000f, -0.381942f},
+ {0.667656f, 2.550000f, -0.489984f},
+ {0.585750f, 2.550000f, -0.585750f},
+ {0.489984f, 2.550000f, -0.667656f},
+ {0.381942f, 2.550000f, -0.734118f},
+ {0.263208f, 2.550000f, -0.783552f},
+ {0.135366f, 2.550000f, -0.814374f},
+ {0.000000f, 2.550000f, -0.825000f},
+ {0.957901f, 2.527200f, -0.159223f},
+ {0.970400f, 2.527200f, 0.000000f},
+ {0.921647f, 2.527200f, -0.309596f},
+ {0.863501f, 2.527200f, -0.449256f},
+ {0.785325f, 2.527200f, -0.576340f},
+ {0.688984f, 2.527200f, -0.688984f},
+ {0.576340f, 2.527200f, -0.785325f},
+ {0.449256f, 2.527200f, -0.863501f},
+ {0.309596f, 2.527200f, -0.921647f},
+ {0.159223f, 2.527200f, -0.957901f},
+ {-0.000000f, 2.527200f, -0.970400f},
+ {1.086029f, 2.502600f, -0.180521f},
+ {1.100200f, 2.502600f, 0.000000f},
+ {1.044926f, 2.502600f, -0.351008f},
+ {0.979002f, 2.502600f, -0.509349f},
+ {0.890370f, 2.502600f, -0.653431f},
+ {0.781142f, 2.502600f, -0.781142f},
+ {0.653431f, 2.502600f, -0.890370f},
+ {0.509349f, 2.502600f, -0.979002f},
+ {0.351008f, 2.502600f, -1.044926f},
+ {0.180521f, 2.502600f, -1.086029f},
+ {-0.000000f, 2.502600f, -1.100200f},
+ {1.189282f, 2.474400f, -0.197684f},
+ {1.204800f, 2.474400f, 0.000000f},
+ {1.144271f, 2.474400f, -0.384379f},
+ {1.072079f, 2.474400f, -0.557774f},
+ {0.975021f, 2.474400f, -0.715555f},
+ {0.855408f, 2.474400f, -0.855408f},
+ {0.715555f, 2.474400f, -0.975021f},
+ {0.557774f, 2.474400f, -1.072079f},
+ {0.384379f, 2.474400f, -1.144271f},
+ {0.197684f, 2.474400f, -1.189282f},
+ {-0.000000f, 2.474400f, -1.204800f},
+ {1.258183f, 2.440800f, -0.209136f},
+ {1.274600f, 2.440800f, 0.000000f},
+ {1.210564f, 2.440800f, -0.406648f},
+ {1.134190f, 2.440800f, -0.590089f},
+ {1.031508f, 2.440800f, -0.757010f},
+ {0.904966f, 2.440800f, -0.904966f},
+ {0.757010f, 2.440800f, -1.031508f},
+ {0.590089f, 2.440800f, -1.134190f},
+ {0.406648f, 2.440800f, -1.210564f},
+ {0.209136f, 2.440800f, -1.258183f},
+ {0.000000f, 2.440800f, -1.274600f},
+ {1.283256f, 2.400000f, -0.213304f},
+ {1.300000f, 2.400000f, 0.000000f},
+ {1.234688f, 2.400000f, -0.414752f},
+ {1.156792f, 2.400000f, -0.601848f},
+ {1.052064f, 2.400000f, -0.772096f},
+ {0.923000f, 2.400000f, -0.923000f},
+ {0.772096f, 2.400000f, -1.052064f},
+ {0.601848f, 2.400000f, -1.156792f},
+ {0.414752f, 2.400000f, -1.234688f},
+ {0.213304f, 2.400000f, -1.283256f},
+ {-0.000000f, 2.400000f, -1.300000f},
+ {-0.045844f, 2.659200f, -0.275801f},
+ {-0.032816f, 2.700000f, -0.197424f},
+ {0.000000f, 2.700000f, -0.200000f},
+ {-0.089140f, 2.659200f, -0.265363f},
+ {-0.063808f, 2.700000f, -0.189952f},
+ {-0.129351f, 2.659200f, -0.248621f},
+ {-0.092592f, 2.700000f, -0.177968f},
+ {-0.165941f, 2.659200f, -0.226113f},
+ {-0.118784f, 2.700000f, -0.161856f},
+ {-0.198374f, 2.659200f, -0.198374f},
+ {-0.142000f, 2.700000f, -0.142000f},
+ {-0.226113f, 2.659200f, -0.165941f},
+ {-0.161856f, 2.700000f, -0.118784f},
+ {-0.248621f, 2.659200f, -0.129351f},
+ {-0.177968f, 2.700000f, -0.092592f},
+ {-0.265363f, 2.659200f, -0.089140f},
+ {-0.189952f, 2.700000f, -0.063808f},
+ {-0.275801f, 2.659200f, -0.045844f},
+ {-0.197424f, 2.700000f, -0.032816f},
+ {-0.279400f, 2.659200f, 0.000000f},
+ {-0.200000f, 2.700000f, 0.000000f},
+ {-0.064188f, 2.625600f, -0.386161f},
+ {0.000000f, 2.625600f, -0.391200f},
+ {-0.124808f, 2.625600f, -0.371546f},
+ {-0.181110f, 2.625600f, -0.348105f},
+ {-0.232342f, 2.625600f, -0.316590f},
+ {-0.277752f, 2.625600f, -0.277752f},
+ {-0.316590f, 2.625600f, -0.232342f},
+ {-0.348105f, 2.625600f, -0.181110f},
+ {-0.371546f, 2.625600f, -0.124808f},
+ {-0.386161f, 2.625600f, -0.064188f},
+ {-0.391200f, 2.625600f, 0.000000f},
+ {-0.086273f, 2.597400f, -0.519028f},
+ {0.000000f, 2.597400f, -0.525800f},
+ {-0.167751f, 2.597400f, -0.499384f},
+ {-0.243424f, 2.597400f, -0.467878f},
+ {-0.312283f, 2.597400f, -0.425519f},
+ {-0.373318f, 2.597400f, -0.373318f},
+ {-0.425519f, 2.597400f, -0.312283f},
+ {-0.467878f, 2.597400f, -0.243424f},
+ {-0.499384f, 2.597400f, -0.167751f},
+ {-0.519028f, 2.597400f, -0.086273f},
+ {-0.525800f, 2.597400f, 0.000000f},
+ {-0.110524f, 2.572800f, -0.664924f},
+ {0.000000f, 2.572800f, -0.673600f},
+ {-0.214905f, 2.572800f, -0.639758f},
+ {-0.311850f, 2.572800f, -0.599396f},
+ {-0.400065f, 2.572800f, -0.545131f},
+ {-0.478256f, 2.572800f, -0.478256f},
+ {-0.545131f, 2.572800f, -0.400065f},
+ {-0.599396f, 2.572800f, -0.311850f},
+ {-0.639758f, 2.572800f, -0.214905f},
+ {-0.664924f, 2.572800f, -0.110524f},
+ {-0.673600f, 2.572800f, 0.000000f},
+ {-0.135366f, 2.550000f, -0.814374f},
+ {0.000000f, 2.550000f, -0.825000f},
+ {-0.263208f, 2.550000f, -0.783552f},
+ {-0.381942f, 2.550000f, -0.734118f},
+ {-0.489984f, 2.550000f, -0.667656f},
+ {-0.585750f, 2.550000f, -0.585750f},
+ {-0.667656f, 2.550000f, -0.489984f},
+ {-0.734118f, 2.550000f, -0.381942f},
+ {-0.783552f, 2.550000f, -0.263208f},
+ {-0.814374f, 2.550000f, -0.135366f},
+ {-0.825000f, 2.550000f, 0.000000f},
+ {-0.159223f, 2.527200f, -0.957901f},
+ {0.000000f, 2.527200f, -0.970400f},
+ {-0.309596f, 2.527200f, -0.921647f},
+ {-0.449256f, 2.527200f, -0.863501f},
+ {-0.576340f, 2.527200f, -0.785325f},
+ {-0.688984f, 2.527200f, -0.688984f},
+ {-0.785325f, 2.527200f, -0.576340f},
+ {-0.863501f, 2.527200f, -0.449256f},
+ {-0.921647f, 2.527200f, -0.309596f},
+ {-0.957901f, 2.527200f, -0.159223f},
+ {-0.970400f, 2.527200f, 0.000000f},
+ {-0.180521f, 2.502600f, -1.086029f},
+ {0.000000f, 2.502600f, -1.100200f},
+ {-0.351008f, 2.502600f, -1.044926f},
+ {-0.509349f, 2.502600f, -0.979002f},
+ {-0.653431f, 2.502600f, -0.890370f},
+ {-0.781142f, 2.502600f, -0.781142f},
+ {-0.890370f, 2.502600f, -0.653431f},
+ {-0.979002f, 2.502600f, -0.509349f},
+ {-1.044926f, 2.502600f, -0.351008f},
+ {-1.086029f, 2.502600f, -0.180521f},
+ {-1.100200f, 2.502600f, 0.000000f},
+ {-0.197684f, 2.474400f, -1.189282f},
+ {0.000000f, 2.474400f, -1.204800f},
+ {-0.384379f, 2.474400f, -1.144271f},
+ {-0.557774f, 2.474400f, -1.072079f},
+ {-0.715555f, 2.474400f, -0.975021f},
+ {-0.855408f, 2.474400f, -0.855408f},
+ {-0.975021f, 2.474400f, -0.715555f},
+ {-1.072079f, 2.474400f, -0.557774f},
+ {-1.144271f, 2.474400f, -0.384379f},
+ {-1.189282f, 2.474400f, -0.197684f},
+ {-1.204800f, 2.474400f, 0.000000f},
+ {-0.209136f, 2.440800f, -1.258183f},
+ {0.000000f, 2.440800f, -1.274600f},
+ {-0.406648f, 2.440800f, -1.210564f},
+ {-0.590089f, 2.440800f, -1.134190f},
+ {-0.757010f, 2.440800f, -1.031508f},
+ {-0.904966f, 2.440800f, -0.904966f},
+ {-1.031508f, 2.440800f, -0.757010f},
+ {-1.134190f, 2.440800f, -0.590089f},
+ {-1.210564f, 2.440800f, -0.406648f},
+ {-1.258183f, 2.440800f, -0.209136f},
+ {-1.274600f, 2.440800f, 0.000000f},
+ {-0.213304f, 2.400000f, -1.283256f},
+ {0.000000f, 2.400000f, -1.300000f},
+ {-0.414752f, 2.400000f, -1.234688f},
+ {-0.601848f, 2.400000f, -1.156792f},
+ {-0.772096f, 2.400000f, -1.052064f},
+ {-0.923000f, 2.400000f, -0.923000f},
+ {-1.052064f, 2.400000f, -0.772096f},
+ {-1.156792f, 2.400000f, -0.601848f},
+ {-1.234688f, 2.400000f, -0.414752f},
+ {-1.283256f, 2.400000f, -0.213304f},
+ {-1.300000f, 2.400000f, 0.000000f},
+ {-0.275801f, 2.659200f, 0.045844f},
+ {-0.197424f, 2.700000f, 0.032816f},
+ {-0.200000f, 2.700000f, 0.000000f},
+ {-0.265363f, 2.659200f, 0.089140f},
+ {-0.189952f, 2.700000f, 0.063808f},
+ {-0.248621f, 2.659200f, 0.129351f},
+ {-0.177968f, 2.700000f, 0.092592f},
+ {-0.226113f, 2.659200f, 0.165941f},
+ {-0.161856f, 2.700000f, 0.118784f},
+ {-0.198374f, 2.659200f, 0.198374f},
+ {-0.142000f, 2.700000f, 0.142000f},
+ {-0.165941f, 2.659200f, 0.226113f},
+ {-0.118784f, 2.700000f, 0.161856f},
+ {-0.129351f, 2.659200f, 0.248621f},
+ {-0.092592f, 2.700000f, 0.177968f},
+ {-0.089140f, 2.659200f, 0.265363f},
+ {-0.063808f, 2.700000f, 0.189952f},
+ {-0.045844f, 2.659200f, 0.275801f},
+ {-0.032816f, 2.700000f, 0.197424f},
+ {0.000000f, 2.659200f, 0.279400f},
+ {0.000000f, 2.700000f, 0.200000f},
+ {-0.386161f, 2.625600f, 0.064188f},
+ {-0.391200f, 2.625600f, 0.000000f},
+ {-0.371546f, 2.625600f, 0.124808f},
+ {-0.348105f, 2.625600f, 0.181110f},
+ {-0.316590f, 2.625600f, 0.232342f},
+ {-0.277752f, 2.625600f, 0.277752f},
+ {-0.232342f, 2.625600f, 0.316590f},
+ {-0.181110f, 2.625600f, 0.348105f},
+ {-0.124808f, 2.625600f, 0.371546f},
+ {-0.064188f, 2.625600f, 0.386161f},
+ {0.000000f, 2.625600f, 0.391200f},
+ {-0.519028f, 2.597400f, 0.086273f},
+ {-0.525800f, 2.597400f, 0.000000f},
+ {-0.499384f, 2.597400f, 0.167751f},
+ {-0.467878f, 2.597400f, 0.243424f},
+ {-0.425519f, 2.597400f, 0.312283f},
+ {-0.373318f, 2.597400f, 0.373318f},
+ {-0.312283f, 2.597400f, 0.425519f},
+ {-0.243424f, 2.597400f, 0.467878f},
+ {-0.167751f, 2.597400f, 0.499384f},
+ {-0.086273f, 2.597400f, 0.519028f},
+ {0.000000f, 2.597400f, 0.525800f},
+ {-0.664924f, 2.572800f, 0.110524f},
+ {-0.673600f, 2.572800f, 0.000000f},
+ {-0.639758f, 2.572800f, 0.214905f},
+ {-0.599396f, 2.572800f, 0.311850f},
+ {-0.545131f, 2.572800f, 0.400065f},
+ {-0.478256f, 2.572800f, 0.478256f},
+ {-0.400065f, 2.572800f, 0.545131f},
+ {-0.311850f, 2.572800f, 0.599396f},
+ {-0.214905f, 2.572800f, 0.639758f},
+ {-0.110524f, 2.572800f, 0.664924f},
+ {0.000000f, 2.572800f, 0.673600f},
+ {-0.814374f, 2.550000f, 0.135366f},
+ {-0.825000f, 2.550000f, 0.000000f},
+ {-0.783552f, 2.550000f, 0.263208f},
+ {-0.734118f, 2.550000f, 0.381942f},
+ {-0.667656f, 2.550000f, 0.489984f},
+ {-0.585750f, 2.550000f, 0.585750f},
+ {-0.489984f, 2.550000f, 0.667656f},
+ {-0.381942f, 2.550000f, 0.734118f},
+ {-0.263208f, 2.550000f, 0.783552f},
+ {-0.135366f, 2.550000f, 0.814374f},
+ {0.000000f, 2.550000f, 0.825000f},
+ {-0.957901f, 2.527200f, 0.159223f},
+ {-0.970400f, 2.527200f, 0.000000f},
+ {-0.921647f, 2.527200f, 0.309596f},
+ {-0.863501f, 2.527200f, 0.449256f},
+ {-0.785325f, 2.527200f, 0.576340f},
+ {-0.688984f, 2.527200f, 0.688984f},
+ {-0.576340f, 2.527200f, 0.785325f},
+ {-0.449256f, 2.527200f, 0.863501f},
+ {-0.309596f, 2.527200f, 0.921647f},
+ {-0.159223f, 2.527200f, 0.957901f},
+ {0.000000f, 2.527200f, 0.970400f},
+ {-1.086029f, 2.502600f, 0.180521f},
+ {-1.100200f, 2.502600f, 0.000000f},
+ {-1.044926f, 2.502600f, 0.351008f},
+ {-0.979002f, 2.502600f, 0.509349f},
+ {-0.890370f, 2.502600f, 0.653431f},
+ {-0.781142f, 2.502600f, 0.781142f},
+ {-0.653431f, 2.502600f, 0.890370f},
+ {-0.509349f, 2.502600f, 0.979002f},
+ {-0.351008f, 2.502600f, 1.044926f},
+ {-0.180521f, 2.502600f, 1.086029f},
+ {0.000000f, 2.502600f, 1.100200f},
+ {-1.189282f, 2.474400f, 0.197684f},
+ {-1.204800f, 2.474400f, 0.000000f},
+ {-1.144271f, 2.474400f, 0.384379f},
+ {-1.072079f, 2.474400f, 0.557774f},
+ {-0.975021f, 2.474400f, 0.715555f},
+ {-0.855408f, 2.474400f, 0.855408f},
+ {-0.715555f, 2.474400f, 0.975021f},
+ {-0.557774f, 2.474400f, 1.072079f},
+ {-0.384379f, 2.474400f, 1.144271f},
+ {-0.197684f, 2.474400f, 1.189282f},
+ {0.000000f, 2.474400f, 1.204800f},
+ {-1.258183f, 2.440800f, 0.209136f},
+ {-1.274600f, 2.440800f, 0.000000f},
+ {-1.210564f, 2.440800f, 0.406648f},
+ {-1.134190f, 2.440800f, 0.590089f},
+ {-1.031508f, 2.440800f, 0.757010f},
+ {-0.904966f, 2.440800f, 0.904966f},
+ {-0.757010f, 2.440800f, 1.031508f},
+ {-0.590089f, 2.440800f, 1.134190f},
+ {-0.406648f, 2.440800f, 1.210564f},
+ {-0.209136f, 2.440800f, 1.258183f},
+ {0.000000f, 2.440800f, 1.274600f},
+ {-1.283256f, 2.400000f, 0.213304f},
+ {-1.300000f, 2.400000f, 0.000000f},
+ {-1.234688f, 2.400000f, 0.414752f},
+ {-1.156792f, 2.400000f, 0.601848f},
+ {-1.052064f, 2.400000f, 0.772096f},
+ {-0.923000f, 2.400000f, 0.923000f},
+ {-0.772096f, 2.400000f, 1.052064f},
+ {-0.601848f, 2.400000f, 1.156792f},
+ {-0.414752f, 2.400000f, 1.234688f},
+ {-0.213304f, 2.400000f, 1.283256f},
+ {0.000000f, 2.400000f, 1.300000f},
+ {0.045844f, 2.659200f, 0.275801f},
+ {0.032816f, 2.700000f, 0.197424f},
+ {0.000000f, 2.700000f, 0.200000f},
+ {0.089140f, 2.659200f, 0.265363f},
+ {0.063808f, 2.700000f, 0.189952f},
+ {0.129351f, 2.659200f, 0.248621f},
+ {0.092592f, 2.700000f, 0.177968f},
+ {0.165941f, 2.659200f, 0.226113f},
+ {0.118784f, 2.700000f, 0.161856f},
+ {0.198374f, 2.659200f, 0.198374f},
+ {0.142000f, 2.700000f, 0.142000f},
+ {0.226113f, 2.659200f, 0.165941f},
+ {0.161856f, 2.700000f, 0.118784f},
+ {0.248621f, 2.659200f, 0.129351f},
+ {0.177968f, 2.700000f, 0.092592f},
+ {0.265363f, 2.659200f, 0.089140f},
+ {0.189952f, 2.700000f, 0.063808f},
+ {0.275801f, 2.659200f, 0.045844f},
+ {0.197424f, 2.700000f, 0.032816f},
+ {0.200000f, 2.700000f, -0.000000f},
+ {0.064188f, 2.625600f, 0.386161f},
+ {0.000000f, 2.625600f, 0.391200f},
+ {0.124808f, 2.625600f, 0.371546f},
+ {0.181110f, 2.625600f, 0.348105f},
+ {0.232342f, 2.625600f, 0.316590f},
+ {0.277752f, 2.625600f, 0.277752f},
+ {0.316590f, 2.625600f, 0.232342f},
+ {0.348105f, 2.625600f, 0.181110f},
+ {0.371546f, 2.625600f, 0.124808f},
+ {0.386161f, 2.625600f, 0.064188f},
+ {0.391200f, 2.625600f, 0.000000f},
+ {0.086273f, 2.597400f, 0.519028f},
+ {0.000000f, 2.597400f, 0.525800f},
+ {0.167751f, 2.597400f, 0.499384f},
+ {0.243424f, 2.597400f, 0.467878f},
+ {0.312283f, 2.597400f, 0.425519f},
+ {0.373318f, 2.597400f, 0.373318f},
+ {0.425519f, 2.597400f, 0.312283f},
+ {0.467878f, 2.597400f, 0.243424f},
+ {0.499384f, 2.597400f, 0.167751f},
+ {0.519028f, 2.597400f, 0.086273f},
+ {0.525800f, 2.597400f, -0.000000f},
+ {0.110524f, 2.572800f, 0.664924f},
+ {0.000000f, 2.572800f, 0.673600f},
+ {0.214905f, 2.572800f, 0.639758f},
+ {0.311850f, 2.572800f, 0.599396f},
+ {0.400065f, 2.572800f, 0.545131f},
+ {0.478256f, 2.572800f, 0.478256f},
+ {0.545131f, 2.572800f, 0.400065f},
+ {0.599396f, 2.572800f, 0.311850f},
+ {0.639758f, 2.572800f, 0.214905f},
+ {0.664924f, 2.572800f, 0.110524f},
+ {0.673600f, 2.572800f, -0.000000f},
+ {0.135366f, 2.550000f, 0.814374f},
+ {0.000000f, 2.550000f, 0.825000f},
+ {0.263208f, 2.550000f, 0.783552f},
+ {0.381942f, 2.550000f, 0.734118f},
+ {0.489984f, 2.550000f, 0.667656f},
+ {0.585750f, 2.550000f, 0.585750f},
+ {0.667656f, 2.550000f, 0.489984f},
+ {0.734118f, 2.550000f, 0.381942f},
+ {0.783552f, 2.550000f, 0.263208f},
+ {0.814374f, 2.550000f, 0.135366f},
+ {0.825000f, 2.550000f, 0.000000f},
+ {0.159223f, 2.527200f, 0.957901f},
+ {0.000000f, 2.527200f, 0.970400f},
+ {0.309596f, 2.527200f, 0.921647f},
+ {0.449256f, 2.527200f, 0.863501f},
+ {0.576340f, 2.527200f, 0.785325f},
+ {0.688984f, 2.527200f, 0.688984f},
+ {0.785325f, 2.527200f, 0.576340f},
+ {0.863501f, 2.527200f, 0.449256f},
+ {0.921647f, 2.527200f, 0.309596f},
+ {0.957901f, 2.527200f, 0.159223f},
+ {0.970400f, 2.527200f, -0.000000f},
+ {0.180521f, 2.502600f, 1.086029f},
+ {0.000000f, 2.502600f, 1.100200f},
+ {0.351008f, 2.502600f, 1.044926f},
+ {0.509349f, 2.502600f, 0.979002f},
+ {0.653431f, 2.502600f, 0.890370f},
+ {0.781142f, 2.502600f, 0.781142f},
+ {0.890370f, 2.502600f, 0.653431f},
+ {0.979002f, 2.502600f, 0.509349f},
+ {1.044926f, 2.502600f, 0.351008f},
+ {1.086029f, 2.502600f, 0.180521f},
+ {1.100200f, 2.502600f, -0.000000f},
+ {0.197684f, 2.474400f, 1.189282f},
+ {0.000000f, 2.474400f, 1.204800f},
+ {0.384379f, 2.474400f, 1.144271f},
+ {0.557774f, 2.474400f, 1.072079f},
+ {0.715555f, 2.474400f, 0.975021f},
+ {0.855408f, 2.474400f, 0.855408f},
+ {0.975021f, 2.474400f, 0.715555f},
+ {1.072079f, 2.474400f, 0.557774f},
+ {1.144271f, 2.474400f, 0.384379f},
+ {1.189282f, 2.474400f, 0.197684f},
+ {1.204800f, 2.474400f, -0.000000f},
+ {0.209136f, 2.440800f, 1.258183f},
+ {0.000000f, 2.440800f, 1.274600f},
+ {0.406648f, 2.440800f, 1.210564f},
+ {0.590089f, 2.440800f, 1.134190f},
+ {0.757010f, 2.440800f, 1.031508f},
+ {0.904966f, 2.440800f, 0.904966f},
+ {1.031508f, 2.440800f, 0.757010f},
+ {1.134190f, 2.440800f, 0.590089f},
+ {1.210564f, 2.440800f, 0.406648f},
+ {1.258183f, 2.440800f, 0.209136f},
+ {1.274600f, 2.440800f, 0.000000f},
+ {0.213304f, 2.400000f, 1.283256f},
+ {0.000000f, 2.400000f, 1.300000f},
+ {0.414752f, 2.400000f, 1.234688f},
+ {0.601848f, 2.400000f, 1.156792f},
+ {0.772096f, 2.400000f, 1.052064f},
+ {0.923000f, 2.400000f, 0.923000f},
+ {1.052064f, 2.400000f, 0.772096f},
+ {1.156792f, 2.400000f, 0.601848f},
+ {1.234688f, 2.400000f, 0.414752f},
+ {1.283256f, 2.400000f, 0.213304f},
+ {1.300000f, 2.400000f, -0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.388275f, 0.002175f, 0.000000f},
+ {0.383274f, 0.002175f, 0.063708f},
+ {0.368768f, 0.002175f, 0.123875f},
+ {0.345503f, 0.002175f, 0.179756f},
+ {0.314223f, 0.002175f, 0.230604f},
+ {0.275675f, 0.002175f, 0.275675f},
+ {0.230604f, 0.002175f, 0.314223f},
+ {0.179756f, 0.002175f, 0.345503f},
+ {0.123875f, 0.002175f, 0.368768f},
+ {0.063708f, 0.002175f, 0.383274f},
+ {-0.000000f, 0.002175f, 0.388275f},
+ {0.694143f, 0.008400f, 0.115381f},
+ {0.703200f, 0.008400f, 0.000000f},
+ {0.667871f, 0.008400f, 0.224349f},
+ {0.625735f, 0.008400f, 0.325553f},
+ {0.569086f, 0.008400f, 0.417645f},
+ {0.499272f, 0.008400f, 0.499272f},
+ {0.417645f, 0.008400f, 0.569086f},
+ {0.325553f, 0.008400f, 0.625735f},
+ {0.224349f, 0.008400f, 0.667871f},
+ {0.115381f, 0.008400f, 0.694143f},
+ {0.000000f, 0.008400f, 0.703200f},
+ {0.940158f, 0.018225f, 0.156274f},
+ {0.952425f, 0.018225f, 0.000000f},
+ {0.904575f, 0.018225f, 0.303862f},
+ {0.847506f, 0.018225f, 0.440935f},
+ {0.770779f, 0.018225f, 0.565664f},
+ {0.676222f, 0.018225f, 0.676222f},
+ {0.565664f, 0.018225f, 0.770779f},
+ {0.440935f, 0.018225f, 0.847506f},
+ {0.303862f, 0.018225f, 0.904575f},
+ {0.156274f, 0.018225f, 0.940158f},
+ {-0.000000f, 0.018225f, 0.952425f},
+ {1.128870f, 0.031200f, 0.187642f},
+ {1.143600f, 0.031200f, 0.000000f},
+ {1.086146f, 0.031200f, 0.364854f},
+ {1.017621f, 0.031200f, 0.529441f},
+ {0.925493f, 0.031200f, 0.679207f},
+ {0.811956f, 0.031200f, 0.811956f},
+ {0.679207f, 0.031200f, 0.925493f},
+ {0.529441f, 0.031200f, 1.017621f},
+ {0.364854f, 0.031200f, 1.086146f},
+ {0.187642f, 0.031200f, 1.128870f},
+ {0.000000f, 0.031200f, 1.143600f},
+ {1.267832f, 0.046875f, 0.210740f},
+ {1.284375f, 0.046875f, 0.000000f},
+ {1.219848f, 0.046875f, 0.409767f},
+ {1.142888f, 0.046875f, 0.594614f},
+ {1.039419f, 0.046875f, 0.762816f},
+ {0.911906f, 0.046875f, 0.911906f},
+ {0.762816f, 0.046875f, 1.039419f},
+ {0.594614f, 0.046875f, 1.142888f},
+ {0.409767f, 0.046875f, 1.219848f},
+ {0.210740f, 0.046875f, 1.267832f},
+ {0.000000f, 0.046875f, 1.284375f},
+ {1.364595f, 0.064800f, 0.226824f},
+ {1.382400f, 0.064800f, 0.000000f},
+ {1.312948f, 0.064800f, 0.441041f},
+ {1.230115f, 0.064800f, 0.639996f},
+ {1.118749f, 0.064800f, 0.821035f},
+ {0.981504f, 0.064800f, 0.981504f},
+ {0.821035f, 0.064800f, 1.118749f},
+ {0.639996f, 0.064800f, 1.230115f},
+ {0.441041f, 0.064800f, 1.312948f},
+ {0.226824f, 0.064800f, 1.364595f},
+ {-0.000000f, 0.064800f, 1.382400f},
+ {1.426709f, 0.084525f, 0.237149f},
+ {1.445325f, 0.084525f, 0.000000f},
+ {1.372712f, 0.084525f, 0.461116f},
+ {1.286108f, 0.084525f, 0.669128f},
+ {1.169673f, 0.084525f, 0.858407f},
+ {1.026181f, 0.084525f, 1.026181f},
+ {0.858407f, 0.084525f, 1.169673f},
+ {0.669128f, 0.084525f, 1.286108f},
+ {0.461116f, 0.084525f, 1.372712f},
+ {0.237149f, 0.084525f, 1.426709f},
+ {0.000000f, 0.084525f, 1.445325f},
+ {1.461727f, 0.105600f, 0.242970f},
+ {1.480800f, 0.105600f, 0.000000f},
+ {1.406405f, 0.105600f, 0.472434f},
+ {1.317675f, 0.105600f, 0.685551f},
+ {1.198382f, 0.105600f, 0.879477f},
+ {1.051368f, 0.105600f, 1.051368f},
+ {0.879477f, 0.105600f, 1.198382f},
+ {0.685551f, 0.105600f, 1.317675f},
+ {0.472434f, 0.105600f, 1.406405f},
+ {0.242970f, 0.105600f, 1.461727f},
+ {-0.000000f, 0.105600f, 1.480800f},
+ {1.477200f, 0.127575f, 0.245542f},
+ {1.496475f, 0.127575f, 0.000000f},
+ {1.421292f, 0.127575f, 0.477435f},
+ {1.331623f, 0.127575f, 0.692808f},
+ {1.211067f, 0.127575f, 0.888786f},
+ {1.062497f, 0.127575f, 1.062497f},
+ {0.888786f, 0.127575f, 1.211067f},
+ {0.692808f, 0.127575f, 1.331623f},
+ {0.477435f, 0.127575f, 1.421292f},
+ {0.245542f, 0.127575f, 1.477200f},
+ {-0.000000f, 0.127575f, 1.496475f},
+ {1.480680f, 0.150000f, 0.246120f},
+ {1.424640f, 0.150000f, 0.478560f},
+ {1.334760f, 0.150000f, 0.694440f},
+ {1.213920f, 0.150000f, 0.890880f},
+ {0.890880f, 0.150000f, 1.213920f},
+ {0.694440f, 0.150000f, 1.334760f},
+ {0.478560f, 0.150000f, 1.424640f},
+ {0.246120f, 0.150000f, 1.480680f},
+ {0.000000f, 0.002175f, 0.388275f},
+ {-0.063708f, 0.002175f, 0.383274f},
+ {-0.123875f, 0.002175f, 0.368768f},
+ {-0.179756f, 0.002175f, 0.345503f},
+ {-0.230604f, 0.002175f, 0.314223f},
+ {-0.275675f, 0.002175f, 0.275675f},
+ {-0.314223f, 0.002175f, 0.230604f},
+ {-0.345503f, 0.002175f, 0.179756f},
+ {-0.368768f, 0.002175f, 0.123875f},
+ {-0.383274f, 0.002175f, 0.063708f},
+ {-0.388275f, 0.002175f, -0.000000f},
+ {-0.115381f, 0.008400f, 0.694143f},
+ {-0.224349f, 0.008400f, 0.667871f},
+ {-0.325553f, 0.008400f, 0.625735f},
+ {-0.417645f, 0.008400f, 0.569086f},
+ {-0.499272f, 0.008400f, 0.499272f},
+ {-0.569086f, 0.008400f, 0.417645f},
+ {-0.625735f, 0.008400f, 0.325553f},
+ {-0.667871f, 0.008400f, 0.224349f},
+ {-0.694143f, 0.008400f, 0.115381f},
+ {-0.703200f, 0.008400f, 0.000000f},
+ {-0.156274f, 0.018225f, 0.940158f},
+ {0.000000f, 0.018225f, 0.952425f},
+ {-0.303862f, 0.018225f, 0.904575f},
+ {-0.440935f, 0.018225f, 0.847506f},
+ {-0.565664f, 0.018225f, 0.770779f},
+ {-0.676222f, 0.018225f, 0.676222f},
+ {-0.770779f, 0.018225f, 0.565664f},
+ {-0.847506f, 0.018225f, 0.440935f},
+ {-0.904575f, 0.018225f, 0.303862f},
+ {-0.940158f, 0.018225f, 0.156274f},
+ {-0.952425f, 0.018225f, -0.000000f},
+ {-0.187642f, 0.031200f, 1.128870f},
+ {0.000000f, 0.031200f, 1.143600f},
+ {-0.364854f, 0.031200f, 1.086146f},
+ {-0.529441f, 0.031200f, 1.017621f},
+ {-0.679207f, 0.031200f, 0.925493f},
+ {-0.811956f, 0.031200f, 0.811956f},
+ {-0.925493f, 0.031200f, 0.679207f},
+ {-1.017621f, 0.031200f, 0.529441f},
+ {-1.086146f, 0.031200f, 0.364854f},
+ {-1.128870f, 0.031200f, 0.187642f},
+ {-1.143600f, 0.031200f, 0.000000f},
+ {-0.210740f, 0.046875f, 1.267832f},
+ {0.000000f, 0.046875f, 1.284375f},
+ {-0.409767f, 0.046875f, 1.219848f},
+ {-0.594614f, 0.046875f, 1.142888f},
+ {-0.762816f, 0.046875f, 1.039419f},
+ {-0.911906f, 0.046875f, 0.911906f},
+ {-1.039419f, 0.046875f, 0.762816f},
+ {-1.142888f, 0.046875f, 0.594614f},
+ {-1.219848f, 0.046875f, 0.409767f},
+ {-1.267832f, 0.046875f, 0.210740f},
+ {-1.284375f, 0.046875f, 0.000000f},
+ {-0.226824f, 0.064800f, 1.364595f},
+ {0.000000f, 0.064800f, 1.382400f},
+ {-0.441041f, 0.064800f, 1.312948f},
+ {-0.639996f, 0.064800f, 1.230115f},
+ {-0.821035f, 0.064800f, 1.118749f},
+ {-0.981504f, 0.064800f, 0.981504f},
+ {-1.118749f, 0.064800f, 0.821035f},
+ {-1.230115f, 0.064800f, 0.639996f},
+ {-1.312948f, 0.064800f, 0.441041f},
+ {-1.364595f, 0.064800f, 0.226824f},
+ {-1.382400f, 0.064800f, -0.000000f},
+ {-0.237149f, 0.084525f, 1.426709f},
+ {0.000000f, 0.084525f, 1.445325f},
+ {-0.461116f, 0.084525f, 1.372712f},
+ {-0.669128f, 0.084525f, 1.286108f},
+ {-0.858407f, 0.084525f, 1.169673f},
+ {-1.026181f, 0.084525f, 1.026181f},
+ {-1.169673f, 0.084525f, 0.858407f},
+ {-1.286108f, 0.084525f, 0.669128f},
+ {-1.372712f, 0.084525f, 0.461116f},
+ {-1.426709f, 0.084525f, 0.237149f},
+ {-1.445325f, 0.084525f, 0.000000f},
+ {-0.242970f, 0.105600f, 1.461727f},
+ {0.000000f, 0.105600f, 1.480800f},
+ {-0.472434f, 0.105600f, 1.406405f},
+ {-0.685551f, 0.105600f, 1.317675f},
+ {-0.879477f, 0.105600f, 1.198382f},
+ {-1.051368f, 0.105600f, 1.051368f},
+ {-1.198382f, 0.105600f, 0.879477f},
+ {-1.317675f, 0.105600f, 0.685551f},
+ {-1.406405f, 0.105600f, 0.472434f},
+ {-1.461727f, 0.105600f, 0.242970f},
+ {-1.480800f, 0.105600f, -0.000000f},
+ {-0.245542f, 0.127575f, 1.477200f},
+ {0.000000f, 0.127575f, 1.496475f},
+ {-0.477435f, 0.127575f, 1.421292f},
+ {-0.692808f, 0.127575f, 1.331623f},
+ {-0.888786f, 0.127575f, 1.211067f},
+ {-1.062497f, 0.127575f, 1.062497f},
+ {-1.211067f, 0.127575f, 0.888786f},
+ {-1.331623f, 0.127575f, 0.692808f},
+ {-1.421292f, 0.127575f, 0.477435f},
+ {-1.477200f, 0.127575f, 0.245542f},
+ {-1.496475f, 0.127575f, -0.000000f},
+ {-0.246120f, 0.150000f, 1.480680f},
+ {-0.478560f, 0.150000f, 1.424640f},
+ {-0.694440f, 0.150000f, 1.334760f},
+ {-0.890880f, 0.150000f, 1.213920f},
+ {-1.213920f, 0.150000f, 0.890880f},
+ {-1.334760f, 0.150000f, 0.694440f},
+ {-1.424640f, 0.150000f, 0.478560f},
+ {-1.480680f, 0.150000f, 0.246120f},
+ {-0.388275f, 0.002175f, 0.000000f},
+ {-0.383274f, 0.002175f, -0.063708f},
+ {-0.368768f, 0.002175f, -0.123875f},
+ {-0.345503f, 0.002175f, -0.179756f},
+ {-0.314223f, 0.002175f, -0.230604f},
+ {-0.275675f, 0.002175f, -0.275675f},
+ {-0.230604f, 0.002175f, -0.314223f},
+ {-0.179756f, 0.002175f, -0.345503f},
+ {-0.123875f, 0.002175f, -0.368768f},
+ {-0.063708f, 0.002175f, -0.383274f},
+ {0.000000f, 0.002175f, -0.388275f},
+ {-0.694143f, 0.008400f, -0.115381f},
+ {-0.667871f, 0.008400f, -0.224349f},
+ {-0.625735f, 0.008400f, -0.325553f},
+ {-0.569086f, 0.008400f, -0.417645f},
+ {-0.499272f, 0.008400f, -0.499272f},
+ {-0.417645f, 0.008400f, -0.569086f},
+ {-0.325553f, 0.008400f, -0.625735f},
+ {-0.224349f, 0.008400f, -0.667871f},
+ {-0.115381f, 0.008400f, -0.694143f},
+ {0.000000f, 0.008400f, -0.703200f},
+ {-0.940158f, 0.018225f, -0.156274f},
+ {-0.952425f, 0.018225f, 0.000000f},
+ {-0.904575f, 0.018225f, -0.303862f},
+ {-0.847506f, 0.018225f, -0.440935f},
+ {-0.770779f, 0.018225f, -0.565664f},
+ {-0.676222f, 0.018225f, -0.676222f},
+ {-0.565664f, 0.018225f, -0.770779f},
+ {-0.440935f, 0.018225f, -0.847506f},
+ {-0.303862f, 0.018225f, -0.904575f},
+ {-0.156274f, 0.018225f, -0.940158f},
+ {0.000000f, 0.018225f, -0.952425f},
+ {-1.128870f, 0.031200f, -0.187642f},
+ {-1.143600f, 0.031200f, 0.000000f},
+ {-1.086146f, 0.031200f, -0.364854f},
+ {-1.017621f, 0.031200f, -0.529441f},
+ {-0.925493f, 0.031200f, -0.679207f},
+ {-0.811956f, 0.031200f, -0.811956f},
+ {-0.679207f, 0.031200f, -0.925493f},
+ {-0.529441f, 0.031200f, -1.017621f},
+ {-0.364854f, 0.031200f, -1.086146f},
+ {-0.187642f, 0.031200f, -1.128870f},
+ {0.000000f, 0.031200f, -1.143600f},
+ {-1.267832f, 0.046875f, -0.210740f},
+ {-1.284375f, 0.046875f, 0.000000f},
+ {-1.219848f, 0.046875f, -0.409767f},
+ {-1.142888f, 0.046875f, -0.594614f},
+ {-1.039419f, 0.046875f, -0.762816f},
+ {-0.911906f, 0.046875f, -0.911906f},
+ {-0.762816f, 0.046875f, -1.039419f},
+ {-0.594614f, 0.046875f, -1.142888f},
+ {-0.409767f, 0.046875f, -1.219848f},
+ {-0.210740f, 0.046875f, -1.267832f},
+ {-0.000000f, 0.046875f, -1.284375f},
+ {-1.364595f, 0.064800f, -0.226824f},
+ {-1.382400f, 0.064800f, 0.000000f},
+ {-1.312948f, 0.064800f, -0.441041f},
+ {-1.230115f, 0.064800f, -0.639996f},
+ {-1.118749f, 0.064800f, -0.821035f},
+ {-0.981504f, 0.064800f, -0.981504f},
+ {-0.821035f, 0.064800f, -1.118749f},
+ {-0.639996f, 0.064800f, -1.230115f},
+ {-0.441041f, 0.064800f, -1.312948f},
+ {-0.226824f, 0.064800f, -1.364595f},
+ {0.000000f, 0.064800f, -1.382400f},
+ {-1.426709f, 0.084525f, -0.237149f},
+ {-1.445325f, 0.084525f, 0.000000f},
+ {-1.372712f, 0.084525f, -0.461116f},
+ {-1.286108f, 0.084525f, -0.669128f},
+ {-1.169673f, 0.084525f, -0.858407f},
+ {-1.026181f, 0.084525f, -1.026181f},
+ {-0.858407f, 0.084525f, -1.169673f},
+ {-0.669128f, 0.084525f, -1.286108f},
+ {-0.461116f, 0.084525f, -1.372712f},
+ {-0.237149f, 0.084525f, -1.426709f},
+ {0.000000f, 0.084525f, -1.445325f},
+ {-1.461727f, 0.105600f, -0.242970f},
+ {-1.480800f, 0.105600f, 0.000000f},
+ {-1.406405f, 0.105600f, -0.472434f},
+ {-1.317675f, 0.105600f, -0.685551f},
+ {-1.198382f, 0.105600f, -0.879477f},
+ {-1.051368f, 0.105600f, -1.051368f},
+ {-0.879477f, 0.105600f, -1.198382f},
+ {-0.685551f, 0.105600f, -1.317675f},
+ {-0.472434f, 0.105600f, -1.406405f},
+ {-0.242970f, 0.105600f, -1.461727f},
+ {0.000000f, 0.105600f, -1.480800f},
+ {-1.477200f, 0.127575f, -0.245542f},
+ {-1.496475f, 0.127575f, 0.000000f},
+ {-1.421292f, 0.127575f, -0.477435f},
+ {-1.331623f, 0.127575f, -0.692808f},
+ {-1.211067f, 0.127575f, -0.888786f},
+ {-1.062497f, 0.127575f, -1.062497f},
+ {-0.888786f, 0.127575f, -1.211067f},
+ {-0.692808f, 0.127575f, -1.331623f},
+ {-0.477435f, 0.127575f, -1.421292f},
+ {-0.245542f, 0.127575f, -1.477200f},
+ {0.000000f, 0.127575f, -1.496475f},
+ {-1.480680f, 0.150000f, -0.246120f},
+ {-1.424640f, 0.150000f, -0.478560f},
+ {-1.334760f, 0.150000f, -0.694440f},
+ {-1.213920f, 0.150000f, -0.890880f},
+ {-0.890880f, 0.150000f, -1.213920f},
+ {-0.694440f, 0.150000f, -1.334760f},
+ {-0.478560f, 0.150000f, -1.424640f},
+ {-0.246120f, 0.150000f, -1.480680f},
+ {0.000000f, 0.002175f, -0.388275f},
+ {0.063708f, 0.002175f, -0.383274f},
+ {0.123875f, 0.002175f, -0.368768f},
+ {0.179756f, 0.002175f, -0.345503f},
+ {0.230604f, 0.002175f, -0.314223f},
+ {0.275675f, 0.002175f, -0.275675f},
+ {0.314223f, 0.002175f, -0.230604f},
+ {0.345503f, 0.002175f, -0.179756f},
+ {0.368768f, 0.002175f, -0.123875f},
+ {0.383274f, 0.002175f, -0.063708f},
+ {0.388275f, 0.002175f, 0.000000f},
+ {0.115381f, 0.008400f, -0.694143f},
+ {0.224349f, 0.008400f, -0.667871f},
+ {0.325553f, 0.008400f, -0.625735f},
+ {0.417645f, 0.008400f, -0.569086f},
+ {0.499272f, 0.008400f, -0.499272f},
+ {0.569086f, 0.008400f, -0.417645f},
+ {0.625735f, 0.008400f, -0.325553f},
+ {0.667871f, 0.008400f, -0.224349f},
+ {0.694143f, 0.008400f, -0.115381f},
+ {0.156274f, 0.018225f, -0.940158f},
+ {0.000000f, 0.018225f, -0.952425f},
+ {0.303862f, 0.018225f, -0.904575f},
+ {0.440935f, 0.018225f, -0.847506f},
+ {0.565664f, 0.018225f, -0.770779f},
+ {0.676222f, 0.018225f, -0.676222f},
+ {0.770779f, 0.018225f, -0.565664f},
+ {0.847506f, 0.018225f, -0.440935f},
+ {0.904575f, 0.018225f, -0.303862f},
+ {0.940158f, 0.018225f, -0.156274f},
+ {0.952425f, 0.018225f, 0.000000f},
+ {0.187642f, 0.031200f, -1.128870f},
+ {0.000000f, 0.031200f, -1.143600f},
+ {0.364854f, 0.031200f, -1.086146f},
+ {0.529441f, 0.031200f, -1.017621f},
+ {0.679207f, 0.031200f, -0.925493f},
+ {0.811956f, 0.031200f, -0.811956f},
+ {0.925493f, 0.031200f, -0.679207f},
+ {1.017621f, 0.031200f, -0.529441f},
+ {1.086146f, 0.031200f, -0.364854f},
+ {1.128870f, 0.031200f, -0.187642f},
+ {1.143600f, 0.031200f, 0.000000f},
+ {0.210740f, 0.046875f, -1.267832f},
+ {0.000000f, 0.046875f, -1.284375f},
+ {0.409767f, 0.046875f, -1.219848f},
+ {0.594614f, 0.046875f, -1.142888f},
+ {0.762816f, 0.046875f, -1.039419f},
+ {0.911906f, 0.046875f, -0.911906f},
+ {1.039419f, 0.046875f, -0.762816f},
+ {1.142888f, 0.046875f, -0.594614f},
+ {1.219848f, 0.046875f, -0.409767f},
+ {1.267832f, 0.046875f, -0.210740f},
+ {1.284375f, 0.046875f, -0.000000f},
+ {0.226824f, 0.064800f, -1.364595f},
+ {0.000000f, 0.064800f, -1.382400f},
+ {0.441041f, 0.064800f, -1.312948f},
+ {0.639996f, 0.064800f, -1.230115f},
+ {0.821035f, 0.064800f, -1.118749f},
+ {0.981504f, 0.064800f, -0.981504f},
+ {1.118749f, 0.064800f, -0.821035f},
+ {1.230115f, 0.064800f, -0.639996f},
+ {1.312948f, 0.064800f, -0.441041f},
+ {1.364595f, 0.064800f, -0.226824f},
+ {1.382400f, 0.064800f, 0.000000f},
+ {0.237149f, 0.084525f, -1.426709f},
+ {0.000000f, 0.084525f, -1.445325f},
+ {0.461116f, 0.084525f, -1.372712f},
+ {0.669128f, 0.084525f, -1.286108f},
+ {0.858407f, 0.084525f, -1.169673f},
+ {1.026181f, 0.084525f, -1.026181f},
+ {1.169673f, 0.084525f, -0.858407f},
+ {1.286108f, 0.084525f, -0.669128f},
+ {1.372712f, 0.084525f, -0.461116f},
+ {1.426709f, 0.084525f, -0.237149f},
+ {1.445325f, 0.084525f, 0.000000f},
+ {0.242970f, 0.105600f, -1.461727f},
+ {0.000000f, 0.105600f, -1.480800f},
+ {0.472434f, 0.105600f, -1.406405f},
+ {0.685551f, 0.105600f, -1.317675f},
+ {0.879477f, 0.105600f, -1.198382f},
+ {1.051368f, 0.105600f, -1.051368f},
+ {1.198382f, 0.105600f, -0.879477f},
+ {1.317675f, 0.105600f, -0.685551f},
+ {1.406405f, 0.105600f, -0.472434f},
+ {1.461727f, 0.105600f, -0.242970f},
+ {1.480800f, 0.105600f, 0.000000f},
+ {0.245542f, 0.127575f, -1.477200f},
+ {0.000000f, 0.127575f, -1.496475f},
+ {0.477435f, 0.127575f, -1.421292f},
+ {0.692808f, 0.127575f, -1.331623f},
+ {0.888786f, 0.127575f, -1.211067f},
+ {1.062497f, 0.127575f, -1.062497f},
+ {1.211067f, 0.127575f, -0.888786f},
+ {1.331623f, 0.127575f, -0.692808f},
+ {1.421292f, 0.127575f, -0.477435f},
+ {1.477200f, 0.127575f, -0.245542f},
+ {1.496475f, 0.127575f, 0.000000f},
+ {0.246120f, 0.150000f, -1.480680f},
+ {0.478560f, 0.150000f, -1.424640f},
+ {0.694440f, 0.150000f, -1.334760f},
+ {0.890880f, 0.150000f, -1.213920f},
+ {1.213920f, 0.150000f, -0.890880f},
+ {1.334760f, 0.150000f, -0.694440f},
+ {1.424640f, 0.150000f, -0.478560f},
+ {1.480680f, 0.150000f, -0.246120f},
+};
+
+static const float teapot_texcoords[TEAPOT_VERTEX_COUNT][2] = {
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+ {0.000000f, 0.000000f},
+};
+
+static const float teapot_normals[TEAPOT_VERTEX_COUNT][3] = {
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+ {0.000000f, 0.000000f, 0.000000f},
+};
+
+static const uint16_t teapot_indices[TEAPOT_INDEX_COUNT] = {
+ 0, 1, 2,
+ 2, 3, 0,
+ 4, 5, 1,
+ 1, 0, 4,
+ 6, 7, 5,
+ 5, 4, 6,
+ 8, 9, 7,
+ 7, 6, 8,
+ 10, 11, 9,
+ 9, 8, 10,
+ 12, 13, 11,
+ 11, 10, 12,
+ 14, 15, 13,
+ 13, 12, 14,
+ 16, 17, 15,
+ 15, 14, 16,
+ 18, 19, 17,
+ 17, 16, 18,
+ 20, 21, 19,
+ 19, 18, 20,
+ 22, 0, 3,
+ 3, 23, 22,
+ 24, 4, 0,
+ 0, 22, 24,
+ 25, 6, 4,
+ 4, 24, 25,
+ 26, 8, 6,
+ 6, 25, 26,
+ 27, 10, 8,
+ 8, 26, 27,
+ 28, 12, 10,
+ 10, 27, 28,
+ 29, 14, 12,
+ 12, 28, 29,
+ 30, 16, 14,
+ 14, 29, 30,
+ 31, 18, 16,
+ 16, 30, 31,
+ 32, 20, 18,
+ 18, 31, 32,
+ 33, 22, 23,
+ 23, 34, 33,
+ 35, 24, 22,
+ 22, 33, 35,
+ 36, 25, 24,
+ 24, 35, 36,
+ 37, 26, 25,
+ 25, 36, 37,
+ 38, 27, 26,
+ 26, 37, 38,
+ 39, 28, 27,
+ 27, 38, 39,
+ 40, 29, 28,
+ 28, 39, 40,
+ 41, 30, 29,
+ 29, 40, 41,
+ 42, 31, 30,
+ 30, 41, 42,
+ 43, 32, 31,
+ 31, 42, 43,
+ 44, 33, 34,
+ 34, 45, 44,
+ 46, 35, 33,
+ 33, 44, 46,
+ 47, 36, 35,
+ 35, 46, 47,
+ 48, 37, 36,
+ 36, 47, 48,
+ 49, 38, 37,
+ 37, 48, 49,
+ 50, 39, 38,
+ 38, 49, 50,
+ 51, 40, 39,
+ 39, 50, 51,
+ 52, 41, 40,
+ 40, 51, 52,
+ 53, 42, 41,
+ 41, 52, 53,
+ 54, 43, 42,
+ 42, 53, 54,
+ 55, 44, 45,
+ 45, 56, 55,
+ 57, 46, 44,
+ 44, 55, 57,
+ 58, 47, 46,
+ 46, 57, 58,
+ 59, 48, 47,
+ 47, 58, 59,
+ 60, 49, 48,
+ 48, 59, 60,
+ 61, 50, 49,
+ 49, 60, 61,
+ 62, 51, 50,
+ 50, 61, 62,
+ 63, 52, 51,
+ 51, 62, 63,
+ 64, 53, 52,
+ 52, 63, 64,
+ 65, 54, 53,
+ 53, 64, 65,
+ 66, 55, 56,
+ 56, 67, 66,
+ 68, 57, 55,
+ 55, 66, 68,
+ 69, 58, 57,
+ 57, 68, 69,
+ 70, 59, 58,
+ 58, 69, 70,
+ 71, 60, 59,
+ 59, 70, 71,
+ 72, 61, 60,
+ 60, 71, 72,
+ 73, 62, 61,
+ 61, 72, 73,
+ 74, 63, 62,
+ 62, 73, 74,
+ 75, 64, 63,
+ 63, 74, 75,
+ 76, 65, 64,
+ 64, 75, 76,
+ 77, 66, 67,
+ 67, 78, 77,
+ 79, 68, 66,
+ 66, 77, 79,
+ 80, 69, 68,
+ 68, 79, 80,
+ 81, 70, 69,
+ 69, 80, 81,
+ 82, 71, 70,
+ 70, 81, 82,
+ 83, 72, 71,
+ 71, 82, 83,
+ 84, 73, 72,
+ 72, 83, 84,
+ 85, 74, 73,
+ 73, 84, 85,
+ 86, 75, 74,
+ 74, 85, 86,
+ 87, 76, 75,
+ 75, 86, 87,
+ 88, 77, 78,
+ 78, 89, 88,
+ 90, 79, 77,
+ 77, 88, 90,
+ 91, 80, 79,
+ 79, 90, 91,
+ 92, 81, 80,
+ 80, 91, 92,
+ 93, 82, 81,
+ 81, 92, 93,
+ 94, 83, 82,
+ 82, 93, 94,
+ 95, 84, 83,
+ 83, 94, 95,
+ 96, 85, 84,
+ 84, 95, 96,
+ 97, 86, 85,
+ 85, 96, 97,
+ 98, 87, 86,
+ 86, 97, 98,
+ 99, 88, 89,
+ 89, 100, 99,
+ 101, 90, 88,
+ 88, 99, 101,
+ 102, 91, 90,
+ 90, 101, 102,
+ 103, 92, 91,
+ 91, 102, 103,
+ 104, 93, 92,
+ 92, 103, 104,
+ 105, 94, 93,
+ 93, 104, 105,
+ 106, 95, 94,
+ 94, 105, 106,
+ 107, 96, 95,
+ 95, 106, 107,
+ 108, 97, 96,
+ 96, 107, 108,
+ 109, 98, 97,
+ 97, 108, 109,
+ 110, 99, 100,
+ 100, 111, 110,
+ 112, 101, 99,
+ 99, 110, 112,
+ 113, 102, 101,
+ 101, 112, 113,
+ 114, 103, 102,
+ 102, 113, 114,
+ 115, 104, 103,
+ 103, 114, 115,
+ 116, 105, 104,
+ 104, 115, 116,
+ 117, 106, 105,
+ 105, 116, 117,
+ 118, 107, 106,
+ 106, 117, 118,
+ 119, 108, 107,
+ 107, 118, 119,
+ 120, 109, 108,
+ 108, 119, 120,
+ 121, 122, 123,
+ 123, 124, 121,
+ 125, 126, 122,
+ 122, 121, 125,
+ 127, 128, 126,
+ 126, 125, 127,
+ 129, 130, 128,
+ 128, 127, 129,
+ 131, 132, 130,
+ 130, 129, 131,
+ 133, 134, 132,
+ 132, 131, 133,
+ 135, 136, 134,
+ 134, 133, 135,
+ 137, 138, 136,
+ 136, 135, 137,
+ 139, 140, 138,
+ 138, 137, 139,
+ 141, 142, 140,
+ 140, 139, 141,
+ 143, 121, 124,
+ 124, 144, 143,
+ 145, 125, 121,
+ 121, 143, 145,
+ 146, 127, 125,
+ 125, 145, 146,
+ 147, 129, 127,
+ 127, 146, 147,
+ 148, 131, 129,
+ 129, 147, 148,
+ 149, 133, 131,
+ 131, 148, 149,
+ 150, 135, 133,
+ 133, 149, 150,
+ 151, 137, 135,
+ 135, 150, 151,
+ 152, 139, 137,
+ 137, 151, 152,
+ 153, 141, 139,
+ 139, 152, 153,
+ 154, 143, 144,
+ 144, 155, 154,
+ 156, 145, 143,
+ 143, 154, 156,
+ 157, 146, 145,
+ 145, 156, 157,
+ 158, 147, 146,
+ 146, 157, 158,
+ 159, 148, 147,
+ 147, 158, 159,
+ 160, 149, 148,
+ 148, 159, 160,
+ 161, 150, 149,
+ 149, 160, 161,
+ 162, 151, 150,
+ 150, 161, 162,
+ 163, 152, 151,
+ 151, 162, 163,
+ 164, 153, 152,
+ 152, 163, 164,
+ 165, 154, 155,
+ 155, 166, 165,
+ 167, 156, 154,
+ 154, 165, 167,
+ 168, 157, 156,
+ 156, 167, 168,
+ 169, 158, 157,
+ 157, 168, 169,
+ 170, 159, 158,
+ 158, 169, 170,
+ 171, 160, 159,
+ 159, 170, 171,
+ 172, 161, 160,
+ 160, 171, 172,
+ 173, 162, 161,
+ 161, 172, 173,
+ 174, 163, 162,
+ 162, 173, 174,
+ 175, 164, 163,
+ 163, 174, 175,
+ 176, 165, 166,
+ 166, 177, 176,
+ 178, 167, 165,
+ 165, 176, 178,
+ 179, 168, 167,
+ 167, 178, 179,
+ 180, 169, 168,
+ 168, 179, 180,
+ 181, 170, 169,
+ 169, 180, 181,
+ 182, 171, 170,
+ 170, 181, 182,
+ 183, 172, 171,
+ 171, 182, 183,
+ 184, 173, 172,
+ 172, 183, 184,
+ 185, 174, 173,
+ 173, 184, 185,
+ 186, 175, 174,
+ 174, 185, 186,
+ 187, 176, 177,
+ 177, 188, 187,
+ 189, 178, 176,
+ 176, 187, 189,
+ 190, 179, 178,
+ 178, 189, 190,
+ 191, 180, 179,
+ 179, 190, 191,
+ 192, 181, 180,
+ 180, 191, 192,
+ 193, 182, 181,
+ 181, 192, 193,
+ 194, 183, 182,
+ 182, 193, 194,
+ 195, 184, 183,
+ 183, 194, 195,
+ 196, 185, 184,
+ 184, 195, 196,
+ 197, 186, 185,
+ 185, 196, 197,
+ 198, 187, 188,
+ 188, 87, 198,
+ 199, 189, 187,
+ 187, 198, 199,
+ 200, 190, 189,
+ 189, 199, 200,
+ 201, 191, 190,
+ 190, 200, 201,
+ 202, 192, 191,
+ 191, 201, 202,
+ 203, 193, 192,
+ 192, 202, 203,
+ 204, 194, 193,
+ 193, 203, 204,
+ 205, 195, 194,
+ 194, 204, 205,
+ 206, 196, 195,
+ 195, 205, 206,
+ 207, 197, 196,
+ 196, 206, 207,
+ 208, 198, 87,
+ 87, 209, 208,
+ 210, 199, 198,
+ 198, 208, 210,
+ 211, 200, 199,
+ 199, 210, 211,
+ 212, 201, 200,
+ 200, 211, 212,
+ 213, 202, 201,
+ 201, 212, 213,
+ 214, 203, 202,
+ 202, 213, 214,
+ 215, 204, 203,
+ 203, 214, 215,
+ 216, 205, 204,
+ 204, 215, 216,
+ 217, 206, 205,
+ 205, 216, 217,
+ 218, 207, 206,
+ 206, 217, 218,
+ 219, 208, 209,
+ 209, 220, 219,
+ 221, 210, 208,
+ 208, 219, 221,
+ 222, 211, 210,
+ 210, 221, 222,
+ 223, 212, 211,
+ 211, 222, 223,
+ 224, 213, 212,
+ 212, 223, 224,
+ 225, 214, 213,
+ 213, 224, 225,
+ 226, 215, 214,
+ 214, 225, 226,
+ 227, 216, 215,
+ 215, 226, 227,
+ 228, 217, 216,
+ 216, 227, 228,
+ 229, 218, 217,
+ 217, 228, 229,
+ 230, 219, 220,
+ 220, 231, 230,
+ 232, 221, 219,
+ 219, 230, 232,
+ 233, 222, 221,
+ 221, 232, 233,
+ 234, 223, 222,
+ 222, 233, 234,
+ 235, 224, 223,
+ 223, 234, 235,
+ 236, 225, 224,
+ 224, 235, 236,
+ 237, 226, 225,
+ 225, 236, 237,
+ 238, 227, 226,
+ 226, 237, 238,
+ 239, 228, 227,
+ 227, 238, 239,
+ 240, 229, 228,
+ 228, 239, 240,
+ 241, 242, 243,
+ 243, 244, 241,
+ 245, 246, 242,
+ 242, 241, 245,
+ 247, 248, 246,
+ 246, 245, 247,
+ 249, 250, 248,
+ 248, 247, 249,
+ 251, 252, 250,
+ 250, 249, 251,
+ 253, 254, 252,
+ 252, 251, 253,
+ 255, 256, 254,
+ 254, 253, 255,
+ 257, 258, 256,
+ 256, 255, 257,
+ 259, 260, 258,
+ 258, 257, 259,
+ 261, 262, 260,
+ 260, 259, 261,
+ 263, 241, 244,
+ 244, 264, 263,
+ 265, 245, 241,
+ 241, 263, 265,
+ 266, 247, 245,
+ 245, 265, 266,
+ 267, 249, 247,
+ 247, 266, 267,
+ 268, 251, 249,
+ 249, 267, 268,
+ 269, 253, 251,
+ 251, 268, 269,
+ 270, 255, 253,
+ 253, 269, 270,
+ 271, 257, 255,
+ 255, 270, 271,
+ 272, 259, 257,
+ 257, 271, 272,
+ 273, 261, 259,
+ 259, 272, 273,
+ 274, 263, 264,
+ 264, 275, 274,
+ 276, 265, 263,
+ 263, 274, 276,
+ 277, 266, 265,
+ 265, 276, 277,
+ 278, 267, 266,
+ 266, 277, 278,
+ 279, 268, 267,
+ 267, 278, 279,
+ 280, 269, 268,
+ 268, 279, 280,
+ 281, 270, 269,
+ 269, 280, 281,
+ 282, 271, 270,
+ 270, 281, 282,
+ 283, 272, 271,
+ 271, 282, 283,
+ 284, 273, 272,
+ 272, 283, 284,
+ 285, 274, 275,
+ 275, 286, 285,
+ 287, 276, 274,
+ 274, 285, 287,
+ 288, 277, 276,
+ 276, 287, 288,
+ 289, 278, 277,
+ 277, 288, 289,
+ 290, 279, 278,
+ 278, 289, 290,
+ 291, 280, 279,
+ 279, 290, 291,
+ 292, 281, 280,
+ 280, 291, 292,
+ 293, 282, 281,
+ 281, 292, 293,
+ 294, 283, 282,
+ 282, 293, 294,
+ 295, 284, 283,
+ 283, 294, 295,
+ 296, 285, 286,
+ 286, 297, 296,
+ 298, 287, 285,
+ 285, 296, 298,
+ 299, 288, 287,
+ 287, 298, 299,
+ 300, 289, 288,
+ 288, 299, 300,
+ 301, 290, 289,
+ 289, 300, 301,
+ 302, 291, 290,
+ 290, 301, 302,
+ 303, 292, 291,
+ 291, 302, 303,
+ 304, 293, 292,
+ 292, 303, 304,
+ 305, 294, 293,
+ 293, 304, 305,
+ 306, 295, 294,
+ 294, 305, 306,
+ 307, 296, 297,
+ 297, 308, 307,
+ 309, 298, 296,
+ 296, 307, 309,
+ 310, 299, 298,
+ 298, 309, 310,
+ 311, 300, 299,
+ 299, 310, 311,
+ 312, 301, 300,
+ 300, 311, 312,
+ 313, 302, 301,
+ 301, 312, 313,
+ 314, 303, 302,
+ 302, 313, 314,
+ 315, 304, 303,
+ 303, 314, 315,
+ 316, 305, 304,
+ 304, 315, 316,
+ 317, 306, 305,
+ 305, 316, 317,
+ 318, 307, 308,
+ 308, 207, 318,
+ 319, 309, 307,
+ 307, 318, 319,
+ 320, 310, 309,
+ 309, 319, 320,
+ 321, 311, 310,
+ 310, 320, 321,
+ 322, 312, 311,
+ 311, 321, 322,
+ 323, 313, 312,
+ 312, 322, 323,
+ 324, 314, 313,
+ 313, 323, 324,
+ 325, 315, 314,
+ 314, 324, 325,
+ 326, 316, 315,
+ 315, 325, 326,
+ 327, 317, 316,
+ 316, 326, 327,
+ 328, 318, 207,
+ 207, 329, 328,
+ 330, 319, 318,
+ 318, 328, 330,
+ 331, 320, 319,
+ 319, 330, 331,
+ 332, 321, 320,
+ 320, 331, 332,
+ 333, 322, 321,
+ 321, 332, 333,
+ 334, 323, 322,
+ 322, 333, 334,
+ 335, 324, 323,
+ 323, 334, 335,
+ 336, 325, 324,
+ 324, 335, 336,
+ 337, 326, 325,
+ 325, 336, 337,
+ 338, 327, 326,
+ 326, 337, 338,
+ 339, 328, 329,
+ 329, 340, 339,
+ 341, 330, 328,
+ 328, 339, 341,
+ 342, 331, 330,
+ 330, 341, 342,
+ 343, 332, 331,
+ 331, 342, 343,
+ 344, 333, 332,
+ 332, 343, 344,
+ 345, 334, 333,
+ 333, 344, 345,
+ 346, 335, 334,
+ 334, 345, 346,
+ 347, 336, 335,
+ 335, 346, 347,
+ 348, 337, 336,
+ 336, 347, 348,
+ 349, 338, 337,
+ 337, 348, 349,
+ 350, 339, 340,
+ 340, 351, 350,
+ 352, 341, 339,
+ 339, 350, 352,
+ 353, 342, 341,
+ 341, 352, 353,
+ 354, 343, 342,
+ 342, 353, 354,
+ 355, 344, 343,
+ 343, 354, 355,
+ 356, 345, 344,
+ 344, 355, 356,
+ 357, 346, 345,
+ 345, 356, 357,
+ 358, 347, 346,
+ 346, 357, 358,
+ 359, 348, 347,
+ 347, 358, 359,
+ 360, 349, 348,
+ 348, 359, 360,
+ 361, 362, 363,
+ 363, 364, 361,
+ 365, 366, 362,
+ 362, 361, 365,
+ 367, 368, 366,
+ 366, 365, 367,
+ 369, 370, 368,
+ 368, 367, 369,
+ 371, 372, 370,
+ 370, 369, 371,
+ 373, 374, 372,
+ 372, 371, 373,
+ 375, 376, 374,
+ 374, 373, 375,
+ 377, 378, 376,
+ 376, 375, 377,
+ 379, 380, 378,
+ 378, 377, 379,
+ 381, 382, 380,
+ 380, 379, 381,
+ 383, 361, 364,
+ 364, 384, 383,
+ 385, 365, 361,
+ 361, 383, 385,
+ 386, 367, 365,
+ 365, 385, 386,
+ 387, 369, 367,
+ 367, 386, 387,
+ 388, 371, 369,
+ 369, 387, 388,
+ 389, 373, 371,
+ 371, 388, 389,
+ 390, 375, 373,
+ 373, 389, 390,
+ 391, 377, 375,
+ 375, 390, 391,
+ 392, 379, 377,
+ 377, 391, 392,
+ 393, 381, 379,
+ 379, 392, 393,
+ 394, 383, 384,
+ 384, 395, 394,
+ 396, 385, 383,
+ 383, 394, 396,
+ 397, 386, 385,
+ 385, 396, 397,
+ 398, 387, 386,
+ 386, 397, 398,
+ 399, 388, 387,
+ 387, 398, 399,
+ 400, 389, 388,
+ 388, 399, 400,
+ 401, 390, 389,
+ 389, 400, 401,
+ 402, 391, 390,
+ 390, 401, 402,
+ 403, 392, 391,
+ 391, 402, 403,
+ 404, 393, 392,
+ 392, 403, 404,
+ 405, 394, 395,
+ 395, 406, 405,
+ 407, 396, 394,
+ 394, 405, 407,
+ 408, 397, 396,
+ 396, 407, 408,
+ 409, 398, 397,
+ 397, 408, 409,
+ 410, 399, 398,
+ 398, 409, 410,
+ 411, 400, 399,
+ 399, 410, 411,
+ 412, 401, 400,
+ 400, 411, 412,
+ 413, 402, 401,
+ 401, 412, 413,
+ 414, 403, 402,
+ 402, 413, 414,
+ 415, 404, 403,
+ 403, 414, 415,
+ 416, 405, 406,
+ 406, 417, 416,
+ 418, 407, 405,
+ 405, 416, 418,
+ 419, 408, 407,
+ 407, 418, 419,
+ 420, 409, 408,
+ 408, 419, 420,
+ 421, 410, 409,
+ 409, 420, 421,
+ 422, 411, 410,
+ 410, 421, 422,
+ 423, 412, 411,
+ 411, 422, 423,
+ 424, 413, 412,
+ 412, 423, 424,
+ 425, 414, 413,
+ 413, 424, 425,
+ 426, 415, 414,
+ 414, 425, 426,
+ 427, 416, 417,
+ 417, 428, 427,
+ 429, 418, 416,
+ 416, 427, 429,
+ 430, 419, 418,
+ 418, 429, 430,
+ 431, 420, 419,
+ 419, 430, 431,
+ 432, 421, 420,
+ 420, 431, 432,
+ 433, 422, 421,
+ 421, 432, 433,
+ 434, 423, 422,
+ 422, 433, 434,
+ 435, 424, 423,
+ 423, 434, 435,
+ 436, 425, 424,
+ 424, 435, 436,
+ 437, 426, 425,
+ 425, 436, 437,
+ 438, 427, 428,
+ 428, 327, 438,
+ 439, 429, 427,
+ 427, 438, 439,
+ 440, 430, 429,
+ 429, 439, 440,
+ 441, 431, 430,
+ 430, 440, 441,
+ 442, 432, 431,
+ 431, 441, 442,
+ 443, 433, 432,
+ 432, 442, 443,
+ 444, 434, 433,
+ 433, 443, 444,
+ 445, 435, 434,
+ 434, 444, 445,
+ 446, 436, 435,
+ 435, 445, 446,
+ 78, 437, 436,
+ 436, 446, 78,
+ 447, 438, 327,
+ 327, 448, 447,
+ 449, 439, 438,
+ 438, 447, 449,
+ 450, 440, 439,
+ 439, 449, 450,
+ 451, 441, 440,
+ 440, 450, 451,
+ 452, 442, 441,
+ 441, 451, 452,
+ 453, 443, 442,
+ 442, 452, 453,
+ 454, 444, 443,
+ 443, 453, 454,
+ 455, 445, 444,
+ 444, 454, 455,
+ 456, 446, 445,
+ 445, 455, 456,
+ 457, 78, 446,
+ 446, 456, 457,
+ 458, 447, 448,
+ 448, 459, 458,
+ 460, 449, 447,
+ 447, 458, 460,
+ 461, 450, 449,
+ 449, 460, 461,
+ 462, 451, 450,
+ 450, 461, 462,
+ 463, 452, 451,
+ 451, 462, 463,
+ 464, 453, 452,
+ 452, 463, 464,
+ 465, 454, 453,
+ 453, 464, 465,
+ 466, 455, 454,
+ 454, 465, 466,
+ 467, 456, 455,
+ 455, 466, 467,
+ 468, 457, 456,
+ 456, 467, 468,
+ 469, 458, 459,
+ 459, 470, 469,
+ 471, 460, 458,
+ 458, 469, 471,
+ 472, 461, 460,
+ 460, 471, 472,
+ 473, 462, 461,
+ 461, 472, 473,
+ 474, 463, 462,
+ 462, 473, 474,
+ 475, 464, 463,
+ 463, 474, 475,
+ 476, 465, 464,
+ 464, 475, 476,
+ 477, 466, 465,
+ 465, 476, 477,
+ 478, 467, 466,
+ 466, 477, 478,
+ 479, 468, 467,
+ 467, 478, 479,
+ 480, 110, 111,
+ 111, 481, 480,
+ 482, 112, 110,
+ 110, 480, 482,
+ 483, 113, 112,
+ 112, 482, 483,
+ 484, 114, 113,
+ 113, 483, 484,
+ 485, 115, 114,
+ 114, 484, 485,
+ 486, 116, 115,
+ 115, 485, 486,
+ 487, 117, 116,
+ 116, 486, 487,
+ 488, 118, 117,
+ 117, 487, 488,
+ 489, 119, 118,
+ 118, 488, 489,
+ 490, 120, 119,
+ 119, 489, 490,
+ 491, 480, 481,
+ 481, 492, 491,
+ 493, 482, 480,
+ 480, 491, 493,
+ 494, 483, 482,
+ 482, 493, 494,
+ 495, 484, 483,
+ 483, 494, 495,
+ 496, 485, 484,
+ 484, 495, 496,
+ 497, 486, 485,
+ 485, 496, 497,
+ 498, 487, 486,
+ 486, 497, 498,
+ 499, 488, 487,
+ 487, 498, 499,
+ 500, 489, 488,
+ 488, 499, 500,
+ 501, 490, 489,
+ 489, 500, 501,
+ 502, 491, 492,
+ 492, 503, 502,
+ 504, 493, 491,
+ 491, 502, 504,
+ 505, 494, 493,
+ 493, 504, 505,
+ 506, 495, 494,
+ 494, 505, 506,
+ 507, 496, 495,
+ 495, 506, 507,
+ 508, 497, 496,
+ 496, 507, 508,
+ 509, 498, 497,
+ 497, 508, 509,
+ 510, 499, 498,
+ 498, 509, 510,
+ 511, 500, 499,
+ 499, 510, 511,
+ 512, 501, 500,
+ 500, 511, 512,
+ 513, 502, 503,
+ 503, 514, 513,
+ 515, 504, 502,
+ 502, 513, 515,
+ 516, 505, 504,
+ 504, 515, 516,
+ 517, 506, 505,
+ 505, 516, 517,
+ 518, 507, 506,
+ 506, 517, 518,
+ 519, 508, 507,
+ 507, 518, 519,
+ 520, 509, 508,
+ 508, 519, 520,
+ 521, 510, 509,
+ 509, 520, 521,
+ 522, 511, 510,
+ 510, 521, 522,
+ 523, 512, 511,
+ 511, 522, 523,
+ 524, 513, 514,
+ 514, 525, 524,
+ 526, 515, 513,
+ 513, 524, 526,
+ 527, 516, 515,
+ 515, 526, 527,
+ 528, 517, 516,
+ 516, 527, 528,
+ 529, 518, 517,
+ 517, 528, 529,
+ 530, 519, 518,
+ 518, 529, 530,
+ 531, 520, 519,
+ 519, 530, 531,
+ 532, 521, 520,
+ 520, 531, 532,
+ 533, 522, 521,
+ 521, 532, 533,
+ 534, 523, 522,
+ 522, 533, 534,
+ 535, 524, 525,
+ 525, 536, 535,
+ 537, 526, 524,
+ 524, 535, 537,
+ 538, 527, 526,
+ 526, 537, 538,
+ 539, 528, 527,
+ 527, 538, 539,
+ 540, 529, 528,
+ 528, 539, 540,
+ 541, 530, 529,
+ 529, 540, 541,
+ 542, 531, 530,
+ 530, 541, 542,
+ 543, 532, 531,
+ 531, 542, 543,
+ 544, 533, 532,
+ 532, 543, 544,
+ 545, 534, 533,
+ 533, 544, 545,
+ 546, 535, 536,
+ 536, 547, 546,
+ 548, 537, 535,
+ 535, 546, 548,
+ 549, 538, 537,
+ 537, 548, 549,
+ 550, 539, 538,
+ 538, 549, 550,
+ 551, 540, 539,
+ 539, 550, 551,
+ 552, 541, 540,
+ 540, 551, 552,
+ 553, 542, 541,
+ 541, 552, 553,
+ 554, 543, 542,
+ 542, 553, 554,
+ 555, 544, 543,
+ 543, 554, 555,
+ 556, 545, 544,
+ 544, 555, 556,
+ 557, 546, 547,
+ 547, 558, 557,
+ 559, 548, 546,
+ 546, 557, 559,
+ 560, 549, 548,
+ 548, 559, 560,
+ 561, 550, 549,
+ 549, 560, 561,
+ 562, 551, 550,
+ 550, 561, 562,
+ 563, 552, 551,
+ 551, 562, 563,
+ 564, 553, 552,
+ 552, 563, 564,
+ 565, 554, 553,
+ 553, 564, 565,
+ 566, 555, 554,
+ 554, 565, 566,
+ 567, 556, 555,
+ 555, 566, 567,
+ 568, 557, 558,
+ 558, 569, 568,
+ 570, 559, 557,
+ 557, 568, 570,
+ 571, 560, 559,
+ 559, 570, 571,
+ 572, 561, 560,
+ 560, 571, 572,
+ 573, 562, 561,
+ 561, 572, 573,
+ 574, 563, 562,
+ 562, 573, 574,
+ 575, 564, 563,
+ 563, 574, 575,
+ 576, 565, 564,
+ 564, 575, 576,
+ 577, 566, 565,
+ 565, 576, 577,
+ 578, 567, 566,
+ 566, 577, 578,
+ 579, 568, 569,
+ 569, 580, 579,
+ 581, 570, 568,
+ 568, 579, 581,
+ 582, 571, 570,
+ 570, 581, 582,
+ 583, 572, 571,
+ 571, 582, 583,
+ 584, 573, 572,
+ 572, 583, 584,
+ 585, 574, 573,
+ 573, 584, 585,
+ 586, 575, 574,
+ 574, 585, 586,
+ 587, 576, 575,
+ 575, 586, 587,
+ 588, 577, 576,
+ 576, 587, 588,
+ 589, 578, 577,
+ 577, 588, 589,
+ 590, 230, 231,
+ 231, 591, 590,
+ 592, 232, 230,
+ 230, 590, 592,
+ 593, 233, 232,
+ 232, 592, 593,
+ 594, 234, 233,
+ 233, 593, 594,
+ 595, 235, 234,
+ 234, 594, 595,
+ 596, 236, 235,
+ 235, 595, 596,
+ 597, 237, 236,
+ 236, 596, 597,
+ 598, 238, 237,
+ 237, 597, 598,
+ 599, 239, 238,
+ 238, 598, 599,
+ 600, 240, 239,
+ 239, 599, 600,
+ 601, 590, 591,
+ 591, 602, 601,
+ 603, 592, 590,
+ 590, 601, 603,
+ 604, 593, 592,
+ 592, 603, 604,
+ 605, 594, 593,
+ 593, 604, 605,
+ 606, 595, 594,
+ 594, 605, 606,
+ 607, 596, 595,
+ 595, 606, 607,
+ 608, 597, 596,
+ 596, 607, 608,
+ 609, 598, 597,
+ 597, 608, 609,
+ 610, 599, 598,
+ 598, 609, 610,
+ 611, 600, 599,
+ 599, 610, 611,
+ 612, 601, 602,
+ 602, 613, 612,
+ 614, 603, 601,
+ 601, 612, 614,
+ 615, 604, 603,
+ 603, 614, 615,
+ 616, 605, 604,
+ 604, 615, 616,
+ 617, 606, 605,
+ 605, 616, 617,
+ 618, 607, 606,
+ 606, 617, 618,
+ 619, 608, 607,
+ 607, 618, 619,
+ 620, 609, 608,
+ 608, 619, 620,
+ 621, 610, 609,
+ 609, 620, 621,
+ 622, 611, 610,
+ 610, 621, 622,
+ 623, 612, 613,
+ 613, 624, 623,
+ 625, 614, 612,
+ 612, 623, 625,
+ 626, 615, 614,
+ 614, 625, 626,
+ 627, 616, 615,
+ 615, 626, 627,
+ 628, 617, 616,
+ 616, 627, 628,
+ 629, 618, 617,
+ 617, 628, 629,
+ 630, 619, 618,
+ 618, 629, 630,
+ 631, 620, 619,
+ 619, 630, 631,
+ 632, 621, 620,
+ 620, 631, 632,
+ 633, 622, 621,
+ 621, 632, 633,
+ 634, 623, 624,
+ 624, 635, 634,
+ 636, 625, 623,
+ 623, 634, 636,
+ 637, 626, 625,
+ 625, 636, 637,
+ 638, 627, 626,
+ 626, 637, 638,
+ 639, 628, 627,
+ 627, 638, 639,
+ 640, 629, 628,
+ 628, 639, 640,
+ 641, 630, 629,
+ 629, 640, 641,
+ 642, 631, 630,
+ 630, 641, 642,
+ 643, 632, 631,
+ 631, 642, 643,
+ 644, 633, 632,
+ 632, 643, 644,
+ 645, 634, 635,
+ 635, 646, 645,
+ 647, 636, 634,
+ 634, 645, 647,
+ 648, 637, 636,
+ 636, 647, 648,
+ 649, 638, 637,
+ 637, 648, 649,
+ 650, 639, 638,
+ 638, 649, 650,
+ 651, 640, 639,
+ 639, 650, 651,
+ 652, 641, 640,
+ 640, 651, 652,
+ 653, 642, 641,
+ 641, 652, 653,
+ 654, 643, 642,
+ 642, 653, 654,
+ 655, 644, 643,
+ 643, 654, 655,
+ 656, 645, 646,
+ 646, 657, 656,
+ 658, 647, 645,
+ 645, 656, 658,
+ 659, 648, 647,
+ 647, 658, 659,
+ 660, 649, 648,
+ 648, 659, 660,
+ 661, 650, 649,
+ 649, 660, 661,
+ 662, 651, 650,
+ 650, 661, 662,
+ 663, 652, 651,
+ 651, 662, 663,
+ 664, 653, 652,
+ 652, 663, 664,
+ 665, 654, 653,
+ 653, 664, 665,
+ 666, 655, 654,
+ 654, 665, 666,
+ 667, 656, 657,
+ 657, 668, 667,
+ 669, 658, 656,
+ 656, 667, 669,
+ 670, 659, 658,
+ 658, 669, 670,
+ 671, 660, 659,
+ 659, 670, 671,
+ 672, 661, 660,
+ 660, 671, 672,
+ 673, 662, 661,
+ 661, 672, 673,
+ 674, 663, 662,
+ 662, 673, 674,
+ 675, 664, 663,
+ 663, 674, 675,
+ 676, 665, 664,
+ 664, 675, 676,
+ 677, 666, 665,
+ 665, 676, 677,
+ 678, 667, 668,
+ 668, 679, 678,
+ 680, 669, 667,
+ 667, 678, 680,
+ 681, 670, 669,
+ 669, 680, 681,
+ 682, 671, 670,
+ 670, 681, 682,
+ 683, 672, 671,
+ 671, 682, 683,
+ 684, 673, 672,
+ 672, 683, 684,
+ 685, 674, 673,
+ 673, 684, 685,
+ 686, 675, 674,
+ 674, 685, 686,
+ 687, 676, 675,
+ 675, 686, 687,
+ 688, 677, 676,
+ 676, 687, 688,
+ 689, 678, 679,
+ 679, 690, 689,
+ 691, 680, 678,
+ 678, 689, 691,
+ 692, 681, 680,
+ 680, 691, 692,
+ 693, 682, 681,
+ 681, 692, 693,
+ 694, 683, 682,
+ 682, 693, 694,
+ 695, 684, 683,
+ 683, 694, 695,
+ 696, 685, 684,
+ 684, 695, 696,
+ 697, 686, 685,
+ 685, 696, 697,
+ 698, 687, 686,
+ 686, 697, 698,
+ 699, 688, 687,
+ 687, 698, 699,
+ 700, 350, 351,
+ 351, 701, 700,
+ 702, 352, 350,
+ 350, 700, 702,
+ 703, 353, 352,
+ 352, 702, 703,
+ 704, 354, 353,
+ 353, 703, 704,
+ 705, 355, 354,
+ 354, 704, 705,
+ 706, 356, 355,
+ 355, 705, 706,
+ 707, 357, 356,
+ 356, 706, 707,
+ 708, 358, 357,
+ 357, 707, 708,
+ 709, 359, 358,
+ 358, 708, 709,
+ 710, 360, 359,
+ 359, 709, 710,
+ 711, 700, 701,
+ 701, 712, 711,
+ 713, 702, 700,
+ 700, 711, 713,
+ 714, 703, 702,
+ 702, 713, 714,
+ 715, 704, 703,
+ 703, 714, 715,
+ 716, 705, 704,
+ 704, 715, 716,
+ 717, 706, 705,
+ 705, 716, 717,
+ 718, 707, 706,
+ 706, 717, 718,
+ 719, 708, 707,
+ 707, 718, 719,
+ 720, 709, 708,
+ 708, 719, 720,
+ 721, 710, 709,
+ 709, 720, 721,
+ 722, 711, 712,
+ 712, 723, 722,
+ 724, 713, 711,
+ 711, 722, 724,
+ 725, 714, 713,
+ 713, 724, 725,
+ 726, 715, 714,
+ 714, 725, 726,
+ 727, 716, 715,
+ 715, 726, 727,
+ 728, 717, 716,
+ 716, 727, 728,
+ 729, 718, 717,
+ 717, 728, 729,
+ 730, 719, 718,
+ 718, 729, 730,
+ 731, 720, 719,
+ 719, 730, 731,
+ 732, 721, 720,
+ 720, 731, 732,
+ 733, 722, 723,
+ 723, 734, 733,
+ 735, 724, 722,
+ 722, 733, 735,
+ 736, 725, 724,
+ 724, 735, 736,
+ 737, 726, 725,
+ 725, 736, 737,
+ 738, 727, 726,
+ 726, 737, 738,
+ 739, 728, 727,
+ 727, 738, 739,
+ 740, 729, 728,
+ 728, 739, 740,
+ 741, 730, 729,
+ 729, 740, 741,
+ 742, 731, 730,
+ 730, 741, 742,
+ 743, 732, 731,
+ 731, 742, 743,
+ 744, 733, 734,
+ 734, 745, 744,
+ 746, 735, 733,
+ 733, 744, 746,
+ 747, 736, 735,
+ 735, 746, 747,
+ 748, 737, 736,
+ 736, 747, 748,
+ 749, 738, 737,
+ 737, 748, 749,
+ 750, 739, 738,
+ 738, 749, 750,
+ 751, 740, 739,
+ 739, 750, 751,
+ 752, 741, 740,
+ 740, 751, 752,
+ 753, 742, 741,
+ 741, 752, 753,
+ 754, 743, 742,
+ 742, 753, 754,
+ 755, 744, 745,
+ 745, 756, 755,
+ 757, 746, 744,
+ 744, 755, 757,
+ 758, 747, 746,
+ 746, 757, 758,
+ 759, 748, 747,
+ 747, 758, 759,
+ 760, 749, 748,
+ 748, 759, 760,
+ 761, 750, 749,
+ 749, 760, 761,
+ 762, 751, 750,
+ 750, 761, 762,
+ 763, 752, 751,
+ 751, 762, 763,
+ 764, 753, 752,
+ 752, 763, 764,
+ 765, 754, 753,
+ 753, 764, 765,
+ 766, 755, 756,
+ 756, 767, 766,
+ 768, 757, 755,
+ 755, 766, 768,
+ 769, 758, 757,
+ 757, 768, 769,
+ 770, 759, 758,
+ 758, 769, 770,
+ 771, 760, 759,
+ 759, 770, 771,
+ 772, 761, 760,
+ 760, 771, 772,
+ 773, 762, 761,
+ 761, 772, 773,
+ 774, 763, 762,
+ 762, 773, 774,
+ 775, 764, 763,
+ 763, 774, 775,
+ 776, 765, 764,
+ 764, 775, 776,
+ 777, 766, 767,
+ 767, 778, 777,
+ 779, 768, 766,
+ 766, 777, 779,
+ 780, 769, 768,
+ 768, 779, 780,
+ 781, 770, 769,
+ 769, 780, 781,
+ 782, 771, 770,
+ 770, 781, 782,
+ 783, 772, 771,
+ 771, 782, 783,
+ 784, 773, 772,
+ 772, 783, 784,
+ 785, 774, 773,
+ 773, 784, 785,
+ 786, 775, 774,
+ 774, 785, 786,
+ 787, 776, 775,
+ 775, 786, 787,
+ 788, 777, 778,
+ 778, 789, 788,
+ 790, 779, 777,
+ 777, 788, 790,
+ 791, 780, 779,
+ 779, 790, 791,
+ 792, 781, 780,
+ 780, 791, 792,
+ 793, 782, 781,
+ 781, 792, 793,
+ 794, 783, 782,
+ 782, 793, 794,
+ 795, 784, 783,
+ 783, 794, 795,
+ 796, 785, 784,
+ 784, 795, 796,
+ 797, 786, 785,
+ 785, 796, 797,
+ 798, 787, 786,
+ 786, 797, 798,
+ 799, 788, 789,
+ 789, 800, 799,
+ 801, 790, 788,
+ 788, 799, 801,
+ 802, 791, 790,
+ 790, 801, 802,
+ 803, 792, 791,
+ 791, 802, 803,
+ 804, 793, 792,
+ 792, 803, 804,
+ 805, 794, 793,
+ 793, 804, 805,
+ 806, 795, 794,
+ 794, 805, 806,
+ 807, 796, 795,
+ 795, 806, 807,
+ 808, 797, 796,
+ 796, 807, 808,
+ 809, 798, 797,
+ 797, 808, 809,
+ 810, 469, 470,
+ 470, 811, 810,
+ 812, 471, 469,
+ 469, 810, 812,
+ 813, 472, 471,
+ 471, 812, 813,
+ 814, 473, 472,
+ 472, 813, 814,
+ 815, 474, 473,
+ 473, 814, 815,
+ 816, 475, 474,
+ 474, 815, 816,
+ 817, 476, 475,
+ 475, 816, 817,
+ 818, 477, 476,
+ 476, 817, 818,
+ 819, 478, 477,
+ 477, 818, 819,
+ 820, 479, 478,
+ 478, 819, 820,
+ 821, 810, 811,
+ 811, 822, 821,
+ 823, 812, 810,
+ 810, 821, 823,
+ 824, 813, 812,
+ 812, 823, 824,
+ 825, 814, 813,
+ 813, 824, 825,
+ 826, 815, 814,
+ 814, 825, 826,
+ 827, 816, 815,
+ 815, 826, 827,
+ 828, 817, 816,
+ 816, 827, 828,
+ 829, 818, 817,
+ 817, 828, 829,
+ 830, 819, 818,
+ 818, 829, 830,
+ 831, 820, 819,
+ 819, 830, 831,
+ 832, 821, 822,
+ 822, 833, 832,
+ 834, 823, 821,
+ 821, 832, 834,
+ 835, 824, 823,
+ 823, 834, 835,
+ 836, 825, 824,
+ 824, 835, 836,
+ 837, 826, 825,
+ 825, 836, 837,
+ 838, 827, 826,
+ 826, 837, 838,
+ 839, 828, 827,
+ 827, 838, 839,
+ 840, 829, 828,
+ 828, 839, 840,
+ 841, 830, 829,
+ 829, 840, 841,
+ 842, 831, 830,
+ 830, 841, 842,
+ 843, 832, 833,
+ 833, 844, 843,
+ 845, 834, 832,
+ 832, 843, 845,
+ 846, 835, 834,
+ 834, 845, 846,
+ 847, 836, 835,
+ 835, 846, 847,
+ 848, 837, 836,
+ 836, 847, 848,
+ 849, 838, 837,
+ 837, 848, 849,
+ 850, 839, 838,
+ 838, 849, 850,
+ 851, 840, 839,
+ 839, 850, 851,
+ 852, 841, 840,
+ 840, 851, 852,
+ 853, 842, 841,
+ 841, 852, 853,
+ 854, 843, 844,
+ 844, 855, 854,
+ 856, 845, 843,
+ 843, 854, 856,
+ 857, 846, 845,
+ 845, 856, 857,
+ 858, 847, 846,
+ 846, 857, 858,
+ 859, 848, 847,
+ 847, 858, 859,
+ 860, 849, 848,
+ 848, 859, 860,
+ 861, 850, 849,
+ 849, 860, 861,
+ 862, 851, 850,
+ 850, 861, 862,
+ 863, 852, 851,
+ 851, 862, 863,
+ 864, 853, 852,
+ 852, 863, 864,
+ 865, 854, 855,
+ 855, 866, 865,
+ 867, 856, 854,
+ 854, 865, 867,
+ 868, 857, 856,
+ 856, 867, 868,
+ 869, 858, 857,
+ 857, 868, 869,
+ 870, 859, 858,
+ 858, 869, 870,
+ 871, 860, 859,
+ 859, 870, 871,
+ 872, 861, 860,
+ 860, 871, 872,
+ 873, 862, 861,
+ 861, 872, 873,
+ 874, 863, 862,
+ 862, 873, 874,
+ 875, 864, 863,
+ 863, 874, 875,
+ 876, 865, 866,
+ 866, 877, 876,
+ 878, 867, 865,
+ 865, 876, 878,
+ 879, 868, 867,
+ 867, 878, 879,
+ 880, 869, 868,
+ 868, 879, 880,
+ 881, 870, 869,
+ 869, 880, 881,
+ 882, 871, 870,
+ 870, 881, 882,
+ 883, 872, 871,
+ 871, 882, 883,
+ 884, 873, 872,
+ 872, 883, 884,
+ 885, 874, 873,
+ 873, 884, 885,
+ 886, 875, 874,
+ 874, 885, 886,
+ 887, 876, 877,
+ 877, 888, 887,
+ 889, 878, 876,
+ 876, 887, 889,
+ 890, 879, 878,
+ 878, 889, 890,
+ 891, 880, 879,
+ 879, 890, 891,
+ 892, 881, 880,
+ 880, 891, 892,
+ 893, 882, 881,
+ 881, 892, 893,
+ 894, 883, 882,
+ 882, 893, 894,
+ 895, 884, 883,
+ 883, 894, 895,
+ 896, 885, 884,
+ 884, 895, 896,
+ 897, 886, 885,
+ 885, 896, 897,
+ 898, 887, 888,
+ 888, 899, 898,
+ 900, 889, 887,
+ 887, 898, 900,
+ 901, 890, 889,
+ 889, 900, 901,
+ 902, 891, 890,
+ 890, 901, 902,
+ 903, 892, 891,
+ 891, 902, 903,
+ 904, 893, 892,
+ 892, 903, 904,
+ 905, 894, 893,
+ 893, 904, 905,
+ 906, 895, 894,
+ 894, 905, 906,
+ 907, 896, 895,
+ 895, 906, 907,
+ 908, 897, 896,
+ 896, 907, 908,
+ 909, 898, 899,
+ 899, 910, 909,
+ 911, 900, 898,
+ 898, 909, 911,
+ 912, 901, 900,
+ 900, 911, 912,
+ 913, 902, 901,
+ 901, 912, 913,
+ 914, 903, 902,
+ 902, 913, 914,
+ 915, 904, 903,
+ 903, 914, 915,
+ 916, 905, 904,
+ 904, 915, 916,
+ 917, 906, 905,
+ 905, 916, 917,
+ 918, 907, 906,
+ 906, 917, 918,
+ 919, 908, 907,
+ 907, 918, 919,
+ 920, 579, 580,
+ 580, 921, 920,
+ 922, 923, 579,
+ 579, 920, 922,
+ 924, 925, 923,
+ 923, 922, 924,
+ 926, 927, 925,
+ 925, 924, 926,
+ 928, 929, 927,
+ 927, 926, 928,
+ 930, 931, 929,
+ 929, 928, 930,
+ 932, 933, 931,
+ 931, 930, 932,
+ 934, 935, 933,
+ 933, 932, 934,
+ 936, 937, 935,
+ 935, 934, 936,
+ 938, 690, 937,
+ 937, 936, 938,
+ 939, 920, 921,
+ 921, 940, 939,
+ 941, 922, 920,
+ 920, 939, 941,
+ 942, 924, 922,
+ 922, 941, 942,
+ 943, 926, 924,
+ 924, 942, 943,
+ 944, 928, 926,
+ 926, 943, 944,
+ 945, 930, 928,
+ 928, 944, 945,
+ 946, 932, 930,
+ 930, 945, 946,
+ 947, 934, 932,
+ 932, 946, 947,
+ 948, 936, 934,
+ 934, 947, 948,
+ 949, 938, 936,
+ 936, 948, 949,
+ 950, 939, 940,
+ 940, 951, 950,
+ 952, 941, 939,
+ 939, 950, 952,
+ 953, 942, 941,
+ 941, 952, 953,
+ 954, 943, 942,
+ 942, 953, 954,
+ 955, 944, 943,
+ 943, 954, 955,
+ 956, 945, 944,
+ 944, 955, 956,
+ 957, 946, 945,
+ 945, 956, 957,
+ 958, 947, 946,
+ 946, 957, 958,
+ 959, 948, 947,
+ 947, 958, 959,
+ 960, 949, 948,
+ 948, 959, 960,
+ 961, 950, 951,
+ 951, 962, 961,
+ 963, 952, 950,
+ 950, 961, 963,
+ 964, 953, 952,
+ 952, 963, 964,
+ 965, 954, 953,
+ 953, 964, 965,
+ 966, 955, 954,
+ 954, 965, 966,
+ 967, 956, 955,
+ 955, 966, 967,
+ 968, 957, 956,
+ 956, 967, 968,
+ 969, 958, 957,
+ 957, 968, 969,
+ 970, 959, 958,
+ 958, 969, 970,
+ 971, 960, 959,
+ 959, 970, 971,
+ 972, 961, 962,
+ 962, 973, 972,
+ 974, 963, 961,
+ 961, 972, 974,
+ 975, 964, 963,
+ 963, 974, 975,
+ 976, 965, 964,
+ 964, 975, 976,
+ 977, 966, 965,
+ 965, 976, 977,
+ 978, 967, 966,
+ 966, 977, 978,
+ 979, 968, 967,
+ 967, 978, 979,
+ 980, 969, 968,
+ 968, 979, 980,
+ 981, 970, 969,
+ 969, 980, 981,
+ 982, 971, 970,
+ 970, 981, 982,
+ 983, 972, 973,
+ 973, 984, 983,
+ 985, 974, 972,
+ 972, 983, 985,
+ 986, 975, 974,
+ 974, 985, 986,
+ 987, 976, 975,
+ 975, 986, 987,
+ 988, 977, 976,
+ 976, 987, 988,
+ 989, 978, 977,
+ 977, 988, 989,
+ 990, 979, 978,
+ 978, 989, 990,
+ 991, 980, 979,
+ 979, 990, 991,
+ 992, 981, 980,
+ 980, 991, 992,
+ 993, 982, 981,
+ 981, 992, 993,
+ 994, 983, 984,
+ 984, 995, 994,
+ 996, 985, 983,
+ 983, 994, 996,
+ 997, 986, 985,
+ 985, 996, 997,
+ 998, 987, 986,
+ 986, 997, 998,
+ 999, 988, 987,
+ 987, 998, 999,
+ 1000, 989, 988,
+ 988, 999, 1000,
+ 1001, 990, 989,
+ 989, 1000, 1001,
+ 1002, 991, 990,
+ 990, 1001, 1002,
+ 1003, 992, 991,
+ 991, 1002, 1003,
+ 1004, 993, 992,
+ 992, 1003, 1004,
+ 1005, 994, 995,
+ 995, 1006, 1005,
+ 1007, 996, 994,
+ 994, 1005, 1007,
+ 1008, 997, 996,
+ 996, 1007, 1008,
+ 1009, 998, 997,
+ 997, 1008, 1009,
+ 1010, 999, 998,
+ 998, 1009, 1010,
+ 1011, 1000, 999,
+ 999, 1010, 1011,
+ 1012, 1001, 1000,
+ 1000, 1011, 1012,
+ 1013, 1002, 1001,
+ 1001, 1012, 1013,
+ 1014, 1003, 1002,
+ 1002, 1013, 1014,
+ 1015, 1004, 1003,
+ 1003, 1014, 1015,
+ 1016, 1005, 1006,
+ 1006, 1017, 1016,
+ 1018, 1007, 1005,
+ 1005, 1016, 1018,
+ 1019, 1008, 1007,
+ 1007, 1018, 1019,
+ 1020, 1009, 1008,
+ 1008, 1019, 1020,
+ 1021, 1010, 1009,
+ 1009, 1020, 1021,
+ 1022, 1011, 1010,
+ 1010, 1021, 1022,
+ 1023, 1012, 1011,
+ 1011, 1022, 1023,
+ 1024, 1013, 1012,
+ 1012, 1023, 1024,
+ 1025, 1014, 1013,
+ 1013, 1024, 1025,
+ 1026, 1015, 1014,
+ 1014, 1025, 1026,
+ 1027, 1016, 1017,
+ 1017, 1028, 1027,
+ 1029, 1018, 1016,
+ 1016, 1027, 1029,
+ 1030, 1019, 1018,
+ 1018, 1029, 1030,
+ 1031, 1020, 1019,
+ 1019, 1030, 1031,
+ 1032, 1021, 1020,
+ 1020, 1031, 1032,
+ 1033, 1022, 1021,
+ 1021, 1032, 1033,
+ 1034, 1023, 1022,
+ 1022, 1033, 1034,
+ 1035, 1024, 1023,
+ 1023, 1034, 1035,
+ 1036, 1025, 1024,
+ 1024, 1035, 1036,
+ 1037, 1026, 1025,
+ 1025, 1036, 1037,
+ 1038, 689, 690,
+ 690, 1039, 1038,
+ 1040, 1041, 689,
+ 689, 1038, 1040,
+ 1042, 1043, 1041,
+ 1041, 1040, 1042,
+ 1044, 1045, 1043,
+ 1043, 1042, 1044,
+ 1046, 1047, 1045,
+ 1045, 1044, 1046,
+ 1048, 1049, 1047,
+ 1047, 1046, 1048,
+ 1050, 1051, 1049,
+ 1049, 1048, 1050,
+ 1052, 1053, 1051,
+ 1051, 1050, 1052,
+ 1054, 1055, 1053,
+ 1053, 1052, 1054,
+ 1056, 800, 1055,
+ 1055, 1054, 1056,
+ 1057, 1038, 1039,
+ 1039, 1058, 1057,
+ 1059, 1040, 1038,
+ 1038, 1057, 1059,
+ 1060, 1042, 1040,
+ 1040, 1059, 1060,
+ 1061, 1044, 1042,
+ 1042, 1060, 1061,
+ 1062, 1046, 1044,
+ 1044, 1061, 1062,
+ 1063, 1048, 1046,
+ 1046, 1062, 1063,
+ 1064, 1050, 1048,
+ 1048, 1063, 1064,
+ 1065, 1052, 1050,
+ 1050, 1064, 1065,
+ 1066, 1054, 1052,
+ 1052, 1065, 1066,
+ 1067, 1056, 1054,
+ 1054, 1066, 1067,
+ 1068, 1057, 1058,
+ 1058, 1069, 1068,
+ 1070, 1059, 1057,
+ 1057, 1068, 1070,
+ 1071, 1060, 1059,
+ 1059, 1070, 1071,
+ 1072, 1061, 1060,
+ 1060, 1071, 1072,
+ 1073, 1062, 1061,
+ 1061, 1072, 1073,
+ 1074, 1063, 1062,
+ 1062, 1073, 1074,
+ 1075, 1064, 1063,
+ 1063, 1074, 1075,
+ 1076, 1065, 1064,
+ 1064, 1075, 1076,
+ 1077, 1066, 1065,
+ 1065, 1076, 1077,
+ 1078, 1067, 1066,
+ 1066, 1077, 1078,
+ 1079, 1068, 1069,
+ 1069, 1080, 1079,
+ 1081, 1070, 1068,
+ 1068, 1079, 1081,
+ 1082, 1071, 1070,
+ 1070, 1081, 1082,
+ 1083, 1072, 1071,
+ 1071, 1082, 1083,
+ 1084, 1073, 1072,
+ 1072, 1083, 1084,
+ 1085, 1074, 1073,
+ 1073, 1084, 1085,
+ 1086, 1075, 1074,
+ 1074, 1085, 1086,
+ 1087, 1076, 1075,
+ 1075, 1086, 1087,
+ 1088, 1077, 1076,
+ 1076, 1087, 1088,
+ 1089, 1078, 1077,
+ 1077, 1088, 1089,
+ 1090, 1079, 1080,
+ 1080, 1091, 1090,
+ 1092, 1081, 1079,
+ 1079, 1090, 1092,
+ 1093, 1082, 1081,
+ 1081, 1092, 1093,
+ 1094, 1083, 1082,
+ 1082, 1093, 1094,
+ 1095, 1084, 1083,
+ 1083, 1094, 1095,
+ 1096, 1085, 1084,
+ 1084, 1095, 1096,
+ 1097, 1086, 1085,
+ 1085, 1096, 1097,
+ 1098, 1087, 1086,
+ 1086, 1097, 1098,
+ 1099, 1088, 1087,
+ 1087, 1098, 1099,
+ 1100, 1089, 1088,
+ 1088, 1099, 1100,
+ 1101, 1090, 1091,
+ 1091, 1102, 1101,
+ 1103, 1092, 1090,
+ 1090, 1101, 1103,
+ 1104, 1093, 1092,
+ 1092, 1103, 1104,
+ 1105, 1094, 1093,
+ 1093, 1104, 1105,
+ 1106, 1095, 1094,
+ 1094, 1105, 1106,
+ 1107, 1096, 1095,
+ 1095, 1106, 1107,
+ 1108, 1097, 1096,
+ 1096, 1107, 1108,
+ 1109, 1098, 1097,
+ 1097, 1108, 1109,
+ 1110, 1099, 1098,
+ 1098, 1109, 1110,
+ 1111, 1100, 1099,
+ 1099, 1110, 1111,
+ 1112, 1101, 1102,
+ 1102, 1113, 1112,
+ 1114, 1103, 1101,
+ 1101, 1112, 1114,
+ 1115, 1104, 1103,
+ 1103, 1114, 1115,
+ 1116, 1105, 1104,
+ 1104, 1115, 1116,
+ 1117, 1106, 1105,
+ 1105, 1116, 1117,
+ 1118, 1107, 1106,
+ 1106, 1117, 1118,
+ 1119, 1108, 1107,
+ 1107, 1118, 1119,
+ 1120, 1109, 1108,
+ 1108, 1119, 1120,
+ 1121, 1110, 1109,
+ 1109, 1120, 1121,
+ 1122, 1111, 1110,
+ 1110, 1121, 1122,
+ 1123, 1112, 1113,
+ 1113, 1124, 1123,
+ 1125, 1114, 1112,
+ 1112, 1123, 1125,
+ 1126, 1115, 1114,
+ 1114, 1125, 1126,
+ 1127, 1116, 1115,
+ 1115, 1126, 1127,
+ 1128, 1117, 1116,
+ 1116, 1127, 1128,
+ 1129, 1118, 1117,
+ 1117, 1128, 1129,
+ 1130, 1119, 1118,
+ 1118, 1129, 1130,
+ 1131, 1120, 1119,
+ 1119, 1130, 1131,
+ 1132, 1121, 1120,
+ 1120, 1131, 1132,
+ 1133, 1122, 1121,
+ 1121, 1132, 1133,
+ 1134, 1123, 1124,
+ 1124, 1135, 1134,
+ 1136, 1125, 1123,
+ 1123, 1134, 1136,
+ 1137, 1126, 1125,
+ 1125, 1136, 1137,
+ 1138, 1127, 1126,
+ 1126, 1137, 1138,
+ 1139, 1128, 1127,
+ 1127, 1138, 1139,
+ 1140, 1129, 1128,
+ 1128, 1139, 1140,
+ 1141, 1130, 1129,
+ 1129, 1140, 1141,
+ 1142, 1131, 1130,
+ 1130, 1141, 1142,
+ 1143, 1132, 1131,
+ 1131, 1142, 1143,
+ 1144, 1133, 1132,
+ 1132, 1143, 1144,
+ 1145, 1134, 1135,
+ 1135, 1146, 1145,
+ 1147, 1136, 1134,
+ 1134, 1145, 1147,
+ 1148, 1137, 1136,
+ 1136, 1147, 1148,
+ 1149, 1138, 1137,
+ 1137, 1148, 1149,
+ 1150, 1139, 1138,
+ 1138, 1149, 1150,
+ 1151, 1140, 1139,
+ 1139, 1150, 1151,
+ 1152, 1141, 1140,
+ 1140, 1151, 1152,
+ 1153, 1142, 1141,
+ 1141, 1152, 1153,
+ 1154, 1143, 1142,
+ 1142, 1153, 1154,
+ 1155, 1144, 1143,
+ 1143, 1154, 1155,
+ 1156, 799, 800,
+ 800, 1157, 1156,
+ 1158, 1159, 799,
+ 799, 1156, 1158,
+ 1160, 1161, 1159,
+ 1159, 1158, 1160,
+ 1162, 1163, 1161,
+ 1161, 1160, 1162,
+ 1164, 1165, 1163,
+ 1163, 1162, 1164,
+ 1166, 1167, 1165,
+ 1165, 1164, 1166,
+ 1168, 1169, 1167,
+ 1167, 1166, 1168,
+ 1170, 1171, 1169,
+ 1169, 1168, 1170,
+ 1172, 1173, 1171,
+ 1171, 1170, 1172,
+ 1174, 910, 1173,
+ 1173, 1172, 1174,
+ 1175, 1156, 1157,
+ 1157, 1176, 1175,
+ 1177, 1158, 1156,
+ 1156, 1175, 1177,
+ 1178, 1160, 1158,
+ 1158, 1177, 1178,
+ 1179, 1162, 1160,
+ 1160, 1178, 1179,
+ 1180, 1164, 1162,
+ 1162, 1179, 1180,
+ 1181, 1166, 1164,
+ 1164, 1180, 1181,
+ 1182, 1168, 1166,
+ 1166, 1181, 1182,
+ 1183, 1170, 1168,
+ 1168, 1182, 1183,
+ 1184, 1172, 1170,
+ 1170, 1183, 1184,
+ 1185, 1174, 1172,
+ 1172, 1184, 1185,
+ 1186, 1175, 1176,
+ 1176, 1187, 1186,
+ 1188, 1177, 1175,
+ 1175, 1186, 1188,
+ 1189, 1178, 1177,
+ 1177, 1188, 1189,
+ 1190, 1179, 1178,
+ 1178, 1189, 1190,
+ 1191, 1180, 1179,
+ 1179, 1190, 1191,
+ 1192, 1181, 1180,
+ 1180, 1191, 1192,
+ 1193, 1182, 1181,
+ 1181, 1192, 1193,
+ 1194, 1183, 1182,
+ 1182, 1193, 1194,
+ 1195, 1184, 1183,
+ 1183, 1194, 1195,
+ 1196, 1185, 1184,
+ 1184, 1195, 1196,
+ 1197, 1186, 1187,
+ 1187, 1198, 1197,
+ 1199, 1188, 1186,
+ 1186, 1197, 1199,
+ 1200, 1189, 1188,
+ 1188, 1199, 1200,
+ 1201, 1190, 1189,
+ 1189, 1200, 1201,
+ 1202, 1191, 1190,
+ 1190, 1201, 1202,
+ 1203, 1192, 1191,
+ 1191, 1202, 1203,
+ 1204, 1193, 1192,
+ 1192, 1203, 1204,
+ 1205, 1194, 1193,
+ 1193, 1204, 1205,
+ 1206, 1195, 1194,
+ 1194, 1205, 1206,
+ 1207, 1196, 1195,
+ 1195, 1206, 1207,
+ 1208, 1197, 1198,
+ 1198, 1209, 1208,
+ 1210, 1199, 1197,
+ 1197, 1208, 1210,
+ 1211, 1200, 1199,
+ 1199, 1210, 1211,
+ 1212, 1201, 1200,
+ 1200, 1211, 1212,
+ 1213, 1202, 1201,
+ 1201, 1212, 1213,
+ 1214, 1203, 1202,
+ 1202, 1213, 1214,
+ 1215, 1204, 1203,
+ 1203, 1214, 1215,
+ 1216, 1205, 1204,
+ 1204, 1215, 1216,
+ 1217, 1206, 1205,
+ 1205, 1216, 1217,
+ 1218, 1207, 1206,
+ 1206, 1217, 1218,
+ 1219, 1208, 1209,
+ 1209, 1220, 1219,
+ 1221, 1210, 1208,
+ 1208, 1219, 1221,
+ 1222, 1211, 1210,
+ 1210, 1221, 1222,
+ 1223, 1212, 1211,
+ 1211, 1222, 1223,
+ 1224, 1213, 1212,
+ 1212, 1223, 1224,
+ 1225, 1214, 1213,
+ 1213, 1224, 1225,
+ 1226, 1215, 1214,
+ 1214, 1225, 1226,
+ 1227, 1216, 1215,
+ 1215, 1226, 1227,
+ 1228, 1217, 1216,
+ 1216, 1227, 1228,
+ 1229, 1218, 1217,
+ 1217, 1228, 1229,
+ 1230, 1219, 1220,
+ 1220, 1231, 1230,
+ 1232, 1221, 1219,
+ 1219, 1230, 1232,
+ 1233, 1222, 1221,
+ 1221, 1232, 1233,
+ 1234, 1223, 1222,
+ 1222, 1233, 1234,
+ 1235, 1224, 1223,
+ 1223, 1234, 1235,
+ 1236, 1225, 1224,
+ 1224, 1235, 1236,
+ 1237, 1226, 1225,
+ 1225, 1236, 1237,
+ 1238, 1227, 1226,
+ 1226, 1237, 1238,
+ 1239, 1228, 1227,
+ 1227, 1238, 1239,
+ 1240, 1229, 1228,
+ 1228, 1239, 1240,
+ 1241, 1230, 1231,
+ 1231, 1242, 1241,
+ 1243, 1232, 1230,
+ 1230, 1241, 1243,
+ 1244, 1233, 1232,
+ 1232, 1243, 1244,
+ 1245, 1234, 1233,
+ 1233, 1244, 1245,
+ 1246, 1235, 1234,
+ 1234, 1245, 1246,
+ 1247, 1236, 1235,
+ 1235, 1246, 1247,
+ 1248, 1237, 1236,
+ 1236, 1247, 1248,
+ 1249, 1238, 1237,
+ 1237, 1248, 1249,
+ 1250, 1239, 1238,
+ 1238, 1249, 1250,
+ 1251, 1240, 1239,
+ 1239, 1250, 1251,
+ 1252, 1241, 1242,
+ 1242, 1253, 1252,
+ 1254, 1243, 1241,
+ 1241, 1252, 1254,
+ 1255, 1244, 1243,
+ 1243, 1254, 1255,
+ 1256, 1245, 1244,
+ 1244, 1255, 1256,
+ 1257, 1246, 1245,
+ 1245, 1256, 1257,
+ 1258, 1247, 1246,
+ 1246, 1257, 1258,
+ 1259, 1248, 1247,
+ 1247, 1258, 1259,
+ 1260, 1249, 1248,
+ 1248, 1259, 1260,
+ 1261, 1250, 1249,
+ 1249, 1260, 1261,
+ 1262, 1251, 1250,
+ 1250, 1261, 1262,
+ 1263, 1252, 1253,
+ 1253, 1264, 1263,
+ 1265, 1254, 1252,
+ 1252, 1263, 1265,
+ 1266, 1255, 1254,
+ 1254, 1265, 1266,
+ 1267, 1256, 1255,
+ 1255, 1266, 1267,
+ 1268, 1257, 1256,
+ 1256, 1267, 1268,
+ 1269, 1258, 1257,
+ 1257, 1268, 1269,
+ 1270, 1259, 1258,
+ 1258, 1269, 1270,
+ 1271, 1260, 1259,
+ 1259, 1270, 1271,
+ 1272, 1261, 1260,
+ 1260, 1271, 1272,
+ 1273, 1262, 1261,
+ 1261, 1272, 1273,
+ 1274, 909, 910,
+ 910, 1275, 1274,
+ 1276, 1277, 909,
+ 909, 1274, 1276,
+ 1278, 1279, 1277,
+ 1277, 1276, 1278,
+ 1280, 1281, 1279,
+ 1279, 1278, 1280,
+ 1282, 1283, 1281,
+ 1281, 1280, 1282,
+ 1284, 1285, 1283,
+ 1283, 1282, 1284,
+ 1286, 1287, 1285,
+ 1285, 1284, 1286,
+ 1288, 1289, 1287,
+ 1287, 1286, 1288,
+ 1290, 1291, 1289,
+ 1289, 1288, 1290,
+ 1292, 580, 1291,
+ 1291, 1290, 1292,
+ 1293, 1274, 1275,
+ 1275, 1294, 1293,
+ 1295, 1276, 1274,
+ 1274, 1293, 1295,
+ 1296, 1278, 1276,
+ 1276, 1295, 1296,
+ 1297, 1280, 1278,
+ 1278, 1296, 1297,
+ 1298, 1282, 1280,
+ 1280, 1297, 1298,
+ 1299, 1284, 1282,
+ 1282, 1298, 1299,
+ 1300, 1286, 1284,
+ 1284, 1299, 1300,
+ 1301, 1288, 1286,
+ 1286, 1300, 1301,
+ 1302, 1290, 1288,
+ 1288, 1301, 1302,
+ 1303, 1292, 1290,
+ 1290, 1302, 1303,
+ 1304, 1293, 1294,
+ 1294, 1305, 1304,
+ 1306, 1295, 1293,
+ 1293, 1304, 1306,
+ 1307, 1296, 1295,
+ 1295, 1306, 1307,
+ 1308, 1297, 1296,
+ 1296, 1307, 1308,
+ 1309, 1298, 1297,
+ 1297, 1308, 1309,
+ 1310, 1299, 1298,
+ 1298, 1309, 1310,
+ 1311, 1300, 1299,
+ 1299, 1310, 1311,
+ 1312, 1301, 1300,
+ 1300, 1311, 1312,
+ 1313, 1302, 1301,
+ 1301, 1312, 1313,
+ 1314, 1303, 1302,
+ 1302, 1313, 1314,
+ 1315, 1304, 1305,
+ 1305, 1316, 1315,
+ 1317, 1306, 1304,
+ 1304, 1315, 1317,
+ 1318, 1307, 1306,
+ 1306, 1317, 1318,
+ 1319, 1308, 1307,
+ 1307, 1318, 1319,
+ 1320, 1309, 1308,
+ 1308, 1319, 1320,
+ 1321, 1310, 1309,
+ 1309, 1320, 1321,
+ 1322, 1311, 1310,
+ 1310, 1321, 1322,
+ 1323, 1312, 1311,
+ 1311, 1322, 1323,
+ 1324, 1313, 1312,
+ 1312, 1323, 1324,
+ 1325, 1314, 1313,
+ 1313, 1324, 1325,
+ 1326, 1315, 1316,
+ 1316, 1327, 1326,
+ 1328, 1317, 1315,
+ 1315, 1326, 1328,
+ 1329, 1318, 1317,
+ 1317, 1328, 1329,
+ 1330, 1319, 1318,
+ 1318, 1329, 1330,
+ 1331, 1320, 1319,
+ 1319, 1330, 1331,
+ 1332, 1321, 1320,
+ 1320, 1331, 1332,
+ 1333, 1322, 1321,
+ 1321, 1332, 1333,
+ 1334, 1323, 1322,
+ 1322, 1333, 1334,
+ 1335, 1324, 1323,
+ 1323, 1334, 1335,
+ 1336, 1325, 1324,
+ 1324, 1335, 1336,
+ 1337, 1326, 1327,
+ 1327, 1338, 1337,
+ 1339, 1328, 1326,
+ 1326, 1337, 1339,
+ 1340, 1329, 1328,
+ 1328, 1339, 1340,
+ 1341, 1330, 1329,
+ 1329, 1340, 1341,
+ 1342, 1331, 1330,
+ 1330, 1341, 1342,
+ 1343, 1332, 1331,
+ 1331, 1342, 1343,
+ 1344, 1333, 1332,
+ 1332, 1343, 1344,
+ 1345, 1334, 1333,
+ 1333, 1344, 1345,
+ 1346, 1335, 1334,
+ 1334, 1345, 1346,
+ 1347, 1336, 1335,
+ 1335, 1346, 1347,
+ 1348, 1337, 1338,
+ 1338, 1349, 1348,
+ 1350, 1339, 1337,
+ 1337, 1348, 1350,
+ 1351, 1340, 1339,
+ 1339, 1350, 1351,
+ 1352, 1341, 1340,
+ 1340, 1351, 1352,
+ 1353, 1342, 1341,
+ 1341, 1352, 1353,
+ 1354, 1343, 1342,
+ 1342, 1353, 1354,
+ 1355, 1344, 1343,
+ 1343, 1354, 1355,
+ 1356, 1345, 1344,
+ 1344, 1355, 1356,
+ 1357, 1346, 1345,
+ 1345, 1356, 1357,
+ 1358, 1347, 1346,
+ 1346, 1357, 1358,
+ 1359, 1348, 1349,
+ 1349, 1360, 1359,
+ 1361, 1350, 1348,
+ 1348, 1359, 1361,
+ 1362, 1351, 1350,
+ 1350, 1361, 1362,
+ 1363, 1352, 1351,
+ 1351, 1362, 1363,
+ 1364, 1353, 1352,
+ 1352, 1363, 1364,
+ 1365, 1354, 1353,
+ 1353, 1364, 1365,
+ 1366, 1355, 1354,
+ 1354, 1365, 1366,
+ 1367, 1356, 1355,
+ 1355, 1366, 1367,
+ 1368, 1357, 1356,
+ 1356, 1367, 1368,
+ 1369, 1358, 1357,
+ 1357, 1368, 1369,
+ 1370, 1359, 1360,
+ 1360, 1371, 1370,
+ 1372, 1361, 1359,
+ 1359, 1370, 1372,
+ 1373, 1362, 1361,
+ 1361, 1372, 1373,
+ 1374, 1363, 1362,
+ 1362, 1373, 1374,
+ 1375, 1364, 1363,
+ 1363, 1374, 1375,
+ 1376, 1365, 1364,
+ 1364, 1375, 1376,
+ 1377, 1366, 1365,
+ 1365, 1376, 1377,
+ 1378, 1367, 1366,
+ 1366, 1377, 1378,
+ 1379, 1368, 1367,
+ 1367, 1378, 1379,
+ 1380, 1369, 1368,
+ 1368, 1379, 1380,
+ 1381, 1370, 1371,
+ 1371, 1382, 1381,
+ 1383, 1372, 1370,
+ 1370, 1381, 1383,
+ 1384, 1373, 1372,
+ 1372, 1383, 1384,
+ 1385, 1374, 1373,
+ 1373, 1384, 1385,
+ 1386, 1375, 1374,
+ 1374, 1385, 1386,
+ 1387, 1376, 1375,
+ 1375, 1386, 1387,
+ 1388, 1377, 1376,
+ 1376, 1387, 1388,
+ 1389, 1378, 1377,
+ 1377, 1388, 1389,
+ 1390, 1379, 1378,
+ 1378, 1389, 1390,
+ 1391, 1380, 1379,
+ 1379, 1390, 1391,
+ 1392, 1393, 1394,
+ 1394, 1395, 1392,
+ 1396, 1397, 1393,
+ 1393, 1392, 1396,
+ 1398, 1399, 1397,
+ 1397, 1396, 1398,
+ 1400, 1401, 1399,
+ 1399, 1398, 1400,
+ 1402, 1403, 1401,
+ 1401, 1400, 1402,
+ 1404, 1405, 1403,
+ 1403, 1402, 1404,
+ 1406, 1407, 1405,
+ 1405, 1404, 1406,
+ 1408, 1409, 1407,
+ 1407, 1406, 1408,
+ 1410, 1411, 1409,
+ 1409, 1408, 1410,
+ 1412, 1413, 1411,
+ 1411, 1410, 1412,
+ 1414, 1392, 1395,
+ 1395, 1415, 1414,
+ 1416, 1396, 1392,
+ 1392, 1414, 1416,
+ 1417, 1398, 1396,
+ 1396, 1416, 1417,
+ 1418, 1400, 1398,
+ 1398, 1417, 1418,
+ 1419, 1402, 1400,
+ 1400, 1418, 1419,
+ 1420, 1404, 1402,
+ 1402, 1419, 1420,
+ 1421, 1406, 1404,
+ 1404, 1420, 1421,
+ 1422, 1408, 1406,
+ 1406, 1421, 1422,
+ 1423, 1410, 1408,
+ 1408, 1422, 1423,
+ 1424, 1412, 1410,
+ 1410, 1423, 1424,
+ 1425, 1414, 1415,
+ 1415, 1426, 1425,
+ 1427, 1416, 1414,
+ 1414, 1425, 1427,
+ 1428, 1417, 1416,
+ 1416, 1427, 1428,
+ 1429, 1418, 1417,
+ 1417, 1428, 1429,
+ 1430, 1419, 1418,
+ 1418, 1429, 1430,
+ 1431, 1420, 1419,
+ 1419, 1430, 1431,
+ 1432, 1421, 1420,
+ 1420, 1431, 1432,
+ 1433, 1422, 1421,
+ 1421, 1432, 1433,
+ 1434, 1423, 1422,
+ 1422, 1433, 1434,
+ 1435, 1424, 1423,
+ 1423, 1434, 1435,
+ 1436, 1425, 1426,
+ 1426, 1437, 1436,
+ 1438, 1427, 1425,
+ 1425, 1436, 1438,
+ 1439, 1428, 1427,
+ 1427, 1438, 1439,
+ 1440, 1429, 1428,
+ 1428, 1439, 1440,
+ 1441, 1430, 1429,
+ 1429, 1440, 1441,
+ 1442, 1431, 1430,
+ 1430, 1441, 1442,
+ 1443, 1432, 1431,
+ 1431, 1442, 1443,
+ 1444, 1433, 1432,
+ 1432, 1443, 1444,
+ 1445, 1434, 1433,
+ 1433, 1444, 1445,
+ 1446, 1435, 1434,
+ 1434, 1445, 1446,
+ 1447, 1436, 1437,
+ 1437, 1448, 1447,
+ 1449, 1438, 1436,
+ 1436, 1447, 1449,
+ 1450, 1439, 1438,
+ 1438, 1449, 1450,
+ 1451, 1440, 1439,
+ 1439, 1450, 1451,
+ 1452, 1441, 1440,
+ 1440, 1451, 1452,
+ 1453, 1442, 1441,
+ 1441, 1452, 1453,
+ 1454, 1443, 1442,
+ 1442, 1453, 1454,
+ 1455, 1444, 1443,
+ 1443, 1454, 1455,
+ 1456, 1445, 1444,
+ 1444, 1455, 1456,
+ 1457, 1446, 1445,
+ 1445, 1456, 1457,
+ 1458, 1447, 1448,
+ 1448, 1459, 1458,
+ 1460, 1449, 1447,
+ 1447, 1458, 1460,
+ 1461, 1450, 1449,
+ 1449, 1460, 1461,
+ 1462, 1451, 1450,
+ 1450, 1461, 1462,
+ 1463, 1452, 1451,
+ 1451, 1462, 1463,
+ 1464, 1453, 1452,
+ 1452, 1463, 1464,
+ 1465, 1454, 1453,
+ 1453, 1464, 1465,
+ 1466, 1455, 1454,
+ 1454, 1465, 1466,
+ 1467, 1456, 1455,
+ 1455, 1466, 1467,
+ 1468, 1457, 1456,
+ 1456, 1467, 1468,
+ 1469, 1458, 1459,
+ 1459, 1470, 1469,
+ 1471, 1460, 1458,
+ 1458, 1469, 1471,
+ 1472, 1461, 1460,
+ 1460, 1471, 1472,
+ 1473, 1462, 1461,
+ 1461, 1472, 1473,
+ 1474, 1463, 1462,
+ 1462, 1473, 1474,
+ 1475, 1464, 1463,
+ 1463, 1474, 1475,
+ 1476, 1465, 1464,
+ 1464, 1475, 1476,
+ 1477, 1466, 1465,
+ 1465, 1476, 1477,
+ 1478, 1467, 1466,
+ 1466, 1477, 1478,
+ 1479, 1468, 1467,
+ 1467, 1478, 1479,
+ 1480, 1469, 1470,
+ 1470, 1481, 1480,
+ 1482, 1471, 1469,
+ 1469, 1480, 1482,
+ 1483, 1472, 1471,
+ 1471, 1482, 1483,
+ 1484, 1473, 1472,
+ 1472, 1483, 1484,
+ 1485, 1474, 1473,
+ 1473, 1484, 1485,
+ 1486, 1475, 1474,
+ 1474, 1485, 1486,
+ 1487, 1476, 1475,
+ 1475, 1486, 1487,
+ 1488, 1477, 1476,
+ 1476, 1487, 1488,
+ 1489, 1478, 1477,
+ 1477, 1488, 1489,
+ 1490, 1479, 1478,
+ 1478, 1489, 1490,
+ 1491, 1480, 1481,
+ 1481, 1492, 1491,
+ 1493, 1482, 1480,
+ 1480, 1491, 1493,
+ 1494, 1483, 1482,
+ 1482, 1493, 1494,
+ 1495, 1484, 1483,
+ 1483, 1494, 1495,
+ 1496, 1485, 1484,
+ 1484, 1495, 1496,
+ 1497, 1486, 1485,
+ 1485, 1496, 1497,
+ 1498, 1487, 1486,
+ 1486, 1497, 1498,
+ 1499, 1488, 1487,
+ 1487, 1498, 1499,
+ 1500, 1489, 1488,
+ 1488, 1499, 1500,
+ 1501, 1490, 1489,
+ 1489, 1500, 1501,
+ 1502, 1491, 1492,
+ 1492, 1503, 1502,
+ 1504, 1493, 1491,
+ 1491, 1502, 1504,
+ 1505, 1494, 1493,
+ 1493, 1504, 1505,
+ 1506, 1495, 1494,
+ 1494, 1505, 1506,
+ 1507, 1496, 1495,
+ 1495, 1506, 1507,
+ 1508, 1497, 1496,
+ 1496, 1507, 1508,
+ 1509, 1498, 1497,
+ 1497, 1508, 1509,
+ 1510, 1499, 1498,
+ 1498, 1509, 1510,
+ 1511, 1500, 1499,
+ 1499, 1510, 1511,
+ 1512, 1501, 1500,
+ 1500, 1511, 1512,
+ 1513, 1514, 1413,
+ 1413, 1412, 1513,
+ 1515, 1516, 1514,
+ 1514, 1513, 1515,
+ 1517, 1518, 1516,
+ 1516, 1515, 1517,
+ 1519, 1520, 1518,
+ 1518, 1517, 1519,
+ 1521, 1522, 1520,
+ 1520, 1519, 1521,
+ 1523, 1524, 1522,
+ 1522, 1521, 1523,
+ 1525, 1526, 1524,
+ 1524, 1523, 1525,
+ 1527, 1528, 1526,
+ 1526, 1525, 1527,
+ 1529, 1530, 1528,
+ 1528, 1527, 1529,
+ 1395, 1394, 1530,
+ 1530, 1529, 1395,
+ 1531, 1513, 1412,
+ 1412, 1532, 1531,
+ 1533, 1515, 1513,
+ 1513, 1531, 1533,
+ 1534, 1517, 1515,
+ 1515, 1533, 1534,
+ 1535, 1519, 1517,
+ 1517, 1534, 1535,
+ 1536, 1521, 1519,
+ 1519, 1535, 1536,
+ 1537, 1523, 1521,
+ 1521, 1536, 1537,
+ 1538, 1525, 1523,
+ 1523, 1537, 1538,
+ 1539, 1527, 1525,
+ 1525, 1538, 1539,
+ 1540, 1529, 1527,
+ 1527, 1539, 1540,
+ 1541, 1395, 1529,
+ 1529, 1540, 1541,
+ 1542, 1531, 1532,
+ 1532, 1435, 1542,
+ 1543, 1533, 1531,
+ 1531, 1542, 1543,
+ 1544, 1534, 1533,
+ 1533, 1543, 1544,
+ 1545, 1535, 1534,
+ 1534, 1544, 1545,
+ 1546, 1536, 1535,
+ 1535, 1545, 1546,
+ 1547, 1537, 1536,
+ 1536, 1546, 1547,
+ 1548, 1538, 1537,
+ 1537, 1547, 1548,
+ 1549, 1539, 1538,
+ 1538, 1548, 1549,
+ 1550, 1540, 1539,
+ 1539, 1549, 1550,
+ 1426, 1541, 1540,
+ 1540, 1550, 1426,
+ 1551, 1542, 1435,
+ 1435, 1552, 1551,
+ 1553, 1543, 1542,
+ 1542, 1551, 1553,
+ 1554, 1544, 1543,
+ 1543, 1553, 1554,
+ 1555, 1545, 1544,
+ 1544, 1554, 1555,
+ 1556, 1546, 1545,
+ 1545, 1555, 1556,
+ 1557, 1547, 1546,
+ 1546, 1556, 1557,
+ 1558, 1548, 1547,
+ 1547, 1557, 1558,
+ 1559, 1549, 1548,
+ 1548, 1558, 1559,
+ 1560, 1550, 1549,
+ 1549, 1559, 1560,
+ 1561, 1426, 1550,
+ 1550, 1560, 1561,
+ 1562, 1551, 1552,
+ 1552, 1457, 1562,
+ 1563, 1553, 1551,
+ 1551, 1562, 1563,
+ 1564, 1554, 1553,
+ 1553, 1563, 1564,
+ 1565, 1555, 1554,
+ 1554, 1564, 1565,
+ 1566, 1556, 1555,
+ 1555, 1565, 1566,
+ 1567, 1557, 1556,
+ 1556, 1566, 1567,
+ 1568, 1558, 1557,
+ 1557, 1567, 1568,
+ 1569, 1559, 1558,
+ 1558, 1568, 1569,
+ 1570, 1560, 1559,
+ 1559, 1569, 1570,
+ 1571, 1561, 1560,
+ 1560, 1570, 1571,
+ 1572, 1562, 1457,
+ 1457, 1573, 1572,
+ 1574, 1563, 1562,
+ 1562, 1572, 1574,
+ 1575, 1564, 1563,
+ 1563, 1574, 1575,
+ 1576, 1565, 1564,
+ 1564, 1575, 1576,
+ 1577, 1566, 1565,
+ 1565, 1576, 1577,
+ 1578, 1567, 1566,
+ 1566, 1577, 1578,
+ 1579, 1568, 1567,
+ 1567, 1578, 1579,
+ 1580, 1569, 1568,
+ 1568, 1579, 1580,
+ 1581, 1570, 1569,
+ 1569, 1580, 1581,
+ 1582, 1571, 1570,
+ 1570, 1581, 1582,
+ 1583, 1572, 1573,
+ 1573, 1479, 1583,
+ 1584, 1574, 1572,
+ 1572, 1583, 1584,
+ 1585, 1575, 1574,
+ 1574, 1584, 1585,
+ 1586, 1576, 1575,
+ 1575, 1585, 1586,
+ 1587, 1577, 1576,
+ 1576, 1586, 1587,
+ 1588, 1578, 1577,
+ 1577, 1587, 1588,
+ 1589, 1579, 1578,
+ 1578, 1588, 1589,
+ 1590, 1580, 1579,
+ 1579, 1589, 1590,
+ 1591, 1581, 1580,
+ 1580, 1590, 1591,
+ 1470, 1582, 1581,
+ 1581, 1591, 1470,
+ 1592, 1583, 1479,
+ 1479, 1490, 1592,
+ 1593, 1584, 1583,
+ 1583, 1592, 1593,
+ 1594, 1585, 1584,
+ 1584, 1593, 1594,
+ 1595, 1586, 1585,
+ 1585, 1594, 1595,
+ 1596, 1587, 1586,
+ 1586, 1595, 1596,
+ 1597, 1588, 1587,
+ 1587, 1596, 1597,
+ 1598, 1589, 1588,
+ 1588, 1597, 1598,
+ 1599, 1590, 1589,
+ 1589, 1598, 1599,
+ 1600, 1591, 1590,
+ 1590, 1599, 1600,
+ 1601, 1470, 1591,
+ 1591, 1600, 1601,
+ 1602, 1592, 1490,
+ 1490, 1603, 1602,
+ 1604, 1593, 1592,
+ 1592, 1602, 1604,
+ 1605, 1594, 1593,
+ 1593, 1604, 1605,
+ 1606, 1595, 1594,
+ 1594, 1605, 1606,
+ 1607, 1596, 1595,
+ 1595, 1606, 1607,
+ 1608, 1597, 1596,
+ 1596, 1607, 1608,
+ 1609, 1598, 1597,
+ 1597, 1608, 1609,
+ 1610, 1599, 1598,
+ 1598, 1609, 1610,
+ 1611, 1600, 1599,
+ 1599, 1610, 1611,
+ 1612, 1601, 1600,
+ 1600, 1611, 1612,
+ 1613, 1602, 1603,
+ 1603, 1512, 1613,
+ 1614, 1604, 1602,
+ 1602, 1613, 1614,
+ 1615, 1605, 1604,
+ 1604, 1614, 1615,
+ 1616, 1606, 1605,
+ 1605, 1615, 1616,
+ 1617, 1607, 1606,
+ 1606, 1616, 1617,
+ 1618, 1608, 1607,
+ 1607, 1617, 1618,
+ 1619, 1609, 1608,
+ 1608, 1618, 1619,
+ 1620, 1610, 1609,
+ 1609, 1619, 1620,
+ 1621, 1611, 1610,
+ 1610, 1620, 1621,
+ 1503, 1612, 1611,
+ 1611, 1621, 1503,
+ 1622, 1502, 1503,
+ 1503, 1623, 1622,
+ 1624, 1504, 1502,
+ 1502, 1622, 1624,
+ 1625, 1505, 1504,
+ 1504, 1624, 1625,
+ 1626, 1506, 1505,
+ 1505, 1625, 1626,
+ 1627, 1507, 1506,
+ 1506, 1626, 1627,
+ 1628, 1508, 1507,
+ 1507, 1627, 1628,
+ 1629, 1509, 1508,
+ 1508, 1628, 1629,
+ 1630, 1510, 1509,
+ 1509, 1629, 1630,
+ 1631, 1511, 1510,
+ 1510, 1630, 1631,
+ 1632, 1512, 1511,
+ 1511, 1631, 1632,
+ 1633, 1622, 1623,
+ 1623, 1634, 1633,
+ 1635, 1624, 1622,
+ 1622, 1633, 1635,
+ 1636, 1625, 1624,
+ 1624, 1635, 1636,
+ 1637, 1626, 1625,
+ 1625, 1636, 1637,
+ 1638, 1627, 1626,
+ 1626, 1637, 1638,
+ 1639, 1628, 1627,
+ 1627, 1638, 1639,
+ 1640, 1629, 1628,
+ 1628, 1639, 1640,
+ 1641, 1630, 1629,
+ 1629, 1640, 1641,
+ 1642, 1631, 1630,
+ 1630, 1641, 1642,
+ 1643, 1632, 1631,
+ 1631, 1642, 1643,
+ 1644, 1633, 1634,
+ 1634, 1645, 1644,
+ 1646, 1635, 1633,
+ 1633, 1644, 1646,
+ 1647, 1636, 1635,
+ 1635, 1646, 1647,
+ 1648, 1637, 1636,
+ 1636, 1647, 1648,
+ 1649, 1638, 1637,
+ 1637, 1648, 1649,
+ 1650, 1639, 1638,
+ 1638, 1649, 1650,
+ 1651, 1640, 1639,
+ 1639, 1650, 1651,
+ 1652, 1641, 1640,
+ 1640, 1651, 1652,
+ 1653, 1642, 1641,
+ 1641, 1652, 1653,
+ 1654, 1643, 1642,
+ 1642, 1653, 1654,
+ 1655, 1644, 1645,
+ 1645, 1656, 1655,
+ 1657, 1646, 1644,
+ 1644, 1655, 1657,
+ 1658, 1647, 1646,
+ 1646, 1657, 1658,
+ 1659, 1648, 1647,
+ 1647, 1658, 1659,
+ 1660, 1649, 1648,
+ 1648, 1659, 1660,
+ 1661, 1650, 1649,
+ 1649, 1660, 1661,
+ 1662, 1651, 1650,
+ 1650, 1661, 1662,
+ 1663, 1652, 1651,
+ 1651, 1662, 1663,
+ 1664, 1653, 1652,
+ 1652, 1663, 1664,
+ 1665, 1654, 1653,
+ 1653, 1664, 1665,
+ 1666, 1655, 1656,
+ 1656, 1667, 1666,
+ 1668, 1657, 1655,
+ 1655, 1666, 1668,
+ 1669, 1658, 1657,
+ 1657, 1668, 1669,
+ 1670, 1659, 1658,
+ 1658, 1669, 1670,
+ 1671, 1660, 1659,
+ 1659, 1670, 1671,
+ 1672, 1661, 1660,
+ 1660, 1671, 1672,
+ 1673, 1662, 1661,
+ 1661, 1672, 1673,
+ 1674, 1663, 1662,
+ 1662, 1673, 1674,
+ 1675, 1664, 1663,
+ 1663, 1674, 1675,
+ 1676, 1665, 1664,
+ 1664, 1675, 1676,
+ 1677, 1666, 1667,
+ 1667, 1678, 1677,
+ 1679, 1668, 1666,
+ 1666, 1677, 1679,
+ 1680, 1669, 1668,
+ 1668, 1679, 1680,
+ 1681, 1670, 1669,
+ 1669, 1680, 1681,
+ 1682, 1671, 1670,
+ 1670, 1681, 1682,
+ 1683, 1672, 1671,
+ 1671, 1682, 1683,
+ 1684, 1673, 1672,
+ 1672, 1683, 1684,
+ 1685, 1674, 1673,
+ 1673, 1684, 1685,
+ 1686, 1675, 1674,
+ 1674, 1685, 1686,
+ 1687, 1676, 1675,
+ 1675, 1686, 1687,
+ 1688, 1677, 1678,
+ 1678, 1689, 1688,
+ 1690, 1679, 1677,
+ 1677, 1688, 1690,
+ 1691, 1680, 1679,
+ 1679, 1690, 1691,
+ 1692, 1681, 1680,
+ 1680, 1691, 1692,
+ 1693, 1682, 1681,
+ 1681, 1692, 1693,
+ 1694, 1683, 1682,
+ 1682, 1693, 1694,
+ 1695, 1684, 1683,
+ 1683, 1694, 1695,
+ 1696, 1685, 1684,
+ 1684, 1695, 1696,
+ 1697, 1686, 1685,
+ 1685, 1696, 1697,
+ 1698, 1687, 1686,
+ 1686, 1697, 1698,
+ 1699, 1688, 1689,
+ 1689, 1700, 1699,
+ 1701, 1690, 1688,
+ 1688, 1699, 1701,
+ 1702, 1691, 1690,
+ 1690, 1701, 1702,
+ 1703, 1692, 1691,
+ 1691, 1702, 1703,
+ 1704, 1693, 1692,
+ 1692, 1703, 1704,
+ 1705, 1694, 1693,
+ 1693, 1704, 1705,
+ 1706, 1695, 1694,
+ 1694, 1705, 1706,
+ 1707, 1696, 1695,
+ 1695, 1706, 1707,
+ 1708, 1697, 1696,
+ 1696, 1707, 1708,
+ 1709, 1698, 1697,
+ 1697, 1708, 1709,
+ 1710, 1699, 1700,
+ 1700, 1711, 1710,
+ 1712, 1701, 1699,
+ 1699, 1710, 1712,
+ 1713, 1702, 1701,
+ 1701, 1712, 1713,
+ 1714, 1703, 1702,
+ 1702, 1713, 1714,
+ 1715, 1704, 1703,
+ 1703, 1714, 1715,
+ 1716, 1705, 1704,
+ 1704, 1715, 1716,
+ 1717, 1706, 1705,
+ 1705, 1716, 1717,
+ 1718, 1707, 1706,
+ 1706, 1717, 1718,
+ 1719, 1708, 1707,
+ 1707, 1718, 1719,
+ 1720, 1709, 1708,
+ 1708, 1719, 1720,
+ 1721, 1710, 1711,
+ 1711, 800, 1721,
+ 1722, 1712, 1710,
+ 1710, 1721, 1722,
+ 1723, 1713, 1712,
+ 1712, 1722, 1723,
+ 1724, 1714, 1713,
+ 1713, 1723, 1724,
+ 1725, 1715, 1714,
+ 1714, 1724, 1725,
+ 1726, 1716, 1715,
+ 1715, 1725, 1726,
+ 1727, 1717, 1716,
+ 1716, 1726, 1727,
+ 1728, 1718, 1717,
+ 1717, 1727, 1728,
+ 1729, 1719, 1718,
+ 1718, 1728, 1729,
+ 1730, 1720, 1719,
+ 1719, 1729, 1730,
+ 1731, 1613, 1512,
+ 1512, 1632, 1731,
+ 1732, 1614, 1613,
+ 1613, 1731, 1732,
+ 1733, 1615, 1614,
+ 1614, 1732, 1733,
+ 1734, 1616, 1615,
+ 1615, 1733, 1734,
+ 1735, 1617, 1616,
+ 1616, 1734, 1735,
+ 1736, 1618, 1617,
+ 1617, 1735, 1736,
+ 1737, 1619, 1618,
+ 1618, 1736, 1737,
+ 1738, 1620, 1619,
+ 1619, 1737, 1738,
+ 1739, 1621, 1620,
+ 1620, 1738, 1739,
+ 1623, 1503, 1621,
+ 1621, 1739, 1623,
+ 1740, 1731, 1632,
+ 1632, 1741, 1740,
+ 1742, 1732, 1731,
+ 1731, 1740, 1742,
+ 1743, 1733, 1732,
+ 1732, 1742, 1743,
+ 1744, 1734, 1733,
+ 1733, 1743, 1744,
+ 1745, 1735, 1734,
+ 1734, 1744, 1745,
+ 1746, 1736, 1735,
+ 1735, 1745, 1746,
+ 1747, 1737, 1736,
+ 1736, 1746, 1747,
+ 1748, 1738, 1737,
+ 1737, 1747, 1748,
+ 1749, 1739, 1738,
+ 1738, 1748, 1749,
+ 1750, 1623, 1739,
+ 1739, 1749, 1750,
+ 1751, 1740, 1741,
+ 1741, 1752, 1751,
+ 1753, 1742, 1740,
+ 1740, 1751, 1753,
+ 1754, 1743, 1742,
+ 1742, 1753, 1754,
+ 1755, 1744, 1743,
+ 1743, 1754, 1755,
+ 1756, 1745, 1744,
+ 1744, 1755, 1756,
+ 1757, 1746, 1745,
+ 1745, 1756, 1757,
+ 1758, 1747, 1746,
+ 1746, 1757, 1758,
+ 1759, 1748, 1747,
+ 1747, 1758, 1759,
+ 1760, 1749, 1748,
+ 1748, 1759, 1760,
+ 1645, 1750, 1749,
+ 1749, 1760, 1645,
+ 1761, 1751, 1752,
+ 1752, 1665, 1761,
+ 1762, 1753, 1751,
+ 1751, 1761, 1762,
+ 1763, 1754, 1753,
+ 1753, 1762, 1763,
+ 1764, 1755, 1754,
+ 1754, 1763, 1764,
+ 1765, 1756, 1755,
+ 1755, 1764, 1765,
+ 1766, 1757, 1756,
+ 1756, 1765, 1766,
+ 1767, 1758, 1757,
+ 1757, 1766, 1767,
+ 1768, 1759, 1758,
+ 1758, 1767, 1768,
+ 1769, 1760, 1759,
+ 1759, 1768, 1769,
+ 1656, 1645, 1760,
+ 1760, 1769, 1656,
+ 1770, 1761, 1665,
+ 1665, 1771, 1770,
+ 1772, 1762, 1761,
+ 1761, 1770, 1772,
+ 1773, 1763, 1762,
+ 1762, 1772, 1773,
+ 1774, 1764, 1763,
+ 1763, 1773, 1774,
+ 1775, 1765, 1764,
+ 1764, 1774, 1775,
+ 1776, 1766, 1765,
+ 1765, 1775, 1776,
+ 1777, 1767, 1766,
+ 1766, 1776, 1777,
+ 1778, 1768, 1767,
+ 1767, 1777, 1778,
+ 1779, 1769, 1768,
+ 1768, 1778, 1779,
+ 1780, 1656, 1769,
+ 1769, 1779, 1780,
+ 1781, 1770, 1771,
+ 1771, 1782, 1781,
+ 1783, 1772, 1770,
+ 1770, 1781, 1783,
+ 1784, 1773, 1772,
+ 1772, 1783, 1784,
+ 1785, 1774, 1773,
+ 1773, 1784, 1785,
+ 1786, 1775, 1774,
+ 1774, 1785, 1786,
+ 1787, 1776, 1775,
+ 1775, 1786, 1787,
+ 1788, 1777, 1776,
+ 1776, 1787, 1788,
+ 1789, 1778, 1777,
+ 1777, 1788, 1789,
+ 1790, 1779, 1778,
+ 1778, 1789, 1790,
+ 1791, 1780, 1779,
+ 1779, 1790, 1791,
+ 1792, 1781, 1782,
+ 1782, 1698, 1792,
+ 1793, 1783, 1781,
+ 1781, 1792, 1793,
+ 1794, 1784, 1783,
+ 1783, 1793, 1794,
+ 1795, 1785, 1784,
+ 1784, 1794, 1795,
+ 1796, 1786, 1785,
+ 1785, 1795, 1796,
+ 1797, 1787, 1786,
+ 1786, 1796, 1797,
+ 1798, 1788, 1787,
+ 1787, 1797, 1798,
+ 1799, 1789, 1788,
+ 1788, 1798, 1799,
+ 1800, 1790, 1789,
+ 1789, 1799, 1800,
+ 1689, 1791, 1790,
+ 1790, 1800, 1689,
+ 1801, 1792, 1698,
+ 1698, 1802, 1801,
+ 1803, 1793, 1792,
+ 1792, 1801, 1803,
+ 1804, 1794, 1793,
+ 1793, 1803, 1804,
+ 1805, 1795, 1794,
+ 1794, 1804, 1805,
+ 1806, 1796, 1795,
+ 1795, 1805, 1806,
+ 1807, 1797, 1796,
+ 1796, 1806, 1807,
+ 1808, 1798, 1797,
+ 1797, 1807, 1808,
+ 1809, 1799, 1798,
+ 1798, 1808, 1809,
+ 1810, 1800, 1799,
+ 1799, 1809, 1810,
+ 1811, 1689, 1800,
+ 1800, 1810, 1811,
+ 1812, 1801, 1802,
+ 1802, 1813, 1812,
+ 1814, 1803, 1801,
+ 1801, 1812, 1814,
+ 1815, 1804, 1803,
+ 1803, 1814, 1815,
+ 1816, 1805, 1804,
+ 1804, 1815, 1816,
+ 1817, 1806, 1805,
+ 1805, 1816, 1817,
+ 1818, 1807, 1806,
+ 1806, 1817, 1818,
+ 1819, 1808, 1807,
+ 1807, 1818, 1819,
+ 1820, 1809, 1808,
+ 1808, 1819, 1820,
+ 1821, 1810, 1809,
+ 1809, 1820, 1821,
+ 1822, 1811, 1810,
+ 1810, 1821, 1822,
+ 1823, 1812, 1813,
+ 1813, 1824, 1823,
+ 1825, 1814, 1812,
+ 1812, 1823, 1825,
+ 1826, 1815, 1814,
+ 1814, 1825, 1826,
+ 1827, 1816, 1815,
+ 1815, 1826, 1827,
+ 1828, 1817, 1816,
+ 1816, 1827, 1828,
+ 1829, 1818, 1817,
+ 1817, 1828, 1829,
+ 1830, 1819, 1818,
+ 1818, 1829, 1830,
+ 1831, 1820, 1819,
+ 1819, 1830, 1831,
+ 1832, 1821, 1820,
+ 1820, 1831, 1832,
+ 1833, 1822, 1821,
+ 1821, 1832, 1833,
+ 1834, 1835, 1836,
+ 1836, 1837, 1834,
+ 1838, 1839, 1835,
+ 1835, 1834, 1838,
+ 1840, 1841, 1839,
+ 1839, 1838, 1840,
+ 1842, 1843, 1841,
+ 1841, 1840, 1842,
+ 1844, 1845, 1843,
+ 1843, 1842, 1844,
+ 1846, 1847, 1845,
+ 1845, 1844, 1846,
+ 1848, 1849, 1847,
+ 1847, 1846, 1848,
+ 1850, 1851, 1849,
+ 1849, 1848, 1850,
+ 1852, 1853, 1851,
+ 1851, 1850, 1852,
+ 1854, 1855, 1853,
+ 1853, 1852, 1854,
+ 1856, 1834, 1837,
+ 1837, 1857, 1856,
+ 1858, 1838, 1834,
+ 1834, 1856, 1858,
+ 1859, 1840, 1838,
+ 1838, 1858, 1859,
+ 1860, 1842, 1840,
+ 1840, 1859, 1860,
+ 1861, 1844, 1842,
+ 1842, 1860, 1861,
+ 1862, 1846, 1844,
+ 1844, 1861, 1862,
+ 1863, 1848, 1846,
+ 1846, 1862, 1863,
+ 1864, 1850, 1848,
+ 1848, 1863, 1864,
+ 1865, 1852, 1850,
+ 1850, 1864, 1865,
+ 1866, 1854, 1852,
+ 1852, 1865, 1866,
+ 1867, 1856, 1857,
+ 1857, 1868, 1867,
+ 1869, 1858, 1856,
+ 1856, 1867, 1869,
+ 1870, 1859, 1858,
+ 1858, 1869, 1870,
+ 1871, 1860, 1859,
+ 1859, 1870, 1871,
+ 1872, 1861, 1860,
+ 1860, 1871, 1872,
+ 1873, 1862, 1861,
+ 1861, 1872, 1873,
+ 1874, 1863, 1862,
+ 1862, 1873, 1874,
+ 1875, 1864, 1863,
+ 1863, 1874, 1875,
+ 1876, 1865, 1864,
+ 1864, 1875, 1876,
+ 1877, 1866, 1865,
+ 1865, 1876, 1877,
+ 1878, 1867, 1868,
+ 1868, 1879, 1878,
+ 1880, 1869, 1867,
+ 1867, 1878, 1880,
+ 1881, 1870, 1869,
+ 1869, 1880, 1881,
+ 1882, 1871, 1870,
+ 1870, 1881, 1882,
+ 1883, 1872, 1871,
+ 1871, 1882, 1883,
+ 1884, 1873, 1872,
+ 1872, 1883, 1884,
+ 1885, 1874, 1873,
+ 1873, 1884, 1885,
+ 1886, 1875, 1874,
+ 1874, 1885, 1886,
+ 1887, 1876, 1875,
+ 1875, 1886, 1887,
+ 1888, 1877, 1876,
+ 1876, 1887, 1888,
+ 1889, 1878, 1879,
+ 1879, 1890, 1889,
+ 1891, 1880, 1878,
+ 1878, 1889, 1891,
+ 1892, 1881, 1880,
+ 1880, 1891, 1892,
+ 1893, 1882, 1881,
+ 1881, 1892, 1893,
+ 1894, 1883, 1882,
+ 1882, 1893, 1894,
+ 1895, 1884, 1883,
+ 1883, 1894, 1895,
+ 1896, 1885, 1884,
+ 1884, 1895, 1896,
+ 1897, 1886, 1885,
+ 1885, 1896, 1897,
+ 1898, 1887, 1886,
+ 1886, 1897, 1898,
+ 1899, 1888, 1887,
+ 1887, 1898, 1899,
+ 1900, 1889, 1890,
+ 1890, 1901, 1900,
+ 1902, 1891, 1889,
+ 1889, 1900, 1902,
+ 1903, 1892, 1891,
+ 1891, 1902, 1903,
+ 1904, 1893, 1892,
+ 1892, 1903, 1904,
+ 1905, 1894, 1893,
+ 1893, 1904, 1905,
+ 1906, 1895, 1894,
+ 1894, 1905, 1906,
+ 1907, 1896, 1895,
+ 1895, 1906, 1907,
+ 1908, 1897, 1896,
+ 1896, 1907, 1908,
+ 1909, 1898, 1897,
+ 1897, 1908, 1909,
+ 1910, 1899, 1898,
+ 1898, 1909, 1910,
+ 1911, 1900, 1901,
+ 1901, 1912, 1911,
+ 1913, 1902, 1900,
+ 1900, 1911, 1913,
+ 1914, 1903, 1902,
+ 1902, 1913, 1914,
+ 1915, 1904, 1903,
+ 1903, 1914, 1915,
+ 1916, 1905, 1904,
+ 1904, 1915, 1916,
+ 1917, 1906, 1905,
+ 1905, 1916, 1917,
+ 1918, 1907, 1906,
+ 1906, 1917, 1918,
+ 1919, 1908, 1907,
+ 1907, 1918, 1919,
+ 1920, 1909, 1908,
+ 1908, 1919, 1920,
+ 1921, 1910, 1909,
+ 1909, 1920, 1921,
+ 1922, 1911, 1912,
+ 1912, 1923, 1922,
+ 1924, 1913, 1911,
+ 1911, 1922, 1924,
+ 1925, 1914, 1913,
+ 1913, 1924, 1925,
+ 1926, 1915, 1914,
+ 1914, 1925, 1926,
+ 1927, 1916, 1915,
+ 1915, 1926, 1927,
+ 1928, 1917, 1916,
+ 1916, 1927, 1928,
+ 1929, 1918, 1917,
+ 1917, 1928, 1929,
+ 1930, 1919, 1918,
+ 1918, 1929, 1930,
+ 1931, 1920, 1919,
+ 1919, 1930, 1931,
+ 1932, 1921, 1920,
+ 1920, 1931, 1932,
+ 1933, 1922, 1923,
+ 1923, 1934, 1933,
+ 1935, 1924, 1922,
+ 1922, 1933, 1935,
+ 1936, 1925, 1924,
+ 1924, 1935, 1936,
+ 1937, 1926, 1925,
+ 1925, 1936, 1937,
+ 1938, 1927, 1926,
+ 1926, 1937, 1938,
+ 1939, 1928, 1927,
+ 1927, 1938, 1939,
+ 1940, 1929, 1928,
+ 1928, 1939, 1940,
+ 1941, 1930, 1929,
+ 1929, 1940, 1941,
+ 1942, 1931, 1930,
+ 1930, 1941, 1942,
+ 1943, 1932, 1931,
+ 1931, 1942, 1943,
+ 1944, 1933, 1934,
+ 1934, 1945, 1944,
+ 1946, 1935, 1933,
+ 1933, 1944, 1946,
+ 1947, 1936, 1935,
+ 1935, 1946, 1947,
+ 1948, 1937, 1936,
+ 1936, 1947, 1948,
+ 1949, 1938, 1937,
+ 1937, 1948, 1949,
+ 1950, 1939, 1938,
+ 1938, 1949, 1950,
+ 1951, 1940, 1939,
+ 1939, 1950, 1951,
+ 1952, 1941, 1940,
+ 1940, 1951, 1952,
+ 1953, 1942, 1941,
+ 1941, 1952, 1953,
+ 1954, 1943, 1942,
+ 1942, 1953, 1954,
+ 1955, 1956, 1957,
+ 1957, 1958, 1955,
+ 1959, 1960, 1956,
+ 1956, 1955, 1959,
+ 1961, 1962, 1960,
+ 1960, 1959, 1961,
+ 1963, 1964, 1962,
+ 1962, 1961, 1963,
+ 1965, 1966, 1964,
+ 1964, 1963, 1965,
+ 1967, 1968, 1966,
+ 1966, 1965, 1967,
+ 1969, 1970, 1968,
+ 1968, 1967, 1969,
+ 1971, 1972, 1970,
+ 1970, 1969, 1971,
+ 1973, 1974, 1972,
+ 1972, 1971, 1973,
+ 1975, 1976, 1974,
+ 1974, 1973, 1975,
+ 1977, 1955, 1958,
+ 1958, 1978, 1977,
+ 1979, 1959, 1955,
+ 1955, 1977, 1979,
+ 1980, 1961, 1959,
+ 1959, 1979, 1980,
+ 1981, 1963, 1961,
+ 1961, 1980, 1981,
+ 1982, 1965, 1963,
+ 1963, 1981, 1982,
+ 1983, 1967, 1965,
+ 1965, 1982, 1983,
+ 1984, 1969, 1967,
+ 1967, 1983, 1984,
+ 1985, 1971, 1969,
+ 1969, 1984, 1985,
+ 1986, 1973, 1971,
+ 1971, 1985, 1986,
+ 1987, 1975, 1973,
+ 1973, 1986, 1987,
+ 1988, 1977, 1978,
+ 1978, 1989, 1988,
+ 1990, 1979, 1977,
+ 1977, 1988, 1990,
+ 1991, 1980, 1979,
+ 1979, 1990, 1991,
+ 1992, 1981, 1980,
+ 1980, 1991, 1992,
+ 1993, 1982, 1981,
+ 1981, 1992, 1993,
+ 1994, 1983, 1982,
+ 1982, 1993, 1994,
+ 1995, 1984, 1983,
+ 1983, 1994, 1995,
+ 1996, 1985, 1984,
+ 1984, 1995, 1996,
+ 1997, 1986, 1985,
+ 1985, 1996, 1997,
+ 1998, 1987, 1986,
+ 1986, 1997, 1998,
+ 1999, 1988, 1989,
+ 1989, 2000, 1999,
+ 2001, 1990, 1988,
+ 1988, 1999, 2001,
+ 2002, 1991, 1990,
+ 1990, 2001, 2002,
+ 2003, 1992, 1991,
+ 1991, 2002, 2003,
+ 2004, 1993, 1992,
+ 1992, 2003, 2004,
+ 2005, 1994, 1993,
+ 1993, 2004, 2005,
+ 2006, 1995, 1994,
+ 1994, 2005, 2006,
+ 2007, 1996, 1995,
+ 1995, 2006, 2007,
+ 2008, 1997, 1996,
+ 1996, 2007, 2008,
+ 2009, 1998, 1997,
+ 1997, 2008, 2009,
+ 2010, 1999, 2000,
+ 2000, 2011, 2010,
+ 2012, 2001, 1999,
+ 1999, 2010, 2012,
+ 2013, 2002, 2001,
+ 2001, 2012, 2013,
+ 2014, 2003, 2002,
+ 2002, 2013, 2014,
+ 2015, 2004, 2003,
+ 2003, 2014, 2015,
+ 2016, 2005, 2004,
+ 2004, 2015, 2016,
+ 2017, 2006, 2005,
+ 2005, 2016, 2017,
+ 2018, 2007, 2006,
+ 2006, 2017, 2018,
+ 2019, 2008, 2007,
+ 2007, 2018, 2019,
+ 2020, 2009, 2008,
+ 2008, 2019, 2020,
+ 2021, 2010, 2011,
+ 2011, 2022, 2021,
+ 2023, 2012, 2010,
+ 2010, 2021, 2023,
+ 2024, 2013, 2012,
+ 2012, 2023, 2024,
+ 2025, 2014, 2013,
+ 2013, 2024, 2025,
+ 2026, 2015, 2014,
+ 2014, 2025, 2026,
+ 2027, 2016, 2015,
+ 2015, 2026, 2027,
+ 2028, 2017, 2016,
+ 2016, 2027, 2028,
+ 2029, 2018, 2017,
+ 2017, 2028, 2029,
+ 2030, 2019, 2018,
+ 2018, 2029, 2030,
+ 2031, 2020, 2019,
+ 2019, 2030, 2031,
+ 2032, 2021, 2022,
+ 2022, 2033, 2032,
+ 2034, 2023, 2021,
+ 2021, 2032, 2034,
+ 2035, 2024, 2023,
+ 2023, 2034, 2035,
+ 2036, 2025, 2024,
+ 2024, 2035, 2036,
+ 2037, 2026, 2025,
+ 2025, 2036, 2037,
+ 2038, 2027, 2026,
+ 2026, 2037, 2038,
+ 2039, 2028, 2027,
+ 2027, 2038, 2039,
+ 2040, 2029, 2028,
+ 2028, 2039, 2040,
+ 2041, 2030, 2029,
+ 2029, 2040, 2041,
+ 2042, 2031, 2030,
+ 2030, 2041, 2042,
+ 2043, 2032, 2033,
+ 2033, 1932, 2043,
+ 2044, 2034, 2032,
+ 2032, 2043, 2044,
+ 2045, 2035, 2034,
+ 2034, 2044, 2045,
+ 2046, 2036, 2035,
+ 2035, 2045, 2046,
+ 2047, 2037, 2036,
+ 2036, 2046, 2047,
+ 2048, 2038, 2037,
+ 2037, 2047, 2048,
+ 2049, 2039, 2038,
+ 2038, 2048, 2049,
+ 2050, 2040, 2039,
+ 2039, 2049, 2050,
+ 2051, 2041, 2040,
+ 2040, 2050, 2051,
+ 1923, 2042, 2041,
+ 2041, 2051, 1923,
+ 2052, 2043, 1932,
+ 1932, 2053, 2052,
+ 2054, 2044, 2043,
+ 2043, 2052, 2054,
+ 2055, 2045, 2044,
+ 2044, 2054, 2055,
+ 2056, 2046, 2045,
+ 2045, 2055, 2056,
+ 2057, 2047, 2046,
+ 2046, 2056, 2057,
+ 2058, 2048, 2047,
+ 2047, 2057, 2058,
+ 2059, 2049, 2048,
+ 2048, 2058, 2059,
+ 2060, 2050, 2049,
+ 2049, 2059, 2060,
+ 2061, 2051, 2050,
+ 2050, 2060, 2061,
+ 2062, 1923, 2051,
+ 2051, 2061, 2062,
+ 2063, 2052, 2053,
+ 2053, 2064, 2063,
+ 2065, 2054, 2052,
+ 2052, 2063, 2065,
+ 2066, 2055, 2054,
+ 2054, 2065, 2066,
+ 2067, 2056, 2055,
+ 2055, 2066, 2067,
+ 2068, 2057, 2056,
+ 2056, 2067, 2068,
+ 2069, 2058, 2057,
+ 2057, 2068, 2069,
+ 2070, 2059, 2058,
+ 2058, 2069, 2070,
+ 2071, 2060, 2059,
+ 2059, 2070, 2071,
+ 2072, 2061, 2060,
+ 2060, 2071, 2072,
+ 2073, 2062, 2061,
+ 2061, 2072, 2073,
+ 2074, 2075, 2076,
+ 2076, 2077, 2074,
+ 2078, 2079, 2075,
+ 2075, 2074, 2078,
+ 2080, 2081, 2079,
+ 2079, 2078, 2080,
+ 2082, 2083, 2081,
+ 2081, 2080, 2082,
+ 2084, 2085, 2083,
+ 2083, 2082, 2084,
+ 2086, 2087, 2085,
+ 2085, 2084, 2086,
+ 2088, 2089, 2087,
+ 2087, 2086, 2088,
+ 2090, 2091, 2089,
+ 2089, 2088, 2090,
+ 2092, 2093, 2091,
+ 2091, 2090, 2092,
+ 2094, 2064, 2093,
+ 2093, 2092, 2094,
+ 2095, 2074, 2077,
+ 2077, 2096, 2095,
+ 2097, 2078, 2074,
+ 2074, 2095, 2097,
+ 2098, 2080, 2078,
+ 2078, 2097, 2098,
+ 2099, 2082, 2080,
+ 2080, 2098, 2099,
+ 2100, 2084, 2082,
+ 2082, 2099, 2100,
+ 2101, 2086, 2084,
+ 2084, 2100, 2101,
+ 2102, 2088, 2086,
+ 2086, 2101, 2102,
+ 2103, 2090, 2088,
+ 2088, 2102, 2103,
+ 2104, 2092, 2090,
+ 2090, 2103, 2104,
+ 2105, 2094, 2092,
+ 2092, 2104, 2105,
+ 2106, 2095, 2096,
+ 2096, 2107, 2106,
+ 2108, 2097, 2095,
+ 2095, 2106, 2108,
+ 2109, 2098, 2097,
+ 2097, 2108, 2109,
+ 2110, 2099, 2098,
+ 2098, 2109, 2110,
+ 2111, 2100, 2099,
+ 2099, 2110, 2111,
+ 2112, 2101, 2100,
+ 2100, 2111, 2112,
+ 2113, 2102, 2101,
+ 2101, 2112, 2113,
+ 2114, 2103, 2102,
+ 2102, 2113, 2114,
+ 2115, 2104, 2103,
+ 2103, 2114, 2115,
+ 2116, 2105, 2104,
+ 2104, 2115, 2116,
+ 2117, 2106, 2107,
+ 2107, 2118, 2117,
+ 2119, 2108, 2106,
+ 2106, 2117, 2119,
+ 2120, 2109, 2108,
+ 2108, 2119, 2120,
+ 2121, 2110, 2109,
+ 2109, 2120, 2121,
+ 2122, 2111, 2110,
+ 2110, 2121, 2122,
+ 2123, 2112, 2111,
+ 2111, 2122, 2123,
+ 2124, 2113, 2112,
+ 2112, 2123, 2124,
+ 2125, 2114, 2113,
+ 2113, 2124, 2125,
+ 2126, 2115, 2114,
+ 2114, 2125, 2126,
+ 2127, 2116, 2115,
+ 2115, 2126, 2127,
+ 2128, 2117, 2118,
+ 2118, 2129, 2128,
+ 2130, 2119, 2117,
+ 2117, 2128, 2130,
+ 2131, 2120, 2119,
+ 2119, 2130, 2131,
+ 2132, 2121, 2120,
+ 2120, 2131, 2132,
+ 2133, 2122, 2121,
+ 2121, 2132, 2133,
+ 2134, 2123, 2122,
+ 2122, 2133, 2134,
+ 2135, 2124, 2123,
+ 2123, 2134, 2135,
+ 2136, 2125, 2124,
+ 2124, 2135, 2136,
+ 2137, 2126, 2125,
+ 2125, 2136, 2137,
+ 2138, 2127, 2126,
+ 2126, 2137, 2138,
+ 2139, 2128, 2129,
+ 2129, 2140, 2139,
+ 2141, 2130, 2128,
+ 2128, 2139, 2141,
+ 2142, 2131, 2130,
+ 2130, 2141, 2142,
+ 2143, 2132, 2131,
+ 2131, 2142, 2143,
+ 2144, 2133, 2132,
+ 2132, 2143, 2144,
+ 2145, 2134, 2133,
+ 2133, 2144, 2145,
+ 2146, 2135, 2134,
+ 2134, 2145, 2146,
+ 2147, 2136, 2135,
+ 2135, 2146, 2147,
+ 2148, 2137, 2136,
+ 2136, 2147, 2148,
+ 2149, 2138, 2137,
+ 2137, 2148, 2149,
+ 2150, 2139, 2140,
+ 2140, 2151, 2150,
+ 2152, 2141, 2139,
+ 2139, 2150, 2152,
+ 2153, 2142, 2141,
+ 2141, 2152, 2153,
+ 2154, 2143, 2142,
+ 2142, 2153, 2154,
+ 2155, 2144, 2143,
+ 2143, 2154, 2155,
+ 2156, 2145, 2144,
+ 2144, 2155, 2156,
+ 2157, 2146, 2145,
+ 2145, 2156, 2157,
+ 2158, 2147, 2146,
+ 2146, 2157, 2158,
+ 2159, 2148, 2147,
+ 2147, 2158, 2159,
+ 2160, 2149, 2148,
+ 2148, 2159, 2160,
+ 2161, 2150, 2151,
+ 2151, 2162, 2161,
+ 2163, 2152, 2150,
+ 2150, 2161, 2163,
+ 2164, 2153, 2152,
+ 2152, 2163, 2164,
+ 2165, 2154, 2153,
+ 2153, 2164, 2165,
+ 2166, 2155, 2154,
+ 2154, 2165, 2166,
+ 2167, 2156, 2155,
+ 2155, 2166, 2167,
+ 2168, 2157, 2156,
+ 2156, 2167, 2168,
+ 2169, 2158, 2157,
+ 2157, 2168, 2169,
+ 2170, 2159, 2158,
+ 2158, 2169, 2170,
+ 2171, 2160, 2159,
+ 2159, 2170, 2171,
+ 2172, 2161, 2162,
+ 2162, 2173, 2172,
+ 2174, 2163, 2161,
+ 2161, 2172, 2174,
+ 2175, 2164, 2163,
+ 2163, 2174, 2175,
+ 2176, 2165, 2164,
+ 2164, 2175, 2176,
+ 2177, 2166, 2165,
+ 2165, 2176, 2177,
+ 2178, 2167, 2166,
+ 2166, 2177, 2178,
+ 2179, 2168, 2167,
+ 2167, 2178, 2179,
+ 2180, 2169, 2168,
+ 2168, 2179, 2180,
+ 2181, 2170, 2169,
+ 2169, 2180, 2181,
+ 2182, 2171, 2170,
+ 2170, 2181, 2182,
+ 2183, 2172, 2173,
+ 2173, 2184, 2183,
+ 2185, 2174, 2172,
+ 2172, 2183, 2185,
+ 2186, 2175, 2174,
+ 2174, 2185, 2186,
+ 2187, 2176, 2175,
+ 2175, 2186, 2187,
+ 2188, 2177, 2176,
+ 2176, 2187, 2188,
+ 2189, 2178, 2177,
+ 2177, 2188, 2189,
+ 2190, 2179, 2178,
+ 2178, 2189, 2190,
+ 2191, 2180, 2179,
+ 2179, 2190, 2191,
+ 2192, 2181, 2180,
+ 2180, 2191, 2192,
+ 2193, 2182, 2181,
+ 2181, 2192, 2193,
+ 2194, 2063, 2064,
+ 2064, 2094, 2194,
+ 2195, 2065, 2063,
+ 2063, 2194, 2195,
+ 2196, 2066, 2065,
+ 2065, 2195, 2196,
+ 2197, 2067, 2066,
+ 2066, 2196, 2197,
+ 2198, 2068, 2067,
+ 2067, 2197, 2198,
+ 2199, 2069, 2068,
+ 2068, 2198, 2199,
+ 2200, 2201, 2069,
+ 2069, 2199, 2200,
+ 2202, 2203, 2201,
+ 2201, 2200, 2202,
+ 2204, 2205, 2203,
+ 2203, 2202, 2204,
+ 2077, 2076, 2205,
+ 2205, 2204, 2077,
+ 2206, 2194, 2094,
+ 2094, 2105, 2206,
+ 2207, 2195, 2194,
+ 2194, 2206, 2207,
+ 2208, 2196, 2195,
+ 2195, 2207, 2208,
+ 2209, 2197, 2196,
+ 2196, 2208, 2209,
+ 2210, 2198, 2197,
+ 2197, 2209, 2210,
+ 2211, 2199, 2198,
+ 2198, 2210, 2211,
+ 2212, 2200, 2199,
+ 2199, 2211, 2212,
+ 2213, 2202, 2200,
+ 2200, 2212, 2213,
+ 2214, 2204, 2202,
+ 2202, 2213, 2214,
+ 2096, 2077, 2204,
+ 2204, 2214, 2096,
+ 2215, 2206, 2105,
+ 2105, 2116, 2215,
+ 2216, 2207, 2206,
+ 2206, 2215, 2216,
+ 2217, 2208, 2207,
+ 2207, 2216, 2217,
+ 2218, 2209, 2208,
+ 2208, 2217, 2218,
+ 2219, 2210, 2209,
+ 2209, 2218, 2219,
+ 2220, 2211, 2210,
+ 2210, 2219, 2220,
+ 2221, 2212, 2211,
+ 2211, 2220, 2221,
+ 2222, 2213, 2212,
+ 2212, 2221, 2222,
+ 2223, 2214, 2213,
+ 2213, 2222, 2223,
+ 2224, 2096, 2214,
+ 2214, 2223, 2224,
+ 2225, 2215, 2116,
+ 2116, 2127, 2225,
+ 2226, 2216, 2215,
+ 2215, 2225, 2226,
+ 2227, 2217, 2216,
+ 2216, 2226, 2227,
+ 2228, 2218, 2217,
+ 2217, 2227, 2228,
+ 2229, 2219, 2218,
+ 2218, 2228, 2229,
+ 2230, 2220, 2219,
+ 2219, 2229, 2230,
+ 2231, 2221, 2220,
+ 2220, 2230, 2231,
+ 2232, 2222, 2221,
+ 2221, 2231, 2232,
+ 2233, 2223, 2222,
+ 2222, 2232, 2233,
+ 2118, 2224, 2223,
+ 2223, 2233, 2118,
+ 2234, 2225, 2127,
+ 2127, 2235, 2234,
+ 2236, 2226, 2225,
+ 2225, 2234, 2236,
+ 2237, 2227, 2226,
+ 2226, 2236, 2237,
+ 2238, 2228, 2227,
+ 2227, 2237, 2238,
+ 2239, 2229, 2228,
+ 2228, 2238, 2239,
+ 2240, 2230, 2229,
+ 2229, 2239, 2240,
+ 2241, 2231, 2230,
+ 2230, 2240, 2241,
+ 2242, 2232, 2231,
+ 2231, 2241, 2242,
+ 2243, 2233, 2232,
+ 2232, 2242, 2243,
+ 2244, 2118, 2233,
+ 2233, 2243, 2244,
+ 2245, 2234, 2235,
+ 2235, 2246, 2245,
+ 2247, 2236, 2234,
+ 2234, 2245, 2247,
+ 2248, 2237, 2236,
+ 2236, 2247, 2248,
+ 2249, 2238, 2237,
+ 2237, 2248, 2249,
+ 2250, 2239, 2238,
+ 2238, 2249, 2250,
+ 2251, 2240, 2239,
+ 2239, 2250, 2251,
+ 2252, 2241, 2240,
+ 2240, 2251, 2252,
+ 2253, 2242, 2241,
+ 2241, 2252, 2253,
+ 2254, 2243, 2242,
+ 2242, 2253, 2254,
+ 2255, 2244, 2243,
+ 2243, 2254, 2255,
+ 2256, 2245, 2246,
+ 2246, 2257, 2256,
+ 2258, 2247, 2245,
+ 2245, 2256, 2258,
+ 2259, 2248, 2247,
+ 2247, 2258, 2259,
+ 2260, 2249, 2248,
+ 2248, 2259, 2260,
+ 2261, 2250, 2249,
+ 2249, 2260, 2261,
+ 2262, 2251, 2250,
+ 2250, 2261, 2262,
+ 2263, 2252, 2251,
+ 2251, 2262, 2263,
+ 2264, 2253, 2252,
+ 2252, 2263, 2264,
+ 2265, 2254, 2253,
+ 2253, 2264, 2265,
+ 2266, 2255, 2254,
+ 2254, 2265, 2266,
+ 2267, 2256, 2257,
+ 2257, 2268, 2267,
+ 2269, 2258, 2256,
+ 2256, 2267, 2269,
+ 2270, 2259, 2258,
+ 2258, 2269, 2270,
+ 2271, 2260, 2259,
+ 2259, 2270, 2271,
+ 2272, 2261, 2260,
+ 2260, 2271, 2272,
+ 2273, 2262, 2261,
+ 2261, 2272, 2273,
+ 2274, 2263, 2262,
+ 2262, 2273, 2274,
+ 2275, 2264, 2263,
+ 2263, 2274, 2275,
+ 2276, 2265, 2264,
+ 2264, 2275, 2276,
+ 2277, 2266, 2265,
+ 2265, 2276, 2277,
+ 2278, 2267, 2268,
+ 2268, 2279, 2278,
+ 2280, 2269, 2267,
+ 2267, 2278, 2280,
+ 2281, 2270, 2269,
+ 2269, 2280, 2281,
+ 2282, 2271, 2270,
+ 2270, 2281, 2282,
+ 2283, 2272, 2271,
+ 2271, 2282, 2283,
+ 2284, 2273, 2272,
+ 2272, 2283, 2284,
+ 2285, 2274, 2273,
+ 2273, 2284, 2285,
+ 2286, 2275, 2274,
+ 2274, 2285, 2286,
+ 2287, 2276, 2275,
+ 2275, 2286, 2287,
+ 2288, 2277, 2276,
+ 2276, 2287, 2288,
+ 2289, 2278, 2279,
+ 2279, 2193, 2289,
+ 2290, 2280, 2278,
+ 2278, 2289, 2290,
+ 2291, 2281, 2280,
+ 2280, 2290, 2291,
+ 2292, 2282, 2281,
+ 2281, 2291, 2292,
+ 2293, 2283, 2282,
+ 2282, 2292, 2293,
+ 2294, 2284, 2283,
+ 2283, 2293, 2294,
+ 2295, 2285, 2284,
+ 2284, 2294, 2295,
+ 2296, 2286, 2285,
+ 2285, 2295, 2296,
+ 2297, 2287, 2286,
+ 2286, 2296, 2297,
+ 2184, 2288, 2287,
+ 2287, 2297, 2184,
+ 2298, 2299, 2300,
+ 2298, 2300, 2301,
+ 2298, 2301, 2302,
+ 2298, 2302, 2303,
+ 2298, 2303, 2304,
+ 2298, 2304, 2305,
+ 2298, 2305, 2306,
+ 2298, 2306, 2307,
+ 2298, 2307, 2308,
+ 2298, 2308, 2309,
+ 2310, 2300, 2299,
+ 2299, 2311, 2310,
+ 2312, 2301, 2300,
+ 2300, 2310, 2312,
+ 2313, 2302, 2301,
+ 2301, 2312, 2313,
+ 2314, 2303, 2302,
+ 2302, 2313, 2314,
+ 2315, 2304, 2303,
+ 2303, 2314, 2315,
+ 2316, 2305, 2304,
+ 2304, 2315, 2316,
+ 2317, 2306, 2305,
+ 2305, 2316, 2317,
+ 2318, 2307, 2306,
+ 2306, 2317, 2318,
+ 2319, 2308, 2307,
+ 2307, 2318, 2319,
+ 2320, 2309, 2308,
+ 2308, 2319, 2320,
+ 2321, 2310, 2311,
+ 2311, 2322, 2321,
+ 2323, 2312, 2310,
+ 2310, 2321, 2323,
+ 2324, 2313, 2312,
+ 2312, 2323, 2324,
+ 2325, 2314, 2313,
+ 2313, 2324, 2325,
+ 2326, 2315, 2314,
+ 2314, 2325, 2326,
+ 2327, 2316, 2315,
+ 2315, 2326, 2327,
+ 2328, 2317, 2316,
+ 2316, 2327, 2328,
+ 2329, 2318, 2317,
+ 2317, 2328, 2329,
+ 2330, 2319, 2318,
+ 2318, 2329, 2330,
+ 2331, 2320, 2319,
+ 2319, 2330, 2331,
+ 2332, 2321, 2322,
+ 2322, 2333, 2332,
+ 2334, 2323, 2321,
+ 2321, 2332, 2334,
+ 2335, 2324, 2323,
+ 2323, 2334, 2335,
+ 2336, 2325, 2324,
+ 2324, 2335, 2336,
+ 2337, 2326, 2325,
+ 2325, 2336, 2337,
+ 2338, 2327, 2326,
+ 2326, 2337, 2338,
+ 2339, 2328, 2327,
+ 2327, 2338, 2339,
+ 2340, 2329, 2328,
+ 2328, 2339, 2340,
+ 2341, 2330, 2329,
+ 2329, 2340, 2341,
+ 2342, 2331, 2330,
+ 2330, 2341, 2342,
+ 2343, 2332, 2333,
+ 2333, 2344, 2343,
+ 2345, 2334, 2332,
+ 2332, 2343, 2345,
+ 2346, 2335, 2334,
+ 2334, 2345, 2346,
+ 2347, 2336, 2335,
+ 2335, 2346, 2347,
+ 2348, 2337, 2336,
+ 2336, 2347, 2348,
+ 2349, 2338, 2337,
+ 2337, 2348, 2349,
+ 2350, 2339, 2338,
+ 2338, 2349, 2350,
+ 2351, 2340, 2339,
+ 2339, 2350, 2351,
+ 2352, 2341, 2340,
+ 2340, 2351, 2352,
+ 2353, 2342, 2341,
+ 2341, 2352, 2353,
+ 2354, 2343, 2344,
+ 2344, 2355, 2354,
+ 2356, 2345, 2343,
+ 2343, 2354, 2356,
+ 2357, 2346, 2345,
+ 2345, 2356, 2357,
+ 2358, 2347, 2346,
+ 2346, 2357, 2358,
+ 2359, 2348, 2347,
+ 2347, 2358, 2359,
+ 2360, 2349, 2348,
+ 2348, 2359, 2360,
+ 2361, 2350, 2349,
+ 2349, 2360, 2361,
+ 2362, 2351, 2350,
+ 2350, 2361, 2362,
+ 2363, 2352, 2351,
+ 2351, 2362, 2363,
+ 2364, 2353, 2352,
+ 2352, 2363, 2364,
+ 2365, 2354, 2355,
+ 2355, 2366, 2365,
+ 2367, 2356, 2354,
+ 2354, 2365, 2367,
+ 2368, 2357, 2356,
+ 2356, 2367, 2368,
+ 2369, 2358, 2357,
+ 2357, 2368, 2369,
+ 2370, 2359, 2358,
+ 2358, 2369, 2370,
+ 2371, 2360, 2359,
+ 2359, 2370, 2371,
+ 2372, 2361, 2360,
+ 2360, 2371, 2372,
+ 2373, 2362, 2361,
+ 2361, 2372, 2373,
+ 2374, 2363, 2362,
+ 2362, 2373, 2374,
+ 2375, 2364, 2363,
+ 2363, 2374, 2375,
+ 2376, 2365, 2366,
+ 2366, 2377, 2376,
+ 2378, 2367, 2365,
+ 2365, 2376, 2378,
+ 2379, 2368, 2367,
+ 2367, 2378, 2379,
+ 2380, 2369, 2368,
+ 2368, 2379, 2380,
+ 2381, 2370, 2369,
+ 2369, 2380, 2381,
+ 2382, 2371, 2370,
+ 2370, 2381, 2382,
+ 2383, 2372, 2371,
+ 2371, 2382, 2383,
+ 2384, 2373, 2372,
+ 2372, 2383, 2384,
+ 2385, 2374, 2373,
+ 2373, 2384, 2385,
+ 2386, 2375, 2374,
+ 2374, 2385, 2386,
+ 2387, 2376, 2377,
+ 2377, 2388, 2387,
+ 2389, 2378, 2376,
+ 2376, 2387, 2389,
+ 2390, 2379, 2378,
+ 2378, 2389, 2390,
+ 2391, 2380, 2379,
+ 2379, 2390, 2391,
+ 2392, 2381, 2380,
+ 2380, 2391, 2392,
+ 2393, 2382, 2381,
+ 2381, 2392, 2393,
+ 2394, 2383, 2382,
+ 2382, 2393, 2394,
+ 2395, 2384, 2383,
+ 2383, 2394, 2395,
+ 2396, 2385, 2384,
+ 2384, 2395, 2396,
+ 2397, 2386, 2385,
+ 2385, 2396, 2397,
+ 2398, 2387, 2388,
+ 2388, 2399, 2398,
+ 2400, 2389, 2387,
+ 2387, 2398, 2400,
+ 2401, 2390, 2389,
+ 2389, 2400, 2401,
+ 2402, 2391, 2390,
+ 2390, 2401, 2402,
+ 2403, 2392, 2391,
+ 2391, 2402, 2403,
+ 2404, 2393, 2392,
+ 2392, 2403, 2404,
+ 2405, 2394, 2393,
+ 2393, 2404, 2405,
+ 2406, 2395, 2394,
+ 2394, 2405, 2406,
+ 2407, 2396, 2395,
+ 2395, 2406, 2407,
+ 2408, 2397, 2396,
+ 2396, 2407, 2408,
+ 2298, 2409, 2410,
+ 2298, 2410, 2411,
+ 2298, 2411, 2412,
+ 2298, 2412, 2413,
+ 2298, 2413, 2414,
+ 2298, 2414, 2415,
+ 2298, 2415, 2416,
+ 2298, 2416, 2417,
+ 2298, 2417, 2418,
+ 2298, 2418, 2419,
+ 2420, 2410, 2409,
+ 2409, 2421, 2420,
+ 2422, 2411, 2410,
+ 2410, 2420, 2422,
+ 2423, 2412, 2411,
+ 2411, 2422, 2423,
+ 2424, 2413, 2412,
+ 2412, 2423, 2424,
+ 2425, 2414, 2413,
+ 2413, 2424, 2425,
+ 2426, 2415, 2414,
+ 2414, 2425, 2426,
+ 2427, 2416, 2415,
+ 2415, 2426, 2427,
+ 2428, 2417, 2416,
+ 2416, 2427, 2428,
+ 2429, 2418, 2417,
+ 2417, 2428, 2429,
+ 2430, 2419, 2418,
+ 2418, 2429, 2430,
+ 2431, 2420, 2421,
+ 2421, 2432, 2431,
+ 2433, 2422, 2420,
+ 2420, 2431, 2433,
+ 2434, 2423, 2422,
+ 2422, 2433, 2434,
+ 2435, 2424, 2423,
+ 2423, 2434, 2435,
+ 2436, 2425, 2424,
+ 2424, 2435, 2436,
+ 2437, 2426, 2425,
+ 2425, 2436, 2437,
+ 2438, 2427, 2426,
+ 2426, 2437, 2438,
+ 2439, 2428, 2427,
+ 2427, 2438, 2439,
+ 2440, 2429, 2428,
+ 2428, 2439, 2440,
+ 2441, 2430, 2429,
+ 2429, 2440, 2441,
+ 2442, 2431, 2432,
+ 2432, 2443, 2442,
+ 2444, 2433, 2431,
+ 2431, 2442, 2444,
+ 2445, 2434, 2433,
+ 2433, 2444, 2445,
+ 2446, 2435, 2434,
+ 2434, 2445, 2446,
+ 2447, 2436, 2435,
+ 2435, 2446, 2447,
+ 2448, 2437, 2436,
+ 2436, 2447, 2448,
+ 2449, 2438, 2437,
+ 2437, 2448, 2449,
+ 2450, 2439, 2438,
+ 2438, 2449, 2450,
+ 2451, 2440, 2439,
+ 2439, 2450, 2451,
+ 2452, 2441, 2440,
+ 2440, 2451, 2452,
+ 2453, 2442, 2443,
+ 2443, 2454, 2453,
+ 2455, 2444, 2442,
+ 2442, 2453, 2455,
+ 2456, 2445, 2444,
+ 2444, 2455, 2456,
+ 2457, 2446, 2445,
+ 2445, 2456, 2457,
+ 2458, 2447, 2446,
+ 2446, 2457, 2458,
+ 2459, 2448, 2447,
+ 2447, 2458, 2459,
+ 2460, 2449, 2448,
+ 2448, 2459, 2460,
+ 2461, 2450, 2449,
+ 2449, 2460, 2461,
+ 2462, 2451, 2450,
+ 2450, 2461, 2462,
+ 2463, 2452, 2451,
+ 2451, 2462, 2463,
+ 2464, 2453, 2454,
+ 2454, 2465, 2464,
+ 2466, 2455, 2453,
+ 2453, 2464, 2466,
+ 2467, 2456, 2455,
+ 2455, 2466, 2467,
+ 2468, 2457, 2456,
+ 2456, 2467, 2468,
+ 2469, 2458, 2457,
+ 2457, 2468, 2469,
+ 2470, 2459, 2458,
+ 2458, 2469, 2470,
+ 2471, 2460, 2459,
+ 2459, 2470, 2471,
+ 2472, 2461, 2460,
+ 2460, 2471, 2472,
+ 2473, 2462, 2461,
+ 2461, 2472, 2473,
+ 2474, 2463, 2462,
+ 2462, 2473, 2474,
+ 2475, 2464, 2465,
+ 2465, 2476, 2475,
+ 2477, 2466, 2464,
+ 2464, 2475, 2477,
+ 2478, 2467, 2466,
+ 2466, 2477, 2478,
+ 2479, 2468, 2467,
+ 2467, 2478, 2479,
+ 2480, 2469, 2468,
+ 2468, 2479, 2480,
+ 2481, 2470, 2469,
+ 2469, 2480, 2481,
+ 2482, 2471, 2470,
+ 2470, 2481, 2482,
+ 2483, 2472, 2471,
+ 2471, 2482, 2483,
+ 2484, 2473, 2472,
+ 2472, 2483, 2484,
+ 2485, 2474, 2473,
+ 2473, 2484, 2485,
+ 2486, 2475, 2476,
+ 2476, 2487, 2486,
+ 2488, 2477, 2475,
+ 2475, 2486, 2488,
+ 2489, 2478, 2477,
+ 2477, 2488, 2489,
+ 2490, 2479, 2478,
+ 2478, 2489, 2490,
+ 2491, 2480, 2479,
+ 2479, 2490, 2491,
+ 2492, 2481, 2480,
+ 2480, 2491, 2492,
+ 2493, 2482, 2481,
+ 2481, 2492, 2493,
+ 2494, 2483, 2482,
+ 2482, 2493, 2494,
+ 2495, 2484, 2483,
+ 2483, 2494, 2495,
+ 2496, 2485, 2484,
+ 2484, 2495, 2496,
+ 2497, 2486, 2487,
+ 2487, 2498, 2497,
+ 2499, 2488, 2486,
+ 2486, 2497, 2499,
+ 2500, 2489, 2488,
+ 2488, 2499, 2500,
+ 2501, 2490, 2489,
+ 2489, 2500, 2501,
+ 2502, 2491, 2490,
+ 2490, 2501, 2502,
+ 2503, 2492, 2491,
+ 2491, 2502, 2503,
+ 2504, 2493, 2492,
+ 2492, 2503, 2504,
+ 2505, 2494, 2493,
+ 2493, 2504, 2505,
+ 2506, 2495, 2494,
+ 2494, 2505, 2506,
+ 2507, 2496, 2495,
+ 2495, 2506, 2507,
+ 2508, 2497, 2498,
+ 2498, 2509, 2508,
+ 2510, 2499, 2497,
+ 2497, 2508, 2510,
+ 2511, 2500, 2499,
+ 2499, 2510, 2511,
+ 2512, 2501, 2500,
+ 2500, 2511, 2512,
+ 2513, 2502, 2501,
+ 2501, 2512, 2513,
+ 2514, 2503, 2502,
+ 2502, 2513, 2514,
+ 2515, 2504, 2503,
+ 2503, 2514, 2515,
+ 2516, 2505, 2504,
+ 2504, 2515, 2516,
+ 2517, 2506, 2505,
+ 2505, 2516, 2517,
+ 2518, 2507, 2506,
+ 2506, 2517, 2518,
+ 2298, 2519, 2520,
+ 2298, 2520, 2521,
+ 2298, 2521, 2522,
+ 2298, 2522, 2523,
+ 2298, 2523, 2524,
+ 2298, 2524, 2525,
+ 2298, 2525, 2526,
+ 2298, 2526, 2527,
+ 2298, 2527, 2528,
+ 2298, 2528, 2529,
+ 2530, 2520, 2519,
+ 2519, 2531, 2530,
+ 2532, 2521, 2520,
+ 2520, 2530, 2532,
+ 2533, 2522, 2521,
+ 2521, 2532, 2533,
+ 2534, 2523, 2522,
+ 2522, 2533, 2534,
+ 2535, 2524, 2523,
+ 2523, 2534, 2535,
+ 2536, 2525, 2524,
+ 2524, 2535, 2536,
+ 2537, 2526, 2525,
+ 2525, 2536, 2537,
+ 2538, 2527, 2526,
+ 2526, 2537, 2538,
+ 2539, 2528, 2527,
+ 2527, 2538, 2539,
+ 2540, 2529, 2528,
+ 2528, 2539, 2540,
+ 2541, 2530, 2531,
+ 2531, 2542, 2541,
+ 2543, 2532, 2530,
+ 2530, 2541, 2543,
+ 2544, 2533, 2532,
+ 2532, 2543, 2544,
+ 2545, 2534, 2533,
+ 2533, 2544, 2545,
+ 2546, 2535, 2534,
+ 2534, 2545, 2546,
+ 2547, 2536, 2535,
+ 2535, 2546, 2547,
+ 2548, 2537, 2536,
+ 2536, 2547, 2548,
+ 2549, 2538, 2537,
+ 2537, 2548, 2549,
+ 2550, 2539, 2538,
+ 2538, 2549, 2550,
+ 2551, 2540, 2539,
+ 2539, 2550, 2551,
+ 2552, 2541, 2542,
+ 2542, 2553, 2552,
+ 2554, 2543, 2541,
+ 2541, 2552, 2554,
+ 2555, 2544, 2543,
+ 2543, 2554, 2555,
+ 2556, 2545, 2544,
+ 2544, 2555, 2556,
+ 2557, 2546, 2545,
+ 2545, 2556, 2557,
+ 2558, 2547, 2546,
+ 2546, 2557, 2558,
+ 2559, 2548, 2547,
+ 2547, 2558, 2559,
+ 2560, 2549, 2548,
+ 2548, 2559, 2560,
+ 2561, 2550, 2549,
+ 2549, 2560, 2561,
+ 2562, 2551, 2550,
+ 2550, 2561, 2562,
+ 2563, 2552, 2553,
+ 2553, 2564, 2563,
+ 2565, 2554, 2552,
+ 2552, 2563, 2565,
+ 2566, 2555, 2554,
+ 2554, 2565, 2566,
+ 2567, 2556, 2555,
+ 2555, 2566, 2567,
+ 2568, 2557, 2556,
+ 2556, 2567, 2568,
+ 2569, 2558, 2557,
+ 2557, 2568, 2569,
+ 2570, 2559, 2558,
+ 2558, 2569, 2570,
+ 2571, 2560, 2559,
+ 2559, 2570, 2571,
+ 2572, 2561, 2560,
+ 2560, 2571, 2572,
+ 2573, 2562, 2561,
+ 2561, 2572, 2573,
+ 2574, 2563, 2564,
+ 2564, 2575, 2574,
+ 2576, 2565, 2563,
+ 2563, 2574, 2576,
+ 2577, 2566, 2565,
+ 2565, 2576, 2577,
+ 2578, 2567, 2566,
+ 2566, 2577, 2578,
+ 2579, 2568, 2567,
+ 2567, 2578, 2579,
+ 2580, 2569, 2568,
+ 2568, 2579, 2580,
+ 2581, 2570, 2569,
+ 2569, 2580, 2581,
+ 2582, 2571, 2570,
+ 2570, 2581, 2582,
+ 2583, 2572, 2571,
+ 2571, 2582, 2583,
+ 2584, 2573, 2572,
+ 2572, 2583, 2584,
+ 2585, 2574, 2575,
+ 2575, 2586, 2585,
+ 2587, 2576, 2574,
+ 2574, 2585, 2587,
+ 2588, 2577, 2576,
+ 2576, 2587, 2588,
+ 2589, 2578, 2577,
+ 2577, 2588, 2589,
+ 2590, 2579, 2578,
+ 2578, 2589, 2590,
+ 2591, 2580, 2579,
+ 2579, 2590, 2591,
+ 2592, 2581, 2580,
+ 2580, 2591, 2592,
+ 2593, 2582, 2581,
+ 2581, 2592, 2593,
+ 2594, 2583, 2582,
+ 2582, 2593, 2594,
+ 2595, 2584, 2583,
+ 2583, 2594, 2595,
+ 2596, 2585, 2586,
+ 2586, 2597, 2596,
+ 2598, 2587, 2585,
+ 2585, 2596, 2598,
+ 2599, 2588, 2587,
+ 2587, 2598, 2599,
+ 2600, 2589, 2588,
+ 2588, 2599, 2600,
+ 2601, 2590, 2589,
+ 2589, 2600, 2601,
+ 2602, 2591, 2590,
+ 2590, 2601, 2602,
+ 2603, 2592, 2591,
+ 2591, 2602, 2603,
+ 2604, 2593, 2592,
+ 2592, 2603, 2604,
+ 2605, 2594, 2593,
+ 2593, 2604, 2605,
+ 2606, 2595, 2594,
+ 2594, 2605, 2606,
+ 2607, 2596, 2597,
+ 2597, 2608, 2607,
+ 2609, 2598, 2596,
+ 2596, 2607, 2609,
+ 2610, 2599, 2598,
+ 2598, 2609, 2610,
+ 2611, 2600, 2599,
+ 2599, 2610, 2611,
+ 2612, 2601, 2600,
+ 2600, 2611, 2612,
+ 2613, 2602, 2601,
+ 2601, 2612, 2613,
+ 2614, 2603, 2602,
+ 2602, 2613, 2614,
+ 2615, 2604, 2603,
+ 2603, 2614, 2615,
+ 2616, 2605, 2604,
+ 2604, 2615, 2616,
+ 2617, 2606, 2605,
+ 2605, 2616, 2617,
+ 2618, 2607, 2608,
+ 2608, 2619, 2618,
+ 2620, 2609, 2607,
+ 2607, 2618, 2620,
+ 2621, 2610, 2609,
+ 2609, 2620, 2621,
+ 2622, 2611, 2610,
+ 2610, 2621, 2622,
+ 2623, 2612, 2611,
+ 2611, 2622, 2623,
+ 2624, 2613, 2612,
+ 2612, 2623, 2624,
+ 2625, 2614, 2613,
+ 2613, 2624, 2625,
+ 2626, 2615, 2614,
+ 2614, 2625, 2626,
+ 2627, 2616, 2615,
+ 2615, 2626, 2627,
+ 2628, 2617, 2616,
+ 2616, 2627, 2628,
+ 2298, 2629, 2630,
+ 2298, 2630, 2631,
+ 2298, 2631, 2632,
+ 2298, 2632, 2633,
+ 2298, 2633, 2634,
+ 2298, 2634, 2635,
+ 2298, 2635, 2636,
+ 2298, 2636, 2637,
+ 2298, 2637, 2638,
+ 2298, 2638, 2639,
+ 2640, 2630, 2629,
+ 2629, 2641, 2640,
+ 2642, 2631, 2630,
+ 2630, 2640, 2642,
+ 2643, 2632, 2631,
+ 2631, 2642, 2643,
+ 2644, 2633, 2632,
+ 2632, 2643, 2644,
+ 2645, 2634, 2633,
+ 2633, 2644, 2645,
+ 2646, 2635, 2634,
+ 2634, 2645, 2646,
+ 2647, 2636, 2635,
+ 2635, 2646, 2647,
+ 2648, 2637, 2636,
+ 2636, 2647, 2648,
+ 2649, 2638, 2637,
+ 2637, 2648, 2649,
+ 2650, 2639, 2638,
+ 2638, 2649, 2650,
+ 2651, 2640, 2641,
+ 2641, 2652, 2651,
+ 2653, 2642, 2640,
+ 2640, 2651, 2653,
+ 2654, 2643, 2642,
+ 2642, 2653, 2654,
+ 2655, 2644, 2643,
+ 2643, 2654, 2655,
+ 2656, 2645, 2644,
+ 2644, 2655, 2656,
+ 2657, 2646, 2645,
+ 2645, 2656, 2657,
+ 2658, 2647, 2646,
+ 2646, 2657, 2658,
+ 2659, 2648, 2647,
+ 2647, 2658, 2659,
+ 2660, 2649, 2648,
+ 2648, 2659, 2660,
+ 2661, 2650, 2649,
+ 2649, 2660, 2661,
+ 2662, 2651, 2652,
+ 2652, 2663, 2662,
+ 2664, 2653, 2651,
+ 2651, 2662, 2664,
+ 2665, 2654, 2653,
+ 2653, 2664, 2665,
+ 2666, 2655, 2654,
+ 2654, 2665, 2666,
+ 2667, 2656, 2655,
+ 2655, 2666, 2667,
+ 2668, 2657, 2656,
+ 2656, 2667, 2668,
+ 2669, 2658, 2657,
+ 2657, 2668, 2669,
+ 2670, 2659, 2658,
+ 2658, 2669, 2670,
+ 2671, 2660, 2659,
+ 2659, 2670, 2671,
+ 2672, 2661, 2660,
+ 2660, 2671, 2672,
+ 2673, 2662, 2663,
+ 2663, 2674, 2673,
+ 2675, 2664, 2662,
+ 2662, 2673, 2675,
+ 2676, 2665, 2664,
+ 2664, 2675, 2676,
+ 2677, 2666, 2665,
+ 2665, 2676, 2677,
+ 2678, 2667, 2666,
+ 2666, 2677, 2678,
+ 2679, 2668, 2667,
+ 2667, 2678, 2679,
+ 2680, 2669, 2668,
+ 2668, 2679, 2680,
+ 2681, 2670, 2669,
+ 2669, 2680, 2681,
+ 2682, 2671, 2670,
+ 2670, 2681, 2682,
+ 2683, 2672, 2671,
+ 2671, 2682, 2683,
+ 2684, 2673, 2674,
+ 2674, 2685, 2684,
+ 2686, 2675, 2673,
+ 2673, 2684, 2686,
+ 2687, 2676, 2675,
+ 2675, 2686, 2687,
+ 2688, 2677, 2676,
+ 2676, 2687, 2688,
+ 2689, 2678, 2677,
+ 2677, 2688, 2689,
+ 2690, 2679, 2678,
+ 2678, 2689, 2690,
+ 2691, 2680, 2679,
+ 2679, 2690, 2691,
+ 2692, 2681, 2680,
+ 2680, 2691, 2692,
+ 2693, 2682, 2681,
+ 2681, 2692, 2693,
+ 2694, 2683, 2682,
+ 2682, 2693, 2694,
+ 2695, 2684, 2685,
+ 2685, 2696, 2695,
+ 2697, 2686, 2684,
+ 2684, 2695, 2697,
+ 2698, 2687, 2686,
+ 2686, 2697, 2698,
+ 2699, 2688, 2687,
+ 2687, 2698, 2699,
+ 2700, 2689, 2688,
+ 2688, 2699, 2700,
+ 2701, 2690, 2689,
+ 2689, 2700, 2701,
+ 2702, 2691, 2690,
+ 2690, 2701, 2702,
+ 2703, 2692, 2691,
+ 2691, 2702, 2703,
+ 2704, 2693, 2692,
+ 2692, 2703, 2704,
+ 2705, 2694, 2693,
+ 2693, 2704, 2705,
+ 2706, 2695, 2696,
+ 2696, 2707, 2706,
+ 2708, 2697, 2695,
+ 2695, 2706, 2708,
+ 2709, 2698, 2697,
+ 2697, 2708, 2709,
+ 2710, 2699, 2698,
+ 2698, 2709, 2710,
+ 2711, 2700, 2699,
+ 2699, 2710, 2711,
+ 2712, 2701, 2700,
+ 2700, 2711, 2712,
+ 2713, 2702, 2701,
+ 2701, 2712, 2713,
+ 2714, 2703, 2702,
+ 2702, 2713, 2714,
+ 2715, 2704, 2703,
+ 2703, 2714, 2715,
+ 2716, 2705, 2704,
+ 2704, 2715, 2716,
+ 2717, 2706, 2707,
+ 2707, 2718, 2717,
+ 2719, 2708, 2706,
+ 2706, 2717, 2719,
+ 2720, 2709, 2708,
+ 2708, 2719, 2720,
+ 2721, 2710, 2709,
+ 2709, 2720, 2721,
+ 2722, 2711, 2710,
+ 2710, 2721, 2722,
+ 2723, 2712, 2711,
+ 2711, 2722, 2723,
+ 2724, 2713, 2712,
+ 2712, 2723, 2724,
+ 2725, 2714, 2713,
+ 2713, 2724, 2725,
+ 2726, 2715, 2714,
+ 2714, 2725, 2726,
+ 2727, 2716, 2715,
+ 2715, 2726, 2727,
+ 2728, 2717, 2718,
+ 2718, 2729, 2728,
+ 2730, 2719, 2717,
+ 2717, 2728, 2730,
+ 2731, 2720, 2719,
+ 2719, 2730, 2731,
+ 2732, 2721, 2720,
+ 2720, 2731, 2732,
+ 2733, 2722, 2721,
+ 2721, 2732, 2733,
+ 2734, 2723, 2722,
+ 2722, 2733, 2734,
+ 2735, 2724, 2723,
+ 2723, 2734, 2735,
+ 2736, 2725, 2724,
+ 2724, 2735, 2736,
+ 2737, 2726, 2725,
+ 2725, 2736, 2737,
+ 2738, 2727, 2726,
+ 2726, 2737, 2738,
+ 2739, 2740, 2741,
+ 2741, 2742, 2739,
+ 2743, 2744, 2740,
+ 2740, 2739, 2743,
+ 2745, 2746, 2744,
+ 2744, 2743, 2745,
+ 2747, 2748, 2746,
+ 2746, 2745, 2747,
+ 2749, 2750, 2748,
+ 2748, 2747, 2749,
+ 2751, 2752, 2750,
+ 2750, 2749, 2751,
+ 2753, 2754, 2752,
+ 2752, 2751, 2753,
+ 2755, 2756, 2754,
+ 2754, 2753, 2755,
+ 2757, 2758, 2756,
+ 2756, 2755, 2757,
+ 2759, 2760, 2758,
+ 2758, 2757, 2759,
+ 2761, 2739, 2742,
+ 2742, 2762, 2761,
+ 2763, 2743, 2739,
+ 2739, 2761, 2763,
+ 2764, 2745, 2743,
+ 2743, 2763, 2764,
+ 2765, 2747, 2745,
+ 2745, 2764, 2765,
+ 2766, 2749, 2747,
+ 2747, 2765, 2766,
+ 2767, 2751, 2749,
+ 2749, 2766, 2767,
+ 2768, 2753, 2751,
+ 2751, 2767, 2768,
+ 2769, 2755, 2753,
+ 2753, 2768, 2769,
+ 2770, 2757, 2755,
+ 2755, 2769, 2770,
+ 2771, 2759, 2757,
+ 2757, 2770, 2771,
+ 2772, 2761, 2762,
+ 2762, 2773, 2772,
+ 2774, 2763, 2761,
+ 2761, 2772, 2774,
+ 2775, 2764, 2763,
+ 2763, 2774, 2775,
+ 2776, 2765, 2764,
+ 2764, 2775, 2776,
+ 2777, 2766, 2765,
+ 2765, 2776, 2777,
+ 2778, 2767, 2766,
+ 2766, 2777, 2778,
+ 2779, 2768, 2767,
+ 2767, 2778, 2779,
+ 2780, 2769, 2768,
+ 2768, 2779, 2780,
+ 2781, 2770, 2769,
+ 2769, 2780, 2781,
+ 2782, 2771, 2770,
+ 2770, 2781, 2782,
+ 2783, 2772, 2773,
+ 2773, 2784, 2783,
+ 2785, 2774, 2772,
+ 2772, 2783, 2785,
+ 2786, 2775, 2774,
+ 2774, 2785, 2786,
+ 2787, 2776, 2775,
+ 2775, 2786, 2787,
+ 2788, 2777, 2776,
+ 2776, 2787, 2788,
+ 2789, 2778, 2777,
+ 2777, 2788, 2789,
+ 2790, 2779, 2778,
+ 2778, 2789, 2790,
+ 2791, 2780, 2779,
+ 2779, 2790, 2791,
+ 2792, 2781, 2780,
+ 2780, 2791, 2792,
+ 2793, 2782, 2781,
+ 2781, 2792, 2793,
+ 2794, 2783, 2784,
+ 2784, 2795, 2794,
+ 2796, 2785, 2783,
+ 2783, 2794, 2796,
+ 2797, 2786, 2785,
+ 2785, 2796, 2797,
+ 2798, 2787, 2786,
+ 2786, 2797, 2798,
+ 2799, 2788, 2787,
+ 2787, 2798, 2799,
+ 2800, 2789, 2788,
+ 2788, 2799, 2800,
+ 2801, 2790, 2789,
+ 2789, 2800, 2801,
+ 2802, 2791, 2790,
+ 2790, 2801, 2802,
+ 2803, 2792, 2791,
+ 2791, 2802, 2803,
+ 2804, 2793, 2792,
+ 2792, 2803, 2804,
+ 2805, 2794, 2795,
+ 2795, 2806, 2805,
+ 2807, 2796, 2794,
+ 2794, 2805, 2807,
+ 2808, 2797, 2796,
+ 2796, 2807, 2808,
+ 2809, 2798, 2797,
+ 2797, 2808, 2809,
+ 2810, 2799, 2798,
+ 2798, 2809, 2810,
+ 2811, 2800, 2799,
+ 2799, 2810, 2811,
+ 2812, 2801, 2800,
+ 2800, 2811, 2812,
+ 2813, 2802, 2801,
+ 2801, 2812, 2813,
+ 2814, 2803, 2802,
+ 2802, 2813, 2814,
+ 2815, 2804, 2803,
+ 2803, 2814, 2815,
+ 2816, 2805, 2806,
+ 2806, 2817, 2816,
+ 2818, 2807, 2805,
+ 2805, 2816, 2818,
+ 2819, 2808, 2807,
+ 2807, 2818, 2819,
+ 2820, 2809, 2808,
+ 2808, 2819, 2820,
+ 2821, 2810, 2809,
+ 2809, 2820, 2821,
+ 2822, 2811, 2810,
+ 2810, 2821, 2822,
+ 2823, 2812, 2811,
+ 2811, 2822, 2823,
+ 2824, 2813, 2812,
+ 2812, 2823, 2824,
+ 2825, 2814, 2813,
+ 2813, 2824, 2825,
+ 2826, 2815, 2814,
+ 2814, 2825, 2826,
+ 2827, 2816, 2817,
+ 2817, 2828, 2827,
+ 2829, 2818, 2816,
+ 2816, 2827, 2829,
+ 2830, 2819, 2818,
+ 2818, 2829, 2830,
+ 2831, 2820, 2819,
+ 2819, 2830, 2831,
+ 2832, 2821, 2820,
+ 2820, 2831, 2832,
+ 2833, 2822, 2821,
+ 2821, 2832, 2833,
+ 2834, 2823, 2822,
+ 2822, 2833, 2834,
+ 2835, 2824, 2823,
+ 2823, 2834, 2835,
+ 2836, 2825, 2824,
+ 2824, 2835, 2836,
+ 2837, 2826, 2825,
+ 2825, 2836, 2837,
+ 2838, 2827, 2828,
+ 2828, 2839, 2838,
+ 2840, 2829, 2827,
+ 2827, 2838, 2840,
+ 2841, 2830, 2829,
+ 2829, 2840, 2841,
+ 2842, 2831, 2830,
+ 2830, 2841, 2842,
+ 2843, 2832, 2831,
+ 2831, 2842, 2843,
+ 2844, 2833, 2832,
+ 2832, 2843, 2844,
+ 2845, 2834, 2833,
+ 2833, 2844, 2845,
+ 2846, 2835, 2834,
+ 2834, 2845, 2846,
+ 2847, 2836, 2835,
+ 2835, 2846, 2847,
+ 2848, 2837, 2836,
+ 2836, 2847, 2848,
+ 2849, 2838, 2839,
+ 2839, 2850, 2849,
+ 2851, 2840, 2838,
+ 2838, 2849, 2851,
+ 2852, 2841, 2840,
+ 2840, 2851, 2852,
+ 2853, 2842, 2841,
+ 2841, 2852, 2853,
+ 2854, 2843, 2842,
+ 2842, 2853, 2854,
+ 2855, 2844, 2843,
+ 2843, 2854, 2855,
+ 2856, 2845, 2844,
+ 2844, 2855, 2856,
+ 2857, 2846, 2845,
+ 2845, 2856, 2857,
+ 2858, 2847, 2846,
+ 2846, 2857, 2858,
+ 2859, 2848, 2847,
+ 2847, 2858, 2859,
+ 2860, 2861, 2862,
+ 2862, 2759, 2860,
+ 2863, 2864, 2861,
+ 2861, 2860, 2863,
+ 2865, 2866, 2864,
+ 2864, 2863, 2865,
+ 2867, 2868, 2866,
+ 2866, 2865, 2867,
+ 2869, 2870, 2868,
+ 2868, 2867, 2869,
+ 2871, 2872, 2870,
+ 2870, 2869, 2871,
+ 2873, 2874, 2872,
+ 2872, 2871, 2873,
+ 2875, 2876, 2874,
+ 2874, 2873, 2875,
+ 2877, 2878, 2876,
+ 2876, 2875, 2877,
+ 2879, 2880, 2878,
+ 2878, 2877, 2879,
+ 2881, 2860, 2759,
+ 2759, 2882, 2881,
+ 2883, 2863, 2860,
+ 2860, 2881, 2883,
+ 2884, 2865, 2863,
+ 2863, 2883, 2884,
+ 2885, 2867, 2865,
+ 2865, 2884, 2885,
+ 2886, 2869, 2867,
+ 2867, 2885, 2886,
+ 2887, 2871, 2869,
+ 2869, 2886, 2887,
+ 2888, 2873, 2871,
+ 2871, 2887, 2888,
+ 2889, 2875, 2873,
+ 2873, 2888, 2889,
+ 2890, 2877, 2875,
+ 2875, 2889, 2890,
+ 2891, 2879, 2877,
+ 2877, 2890, 2891,
+ 2892, 2881, 2882,
+ 2882, 2893, 2892,
+ 2894, 2883, 2881,
+ 2881, 2892, 2894,
+ 2895, 2884, 2883,
+ 2883, 2894, 2895,
+ 2896, 2885, 2884,
+ 2884, 2895, 2896,
+ 2897, 2886, 2885,
+ 2885, 2896, 2897,
+ 2898, 2887, 2886,
+ 2886, 2897, 2898,
+ 2899, 2888, 2887,
+ 2887, 2898, 2899,
+ 2900, 2889, 2888,
+ 2888, 2899, 2900,
+ 2901, 2890, 2889,
+ 2889, 2900, 2901,
+ 2902, 2891, 2890,
+ 2890, 2901, 2902,
+ 2903, 2892, 2893,
+ 2893, 2904, 2903,
+ 2905, 2894, 2892,
+ 2892, 2903, 2905,
+ 2906, 2895, 2894,
+ 2894, 2905, 2906,
+ 2907, 2896, 2895,
+ 2895, 2906, 2907,
+ 2908, 2897, 2896,
+ 2896, 2907, 2908,
+ 2909, 2898, 2897,
+ 2897, 2908, 2909,
+ 2910, 2899, 2898,
+ 2898, 2909, 2910,
+ 2911, 2900, 2899,
+ 2899, 2910, 2911,
+ 2912, 2901, 2900,
+ 2900, 2911, 2912,
+ 2913, 2902, 2901,
+ 2901, 2912, 2913,
+ 2914, 2903, 2904,
+ 2904, 2915, 2914,
+ 2916, 2905, 2903,
+ 2903, 2914, 2916,
+ 2917, 2906, 2905,
+ 2905, 2916, 2917,
+ 2918, 2907, 2906,
+ 2906, 2917, 2918,
+ 2919, 2908, 2907,
+ 2907, 2918, 2919,
+ 2920, 2909, 2908,
+ 2908, 2919, 2920,
+ 2921, 2910, 2909,
+ 2909, 2920, 2921,
+ 2922, 2911, 2910,
+ 2910, 2921, 2922,
+ 2923, 2912, 2911,
+ 2911, 2922, 2923,
+ 2924, 2913, 2912,
+ 2912, 2923, 2924,
+ 2925, 2914, 2915,
+ 2915, 2926, 2925,
+ 2927, 2916, 2914,
+ 2914, 2925, 2927,
+ 2928, 2917, 2916,
+ 2916, 2927, 2928,
+ 2929, 2918, 2917,
+ 2917, 2928, 2929,
+ 2930, 2919, 2918,
+ 2918, 2929, 2930,
+ 2931, 2920, 2919,
+ 2919, 2930, 2931,
+ 2932, 2921, 2920,
+ 2920, 2931, 2932,
+ 2933, 2922, 2921,
+ 2921, 2932, 2933,
+ 2934, 2923, 2922,
+ 2922, 2933, 2934,
+ 2935, 2924, 2923,
+ 2923, 2934, 2935,
+ 2936, 2925, 2926,
+ 2926, 2937, 2936,
+ 2938, 2927, 2925,
+ 2925, 2936, 2938,
+ 2939, 2928, 2927,
+ 2927, 2938, 2939,
+ 2940, 2929, 2928,
+ 2928, 2939, 2940,
+ 2941, 2930, 2929,
+ 2929, 2940, 2941,
+ 2942, 2931, 2930,
+ 2930, 2941, 2942,
+ 2943, 2932, 2931,
+ 2931, 2942, 2943,
+ 2944, 2933, 2932,
+ 2932, 2943, 2944,
+ 2945, 2934, 2933,
+ 2933, 2944, 2945,
+ 2946, 2935, 2934,
+ 2934, 2945, 2946,
+ 2947, 2936, 2937,
+ 2937, 2948, 2947,
+ 2949, 2938, 2936,
+ 2936, 2947, 2949,
+ 2950, 2939, 2938,
+ 2938, 2949, 2950,
+ 2951, 2940, 2939,
+ 2939, 2950, 2951,
+ 2952, 2941, 2940,
+ 2940, 2951, 2952,
+ 2953, 2942, 2941,
+ 2941, 2952, 2953,
+ 2954, 2943, 2942,
+ 2942, 2953, 2954,
+ 2955, 2944, 2943,
+ 2943, 2954, 2955,
+ 2956, 2945, 2944,
+ 2944, 2955, 2956,
+ 2957, 2946, 2945,
+ 2945, 2956, 2957,
+ 2958, 2947, 2948,
+ 2948, 2959, 2958,
+ 2960, 2949, 2947,
+ 2947, 2958, 2960,
+ 2961, 2950, 2949,
+ 2949, 2960, 2961,
+ 2962, 2951, 2950,
+ 2950, 2961, 2962,
+ 2963, 2952, 2951,
+ 2951, 2962, 2963,
+ 2964, 2953, 2952,
+ 2952, 2963, 2964,
+ 2965, 2954, 2953,
+ 2953, 2964, 2965,
+ 2966, 2955, 2954,
+ 2954, 2965, 2966,
+ 2967, 2956, 2955,
+ 2955, 2966, 2967,
+ 2968, 2957, 2956,
+ 2956, 2967, 2968,
+ 2969, 2958, 2959,
+ 2959, 2970, 2969,
+ 2971, 2960, 2958,
+ 2958, 2969, 2971,
+ 2972, 2961, 2960,
+ 2960, 2971, 2972,
+ 2973, 2962, 2961,
+ 2961, 2972, 2973,
+ 2974, 2963, 2962,
+ 2962, 2973, 2974,
+ 2975, 2964, 2963,
+ 2963, 2974, 2975,
+ 2976, 2965, 2964,
+ 2964, 2975, 2976,
+ 2977, 2966, 2965,
+ 2965, 2976, 2977,
+ 2978, 2967, 2966,
+ 2966, 2977, 2978,
+ 2979, 2968, 2967,
+ 2967, 2978, 2979,
+ 2980, 2981, 2982,
+ 2982, 2879, 2980,
+ 2983, 2984, 2981,
+ 2981, 2980, 2983,
+ 2985, 2986, 2984,
+ 2984, 2983, 2985,
+ 2987, 2988, 2986,
+ 2986, 2985, 2987,
+ 2989, 2990, 2988,
+ 2988, 2987, 2989,
+ 2991, 2992, 2990,
+ 2990, 2989, 2991,
+ 2993, 2994, 2992,
+ 2992, 2991, 2993,
+ 2995, 2996, 2994,
+ 2994, 2993, 2995,
+ 2997, 2998, 2996,
+ 2996, 2995, 2997,
+ 2999, 3000, 2998,
+ 2998, 2997, 2999,
+ 3001, 2980, 2879,
+ 2879, 3002, 3001,
+ 3003, 2983, 2980,
+ 2980, 3001, 3003,
+ 3004, 2985, 2983,
+ 2983, 3003, 3004,
+ 3005, 2987, 2985,
+ 2985, 3004, 3005,
+ 3006, 2989, 2987,
+ 2987, 3005, 3006,
+ 3007, 2991, 2989,
+ 2989, 3006, 3007,
+ 3008, 2993, 2991,
+ 2991, 3007, 3008,
+ 3009, 2995, 2993,
+ 2993, 3008, 3009,
+ 3010, 2997, 2995,
+ 2995, 3009, 3010,
+ 3011, 2999, 2997,
+ 2997, 3010, 3011,
+ 3012, 3001, 3002,
+ 3002, 3013, 3012,
+ 3014, 3003, 3001,
+ 3001, 3012, 3014,
+ 3015, 3004, 3003,
+ 3003, 3014, 3015,
+ 3016, 3005, 3004,
+ 3004, 3015, 3016,
+ 3017, 3006, 3005,
+ 3005, 3016, 3017,
+ 3018, 3007, 3006,
+ 3006, 3017, 3018,
+ 3019, 3008, 3007,
+ 3007, 3018, 3019,
+ 3020, 3009, 3008,
+ 3008, 3019, 3020,
+ 3021, 3010, 3009,
+ 3009, 3020, 3021,
+ 3022, 3011, 3010,
+ 3010, 3021, 3022,
+ 3023, 3012, 3013,
+ 3013, 3024, 3023,
+ 3025, 3014, 3012,
+ 3012, 3023, 3025,
+ 3026, 3015, 3014,
+ 3014, 3025, 3026,
+ 3027, 3016, 3015,
+ 3015, 3026, 3027,
+ 3028, 3017, 3016,
+ 3016, 3027, 3028,
+ 3029, 3018, 3017,
+ 3017, 3028, 3029,
+ 3030, 3019, 3018,
+ 3018, 3029, 3030,
+ 3031, 3020, 3019,
+ 3019, 3030, 3031,
+ 3032, 3021, 3020,
+ 3020, 3031, 3032,
+ 3033, 3022, 3021,
+ 3021, 3032, 3033,
+ 3034, 3023, 3024,
+ 3024, 3035, 3034,
+ 3036, 3025, 3023,
+ 3023, 3034, 3036,
+ 3037, 3026, 3025,
+ 3025, 3036, 3037,
+ 3038, 3027, 3026,
+ 3026, 3037, 3038,
+ 3039, 3028, 3027,
+ 3027, 3038, 3039,
+ 3040, 3029, 3028,
+ 3028, 3039, 3040,
+ 3041, 3030, 3029,
+ 3029, 3040, 3041,
+ 3042, 3031, 3030,
+ 3030, 3041, 3042,
+ 3043, 3032, 3031,
+ 3031, 3042, 3043,
+ 3044, 3033, 3032,
+ 3032, 3043, 3044,
+ 3045, 3034, 3035,
+ 3035, 3046, 3045,
+ 3047, 3036, 3034,
+ 3034, 3045, 3047,
+ 3048, 3037, 3036,
+ 3036, 3047, 3048,
+ 3049, 3038, 3037,
+ 3037, 3048, 3049,
+ 3050, 3039, 3038,
+ 3038, 3049, 3050,
+ 3051, 3040, 3039,
+ 3039, 3050, 3051,
+ 3052, 3041, 3040,
+ 3040, 3051, 3052,
+ 3053, 3042, 3041,
+ 3041, 3052, 3053,
+ 3054, 3043, 3042,
+ 3042, 3053, 3054,
+ 3055, 3044, 3043,
+ 3043, 3054, 3055,
+ 3056, 3045, 3046,
+ 3046, 3057, 3056,
+ 3058, 3047, 3045,
+ 3045, 3056, 3058,
+ 3059, 3048, 3047,
+ 3047, 3058, 3059,
+ 3060, 3049, 3048,
+ 3048, 3059, 3060,
+ 3061, 3050, 3049,
+ 3049, 3060, 3061,
+ 3062, 3051, 3050,
+ 3050, 3061, 3062,
+ 3063, 3052, 3051,
+ 3051, 3062, 3063,
+ 3064, 3053, 3052,
+ 3052, 3063, 3064,
+ 3065, 3054, 3053,
+ 3053, 3064, 3065,
+ 3066, 3055, 3054,
+ 3054, 3065, 3066,
+ 3067, 3056, 3057,
+ 3057, 3068, 3067,
+ 3069, 3058, 3056,
+ 3056, 3067, 3069,
+ 3070, 3059, 3058,
+ 3058, 3069, 3070,
+ 3071, 3060, 3059,
+ 3059, 3070, 3071,
+ 3072, 3061, 3060,
+ 3060, 3071, 3072,
+ 3073, 3062, 3061,
+ 3061, 3072, 3073,
+ 3074, 3063, 3062,
+ 3062, 3073, 3074,
+ 3075, 3064, 3063,
+ 3063, 3074, 3075,
+ 3076, 3065, 3064,
+ 3064, 3075, 3076,
+ 3077, 3066, 3065,
+ 3065, 3076, 3077,
+ 3078, 3067, 3068,
+ 3068, 3079, 3078,
+ 3080, 3069, 3067,
+ 3067, 3078, 3080,
+ 3081, 3070, 3069,
+ 3069, 3080, 3081,
+ 3082, 3071, 3070,
+ 3070, 3081, 3082,
+ 3083, 3072, 3071,
+ 3071, 3082, 3083,
+ 3084, 3073, 3072,
+ 3072, 3083, 3084,
+ 3085, 3074, 3073,
+ 3073, 3084, 3085,
+ 3086, 3075, 3074,
+ 3074, 3085, 3086,
+ 3087, 3076, 3075,
+ 3075, 3086, 3087,
+ 3088, 3077, 3076,
+ 3076, 3087, 3088,
+ 3089, 3078, 3079,
+ 3079, 3090, 3089,
+ 3091, 3080, 3078,
+ 3078, 3089, 3091,
+ 3092, 3081, 3080,
+ 3080, 3091, 3092,
+ 3093, 3082, 3081,
+ 3081, 3092, 3093,
+ 3094, 3083, 3082,
+ 3082, 3093, 3094,
+ 3095, 3084, 3083,
+ 3083, 3094, 3095,
+ 3096, 3085, 3084,
+ 3084, 3095, 3096,
+ 3097, 3086, 3085,
+ 3085, 3096, 3097,
+ 3098, 3087, 3086,
+ 3086, 3097, 3098,
+ 3099, 3088, 3087,
+ 3087, 3098, 3099,
+ 3100, 3101, 3102,
+ 3102, 2999, 3100,
+ 3103, 3104, 3101,
+ 3101, 3100, 3103,
+ 3105, 3106, 3104,
+ 3104, 3103, 3105,
+ 3107, 3108, 3106,
+ 3106, 3105, 3107,
+ 3109, 3110, 3108,
+ 3108, 3107, 3109,
+ 3111, 3112, 3110,
+ 3110, 3109, 3111,
+ 3113, 3114, 3112,
+ 3112, 3111, 3113,
+ 3115, 3116, 3114,
+ 3114, 3113, 3115,
+ 3117, 3118, 3116,
+ 3116, 3115, 3117,
+ 2742, 3119, 3118,
+ 3118, 3117, 2742,
+ 3120, 3100, 2999,
+ 2999, 3121, 3120,
+ 3122, 3103, 3100,
+ 3100, 3120, 3122,
+ 3123, 3105, 3103,
+ 3103, 3122, 3123,
+ 3124, 3107, 3105,
+ 3105, 3123, 3124,
+ 3125, 3109, 3107,
+ 3107, 3124, 3125,
+ 3126, 3111, 3109,
+ 3109, 3125, 3126,
+ 3127, 3113, 3111,
+ 3111, 3126, 3127,
+ 3128, 3115, 3113,
+ 3113, 3127, 3128,
+ 3129, 3117, 3115,
+ 3115, 3128, 3129,
+ 3130, 2742, 3117,
+ 3117, 3129, 3130,
+ 3131, 3120, 3121,
+ 3121, 3132, 3131,
+ 3133, 3122, 3120,
+ 3120, 3131, 3133,
+ 3134, 3123, 3122,
+ 3122, 3133, 3134,
+ 3135, 3124, 3123,
+ 3123, 3134, 3135,
+ 3136, 3125, 3124,
+ 3124, 3135, 3136,
+ 3137, 3126, 3125,
+ 3125, 3136, 3137,
+ 3138, 3127, 3126,
+ 3126, 3137, 3138,
+ 3139, 3128, 3127,
+ 3127, 3138, 3139,
+ 3140, 3129, 3128,
+ 3128, 3139, 3140,
+ 3141, 3130, 3129,
+ 3129, 3140, 3141,
+ 3142, 3131, 3132,
+ 3132, 3143, 3142,
+ 3144, 3133, 3131,
+ 3131, 3142, 3144,
+ 3145, 3134, 3133,
+ 3133, 3144, 3145,
+ 3146, 3135, 3134,
+ 3134, 3145, 3146,
+ 3147, 3136, 3135,
+ 3135, 3146, 3147,
+ 3148, 3137, 3136,
+ 3136, 3147, 3148,
+ 3149, 3138, 3137,
+ 3137, 3148, 3149,
+ 3150, 3139, 3138,
+ 3138, 3149, 3150,
+ 3151, 3140, 3139,
+ 3139, 3150, 3151,
+ 3152, 3141, 3140,
+ 3140, 3151, 3152,
+ 3153, 3142, 3143,
+ 3143, 3154, 3153,
+ 3155, 3144, 3142,
+ 3142, 3153, 3155,
+ 3156, 3145, 3144,
+ 3144, 3155, 3156,
+ 3157, 3146, 3145,
+ 3145, 3156, 3157,
+ 3158, 3147, 3146,
+ 3146, 3157, 3158,
+ 3159, 3148, 3147,
+ 3147, 3158, 3159,
+ 3160, 3149, 3148,
+ 3148, 3159, 3160,
+ 3161, 3150, 3149,
+ 3149, 3160, 3161,
+ 3162, 3151, 3150,
+ 3150, 3161, 3162,
+ 3163, 3152, 3151,
+ 3151, 3162, 3163,
+ 3164, 3153, 3154,
+ 3154, 3165, 3164,
+ 3166, 3155, 3153,
+ 3153, 3164, 3166,
+ 3167, 3156, 3155,
+ 3155, 3166, 3167,
+ 3168, 3157, 3156,
+ 3156, 3167, 3168,
+ 3169, 3158, 3157,
+ 3157, 3168, 3169,
+ 3170, 3159, 3158,
+ 3158, 3169, 3170,
+ 3171, 3160, 3159,
+ 3159, 3170, 3171,
+ 3172, 3161, 3160,
+ 3160, 3171, 3172,
+ 3173, 3162, 3161,
+ 3161, 3172, 3173,
+ 3174, 3163, 3162,
+ 3162, 3173, 3174,
+ 3175, 3164, 3165,
+ 3165, 3176, 3175,
+ 3177, 3166, 3164,
+ 3164, 3175, 3177,
+ 3178, 3167, 3166,
+ 3166, 3177, 3178,
+ 3179, 3168, 3167,
+ 3167, 3178, 3179,
+ 3180, 3169, 3168,
+ 3168, 3179, 3180,
+ 3181, 3170, 3169,
+ 3169, 3180, 3181,
+ 3182, 3171, 3170,
+ 3170, 3181, 3182,
+ 3183, 3172, 3171,
+ 3171, 3182, 3183,
+ 3184, 3173, 3172,
+ 3172, 3183, 3184,
+ 3185, 3174, 3173,
+ 3173, 3184, 3185,
+ 3186, 3175, 3176,
+ 3176, 3187, 3186,
+ 3188, 3177, 3175,
+ 3175, 3186, 3188,
+ 3189, 3178, 3177,
+ 3177, 3188, 3189,
+ 3190, 3179, 3178,
+ 3178, 3189, 3190,
+ 3191, 3180, 3179,
+ 3179, 3190, 3191,
+ 3192, 3181, 3180,
+ 3180, 3191, 3192,
+ 3193, 3182, 3181,
+ 3181, 3192, 3193,
+ 3194, 3183, 3182,
+ 3182, 3193, 3194,
+ 3195, 3184, 3183,
+ 3183, 3194, 3195,
+ 3196, 3185, 3184,
+ 3184, 3195, 3196,
+ 3197, 3186, 3187,
+ 3187, 3198, 3197,
+ 3199, 3188, 3186,
+ 3186, 3197, 3199,
+ 3200, 3189, 3188,
+ 3188, 3199, 3200,
+ 3201, 3190, 3189,
+ 3189, 3200, 3201,
+ 3202, 3191, 3190,
+ 3190, 3201, 3202,
+ 3203, 3192, 3191,
+ 3191, 3202, 3203,
+ 3204, 3193, 3192,
+ 3192, 3203, 3204,
+ 3205, 3194, 3193,
+ 3193, 3204, 3205,
+ 3206, 3195, 3194,
+ 3194, 3205, 3206,
+ 3207, 3196, 3195,
+ 3195, 3206, 3207,
+ 3208, 3197, 3198,
+ 3198, 3209, 3208,
+ 3210, 3199, 3197,
+ 3197, 3208, 3210,
+ 3211, 3200, 3199,
+ 3199, 3210, 3211,
+ 3212, 3201, 3200,
+ 3200, 3211, 3212,
+ 3213, 3202, 3201,
+ 3201, 3212, 3213,
+ 3214, 3203, 3202,
+ 3202, 3213, 3214,
+ 3215, 3204, 3203,
+ 3203, 3214, 3215,
+ 3216, 3205, 3204,
+ 3204, 3215, 3216,
+ 3217, 3206, 3205,
+ 3205, 3216, 3217,
+ 3218, 3207, 3206,
+ 3206, 3217, 3218,
+ 3219, 3220, 3221,
+ 3219, 3221, 3222,
+ 3219, 3222, 3223,
+ 3219, 3223, 3224,
+ 3219, 3224, 3225,
+ 3219, 3225, 3226,
+ 3219, 3226, 3227,
+ 3219, 3227, 3228,
+ 3219, 3228, 3229,
+ 3219, 3229, 3230,
+ 3231, 3221, 3220,
+ 3220, 3232, 3231,
+ 3233, 3222, 3221,
+ 3221, 3231, 3233,
+ 3234, 3223, 3222,
+ 3222, 3233, 3234,
+ 3235, 3224, 3223,
+ 3223, 3234, 3235,
+ 3236, 3225, 3224,
+ 3224, 3235, 3236,
+ 3237, 3226, 3225,
+ 3225, 3236, 3237,
+ 3238, 3227, 3226,
+ 3226, 3237, 3238,
+ 3239, 3228, 3227,
+ 3227, 3238, 3239,
+ 3240, 3229, 3228,
+ 3228, 3239, 3240,
+ 3241, 3230, 3229,
+ 3229, 3240, 3241,
+ 3242, 3231, 3232,
+ 3232, 3243, 3242,
+ 3244, 3233, 3231,
+ 3231, 3242, 3244,
+ 3245, 3234, 3233,
+ 3233, 3244, 3245,
+ 3246, 3235, 3234,
+ 3234, 3245, 3246,
+ 3247, 3236, 3235,
+ 3235, 3246, 3247,
+ 3248, 3237, 3236,
+ 3236, 3247, 3248,
+ 3249, 3238, 3237,
+ 3237, 3248, 3249,
+ 3250, 3239, 3238,
+ 3238, 3249, 3250,
+ 3251, 3240, 3239,
+ 3239, 3250, 3251,
+ 3252, 3241, 3240,
+ 3240, 3251, 3252,
+ 3253, 3242, 3243,
+ 3243, 3254, 3253,
+ 3255, 3244, 3242,
+ 3242, 3253, 3255,
+ 3256, 3245, 3244,
+ 3244, 3255, 3256,
+ 3257, 3246, 3245,
+ 3245, 3256, 3257,
+ 3258, 3247, 3246,
+ 3246, 3257, 3258,
+ 3259, 3248, 3247,
+ 3247, 3258, 3259,
+ 3260, 3249, 3248,
+ 3248, 3259, 3260,
+ 3261, 3250, 3249,
+ 3249, 3260, 3261,
+ 3262, 3251, 3250,
+ 3250, 3261, 3262,
+ 3263, 3252, 3251,
+ 3251, 3262, 3263,
+ 3264, 3253, 3254,
+ 3254, 3265, 3264,
+ 3266, 3255, 3253,
+ 3253, 3264, 3266,
+ 3267, 3256, 3255,
+ 3255, 3266, 3267,
+ 3268, 3257, 3256,
+ 3256, 3267, 3268,
+ 3269, 3258, 3257,
+ 3257, 3268, 3269,
+ 3270, 3259, 3258,
+ 3258, 3269, 3270,
+ 3271, 3260, 3259,
+ 3259, 3270, 3271,
+ 3272, 3261, 3260,
+ 3260, 3271, 3272,
+ 3273, 3262, 3261,
+ 3261, 3272, 3273,
+ 3274, 3263, 3262,
+ 3262, 3273, 3274,
+ 3275, 3264, 3265,
+ 3265, 3276, 3275,
+ 3277, 3266, 3264,
+ 3264, 3275, 3277,
+ 3278, 3267, 3266,
+ 3266, 3277, 3278,
+ 3279, 3268, 3267,
+ 3267, 3278, 3279,
+ 3280, 3269, 3268,
+ 3268, 3279, 3280,
+ 3281, 3270, 3269,
+ 3269, 3280, 3281,
+ 3282, 3271, 3270,
+ 3270, 3281, 3282,
+ 3283, 3272, 3271,
+ 3271, 3282, 3283,
+ 3284, 3273, 3272,
+ 3272, 3283, 3284,
+ 3285, 3274, 3273,
+ 3273, 3284, 3285,
+ 3286, 3275, 3276,
+ 3276, 3287, 3286,
+ 3288, 3277, 3275,
+ 3275, 3286, 3288,
+ 3289, 3278, 3277,
+ 3277, 3288, 3289,
+ 3290, 3279, 3278,
+ 3278, 3289, 3290,
+ 3291, 3280, 3279,
+ 3279, 3290, 3291,
+ 3292, 3281, 3280,
+ 3280, 3291, 3292,
+ 3293, 3282, 3281,
+ 3281, 3292, 3293,
+ 3294, 3283, 3282,
+ 3282, 3293, 3294,
+ 3295, 3284, 3283,
+ 3283, 3294, 3295,
+ 3296, 3285, 3284,
+ 3284, 3295, 3296,
+ 3297, 3286, 3287,
+ 3287, 3298, 3297,
+ 3299, 3288, 3286,
+ 3286, 3297, 3299,
+ 3300, 3289, 3288,
+ 3288, 3299, 3300,
+ 3301, 3290, 3289,
+ 3289, 3300, 3301,
+ 3302, 3291, 3290,
+ 3290, 3301, 3302,
+ 3303, 3292, 3291,
+ 3291, 3302, 3303,
+ 3304, 3293, 3292,
+ 3292, 3303, 3304,
+ 3305, 3294, 3293,
+ 3293, 3304, 3305,
+ 3306, 3295, 3294,
+ 3294, 3305, 3306,
+ 3307, 3296, 3295,
+ 3295, 3306, 3307,
+ 3308, 3297, 3298,
+ 3298, 3309, 3308,
+ 3310, 3299, 3297,
+ 3297, 3308, 3310,
+ 3311, 3300, 3299,
+ 3299, 3310, 3311,
+ 3312, 3301, 3300,
+ 3300, 3311, 3312,
+ 3313, 3302, 3301,
+ 3301, 3312, 3313,
+ 3314, 3303, 3302,
+ 3302, 3313, 3314,
+ 3315, 3304, 3303,
+ 3303, 3314, 3315,
+ 3316, 3305, 3304,
+ 3304, 3315, 3316,
+ 3317, 3306, 3305,
+ 3305, 3316, 3317,
+ 3318, 3307, 3306,
+ 3306, 3317, 3318,
+ 3319, 3308, 3309,
+ 3309, 1391, 3319,
+ 3320, 3310, 3308,
+ 3308, 3319, 3320,
+ 3321, 3311, 3310,
+ 3310, 3320, 3321,
+ 3322, 3312, 3311,
+ 3311, 3321, 3322,
+ 1386, 3313, 3312,
+ 3312, 3322, 1386,
+ 3323, 3314, 3313,
+ 3313, 1386, 3323,
+ 3324, 3315, 3314,
+ 3314, 3323, 3324,
+ 3325, 3316, 3315,
+ 3315, 3324, 3325,
+ 3326, 3317, 3316,
+ 3316, 3325, 3326,
+ 1273, 3318, 3317,
+ 3317, 3326, 1273,
+ 3219, 3327, 3328,
+ 3219, 3328, 3329,
+ 3219, 3329, 3330,
+ 3219, 3330, 3331,
+ 3219, 3331, 3332,
+ 3219, 3332, 3333,
+ 3219, 3333, 3334,
+ 3219, 3334, 3335,
+ 3219, 3335, 3336,
+ 3219, 3336, 3337,
+ 3338, 3328, 3327,
+ 3327, 3241, 3338,
+ 3339, 3329, 3328,
+ 3328, 3338, 3339,
+ 3340, 3330, 3329,
+ 3329, 3339, 3340,
+ 3341, 3331, 3330,
+ 3330, 3340, 3341,
+ 3342, 3332, 3331,
+ 3331, 3341, 3342,
+ 3343, 3333, 3332,
+ 3332, 3342, 3343,
+ 3344, 3334, 3333,
+ 3333, 3343, 3344,
+ 3345, 3335, 3334,
+ 3334, 3344, 3345,
+ 3346, 3336, 3335,
+ 3335, 3345, 3346,
+ 3347, 3337, 3336,
+ 3336, 3346, 3347,
+ 3348, 3338, 3241,
+ 3241, 3349, 3348,
+ 3350, 3339, 3338,
+ 3338, 3348, 3350,
+ 3351, 3340, 3339,
+ 3339, 3350, 3351,
+ 3352, 3341, 3340,
+ 3340, 3351, 3352,
+ 3353, 3342, 3341,
+ 3341, 3352, 3353,
+ 3354, 3343, 3342,
+ 3342, 3353, 3354,
+ 3355, 3344, 3343,
+ 3343, 3354, 3355,
+ 3356, 3345, 3344,
+ 3344, 3355, 3356,
+ 3357, 3346, 3345,
+ 3345, 3356, 3357,
+ 3358, 3347, 3346,
+ 3346, 3357, 3358,
+ 3359, 3348, 3349,
+ 3349, 3360, 3359,
+ 3361, 3350, 3348,
+ 3348, 3359, 3361,
+ 3362, 3351, 3350,
+ 3350, 3361, 3362,
+ 3363, 3352, 3351,
+ 3351, 3362, 3363,
+ 3364, 3353, 3352,
+ 3352, 3363, 3364,
+ 3365, 3354, 3353,
+ 3353, 3364, 3365,
+ 3366, 3355, 3354,
+ 3354, 3365, 3366,
+ 3367, 3356, 3355,
+ 3355, 3366, 3367,
+ 3368, 3357, 3356,
+ 3356, 3367, 3368,
+ 3369, 3358, 3357,
+ 3357, 3368, 3369,
+ 3370, 3359, 3360,
+ 3360, 3371, 3370,
+ 3372, 3361, 3359,
+ 3359, 3370, 3372,
+ 3373, 3362, 3361,
+ 3361, 3372, 3373,
+ 3374, 3363, 3362,
+ 3362, 3373, 3374,
+ 3375, 3364, 3363,
+ 3363, 3374, 3375,
+ 3376, 3365, 3364,
+ 3364, 3375, 3376,
+ 3377, 3366, 3365,
+ 3365, 3376, 3377,
+ 3378, 3367, 3366,
+ 3366, 3377, 3378,
+ 3379, 3368, 3367,
+ 3367, 3378, 3379,
+ 3380, 3369, 3368,
+ 3368, 3379, 3380,
+ 3381, 3370, 3371,
+ 3371, 3382, 3381,
+ 3383, 3372, 3370,
+ 3370, 3381, 3383,
+ 3384, 3373, 3372,
+ 3372, 3383, 3384,
+ 3385, 3374, 3373,
+ 3373, 3384, 3385,
+ 3386, 3375, 3374,
+ 3374, 3385, 3386,
+ 3387, 3376, 3375,
+ 3375, 3386, 3387,
+ 3388, 3377, 3376,
+ 3376, 3387, 3388,
+ 3389, 3378, 3377,
+ 3377, 3388, 3389,
+ 3390, 3379, 3378,
+ 3378, 3389, 3390,
+ 3391, 3380, 3379,
+ 3379, 3390, 3391,
+ 3392, 3381, 3382,
+ 3382, 3393, 3392,
+ 3394, 3383, 3381,
+ 3381, 3392, 3394,
+ 3395, 3384, 3383,
+ 3383, 3394, 3395,
+ 3396, 3385, 3384,
+ 3384, 3395, 3396,
+ 3397, 3386, 3385,
+ 3385, 3396, 3397,
+ 3398, 3387, 3386,
+ 3386, 3397, 3398,
+ 3399, 3388, 3387,
+ 3387, 3398, 3399,
+ 3400, 3389, 3388,
+ 3388, 3399, 3400,
+ 3401, 3390, 3389,
+ 3389, 3400, 3401,
+ 3402, 3391, 3390,
+ 3390, 3401, 3402,
+ 3403, 3392, 3393,
+ 3393, 3404, 3403,
+ 3405, 3394, 3392,
+ 3392, 3403, 3405,
+ 3406, 3395, 3394,
+ 3394, 3405, 3406,
+ 3407, 3396, 3395,
+ 3395, 3406, 3407,
+ 3408, 3397, 3396,
+ 3396, 3407, 3408,
+ 3409, 3398, 3397,
+ 3397, 3408, 3409,
+ 3410, 3399, 3398,
+ 3398, 3409, 3410,
+ 3411, 3400, 3399,
+ 3399, 3410, 3411,
+ 3412, 3401, 3400,
+ 3400, 3411, 3412,
+ 3413, 3402, 3401,
+ 3401, 3412, 3413,
+ 3414, 3403, 3404,
+ 3404, 3415, 3414,
+ 3416, 3405, 3403,
+ 3403, 3414, 3416,
+ 3417, 3406, 3405,
+ 3405, 3416, 3417,
+ 3418, 3407, 3406,
+ 3406, 3417, 3418,
+ 3419, 3408, 3407,
+ 3407, 3418, 3419,
+ 3420, 3409, 3408,
+ 3408, 3419, 3420,
+ 3421, 3410, 3409,
+ 3409, 3420, 3421,
+ 3422, 3411, 3410,
+ 3410, 3421, 3422,
+ 3423, 3412, 3411,
+ 3411, 3422, 3423,
+ 3424, 3413, 3412,
+ 3412, 3423, 3424,
+ 3425, 3414, 3415,
+ 3415, 1273, 3425,
+ 3426, 3416, 3414,
+ 3414, 3425, 3426,
+ 3427, 3417, 3416,
+ 3416, 3426, 3427,
+ 3428, 3418, 3417,
+ 3417, 3427, 3428,
+ 1268, 3419, 3418,
+ 3418, 3428, 1268,
+ 3429, 3420, 3419,
+ 3419, 1268, 3429,
+ 3430, 3421, 3420,
+ 3420, 3429, 3430,
+ 3431, 3422, 3421,
+ 3421, 3430, 3431,
+ 3432, 3423, 3422,
+ 3422, 3431, 3432,
+ 1155, 3424, 3423,
+ 3423, 3432, 1155,
+ 3219, 3433, 3434,
+ 3219, 3434, 3435,
+ 3219, 3435, 3436,
+ 3219, 3436, 3437,
+ 3219, 3437, 3438,
+ 3219, 3438, 3439,
+ 3219, 3439, 3440,
+ 3219, 3440, 3441,
+ 3219, 3441, 3442,
+ 3219, 3442, 3443,
+ 3444, 3434, 3433,
+ 3433, 3347, 3444,
+ 3445, 3435, 3434,
+ 3434, 3444, 3445,
+ 3446, 3436, 3435,
+ 3435, 3445, 3446,
+ 3447, 3437, 3436,
+ 3436, 3446, 3447,
+ 3448, 3438, 3437,
+ 3437, 3447, 3448,
+ 3449, 3439, 3438,
+ 3438, 3448, 3449,
+ 3450, 3440, 3439,
+ 3439, 3449, 3450,
+ 3451, 3441, 3440,
+ 3440, 3450, 3451,
+ 3452, 3442, 3441,
+ 3441, 3451, 3452,
+ 3453, 3443, 3442,
+ 3442, 3452, 3453,
+ 3454, 3444, 3347,
+ 3347, 3455, 3454,
+ 3456, 3445, 3444,
+ 3444, 3454, 3456,
+ 3457, 3446, 3445,
+ 3445, 3456, 3457,
+ 3458, 3447, 3446,
+ 3446, 3457, 3458,
+ 3459, 3448, 3447,
+ 3447, 3458, 3459,
+ 3460, 3449, 3448,
+ 3448, 3459, 3460,
+ 3461, 3450, 3449,
+ 3449, 3460, 3461,
+ 3462, 3451, 3450,
+ 3450, 3461, 3462,
+ 3463, 3452, 3451,
+ 3451, 3462, 3463,
+ 3464, 3453, 3452,
+ 3452, 3463, 3464,
+ 3465, 3454, 3455,
+ 3455, 3466, 3465,
+ 3467, 3456, 3454,
+ 3454, 3465, 3467,
+ 3468, 3457, 3456,
+ 3456, 3467, 3468,
+ 3469, 3458, 3457,
+ 3457, 3468, 3469,
+ 3470, 3459, 3458,
+ 3458, 3469, 3470,
+ 3471, 3460, 3459,
+ 3459, 3470, 3471,
+ 3472, 3461, 3460,
+ 3460, 3471, 3472,
+ 3473, 3462, 3461,
+ 3461, 3472, 3473,
+ 3474, 3463, 3462,
+ 3462, 3473, 3474,
+ 3475, 3464, 3463,
+ 3463, 3474, 3475,
+ 3476, 3465, 3466,
+ 3466, 3477, 3476,
+ 3478, 3467, 3465,
+ 3465, 3476, 3478,
+ 3479, 3468, 3467,
+ 3467, 3478, 3479,
+ 3480, 3469, 3468,
+ 3468, 3479, 3480,
+ 3481, 3470, 3469,
+ 3469, 3480, 3481,
+ 3482, 3471, 3470,
+ 3470, 3481, 3482,
+ 3483, 3472, 3471,
+ 3471, 3482, 3483,
+ 3484, 3473, 3472,
+ 3472, 3483, 3484,
+ 3485, 3474, 3473,
+ 3473, 3484, 3485,
+ 3486, 3475, 3474,
+ 3474, 3485, 3486,
+ 3487, 3476, 3477,
+ 3477, 3488, 3487,
+ 3489, 3478, 3476,
+ 3476, 3487, 3489,
+ 3490, 3479, 3478,
+ 3478, 3489, 3490,
+ 3491, 3480, 3479,
+ 3479, 3490, 3491,
+ 3492, 3481, 3480,
+ 3480, 3491, 3492,
+ 3493, 3482, 3481,
+ 3481, 3492, 3493,
+ 3494, 3483, 3482,
+ 3482, 3493, 3494,
+ 3495, 3484, 3483,
+ 3483, 3494, 3495,
+ 3496, 3485, 3484,
+ 3484, 3495, 3496,
+ 3497, 3486, 3485,
+ 3485, 3496, 3497,
+ 3498, 3487, 3488,
+ 3488, 3499, 3498,
+ 3500, 3489, 3487,
+ 3487, 3498, 3500,
+ 3501, 3490, 3489,
+ 3489, 3500, 3501,
+ 3502, 3491, 3490,
+ 3490, 3501, 3502,
+ 3503, 3492, 3491,
+ 3491, 3502, 3503,
+ 3504, 3493, 3492,
+ 3492, 3503, 3504,
+ 3505, 3494, 3493,
+ 3493, 3504, 3505,
+ 3506, 3495, 3494,
+ 3494, 3505, 3506,
+ 3507, 3496, 3495,
+ 3495, 3506, 3507,
+ 3508, 3497, 3496,
+ 3496, 3507, 3508,
+ 3509, 3498, 3499,
+ 3499, 3510, 3509,
+ 3511, 3500, 3498,
+ 3498, 3509, 3511,
+ 3512, 3501, 3500,
+ 3500, 3511, 3512,
+ 3513, 3502, 3501,
+ 3501, 3512, 3513,
+ 3514, 3503, 3502,
+ 3502, 3513, 3514,
+ 3515, 3504, 3503,
+ 3503, 3514, 3515,
+ 3516, 3505, 3504,
+ 3504, 3515, 3516,
+ 3517, 3506, 3505,
+ 3505, 3516, 3517,
+ 3518, 3507, 3506,
+ 3506, 3517, 3518,
+ 3519, 3508, 3507,
+ 3507, 3518, 3519,
+ 3520, 3509, 3510,
+ 3510, 3521, 3520,
+ 3522, 3511, 3509,
+ 3509, 3520, 3522,
+ 3523, 3512, 3511,
+ 3511, 3522, 3523,
+ 3524, 3513, 3512,
+ 3512, 3523, 3524,
+ 3525, 3514, 3513,
+ 3513, 3524, 3525,
+ 3526, 3515, 3514,
+ 3514, 3525, 3526,
+ 3527, 3516, 3515,
+ 3515, 3526, 3527,
+ 3528, 3517, 3516,
+ 3516, 3527, 3528,
+ 3529, 3518, 3517,
+ 3517, 3528, 3529,
+ 3530, 3519, 3518,
+ 3518, 3529, 3530,
+ 3531, 3520, 3521,
+ 3521, 1155, 3531,
+ 3532, 3522, 3520,
+ 3520, 3531, 3532,
+ 3533, 3523, 3522,
+ 3522, 3532, 3533,
+ 3534, 3524, 3523,
+ 3523, 3533, 3534,
+ 1150, 3525, 3524,
+ 3524, 3534, 1150,
+ 3535, 3526, 3525,
+ 3525, 1150, 3535,
+ 3536, 3527, 3526,
+ 3526, 3535, 3536,
+ 3537, 3528, 3527,
+ 3527, 3536, 3537,
+ 3538, 3529, 3528,
+ 3528, 3537, 3538,
+ 1037, 3530, 3529,
+ 3529, 3538, 1037,
+ 3219, 3539, 3540,
+ 3219, 3540, 3541,
+ 3219, 3541, 3542,
+ 3219, 3542, 3543,
+ 3219, 3543, 3544,
+ 3219, 3544, 3545,
+ 3219, 3545, 3546,
+ 3219, 3546, 3547,
+ 3219, 3547, 3548,
+ 3219, 3548, 3549,
+ 3550, 3540, 3539,
+ 3539, 3453, 3550,
+ 3551, 3541, 3540,
+ 3540, 3550, 3551,
+ 3552, 3542, 3541,
+ 3541, 3551, 3552,
+ 3553, 3543, 3542,
+ 3542, 3552, 3553,
+ 3554, 3544, 3543,
+ 3543, 3553, 3554,
+ 3555, 3545, 3544,
+ 3544, 3554, 3555,
+ 3556, 3546, 3545,
+ 3545, 3555, 3556,
+ 3557, 3547, 3546,
+ 3546, 3556, 3557,
+ 3558, 3548, 3547,
+ 3547, 3557, 3558,
+ 3232, 3549, 3548,
+ 3548, 3558, 3232,
+ 3559, 3550, 3453,
+ 3453, 3560, 3559,
+ 3561, 3551, 3550,
+ 3550, 3559, 3561,
+ 3562, 3552, 3551,
+ 3551, 3561, 3562,
+ 3563, 3553, 3552,
+ 3552, 3562, 3563,
+ 3564, 3554, 3553,
+ 3553, 3563, 3564,
+ 3565, 3555, 3554,
+ 3554, 3564, 3565,
+ 3566, 3556, 3555,
+ 3555, 3565, 3566,
+ 3567, 3557, 3556,
+ 3556, 3566, 3567,
+ 3568, 3558, 3557,
+ 3557, 3567, 3568,
+ 3569, 3232, 3558,
+ 3558, 3568, 3569,
+ 3570, 3559, 3560,
+ 3560, 3571, 3570,
+ 3572, 3561, 3559,
+ 3559, 3570, 3572,
+ 3573, 3562, 3561,
+ 3561, 3572, 3573,
+ 3574, 3563, 3562,
+ 3562, 3573, 3574,
+ 3575, 3564, 3563,
+ 3563, 3574, 3575,
+ 3576, 3565, 3564,
+ 3564, 3575, 3576,
+ 3577, 3566, 3565,
+ 3565, 3576, 3577,
+ 3578, 3567, 3566,
+ 3566, 3577, 3578,
+ 3579, 3568, 3567,
+ 3567, 3578, 3579,
+ 3580, 3569, 3568,
+ 3568, 3579, 3580,
+ 3581, 3570, 3571,
+ 3571, 3582, 3581,
+ 3583, 3572, 3570,
+ 3570, 3581, 3583,
+ 3584, 3573, 3572,
+ 3572, 3583, 3584,
+ 3585, 3574, 3573,
+ 3573, 3584, 3585,
+ 3586, 3575, 3574,
+ 3574, 3585, 3586,
+ 3587, 3576, 3575,
+ 3575, 3586, 3587,
+ 3588, 3577, 3576,
+ 3576, 3587, 3588,
+ 3589, 3578, 3577,
+ 3577, 3588, 3589,
+ 3590, 3579, 3578,
+ 3578, 3589, 3590,
+ 3591, 3580, 3579,
+ 3579, 3590, 3591,
+ 3592, 3581, 3582,
+ 3582, 3593, 3592,
+ 3594, 3583, 3581,
+ 3581, 3592, 3594,
+ 3595, 3584, 3583,
+ 3583, 3594, 3595,
+ 3596, 3585, 3584,
+ 3584, 3595, 3596,
+ 3597, 3586, 3585,
+ 3585, 3596, 3597,
+ 3598, 3587, 3586,
+ 3586, 3597, 3598,
+ 3599, 3588, 3587,
+ 3587, 3598, 3599,
+ 3600, 3589, 3588,
+ 3588, 3599, 3600,
+ 3601, 3590, 3589,
+ 3589, 3600, 3601,
+ 3602, 3591, 3590,
+ 3590, 3601, 3602,
+ 3603, 3592, 3593,
+ 3593, 3604, 3603,
+ 3605, 3594, 3592,
+ 3592, 3603, 3605,
+ 3606, 3595, 3594,
+ 3594, 3605, 3606,
+ 3607, 3596, 3595,
+ 3595, 3606, 3607,
+ 3608, 3597, 3596,
+ 3596, 3607, 3608,
+ 3609, 3598, 3597,
+ 3597, 3608, 3609,
+ 3610, 3599, 3598,
+ 3598, 3609, 3610,
+ 3611, 3600, 3599,
+ 3599, 3610, 3611,
+ 3612, 3601, 3600,
+ 3600, 3611, 3612,
+ 3613, 3602, 3601,
+ 3601, 3612, 3613,
+ 3614, 3603, 3604,
+ 3604, 3615, 3614,
+ 3616, 3605, 3603,
+ 3603, 3614, 3616,
+ 3617, 3606, 3605,
+ 3605, 3616, 3617,
+ 3618, 3607, 3606,
+ 3606, 3617, 3618,
+ 3619, 3608, 3607,
+ 3607, 3618, 3619,
+ 3620, 3609, 3608,
+ 3608, 3619, 3620,
+ 3621, 3610, 3609,
+ 3609, 3620, 3621,
+ 3622, 3611, 3610,
+ 3610, 3621, 3622,
+ 3623, 3612, 3611,
+ 3611, 3622, 3623,
+ 3624, 3613, 3612,
+ 3612, 3623, 3624,
+ 3625, 3614, 3615,
+ 3615, 3626, 3625,
+ 3627, 3616, 3614,
+ 3614, 3625, 3627,
+ 3628, 3617, 3616,
+ 3616, 3627, 3628,
+ 3629, 3618, 3617,
+ 3617, 3628, 3629,
+ 3630, 3619, 3618,
+ 3618, 3629, 3630,
+ 3631, 3620, 3619,
+ 3619, 3630, 3631,
+ 3632, 3621, 3620,
+ 3620, 3631, 3632,
+ 3633, 3622, 3621,
+ 3621, 3632, 3633,
+ 3634, 3623, 3622,
+ 3622, 3633, 3634,
+ 3635, 3624, 3623,
+ 3623, 3634, 3635,
+ 3636, 3625, 3626,
+ 3626, 1037, 3636,
+ 3637, 3627, 3625,
+ 3625, 3636, 3637,
+ 3638, 3628, 3627,
+ 3627, 3637, 3638,
+ 3639, 3629, 3628,
+ 3628, 3638, 3639,
+ 1032, 3630, 3629,
+ 3629, 3639, 1032,
+ 3640, 3631, 3630,
+ 3630, 1032, 3640,
+ 3641, 3632, 3631,
+ 3631, 3640, 3641,
+ 3642, 3633, 3632,
+ 3632, 3641, 3642,
+ 3643, 3634, 3633,
+ 3633, 3642, 3643,
+ 1391, 3635, 3634,
+ 3634, 3643, 1391,
+};
+
+#endif // TEAPOT_H
diff --git a/Rend/demos/teapot/shaders/basic.slang b/Rend/demos/teapot/shaders/basic.slang
new file mode 100644
index 0000000..cfbf48a
--- /dev/null
+++ b/Rend/demos/teapot/shaders/basic.slang
@@ -0,0 +1,36 @@
+struct VSInput {
+ [[vk::location(0)]] float3 inPosition : POSITION;
+ [[vk::location(1)]] float2 uv : TEXCOORD0;
+};
+
+struct VSOutput {
+ float4 pos : SV_Position;
+ float3 color;
+ float2 uv;
+};
+
+struct PushConstants {
+ float4x4 ubo;
+};
+
+[[vk::binding(0, 0)]] ConstantBuffer<float4x4> ubos[3];
+[[vk::binding(1, 0)]] Sampler2D test[3];
+
+[[vk::push_constant]]
+PushConstants pc;
+
+[shader("vertex")]
+VSOutput vertMain(VSInput input) {
+ VSOutput output;
+
+ output.pos = mul(pc.ubo, float4(input.inPosition, 1.0));
+ output.color = input.inPosition;
+ output.uv = input.uv;
+ return output;
+}
+
+[shader("fragment")]
+float4 fragMain(VSOutput vertIn) : SV_TARGET {
+ float4 col = test[0].Sample(vertIn.uv);
+ return float4(col.rgb, 1.0);
+}
diff --git a/Rend/demos/teapot/shaders/texture.slang b/Rend/demos/teapot/shaders/texture.slang
new file mode 100644
index 0000000..0210b66
--- /dev/null
+++ b/Rend/demos/teapot/shaders/texture.slang
@@ -0,0 +1,28 @@
+struct VSInput {
+ [[vk::location(0)]] float3 pos : POSITION;
+ [[vk::location(1)]] float2 uv : TEXCOORD0;
+ [[vk::location(2)]] float2 offset;
+};
+
+struct VSOutput {
+ float4 pos : SV_Position;
+ float2 uv;
+};
+
+[[vk::binding(0, 0)]] ConstantBuffer<float4x4> ubos[3];
+[[vk::binding(1, 0)]] Sampler2D test[3];
+
+[shader("vertex")]
+VSOutput vertMain(VSInput input) {
+ VSOutput output;
+ output.pos = float4(input.pos, 1.0);
+ output.pos.x -= input.offset.x;
+ output.pos.y -= input.offset.y;
+ output.uv = input.uv;
+ return output;
+}
+
+[shader("fragment")]
+float4 fragMain(VSOutput vertIn) : SV_TARGET {
+ return test[0].Sample(vertIn.uv);
+}
diff --git a/Rend/demos/teapot/stb_image.h b/Rend/demos/teapot/stb_image.h
new file mode 100644
index 0000000..9eedabe
--- /dev/null
+++ b/Rend/demos/teapot/stb_image.h
@@ -0,0 +1,7988 @@
+/* stb_image - v2.30 - public domain image loader - http://nothings.org/stb
+ no warranty implied; use at your own risk
+
+ Do this:
+ #define STB_IMAGE_IMPLEMENTATION
+ before you include this file in *one* C or C++ file to create the implementation.
+
+ // i.e. it should look like this:
+ #include ...
+ #include ...
+ #include ...
+ #define STB_IMAGE_IMPLEMENTATION
+ #include "stb_image.h"
+
+ You can #define STBI_ASSERT(x) before the #include to avoid using assert.h.
+ And #define STBI_MALLOC, STBI_REALLOC, and STBI_FREE to avoid using malloc,realloc,free
+
+
+ QUICK NOTES:
+ Primarily of interest to game developers and other people who can
+ avoid problematic images and only need the trivial interface
+
+ JPEG baseline & progressive (12 bpc/arithmetic not supported, same as stock IJG lib)
+ PNG 1/2/4/8/16-bit-per-channel
+
+ TGA (not sure what subset, if a subset)
+ BMP non-1bpp, non-RLE
+ PSD (composited view only, no extra channels, 8/16 bit-per-channel)
+
+ GIF (*comp always reports as 4-channel)
+ HDR (radiance rgbE format)
+ PIC (Softimage PIC)
+ PNM (PPM and PGM binary only)
+
+ Animated GIF still needs a proper API, but here's one way to do it:
+ http://gist.github.com/urraka/685d9a6340b26b830d49
+
+ - decode from memory or through FILE (define STBI_NO_STDIO to remove code)
+ - decode from arbitrary I/O callbacks
+ - SIMD acceleration on x86/x64 (SSE2) and ARM (NEON)
+
+ Full documentation under "DOCUMENTATION" below.
+
+
+LICENSE
+
+ See end of file for license information.
+
+RECENT REVISION HISTORY:
+
+ 2.30 (2024-05-31) avoid erroneous gcc warning
+ 2.29 (2023-05-xx) optimizations
+ 2.28 (2023-01-29) many error fixes, security errors, just tons of stuff
+ 2.27 (2021-07-11) document stbi_info better, 16-bit PNM support, bug fixes
+ 2.26 (2020-07-13) many minor fixes
+ 2.25 (2020-02-02) fix warnings
+ 2.24 (2020-02-02) fix warnings; thread-local failure_reason and flip_vertically
+ 2.23 (2019-08-11) fix clang static analysis warning
+ 2.22 (2019-03-04) gif fixes, fix warnings
+ 2.21 (2019-02-25) fix typo in comment
+ 2.20 (2019-02-07) support utf8 filenames in Windows; fix warnings and platform ifdefs
+ 2.19 (2018-02-11) fix warning
+ 2.18 (2018-01-30) fix warnings
+ 2.17 (2018-01-29) bugfix, 1-bit BMP, 16-bitness query, fix warnings
+ 2.16 (2017-07-23) all functions have 16-bit variants; optimizations; bugfixes
+ 2.15 (2017-03-18) fix png-1,2,4; all Imagenet JPGs; no runtime SSE detection on GCC
+ 2.14 (2017-03-03) remove deprecated STBI_JPEG_OLD; fixes for Imagenet JPGs
+ 2.13 (2016-12-04) experimental 16-bit API, only for PNG so far; fixes
+ 2.12 (2016-04-02) fix typo in 2.11 PSD fix that caused crashes
+ 2.11 (2016-04-02) 16-bit PNGS; enable SSE2 in non-gcc x64
+ RGB-format JPEG; remove white matting in PSD;
+ allocate large structures on the stack;
+ correct channel count for PNG & BMP
+ 2.10 (2016-01-22) avoid warning introduced in 2.09
+ 2.09 (2016-01-16) 16-bit TGA; comments in PNM files; STBI_REALLOC_SIZED
+
+ See end of file for full revision history.
+
+
+ ============================ Contributors =========================
+
+ Image formats Extensions, features
+ Sean Barrett (jpeg, png, bmp) Jetro Lauha (stbi_info)
+ Nicolas Schulz (hdr, psd) Martin "SpartanJ" Golini (stbi_info)
+ Jonathan Dummer (tga) James "moose2000" Brown (iPhone PNG)
+ Jean-Marc Lienher (gif) Ben "Disch" Wenger (io callbacks)
+ Tom Seddon (pic) Omar Cornut (1/2/4-bit PNG)
+ Thatcher Ulrich (psd) Nicolas Guillemot (vertical flip)
+ Ken Miller (pgm, ppm) Richard Mitton (16-bit PSD)
+ github:urraka (animated gif) Junggon Kim (PNM comments)
+ Christopher Forseth (animated gif) Daniel Gibson (16-bit TGA)
+ socks-the-fox (16-bit PNG)
+ Jeremy Sawicki (handle all ImageNet JPGs)
+ Optimizations & bugfixes Mikhail Morozov (1-bit BMP)
+ Fabian "ryg" Giesen Anael Seghezzi (is-16-bit query)
+ Arseny Kapoulkine Simon Breuss (16-bit PNM)
+ John-Mark Allen
+ Carmelo J Fdez-Aguera
+
+ Bug & warning fixes
+ Marc LeBlanc David Woo Guillaume George Martins Mozeiko
+ Christpher Lloyd Jerry Jansson Joseph Thomson Blazej Dariusz Roszkowski
+ Phil Jordan Dave Moore Roy Eltham
+ Hayaki Saito Nathan Reed Won Chun
+ Luke Graham Johan Duparc Nick Verigakis the Horde3D community
+ Thomas Ruf Ronny Chevalier github:rlyeh
+ Janez Zemva John Bartholomew Michal Cichon github:romigrou
+ Jonathan Blow Ken Hamada Tero Hanninen github:svdijk
+ Eugene Golushkov Laurent Gomila Cort Stratton github:snagar
+ Aruelien Pocheville Sergio Gonzalez Thibault Reuille github:Zelex
+ Cass Everitt Ryamond Barbiero github:grim210
+ Paul Du Bois Engin Manap Aldo Culquicondor github:sammyhw
+ Philipp Wiesemann Dale Weiler Oriol Ferrer Mesia github:phprus
+ Josh Tobin Neil Bickford Matthew Gregan github:poppolopoppo
+ Julian Raschke Gregory Mullen Christian Floisand github:darealshinji
+ Baldur Karlsson Kevin Schmidt JR Smith github:Michaelangel007
+ Brad Weinberger Matvey Cherevko github:mosra
+ Luca Sas Alexander Veselov Zack Middleton [reserved]
+ Ryan C. Gordon [reserved] [reserved]
+ DO NOT ADD YOUR NAME HERE
+
+ Jacko Dirks
+
+ To add your name to the credits, pick a random blank space in the middle and fill it.
+ 80% of merge conflicts on stb PRs are due to people adding their name at the end
+ of the credits.
+*/
+
+#ifndef STBI_INCLUDE_STB_IMAGE_H
+#define STBI_INCLUDE_STB_IMAGE_H
+
+// DOCUMENTATION
+//
+// Limitations:
+// - no 12-bit-per-channel JPEG
+// - no JPEGs with arithmetic coding
+// - GIF always returns *comp=4
+//
+// Basic usage (see HDR discussion below for HDR usage):
+// int x,y,n;
+// unsigned char *data = stbi_load(filename, &x, &y, &n, 0);
+// // ... process data if not NULL ...
+// // ... x = width, y = height, n = # 8-bit components per pixel ...
+// // ... replace '0' with '1'..'4' to force that many components per pixel
+// // ... but 'n' will always be the number that it would have been if you said 0
+// stbi_image_free(data);
+//
+// Standard parameters:
+// int *x -- outputs image width in pixels
+// int *y -- outputs image height in pixels
+// int *channels_in_file -- outputs # of image components in image file
+// int desired_channels -- if non-zero, # of image components requested in result
+//
+// The return value from an image loader is an 'unsigned char *' which points
+// to the pixel data, or NULL on an allocation failure or if the image is
+// corrupt or invalid. The pixel data consists of *y scanlines of *x pixels,
+// with each pixel consisting of N interleaved 8-bit components; the first
+// pixel pointed to is top-left-most in the image. There is no padding between
+// image scanlines or between pixels, regardless of format. The number of
+// components N is 'desired_channels' if desired_channels is non-zero, or
+// *channels_in_file otherwise. If desired_channels is non-zero,
+// *channels_in_file has the number of components that _would_ have been
+// output otherwise. E.g. if you set desired_channels to 4, you will always
+// get RGBA output, but you can check *channels_in_file to see if it's trivially
+// opaque because e.g. there were only 3 channels in the source image.
+//
+// An output image with N components has the following components interleaved
+// in this order in each pixel:
+//
+// N=#comp components
+// 1 grey
+// 2 grey, alpha
+// 3 red, green, blue
+// 4 red, green, blue, alpha
+//
+// If image loading fails for any reason, the return value will be NULL,
+// and *x, *y, *channels_in_file will be unchanged. The function
+// stbi_failure_reason() can be queried for an extremely brief, end-user
+// unfriendly explanation of why the load failed. Define STBI_NO_FAILURE_STRINGS
+// to avoid compiling these strings at all, and STBI_FAILURE_USERMSG to get slightly
+// more user-friendly ones.
+//
+// Paletted PNG, BMP, GIF, and PIC images are automatically depalettized.
+//
+// To query the width, height and component count of an image without having to
+// decode the full file, you can use the stbi_info family of functions:
+//
+// int x,y,n,ok;
+// ok = stbi_info(filename, &x, &y, &n);
+// // returns ok=1 and sets x, y, n if image is a supported format,
+// // 0 otherwise.
+//
+// Note that stb_image pervasively uses ints in its public API for sizes,
+// including sizes of memory buffers. This is now part of the API and thus
+// hard to change without causing breakage. As a result, the various image
+// loaders all have certain limits on image size; these differ somewhat
+// by format but generally boil down to either just under 2GB or just under
+// 1GB. When the decoded image would be larger than this, stb_image decoding
+// will fail.
+//
+// Additionally, stb_image will reject image files that have any of their
+// dimensions set to a larger value than the configurable STBI_MAX_DIMENSIONS,
+// which defaults to 2**24 = 16777216 pixels. Due to the above memory limit,
+// the only way to have an image with such dimensions load correctly
+// is for it to have a rather extreme aspect ratio. Either way, the
+// assumption here is that such larger images are likely to be malformed
+// or malicious. If you do need to load an image with individual dimensions
+// larger than that, and it still fits in the overall size limit, you can
+// #define STBI_MAX_DIMENSIONS on your own to be something larger.
+//
+// ===========================================================================
+//
+// UNICODE:
+//
+// If compiling for Windows and you wish to use Unicode filenames, compile
+// with
+// #define STBI_WINDOWS_UTF8
+// and pass utf8-encoded filenames. Call stbi_convert_wchar_to_utf8 to convert
+// Windows wchar_t filenames to utf8.
+//
+// ===========================================================================
+//
+// Philosophy
+//
+// stb libraries are designed with the following priorities:
+//
+// 1. easy to use
+// 2. easy to maintain
+// 3. good performance
+//
+// Sometimes I let "good performance" creep up in priority over "easy to maintain",
+// and for best performance I may provide less-easy-to-use APIs that give higher
+// performance, in addition to the easy-to-use ones. Nevertheless, it's important
+// to keep in mind that from the standpoint of you, a client of this library,
+// all you care about is #1 and #3, and stb libraries DO NOT emphasize #3 above all.
+//
+// Some secondary priorities arise directly from the first two, some of which
+// provide more explicit reasons why performance can't be emphasized.
+//
+// - Portable ("ease of use")
+// - Small source code footprint ("easy to maintain")
+// - No dependencies ("ease of use")
+//
+// ===========================================================================
+//
+// I/O callbacks
+//
+// I/O callbacks allow you to read from arbitrary sources, like packaged
+// files or some other source. Data read from callbacks are processed
+// through a small internal buffer (currently 128 bytes) to try to reduce
+// overhead.
+//
+// The three functions you must define are "read" (reads some bytes of data),
+// "skip" (skips some bytes of data), "eof" (reports if the stream is at the end).
+//
+// ===========================================================================
+//
+// SIMD support
+//
+// The JPEG decoder will try to automatically use SIMD kernels on x86 when
+// supported by the compiler. For ARM Neon support, you must explicitly
+// request it.
+//
+// (The old do-it-yourself SIMD API is no longer supported in the current
+// code.)
+//
+// On x86, SSE2 will automatically be used when available based on a run-time
+// test; if not, the generic C versions are used as a fall-back. On ARM targets,
+// the typical path is to have separate builds for NEON and non-NEON devices
+// (at least this is true for iOS and Android). Therefore, the NEON support is
+// toggled by a build flag: define STBI_NEON to get NEON loops.
+//
+// If for some reason you do not want to use any of SIMD code, or if
+// you have issues compiling it, you can disable it entirely by
+// defining STBI_NO_SIMD.
+//
+// ===========================================================================
+//
+// HDR image support (disable by defining STBI_NO_HDR)
+//
+// stb_image supports loading HDR images in general, and currently the Radiance
+// .HDR file format specifically. You can still load any file through the existing
+// interface; if you attempt to load an HDR file, it will be automatically remapped
+// to LDR, assuming gamma 2.2 and an arbitrary scale factor defaulting to 1;
+// both of these constants can be reconfigured through this interface:
+//
+// stbi_hdr_to_ldr_gamma(2.2f);
+// stbi_hdr_to_ldr_scale(1.0f);
+//
+// (note, do not use _inverse_ constants; stbi_image will invert them
+// appropriately).
+//
+// Additionally, there is a new, parallel interface for loading files as
+// (linear) floats to preserve the full dynamic range:
+//
+// float *data = stbi_loadf(filename, &x, &y, &n, 0);
+//
+// If you load LDR images through this interface, those images will
+// be promoted to floating point values, run through the inverse of
+// constants corresponding to the above:
+//
+// stbi_ldr_to_hdr_scale(1.0f);
+// stbi_ldr_to_hdr_gamma(2.2f);
+//
+// Finally, given a filename (or an open file or memory block--see header
+// file for details) containing image data, you can query for the "most
+// appropriate" interface to use (that is, whether the image is HDR or
+// not), using:
+//
+// stbi_is_hdr(char *filename);
+//
+// ===========================================================================
+//
+// iPhone PNG support:
+//
+// We optionally support converting iPhone-formatted PNGs (which store
+// premultiplied BGRA) back to RGB, even though they're internally encoded
+// differently. To enable this conversion, call
+// stbi_convert_iphone_png_to_rgb(1).
+//
+// Call stbi_set_unpremultiply_on_load(1) as well to force a divide per
+// pixel to remove any premultiplied alpha *only* if the image file explicitly
+// says there's premultiplied data (currently only happens in iPhone images,
+// and only if iPhone convert-to-rgb processing is on).
+//
+// ===========================================================================
+//
+// ADDITIONAL CONFIGURATION
+//
+// - You can suppress implementation of any of the decoders to reduce
+// your code footprint by #defining one or more of the following
+// symbols before creating the implementation.
+//
+// STBI_NO_JPEG
+// STBI_NO_PNG
+// STBI_NO_BMP
+// STBI_NO_PSD
+// STBI_NO_TGA
+// STBI_NO_GIF
+// STBI_NO_HDR
+// STBI_NO_PIC
+// STBI_NO_PNM (.ppm and .pgm)
+//
+// - You can request *only* certain decoders and suppress all other ones
+// (this will be more forward-compatible, as addition of new decoders
+// doesn't require you to disable them explicitly):
+//
+// STBI_ONLY_JPEG
+// STBI_ONLY_PNG
+// STBI_ONLY_BMP
+// STBI_ONLY_PSD
+// STBI_ONLY_TGA
+// STBI_ONLY_GIF
+// STBI_ONLY_HDR
+// STBI_ONLY_PIC
+// STBI_ONLY_PNM (.ppm and .pgm)
+//
+// - If you use STBI_NO_PNG (or _ONLY_ without PNG), and you still
+// want the zlib decoder to be available, #define STBI_SUPPORT_ZLIB
+//
+// - If you define STBI_MAX_DIMENSIONS, stb_image will reject images greater
+// than that size (in either width or height) without further processing.
+// This is to let programs in the wild set an upper bound to prevent
+// denial-of-service attacks on untrusted data, as one could generate a
+// valid image of gigantic dimensions and force stb_image to allocate a
+// huge block of memory and spend disproportionate time decoding it. By
+// default this is set to (1 << 24), which is 16777216, but that's still
+// very big.
+
+#ifndef STBI_NO_STDIO
+#include <stdio.h>
+#endif // STBI_NO_STDIO
+
+#define STBI_VERSION 1
+
+enum
+{
+ STBI_default = 0, // only used for desired_channels
+
+ STBI_grey = 1,
+ STBI_grey_alpha = 2,
+ STBI_rgb = 3,
+ STBI_rgb_alpha = 4
+};
+
+#include <stdlib.h>
+typedef unsigned char stbi_uc;
+typedef unsigned short stbi_us;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef STBIDEF
+#ifdef STB_IMAGE_STATIC
+#define STBIDEF static
+#else
+#define STBIDEF extern
+#endif
+#endif
+
+//////////////////////////////////////////////////////////////////////////////
+//
+// PRIMARY API - works on images of any type
+//
+
+//
+// load image by filename, open file, or memory buffer
+//
+
+typedef struct
+{
+ int (*read) (void *user,char *data,int size); // fill 'data' with 'size' bytes. return number of bytes actually read
+ void (*skip) (void *user,int n); // skip the next 'n' bytes, or 'unget' the last -n bytes if negative
+ int (*eof) (void *user); // returns nonzero if we are at end of file/data
+} stbi_io_callbacks;
+
+////////////////////////////////////
+//
+// 8-bits-per-channel interface
+//
+
+STBIDEF stbi_uc *stbi_load_from_memory (stbi_uc const *buffer, int len , int *x, int *y, int *channels_in_file, int desired_channels);
+STBIDEF stbi_uc *stbi_load_from_callbacks(stbi_io_callbacks const *clbk , void *user, int *x, int *y, int *channels_in_file, int desired_channels);
+
+#ifndef STBI_NO_STDIO
+STBIDEF stbi_uc *stbi_load (char const *filename, int *x, int *y, int *channels_in_file, int desired_channels);
+STBIDEF stbi_uc *stbi_load_from_file (FILE *f, int *x, int *y, int *channels_in_file, int desired_channels);
+// for stbi_load_from_file, file pointer is left pointing immediately after image
+#endif
+
+#ifndef STBI_NO_GIF
+STBIDEF stbi_uc *stbi_load_gif_from_memory(stbi_uc const *buffer, int len, int **delays, int *x, int *y, int *z, int *comp, int req_comp);
+#endif
+
+#ifdef STBI_WINDOWS_UTF8
+STBIDEF int stbi_convert_wchar_to_utf8(char *buffer, size_t bufferlen, const wchar_t* input);
+#endif
+
+////////////////////////////////////
+//
+// 16-bits-per-channel interface
+//
+
+STBIDEF stbi_us *stbi_load_16_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *channels_in_file, int desired_channels);
+STBIDEF stbi_us *stbi_load_16_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *channels_in_file, int desired_channels);
+
+#ifndef STBI_NO_STDIO
+STBIDEF stbi_us *stbi_load_16 (char const *filename, int *x, int *y, int *channels_in_file, int desired_channels);
+STBIDEF stbi_us *stbi_load_from_file_16(FILE *f, int *x, int *y, int *channels_in_file, int desired_channels);
+#endif
+
+////////////////////////////////////
+//
+// float-per-channel interface
+//
+#ifndef STBI_NO_LINEAR
+ STBIDEF float *stbi_loadf_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *channels_in_file, int desired_channels);
+ STBIDEF float *stbi_loadf_from_callbacks (stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *channels_in_file, int desired_channels);
+
+ #ifndef STBI_NO_STDIO
+ STBIDEF float *stbi_loadf (char const *filename, int *x, int *y, int *channels_in_file, int desired_channels);
+ STBIDEF float *stbi_loadf_from_file (FILE *f, int *x, int *y, int *channels_in_file, int desired_channels);
+ #endif
+#endif
+
+#ifndef STBI_NO_HDR
+ STBIDEF void stbi_hdr_to_ldr_gamma(float gamma);
+ STBIDEF void stbi_hdr_to_ldr_scale(float scale);
+#endif // STBI_NO_HDR
+
+#ifndef STBI_NO_LINEAR
+ STBIDEF void stbi_ldr_to_hdr_gamma(float gamma);
+ STBIDEF void stbi_ldr_to_hdr_scale(float scale);
+#endif // STBI_NO_LINEAR
+
+// stbi_is_hdr is always defined, but always returns false if STBI_NO_HDR
+STBIDEF int stbi_is_hdr_from_callbacks(stbi_io_callbacks const *clbk, void *user);
+STBIDEF int stbi_is_hdr_from_memory(stbi_uc const *buffer, int len);
+#ifndef STBI_NO_STDIO
+STBIDEF int stbi_is_hdr (char const *filename);
+STBIDEF int stbi_is_hdr_from_file(FILE *f);
+#endif // STBI_NO_STDIO
+
+
+// get a VERY brief reason for failure
+// on most compilers (and ALL modern mainstream compilers) this is threadsafe
+STBIDEF const char *stbi_failure_reason (void);
+
+// free the loaded image -- this is just free()
+STBIDEF void stbi_image_free (void *retval_from_stbi_load);
+
+// get image dimensions & components without fully decoding
+STBIDEF int stbi_info_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp);
+STBIDEF int stbi_info_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp);
+STBIDEF int stbi_is_16_bit_from_memory(stbi_uc const *buffer, int len);
+STBIDEF int stbi_is_16_bit_from_callbacks(stbi_io_callbacks const *clbk, void *user);
+
+#ifndef STBI_NO_STDIO
+STBIDEF int stbi_info (char const *filename, int *x, int *y, int *comp);
+STBIDEF int stbi_info_from_file (FILE *f, int *x, int *y, int *comp);
+STBIDEF int stbi_is_16_bit (char const *filename);
+STBIDEF int stbi_is_16_bit_from_file(FILE *f);
+#endif
+
+
+
+// for image formats that explicitly notate that they have premultiplied alpha,
+// we just return the colors as stored in the file. set this flag to force
+// unpremultiplication. results are undefined if the unpremultiply overflow.
+STBIDEF void stbi_set_unpremultiply_on_load(int flag_true_if_should_unpremultiply);
+
+// indicate whether we should process iphone images back to canonical format,
+// or just pass them through "as-is"
+STBIDEF void stbi_convert_iphone_png_to_rgb(int flag_true_if_should_convert);
+
+// flip the image vertically, so the first pixel in the output array is the bottom left
+STBIDEF void stbi_set_flip_vertically_on_load(int flag_true_if_should_flip);
+
+// as above, but only applies to images loaded on the thread that calls the function
+// this function is only available if your compiler supports thread-local variables;
+// calling it will fail to link if your compiler doesn't
+STBIDEF void stbi_set_unpremultiply_on_load_thread(int flag_true_if_should_unpremultiply);
+STBIDEF void stbi_convert_iphone_png_to_rgb_thread(int flag_true_if_should_convert);
+STBIDEF void stbi_set_flip_vertically_on_load_thread(int flag_true_if_should_flip);
+
+// ZLIB client - used by PNG, available for other purposes
+
+STBIDEF char *stbi_zlib_decode_malloc_guesssize(const char *buffer, int len, int initial_size, int *outlen);
+STBIDEF char *stbi_zlib_decode_malloc_guesssize_headerflag(const char *buffer, int len, int initial_size, int *outlen, int parse_header);
+STBIDEF char *stbi_zlib_decode_malloc(const char *buffer, int len, int *outlen);
+STBIDEF int stbi_zlib_decode_buffer(char *obuffer, int olen, const char *ibuffer, int ilen);
+
+STBIDEF char *stbi_zlib_decode_noheader_malloc(const char *buffer, int len, int *outlen);
+STBIDEF int stbi_zlib_decode_noheader_buffer(char *obuffer, int olen, const char *ibuffer, int ilen);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+//
+//
+//// end header file /////////////////////////////////////////////////////
+#endif // STBI_INCLUDE_STB_IMAGE_H
+
+#ifdef STB_IMAGE_IMPLEMENTATION
+
+#if defined(STBI_ONLY_JPEG) || defined(STBI_ONLY_PNG) || defined(STBI_ONLY_BMP) \
+ || defined(STBI_ONLY_TGA) || defined(STBI_ONLY_GIF) || defined(STBI_ONLY_PSD) \
+ || defined(STBI_ONLY_HDR) || defined(STBI_ONLY_PIC) || defined(STBI_ONLY_PNM) \
+ || defined(STBI_ONLY_ZLIB)
+ #ifndef STBI_ONLY_JPEG
+ #define STBI_NO_JPEG
+ #endif
+ #ifndef STBI_ONLY_PNG
+ #define STBI_NO_PNG
+ #endif
+ #ifndef STBI_ONLY_BMP
+ #define STBI_NO_BMP
+ #endif
+ #ifndef STBI_ONLY_PSD
+ #define STBI_NO_PSD
+ #endif
+ #ifndef STBI_ONLY_TGA
+ #define STBI_NO_TGA
+ #endif
+ #ifndef STBI_ONLY_GIF
+ #define STBI_NO_GIF
+ #endif
+ #ifndef STBI_ONLY_HDR
+ #define STBI_NO_HDR
+ #endif
+ #ifndef STBI_ONLY_PIC
+ #define STBI_NO_PIC
+ #endif
+ #ifndef STBI_ONLY_PNM
+ #define STBI_NO_PNM
+ #endif
+#endif
+
+#if defined(STBI_NO_PNG) && !defined(STBI_SUPPORT_ZLIB) && !defined(STBI_NO_ZLIB)
+#define STBI_NO_ZLIB
+#endif
+
+
+#include <stdarg.h>
+#include <stddef.h> // ptrdiff_t on osx
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+
+#if !defined(STBI_NO_LINEAR) || !defined(STBI_NO_HDR)
+#include <math.h> // ldexp, pow
+#endif
+
+#ifndef STBI_NO_STDIO
+#include <stdio.h>
+#endif
+
+#ifndef STBI_ASSERT
+#include <assert.h>
+#define STBI_ASSERT(x) assert(x)
+#endif
+
+#ifdef __cplusplus
+#define STBI_EXTERN extern "C"
+#else
+#define STBI_EXTERN extern
+#endif
+
+
+#ifndef _MSC_VER
+ #ifdef __cplusplus
+ #define stbi_inline inline
+ #else
+ #define stbi_inline
+ #endif
+#else
+ #define stbi_inline __forceinline
+#endif
+
+#ifndef STBI_NO_THREAD_LOCALS
+ #if defined(__cplusplus) && __cplusplus >= 201103L
+ #define STBI_THREAD_LOCAL thread_local
+ #elif defined(__GNUC__) && __GNUC__ < 5
+ #define STBI_THREAD_LOCAL __thread
+ #elif defined(_MSC_VER)
+ #define STBI_THREAD_LOCAL __declspec(thread)
+ #elif defined (__STDC_VERSION__) && __STDC_VERSION__ >= 201112L && !defined(__STDC_NO_THREADS__)
+ #define STBI_THREAD_LOCAL _Thread_local
+ #endif
+
+ #ifndef STBI_THREAD_LOCAL
+ #if defined(__GNUC__)
+ #define STBI_THREAD_LOCAL __thread
+ #endif
+ #endif
+#endif
+
+#if defined(_MSC_VER) || defined(__SYMBIAN32__)
+typedef unsigned short stbi__uint16;
+typedef signed short stbi__int16;
+typedef unsigned int stbi__uint32;
+typedef signed int stbi__int32;
+#else
+#include <stdint.h>
+typedef uint16_t stbi__uint16;
+typedef int16_t stbi__int16;
+typedef uint32_t stbi__uint32;
+typedef int32_t stbi__int32;
+#endif
+
+// should produce compiler error if size is wrong
+typedef unsigned char validate_uint32[sizeof(stbi__uint32)==4 ? 1 : -1];
+
+#ifdef _MSC_VER
+#define STBI_NOTUSED(v) (void)(v)
+#else
+#define STBI_NOTUSED(v) (void)sizeof(v)
+#endif
+
+#ifdef _MSC_VER
+#define STBI_HAS_LROTL
+#endif
+
+#ifdef STBI_HAS_LROTL
+ #define stbi_lrot(x,y) _lrotl(x,y)
+#else
+ #define stbi_lrot(x,y) (((x) << (y)) | ((x) >> (-(y) & 31)))
+#endif
+
+#if defined(STBI_MALLOC) && defined(STBI_FREE) && (defined(STBI_REALLOC) || defined(STBI_REALLOC_SIZED))
+// ok
+#elif !defined(STBI_MALLOC) && !defined(STBI_FREE) && !defined(STBI_REALLOC) && !defined(STBI_REALLOC_SIZED)
+// ok
+#else
+#error "Must define all or none of STBI_MALLOC, STBI_FREE, and STBI_REALLOC (or STBI_REALLOC_SIZED)."
+#endif
+
+#ifndef STBI_MALLOC
+#define STBI_MALLOC(sz) malloc(sz)
+#define STBI_REALLOC(p,newsz) realloc(p,newsz)
+#define STBI_FREE(p) free(p)
+#endif
+
+#ifndef STBI_REALLOC_SIZED
+#define STBI_REALLOC_SIZED(p,oldsz,newsz) STBI_REALLOC(p,newsz)
+#endif
+
+// x86/x64 detection
+#if defined(__x86_64__) || defined(_M_X64)
+#define STBI__X64_TARGET
+#elif defined(__i386) || defined(_M_IX86)
+#define STBI__X86_TARGET
+#endif
+
+#if defined(__GNUC__) && defined(STBI__X86_TARGET) && !defined(__SSE2__) && !defined(STBI_NO_SIMD)
+// gcc doesn't support sse2 intrinsics unless you compile with -msse2,
+// which in turn means it gets to use SSE2 everywhere. This is unfortunate,
+// but previous attempts to provide the SSE2 functions with runtime
+// detection caused numerous issues. The way architecture extensions are
+// exposed in GCC/Clang is, sadly, not really suited for one-file libs.
+// New behavior: if compiled with -msse2, we use SSE2 without any
+// detection; if not, we don't use it at all.
+#define STBI_NO_SIMD
+#endif
+
+#if defined(__MINGW32__) && defined(STBI__X86_TARGET) && !defined(STBI_MINGW_ENABLE_SSE2) && !defined(STBI_NO_SIMD)
+// Note that __MINGW32__ doesn't actually mean 32-bit, so we have to avoid STBI__X64_TARGET
+//
+// 32-bit MinGW wants ESP to be 16-byte aligned, but this is not in the
+// Windows ABI and VC++ as well as Windows DLLs don't maintain that invariant.
+// As a result, enabling SSE2 on 32-bit MinGW is dangerous when not
+// simultaneously enabling "-mstackrealign".
+//
+// See https://github.com/nothings/stb/issues/81 for more information.
+//
+// So default to no SSE2 on 32-bit MinGW. If you've read this far and added
+// -mstackrealign to your build settings, feel free to #define STBI_MINGW_ENABLE_SSE2.
+#define STBI_NO_SIMD
+#endif
+
+#if !defined(STBI_NO_SIMD) && (defined(STBI__X86_TARGET) || defined(STBI__X64_TARGET))
+#define STBI_SSE2
+#include <emmintrin.h>
+
+#ifdef _MSC_VER
+
+#if _MSC_VER >= 1400 // not VC6
+#include <intrin.h> // __cpuid
+static int stbi__cpuid3(void)
+{
+ int info[4];
+ __cpuid(info,1);
+ return info[3];
+}
+#else
+static int stbi__cpuid3(void)
+{
+ int res;
+ __asm {
+ mov eax,1
+ cpuid
+ mov res,edx
+ }
+ return res;
+}
+#endif
+
+#define STBI_SIMD_ALIGN(type, name) __declspec(align(16)) type name
+
+#if !defined(STBI_NO_JPEG) && defined(STBI_SSE2)
+static int stbi__sse2_available(void)
+{
+ int info3 = stbi__cpuid3();
+ return ((info3 >> 26) & 1) != 0;
+}
+#endif
+
+#else // assume GCC-style if not VC++
+#define STBI_SIMD_ALIGN(type, name) type name __attribute__((aligned(16)))
+
+#if !defined(STBI_NO_JPEG) && defined(STBI_SSE2)
+static int stbi__sse2_available(void)
+{
+ // If we're even attempting to compile this on GCC/Clang, that means
+ // -msse2 is on, which means the compiler is allowed to use SSE2
+ // instructions at will, and so are we.
+ return 1;
+}
+#endif
+
+#endif
+#endif
+
+// ARM NEON
+#if defined(STBI_NO_SIMD) && defined(STBI_NEON)
+#undef STBI_NEON
+#endif
+
+#ifdef STBI_NEON
+#include <arm_neon.h>
+#ifdef _MSC_VER
+#define STBI_SIMD_ALIGN(type, name) __declspec(align(16)) type name
+#else
+#define STBI_SIMD_ALIGN(type, name) type name __attribute__((aligned(16)))
+#endif
+#endif
+
+#ifndef STBI_SIMD_ALIGN
+#define STBI_SIMD_ALIGN(type, name) type name
+#endif
+
+#ifndef STBI_MAX_DIMENSIONS
+#define STBI_MAX_DIMENSIONS (1 << 24)
+#endif
+
+///////////////////////////////////////////////
+//
+// stbi__context struct and start_xxx functions
+
+// stbi__context structure is our basic context used by all images, so it
+// contains all the IO context, plus some basic image information
+typedef struct
+{
+ stbi__uint32 img_x, img_y;
+ int img_n, img_out_n;
+
+ stbi_io_callbacks io;
+ void *io_user_data;
+
+ int read_from_callbacks;
+ int buflen;
+ stbi_uc buffer_start[128];
+ int callback_already_read;
+
+ stbi_uc *img_buffer, *img_buffer_end;
+ stbi_uc *img_buffer_original, *img_buffer_original_end;
+} stbi__context;
+
+
+static void stbi__refill_buffer(stbi__context *s);
+
+// initialize a memory-decode context
+static void stbi__start_mem(stbi__context *s, stbi_uc const *buffer, int len)
+{
+ s->io.read = NULL;
+ s->read_from_callbacks = 0;
+ s->callback_already_read = 0;
+ s->img_buffer = s->img_buffer_original = (stbi_uc *) buffer;
+ s->img_buffer_end = s->img_buffer_original_end = (stbi_uc *) buffer+len;
+}
+
+// initialize a callback-based context
+static void stbi__start_callbacks(stbi__context *s, stbi_io_callbacks *c, void *user)
+{
+ s->io = *c;
+ s->io_user_data = user;
+ s->buflen = sizeof(s->buffer_start);
+ s->read_from_callbacks = 1;
+ s->callback_already_read = 0;
+ s->img_buffer = s->img_buffer_original = s->buffer_start;
+ stbi__refill_buffer(s);
+ s->img_buffer_original_end = s->img_buffer_end;
+}
+
+#ifndef STBI_NO_STDIO
+
+static int stbi__stdio_read(void *user, char *data, int size)
+{
+ return (int) fread(data,1,size,(FILE*) user);
+}
+
+static void stbi__stdio_skip(void *user, int n)
+{
+ int ch;
+ fseek((FILE*) user, n, SEEK_CUR);
+ ch = fgetc((FILE*) user); /* have to read a byte to reset feof()'s flag */
+ if (ch != EOF) {
+ ungetc(ch, (FILE *) user); /* push byte back onto stream if valid. */
+ }
+}
+
+static int stbi__stdio_eof(void *user)
+{
+ return feof((FILE*) user) || ferror((FILE *) user);
+}
+
+static stbi_io_callbacks stbi__stdio_callbacks =
+{
+ stbi__stdio_read,
+ stbi__stdio_skip,
+ stbi__stdio_eof,
+};
+
+static void stbi__start_file(stbi__context *s, FILE *f)
+{
+ stbi__start_callbacks(s, &stbi__stdio_callbacks, (void *) f);
+}
+
+//static void stop_file(stbi__context *s) { }
+
+#endif // !STBI_NO_STDIO
+
+static void stbi__rewind(stbi__context *s)
+{
+ // conceptually rewind SHOULD rewind to the beginning of the stream,
+ // but we just rewind to the beginning of the initial buffer, because
+ // we only use it after doing 'test', which only ever looks at at most 92 bytes
+ s->img_buffer = s->img_buffer_original;
+ s->img_buffer_end = s->img_buffer_original_end;
+}
+
+enum
+{
+ STBI_ORDER_RGB,
+ STBI_ORDER_BGR
+};
+
+typedef struct
+{
+ int bits_per_channel;
+ int num_channels;
+ int channel_order;
+} stbi__result_info;
+
+#ifndef STBI_NO_JPEG
+static int stbi__jpeg_test(stbi__context *s);
+static void *stbi__jpeg_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri);
+static int stbi__jpeg_info(stbi__context *s, int *x, int *y, int *comp);
+#endif
+
+#ifndef STBI_NO_PNG
+static int stbi__png_test(stbi__context *s);
+static void *stbi__png_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri);
+static int stbi__png_info(stbi__context *s, int *x, int *y, int *comp);
+static int stbi__png_is16(stbi__context *s);
+#endif
+
+#ifndef STBI_NO_BMP
+static int stbi__bmp_test(stbi__context *s);
+static void *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri);
+static int stbi__bmp_info(stbi__context *s, int *x, int *y, int *comp);
+#endif
+
+#ifndef STBI_NO_TGA
+static int stbi__tga_test(stbi__context *s);
+static void *stbi__tga_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri);
+static int stbi__tga_info(stbi__context *s, int *x, int *y, int *comp);
+#endif
+
+#ifndef STBI_NO_PSD
+static int stbi__psd_test(stbi__context *s);
+static void *stbi__psd_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri, int bpc);
+static int stbi__psd_info(stbi__context *s, int *x, int *y, int *comp);
+static int stbi__psd_is16(stbi__context *s);
+#endif
+
+#ifndef STBI_NO_HDR
+static int stbi__hdr_test(stbi__context *s);
+static float *stbi__hdr_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri);
+static int stbi__hdr_info(stbi__context *s, int *x, int *y, int *comp);
+#endif
+
+#ifndef STBI_NO_PIC
+static int stbi__pic_test(stbi__context *s);
+static void *stbi__pic_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri);
+static int stbi__pic_info(stbi__context *s, int *x, int *y, int *comp);
+#endif
+
+#ifndef STBI_NO_GIF
+static int stbi__gif_test(stbi__context *s);
+static void *stbi__gif_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri);
+static void *stbi__load_gif_main(stbi__context *s, int **delays, int *x, int *y, int *z, int *comp, int req_comp);
+static int stbi__gif_info(stbi__context *s, int *x, int *y, int *comp);
+#endif
+
+#ifndef STBI_NO_PNM
+static int stbi__pnm_test(stbi__context *s);
+static void *stbi__pnm_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri);
+static int stbi__pnm_info(stbi__context *s, int *x, int *y, int *comp);
+static int stbi__pnm_is16(stbi__context *s);
+#endif
+
+static
+#ifdef STBI_THREAD_LOCAL
+STBI_THREAD_LOCAL
+#endif
+const char *stbi__g_failure_reason;
+
+STBIDEF const char *stbi_failure_reason(void)
+{
+ return stbi__g_failure_reason;
+}
+
+#ifndef STBI_NO_FAILURE_STRINGS
+static int stbi__err(const char *str)
+{
+ stbi__g_failure_reason = str;
+ return 0;
+}
+#endif
+
+static void *stbi__malloc(size_t size)
+{
+ return STBI_MALLOC(size);
+}
+
+// stb_image uses ints pervasively, including for offset calculations.
+// therefore the largest decoded image size we can support with the
+// current code, even on 64-bit targets, is INT_MAX. this is not a
+// significant limitation for the intended use case.
+//
+// we do, however, need to make sure our size calculations don't
+// overflow. hence a few helper functions for size calculations that
+// multiply integers together, making sure that they're non-negative
+// and no overflow occurs.
+
+// return 1 if the sum is valid, 0 on overflow.
+// negative terms are considered invalid.
+static int stbi__addsizes_valid(int a, int b)
+{
+ if (b < 0) return 0;
+ // now 0 <= b <= INT_MAX, hence also
+ // 0 <= INT_MAX - b <= INTMAX.
+ // And "a + b <= INT_MAX" (which might overflow) is the
+ // same as a <= INT_MAX - b (no overflow)
+ return a <= INT_MAX - b;
+}
+
+// returns 1 if the product is valid, 0 on overflow.
+// negative factors are considered invalid.
+static int stbi__mul2sizes_valid(int a, int b)
+{
+ if (a < 0 || b < 0) return 0;
+ if (b == 0) return 1; // mul-by-0 is always safe
+ // portable way to check for no overflows in a*b
+ return a <= INT_MAX/b;
+}
+
+#if !defined(STBI_NO_JPEG) || !defined(STBI_NO_PNG) || !defined(STBI_NO_TGA) || !defined(STBI_NO_HDR)
+// returns 1 if "a*b + add" has no negative terms/factors and doesn't overflow
+static int stbi__mad2sizes_valid(int a, int b, int add)
+{
+ return stbi__mul2sizes_valid(a, b) && stbi__addsizes_valid(a*b, add);
+}
+#endif
+
+// returns 1 if "a*b*c + add" has no negative terms/factors and doesn't overflow
+static int stbi__mad3sizes_valid(int a, int b, int c, int add)
+{
+ return stbi__mul2sizes_valid(a, b) && stbi__mul2sizes_valid(a*b, c) &&
+ stbi__addsizes_valid(a*b*c, add);
+}
+
+// returns 1 if "a*b*c*d + add" has no negative terms/factors and doesn't overflow
+#if !defined(STBI_NO_LINEAR) || !defined(STBI_NO_HDR) || !defined(STBI_NO_PNM)
+static int stbi__mad4sizes_valid(int a, int b, int c, int d, int add)
+{
+ return stbi__mul2sizes_valid(a, b) && stbi__mul2sizes_valid(a*b, c) &&
+ stbi__mul2sizes_valid(a*b*c, d) && stbi__addsizes_valid(a*b*c*d, add);
+}
+#endif
+
+#if !defined(STBI_NO_JPEG) || !defined(STBI_NO_PNG) || !defined(STBI_NO_TGA) || !defined(STBI_NO_HDR)
+// mallocs with size overflow checking
+static void *stbi__malloc_mad2(int a, int b, int add)
+{
+ if (!stbi__mad2sizes_valid(a, b, add)) return NULL;
+ return stbi__malloc(a*b + add);
+}
+#endif
+
+static void *stbi__malloc_mad3(int a, int b, int c, int add)
+{
+ if (!stbi__mad3sizes_valid(a, b, c, add)) return NULL;
+ return stbi__malloc(a*b*c + add);
+}
+
+#if !defined(STBI_NO_LINEAR) || !defined(STBI_NO_HDR) || !defined(STBI_NO_PNM)
+static void *stbi__malloc_mad4(int a, int b, int c, int d, int add)
+{
+ if (!stbi__mad4sizes_valid(a, b, c, d, add)) return NULL;
+ return stbi__malloc(a*b*c*d + add);
+}
+#endif
+
+// returns 1 if the sum of two signed ints is valid (between -2^31 and 2^31-1 inclusive), 0 on overflow.
+static int stbi__addints_valid(int a, int b)
+{
+ if ((a >= 0) != (b >= 0)) return 1; // a and b have different signs, so no overflow
+ if (a < 0 && b < 0) return a >= INT_MIN - b; // same as a + b >= INT_MIN; INT_MIN - b cannot overflow since b < 0.
+ return a <= INT_MAX - b;
+}
+
+// returns 1 if the product of two ints fits in a signed short, 0 on overflow.
+static int stbi__mul2shorts_valid(int a, int b)
+{
+ if (b == 0 || b == -1) return 1; // multiplication by 0 is always 0; check for -1 so SHRT_MIN/b doesn't overflow
+ if ((a >= 0) == (b >= 0)) return a <= SHRT_MAX/b; // product is positive, so similar to mul2sizes_valid
+ if (b < 0) return a <= SHRT_MIN / b; // same as a * b >= SHRT_MIN
+ return a >= SHRT_MIN / b;
+}
+
+// stbi__err - error
+// stbi__errpf - error returning pointer to float
+// stbi__errpuc - error returning pointer to unsigned char
+
+#ifdef STBI_NO_FAILURE_STRINGS
+ #define stbi__err(x,y) 0
+#elif defined(STBI_FAILURE_USERMSG)
+ #define stbi__err(x,y) stbi__err(y)
+#else
+ #define stbi__err(x,y) stbi__err(x)
+#endif
+
+#define stbi__errpf(x,y) ((float *)(size_t) (stbi__err(x,y)?NULL:NULL))
+#define stbi__errpuc(x,y) ((unsigned char *)(size_t) (stbi__err(x,y)?NULL:NULL))
+
+STBIDEF void stbi_image_free(void *retval_from_stbi_load)
+{
+ STBI_FREE(retval_from_stbi_load);
+}
+
+#ifndef STBI_NO_LINEAR
+static float *stbi__ldr_to_hdr(stbi_uc *data, int x, int y, int comp);
+#endif
+
+#ifndef STBI_NO_HDR
+static stbi_uc *stbi__hdr_to_ldr(float *data, int x, int y, int comp);
+#endif
+
+static int stbi__vertically_flip_on_load_global = 0;
+
+STBIDEF void stbi_set_flip_vertically_on_load(int flag_true_if_should_flip)
+{
+ stbi__vertically_flip_on_load_global = flag_true_if_should_flip;
+}
+
+#ifndef STBI_THREAD_LOCAL
+#define stbi__vertically_flip_on_load stbi__vertically_flip_on_load_global
+#else
+static STBI_THREAD_LOCAL int stbi__vertically_flip_on_load_local, stbi__vertically_flip_on_load_set;
+
+STBIDEF void stbi_set_flip_vertically_on_load_thread(int flag_true_if_should_flip)
+{
+ stbi__vertically_flip_on_load_local = flag_true_if_should_flip;
+ stbi__vertically_flip_on_load_set = 1;
+}
+
+#define stbi__vertically_flip_on_load (stbi__vertically_flip_on_load_set \
+ ? stbi__vertically_flip_on_load_local \
+ : stbi__vertically_flip_on_load_global)
+#endif // STBI_THREAD_LOCAL
+
+static void *stbi__load_main(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri, int bpc)
+{
+ memset(ri, 0, sizeof(*ri)); // make sure it's initialized if we add new fields
+ ri->bits_per_channel = 8; // default is 8 so most paths don't have to be changed
+ ri->channel_order = STBI_ORDER_RGB; // all current input & output are this, but this is here so we can add BGR order
+ ri->num_channels = 0;
+
+ // test the formats with a very explicit header first (at least a FOURCC
+ // or distinctive magic number first)
+ #ifndef STBI_NO_PNG
+ if (stbi__png_test(s)) return stbi__png_load(s,x,y,comp,req_comp, ri);
+ #endif
+ #ifndef STBI_NO_BMP
+ if (stbi__bmp_test(s)) return stbi__bmp_load(s,x,y,comp,req_comp, ri);
+ #endif
+ #ifndef STBI_NO_GIF
+ if (stbi__gif_test(s)) return stbi__gif_load(s,x,y,comp,req_comp, ri);
+ #endif
+ #ifndef STBI_NO_PSD
+ if (stbi__psd_test(s)) return stbi__psd_load(s,x,y,comp,req_comp, ri, bpc);
+ #else
+ STBI_NOTUSED(bpc);
+ #endif
+ #ifndef STBI_NO_PIC
+ if (stbi__pic_test(s)) return stbi__pic_load(s,x,y,comp,req_comp, ri);
+ #endif
+
+ // then the formats that can end up attempting to load with just 1 or 2
+ // bytes matching expectations; these are prone to false positives, so
+ // try them later
+ #ifndef STBI_NO_JPEG
+ if (stbi__jpeg_test(s)) return stbi__jpeg_load(s,x,y,comp,req_comp, ri);
+ #endif
+ #ifndef STBI_NO_PNM
+ if (stbi__pnm_test(s)) return stbi__pnm_load(s,x,y,comp,req_comp, ri);
+ #endif
+
+ #ifndef STBI_NO_HDR
+ if (stbi__hdr_test(s)) {
+ float *hdr = stbi__hdr_load(s, x,y,comp,req_comp, ri);
+ return stbi__hdr_to_ldr(hdr, *x, *y, req_comp ? req_comp : *comp);
+ }
+ #endif
+
+ #ifndef STBI_NO_TGA
+ // test tga last because it's a crappy test!
+ if (stbi__tga_test(s))
+ return stbi__tga_load(s,x,y,comp,req_comp, ri);
+ #endif
+
+ return stbi__errpuc("unknown image type", "Image not of any known type, or corrupt");
+}
+
+static stbi_uc *stbi__convert_16_to_8(stbi__uint16 *orig, int w, int h, int channels)
+{
+ int i;
+ int img_len = w * h * channels;
+ stbi_uc *reduced;
+
+ reduced = (stbi_uc *) stbi__malloc(img_len);
+ if (reduced == NULL) return stbi__errpuc("outofmem", "Out of memory");
+
+ for (i = 0; i < img_len; ++i)
+ reduced[i] = (stbi_uc)((orig[i] >> 8) & 0xFF); // top half of each byte is sufficient approx of 16->8 bit scaling
+
+ STBI_FREE(orig);
+ return reduced;
+}
+
+static stbi__uint16 *stbi__convert_8_to_16(stbi_uc *orig, int w, int h, int channels)
+{
+ int i;
+ int img_len = w * h * channels;
+ stbi__uint16 *enlarged;
+
+ enlarged = (stbi__uint16 *) stbi__malloc(img_len*2);
+ if (enlarged == NULL) return (stbi__uint16 *) stbi__errpuc("outofmem", "Out of memory");
+
+ for (i = 0; i < img_len; ++i)
+ enlarged[i] = (stbi__uint16)((orig[i] << 8) + orig[i]); // replicate to high and low byte, maps 0->0, 255->0xffff
+
+ STBI_FREE(orig);
+ return enlarged;
+}
+
+static void stbi__vertical_flip(void *image, int w, int h, int bytes_per_pixel)
+{
+ int row;
+ size_t bytes_per_row = (size_t)w * bytes_per_pixel;
+ stbi_uc temp[2048];
+ stbi_uc *bytes = (stbi_uc *)image;
+
+ for (row = 0; row < (h>>1); row++) {
+ stbi_uc *row0 = bytes + row*bytes_per_row;
+ stbi_uc *row1 = bytes + (h - row - 1)*bytes_per_row;
+ // swap row0 with row1
+ size_t bytes_left = bytes_per_row;
+ while (bytes_left) {
+ size_t bytes_copy = (bytes_left < sizeof(temp)) ? bytes_left : sizeof(temp);
+ memcpy(temp, row0, bytes_copy);
+ memcpy(row0, row1, bytes_copy);
+ memcpy(row1, temp, bytes_copy);
+ row0 += bytes_copy;
+ row1 += bytes_copy;
+ bytes_left -= bytes_copy;
+ }
+ }
+}
+
+#ifndef STBI_NO_GIF
+static void stbi__vertical_flip_slices(void *image, int w, int h, int z, int bytes_per_pixel)
+{
+ int slice;
+ int slice_size = w * h * bytes_per_pixel;
+
+ stbi_uc *bytes = (stbi_uc *)image;
+ for (slice = 0; slice < z; ++slice) {
+ stbi__vertical_flip(bytes, w, h, bytes_per_pixel);
+ bytes += slice_size;
+ }
+}
+#endif
+
+static unsigned char *stbi__load_and_postprocess_8bit(stbi__context *s, int *x, int *y, int *comp, int req_comp)
+{
+ stbi__result_info ri;
+ void *result = stbi__load_main(s, x, y, comp, req_comp, &ri, 8);
+
+ if (result == NULL)
+ return NULL;
+
+ // it is the responsibility of the loaders to make sure we get either 8 or 16 bit.
+ STBI_ASSERT(ri.bits_per_channel == 8 || ri.bits_per_channel == 16);
+
+ if (ri.bits_per_channel != 8) {
+ result = stbi__convert_16_to_8((stbi__uint16 *) result, *x, *y, req_comp == 0 ? *comp : req_comp);
+ ri.bits_per_channel = 8;
+ }
+
+ // @TODO: move stbi__convert_format to here
+
+ if (stbi__vertically_flip_on_load) {
+ int channels = req_comp ? req_comp : *comp;
+ stbi__vertical_flip(result, *x, *y, channels * sizeof(stbi_uc));
+ }
+
+ return (unsigned char *) result;
+}
+
+static stbi__uint16 *stbi__load_and_postprocess_16bit(stbi__context *s, int *x, int *y, int *comp, int req_comp)
+{
+ stbi__result_info ri;
+ void *result = stbi__load_main(s, x, y, comp, req_comp, &ri, 16);
+
+ if (result == NULL)
+ return NULL;
+
+ // it is the responsibility of the loaders to make sure we get either 8 or 16 bit.
+ STBI_ASSERT(ri.bits_per_channel == 8 || ri.bits_per_channel == 16);
+
+ if (ri.bits_per_channel != 16) {
+ result = stbi__convert_8_to_16((stbi_uc *) result, *x, *y, req_comp == 0 ? *comp : req_comp);
+ ri.bits_per_channel = 16;
+ }
+
+ // @TODO: move stbi__convert_format16 to here
+ // @TODO: special case RGB-to-Y (and RGBA-to-YA) for 8-bit-to-16-bit case to keep more precision
+
+ if (stbi__vertically_flip_on_load) {
+ int channels = req_comp ? req_comp : *comp;
+ stbi__vertical_flip(result, *x, *y, channels * sizeof(stbi__uint16));
+ }
+
+ return (stbi__uint16 *) result;
+}
+
+#if !defined(STBI_NO_HDR) && !defined(STBI_NO_LINEAR)
+static void stbi__float_postprocess(float *result, int *x, int *y, int *comp, int req_comp)
+{
+ if (stbi__vertically_flip_on_load && result != NULL) {
+ int channels = req_comp ? req_comp : *comp;
+ stbi__vertical_flip(result, *x, *y, channels * sizeof(float));
+ }
+}
+#endif
+
+#ifndef STBI_NO_STDIO
+
+#if defined(_WIN32) && defined(STBI_WINDOWS_UTF8)
+STBI_EXTERN __declspec(dllimport) int __stdcall MultiByteToWideChar(unsigned int cp, unsigned long flags, const char *str, int cbmb, wchar_t *widestr, int cchwide);
+STBI_EXTERN __declspec(dllimport) int __stdcall WideCharToMultiByte(unsigned int cp, unsigned long flags, const wchar_t *widestr, int cchwide, char *str, int cbmb, const char *defchar, int *used_default);
+#endif
+
+#if defined(_WIN32) && defined(STBI_WINDOWS_UTF8)
+STBIDEF int stbi_convert_wchar_to_utf8(char *buffer, size_t bufferlen, const wchar_t* input)
+{
+ return WideCharToMultiByte(65001 /* UTF8 */, 0, input, -1, buffer, (int) bufferlen, NULL, NULL);
+}
+#endif
+
+static FILE *stbi__fopen(char const *filename, char const *mode)
+{
+ FILE *f;
+#if defined(_WIN32) && defined(STBI_WINDOWS_UTF8)
+ wchar_t wMode[64];
+ wchar_t wFilename[1024];
+ if (0 == MultiByteToWideChar(65001 /* UTF8 */, 0, filename, -1, wFilename, sizeof(wFilename)/sizeof(*wFilename)))
+ return 0;
+
+ if (0 == MultiByteToWideChar(65001 /* UTF8 */, 0, mode, -1, wMode, sizeof(wMode)/sizeof(*wMode)))
+ return 0;
+
+#if defined(_MSC_VER) && _MSC_VER >= 1400
+ if (0 != _wfopen_s(&f, wFilename, wMode))
+ f = 0;
+#else
+ f = _wfopen(wFilename, wMode);
+#endif
+
+#elif defined(_MSC_VER) && _MSC_VER >= 1400
+ if (0 != fopen_s(&f, filename, mode))
+ f=0;
+#else
+ f = fopen(filename, mode);
+#endif
+ return f;
+}
+
+
+STBIDEF stbi_uc *stbi_load(char const *filename, int *x, int *y, int *comp, int req_comp)
+{
+ FILE *f = stbi__fopen(filename, "rb");
+ unsigned char *result;
+ if (!f) return stbi__errpuc("can't fopen", "Unable to open file");
+ result = stbi_load_from_file(f,x,y,comp,req_comp);
+ fclose(f);
+ return result;
+}
+
+STBIDEF stbi_uc *stbi_load_from_file(FILE *f, int *x, int *y, int *comp, int req_comp)
+{
+ unsigned char *result;
+ stbi__context s;
+ stbi__start_file(&s,f);
+ result = stbi__load_and_postprocess_8bit(&s,x,y,comp,req_comp);
+ if (result) {
+ // need to 'unget' all the characters in the IO buffer
+ fseek(f, - (int) (s.img_buffer_end - s.img_buffer), SEEK_CUR);
+ }
+ return result;
+}
+
+STBIDEF stbi__uint16 *stbi_load_from_file_16(FILE *f, int *x, int *y, int *comp, int req_comp)
+{
+ stbi__uint16 *result;
+ stbi__context s;
+ stbi__start_file(&s,f);
+ result = stbi__load_and_postprocess_16bit(&s,x,y,comp,req_comp);
+ if (result) {
+ // need to 'unget' all the characters in the IO buffer
+ fseek(f, - (int) (s.img_buffer_end - s.img_buffer), SEEK_CUR);
+ }
+ return result;
+}
+
+STBIDEF stbi_us *stbi_load_16(char const *filename, int *x, int *y, int *comp, int req_comp)
+{
+ FILE *f = stbi__fopen(filename, "rb");
+ stbi__uint16 *result;
+ if (!f) return (stbi_us *) stbi__errpuc("can't fopen", "Unable to open file");
+ result = stbi_load_from_file_16(f,x,y,comp,req_comp);
+ fclose(f);
+ return result;
+}
+
+
+#endif //!STBI_NO_STDIO
+
+STBIDEF stbi_us *stbi_load_16_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *channels_in_file, int desired_channels)
+{
+ stbi__context s;
+ stbi__start_mem(&s,buffer,len);
+ return stbi__load_and_postprocess_16bit(&s,x,y,channels_in_file,desired_channels);
+}
+
+STBIDEF stbi_us *stbi_load_16_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *channels_in_file, int desired_channels)
+{
+ stbi__context s;
+ stbi__start_callbacks(&s, (stbi_io_callbacks *)clbk, user);
+ return stbi__load_and_postprocess_16bit(&s,x,y,channels_in_file,desired_channels);
+}
+
+STBIDEF stbi_uc *stbi_load_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp)
+{
+ stbi__context s;
+ stbi__start_mem(&s,buffer,len);
+ return stbi__load_and_postprocess_8bit(&s,x,y,comp,req_comp);
+}
+
+STBIDEF stbi_uc *stbi_load_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp, int req_comp)
+{
+ stbi__context s;
+ stbi__start_callbacks(&s, (stbi_io_callbacks *) clbk, user);
+ return stbi__load_and_postprocess_8bit(&s,x,y,comp,req_comp);
+}
+
+#ifndef STBI_NO_GIF
+STBIDEF stbi_uc *stbi_load_gif_from_memory(stbi_uc const *buffer, int len, int **delays, int *x, int *y, int *z, int *comp, int req_comp)
+{
+ unsigned char *result;
+ stbi__context s;
+ stbi__start_mem(&s,buffer,len);
+
+ result = (unsigned char*) stbi__load_gif_main(&s, delays, x, y, z, comp, req_comp);
+ if (stbi__vertically_flip_on_load) {
+ stbi__vertical_flip_slices( result, *x, *y, *z, *comp );
+ }
+
+ return result;
+}
+#endif
+
+#ifndef STBI_NO_LINEAR
+static float *stbi__loadf_main(stbi__context *s, int *x, int *y, int *comp, int req_comp)
+{
+ unsigned char *data;
+ #ifndef STBI_NO_HDR
+ if (stbi__hdr_test(s)) {
+ stbi__result_info ri;
+ float *hdr_data = stbi__hdr_load(s,x,y,comp,req_comp, &ri);
+ if (hdr_data)
+ stbi__float_postprocess(hdr_data,x,y,comp,req_comp);
+ return hdr_data;
+ }
+ #endif
+ data = stbi__load_and_postprocess_8bit(s, x, y, comp, req_comp);
+ if (data)
+ return stbi__ldr_to_hdr(data, *x, *y, req_comp ? req_comp : *comp);
+ return stbi__errpf("unknown image type", "Image not of any known type, or corrupt");
+}
+
+STBIDEF float *stbi_loadf_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp)
+{
+ stbi__context s;
+ stbi__start_mem(&s,buffer,len);
+ return stbi__loadf_main(&s,x,y,comp,req_comp);
+}
+
+STBIDEF float *stbi_loadf_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp, int req_comp)
+{
+ stbi__context s;
+ stbi__start_callbacks(&s, (stbi_io_callbacks *) clbk, user);
+ return stbi__loadf_main(&s,x,y,comp,req_comp);
+}
+
+#ifndef STBI_NO_STDIO
+STBIDEF float *stbi_loadf(char const *filename, int *x, int *y, int *comp, int req_comp)
+{
+ float *result;
+ FILE *f = stbi__fopen(filename, "rb");
+ if (!f) return stbi__errpf("can't fopen", "Unable to open file");
+ result = stbi_loadf_from_file(f,x,y,comp,req_comp);
+ fclose(f);
+ return result;
+}
+
+STBIDEF float *stbi_loadf_from_file(FILE *f, int *x, int *y, int *comp, int req_comp)
+{
+ stbi__context s;
+ stbi__start_file(&s,f);
+ return stbi__loadf_main(&s,x,y,comp,req_comp);
+}
+#endif // !STBI_NO_STDIO
+
+#endif // !STBI_NO_LINEAR
+
+// these is-hdr-or-not is defined independent of whether STBI_NO_LINEAR is
+// defined, for API simplicity; if STBI_NO_LINEAR is defined, it always
+// reports false!
+
+STBIDEF int stbi_is_hdr_from_memory(stbi_uc const *buffer, int len)
+{
+ #ifndef STBI_NO_HDR
+ stbi__context s;
+ stbi__start_mem(&s,buffer,len);
+ return stbi__hdr_test(&s);
+ #else
+ STBI_NOTUSED(buffer);
+ STBI_NOTUSED(len);
+ return 0;
+ #endif
+}
+
+#ifndef STBI_NO_STDIO
+STBIDEF int stbi_is_hdr (char const *filename)
+{
+ FILE *f = stbi__fopen(filename, "rb");
+ int result=0;
+ if (f) {
+ result = stbi_is_hdr_from_file(f);
+ fclose(f);
+ }
+ return result;
+}
+
+STBIDEF int stbi_is_hdr_from_file(FILE *f)
+{
+ #ifndef STBI_NO_HDR
+ long pos = ftell(f);
+ int res;
+ stbi__context s;
+ stbi__start_file(&s,f);
+ res = stbi__hdr_test(&s);
+ fseek(f, pos, SEEK_SET);
+ return res;
+ #else
+ STBI_NOTUSED(f);
+ return 0;
+ #endif
+}
+#endif // !STBI_NO_STDIO
+
+STBIDEF int stbi_is_hdr_from_callbacks(stbi_io_callbacks const *clbk, void *user)
+{
+ #ifndef STBI_NO_HDR
+ stbi__context s;
+ stbi__start_callbacks(&s, (stbi_io_callbacks *) clbk, user);
+ return stbi__hdr_test(&s);
+ #else
+ STBI_NOTUSED(clbk);
+ STBI_NOTUSED(user);
+ return 0;
+ #endif
+}
+
+#ifndef STBI_NO_LINEAR
+static float stbi__l2h_gamma=2.2f, stbi__l2h_scale=1.0f;
+
+STBIDEF void stbi_ldr_to_hdr_gamma(float gamma) { stbi__l2h_gamma = gamma; }
+STBIDEF void stbi_ldr_to_hdr_scale(float scale) { stbi__l2h_scale = scale; }
+#endif
+
+static float stbi__h2l_gamma_i=1.0f/2.2f, stbi__h2l_scale_i=1.0f;
+
+STBIDEF void stbi_hdr_to_ldr_gamma(float gamma) { stbi__h2l_gamma_i = 1/gamma; }
+STBIDEF void stbi_hdr_to_ldr_scale(float scale) { stbi__h2l_scale_i = 1/scale; }
+
+
+//////////////////////////////////////////////////////////////////////////////
+//
+// Common code used by all image loaders
+//
+
+enum
+{
+ STBI__SCAN_load=0,
+ STBI__SCAN_type,
+ STBI__SCAN_header
+};
+
+static void stbi__refill_buffer(stbi__context *s)
+{
+ int n = (s->io.read)(s->io_user_data,(char*)s->buffer_start,s->buflen);
+ s->callback_already_read += (int) (s->img_buffer - s->img_buffer_original);
+ if (n == 0) {
+ // at end of file, treat same as if from memory, but need to handle case
+ // where s->img_buffer isn't pointing to safe memory, e.g. 0-byte file
+ s->read_from_callbacks = 0;
+ s->img_buffer = s->buffer_start;
+ s->img_buffer_end = s->buffer_start+1;
+ *s->img_buffer = 0;
+ } else {
+ s->img_buffer = s->buffer_start;
+ s->img_buffer_end = s->buffer_start + n;
+ }
+}
+
+stbi_inline static stbi_uc stbi__get8(stbi__context *s)
+{
+ if (s->img_buffer < s->img_buffer_end)
+ return *s->img_buffer++;
+ if (s->read_from_callbacks) {
+ stbi__refill_buffer(s);
+ return *s->img_buffer++;
+ }
+ return 0;
+}
+
+#if defined(STBI_NO_JPEG) && defined(STBI_NO_HDR) && defined(STBI_NO_PIC) && defined(STBI_NO_PNM)
+// nothing
+#else
+stbi_inline static int stbi__at_eof(stbi__context *s)
+{
+ if (s->io.read) {
+ if (!(s->io.eof)(s->io_user_data)) return 0;
+ // if feof() is true, check if buffer = end
+ // special case: we've only got the special 0 character at the end
+ if (s->read_from_callbacks == 0) return 1;
+ }
+
+ return s->img_buffer >= s->img_buffer_end;
+}
+#endif
+
+#if defined(STBI_NO_JPEG) && defined(STBI_NO_PNG) && defined(STBI_NO_BMP) && defined(STBI_NO_PSD) && defined(STBI_NO_TGA) && defined(STBI_NO_GIF) && defined(STBI_NO_PIC)
+// nothing
+#else
+static void stbi__skip(stbi__context *s, int n)
+{
+ if (n == 0) return; // already there!
+ if (n < 0) {
+ s->img_buffer = s->img_buffer_end;
+ return;
+ }
+ if (s->io.read) {
+ int blen = (int) (s->img_buffer_end - s->img_buffer);
+ if (blen < n) {
+ s->img_buffer = s->img_buffer_end;
+ (s->io.skip)(s->io_user_data, n - blen);
+ return;
+ }
+ }
+ s->img_buffer += n;
+}
+#endif
+
+#if defined(STBI_NO_PNG) && defined(STBI_NO_TGA) && defined(STBI_NO_HDR) && defined(STBI_NO_PNM)
+// nothing
+#else
+static int stbi__getn(stbi__context *s, stbi_uc *buffer, int n)
+{
+ if (s->io.read) {
+ int blen = (int) (s->img_buffer_end - s->img_buffer);
+ if (blen < n) {
+ int res, count;
+
+ memcpy(buffer, s->img_buffer, blen);
+
+ count = (s->io.read)(s->io_user_data, (char*) buffer + blen, n - blen);
+ res = (count == (n-blen));
+ s->img_buffer = s->img_buffer_end;
+ return res;
+ }
+ }
+
+ if (s->img_buffer+n <= s->img_buffer_end) {
+ memcpy(buffer, s->img_buffer, n);
+ s->img_buffer += n;
+ return 1;
+ } else
+ return 0;
+}
+#endif
+
+#if defined(STBI_NO_JPEG) && defined(STBI_NO_PNG) && defined(STBI_NO_PSD) && defined(STBI_NO_PIC)
+// nothing
+#else
+static int stbi__get16be(stbi__context *s)
+{
+ int z = stbi__get8(s);
+ return (z << 8) + stbi__get8(s);
+}
+#endif
+
+#if defined(STBI_NO_PNG) && defined(STBI_NO_PSD) && defined(STBI_NO_PIC)
+// nothing
+#else
+static stbi__uint32 stbi__get32be(stbi__context *s)
+{
+ stbi__uint32 z = stbi__get16be(s);
+ return (z << 16) + stbi__get16be(s);
+}
+#endif
+
+#if defined(STBI_NO_BMP) && defined(STBI_NO_TGA) && defined(STBI_NO_GIF)
+// nothing
+#else
+static int stbi__get16le(stbi__context *s)
+{
+ int z = stbi__get8(s);
+ return z + (stbi__get8(s) << 8);
+}
+#endif
+
+#ifndef STBI_NO_BMP
+static stbi__uint32 stbi__get32le(stbi__context *s)
+{
+ stbi__uint32 z = stbi__get16le(s);
+ z += (stbi__uint32)stbi__get16le(s) << 16;
+ return z;
+}
+#endif
+
+#define STBI__BYTECAST(x) ((stbi_uc) ((x) & 255)) // truncate int to byte without warnings
+
+#if defined(STBI_NO_JPEG) && defined(STBI_NO_PNG) && defined(STBI_NO_BMP) && defined(STBI_NO_PSD) && defined(STBI_NO_TGA) && defined(STBI_NO_GIF) && defined(STBI_NO_PIC) && defined(STBI_NO_PNM)
+// nothing
+#else
+//////////////////////////////////////////////////////////////////////////////
+//
+// generic converter from built-in img_n to req_comp
+// individual types do this automatically as much as possible (e.g. jpeg
+// does all cases internally since it needs to colorspace convert anyway,
+// and it never has alpha, so very few cases ). png can automatically
+// interleave an alpha=255 channel, but falls back to this for other cases
+//
+// assume data buffer is malloced, so malloc a new one and free that one
+// only failure mode is malloc failing
+
+static stbi_uc stbi__compute_y(int r, int g, int b)
+{
+ return (stbi_uc) (((r*77) + (g*150) + (29*b)) >> 8);
+}
+#endif
+
+#if defined(STBI_NO_PNG) && defined(STBI_NO_BMP) && defined(STBI_NO_PSD) && defined(STBI_NO_TGA) && defined(STBI_NO_GIF) && defined(STBI_NO_PIC) && defined(STBI_NO_PNM)
+// nothing
+#else
+static unsigned char *stbi__convert_format(unsigned char *data, int img_n, int req_comp, unsigned int x, unsigned int y)
+{
+ int i,j;
+ unsigned char *good;
+
+ if (req_comp == img_n) return data;
+ STBI_ASSERT(req_comp >= 1 && req_comp <= 4);
+
+ good = (unsigned char *) stbi__malloc_mad3(req_comp, x, y, 0);
+ if (good == NULL) {
+ STBI_FREE(data);
+ return stbi__errpuc("outofmem", "Out of memory");
+ }
+
+ for (j=0; j < (int) y; ++j) {
+ unsigned char *src = data + j * x * img_n ;
+ unsigned char *dest = good + j * x * req_comp;
+
+ #define STBI__COMBO(a,b) ((a)*8+(b))
+ #define STBI__CASE(a,b) case STBI__COMBO(a,b): for(i=x-1; i >= 0; --i, src += a, dest += b)
+ // convert source image with img_n components to one with req_comp components;
+ // avoid switch per pixel, so use switch per scanline and massive macros
+ switch (STBI__COMBO(img_n, req_comp)) {
+ STBI__CASE(1,2) { dest[0]=src[0]; dest[1]=255; } break;
+ STBI__CASE(1,3) { dest[0]=dest[1]=dest[2]=src[0]; } break;
+ STBI__CASE(1,4) { dest[0]=dest[1]=dest[2]=src[0]; dest[3]=255; } break;
+ STBI__CASE(2,1) { dest[0]=src[0]; } break;
+ STBI__CASE(2,3) { dest[0]=dest[1]=dest[2]=src[0]; } break;
+ STBI__CASE(2,4) { dest[0]=dest[1]=dest[2]=src[0]; dest[3]=src[1]; } break;
+ STBI__CASE(3,4) { dest[0]=src[0];dest[1]=src[1];dest[2]=src[2];dest[3]=255; } break;
+ STBI__CASE(3,1) { dest[0]=stbi__compute_y(src[0],src[1],src[2]); } break;
+ STBI__CASE(3,2) { dest[0]=stbi__compute_y(src[0],src[1],src[2]); dest[1] = 255; } break;
+ STBI__CASE(4,1) { dest[0]=stbi__compute_y(src[0],src[1],src[2]); } break;
+ STBI__CASE(4,2) { dest[0]=stbi__compute_y(src[0],src[1],src[2]); dest[1] = src[3]; } break;
+ STBI__CASE(4,3) { dest[0]=src[0];dest[1]=src[1];dest[2]=src[2]; } break;
+ default: STBI_ASSERT(0); STBI_FREE(data); STBI_FREE(good); return stbi__errpuc("unsupported", "Unsupported format conversion");
+ }
+ #undef STBI__CASE
+ }
+
+ STBI_FREE(data);
+ return good;
+}
+#endif
+
+#if defined(STBI_NO_PNG) && defined(STBI_NO_PSD)
+// nothing
+#else
+static stbi__uint16 stbi__compute_y_16(int r, int g, int b)
+{
+ return (stbi__uint16) (((r*77) + (g*150) + (29*b)) >> 8);
+}
+#endif
+
+#if defined(STBI_NO_PNG) && defined(STBI_NO_PSD)
+// nothing
+#else
+static stbi__uint16 *stbi__convert_format16(stbi__uint16 *data, int img_n, int req_comp, unsigned int x, unsigned int y)
+{
+ int i,j;
+ stbi__uint16 *good;
+
+ if (req_comp == img_n) return data;
+ STBI_ASSERT(req_comp >= 1 && req_comp <= 4);
+
+ good = (stbi__uint16 *) stbi__malloc(req_comp * x * y * 2);
+ if (good == NULL) {
+ STBI_FREE(data);
+ return (stbi__uint16 *) stbi__errpuc("outofmem", "Out of memory");
+ }
+
+ for (j=0; j < (int) y; ++j) {
+ stbi__uint16 *src = data + j * x * img_n ;
+ stbi__uint16 *dest = good + j * x * req_comp;
+
+ #define STBI__COMBO(a,b) ((a)*8+(b))
+ #define STBI__CASE(a,b) case STBI__COMBO(a,b): for(i=x-1; i >= 0; --i, src += a, dest += b)
+ // convert source image with img_n components to one with req_comp components;
+ // avoid switch per pixel, so use switch per scanline and massive macros
+ switch (STBI__COMBO(img_n, req_comp)) {
+ STBI__CASE(1,2) { dest[0]=src[0]; dest[1]=0xffff; } break;
+ STBI__CASE(1,3) { dest[0]=dest[1]=dest[2]=src[0]; } break;
+ STBI__CASE(1,4) { dest[0]=dest[1]=dest[2]=src[0]; dest[3]=0xffff; } break;
+ STBI__CASE(2,1) { dest[0]=src[0]; } break;
+ STBI__CASE(2,3) { dest[0]=dest[1]=dest[2]=src[0]; } break;
+ STBI__CASE(2,4) { dest[0]=dest[1]=dest[2]=src[0]; dest[3]=src[1]; } break;
+ STBI__CASE(3,4) { dest[0]=src[0];dest[1]=src[1];dest[2]=src[2];dest[3]=0xffff; } break;
+ STBI__CASE(3,1) { dest[0]=stbi__compute_y_16(src[0],src[1],src[2]); } break;
+ STBI__CASE(3,2) { dest[0]=stbi__compute_y_16(src[0],src[1],src[2]); dest[1] = 0xffff; } break;
+ STBI__CASE(4,1) { dest[0]=stbi__compute_y_16(src[0],src[1],src[2]); } break;
+ STBI__CASE(4,2) { dest[0]=stbi__compute_y_16(src[0],src[1],src[2]); dest[1] = src[3]; } break;
+ STBI__CASE(4,3) { dest[0]=src[0];dest[1]=src[1];dest[2]=src[2]; } break;
+ default: STBI_ASSERT(0); STBI_FREE(data); STBI_FREE(good); return (stbi__uint16*) stbi__errpuc("unsupported", "Unsupported format conversion");
+ }
+ #undef STBI__CASE
+ }
+
+ STBI_FREE(data);
+ return good;
+}
+#endif
+
+#ifndef STBI_NO_LINEAR
+static float *stbi__ldr_to_hdr(stbi_uc *data, int x, int y, int comp)
+{
+ int i,k,n;
+ float *output;
+ if (!data) return NULL;
+ output = (float *) stbi__malloc_mad4(x, y, comp, sizeof(float), 0);
+ if (output == NULL) { STBI_FREE(data); return stbi__errpf("outofmem", "Out of memory"); }
+ // compute number of non-alpha components
+ if (comp & 1) n = comp; else n = comp-1;
+ for (i=0; i < x*y; ++i) {
+ for (k=0; k < n; ++k) {
+ output[i*comp + k] = (float) (pow(data[i*comp+k]/255.0f, stbi__l2h_gamma) * stbi__l2h_scale);
+ }
+ }
+ if (n < comp) {
+ for (i=0; i < x*y; ++i) {
+ output[i*comp + n] = data[i*comp + n]/255.0f;
+ }
+ }
+ STBI_FREE(data);
+ return output;
+}
+#endif
+
+#ifndef STBI_NO_HDR
+#define stbi__float2int(x) ((int) (x))
+static stbi_uc *stbi__hdr_to_ldr(float *data, int x, int y, int comp)
+{
+ int i,k,n;
+ stbi_uc *output;
+ if (!data) return NULL;
+ output = (stbi_uc *) stbi__malloc_mad3(x, y, comp, 0);
+ if (output == NULL) { STBI_FREE(data); return stbi__errpuc("outofmem", "Out of memory"); }
+ // compute number of non-alpha components
+ if (comp & 1) n = comp; else n = comp-1;
+ for (i=0; i < x*y; ++i) {
+ for (k=0; k < n; ++k) {
+ float z = (float) pow(data[i*comp+k]*stbi__h2l_scale_i, stbi__h2l_gamma_i) * 255 + 0.5f;
+ if (z < 0) z = 0;
+ if (z > 255) z = 255;
+ output[i*comp + k] = (stbi_uc) stbi__float2int(z);
+ }
+ if (k < comp) {
+ float z = data[i*comp+k] * 255 + 0.5f;
+ if (z < 0) z = 0;
+ if (z > 255) z = 255;
+ output[i*comp + k] = (stbi_uc) stbi__float2int(z);
+ }
+ }
+ STBI_FREE(data);
+ return output;
+}
+#endif
+
+//////////////////////////////////////////////////////////////////////////////
+//
+// "baseline" JPEG/JFIF decoder
+//
+// simple implementation
+// - doesn't support delayed output of y-dimension
+// - simple interface (only one output format: 8-bit interleaved RGB)
+// - doesn't try to recover corrupt jpegs
+// - doesn't allow partial loading, loading multiple at once
+// - still fast on x86 (copying globals into locals doesn't help x86)
+// - allocates lots of intermediate memory (full size of all components)
+// - non-interleaved case requires this anyway
+// - allows good upsampling (see next)
+// high-quality
+// - upsampled channels are bilinearly interpolated, even across blocks
+// - quality integer IDCT derived from IJG's 'slow'
+// performance
+// - fast huffman; reasonable integer IDCT
+// - some SIMD kernels for common paths on targets with SSE2/NEON
+// - uses a lot of intermediate memory, could cache poorly
+
+#ifndef STBI_NO_JPEG
+
+// huffman decoding acceleration
+#define FAST_BITS 9 // larger handles more cases; smaller stomps less cache
+
+typedef struct
+{
+ stbi_uc fast[1 << FAST_BITS];
+ // weirdly, repacking this into AoS is a 10% speed loss, instead of a win
+ stbi__uint16 code[256];
+ stbi_uc values[256];
+ stbi_uc size[257];
+ unsigned int maxcode[18];
+ int delta[17]; // old 'firstsymbol' - old 'firstcode'
+} stbi__huffman;
+
+typedef struct
+{
+ stbi__context *s;
+ stbi__huffman huff_dc[4];
+ stbi__huffman huff_ac[4];
+ stbi__uint16 dequant[4][64];
+ stbi__int16 fast_ac[4][1 << FAST_BITS];
+
+// sizes for components, interleaved MCUs
+ int img_h_max, img_v_max;
+ int img_mcu_x, img_mcu_y;
+ int img_mcu_w, img_mcu_h;
+
+// definition of jpeg image component
+ struct
+ {
+ int id;
+ int h,v;
+ int tq;
+ int hd,ha;
+ int dc_pred;
+
+ int x,y,w2,h2;
+ stbi_uc *data;
+ void *raw_data, *raw_coeff;
+ stbi_uc *linebuf;
+ short *coeff; // progressive only
+ int coeff_w, coeff_h; // number of 8x8 coefficient blocks
+ } img_comp[4];
+
+ stbi__uint32 code_buffer; // jpeg entropy-coded buffer
+ int code_bits; // number of valid bits
+ unsigned char marker; // marker seen while filling entropy buffer
+ int nomore; // flag if we saw a marker so must stop
+
+ int progressive;
+ int spec_start;
+ int spec_end;
+ int succ_high;
+ int succ_low;
+ int eob_run;
+ int jfif;
+ int app14_color_transform; // Adobe APP14 tag
+ int rgb;
+
+ int scan_n, order[4];
+ int restart_interval, todo;
+
+// kernels
+ void (*idct_block_kernel)(stbi_uc *out, int out_stride, short data[64]);
+ void (*YCbCr_to_RGB_kernel)(stbi_uc *out, const stbi_uc *y, const stbi_uc *pcb, const stbi_uc *pcr, int count, int step);
+ stbi_uc *(*resample_row_hv_2_kernel)(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs);
+} stbi__jpeg;
+
+static int stbi__build_huffman(stbi__huffman *h, int *count)
+{
+ int i,j,k=0;
+ unsigned int code;
+ // build size list for each symbol (from JPEG spec)
+ for (i=0; i < 16; ++i) {
+ for (j=0; j < count[i]; ++j) {
+ h->size[k++] = (stbi_uc) (i+1);
+ if(k >= 257) return stbi__err("bad size list","Corrupt JPEG");
+ }
+ }
+ h->size[k] = 0;
+
+ // compute actual symbols (from jpeg spec)
+ code = 0;
+ k = 0;
+ for(j=1; j <= 16; ++j) {
+ // compute delta to add to code to compute symbol id
+ h->delta[j] = k - code;
+ if (h->size[k] == j) {
+ while (h->size[k] == j)
+ h->code[k++] = (stbi__uint16) (code++);
+ if (code-1 >= (1u << j)) return stbi__err("bad code lengths","Corrupt JPEG");
+ }
+ // compute largest code + 1 for this size, preshifted as needed later
+ h->maxcode[j] = code << (16-j);
+ code <<= 1;
+ }
+ h->maxcode[j] = 0xffffffff;
+
+ // build non-spec acceleration table; 255 is flag for not-accelerated
+ memset(h->fast, 255, 1 << FAST_BITS);
+ for (i=0; i < k; ++i) {
+ int s = h->size[i];
+ if (s <= FAST_BITS) {
+ int c = h->code[i] << (FAST_BITS-s);
+ int m = 1 << (FAST_BITS-s);
+ for (j=0; j < m; ++j) {
+ h->fast[c+j] = (stbi_uc) i;
+ }
+ }
+ }
+ return 1;
+}
+
+// build a table that decodes both magnitude and value of small ACs in
+// one go.
+static void stbi__build_fast_ac(stbi__int16 *fast_ac, stbi__huffman *h)
+{
+ int i;
+ for (i=0; i < (1 << FAST_BITS); ++i) {
+ stbi_uc fast = h->fast[i];
+ fast_ac[i] = 0;
+ if (fast < 255) {
+ int rs = h->values[fast];
+ int run = (rs >> 4) & 15;
+ int magbits = rs & 15;
+ int len = h->size[fast];
+
+ if (magbits && len + magbits <= FAST_BITS) {
+ // magnitude code followed by receive_extend code
+ int k = ((i << len) & ((1 << FAST_BITS) - 1)) >> (FAST_BITS - magbits);
+ int m = 1 << (magbits - 1);
+ if (k < m) k += (~0U << magbits) + 1;
+ // if the result is small enough, we can fit it in fast_ac table
+ if (k >= -128 && k <= 127)
+ fast_ac[i] = (stbi__int16) ((k * 256) + (run * 16) + (len + magbits));
+ }
+ }
+ }
+}
+
+static void stbi__grow_buffer_unsafe(stbi__jpeg *j)
+{
+ do {
+ unsigned int b = j->nomore ? 0 : stbi__get8(j->s);
+ if (b == 0xff) {
+ int c = stbi__get8(j->s);
+ while (c == 0xff) c = stbi__get8(j->s); // consume fill bytes
+ if (c != 0) {
+ j->marker = (unsigned char) c;
+ j->nomore = 1;
+ return;
+ }
+ }
+ j->code_buffer |= b << (24 - j->code_bits);
+ j->code_bits += 8;
+ } while (j->code_bits <= 24);
+}
+
+// (1 << n) - 1
+static const stbi__uint32 stbi__bmask[17]={0,1,3,7,15,31,63,127,255,511,1023,2047,4095,8191,16383,32767,65535};
+
+// decode a jpeg huffman value from the bitstream
+stbi_inline static int stbi__jpeg_huff_decode(stbi__jpeg *j, stbi__huffman *h)
+{
+ unsigned int temp;
+ int c,k;
+
+ if (j->code_bits < 16) stbi__grow_buffer_unsafe(j);
+
+ // look at the top FAST_BITS and determine what symbol ID it is,
+ // if the code is <= FAST_BITS
+ c = (j->code_buffer >> (32 - FAST_BITS)) & ((1 << FAST_BITS)-1);
+ k = h->fast[c];
+ if (k < 255) {
+ int s = h->size[k];
+ if (s > j->code_bits)
+ return -1;
+ j->code_buffer <<= s;
+ j->code_bits -= s;
+ return h->values[k];
+ }
+
+ // naive test is to shift the code_buffer down so k bits are
+ // valid, then test against maxcode. To speed this up, we've
+ // preshifted maxcode left so that it has (16-k) 0s at the
+ // end; in other words, regardless of the number of bits, it
+ // wants to be compared against something shifted to have 16;
+ // that way we don't need to shift inside the loop.
+ temp = j->code_buffer >> 16;
+ for (k=FAST_BITS+1 ; ; ++k)
+ if (temp < h->maxcode[k])
+ break;
+ if (k == 17) {
+ // error! code not found
+ j->code_bits -= 16;
+ return -1;
+ }
+
+ if (k > j->code_bits)
+ return -1;
+
+ // convert the huffman code to the symbol id
+ c = ((j->code_buffer >> (32 - k)) & stbi__bmask[k]) + h->delta[k];
+ if(c < 0 || c >= 256) // symbol id out of bounds!
+ return -1;
+ STBI_ASSERT((((j->code_buffer) >> (32 - h->size[c])) & stbi__bmask[h->size[c]]) == h->code[c]);
+
+ // convert the id to a symbol
+ j->code_bits -= k;
+ j->code_buffer <<= k;
+ return h->values[c];
+}
+
+// bias[n] = (-1<<n) + 1
+static const int stbi__jbias[16] = {0,-1,-3,-7,-15,-31,-63,-127,-255,-511,-1023,-2047,-4095,-8191,-16383,-32767};
+
+// combined JPEG 'receive' and JPEG 'extend', since baseline
+// always extends everything it receives.
+stbi_inline static int stbi__extend_receive(stbi__jpeg *j, int n)
+{
+ unsigned int k;
+ int sgn;
+ if (j->code_bits < n) stbi__grow_buffer_unsafe(j);
+ if (j->code_bits < n) return 0; // ran out of bits from stream, return 0s intead of continuing
+
+ sgn = j->code_buffer >> 31; // sign bit always in MSB; 0 if MSB clear (positive), 1 if MSB set (negative)
+ k = stbi_lrot(j->code_buffer, n);
+ j->code_buffer = k & ~stbi__bmask[n];
+ k &= stbi__bmask[n];
+ j->code_bits -= n;
+ return k + (stbi__jbias[n] & (sgn - 1));
+}
+
+// get some unsigned bits
+stbi_inline static int stbi__jpeg_get_bits(stbi__jpeg *j, int n)
+{
+ unsigned int k;
+ if (j->code_bits < n) stbi__grow_buffer_unsafe(j);
+ if (j->code_bits < n) return 0; // ran out of bits from stream, return 0s intead of continuing
+ k = stbi_lrot(j->code_buffer, n);
+ j->code_buffer = k & ~stbi__bmask[n];
+ k &= stbi__bmask[n];
+ j->code_bits -= n;
+ return k;
+}
+
+stbi_inline static int stbi__jpeg_get_bit(stbi__jpeg *j)
+{
+ unsigned int k;
+ if (j->code_bits < 1) stbi__grow_buffer_unsafe(j);
+ if (j->code_bits < 1) return 0; // ran out of bits from stream, return 0s intead of continuing
+ k = j->code_buffer;
+ j->code_buffer <<= 1;
+ --j->code_bits;
+ return k & 0x80000000;
+}
+
+// given a value that's at position X in the zigzag stream,
+// where does it appear in the 8x8 matrix coded as row-major?
+static const stbi_uc stbi__jpeg_dezigzag[64+15] =
+{
+ 0, 1, 8, 16, 9, 2, 3, 10,
+ 17, 24, 32, 25, 18, 11, 4, 5,
+ 12, 19, 26, 33, 40, 48, 41, 34,
+ 27, 20, 13, 6, 7, 14, 21, 28,
+ 35, 42, 49, 56, 57, 50, 43, 36,
+ 29, 22, 15, 23, 30, 37, 44, 51,
+ 58, 59, 52, 45, 38, 31, 39, 46,
+ 53, 60, 61, 54, 47, 55, 62, 63,
+ // let corrupt input sample past end
+ 63, 63, 63, 63, 63, 63, 63, 63,
+ 63, 63, 63, 63, 63, 63, 63
+};
+
+// decode one 64-entry block--
+static int stbi__jpeg_decode_block(stbi__jpeg *j, short data[64], stbi__huffman *hdc, stbi__huffman *hac, stbi__int16 *fac, int b, stbi__uint16 *dequant)
+{
+ int diff,dc,k;
+ int t;
+
+ if (j->code_bits < 16) stbi__grow_buffer_unsafe(j);
+ t = stbi__jpeg_huff_decode(j, hdc);
+ if (t < 0 || t > 15) return stbi__err("bad huffman code","Corrupt JPEG");
+
+ // 0 all the ac values now so we can do it 32-bits at a time
+ memset(data,0,64*sizeof(data[0]));
+
+ diff = t ? stbi__extend_receive(j, t) : 0;
+ if (!stbi__addints_valid(j->img_comp[b].dc_pred, diff)) return stbi__err("bad delta","Corrupt JPEG");
+ dc = j->img_comp[b].dc_pred + diff;
+ j->img_comp[b].dc_pred = dc;
+ if (!stbi__mul2shorts_valid(dc, dequant[0])) return stbi__err("can't merge dc and ac", "Corrupt JPEG");
+ data[0] = (short) (dc * dequant[0]);
+
+ // decode AC components, see JPEG spec
+ k = 1;
+ do {
+ unsigned int zig;
+ int c,r,s;
+ if (j->code_bits < 16) stbi__grow_buffer_unsafe(j);
+ c = (j->code_buffer >> (32 - FAST_BITS)) & ((1 << FAST_BITS)-1);
+ r = fac[c];
+ if (r) { // fast-AC path
+ k += (r >> 4) & 15; // run
+ s = r & 15; // combined length
+ if (s > j->code_bits) return stbi__err("bad huffman code", "Combined length longer than code bits available");
+ j->code_buffer <<= s;
+ j->code_bits -= s;
+ // decode into unzigzag'd location
+ zig = stbi__jpeg_dezigzag[k++];
+ data[zig] = (short) ((r >> 8) * dequant[zig]);
+ } else {
+ int rs = stbi__jpeg_huff_decode(j, hac);
+ if (rs < 0) return stbi__err("bad huffman code","Corrupt JPEG");
+ s = rs & 15;
+ r = rs >> 4;
+ if (s == 0) {
+ if (rs != 0xf0) break; // end block
+ k += 16;
+ } else {
+ k += r;
+ // decode into unzigzag'd location
+ zig = stbi__jpeg_dezigzag[k++];
+ data[zig] = (short) (stbi__extend_receive(j,s) * dequant[zig]);
+ }
+ }
+ } while (k < 64);
+ return 1;
+}
+
+static int stbi__jpeg_decode_block_prog_dc(stbi__jpeg *j, short data[64], stbi__huffman *hdc, int b)
+{
+ int diff,dc;
+ int t;
+ if (j->spec_end != 0) return stbi__err("can't merge dc and ac", "Corrupt JPEG");
+
+ if (j->code_bits < 16) stbi__grow_buffer_unsafe(j);
+
+ if (j->succ_high == 0) {
+ // first scan for DC coefficient, must be first
+ memset(data,0,64*sizeof(data[0])); // 0 all the ac values now
+ t = stbi__jpeg_huff_decode(j, hdc);
+ if (t < 0 || t > 15) return stbi__err("can't merge dc and ac", "Corrupt JPEG");
+ diff = t ? stbi__extend_receive(j, t) : 0;
+
+ if (!stbi__addints_valid(j->img_comp[b].dc_pred, diff)) return stbi__err("bad delta", "Corrupt JPEG");
+ dc = j->img_comp[b].dc_pred + diff;
+ j->img_comp[b].dc_pred = dc;
+ if (!stbi__mul2shorts_valid(dc, 1 << j->succ_low)) return stbi__err("can't merge dc and ac", "Corrupt JPEG");
+ data[0] = (short) (dc * (1 << j->succ_low));
+ } else {
+ // refinement scan for DC coefficient
+ if (stbi__jpeg_get_bit(j))
+ data[0] += (short) (1 << j->succ_low);
+ }
+ return 1;
+}
+
+// @OPTIMIZE: store non-zigzagged during the decode passes,
+// and only de-zigzag when dequantizing
+static int stbi__jpeg_decode_block_prog_ac(stbi__jpeg *j, short data[64], stbi__huffman *hac, stbi__int16 *fac)
+{
+ int k;
+ if (j->spec_start == 0) return stbi__err("can't merge dc and ac", "Corrupt JPEG");
+
+ if (j->succ_high == 0) {
+ int shift = j->succ_low;
+
+ if (j->eob_run) {
+ --j->eob_run;
+ return 1;
+ }
+
+ k = j->spec_start;
+ do {
+ unsigned int zig;
+ int c,r,s;
+ if (j->code_bits < 16) stbi__grow_buffer_unsafe(j);
+ c = (j->code_buffer >> (32 - FAST_BITS)) & ((1 << FAST_BITS)-1);
+ r = fac[c];
+ if (r) { // fast-AC path
+ k += (r >> 4) & 15; // run
+ s = r & 15; // combined length
+ if (s > j->code_bits) return stbi__err("bad huffman code", "Combined length longer than code bits available");
+ j->code_buffer <<= s;
+ j->code_bits -= s;
+ zig = stbi__jpeg_dezigzag[k++];
+ data[zig] = (short) ((r >> 8) * (1 << shift));
+ } else {
+ int rs = stbi__jpeg_huff_decode(j, hac);
+ if (rs < 0) return stbi__err("bad huffman code","Corrupt JPEG");
+ s = rs & 15;
+ r = rs >> 4;
+ if (s == 0) {
+ if (r < 15) {
+ j->eob_run = (1 << r);
+ if (r)
+ j->eob_run += stbi__jpeg_get_bits(j, r);
+ --j->eob_run;
+ break;
+ }
+ k += 16;
+ } else {
+ k += r;
+ zig = stbi__jpeg_dezigzag[k++];
+ data[zig] = (short) (stbi__extend_receive(j,s) * (1 << shift));
+ }
+ }
+ } while (k <= j->spec_end);
+ } else {
+ // refinement scan for these AC coefficients
+
+ short bit = (short) (1 << j->succ_low);
+
+ if (j->eob_run) {
+ --j->eob_run;
+ for (k = j->spec_start; k <= j->spec_end; ++k) {
+ short *p = &data[stbi__jpeg_dezigzag[k]];
+ if (*p != 0)
+ if (stbi__jpeg_get_bit(j))
+ if ((*p & bit)==0) {
+ if (*p > 0)
+ *p += bit;
+ else
+ *p -= bit;
+ }
+ }
+ } else {
+ k = j->spec_start;
+ do {
+ int r,s;
+ int rs = stbi__jpeg_huff_decode(j, hac); // @OPTIMIZE see if we can use the fast path here, advance-by-r is so slow, eh
+ if (rs < 0) return stbi__err("bad huffman code","Corrupt JPEG");
+ s = rs & 15;
+ r = rs >> 4;
+ if (s == 0) {
+ if (r < 15) {
+ j->eob_run = (1 << r) - 1;
+ if (r)
+ j->eob_run += stbi__jpeg_get_bits(j, r);
+ r = 64; // force end of block
+ } else {
+ // r=15 s=0 should write 16 0s, so we just do
+ // a run of 15 0s and then write s (which is 0),
+ // so we don't have to do anything special here
+ }
+ } else {
+ if (s != 1) return stbi__err("bad huffman code", "Corrupt JPEG");
+ // sign bit
+ if (stbi__jpeg_get_bit(j))
+ s = bit;
+ else
+ s = -bit;
+ }
+
+ // advance by r
+ while (k <= j->spec_end) {
+ short *p = &data[stbi__jpeg_dezigzag[k++]];
+ if (*p != 0) {
+ if (stbi__jpeg_get_bit(j))
+ if ((*p & bit)==0) {
+ if (*p > 0)
+ *p += bit;
+ else
+ *p -= bit;
+ }
+ } else {
+ if (r == 0) {
+ *p = (short) s;
+ break;
+ }
+ --r;
+ }
+ }
+ } while (k <= j->spec_end);
+ }
+ }
+ return 1;
+}
+
+// take a -128..127 value and stbi__clamp it and convert to 0..255
+stbi_inline static stbi_uc stbi__clamp(int x)
+{
+ // trick to use a single test to catch both cases
+ if ((unsigned int) x > 255) {
+ if (x < 0) return 0;
+ if (x > 255) return 255;
+ }
+ return (stbi_uc) x;
+}
+
+#define stbi__f2f(x) ((int) (((x) * 4096 + 0.5)))
+#define stbi__fsh(x) ((x) * 4096)
+
+// derived from jidctint -- DCT_ISLOW
+#define STBI__IDCT_1D(s0,s1,s2,s3,s4,s5,s6,s7) \
+ int t0,t1,t2,t3,p1,p2,p3,p4,p5,x0,x1,x2,x3; \
+ p2 = s2; \
+ p3 = s6; \
+ p1 = (p2+p3) * stbi__f2f(0.5411961f); \
+ t2 = p1 + p3*stbi__f2f(-1.847759065f); \
+ t3 = p1 + p2*stbi__f2f( 0.765366865f); \
+ p2 = s0; \
+ p3 = s4; \
+ t0 = stbi__fsh(p2+p3); \
+ t1 = stbi__fsh(p2-p3); \
+ x0 = t0+t3; \
+ x3 = t0-t3; \
+ x1 = t1+t2; \
+ x2 = t1-t2; \
+ t0 = s7; \
+ t1 = s5; \
+ t2 = s3; \
+ t3 = s1; \
+ p3 = t0+t2; \
+ p4 = t1+t3; \
+ p1 = t0+t3; \
+ p2 = t1+t2; \
+ p5 = (p3+p4)*stbi__f2f( 1.175875602f); \
+ t0 = t0*stbi__f2f( 0.298631336f); \
+ t1 = t1*stbi__f2f( 2.053119869f); \
+ t2 = t2*stbi__f2f( 3.072711026f); \
+ t3 = t3*stbi__f2f( 1.501321110f); \
+ p1 = p5 + p1*stbi__f2f(-0.899976223f); \
+ p2 = p5 + p2*stbi__f2f(-2.562915447f); \
+ p3 = p3*stbi__f2f(-1.961570560f); \
+ p4 = p4*stbi__f2f(-0.390180644f); \
+ t3 += p1+p4; \
+ t2 += p2+p3; \
+ t1 += p2+p4; \
+ t0 += p1+p3;
+
+static void stbi__idct_block(stbi_uc *out, int out_stride, short data[64])
+{
+ int i,val[64],*v=val;
+ stbi_uc *o;
+ short *d = data;
+
+ // columns
+ for (i=0; i < 8; ++i,++d, ++v) {
+ // if all zeroes, shortcut -- this avoids dequantizing 0s and IDCTing
+ if (d[ 8]==0 && d[16]==0 && d[24]==0 && d[32]==0
+ && d[40]==0 && d[48]==0 && d[56]==0) {
+ // no shortcut 0 seconds
+ // (1|2|3|4|5|6|7)==0 0 seconds
+ // all separate -0.047 seconds
+ // 1 && 2|3 && 4|5 && 6|7: -0.047 seconds
+ int dcterm = d[0]*4;
+ v[0] = v[8] = v[16] = v[24] = v[32] = v[40] = v[48] = v[56] = dcterm;
+ } else {
+ STBI__IDCT_1D(d[ 0],d[ 8],d[16],d[24],d[32],d[40],d[48],d[56])
+ // constants scaled things up by 1<<12; let's bring them back
+ // down, but keep 2 extra bits of precision
+ x0 += 512; x1 += 512; x2 += 512; x3 += 512;
+ v[ 0] = (x0+t3) >> 10;
+ v[56] = (x0-t3) >> 10;
+ v[ 8] = (x1+t2) >> 10;
+ v[48] = (x1-t2) >> 10;
+ v[16] = (x2+t1) >> 10;
+ v[40] = (x2-t1) >> 10;
+ v[24] = (x3+t0) >> 10;
+ v[32] = (x3-t0) >> 10;
+ }
+ }
+
+ for (i=0, v=val, o=out; i < 8; ++i,v+=8,o+=out_stride) {
+ // no fast case since the first 1D IDCT spread components out
+ STBI__IDCT_1D(v[0],v[1],v[2],v[3],v[4],v[5],v[6],v[7])
+ // constants scaled things up by 1<<12, plus we had 1<<2 from first
+ // loop, plus horizontal and vertical each scale by sqrt(8) so together
+ // we've got an extra 1<<3, so 1<<17 total we need to remove.
+ // so we want to round that, which means adding 0.5 * 1<<17,
+ // aka 65536. Also, we'll end up with -128 to 127 that we want
+ // to encode as 0..255 by adding 128, so we'll add that before the shift
+ x0 += 65536 + (128<<17);
+ x1 += 65536 + (128<<17);
+ x2 += 65536 + (128<<17);
+ x3 += 65536 + (128<<17);
+ // tried computing the shifts into temps, or'ing the temps to see
+ // if any were out of range, but that was slower
+ o[0] = stbi__clamp((x0+t3) >> 17);
+ o[7] = stbi__clamp((x0-t3) >> 17);
+ o[1] = stbi__clamp((x1+t2) >> 17);
+ o[6] = stbi__clamp((x1-t2) >> 17);
+ o[2] = stbi__clamp((x2+t1) >> 17);
+ o[5] = stbi__clamp((x2-t1) >> 17);
+ o[3] = stbi__clamp((x3+t0) >> 17);
+ o[4] = stbi__clamp((x3-t0) >> 17);
+ }
+}
+
+#ifdef STBI_SSE2
+// sse2 integer IDCT. not the fastest possible implementation but it
+// produces bit-identical results to the generic C version so it's
+// fully "transparent".
+static void stbi__idct_simd(stbi_uc *out, int out_stride, short data[64])
+{
+ // This is constructed to match our regular (generic) integer IDCT exactly.
+ __m128i row0, row1, row2, row3, row4, row5, row6, row7;
+ __m128i tmp;
+
+ // dot product constant: even elems=x, odd elems=y
+ #define dct_const(x,y) _mm_setr_epi16((x),(y),(x),(y),(x),(y),(x),(y))
+
+ // out(0) = c0[even]*x + c0[odd]*y (c0, x, y 16-bit, out 32-bit)
+ // out(1) = c1[even]*x + c1[odd]*y
+ #define dct_rot(out0,out1, x,y,c0,c1) \
+ __m128i c0##lo = _mm_unpacklo_epi16((x),(y)); \
+ __m128i c0##hi = _mm_unpackhi_epi16((x),(y)); \
+ __m128i out0##_l = _mm_madd_epi16(c0##lo, c0); \
+ __m128i out0##_h = _mm_madd_epi16(c0##hi, c0); \
+ __m128i out1##_l = _mm_madd_epi16(c0##lo, c1); \
+ __m128i out1##_h = _mm_madd_epi16(c0##hi, c1)
+
+ // out = in << 12 (in 16-bit, out 32-bit)
+ #define dct_widen(out, in) \
+ __m128i out##_l = _mm_srai_epi32(_mm_unpacklo_epi16(_mm_setzero_si128(), (in)), 4); \
+ __m128i out##_h = _mm_srai_epi32(_mm_unpackhi_epi16(_mm_setzero_si128(), (in)), 4)
+
+ // wide add
+ #define dct_wadd(out, a, b) \
+ __m128i out##_l = _mm_add_epi32(a##_l, b##_l); \
+ __m128i out##_h = _mm_add_epi32(a##_h, b##_h)
+
+ // wide sub
+ #define dct_wsub(out, a, b) \
+ __m128i out##_l = _mm_sub_epi32(a##_l, b##_l); \
+ __m128i out##_h = _mm_sub_epi32(a##_h, b##_h)
+
+ // butterfly a/b, add bias, then shift by "s" and pack
+ #define dct_bfly32o(out0, out1, a,b,bias,s) \
+ { \
+ __m128i abiased_l = _mm_add_epi32(a##_l, bias); \
+ __m128i abiased_h = _mm_add_epi32(a##_h, bias); \
+ dct_wadd(sum, abiased, b); \
+ dct_wsub(dif, abiased, b); \
+ out0 = _mm_packs_epi32(_mm_srai_epi32(sum_l, s), _mm_srai_epi32(sum_h, s)); \
+ out1 = _mm_packs_epi32(_mm_srai_epi32(dif_l, s), _mm_srai_epi32(dif_h, s)); \
+ }
+
+ // 8-bit interleave step (for transposes)
+ #define dct_interleave8(a, b) \
+ tmp = a; \
+ a = _mm_unpacklo_epi8(a, b); \
+ b = _mm_unpackhi_epi8(tmp, b)
+
+ // 16-bit interleave step (for transposes)
+ #define dct_interleave16(a, b) \
+ tmp = a; \
+ a = _mm_unpacklo_epi16(a, b); \
+ b = _mm_unpackhi_epi16(tmp, b)
+
+ #define dct_pass(bias,shift) \
+ { \
+ /* even part */ \
+ dct_rot(t2e,t3e, row2,row6, rot0_0,rot0_1); \
+ __m128i sum04 = _mm_add_epi16(row0, row4); \
+ __m128i dif04 = _mm_sub_epi16(row0, row4); \
+ dct_widen(t0e, sum04); \
+ dct_widen(t1e, dif04); \
+ dct_wadd(x0, t0e, t3e); \
+ dct_wsub(x3, t0e, t3e); \
+ dct_wadd(x1, t1e, t2e); \
+ dct_wsub(x2, t1e, t2e); \
+ /* odd part */ \
+ dct_rot(y0o,y2o, row7,row3, rot2_0,rot2_1); \
+ dct_rot(y1o,y3o, row5,row1, rot3_0,rot3_1); \
+ __m128i sum17 = _mm_add_epi16(row1, row7); \
+ __m128i sum35 = _mm_add_epi16(row3, row5); \
+ dct_rot(y4o,y5o, sum17,sum35, rot1_0,rot1_1); \
+ dct_wadd(x4, y0o, y4o); \
+ dct_wadd(x5, y1o, y5o); \
+ dct_wadd(x6, y2o, y5o); \
+ dct_wadd(x7, y3o, y4o); \
+ dct_bfly32o(row0,row7, x0,x7,bias,shift); \
+ dct_bfly32o(row1,row6, x1,x6,bias,shift); \
+ dct_bfly32o(row2,row5, x2,x5,bias,shift); \
+ dct_bfly32o(row3,row4, x3,x4,bias,shift); \
+ }
+
+ __m128i rot0_0 = dct_const(stbi__f2f(0.5411961f), stbi__f2f(0.5411961f) + stbi__f2f(-1.847759065f));
+ __m128i rot0_1 = dct_const(stbi__f2f(0.5411961f) + stbi__f2f( 0.765366865f), stbi__f2f(0.5411961f));
+ __m128i rot1_0 = dct_const(stbi__f2f(1.175875602f) + stbi__f2f(-0.899976223f), stbi__f2f(1.175875602f));
+ __m128i rot1_1 = dct_const(stbi__f2f(1.175875602f), stbi__f2f(1.175875602f) + stbi__f2f(-2.562915447f));
+ __m128i rot2_0 = dct_const(stbi__f2f(-1.961570560f) + stbi__f2f( 0.298631336f), stbi__f2f(-1.961570560f));
+ __m128i rot2_1 = dct_const(stbi__f2f(-1.961570560f), stbi__f2f(-1.961570560f) + stbi__f2f( 3.072711026f));
+ __m128i rot3_0 = dct_const(stbi__f2f(-0.390180644f) + stbi__f2f( 2.053119869f), stbi__f2f(-0.390180644f));
+ __m128i rot3_1 = dct_const(stbi__f2f(-0.390180644f), stbi__f2f(-0.390180644f) + stbi__f2f( 1.501321110f));
+
+ // rounding biases in column/row passes, see stbi__idct_block for explanation.
+ __m128i bias_0 = _mm_set1_epi32(512);
+ __m128i bias_1 = _mm_set1_epi32(65536 + (128<<17));
+
+ // load
+ row0 = _mm_load_si128((const __m128i *) (data + 0*8));
+ row1 = _mm_load_si128((const __m128i *) (data + 1*8));
+ row2 = _mm_load_si128((const __m128i *) (data + 2*8));
+ row3 = _mm_load_si128((const __m128i *) (data + 3*8));
+ row4 = _mm_load_si128((const __m128i *) (data + 4*8));
+ row5 = _mm_load_si128((const __m128i *) (data + 5*8));
+ row6 = _mm_load_si128((const __m128i *) (data + 6*8));
+ row7 = _mm_load_si128((const __m128i *) (data + 7*8));
+
+ // column pass
+ dct_pass(bias_0, 10);
+
+ {
+ // 16bit 8x8 transpose pass 1
+ dct_interleave16(row0, row4);
+ dct_interleave16(row1, row5);
+ dct_interleave16(row2, row6);
+ dct_interleave16(row3, row7);
+
+ // transpose pass 2
+ dct_interleave16(row0, row2);
+ dct_interleave16(row1, row3);
+ dct_interleave16(row4, row6);
+ dct_interleave16(row5, row7);
+
+ // transpose pass 3
+ dct_interleave16(row0, row1);
+ dct_interleave16(row2, row3);
+ dct_interleave16(row4, row5);
+ dct_interleave16(row6, row7);
+ }
+
+ // row pass
+ dct_pass(bias_1, 17);
+
+ {
+ // pack
+ __m128i p0 = _mm_packus_epi16(row0, row1); // a0a1a2a3...a7b0b1b2b3...b7
+ __m128i p1 = _mm_packus_epi16(row2, row3);
+ __m128i p2 = _mm_packus_epi16(row4, row5);
+ __m128i p3 = _mm_packus_epi16(row6, row7);
+
+ // 8bit 8x8 transpose pass 1
+ dct_interleave8(p0, p2); // a0e0a1e1...
+ dct_interleave8(p1, p3); // c0g0c1g1...
+
+ // transpose pass 2
+ dct_interleave8(p0, p1); // a0c0e0g0...
+ dct_interleave8(p2, p3); // b0d0f0h0...
+
+ // transpose pass 3
+ dct_interleave8(p0, p2); // a0b0c0d0...
+ dct_interleave8(p1, p3); // a4b4c4d4...
+
+ // store
+ _mm_storel_epi64((__m128i *) out, p0); out += out_stride;
+ _mm_storel_epi64((__m128i *) out, _mm_shuffle_epi32(p0, 0x4e)); out += out_stride;
+ _mm_storel_epi64((__m128i *) out, p2); out += out_stride;
+ _mm_storel_epi64((__m128i *) out, _mm_shuffle_epi32(p2, 0x4e)); out += out_stride;
+ _mm_storel_epi64((__m128i *) out, p1); out += out_stride;
+ _mm_storel_epi64((__m128i *) out, _mm_shuffle_epi32(p1, 0x4e)); out += out_stride;
+ _mm_storel_epi64((__m128i *) out, p3); out += out_stride;
+ _mm_storel_epi64((__m128i *) out, _mm_shuffle_epi32(p3, 0x4e));
+ }
+
+#undef dct_const
+#undef dct_rot
+#undef dct_widen
+#undef dct_wadd
+#undef dct_wsub
+#undef dct_bfly32o
+#undef dct_interleave8
+#undef dct_interleave16
+#undef dct_pass
+}
+
+#endif // STBI_SSE2
+
+#ifdef STBI_NEON
+
+// NEON integer IDCT. should produce bit-identical
+// results to the generic C version.
+static void stbi__idct_simd(stbi_uc *out, int out_stride, short data[64])
+{
+ int16x8_t row0, row1, row2, row3, row4, row5, row6, row7;
+
+ int16x4_t rot0_0 = vdup_n_s16(stbi__f2f(0.5411961f));
+ int16x4_t rot0_1 = vdup_n_s16(stbi__f2f(-1.847759065f));
+ int16x4_t rot0_2 = vdup_n_s16(stbi__f2f( 0.765366865f));
+ int16x4_t rot1_0 = vdup_n_s16(stbi__f2f( 1.175875602f));
+ int16x4_t rot1_1 = vdup_n_s16(stbi__f2f(-0.899976223f));
+ int16x4_t rot1_2 = vdup_n_s16(stbi__f2f(-2.562915447f));
+ int16x4_t rot2_0 = vdup_n_s16(stbi__f2f(-1.961570560f));
+ int16x4_t rot2_1 = vdup_n_s16(stbi__f2f(-0.390180644f));
+ int16x4_t rot3_0 = vdup_n_s16(stbi__f2f( 0.298631336f));
+ int16x4_t rot3_1 = vdup_n_s16(stbi__f2f( 2.053119869f));
+ int16x4_t rot3_2 = vdup_n_s16(stbi__f2f( 3.072711026f));
+ int16x4_t rot3_3 = vdup_n_s16(stbi__f2f( 1.501321110f));
+
+#define dct_long_mul(out, inq, coeff) \
+ int32x4_t out##_l = vmull_s16(vget_low_s16(inq), coeff); \
+ int32x4_t out##_h = vmull_s16(vget_high_s16(inq), coeff)
+
+#define dct_long_mac(out, acc, inq, coeff) \
+ int32x4_t out##_l = vmlal_s16(acc##_l, vget_low_s16(inq), coeff); \
+ int32x4_t out##_h = vmlal_s16(acc##_h, vget_high_s16(inq), coeff)
+
+#define dct_widen(out, inq) \
+ int32x4_t out##_l = vshll_n_s16(vget_low_s16(inq), 12); \
+ int32x4_t out##_h = vshll_n_s16(vget_high_s16(inq), 12)
+
+// wide add
+#define dct_wadd(out, a, b) \
+ int32x4_t out##_l = vaddq_s32(a##_l, b##_l); \
+ int32x4_t out##_h = vaddq_s32(a##_h, b##_h)
+
+// wide sub
+#define dct_wsub(out, a, b) \
+ int32x4_t out##_l = vsubq_s32(a##_l, b##_l); \
+ int32x4_t out##_h = vsubq_s32(a##_h, b##_h)
+
+// butterfly a/b, then shift using "shiftop" by "s" and pack
+#define dct_bfly32o(out0,out1, a,b,shiftop,s) \
+ { \
+ dct_wadd(sum, a, b); \
+ dct_wsub(dif, a, b); \
+ out0 = vcombine_s16(shiftop(sum_l, s), shiftop(sum_h, s)); \
+ out1 = vcombine_s16(shiftop(dif_l, s), shiftop(dif_h, s)); \
+ }
+
+#define dct_pass(shiftop, shift) \
+ { \
+ /* even part */ \
+ int16x8_t sum26 = vaddq_s16(row2, row6); \
+ dct_long_mul(p1e, sum26, rot0_0); \
+ dct_long_mac(t2e, p1e, row6, rot0_1); \
+ dct_long_mac(t3e, p1e, row2, rot0_2); \
+ int16x8_t sum04 = vaddq_s16(row0, row4); \
+ int16x8_t dif04 = vsubq_s16(row0, row4); \
+ dct_widen(t0e, sum04); \
+ dct_widen(t1e, dif04); \
+ dct_wadd(x0, t0e, t3e); \
+ dct_wsub(x3, t0e, t3e); \
+ dct_wadd(x1, t1e, t2e); \
+ dct_wsub(x2, t1e, t2e); \
+ /* odd part */ \
+ int16x8_t sum15 = vaddq_s16(row1, row5); \
+ int16x8_t sum17 = vaddq_s16(row1, row7); \
+ int16x8_t sum35 = vaddq_s16(row3, row5); \
+ int16x8_t sum37 = vaddq_s16(row3, row7); \
+ int16x8_t sumodd = vaddq_s16(sum17, sum35); \
+ dct_long_mul(p5o, sumodd, rot1_0); \
+ dct_long_mac(p1o, p5o, sum17, rot1_1); \
+ dct_long_mac(p2o, p5o, sum35, rot1_2); \
+ dct_long_mul(p3o, sum37, rot2_0); \
+ dct_long_mul(p4o, sum15, rot2_1); \
+ dct_wadd(sump13o, p1o, p3o); \
+ dct_wadd(sump24o, p2o, p4o); \
+ dct_wadd(sump23o, p2o, p3o); \
+ dct_wadd(sump14o, p1o, p4o); \
+ dct_long_mac(x4, sump13o, row7, rot3_0); \
+ dct_long_mac(x5, sump24o, row5, rot3_1); \
+ dct_long_mac(x6, sump23o, row3, rot3_2); \
+ dct_long_mac(x7, sump14o, row1, rot3_3); \
+ dct_bfly32o(row0,row7, x0,x7,shiftop,shift); \
+ dct_bfly32o(row1,row6, x1,x6,shiftop,shift); \
+ dct_bfly32o(row2,row5, x2,x5,shiftop,shift); \
+ dct_bfly32o(row3,row4, x3,x4,shiftop,shift); \
+ }
+
+ // load
+ row0 = vld1q_s16(data + 0*8);
+ row1 = vld1q_s16(data + 1*8);
+ row2 = vld1q_s16(data + 2*8);
+ row3 = vld1q_s16(data + 3*8);
+ row4 = vld1q_s16(data + 4*8);
+ row5 = vld1q_s16(data + 5*8);
+ row6 = vld1q_s16(data + 6*8);
+ row7 = vld1q_s16(data + 7*8);
+
+ // add DC bias
+ row0 = vaddq_s16(row0, vsetq_lane_s16(1024, vdupq_n_s16(0), 0));
+
+ // column pass
+ dct_pass(vrshrn_n_s32, 10);
+
+ // 16bit 8x8 transpose
+ {
+// these three map to a single VTRN.16, VTRN.32, and VSWP, respectively.
+// whether compilers actually get this is another story, sadly.
+#define dct_trn16(x, y) { int16x8x2_t t = vtrnq_s16(x, y); x = t.val[0]; y = t.val[1]; }
+#define dct_trn32(x, y) { int32x4x2_t t = vtrnq_s32(vreinterpretq_s32_s16(x), vreinterpretq_s32_s16(y)); x = vreinterpretq_s16_s32(t.val[0]); y = vreinterpretq_s16_s32(t.val[1]); }
+#define dct_trn64(x, y) { int16x8_t x0 = x; int16x8_t y0 = y; x = vcombine_s16(vget_low_s16(x0), vget_low_s16(y0)); y = vcombine_s16(vget_high_s16(x0), vget_high_s16(y0)); }
+
+ // pass 1
+ dct_trn16(row0, row1); // a0b0a2b2a4b4a6b6
+ dct_trn16(row2, row3);
+ dct_trn16(row4, row5);
+ dct_trn16(row6, row7);
+
+ // pass 2
+ dct_trn32(row0, row2); // a0b0c0d0a4b4c4d4
+ dct_trn32(row1, row3);
+ dct_trn32(row4, row6);
+ dct_trn32(row5, row7);
+
+ // pass 3
+ dct_trn64(row0, row4); // a0b0c0d0e0f0g0h0
+ dct_trn64(row1, row5);
+ dct_trn64(row2, row6);
+ dct_trn64(row3, row7);
+
+#undef dct_trn16
+#undef dct_trn32
+#undef dct_trn64
+ }
+
+ // row pass
+ // vrshrn_n_s32 only supports shifts up to 16, we need
+ // 17. so do a non-rounding shift of 16 first then follow
+ // up with a rounding shift by 1.
+ dct_pass(vshrn_n_s32, 16);
+
+ {
+ // pack and round
+ uint8x8_t p0 = vqrshrun_n_s16(row0, 1);
+ uint8x8_t p1 = vqrshrun_n_s16(row1, 1);
+ uint8x8_t p2 = vqrshrun_n_s16(row2, 1);
+ uint8x8_t p3 = vqrshrun_n_s16(row3, 1);
+ uint8x8_t p4 = vqrshrun_n_s16(row4, 1);
+ uint8x8_t p5 = vqrshrun_n_s16(row5, 1);
+ uint8x8_t p6 = vqrshrun_n_s16(row6, 1);
+ uint8x8_t p7 = vqrshrun_n_s16(row7, 1);
+
+ // again, these can translate into one instruction, but often don't.
+#define dct_trn8_8(x, y) { uint8x8x2_t t = vtrn_u8(x, y); x = t.val[0]; y = t.val[1]; }
+#define dct_trn8_16(x, y) { uint16x4x2_t t = vtrn_u16(vreinterpret_u16_u8(x), vreinterpret_u16_u8(y)); x = vreinterpret_u8_u16(t.val[0]); y = vreinterpret_u8_u16(t.val[1]); }
+#define dct_trn8_32(x, y) { uint32x2x2_t t = vtrn_u32(vreinterpret_u32_u8(x), vreinterpret_u32_u8(y)); x = vreinterpret_u8_u32(t.val[0]); y = vreinterpret_u8_u32(t.val[1]); }
+
+ // sadly can't use interleaved stores here since we only write
+ // 8 bytes to each scan line!
+
+ // 8x8 8-bit transpose pass 1
+ dct_trn8_8(p0, p1);
+ dct_trn8_8(p2, p3);
+ dct_trn8_8(p4, p5);
+ dct_trn8_8(p6, p7);
+
+ // pass 2
+ dct_trn8_16(p0, p2);
+ dct_trn8_16(p1, p3);
+ dct_trn8_16(p4, p6);
+ dct_trn8_16(p5, p7);
+
+ // pass 3
+ dct_trn8_32(p0, p4);
+ dct_trn8_32(p1, p5);
+ dct_trn8_32(p2, p6);
+ dct_trn8_32(p3, p7);
+
+ // store
+ vst1_u8(out, p0); out += out_stride;
+ vst1_u8(out, p1); out += out_stride;
+ vst1_u8(out, p2); out += out_stride;
+ vst1_u8(out, p3); out += out_stride;
+ vst1_u8(out, p4); out += out_stride;
+ vst1_u8(out, p5); out += out_stride;
+ vst1_u8(out, p6); out += out_stride;
+ vst1_u8(out, p7);
+
+#undef dct_trn8_8
+#undef dct_trn8_16
+#undef dct_trn8_32
+ }
+
+#undef dct_long_mul
+#undef dct_long_mac
+#undef dct_widen
+#undef dct_wadd
+#undef dct_wsub
+#undef dct_bfly32o
+#undef dct_pass
+}
+
+#endif // STBI_NEON
+
+#define STBI__MARKER_none 0xff
+// if there's a pending marker from the entropy stream, return that
+// otherwise, fetch from the stream and get a marker. if there's no
+// marker, return 0xff, which is never a valid marker value
+static stbi_uc stbi__get_marker(stbi__jpeg *j)
+{
+ stbi_uc x;
+ if (j->marker != STBI__MARKER_none) { x = j->marker; j->marker = STBI__MARKER_none; return x; }
+ x = stbi__get8(j->s);
+ if (x != 0xff) return STBI__MARKER_none;
+ while (x == 0xff)
+ x = stbi__get8(j->s); // consume repeated 0xff fill bytes
+ return x;
+}
+
+// in each scan, we'll have scan_n components, and the order
+// of the components is specified by order[]
+#define STBI__RESTART(x) ((x) >= 0xd0 && (x) <= 0xd7)
+
+// after a restart interval, stbi__jpeg_reset the entropy decoder and
+// the dc prediction
+static void stbi__jpeg_reset(stbi__jpeg *j)
+{
+ j->code_bits = 0;
+ j->code_buffer = 0;
+ j->nomore = 0;
+ j->img_comp[0].dc_pred = j->img_comp[1].dc_pred = j->img_comp[2].dc_pred = j->img_comp[3].dc_pred = 0;
+ j->marker = STBI__MARKER_none;
+ j->todo = j->restart_interval ? j->restart_interval : 0x7fffffff;
+ j->eob_run = 0;
+ // no more than 1<<31 MCUs if no restart_interal? that's plenty safe,
+ // since we don't even allow 1<<30 pixels
+}
+
+static int stbi__parse_entropy_coded_data(stbi__jpeg *z)
+{
+ stbi__jpeg_reset(z);
+ if (!z->progressive) {
+ if (z->scan_n == 1) {
+ int i,j;
+ STBI_SIMD_ALIGN(short, data[64]);
+ int n = z->order[0];
+ // non-interleaved data, we just need to process one block at a time,
+ // in trivial scanline order
+ // number of blocks to do just depends on how many actual "pixels" this
+ // component has, independent of interleaved MCU blocking and such
+ int w = (z->img_comp[n].x+7) >> 3;
+ int h = (z->img_comp[n].y+7) >> 3;
+ for (j=0; j < h; ++j) {
+ for (i=0; i < w; ++i) {
+ int ha = z->img_comp[n].ha;
+ if (!stbi__jpeg_decode_block(z, data, z->huff_dc+z->img_comp[n].hd, z->huff_ac+ha, z->fast_ac[ha], n, z->dequant[z->img_comp[n].tq])) return 0;
+ z->idct_block_kernel(z->img_comp[n].data+z->img_comp[n].w2*j*8+i*8, z->img_comp[n].w2, data);
+ // every data block is an MCU, so countdown the restart interval
+ if (--z->todo <= 0) {
+ if (z->code_bits < 24) stbi__grow_buffer_unsafe(z);
+ // if it's NOT a restart, then just bail, so we get corrupt data
+ // rather than no data
+ if (!STBI__RESTART(z->marker)) return 1;
+ stbi__jpeg_reset(z);
+ }
+ }
+ }
+ return 1;
+ } else { // interleaved
+ int i,j,k,x,y;
+ STBI_SIMD_ALIGN(short, data[64]);
+ for (j=0; j < z->img_mcu_y; ++j) {
+ for (i=0; i < z->img_mcu_x; ++i) {
+ // scan an interleaved mcu... process scan_n components in order
+ for (k=0; k < z->scan_n; ++k) {
+ int n = z->order[k];
+ // scan out an mcu's worth of this component; that's just determined
+ // by the basic H and V specified for the component
+ for (y=0; y < z->img_comp[n].v; ++y) {
+ for (x=0; x < z->img_comp[n].h; ++x) {
+ int x2 = (i*z->img_comp[n].h + x)*8;
+ int y2 = (j*z->img_comp[n].v + y)*8;
+ int ha = z->img_comp[n].ha;
+ if (!stbi__jpeg_decode_block(z, data, z->huff_dc+z->img_comp[n].hd, z->huff_ac+ha, z->fast_ac[ha], n, z->dequant[z->img_comp[n].tq])) return 0;
+ z->idct_block_kernel(z->img_comp[n].data+z->img_comp[n].w2*y2+x2, z->img_comp[n].w2, data);
+ }
+ }
+ }
+ // after all interleaved components, that's an interleaved MCU,
+ // so now count down the restart interval
+ if (--z->todo <= 0) {
+ if (z->code_bits < 24) stbi__grow_buffer_unsafe(z);
+ if (!STBI__RESTART(z->marker)) return 1;
+ stbi__jpeg_reset(z);
+ }
+ }
+ }
+ return 1;
+ }
+ } else {
+ if (z->scan_n == 1) {
+ int i,j;
+ int n = z->order[0];
+ // non-interleaved data, we just need to process one block at a time,
+ // in trivial scanline order
+ // number of blocks to do just depends on how many actual "pixels" this
+ // component has, independent of interleaved MCU blocking and such
+ int w = (z->img_comp[n].x+7) >> 3;
+ int h = (z->img_comp[n].y+7) >> 3;
+ for (j=0; j < h; ++j) {
+ for (i=0; i < w; ++i) {
+ short *data = z->img_comp[n].coeff + 64 * (i + j * z->img_comp[n].coeff_w);
+ if (z->spec_start == 0) {
+ if (!stbi__jpeg_decode_block_prog_dc(z, data, &z->huff_dc[z->img_comp[n].hd], n))
+ return 0;
+ } else {
+ int ha = z->img_comp[n].ha;
+ if (!stbi__jpeg_decode_block_prog_ac(z, data, &z->huff_ac[ha], z->fast_ac[ha]))
+ return 0;
+ }
+ // every data block is an MCU, so countdown the restart interval
+ if (--z->todo <= 0) {
+ if (z->code_bits < 24) stbi__grow_buffer_unsafe(z);
+ if (!STBI__RESTART(z->marker)) return 1;
+ stbi__jpeg_reset(z);
+ }
+ }
+ }
+ return 1;
+ } else { // interleaved
+ int i,j,k,x,y;
+ for (j=0; j < z->img_mcu_y; ++j) {
+ for (i=0; i < z->img_mcu_x; ++i) {
+ // scan an interleaved mcu... process scan_n components in order
+ for (k=0; k < z->scan_n; ++k) {
+ int n = z->order[k];
+ // scan out an mcu's worth of this component; that's just determined
+ // by the basic H and V specified for the component
+ for (y=0; y < z->img_comp[n].v; ++y) {
+ for (x=0; x < z->img_comp[n].h; ++x) {
+ int x2 = (i*z->img_comp[n].h + x);
+ int y2 = (j*z->img_comp[n].v + y);
+ short *data = z->img_comp[n].coeff + 64 * (x2 + y2 * z->img_comp[n].coeff_w);
+ if (!stbi__jpeg_decode_block_prog_dc(z, data, &z->huff_dc[z->img_comp[n].hd], n))
+ return 0;
+ }
+ }
+ }
+ // after all interleaved components, that's an interleaved MCU,
+ // so now count down the restart interval
+ if (--z->todo <= 0) {
+ if (z->code_bits < 24) stbi__grow_buffer_unsafe(z);
+ if (!STBI__RESTART(z->marker)) return 1;
+ stbi__jpeg_reset(z);
+ }
+ }
+ }
+ return 1;
+ }
+ }
+}
+
+static void stbi__jpeg_dequantize(short *data, stbi__uint16 *dequant)
+{
+ int i;
+ for (i=0; i < 64; ++i)
+ data[i] *= dequant[i];
+}
+
+static void stbi__jpeg_finish(stbi__jpeg *z)
+{
+ if (z->progressive) {
+ // dequantize and idct the data
+ int i,j,n;
+ for (n=0; n < z->s->img_n; ++n) {
+ int w = (z->img_comp[n].x+7) >> 3;
+ int h = (z->img_comp[n].y+7) >> 3;
+ for (j=0; j < h; ++j) {
+ for (i=0; i < w; ++i) {
+ short *data = z->img_comp[n].coeff + 64 * (i + j * z->img_comp[n].coeff_w);
+ stbi__jpeg_dequantize(data, z->dequant[z->img_comp[n].tq]);
+ z->idct_block_kernel(z->img_comp[n].data+z->img_comp[n].w2*j*8+i*8, z->img_comp[n].w2, data);
+ }
+ }
+ }
+ }
+}
+
+static int stbi__process_marker(stbi__jpeg *z, int m)
+{
+ int L;
+ switch (m) {
+ case STBI__MARKER_none: // no marker found
+ return stbi__err("expected marker","Corrupt JPEG");
+
+ case 0xDD: // DRI - specify restart interval
+ if (stbi__get16be(z->s) != 4) return stbi__err("bad DRI len","Corrupt JPEG");
+ z->restart_interval = stbi__get16be(z->s);
+ return 1;
+
+ case 0xDB: // DQT - define quantization table
+ L = stbi__get16be(z->s)-2;
+ while (L > 0) {
+ int q = stbi__get8(z->s);
+ int p = q >> 4, sixteen = (p != 0);
+ int t = q & 15,i;
+ if (p != 0 && p != 1) return stbi__err("bad DQT type","Corrupt JPEG");
+ if (t > 3) return stbi__err("bad DQT table","Corrupt JPEG");
+
+ for (i=0; i < 64; ++i)
+ z->dequant[t][stbi__jpeg_dezigzag[i]] = (stbi__uint16)(sixteen ? stbi__get16be(z->s) : stbi__get8(z->s));
+ L -= (sixteen ? 129 : 65);
+ }
+ return L==0;
+
+ case 0xC4: // DHT - define huffman table
+ L = stbi__get16be(z->s)-2;
+ while (L > 0) {
+ stbi_uc *v;
+ int sizes[16],i,n=0;
+ int q = stbi__get8(z->s);
+ int tc = q >> 4;
+ int th = q & 15;
+ if (tc > 1 || th > 3) return stbi__err("bad DHT header","Corrupt JPEG");
+ for (i=0; i < 16; ++i) {
+ sizes[i] = stbi__get8(z->s);
+ n += sizes[i];
+ }
+ if(n > 256) return stbi__err("bad DHT header","Corrupt JPEG"); // Loop over i < n would write past end of values!
+ L -= 17;
+ if (tc == 0) {
+ if (!stbi__build_huffman(z->huff_dc+th, sizes)) return 0;
+ v = z->huff_dc[th].values;
+ } else {
+ if (!stbi__build_huffman(z->huff_ac+th, sizes)) return 0;
+ v = z->huff_ac[th].values;
+ }
+ for (i=0; i < n; ++i)
+ v[i] = stbi__get8(z->s);
+ if (tc != 0)
+ stbi__build_fast_ac(z->fast_ac[th], z->huff_ac + th);
+ L -= n;
+ }
+ return L==0;
+ }
+
+ // check for comment block or APP blocks
+ if ((m >= 0xE0 && m <= 0xEF) || m == 0xFE) {
+ L = stbi__get16be(z->s);
+ if (L < 2) {
+ if (m == 0xFE)
+ return stbi__err("bad COM len","Corrupt JPEG");
+ else
+ return stbi__err("bad APP len","Corrupt JPEG");
+ }
+ L -= 2;
+
+ if (m == 0xE0 && L >= 5) { // JFIF APP0 segment
+ static const unsigned char tag[5] = {'J','F','I','F','\0'};
+ int ok = 1;
+ int i;
+ for (i=0; i < 5; ++i)
+ if (stbi__get8(z->s) != tag[i])
+ ok = 0;
+ L -= 5;
+ if (ok)
+ z->jfif = 1;
+ } else if (m == 0xEE && L >= 12) { // Adobe APP14 segment
+ static const unsigned char tag[6] = {'A','d','o','b','e','\0'};
+ int ok = 1;
+ int i;
+ for (i=0; i < 6; ++i)
+ if (stbi__get8(z->s) != tag[i])
+ ok = 0;
+ L -= 6;
+ if (ok) {
+ stbi__get8(z->s); // version
+ stbi__get16be(z->s); // flags0
+ stbi__get16be(z->s); // flags1
+ z->app14_color_transform = stbi__get8(z->s); // color transform
+ L -= 6;
+ }
+ }
+
+ stbi__skip(z->s, L);
+ return 1;
+ }
+
+ return stbi__err("unknown marker","Corrupt JPEG");
+}
+
+// after we see SOS
+static int stbi__process_scan_header(stbi__jpeg *z)
+{
+ int i;
+ int Ls = stbi__get16be(z->s);
+ z->scan_n = stbi__get8(z->s);
+ if (z->scan_n < 1 || z->scan_n > 4 || z->scan_n > (int) z->s->img_n) return stbi__err("bad SOS component count","Corrupt JPEG");
+ if (Ls != 6+2*z->scan_n) return stbi__err("bad SOS len","Corrupt JPEG");
+ for (i=0; i < z->scan_n; ++i) {
+ int id = stbi__get8(z->s), which;
+ int q = stbi__get8(z->s);
+ for (which = 0; which < z->s->img_n; ++which)
+ if (z->img_comp[which].id == id)
+ break;
+ if (which == z->s->img_n) return 0; // no match
+ z->img_comp[which].hd = q >> 4; if (z->img_comp[which].hd > 3) return stbi__err("bad DC huff","Corrupt JPEG");
+ z->img_comp[which].ha = q & 15; if (z->img_comp[which].ha > 3) return stbi__err("bad AC huff","Corrupt JPEG");
+ z->order[i] = which;
+ }
+
+ {
+ int aa;
+ z->spec_start = stbi__get8(z->s);
+ z->spec_end = stbi__get8(z->s); // should be 63, but might be 0
+ aa = stbi__get8(z->s);
+ z->succ_high = (aa >> 4);
+ z->succ_low = (aa & 15);
+ if (z->progressive) {
+ if (z->spec_start > 63 || z->spec_end > 63 || z->spec_start > z->spec_end || z->succ_high > 13 || z->succ_low > 13)
+ return stbi__err("bad SOS", "Corrupt JPEG");
+ } else {
+ if (z->spec_start != 0) return stbi__err("bad SOS","Corrupt JPEG");
+ if (z->succ_high != 0 || z->succ_low != 0) return stbi__err("bad SOS","Corrupt JPEG");
+ z->spec_end = 63;
+ }
+ }
+
+ return 1;
+}
+
+static int stbi__free_jpeg_components(stbi__jpeg *z, int ncomp, int why)
+{
+ int i;
+ for (i=0; i < ncomp; ++i) {
+ if (z->img_comp[i].raw_data) {
+ STBI_FREE(z->img_comp[i].raw_data);
+ z->img_comp[i].raw_data = NULL;
+ z->img_comp[i].data = NULL;
+ }
+ if (z->img_comp[i].raw_coeff) {
+ STBI_FREE(z->img_comp[i].raw_coeff);
+ z->img_comp[i].raw_coeff = 0;
+ z->img_comp[i].coeff = 0;
+ }
+ if (z->img_comp[i].linebuf) {
+ STBI_FREE(z->img_comp[i].linebuf);
+ z->img_comp[i].linebuf = NULL;
+ }
+ }
+ return why;
+}
+
+static int stbi__process_frame_header(stbi__jpeg *z, int scan)
+{
+ stbi__context *s = z->s;
+ int Lf,p,i,q, h_max=1,v_max=1,c;
+ Lf = stbi__get16be(s); if (Lf < 11) return stbi__err("bad SOF len","Corrupt JPEG"); // JPEG
+ p = stbi__get8(s); if (p != 8) return stbi__err("only 8-bit","JPEG format not supported: 8-bit only"); // JPEG baseline
+ s->img_y = stbi__get16be(s); if (s->img_y == 0) return stbi__err("no header height", "JPEG format not supported: delayed height"); // Legal, but we don't handle it--but neither does IJG
+ s->img_x = stbi__get16be(s); if (s->img_x == 0) return stbi__err("0 width","Corrupt JPEG"); // JPEG requires
+ if (s->img_y > STBI_MAX_DIMENSIONS) return stbi__err("too large","Very large image (corrupt?)");
+ if (s->img_x > STBI_MAX_DIMENSIONS) return stbi__err("too large","Very large image (corrupt?)");
+ c = stbi__get8(s);
+ if (c != 3 && c != 1 && c != 4) return stbi__err("bad component count","Corrupt JPEG");
+ s->img_n = c;
+ for (i=0; i < c; ++i) {
+ z->img_comp[i].data = NULL;
+ z->img_comp[i].linebuf = NULL;
+ }
+
+ if (Lf != 8+3*s->img_n) return stbi__err("bad SOF len","Corrupt JPEG");
+
+ z->rgb = 0;
+ for (i=0; i < s->img_n; ++i) {
+ static const unsigned char rgb[3] = { 'R', 'G', 'B' };
+ z->img_comp[i].id = stbi__get8(s);
+ if (s->img_n == 3 && z->img_comp[i].id == rgb[i])
+ ++z->rgb;
+ q = stbi__get8(s);
+ z->img_comp[i].h = (q >> 4); if (!z->img_comp[i].h || z->img_comp[i].h > 4) return stbi__err("bad H","Corrupt JPEG");
+ z->img_comp[i].v = q & 15; if (!z->img_comp[i].v || z->img_comp[i].v > 4) return stbi__err("bad V","Corrupt JPEG");
+ z->img_comp[i].tq = stbi__get8(s); if (z->img_comp[i].tq > 3) return stbi__err("bad TQ","Corrupt JPEG");
+ }
+
+ if (scan != STBI__SCAN_load) return 1;
+
+ if (!stbi__mad3sizes_valid(s->img_x, s->img_y, s->img_n, 0)) return stbi__err("too large", "Image too large to decode");
+
+ for (i=0; i < s->img_n; ++i) {
+ if (z->img_comp[i].h > h_max) h_max = z->img_comp[i].h;
+ if (z->img_comp[i].v > v_max) v_max = z->img_comp[i].v;
+ }
+
+ // check that plane subsampling factors are integer ratios; our resamplers can't deal with fractional ratios
+ // and I've never seen a non-corrupted JPEG file actually use them
+ for (i=0; i < s->img_n; ++i) {
+ if (h_max % z->img_comp[i].h != 0) return stbi__err("bad H","Corrupt JPEG");
+ if (v_max % z->img_comp[i].v != 0) return stbi__err("bad V","Corrupt JPEG");
+ }
+
+ // compute interleaved mcu info
+ z->img_h_max = h_max;
+ z->img_v_max = v_max;
+ z->img_mcu_w = h_max * 8;
+ z->img_mcu_h = v_max * 8;
+ // these sizes can't be more than 17 bits
+ z->img_mcu_x = (s->img_x + z->img_mcu_w-1) / z->img_mcu_w;
+ z->img_mcu_y = (s->img_y + z->img_mcu_h-1) / z->img_mcu_h;
+
+ for (i=0; i < s->img_n; ++i) {
+ // number of effective pixels (e.g. for non-interleaved MCU)
+ z->img_comp[i].x = (s->img_x * z->img_comp[i].h + h_max-1) / h_max;
+ z->img_comp[i].y = (s->img_y * z->img_comp[i].v + v_max-1) / v_max;
+ // to simplify generation, we'll allocate enough memory to decode
+ // the bogus oversized data from using interleaved MCUs and their
+ // big blocks (e.g. a 16x16 iMCU on an image of width 33); we won't
+ // discard the extra data until colorspace conversion
+ //
+ // img_mcu_x, img_mcu_y: <=17 bits; comp[i].h and .v are <=4 (checked earlier)
+ // so these muls can't overflow with 32-bit ints (which we require)
+ z->img_comp[i].w2 = z->img_mcu_x * z->img_comp[i].h * 8;
+ z->img_comp[i].h2 = z->img_mcu_y * z->img_comp[i].v * 8;
+ z->img_comp[i].coeff = 0;
+ z->img_comp[i].raw_coeff = 0;
+ z->img_comp[i].linebuf = NULL;
+ z->img_comp[i].raw_data = stbi__malloc_mad2(z->img_comp[i].w2, z->img_comp[i].h2, 15);
+ if (z->img_comp[i].raw_data == NULL)
+ return stbi__free_jpeg_components(z, i+1, stbi__err("outofmem", "Out of memory"));
+ // align blocks for idct using mmx/sse
+ z->img_comp[i].data = (stbi_uc*) (((size_t) z->img_comp[i].raw_data + 15) & ~15);
+ if (z->progressive) {
+ // w2, h2 are multiples of 8 (see above)
+ z->img_comp[i].coeff_w = z->img_comp[i].w2 / 8;
+ z->img_comp[i].coeff_h = z->img_comp[i].h2 / 8;
+ z->img_comp[i].raw_coeff = stbi__malloc_mad3(z->img_comp[i].w2, z->img_comp[i].h2, sizeof(short), 15);
+ if (z->img_comp[i].raw_coeff == NULL)
+ return stbi__free_jpeg_components(z, i+1, stbi__err("outofmem", "Out of memory"));
+ z->img_comp[i].coeff = (short*) (((size_t) z->img_comp[i].raw_coeff + 15) & ~15);
+ }
+ }
+
+ return 1;
+}
+
+// use comparisons since in some cases we handle more than one case (e.g. SOF)
+#define stbi__DNL(x) ((x) == 0xdc)
+#define stbi__SOI(x) ((x) == 0xd8)
+#define stbi__EOI(x) ((x) == 0xd9)
+#define stbi__SOF(x) ((x) == 0xc0 || (x) == 0xc1 || (x) == 0xc2)
+#define stbi__SOS(x) ((x) == 0xda)
+
+#define stbi__SOF_progressive(x) ((x) == 0xc2)
+
+static int stbi__decode_jpeg_header(stbi__jpeg *z, int scan)
+{
+ int m;
+ z->jfif = 0;
+ z->app14_color_transform = -1; // valid values are 0,1,2
+ z->marker = STBI__MARKER_none; // initialize cached marker to empty
+ m = stbi__get_marker(z);
+ if (!stbi__SOI(m)) return stbi__err("no SOI","Corrupt JPEG");
+ if (scan == STBI__SCAN_type) return 1;
+ m = stbi__get_marker(z);
+ while (!stbi__SOF(m)) {
+ if (!stbi__process_marker(z,m)) return 0;
+ m = stbi__get_marker(z);
+ while (m == STBI__MARKER_none) {
+ // some files have extra padding after their blocks, so ok, we'll scan
+ if (stbi__at_eof(z->s)) return stbi__err("no SOF", "Corrupt JPEG");
+ m = stbi__get_marker(z);
+ }
+ }
+ z->progressive = stbi__SOF_progressive(m);
+ if (!stbi__process_frame_header(z, scan)) return 0;
+ return 1;
+}
+
+static stbi_uc stbi__skip_jpeg_junk_at_end(stbi__jpeg *j)
+{
+ // some JPEGs have junk at end, skip over it but if we find what looks
+ // like a valid marker, resume there
+ while (!stbi__at_eof(j->s)) {
+ stbi_uc x = stbi__get8(j->s);
+ while (x == 0xff) { // might be a marker
+ if (stbi__at_eof(j->s)) return STBI__MARKER_none;
+ x = stbi__get8(j->s);
+ if (x != 0x00 && x != 0xff) {
+ // not a stuffed zero or lead-in to another marker, looks
+ // like an actual marker, return it
+ return x;
+ }
+ // stuffed zero has x=0 now which ends the loop, meaning we go
+ // back to regular scan loop.
+ // repeated 0xff keeps trying to read the next byte of the marker.
+ }
+ }
+ return STBI__MARKER_none;
+}
+
+// decode image to YCbCr format
+static int stbi__decode_jpeg_image(stbi__jpeg *j)
+{
+ int m;
+ for (m = 0; m < 4; m++) {
+ j->img_comp[m].raw_data = NULL;
+ j->img_comp[m].raw_coeff = NULL;
+ }
+ j->restart_interval = 0;
+ if (!stbi__decode_jpeg_header(j, STBI__SCAN_load)) return 0;
+ m = stbi__get_marker(j);
+ while (!stbi__EOI(m)) {
+ if (stbi__SOS(m)) {
+ if (!stbi__process_scan_header(j)) return 0;
+ if (!stbi__parse_entropy_coded_data(j)) return 0;
+ if (j->marker == STBI__MARKER_none ) {
+ j->marker = stbi__skip_jpeg_junk_at_end(j);
+ // if we reach eof without hitting a marker, stbi__get_marker() below will fail and we'll eventually return 0
+ }
+ m = stbi__get_marker(j);
+ if (STBI__RESTART(m))
+ m = stbi__get_marker(j);
+ } else if (stbi__DNL(m)) {
+ int Ld = stbi__get16be(j->s);
+ stbi__uint32 NL = stbi__get16be(j->s);
+ if (Ld != 4) return stbi__err("bad DNL len", "Corrupt JPEG");
+ if (NL != j->s->img_y) return stbi__err("bad DNL height", "Corrupt JPEG");
+ m = stbi__get_marker(j);
+ } else {
+ if (!stbi__process_marker(j, m)) return 1;
+ m = stbi__get_marker(j);
+ }
+ }
+ if (j->progressive)
+ stbi__jpeg_finish(j);
+ return 1;
+}
+
+// static jfif-centered resampling (across block boundaries)
+
+typedef stbi_uc *(*resample_row_func)(stbi_uc *out, stbi_uc *in0, stbi_uc *in1,
+ int w, int hs);
+
+#define stbi__div4(x) ((stbi_uc) ((x) >> 2))
+
+static stbi_uc *resample_row_1(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs)
+{
+ STBI_NOTUSED(out);
+ STBI_NOTUSED(in_far);
+ STBI_NOTUSED(w);
+ STBI_NOTUSED(hs);
+ return in_near;
+}
+
+static stbi_uc* stbi__resample_row_v_2(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs)
+{
+ // need to generate two samples vertically for every one in input
+ int i;
+ STBI_NOTUSED(hs);
+ for (i=0; i < w; ++i)
+ out[i] = stbi__div4(3*in_near[i] + in_far[i] + 2);
+ return out;
+}
+
+static stbi_uc* stbi__resample_row_h_2(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs)
+{
+ // need to generate two samples horizontally for every one in input
+ int i;
+ stbi_uc *input = in_near;
+
+ if (w == 1) {
+ // if only one sample, can't do any interpolation
+ out[0] = out[1] = input[0];
+ return out;
+ }
+
+ out[0] = input[0];
+ out[1] = stbi__div4(input[0]*3 + input[1] + 2);
+ for (i=1; i < w-1; ++i) {
+ int n = 3*input[i]+2;
+ out[i*2+0] = stbi__div4(n+input[i-1]);
+ out[i*2+1] = stbi__div4(n+input[i+1]);
+ }
+ out[i*2+0] = stbi__div4(input[w-2]*3 + input[w-1] + 2);
+ out[i*2+1] = input[w-1];
+
+ STBI_NOTUSED(in_far);
+ STBI_NOTUSED(hs);
+
+ return out;
+}
+
+#define stbi__div16(x) ((stbi_uc) ((x) >> 4))
+
+static stbi_uc *stbi__resample_row_hv_2(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs)
+{
+ // need to generate 2x2 samples for every one in input
+ int i,t0,t1;
+ if (w == 1) {
+ out[0] = out[1] = stbi__div4(3*in_near[0] + in_far[0] + 2);
+ return out;
+ }
+
+ t1 = 3*in_near[0] + in_far[0];
+ out[0] = stbi__div4(t1+2);
+ for (i=1; i < w; ++i) {
+ t0 = t1;
+ t1 = 3*in_near[i]+in_far[i];
+ out[i*2-1] = stbi__div16(3*t0 + t1 + 8);
+ out[i*2 ] = stbi__div16(3*t1 + t0 + 8);
+ }
+ out[w*2-1] = stbi__div4(t1+2);
+
+ STBI_NOTUSED(hs);
+
+ return out;
+}
+
+#if defined(STBI_SSE2) || defined(STBI_NEON)
+static stbi_uc *stbi__resample_row_hv_2_simd(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs)
+{
+ // need to generate 2x2 samples for every one in input
+ int i=0,t0,t1;
+
+ if (w == 1) {
+ out[0] = out[1] = stbi__div4(3*in_near[0] + in_far[0] + 2);
+ return out;
+ }
+
+ t1 = 3*in_near[0] + in_far[0];
+ // process groups of 8 pixels for as long as we can.
+ // note we can't handle the last pixel in a row in this loop
+ // because we need to handle the filter boundary conditions.
+ for (; i < ((w-1) & ~7); i += 8) {
+#if defined(STBI_SSE2)
+ // load and perform the vertical filtering pass
+ // this uses 3*x + y = 4*x + (y - x)
+ __m128i zero = _mm_setzero_si128();
+ __m128i farb = _mm_loadl_epi64((__m128i *) (in_far + i));
+ __m128i nearb = _mm_loadl_epi64((__m128i *) (in_near + i));
+ __m128i farw = _mm_unpacklo_epi8(farb, zero);
+ __m128i nearw = _mm_unpacklo_epi8(nearb, zero);
+ __m128i diff = _mm_sub_epi16(farw, nearw);
+ __m128i nears = _mm_slli_epi16(nearw, 2);
+ __m128i curr = _mm_add_epi16(nears, diff); // current row
+
+ // horizontal filter works the same based on shifted vers of current
+ // row. "prev" is current row shifted right by 1 pixel; we need to
+ // insert the previous pixel value (from t1).
+ // "next" is current row shifted left by 1 pixel, with first pixel
+ // of next block of 8 pixels added in.
+ __m128i prv0 = _mm_slli_si128(curr, 2);
+ __m128i nxt0 = _mm_srli_si128(curr, 2);
+ __m128i prev = _mm_insert_epi16(prv0, t1, 0);
+ __m128i next = _mm_insert_epi16(nxt0, 3*in_near[i+8] + in_far[i+8], 7);
+
+ // horizontal filter, polyphase implementation since it's convenient:
+ // even pixels = 3*cur + prev = cur*4 + (prev - cur)
+ // odd pixels = 3*cur + next = cur*4 + (next - cur)
+ // note the shared term.
+ __m128i bias = _mm_set1_epi16(8);
+ __m128i curs = _mm_slli_epi16(curr, 2);
+ __m128i prvd = _mm_sub_epi16(prev, curr);
+ __m128i nxtd = _mm_sub_epi16(next, curr);
+ __m128i curb = _mm_add_epi16(curs, bias);
+ __m128i even = _mm_add_epi16(prvd, curb);
+ __m128i odd = _mm_add_epi16(nxtd, curb);
+
+ // interleave even and odd pixels, then undo scaling.
+ __m128i int0 = _mm_unpacklo_epi16(even, odd);
+ __m128i int1 = _mm_unpackhi_epi16(even, odd);
+ __m128i de0 = _mm_srli_epi16(int0, 4);
+ __m128i de1 = _mm_srli_epi16(int1, 4);
+
+ // pack and write output
+ __m128i outv = _mm_packus_epi16(de0, de1);
+ _mm_storeu_si128((__m128i *) (out + i*2), outv);
+#elif defined(STBI_NEON)
+ // load and perform the vertical filtering pass
+ // this uses 3*x + y = 4*x + (y - x)
+ uint8x8_t farb = vld1_u8(in_far + i);
+ uint8x8_t nearb = vld1_u8(in_near + i);
+ int16x8_t diff = vreinterpretq_s16_u16(vsubl_u8(farb, nearb));
+ int16x8_t nears = vreinterpretq_s16_u16(vshll_n_u8(nearb, 2));
+ int16x8_t curr = vaddq_s16(nears, diff); // current row
+
+ // horizontal filter works the same based on shifted vers of current
+ // row. "prev" is current row shifted right by 1 pixel; we need to
+ // insert the previous pixel value (from t1).
+ // "next" is current row shifted left by 1 pixel, with first pixel
+ // of next block of 8 pixels added in.
+ int16x8_t prv0 = vextq_s16(curr, curr, 7);
+ int16x8_t nxt0 = vextq_s16(curr, curr, 1);
+ int16x8_t prev = vsetq_lane_s16(t1, prv0, 0);
+ int16x8_t next = vsetq_lane_s16(3*in_near[i+8] + in_far[i+8], nxt0, 7);
+
+ // horizontal filter, polyphase implementation since it's convenient:
+ // even pixels = 3*cur + prev = cur*4 + (prev - cur)
+ // odd pixels = 3*cur + next = cur*4 + (next - cur)
+ // note the shared term.
+ int16x8_t curs = vshlq_n_s16(curr, 2);
+ int16x8_t prvd = vsubq_s16(prev, curr);
+ int16x8_t nxtd = vsubq_s16(next, curr);
+ int16x8_t even = vaddq_s16(curs, prvd);
+ int16x8_t odd = vaddq_s16(curs, nxtd);
+
+ // undo scaling and round, then store with even/odd phases interleaved
+ uint8x8x2_t o;
+ o.val[0] = vqrshrun_n_s16(even, 4);
+ o.val[1] = vqrshrun_n_s16(odd, 4);
+ vst2_u8(out + i*2, o);
+#endif
+
+ // "previous" value for next iter
+ t1 = 3*in_near[i+7] + in_far[i+7];
+ }
+
+ t0 = t1;
+ t1 = 3*in_near[i] + in_far[i];
+ out[i*2] = stbi__div16(3*t1 + t0 + 8);
+
+ for (++i; i < w; ++i) {
+ t0 = t1;
+ t1 = 3*in_near[i]+in_far[i];
+ out[i*2-1] = stbi__div16(3*t0 + t1 + 8);
+ out[i*2 ] = stbi__div16(3*t1 + t0 + 8);
+ }
+ out[w*2-1] = stbi__div4(t1+2);
+
+ STBI_NOTUSED(hs);
+
+ return out;
+}
+#endif
+
+static stbi_uc *stbi__resample_row_generic(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs)
+{
+ // resample with nearest-neighbor
+ int i,j;
+ STBI_NOTUSED(in_far);
+ for (i=0; i < w; ++i)
+ for (j=0; j < hs; ++j)
+ out[i*hs+j] = in_near[i];
+ return out;
+}
+
+// this is a reduced-precision calculation of YCbCr-to-RGB introduced
+// to make sure the code produces the same results in both SIMD and scalar
+#define stbi__float2fixed(x) (((int) ((x) * 4096.0f + 0.5f)) << 8)
+static void stbi__YCbCr_to_RGB_row(stbi_uc *out, const stbi_uc *y, const stbi_uc *pcb, const stbi_uc *pcr, int count, int step)
+{
+ int i;
+ for (i=0; i < count; ++i) {
+ int y_fixed = (y[i] << 20) + (1<<19); // rounding
+ int r,g,b;
+ int cr = pcr[i] - 128;
+ int cb = pcb[i] - 128;
+ r = y_fixed + cr* stbi__float2fixed(1.40200f);
+ g = y_fixed + (cr*-stbi__float2fixed(0.71414f)) + ((cb*-stbi__float2fixed(0.34414f)) & 0xffff0000);
+ b = y_fixed + cb* stbi__float2fixed(1.77200f);
+ r >>= 20;
+ g >>= 20;
+ b >>= 20;
+ if ((unsigned) r > 255) { if (r < 0) r = 0; else r = 255; }
+ if ((unsigned) g > 255) { if (g < 0) g = 0; else g = 255; }
+ if ((unsigned) b > 255) { if (b < 0) b = 0; else b = 255; }
+ out[0] = (stbi_uc)r;
+ out[1] = (stbi_uc)g;
+ out[2] = (stbi_uc)b;
+ out[3] = 255;
+ out += step;
+ }
+}
+
+#if defined(STBI_SSE2) || defined(STBI_NEON)
+static void stbi__YCbCr_to_RGB_simd(stbi_uc *out, stbi_uc const *y, stbi_uc const *pcb, stbi_uc const *pcr, int count, int step)
+{
+ int i = 0;
+
+#ifdef STBI_SSE2
+ // step == 3 is pretty ugly on the final interleave, and i'm not convinced
+ // it's useful in practice (you wouldn't use it for textures, for example).
+ // so just accelerate step == 4 case.
+ if (step == 4) {
+ // this is a fairly straightforward implementation and not super-optimized.
+ __m128i signflip = _mm_set1_epi8(-0x80);
+ __m128i cr_const0 = _mm_set1_epi16( (short) ( 1.40200f*4096.0f+0.5f));
+ __m128i cr_const1 = _mm_set1_epi16( - (short) ( 0.71414f*4096.0f+0.5f));
+ __m128i cb_const0 = _mm_set1_epi16( - (short) ( 0.34414f*4096.0f+0.5f));
+ __m128i cb_const1 = _mm_set1_epi16( (short) ( 1.77200f*4096.0f+0.5f));
+ __m128i y_bias = _mm_set1_epi8((char) (unsigned char) 128);
+ __m128i xw = _mm_set1_epi16(255); // alpha channel
+
+ for (; i+7 < count; i += 8) {
+ // load
+ __m128i y_bytes = _mm_loadl_epi64((__m128i *) (y+i));
+ __m128i cr_bytes = _mm_loadl_epi64((__m128i *) (pcr+i));
+ __m128i cb_bytes = _mm_loadl_epi64((__m128i *) (pcb+i));
+ __m128i cr_biased = _mm_xor_si128(cr_bytes, signflip); // -128
+ __m128i cb_biased = _mm_xor_si128(cb_bytes, signflip); // -128
+
+ // unpack to short (and left-shift cr, cb by 8)
+ __m128i yw = _mm_unpacklo_epi8(y_bias, y_bytes);
+ __m128i crw = _mm_unpacklo_epi8(_mm_setzero_si128(), cr_biased);
+ __m128i cbw = _mm_unpacklo_epi8(_mm_setzero_si128(), cb_biased);
+
+ // color transform
+ __m128i yws = _mm_srli_epi16(yw, 4);
+ __m128i cr0 = _mm_mulhi_epi16(cr_const0, crw);
+ __m128i cb0 = _mm_mulhi_epi16(cb_const0, cbw);
+ __m128i cb1 = _mm_mulhi_epi16(cbw, cb_const1);
+ __m128i cr1 = _mm_mulhi_epi16(crw, cr_const1);
+ __m128i rws = _mm_add_epi16(cr0, yws);
+ __m128i gwt = _mm_add_epi16(cb0, yws);
+ __m128i bws = _mm_add_epi16(yws, cb1);
+ __m128i gws = _mm_add_epi16(gwt, cr1);
+
+ // descale
+ __m128i rw = _mm_srai_epi16(rws, 4);
+ __m128i bw = _mm_srai_epi16(bws, 4);
+ __m128i gw = _mm_srai_epi16(gws, 4);
+
+ // back to byte, set up for transpose
+ __m128i brb = _mm_packus_epi16(rw, bw);
+ __m128i gxb = _mm_packus_epi16(gw, xw);
+
+ // transpose to interleave channels
+ __m128i t0 = _mm_unpacklo_epi8(brb, gxb);
+ __m128i t1 = _mm_unpackhi_epi8(brb, gxb);
+ __m128i o0 = _mm_unpacklo_epi16(t0, t1);
+ __m128i o1 = _mm_unpackhi_epi16(t0, t1);
+
+ // store
+ _mm_storeu_si128((__m128i *) (out + 0), o0);
+ _mm_storeu_si128((__m128i *) (out + 16), o1);
+ out += 32;
+ }
+ }
+#endif
+
+#ifdef STBI_NEON
+ // in this version, step=3 support would be easy to add. but is there demand?
+ if (step == 4) {
+ // this is a fairly straightforward implementation and not super-optimized.
+ uint8x8_t signflip = vdup_n_u8(0x80);
+ int16x8_t cr_const0 = vdupq_n_s16( (short) ( 1.40200f*4096.0f+0.5f));
+ int16x8_t cr_const1 = vdupq_n_s16( - (short) ( 0.71414f*4096.0f+0.5f));
+ int16x8_t cb_const0 = vdupq_n_s16( - (short) ( 0.34414f*4096.0f+0.5f));
+ int16x8_t cb_const1 = vdupq_n_s16( (short) ( 1.77200f*4096.0f+0.5f));
+
+ for (; i+7 < count; i += 8) {
+ // load
+ uint8x8_t y_bytes = vld1_u8(y + i);
+ uint8x8_t cr_bytes = vld1_u8(pcr + i);
+ uint8x8_t cb_bytes = vld1_u8(pcb + i);
+ int8x8_t cr_biased = vreinterpret_s8_u8(vsub_u8(cr_bytes, signflip));
+ int8x8_t cb_biased = vreinterpret_s8_u8(vsub_u8(cb_bytes, signflip));
+
+ // expand to s16
+ int16x8_t yws = vreinterpretq_s16_u16(vshll_n_u8(y_bytes, 4));
+ int16x8_t crw = vshll_n_s8(cr_biased, 7);
+ int16x8_t cbw = vshll_n_s8(cb_biased, 7);
+
+ // color transform
+ int16x8_t cr0 = vqdmulhq_s16(crw, cr_const0);
+ int16x8_t cb0 = vqdmulhq_s16(cbw, cb_const0);
+ int16x8_t cr1 = vqdmulhq_s16(crw, cr_const1);
+ int16x8_t cb1 = vqdmulhq_s16(cbw, cb_const1);
+ int16x8_t rws = vaddq_s16(yws, cr0);
+ int16x8_t gws = vaddq_s16(vaddq_s16(yws, cb0), cr1);
+ int16x8_t bws = vaddq_s16(yws, cb1);
+
+ // undo scaling, round, convert to byte
+ uint8x8x4_t o;
+ o.val[0] = vqrshrun_n_s16(rws, 4);
+ o.val[1] = vqrshrun_n_s16(gws, 4);
+ o.val[2] = vqrshrun_n_s16(bws, 4);
+ o.val[3] = vdup_n_u8(255);
+
+ // store, interleaving r/g/b/a
+ vst4_u8(out, o);
+ out += 8*4;
+ }
+ }
+#endif
+
+ for (; i < count; ++i) {
+ int y_fixed = (y[i] << 20) + (1<<19); // rounding
+ int r,g,b;
+ int cr = pcr[i] - 128;
+ int cb = pcb[i] - 128;
+ r = y_fixed + cr* stbi__float2fixed(1.40200f);
+ g = y_fixed + cr*-stbi__float2fixed(0.71414f) + ((cb*-stbi__float2fixed(0.34414f)) & 0xffff0000);
+ b = y_fixed + cb* stbi__float2fixed(1.77200f);
+ r >>= 20;
+ g >>= 20;
+ b >>= 20;
+ if ((unsigned) r > 255) { if (r < 0) r = 0; else r = 255; }
+ if ((unsigned) g > 255) { if (g < 0) g = 0; else g = 255; }
+ if ((unsigned) b > 255) { if (b < 0) b = 0; else b = 255; }
+ out[0] = (stbi_uc)r;
+ out[1] = (stbi_uc)g;
+ out[2] = (stbi_uc)b;
+ out[3] = 255;
+ out += step;
+ }
+}
+#endif
+
+// set up the kernels
+static void stbi__setup_jpeg(stbi__jpeg *j)
+{
+ j->idct_block_kernel = stbi__idct_block;
+ j->YCbCr_to_RGB_kernel = stbi__YCbCr_to_RGB_row;
+ j->resample_row_hv_2_kernel = stbi__resample_row_hv_2;
+
+#ifdef STBI_SSE2
+ if (stbi__sse2_available()) {
+ j->idct_block_kernel = stbi__idct_simd;
+ j->YCbCr_to_RGB_kernel = stbi__YCbCr_to_RGB_simd;
+ j->resample_row_hv_2_kernel = stbi__resample_row_hv_2_simd;
+ }
+#endif
+
+#ifdef STBI_NEON
+ j->idct_block_kernel = stbi__idct_simd;
+ j->YCbCr_to_RGB_kernel = stbi__YCbCr_to_RGB_simd;
+ j->resample_row_hv_2_kernel = stbi__resample_row_hv_2_simd;
+#endif
+}
+
+// clean up the temporary component buffers
+static void stbi__cleanup_jpeg(stbi__jpeg *j)
+{
+ stbi__free_jpeg_components(j, j->s->img_n, 0);
+}
+
+typedef struct
+{
+ resample_row_func resample;
+ stbi_uc *line0,*line1;
+ int hs,vs; // expansion factor in each axis
+ int w_lores; // horizontal pixels pre-expansion
+ int ystep; // how far through vertical expansion we are
+ int ypos; // which pre-expansion row we're on
+} stbi__resample;
+
+// fast 0..255 * 0..255 => 0..255 rounded multiplication
+static stbi_uc stbi__blinn_8x8(stbi_uc x, stbi_uc y)
+{
+ unsigned int t = x*y + 128;
+ return (stbi_uc) ((t + (t >>8)) >> 8);
+}
+
+static stbi_uc *load_jpeg_image(stbi__jpeg *z, int *out_x, int *out_y, int *comp, int req_comp)
+{
+ int n, decode_n, is_rgb;
+ z->s->img_n = 0; // make stbi__cleanup_jpeg safe
+
+ // validate req_comp
+ if (req_comp < 0 || req_comp > 4) return stbi__errpuc("bad req_comp", "Internal error");
+
+ // load a jpeg image from whichever source, but leave in YCbCr format
+ if (!stbi__decode_jpeg_image(z)) { stbi__cleanup_jpeg(z); return NULL; }
+
+ // determine actual number of components to generate
+ n = req_comp ? req_comp : z->s->img_n >= 3 ? 3 : 1;
+
+ is_rgb = z->s->img_n == 3 && (z->rgb == 3 || (z->app14_color_transform == 0 && !z->jfif));
+
+ if (z->s->img_n == 3 && n < 3 && !is_rgb)
+ decode_n = 1;
+ else
+ decode_n = z->s->img_n;
+
+ // nothing to do if no components requested; check this now to avoid
+ // accessing uninitialized coutput[0] later
+ if (decode_n <= 0) { stbi__cleanup_jpeg(z); return NULL; }
+
+ // resample and color-convert
+ {
+ int k;
+ unsigned int i,j;
+ stbi_uc *output;
+ stbi_uc *coutput[4] = { NULL, NULL, NULL, NULL };
+
+ stbi__resample res_comp[4];
+
+ for (k=0; k < decode_n; ++k) {
+ stbi__resample *r = &res_comp[k];
+
+ // allocate line buffer big enough for upsampling off the edges
+ // with upsample factor of 4
+ z->img_comp[k].linebuf = (stbi_uc *) stbi__malloc(z->s->img_x + 3);
+ if (!z->img_comp[k].linebuf) { stbi__cleanup_jpeg(z); return stbi__errpuc("outofmem", "Out of memory"); }
+
+ r->hs = z->img_h_max / z->img_comp[k].h;
+ r->vs = z->img_v_max / z->img_comp[k].v;
+ r->ystep = r->vs >> 1;
+ r->w_lores = (z->s->img_x + r->hs-1) / r->hs;
+ r->ypos = 0;
+ r->line0 = r->line1 = z->img_comp[k].data;
+
+ if (r->hs == 1 && r->vs == 1) r->resample = resample_row_1;
+ else if (r->hs == 1 && r->vs == 2) r->resample = stbi__resample_row_v_2;
+ else if (r->hs == 2 && r->vs == 1) r->resample = stbi__resample_row_h_2;
+ else if (r->hs == 2 && r->vs == 2) r->resample = z->resample_row_hv_2_kernel;
+ else r->resample = stbi__resample_row_generic;
+ }
+
+ // can't error after this so, this is safe
+ output = (stbi_uc *) stbi__malloc_mad3(n, z->s->img_x, z->s->img_y, 1);
+ if (!output) { stbi__cleanup_jpeg(z); return stbi__errpuc("outofmem", "Out of memory"); }
+
+ // now go ahead and resample
+ for (j=0; j < z->s->img_y; ++j) {
+ stbi_uc *out = output + n * z->s->img_x * j;
+ for (k=0; k < decode_n; ++k) {
+ stbi__resample *r = &res_comp[k];
+ int y_bot = r->ystep >= (r->vs >> 1);
+ coutput[k] = r->resample(z->img_comp[k].linebuf,
+ y_bot ? r->line1 : r->line0,
+ y_bot ? r->line0 : r->line1,
+ r->w_lores, r->hs);
+ if (++r->ystep >= r->vs) {
+ r->ystep = 0;
+ r->line0 = r->line1;
+ if (++r->ypos < z->img_comp[k].y)
+ r->line1 += z->img_comp[k].w2;
+ }
+ }
+ if (n >= 3) {
+ stbi_uc *y = coutput[0];
+ if (z->s->img_n == 3) {
+ if (is_rgb) {
+ for (i=0; i < z->s->img_x; ++i) {
+ out[0] = y[i];
+ out[1] = coutput[1][i];
+ out[2] = coutput[2][i];
+ out[3] = 255;
+ out += n;
+ }
+ } else {
+ z->YCbCr_to_RGB_kernel(out, y, coutput[1], coutput[2], z->s->img_x, n);
+ }
+ } else if (z->s->img_n == 4) {
+ if (z->app14_color_transform == 0) { // CMYK
+ for (i=0; i < z->s->img_x; ++i) {
+ stbi_uc m = coutput[3][i];
+ out[0] = stbi__blinn_8x8(coutput[0][i], m);
+ out[1] = stbi__blinn_8x8(coutput[1][i], m);
+ out[2] = stbi__blinn_8x8(coutput[2][i], m);
+ out[3] = 255;
+ out += n;
+ }
+ } else if (z->app14_color_transform == 2) { // YCCK
+ z->YCbCr_to_RGB_kernel(out, y, coutput[1], coutput[2], z->s->img_x, n);
+ for (i=0; i < z->s->img_x; ++i) {
+ stbi_uc m = coutput[3][i];
+ out[0] = stbi__blinn_8x8(255 - out[0], m);
+ out[1] = stbi__blinn_8x8(255 - out[1], m);
+ out[2] = stbi__blinn_8x8(255 - out[2], m);
+ out += n;
+ }
+ } else { // YCbCr + alpha? Ignore the fourth channel for now
+ z->YCbCr_to_RGB_kernel(out, y, coutput[1], coutput[2], z->s->img_x, n);
+ }
+ } else
+ for (i=0; i < z->s->img_x; ++i) {
+ out[0] = out[1] = out[2] = y[i];
+ out[3] = 255; // not used if n==3
+ out += n;
+ }
+ } else {
+ if (is_rgb) {
+ if (n == 1)
+ for (i=0; i < z->s->img_x; ++i)
+ *out++ = stbi__compute_y(coutput[0][i], coutput[1][i], coutput[2][i]);
+ else {
+ for (i=0; i < z->s->img_x; ++i, out += 2) {
+ out[0] = stbi__compute_y(coutput[0][i], coutput[1][i], coutput[2][i]);
+ out[1] = 255;
+ }
+ }
+ } else if (z->s->img_n == 4 && z->app14_color_transform == 0) {
+ for (i=0; i < z->s->img_x; ++i) {
+ stbi_uc m = coutput[3][i];
+ stbi_uc r = stbi__blinn_8x8(coutput[0][i], m);
+ stbi_uc g = stbi__blinn_8x8(coutput[1][i], m);
+ stbi_uc b = stbi__blinn_8x8(coutput[2][i], m);
+ out[0] = stbi__compute_y(r, g, b);
+ out[1] = 255;
+ out += n;
+ }
+ } else if (z->s->img_n == 4 && z->app14_color_transform == 2) {
+ for (i=0; i < z->s->img_x; ++i) {
+ out[0] = stbi__blinn_8x8(255 - coutput[0][i], coutput[3][i]);
+ out[1] = 255;
+ out += n;
+ }
+ } else {
+ stbi_uc *y = coutput[0];
+ if (n == 1)
+ for (i=0; i < z->s->img_x; ++i) out[i] = y[i];
+ else
+ for (i=0; i < z->s->img_x; ++i) { *out++ = y[i]; *out++ = 255; }
+ }
+ }
+ }
+ stbi__cleanup_jpeg(z);
+ *out_x = z->s->img_x;
+ *out_y = z->s->img_y;
+ if (comp) *comp = z->s->img_n >= 3 ? 3 : 1; // report original components, not output
+ return output;
+ }
+}
+
+static void *stbi__jpeg_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri)
+{
+ unsigned char* result;
+ stbi__jpeg* j = (stbi__jpeg*) stbi__malloc(sizeof(stbi__jpeg));
+ if (!j) return stbi__errpuc("outofmem", "Out of memory");
+ memset(j, 0, sizeof(stbi__jpeg));
+ STBI_NOTUSED(ri);
+ j->s = s;
+ stbi__setup_jpeg(j);
+ result = load_jpeg_image(j, x,y,comp,req_comp);
+ STBI_FREE(j);
+ return result;
+}
+
+static int stbi__jpeg_test(stbi__context *s)
+{
+ int r;
+ stbi__jpeg* j = (stbi__jpeg*)stbi__malloc(sizeof(stbi__jpeg));
+ if (!j) return stbi__err("outofmem", "Out of memory");
+ memset(j, 0, sizeof(stbi__jpeg));
+ j->s = s;
+ stbi__setup_jpeg(j);
+ r = stbi__decode_jpeg_header(j, STBI__SCAN_type);
+ stbi__rewind(s);
+ STBI_FREE(j);
+ return r;
+}
+
+static int stbi__jpeg_info_raw(stbi__jpeg *j, int *x, int *y, int *comp)
+{
+ if (!stbi__decode_jpeg_header(j, STBI__SCAN_header)) {
+ stbi__rewind( j->s );
+ return 0;
+ }
+ if (x) *x = j->s->img_x;
+ if (y) *y = j->s->img_y;
+ if (comp) *comp = j->s->img_n >= 3 ? 3 : 1;
+ return 1;
+}
+
+static int stbi__jpeg_info(stbi__context *s, int *x, int *y, int *comp)
+{
+ int result;
+ stbi__jpeg* j = (stbi__jpeg*) (stbi__malloc(sizeof(stbi__jpeg)));
+ if (!j) return stbi__err("outofmem", "Out of memory");
+ memset(j, 0, sizeof(stbi__jpeg));
+ j->s = s;
+ result = stbi__jpeg_info_raw(j, x, y, comp);
+ STBI_FREE(j);
+ return result;
+}
+#endif
+
+// public domain zlib decode v0.2 Sean Barrett 2006-11-18
+// simple implementation
+// - all input must be provided in an upfront buffer
+// - all output is written to a single output buffer (can malloc/realloc)
+// performance
+// - fast huffman
+
+#ifndef STBI_NO_ZLIB
+
+// fast-way is faster to check than jpeg huffman, but slow way is slower
+#define STBI__ZFAST_BITS 9 // accelerate all cases in default tables
+#define STBI__ZFAST_MASK ((1 << STBI__ZFAST_BITS) - 1)
+#define STBI__ZNSYMS 288 // number of symbols in literal/length alphabet
+
+// zlib-style huffman encoding
+// (jpegs packs from left, zlib from right, so can't share code)
+typedef struct
+{
+ stbi__uint16 fast[1 << STBI__ZFAST_BITS];
+ stbi__uint16 firstcode[16];
+ int maxcode[17];
+ stbi__uint16 firstsymbol[16];
+ stbi_uc size[STBI__ZNSYMS];
+ stbi__uint16 value[STBI__ZNSYMS];
+} stbi__zhuffman;
+
+stbi_inline static int stbi__bitreverse16(int n)
+{
+ n = ((n & 0xAAAA) >> 1) | ((n & 0x5555) << 1);
+ n = ((n & 0xCCCC) >> 2) | ((n & 0x3333) << 2);
+ n = ((n & 0xF0F0) >> 4) | ((n & 0x0F0F) << 4);
+ n = ((n & 0xFF00) >> 8) | ((n & 0x00FF) << 8);
+ return n;
+}
+
+stbi_inline static int stbi__bit_reverse(int v, int bits)
+{
+ STBI_ASSERT(bits <= 16);
+ // to bit reverse n bits, reverse 16 and shift
+ // e.g. 11 bits, bit reverse and shift away 5
+ return stbi__bitreverse16(v) >> (16-bits);
+}
+
+static int stbi__zbuild_huffman(stbi__zhuffman *z, const stbi_uc *sizelist, int num)
+{
+ int i,k=0;
+ int code, next_code[16], sizes[17];
+
+ // DEFLATE spec for generating codes
+ memset(sizes, 0, sizeof(sizes));
+ memset(z->fast, 0, sizeof(z->fast));
+ for (i=0; i < num; ++i)
+ ++sizes[sizelist[i]];
+ sizes[0] = 0;
+ for (i=1; i < 16; ++i)
+ if (sizes[i] > (1 << i))
+ return stbi__err("bad sizes", "Corrupt PNG");
+ code = 0;
+ for (i=1; i < 16; ++i) {
+ next_code[i] = code;
+ z->firstcode[i] = (stbi__uint16) code;
+ z->firstsymbol[i] = (stbi__uint16) k;
+ code = (code + sizes[i]);
+ if (sizes[i])
+ if (code-1 >= (1 << i)) return stbi__err("bad codelengths","Corrupt PNG");
+ z->maxcode[i] = code << (16-i); // preshift for inner loop
+ code <<= 1;
+ k += sizes[i];
+ }
+ z->maxcode[16] = 0x10000; // sentinel
+ for (i=0; i < num; ++i) {
+ int s = sizelist[i];
+ if (s) {
+ int c = next_code[s] - z->firstcode[s] + z->firstsymbol[s];
+ stbi__uint16 fastv = (stbi__uint16) ((s << 9) | i);
+ z->size [c] = (stbi_uc ) s;
+ z->value[c] = (stbi__uint16) i;
+ if (s <= STBI__ZFAST_BITS) {
+ int j = stbi__bit_reverse(next_code[s],s);
+ while (j < (1 << STBI__ZFAST_BITS)) {
+ z->fast[j] = fastv;
+ j += (1 << s);
+ }
+ }
+ ++next_code[s];
+ }
+ }
+ return 1;
+}
+
+// zlib-from-memory implementation for PNG reading
+// because PNG allows splitting the zlib stream arbitrarily,
+// and it's annoying structurally to have PNG call ZLIB call PNG,
+// we require PNG read all the IDATs and combine them into a single
+// memory buffer
+
+typedef struct
+{
+ stbi_uc *zbuffer, *zbuffer_end;
+ int num_bits;
+ int hit_zeof_once;
+ stbi__uint32 code_buffer;
+
+ char *zout;
+ char *zout_start;
+ char *zout_end;
+ int z_expandable;
+
+ stbi__zhuffman z_length, z_distance;
+} stbi__zbuf;
+
+stbi_inline static int stbi__zeof(stbi__zbuf *z)
+{
+ return (z->zbuffer >= z->zbuffer_end);
+}
+
+stbi_inline static stbi_uc stbi__zget8(stbi__zbuf *z)
+{
+ return stbi__zeof(z) ? 0 : *z->zbuffer++;
+}
+
+static void stbi__fill_bits(stbi__zbuf *z)
+{
+ do {
+ if (z->code_buffer >= (1U << z->num_bits)) {
+ z->zbuffer = z->zbuffer_end; /* treat this as EOF so we fail. */
+ return;
+ }
+ z->code_buffer |= (unsigned int) stbi__zget8(z) << z->num_bits;
+ z->num_bits += 8;
+ } while (z->num_bits <= 24);
+}
+
+stbi_inline static unsigned int stbi__zreceive(stbi__zbuf *z, int n)
+{
+ unsigned int k;
+ if (z->num_bits < n) stbi__fill_bits(z);
+ k = z->code_buffer & ((1 << n) - 1);
+ z->code_buffer >>= n;
+ z->num_bits -= n;
+ return k;
+}
+
+static int stbi__zhuffman_decode_slowpath(stbi__zbuf *a, stbi__zhuffman *z)
+{
+ int b,s,k;
+ // not resolved by fast table, so compute it the slow way
+ // use jpeg approach, which requires MSbits at top
+ k = stbi__bit_reverse(a->code_buffer, 16);
+ for (s=STBI__ZFAST_BITS+1; ; ++s)
+ if (k < z->maxcode[s])
+ break;
+ if (s >= 16) return -1; // invalid code!
+ // code size is s, so:
+ b = (k >> (16-s)) - z->firstcode[s] + z->firstsymbol[s];
+ if (b >= STBI__ZNSYMS) return -1; // some data was corrupt somewhere!
+ if (z->size[b] != s) return -1; // was originally an assert, but report failure instead.
+ a->code_buffer >>= s;
+ a->num_bits -= s;
+ return z->value[b];
+}
+
+stbi_inline static int stbi__zhuffman_decode(stbi__zbuf *a, stbi__zhuffman *z)
+{
+ int b,s;
+ if (a->num_bits < 16) {
+ if (stbi__zeof(a)) {
+ if (!a->hit_zeof_once) {
+ // This is the first time we hit eof, insert 16 extra padding btis
+ // to allow us to keep going; if we actually consume any of them
+ // though, that is invalid data. This is caught later.
+ a->hit_zeof_once = 1;
+ a->num_bits += 16; // add 16 implicit zero bits
+ } else {
+ // We already inserted our extra 16 padding bits and are again
+ // out, this stream is actually prematurely terminated.
+ return -1;
+ }
+ } else {
+ stbi__fill_bits(a);
+ }
+ }
+ b = z->fast[a->code_buffer & STBI__ZFAST_MASK];
+ if (b) {
+ s = b >> 9;
+ a->code_buffer >>= s;
+ a->num_bits -= s;
+ return b & 511;
+ }
+ return stbi__zhuffman_decode_slowpath(a, z);
+}
+
+static int stbi__zexpand(stbi__zbuf *z, char *zout, int n) // need to make room for n bytes
+{
+ char *q;
+ unsigned int cur, limit, old_limit;
+ z->zout = zout;
+ if (!z->z_expandable) return stbi__err("output buffer limit","Corrupt PNG");
+ cur = (unsigned int) (z->zout - z->zout_start);
+ limit = old_limit = (unsigned) (z->zout_end - z->zout_start);
+ if (UINT_MAX - cur < (unsigned) n) return stbi__err("outofmem", "Out of memory");
+ while (cur + n > limit) {
+ if(limit > UINT_MAX / 2) return stbi__err("outofmem", "Out of memory");
+ limit *= 2;
+ }
+ q = (char *) STBI_REALLOC_SIZED(z->zout_start, old_limit, limit);
+ STBI_NOTUSED(old_limit);
+ if (q == NULL) return stbi__err("outofmem", "Out of memory");
+ z->zout_start = q;
+ z->zout = q + cur;
+ z->zout_end = q + limit;
+ return 1;
+}
+
+static const int stbi__zlength_base[31] = {
+ 3,4,5,6,7,8,9,10,11,13,
+ 15,17,19,23,27,31,35,43,51,59,
+ 67,83,99,115,131,163,195,227,258,0,0 };
+
+static const int stbi__zlength_extra[31]=
+{ 0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0,0,0 };
+
+static const int stbi__zdist_base[32] = { 1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193,
+257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577,0,0};
+
+static const int stbi__zdist_extra[32] =
+{ 0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13};
+
+static int stbi__parse_huffman_block(stbi__zbuf *a)
+{
+ char *zout = a->zout;
+ for(;;) {
+ int z = stbi__zhuffman_decode(a, &a->z_length);
+ if (z < 256) {
+ if (z < 0) return stbi__err("bad huffman code","Corrupt PNG"); // error in huffman codes
+ if (zout >= a->zout_end) {
+ if (!stbi__zexpand(a, zout, 1)) return 0;
+ zout = a->zout;
+ }
+ *zout++ = (char) z;
+ } else {
+ stbi_uc *p;
+ int len,dist;
+ if (z == 256) {
+ a->zout = zout;
+ if (a->hit_zeof_once && a->num_bits < 16) {
+ // The first time we hit zeof, we inserted 16 extra zero bits into our bit
+ // buffer so the decoder can just do its speculative decoding. But if we
+ // actually consumed any of those bits (which is the case when num_bits < 16),
+ // the stream actually read past the end so it is malformed.
+ return stbi__err("unexpected end","Corrupt PNG");
+ }
+ return 1;
+ }
+ if (z >= 286) return stbi__err("bad huffman code","Corrupt PNG"); // per DEFLATE, length codes 286 and 287 must not appear in compressed data
+ z -= 257;
+ len = stbi__zlength_base[z];
+ if (stbi__zlength_extra[z]) len += stbi__zreceive(a, stbi__zlength_extra[z]);
+ z = stbi__zhuffman_decode(a, &a->z_distance);
+ if (z < 0 || z >= 30) return stbi__err("bad huffman code","Corrupt PNG"); // per DEFLATE, distance codes 30 and 31 must not appear in compressed data
+ dist = stbi__zdist_base[z];
+ if (stbi__zdist_extra[z]) dist += stbi__zreceive(a, stbi__zdist_extra[z]);
+ if (zout - a->zout_start < dist) return stbi__err("bad dist","Corrupt PNG");
+ if (len > a->zout_end - zout) {
+ if (!stbi__zexpand(a, zout, len)) return 0;
+ zout = a->zout;
+ }
+ p = (stbi_uc *) (zout - dist);
+ if (dist == 1) { // run of one byte; common in images.
+ stbi_uc v = *p;
+ if (len) { do *zout++ = v; while (--len); }
+ } else {
+ if (len) { do *zout++ = *p++; while (--len); }
+ }
+ }
+ }
+}
+
+static int stbi__compute_huffman_codes(stbi__zbuf *a)
+{
+ static const stbi_uc length_dezigzag[19] = { 16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15 };
+ stbi__zhuffman z_codelength;
+ stbi_uc lencodes[286+32+137];//padding for maximum single op
+ stbi_uc codelength_sizes[19];
+ int i,n;
+
+ int hlit = stbi__zreceive(a,5) + 257;
+ int hdist = stbi__zreceive(a,5) + 1;
+ int hclen = stbi__zreceive(a,4) + 4;
+ int ntot = hlit + hdist;
+
+ memset(codelength_sizes, 0, sizeof(codelength_sizes));
+ for (i=0; i < hclen; ++i) {
+ int s = stbi__zreceive(a,3);
+ codelength_sizes[length_dezigzag[i]] = (stbi_uc) s;
+ }
+ if (!stbi__zbuild_huffman(&z_codelength, codelength_sizes, 19)) return 0;
+
+ n = 0;
+ while (n < ntot) {
+ int c = stbi__zhuffman_decode(a, &z_codelength);
+ if (c < 0 || c >= 19) return stbi__err("bad codelengths", "Corrupt PNG");
+ if (c < 16)
+ lencodes[n++] = (stbi_uc) c;
+ else {
+ stbi_uc fill = 0;
+ if (c == 16) {
+ c = stbi__zreceive(a,2)+3;
+ if (n == 0) return stbi__err("bad codelengths", "Corrupt PNG");
+ fill = lencodes[n-1];
+ } else if (c == 17) {
+ c = stbi__zreceive(a,3)+3;
+ } else if (c == 18) {
+ c = stbi__zreceive(a,7)+11;
+ } else {
+ return stbi__err("bad codelengths", "Corrupt PNG");
+ }
+ if (ntot - n < c) return stbi__err("bad codelengths", "Corrupt PNG");
+ memset(lencodes+n, fill, c);
+ n += c;
+ }
+ }
+ if (n != ntot) return stbi__err("bad codelengths","Corrupt PNG");
+ if (!stbi__zbuild_huffman(&a->z_length, lencodes, hlit)) return 0;
+ if (!stbi__zbuild_huffman(&a->z_distance, lencodes+hlit, hdist)) return 0;
+ return 1;
+}
+
+static int stbi__parse_uncompressed_block(stbi__zbuf *a)
+{
+ stbi_uc header[4];
+ int len,nlen,k;
+ if (a->num_bits & 7)
+ stbi__zreceive(a, a->num_bits & 7); // discard
+ // drain the bit-packed data into header
+ k = 0;
+ while (a->num_bits > 0) {
+ header[k++] = (stbi_uc) (a->code_buffer & 255); // suppress MSVC run-time check
+ a->code_buffer >>= 8;
+ a->num_bits -= 8;
+ }
+ if (a->num_bits < 0) return stbi__err("zlib corrupt","Corrupt PNG");
+ // now fill header the normal way
+ while (k < 4)
+ header[k++] = stbi__zget8(a);
+ len = header[1] * 256 + header[0];
+ nlen = header[3] * 256 + header[2];
+ if (nlen != (len ^ 0xffff)) return stbi__err("zlib corrupt","Corrupt PNG");
+ if (a->zbuffer + len > a->zbuffer_end) return stbi__err("read past buffer","Corrupt PNG");
+ if (a->zout + len > a->zout_end)
+ if (!stbi__zexpand(a, a->zout, len)) return 0;
+ memcpy(a->zout, a->zbuffer, len);
+ a->zbuffer += len;
+ a->zout += len;
+ return 1;
+}
+
+static int stbi__parse_zlib_header(stbi__zbuf *a)
+{
+ int cmf = stbi__zget8(a);
+ int cm = cmf & 15;
+ /* int cinfo = cmf >> 4; */
+ int flg = stbi__zget8(a);
+ if (stbi__zeof(a)) return stbi__err("bad zlib header","Corrupt PNG"); // zlib spec
+ if ((cmf*256+flg) % 31 != 0) return stbi__err("bad zlib header","Corrupt PNG"); // zlib spec
+ if (flg & 32) return stbi__err("no preset dict","Corrupt PNG"); // preset dictionary not allowed in png
+ if (cm != 8) return stbi__err("bad compression","Corrupt PNG"); // DEFLATE required for png
+ // window = 1 << (8 + cinfo)... but who cares, we fully buffer output
+ return 1;
+}
+
+static const stbi_uc stbi__zdefault_length[STBI__ZNSYMS] =
+{
+ 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
+ 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
+ 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
+ 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
+ 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,
+ 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,
+ 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,
+ 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,
+ 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,8,8,8,8,8,8,8,8
+};
+static const stbi_uc stbi__zdefault_distance[32] =
+{
+ 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5
+};
+/*
+Init algorithm:
+{
+ int i; // use <= to match clearly with spec
+ for (i=0; i <= 143; ++i) stbi__zdefault_length[i] = 8;
+ for ( ; i <= 255; ++i) stbi__zdefault_length[i] = 9;
+ for ( ; i <= 279; ++i) stbi__zdefault_length[i] = 7;
+ for ( ; i <= 287; ++i) stbi__zdefault_length[i] = 8;
+
+ for (i=0; i <= 31; ++i) stbi__zdefault_distance[i] = 5;
+}
+*/
+
+static int stbi__parse_zlib(stbi__zbuf *a, int parse_header)
+{
+ int final, type;
+ if (parse_header)
+ if (!stbi__parse_zlib_header(a)) return 0;
+ a->num_bits = 0;
+ a->code_buffer = 0;
+ a->hit_zeof_once = 0;
+ do {
+ final = stbi__zreceive(a,1);
+ type = stbi__zreceive(a,2);
+ if (type == 0) {
+ if (!stbi__parse_uncompressed_block(a)) return 0;
+ } else if (type == 3) {
+ return 0;
+ } else {
+ if (type == 1) {
+ // use fixed code lengths
+ if (!stbi__zbuild_huffman(&a->z_length , stbi__zdefault_length , STBI__ZNSYMS)) return 0;
+ if (!stbi__zbuild_huffman(&a->z_distance, stbi__zdefault_distance, 32)) return 0;
+ } else {
+ if (!stbi__compute_huffman_codes(a)) return 0;
+ }
+ if (!stbi__parse_huffman_block(a)) return 0;
+ }
+ } while (!final);
+ return 1;
+}
+
+static int stbi__do_zlib(stbi__zbuf *a, char *obuf, int olen, int exp, int parse_header)
+{
+ a->zout_start = obuf;
+ a->zout = obuf;
+ a->zout_end = obuf + olen;
+ a->z_expandable = exp;
+
+ return stbi__parse_zlib(a, parse_header);
+}
+
+STBIDEF char *stbi_zlib_decode_malloc_guesssize(const char *buffer, int len, int initial_size, int *outlen)
+{
+ stbi__zbuf a;
+ char *p = (char *) stbi__malloc(initial_size);
+ if (p == NULL) return NULL;
+ a.zbuffer = (stbi_uc *) buffer;
+ a.zbuffer_end = (stbi_uc *) buffer + len;
+ if (stbi__do_zlib(&a, p, initial_size, 1, 1)) {
+ if (outlen) *outlen = (int) (a.zout - a.zout_start);
+ return a.zout_start;
+ } else {
+ STBI_FREE(a.zout_start);
+ return NULL;
+ }
+}
+
+STBIDEF char *stbi_zlib_decode_malloc(char const *buffer, int len, int *outlen)
+{
+ return stbi_zlib_decode_malloc_guesssize(buffer, len, 16384, outlen);
+}
+
+STBIDEF char *stbi_zlib_decode_malloc_guesssize_headerflag(const char *buffer, int len, int initial_size, int *outlen, int parse_header)
+{
+ stbi__zbuf a;
+ char *p = (char *) stbi__malloc(initial_size);
+ if (p == NULL) return NULL;
+ a.zbuffer = (stbi_uc *) buffer;
+ a.zbuffer_end = (stbi_uc *) buffer + len;
+ if (stbi__do_zlib(&a, p, initial_size, 1, parse_header)) {
+ if (outlen) *outlen = (int) (a.zout - a.zout_start);
+ return a.zout_start;
+ } else {
+ STBI_FREE(a.zout_start);
+ return NULL;
+ }
+}
+
+STBIDEF int stbi_zlib_decode_buffer(char *obuffer, int olen, char const *ibuffer, int ilen)
+{
+ stbi__zbuf a;
+ a.zbuffer = (stbi_uc *) ibuffer;
+ a.zbuffer_end = (stbi_uc *) ibuffer + ilen;
+ if (stbi__do_zlib(&a, obuffer, olen, 0, 1))
+ return (int) (a.zout - a.zout_start);
+ else
+ return -1;
+}
+
+STBIDEF char *stbi_zlib_decode_noheader_malloc(char const *buffer, int len, int *outlen)
+{
+ stbi__zbuf a;
+ char *p = (char *) stbi__malloc(16384);
+ if (p == NULL) return NULL;
+ a.zbuffer = (stbi_uc *) buffer;
+ a.zbuffer_end = (stbi_uc *) buffer+len;
+ if (stbi__do_zlib(&a, p, 16384, 1, 0)) {
+ if (outlen) *outlen = (int) (a.zout - a.zout_start);
+ return a.zout_start;
+ } else {
+ STBI_FREE(a.zout_start);
+ return NULL;
+ }
+}
+
+STBIDEF int stbi_zlib_decode_noheader_buffer(char *obuffer, int olen, const char *ibuffer, int ilen)
+{
+ stbi__zbuf a;
+ a.zbuffer = (stbi_uc *) ibuffer;
+ a.zbuffer_end = (stbi_uc *) ibuffer + ilen;
+ if (stbi__do_zlib(&a, obuffer, olen, 0, 0))
+ return (int) (a.zout - a.zout_start);
+ else
+ return -1;
+}
+#endif
+
+// public domain "baseline" PNG decoder v0.10 Sean Barrett 2006-11-18
+// simple implementation
+// - only 8-bit samples
+// - no CRC checking
+// - allocates lots of intermediate memory
+// - avoids problem of streaming data between subsystems
+// - avoids explicit window management
+// performance
+// - uses stb_zlib, a PD zlib implementation with fast huffman decoding
+
+#ifndef STBI_NO_PNG
+typedef struct
+{
+ stbi__uint32 length;
+ stbi__uint32 type;
+} stbi__pngchunk;
+
+static stbi__pngchunk stbi__get_chunk_header(stbi__context *s)
+{
+ stbi__pngchunk c;
+ c.length = stbi__get32be(s);
+ c.type = stbi__get32be(s);
+ return c;
+}
+
+static int stbi__check_png_header(stbi__context *s)
+{
+ static const stbi_uc png_sig[8] = { 137,80,78,71,13,10,26,10 };
+ int i;
+ for (i=0; i < 8; ++i)
+ if (stbi__get8(s) != png_sig[i]) return stbi__err("bad png sig","Not a PNG");
+ return 1;
+}
+
+typedef struct
+{
+ stbi__context *s;
+ stbi_uc *idata, *expanded, *out;
+ int depth;
+} stbi__png;
+
+
+enum {
+ STBI__F_none=0,
+ STBI__F_sub=1,
+ STBI__F_up=2,
+ STBI__F_avg=3,
+ STBI__F_paeth=4,
+ // synthetic filter used for first scanline to avoid needing a dummy row of 0s
+ STBI__F_avg_first
+};
+
+static stbi_uc first_row_filter[5] =
+{
+ STBI__F_none,
+ STBI__F_sub,
+ STBI__F_none,
+ STBI__F_avg_first,
+ STBI__F_sub // Paeth with b=c=0 turns out to be equivalent to sub
+};
+
+static int stbi__paeth(int a, int b, int c)
+{
+ // This formulation looks very different from the reference in the PNG spec, but is
+ // actually equivalent and has favorable data dependencies and admits straightforward
+ // generation of branch-free code, which helps performance significantly.
+ int thresh = c*3 - (a + b);
+ int lo = a < b ? a : b;
+ int hi = a < b ? b : a;
+ int t0 = (hi <= thresh) ? lo : c;
+ int t1 = (thresh <= lo) ? hi : t0;
+ return t1;
+}
+
+static const stbi_uc stbi__depth_scale_table[9] = { 0, 0xff, 0x55, 0, 0x11, 0,0,0, 0x01 };
+
+// adds an extra all-255 alpha channel
+// dest == src is legal
+// img_n must be 1 or 3
+static void stbi__create_png_alpha_expand8(stbi_uc *dest, stbi_uc *src, stbi__uint32 x, int img_n)
+{
+ int i;
+ // must process data backwards since we allow dest==src
+ if (img_n == 1) {
+ for (i=x-1; i >= 0; --i) {
+ dest[i*2+1] = 255;
+ dest[i*2+0] = src[i];
+ }
+ } else {
+ STBI_ASSERT(img_n == 3);
+ for (i=x-1; i >= 0; --i) {
+ dest[i*4+3] = 255;
+ dest[i*4+2] = src[i*3+2];
+ dest[i*4+1] = src[i*3+1];
+ dest[i*4+0] = src[i*3+0];
+ }
+ }
+}
+
+// create the png data from post-deflated data
+static int stbi__create_png_image_raw(stbi__png *a, stbi_uc *raw, stbi__uint32 raw_len, int out_n, stbi__uint32 x, stbi__uint32 y, int depth, int color)
+{
+ int bytes = (depth == 16 ? 2 : 1);
+ stbi__context *s = a->s;
+ stbi__uint32 i,j,stride = x*out_n*bytes;
+ stbi__uint32 img_len, img_width_bytes;
+ stbi_uc *filter_buf;
+ int all_ok = 1;
+ int k;
+ int img_n = s->img_n; // copy it into a local for later
+
+ int output_bytes = out_n*bytes;
+ int filter_bytes = img_n*bytes;
+ int width = x;
+
+ STBI_ASSERT(out_n == s->img_n || out_n == s->img_n+1);
+ a->out = (stbi_uc *) stbi__malloc_mad3(x, y, output_bytes, 0); // extra bytes to write off the end into
+ if (!a->out) return stbi__err("outofmem", "Out of memory");
+
+ // note: error exits here don't need to clean up a->out individually,
+ // stbi__do_png always does on error.
+ if (!stbi__mad3sizes_valid(img_n, x, depth, 7)) return stbi__err("too large", "Corrupt PNG");
+ img_width_bytes = (((img_n * x * depth) + 7) >> 3);
+ if (!stbi__mad2sizes_valid(img_width_bytes, y, img_width_bytes)) return stbi__err("too large", "Corrupt PNG");
+ img_len = (img_width_bytes + 1) * y;
+
+ // we used to check for exact match between raw_len and img_len on non-interlaced PNGs,
+ // but issue #276 reported a PNG in the wild that had extra data at the end (all zeros),
+ // so just check for raw_len < img_len always.
+ if (raw_len < img_len) return stbi__err("not enough pixels","Corrupt PNG");
+
+ // Allocate two scan lines worth of filter workspace buffer.
+ filter_buf = (stbi_uc *) stbi__malloc_mad2(img_width_bytes, 2, 0);
+ if (!filter_buf) return stbi__err("outofmem", "Out of memory");
+
+ // Filtering for low-bit-depth images
+ if (depth < 8) {
+ filter_bytes = 1;
+ width = img_width_bytes;
+ }
+
+ for (j=0; j < y; ++j) {
+ // cur/prior filter buffers alternate
+ stbi_uc *cur = filter_buf + (j & 1)*img_width_bytes;
+ stbi_uc *prior = filter_buf + (~j & 1)*img_width_bytes;
+ stbi_uc *dest = a->out + stride*j;
+ int nk = width * filter_bytes;
+ int filter = *raw++;
+
+ // check filter type
+ if (filter > 4) {
+ all_ok = stbi__err("invalid filter","Corrupt PNG");
+ break;
+ }
+
+ // if first row, use special filter that doesn't sample previous row
+ if (j == 0) filter = first_row_filter[filter];
+
+ // perform actual filtering
+ switch (filter) {
+ case STBI__F_none:
+ memcpy(cur, raw, nk);
+ break;
+ case STBI__F_sub:
+ memcpy(cur, raw, filter_bytes);
+ for (k = filter_bytes; k < nk; ++k)
+ cur[k] = STBI__BYTECAST(raw[k] + cur[k-filter_bytes]);
+ break;
+ case STBI__F_up:
+ for (k = 0; k < nk; ++k)
+ cur[k] = STBI__BYTECAST(raw[k] + prior[k]);
+ break;
+ case STBI__F_avg:
+ for (k = 0; k < filter_bytes; ++k)
+ cur[k] = STBI__BYTECAST(raw[k] + (prior[k]>>1));
+ for (k = filter_bytes; k < nk; ++k)
+ cur[k] = STBI__BYTECAST(raw[k] + ((prior[k] + cur[k-filter_bytes])>>1));
+ break;
+ case STBI__F_paeth:
+ for (k = 0; k < filter_bytes; ++k)
+ cur[k] = STBI__BYTECAST(raw[k] + prior[k]); // prior[k] == stbi__paeth(0,prior[k],0)
+ for (k = filter_bytes; k < nk; ++k)
+ cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k-filter_bytes], prior[k], prior[k-filter_bytes]));
+ break;
+ case STBI__F_avg_first:
+ memcpy(cur, raw, filter_bytes);
+ for (k = filter_bytes; k < nk; ++k)
+ cur[k] = STBI__BYTECAST(raw[k] + (cur[k-filter_bytes] >> 1));
+ break;
+ }
+
+ raw += nk;
+
+ // expand decoded bits in cur to dest, also adding an extra alpha channel if desired
+ if (depth < 8) {
+ stbi_uc scale = (color == 0) ? stbi__depth_scale_table[depth] : 1; // scale grayscale values to 0..255 range
+ stbi_uc *in = cur;
+ stbi_uc *out = dest;
+ stbi_uc inb = 0;
+ stbi__uint32 nsmp = x*img_n;
+
+ // expand bits to bytes first
+ if (depth == 4) {
+ for (i=0; i < nsmp; ++i) {
+ if ((i & 1) == 0) inb = *in++;
+ *out++ = scale * (inb >> 4);
+ inb <<= 4;
+ }
+ } else if (depth == 2) {
+ for (i=0; i < nsmp; ++i) {
+ if ((i & 3) == 0) inb = *in++;
+ *out++ = scale * (inb >> 6);
+ inb <<= 2;
+ }
+ } else {
+ STBI_ASSERT(depth == 1);
+ for (i=0; i < nsmp; ++i) {
+ if ((i & 7) == 0) inb = *in++;
+ *out++ = scale * (inb >> 7);
+ inb <<= 1;
+ }
+ }
+
+ // insert alpha=255 values if desired
+ if (img_n != out_n)
+ stbi__create_png_alpha_expand8(dest, dest, x, img_n);
+ } else if (depth == 8) {
+ if (img_n == out_n)
+ memcpy(dest, cur, x*img_n);
+ else
+ stbi__create_png_alpha_expand8(dest, cur, x, img_n);
+ } else if (depth == 16) {
+ // convert the image data from big-endian to platform-native
+ stbi__uint16 *dest16 = (stbi__uint16*)dest;
+ stbi__uint32 nsmp = x*img_n;
+
+ if (img_n == out_n) {
+ for (i = 0; i < nsmp; ++i, ++dest16, cur += 2)
+ *dest16 = (cur[0] << 8) | cur[1];
+ } else {
+ STBI_ASSERT(img_n+1 == out_n);
+ if (img_n == 1) {
+ for (i = 0; i < x; ++i, dest16 += 2, cur += 2) {
+ dest16[0] = (cur[0] << 8) | cur[1];
+ dest16[1] = 0xffff;
+ }
+ } else {
+ STBI_ASSERT(img_n == 3);
+ for (i = 0; i < x; ++i, dest16 += 4, cur += 6) {
+ dest16[0] = (cur[0] << 8) | cur[1];
+ dest16[1] = (cur[2] << 8) | cur[3];
+ dest16[2] = (cur[4] << 8) | cur[5];
+ dest16[3] = 0xffff;
+ }
+ }
+ }
+ }
+ }
+
+ STBI_FREE(filter_buf);
+ if (!all_ok) return 0;
+
+ return 1;
+}
+
+static int stbi__create_png_image(stbi__png *a, stbi_uc *image_data, stbi__uint32 image_data_len, int out_n, int depth, int color, int interlaced)
+{
+ int bytes = (depth == 16 ? 2 : 1);
+ int out_bytes = out_n * bytes;
+ stbi_uc *final;
+ int p;
+ if (!interlaced)
+ return stbi__create_png_image_raw(a, image_data, image_data_len, out_n, a->s->img_x, a->s->img_y, depth, color);
+
+ // de-interlacing
+ final = (stbi_uc *) stbi__malloc_mad3(a->s->img_x, a->s->img_y, out_bytes, 0);
+ if (!final) return stbi__err("outofmem", "Out of memory");
+ for (p=0; p < 7; ++p) {
+ int xorig[] = { 0,4,0,2,0,1,0 };
+ int yorig[] = { 0,0,4,0,2,0,1 };
+ int xspc[] = { 8,8,4,4,2,2,1 };
+ int yspc[] = { 8,8,8,4,4,2,2 };
+ int i,j,x,y;
+ // pass1_x[4] = 0, pass1_x[5] = 1, pass1_x[12] = 1
+ x = (a->s->img_x - xorig[p] + xspc[p]-1) / xspc[p];
+ y = (a->s->img_y - yorig[p] + yspc[p]-1) / yspc[p];
+ if (x && y) {
+ stbi__uint32 img_len = ((((a->s->img_n * x * depth) + 7) >> 3) + 1) * y;
+ if (!stbi__create_png_image_raw(a, image_data, image_data_len, out_n, x, y, depth, color)) {
+ STBI_FREE(final);
+ return 0;
+ }
+ for (j=0; j < y; ++j) {
+ for (i=0; i < x; ++i) {
+ int out_y = j*yspc[p]+yorig[p];
+ int out_x = i*xspc[p]+xorig[p];
+ memcpy(final + out_y*a->s->img_x*out_bytes + out_x*out_bytes,
+ a->out + (j*x+i)*out_bytes, out_bytes);
+ }
+ }
+ STBI_FREE(a->out);
+ image_data += img_len;
+ image_data_len -= img_len;
+ }
+ }
+ a->out = final;
+
+ return 1;
+}
+
+static int stbi__compute_transparency(stbi__png *z, stbi_uc tc[3], int out_n)
+{
+ stbi__context *s = z->s;
+ stbi__uint32 i, pixel_count = s->img_x * s->img_y;
+ stbi_uc *p = z->out;
+
+ // compute color-based transparency, assuming we've
+ // already got 255 as the alpha value in the output
+ STBI_ASSERT(out_n == 2 || out_n == 4);
+
+ if (out_n == 2) {
+ for (i=0; i < pixel_count; ++i) {
+ p[1] = (p[0] == tc[0] ? 0 : 255);
+ p += 2;
+ }
+ } else {
+ for (i=0; i < pixel_count; ++i) {
+ if (p[0] == tc[0] && p[1] == tc[1] && p[2] == tc[2])
+ p[3] = 0;
+ p += 4;
+ }
+ }
+ return 1;
+}
+
+static int stbi__compute_transparency16(stbi__png *z, stbi__uint16 tc[3], int out_n)
+{
+ stbi__context *s = z->s;
+ stbi__uint32 i, pixel_count = s->img_x * s->img_y;
+ stbi__uint16 *p = (stbi__uint16*) z->out;
+
+ // compute color-based transparency, assuming we've
+ // already got 65535 as the alpha value in the output
+ STBI_ASSERT(out_n == 2 || out_n == 4);
+
+ if (out_n == 2) {
+ for (i = 0; i < pixel_count; ++i) {
+ p[1] = (p[0] == tc[0] ? 0 : 65535);
+ p += 2;
+ }
+ } else {
+ for (i = 0; i < pixel_count; ++i) {
+ if (p[0] == tc[0] && p[1] == tc[1] && p[2] == tc[2])
+ p[3] = 0;
+ p += 4;
+ }
+ }
+ return 1;
+}
+
+static int stbi__expand_png_palette(stbi__png *a, stbi_uc *palette, int len, int pal_img_n)
+{
+ stbi__uint32 i, pixel_count = a->s->img_x * a->s->img_y;
+ stbi_uc *p, *temp_out, *orig = a->out;
+
+ p = (stbi_uc *) stbi__malloc_mad2(pixel_count, pal_img_n, 0);
+ if (p == NULL) return stbi__err("outofmem", "Out of memory");
+
+ // between here and free(out) below, exitting would leak
+ temp_out = p;
+
+ if (pal_img_n == 3) {
+ for (i=0; i < pixel_count; ++i) {
+ int n = orig[i]*4;
+ p[0] = palette[n ];
+ p[1] = palette[n+1];
+ p[2] = palette[n+2];
+ p += 3;
+ }
+ } else {
+ for (i=0; i < pixel_count; ++i) {
+ int n = orig[i]*4;
+ p[0] = palette[n ];
+ p[1] = palette[n+1];
+ p[2] = palette[n+2];
+ p[3] = palette[n+3];
+ p += 4;
+ }
+ }
+ STBI_FREE(a->out);
+ a->out = temp_out;
+
+ STBI_NOTUSED(len);
+
+ return 1;
+}
+
+static int stbi__unpremultiply_on_load_global = 0;
+static int stbi__de_iphone_flag_global = 0;
+
+STBIDEF void stbi_set_unpremultiply_on_load(int flag_true_if_should_unpremultiply)
+{
+ stbi__unpremultiply_on_load_global = flag_true_if_should_unpremultiply;
+}
+
+STBIDEF void stbi_convert_iphone_png_to_rgb(int flag_true_if_should_convert)
+{
+ stbi__de_iphone_flag_global = flag_true_if_should_convert;
+}
+
+#ifndef STBI_THREAD_LOCAL
+#define stbi__unpremultiply_on_load stbi__unpremultiply_on_load_global
+#define stbi__de_iphone_flag stbi__de_iphone_flag_global
+#else
+static STBI_THREAD_LOCAL int stbi__unpremultiply_on_load_local, stbi__unpremultiply_on_load_set;
+static STBI_THREAD_LOCAL int stbi__de_iphone_flag_local, stbi__de_iphone_flag_set;
+
+STBIDEF void stbi_set_unpremultiply_on_load_thread(int flag_true_if_should_unpremultiply)
+{
+ stbi__unpremultiply_on_load_local = flag_true_if_should_unpremultiply;
+ stbi__unpremultiply_on_load_set = 1;
+}
+
+STBIDEF void stbi_convert_iphone_png_to_rgb_thread(int flag_true_if_should_convert)
+{
+ stbi__de_iphone_flag_local = flag_true_if_should_convert;
+ stbi__de_iphone_flag_set = 1;
+}
+
+#define stbi__unpremultiply_on_load (stbi__unpremultiply_on_load_set \
+ ? stbi__unpremultiply_on_load_local \
+ : stbi__unpremultiply_on_load_global)
+#define stbi__de_iphone_flag (stbi__de_iphone_flag_set \
+ ? stbi__de_iphone_flag_local \
+ : stbi__de_iphone_flag_global)
+#endif // STBI_THREAD_LOCAL
+
+static void stbi__de_iphone(stbi__png *z)
+{
+ stbi__context *s = z->s;
+ stbi__uint32 i, pixel_count = s->img_x * s->img_y;
+ stbi_uc *p = z->out;
+
+ if (s->img_out_n == 3) { // convert bgr to rgb
+ for (i=0; i < pixel_count; ++i) {
+ stbi_uc t = p[0];
+ p[0] = p[2];
+ p[2] = t;
+ p += 3;
+ }
+ } else {
+ STBI_ASSERT(s->img_out_n == 4);
+ if (stbi__unpremultiply_on_load) {
+ // convert bgr to rgb and unpremultiply
+ for (i=0; i < pixel_count; ++i) {
+ stbi_uc a = p[3];
+ stbi_uc t = p[0];
+ if (a) {
+ stbi_uc half = a / 2;
+ p[0] = (p[2] * 255 + half) / a;
+ p[1] = (p[1] * 255 + half) / a;
+ p[2] = ( t * 255 + half) / a;
+ } else {
+ p[0] = p[2];
+ p[2] = t;
+ }
+ p += 4;
+ }
+ } else {
+ // convert bgr to rgb
+ for (i=0; i < pixel_count; ++i) {
+ stbi_uc t = p[0];
+ p[0] = p[2];
+ p[2] = t;
+ p += 4;
+ }
+ }
+ }
+}
+
+#define STBI__PNG_TYPE(a,b,c,d) (((unsigned) (a) << 24) + ((unsigned) (b) << 16) + ((unsigned) (c) << 8) + (unsigned) (d))
+
+static int stbi__parse_png_file(stbi__png *z, int scan, int req_comp)
+{
+ stbi_uc palette[1024], pal_img_n=0;
+ stbi_uc has_trans=0, tc[3]={0};
+ stbi__uint16 tc16[3];
+ stbi__uint32 ioff=0, idata_limit=0, i, pal_len=0;
+ int first=1,k,interlace=0, color=0, is_iphone=0;
+ stbi__context *s = z->s;
+
+ z->expanded = NULL;
+ z->idata = NULL;
+ z->out = NULL;
+
+ if (!stbi__check_png_header(s)) return 0;
+
+ if (scan == STBI__SCAN_type) return 1;
+
+ for (;;) {
+ stbi__pngchunk c = stbi__get_chunk_header(s);
+ switch (c.type) {
+ case STBI__PNG_TYPE('C','g','B','I'):
+ is_iphone = 1;
+ stbi__skip(s, c.length);
+ break;
+ case STBI__PNG_TYPE('I','H','D','R'): {
+ int comp,filter;
+ if (!first) return stbi__err("multiple IHDR","Corrupt PNG");
+ first = 0;
+ if (c.length != 13) return stbi__err("bad IHDR len","Corrupt PNG");
+ s->img_x = stbi__get32be(s);
+ s->img_y = stbi__get32be(s);
+ if (s->img_y > STBI_MAX_DIMENSIONS) return stbi__err("too large","Very large image (corrupt?)");
+ if (s->img_x > STBI_MAX_DIMENSIONS) return stbi__err("too large","Very large image (corrupt?)");
+ z->depth = stbi__get8(s); if (z->depth != 1 && z->depth != 2 && z->depth != 4 && z->depth != 8 && z->depth != 16) return stbi__err("1/2/4/8/16-bit only","PNG not supported: 1/2/4/8/16-bit only");
+ color = stbi__get8(s); if (color > 6) return stbi__err("bad ctype","Corrupt PNG");
+ if (color == 3 && z->depth == 16) return stbi__err("bad ctype","Corrupt PNG");
+ if (color == 3) pal_img_n = 3; else if (color & 1) return stbi__err("bad ctype","Corrupt PNG");
+ comp = stbi__get8(s); if (comp) return stbi__err("bad comp method","Corrupt PNG");
+ filter= stbi__get8(s); if (filter) return stbi__err("bad filter method","Corrupt PNG");
+ interlace = stbi__get8(s); if (interlace>1) return stbi__err("bad interlace method","Corrupt PNG");
+ if (!s->img_x || !s->img_y) return stbi__err("0-pixel image","Corrupt PNG");
+ if (!pal_img_n) {
+ s->img_n = (color & 2 ? 3 : 1) + (color & 4 ? 1 : 0);
+ if ((1 << 30) / s->img_x / s->img_n < s->img_y) return stbi__err("too large", "Image too large to decode");
+ } else {
+ // if paletted, then pal_n is our final components, and
+ // img_n is # components to decompress/filter.
+ s->img_n = 1;
+ if ((1 << 30) / s->img_x / 4 < s->img_y) return stbi__err("too large","Corrupt PNG");
+ }
+ // even with SCAN_header, have to scan to see if we have a tRNS
+ break;
+ }
+
+ case STBI__PNG_TYPE('P','L','T','E'): {
+ if (first) return stbi__err("first not IHDR", "Corrupt PNG");
+ if (c.length > 256*3) return stbi__err("invalid PLTE","Corrupt PNG");
+ pal_len = c.length / 3;
+ if (pal_len * 3 != c.length) return stbi__err("invalid PLTE","Corrupt PNG");
+ for (i=0; i < pal_len; ++i) {
+ palette[i*4+0] = stbi__get8(s);
+ palette[i*4+1] = stbi__get8(s);
+ palette[i*4+2] = stbi__get8(s);
+ palette[i*4+3] = 255;
+ }
+ break;
+ }
+
+ case STBI__PNG_TYPE('t','R','N','S'): {
+ if (first) return stbi__err("first not IHDR", "Corrupt PNG");
+ if (z->idata) return stbi__err("tRNS after IDAT","Corrupt PNG");
+ if (pal_img_n) {
+ if (scan == STBI__SCAN_header) { s->img_n = 4; return 1; }
+ if (pal_len == 0) return stbi__err("tRNS before PLTE","Corrupt PNG");
+ if (c.length > pal_len) return stbi__err("bad tRNS len","Corrupt PNG");
+ pal_img_n = 4;
+ for (i=0; i < c.length; ++i)
+ palette[i*4+3] = stbi__get8(s);
+ } else {
+ if (!(s->img_n & 1)) return stbi__err("tRNS with alpha","Corrupt PNG");
+ if (c.length != (stbi__uint32) s->img_n*2) return stbi__err("bad tRNS len","Corrupt PNG");
+ has_trans = 1;
+ // non-paletted with tRNS = constant alpha. if header-scanning, we can stop now.
+ if (scan == STBI__SCAN_header) { ++s->img_n; return 1; }
+ if (z->depth == 16) {
+ for (k = 0; k < s->img_n && k < 3; ++k) // extra loop test to suppress false GCC warning
+ tc16[k] = (stbi__uint16)stbi__get16be(s); // copy the values as-is
+ } else {
+ for (k = 0; k < s->img_n && k < 3; ++k)
+ tc[k] = (stbi_uc)(stbi__get16be(s) & 255) * stbi__depth_scale_table[z->depth]; // non 8-bit images will be larger
+ }
+ }
+ break;
+ }
+
+ case STBI__PNG_TYPE('I','D','A','T'): {
+ if (first) return stbi__err("first not IHDR", "Corrupt PNG");
+ if (pal_img_n && !pal_len) return stbi__err("no PLTE","Corrupt PNG");
+ if (scan == STBI__SCAN_header) {
+ // header scan definitely stops at first IDAT
+ if (pal_img_n)
+ s->img_n = pal_img_n;
+ return 1;
+ }
+ if (c.length > (1u << 30)) return stbi__err("IDAT size limit", "IDAT section larger than 2^30 bytes");
+ if ((int)(ioff + c.length) < (int)ioff) return 0;
+ if (ioff + c.length > idata_limit) {
+ stbi__uint32 idata_limit_old = idata_limit;
+ stbi_uc *p;
+ if (idata_limit == 0) idata_limit = c.length > 4096 ? c.length : 4096;
+ while (ioff + c.length > idata_limit)
+ idata_limit *= 2;
+ STBI_NOTUSED(idata_limit_old);
+ p = (stbi_uc *) STBI_REALLOC_SIZED(z->idata, idata_limit_old, idata_limit); if (p == NULL) return stbi__err("outofmem", "Out of memory");
+ z->idata = p;
+ }
+ if (!stbi__getn(s, z->idata+ioff,c.length)) return stbi__err("outofdata","Corrupt PNG");
+ ioff += c.length;
+ break;
+ }
+
+ case STBI__PNG_TYPE('I','E','N','D'): {
+ stbi__uint32 raw_len, bpl;
+ if (first) return stbi__err("first not IHDR", "Corrupt PNG");
+ if (scan != STBI__SCAN_load) return 1;
+ if (z->idata == NULL) return stbi__err("no IDAT","Corrupt PNG");
+ // initial guess for decoded data size to avoid unnecessary reallocs
+ bpl = (s->img_x * z->depth + 7) / 8; // bytes per line, per component
+ raw_len = bpl * s->img_y * s->img_n /* pixels */ + s->img_y /* filter mode per row */;
+ z->expanded = (stbi_uc *) stbi_zlib_decode_malloc_guesssize_headerflag((char *) z->idata, ioff, raw_len, (int *) &raw_len, !is_iphone);
+ if (z->expanded == NULL) return 0; // zlib should set error
+ STBI_FREE(z->idata); z->idata = NULL;
+ if ((req_comp == s->img_n+1 && req_comp != 3 && !pal_img_n) || has_trans)
+ s->img_out_n = s->img_n+1;
+ else
+ s->img_out_n = s->img_n;
+ if (!stbi__create_png_image(z, z->expanded, raw_len, s->img_out_n, z->depth, color, interlace)) return 0;
+ if (has_trans) {
+ if (z->depth == 16) {
+ if (!stbi__compute_transparency16(z, tc16, s->img_out_n)) return 0;
+ } else {
+ if (!stbi__compute_transparency(z, tc, s->img_out_n)) return 0;
+ }
+ }
+ if (is_iphone && stbi__de_iphone_flag && s->img_out_n > 2)
+ stbi__de_iphone(z);
+ if (pal_img_n) {
+ // pal_img_n == 3 or 4
+ s->img_n = pal_img_n; // record the actual colors we had
+ s->img_out_n = pal_img_n;
+ if (req_comp >= 3) s->img_out_n = req_comp;
+ if (!stbi__expand_png_palette(z, palette, pal_len, s->img_out_n))
+ return 0;
+ } else if (has_trans) {
+ // non-paletted image with tRNS -> source image has (constant) alpha
+ ++s->img_n;
+ }
+ STBI_FREE(z->expanded); z->expanded = NULL;
+ // end of PNG chunk, read and skip CRC
+ stbi__get32be(s);
+ return 1;
+ }
+
+ default:
+ // if critical, fail
+ if (first) return stbi__err("first not IHDR", "Corrupt PNG");
+ if ((c.type & (1 << 29)) == 0) {
+ #ifndef STBI_NO_FAILURE_STRINGS
+ // not threadsafe
+ static char invalid_chunk[] = "XXXX PNG chunk not known";
+ invalid_chunk[0] = STBI__BYTECAST(c.type >> 24);
+ invalid_chunk[1] = STBI__BYTECAST(c.type >> 16);
+ invalid_chunk[2] = STBI__BYTECAST(c.type >> 8);
+ invalid_chunk[3] = STBI__BYTECAST(c.type >> 0);
+ #endif
+ return stbi__err(invalid_chunk, "PNG not supported: unknown PNG chunk type");
+ }
+ stbi__skip(s, c.length);
+ break;
+ }
+ // end of PNG chunk, read and skip CRC
+ stbi__get32be(s);
+ }
+}
+
+static void *stbi__do_png(stbi__png *p, int *x, int *y, int *n, int req_comp, stbi__result_info *ri)
+{
+ void *result=NULL;
+ if (req_comp < 0 || req_comp > 4) return stbi__errpuc("bad req_comp", "Internal error");
+ if (stbi__parse_png_file(p, STBI__SCAN_load, req_comp)) {
+ if (p->depth <= 8)
+ ri->bits_per_channel = 8;
+ else if (p->depth == 16)
+ ri->bits_per_channel = 16;
+ else
+ return stbi__errpuc("bad bits_per_channel", "PNG not supported: unsupported color depth");
+ result = p->out;
+ p->out = NULL;
+ if (req_comp && req_comp != p->s->img_out_n) {
+ if (ri->bits_per_channel == 8)
+ result = stbi__convert_format((unsigned char *) result, p->s->img_out_n, req_comp, p->s->img_x, p->s->img_y);
+ else
+ result = stbi__convert_format16((stbi__uint16 *) result, p->s->img_out_n, req_comp, p->s->img_x, p->s->img_y);
+ p->s->img_out_n = req_comp;
+ if (result == NULL) return result;
+ }
+ *x = p->s->img_x;
+ *y = p->s->img_y;
+ if (n) *n = p->s->img_n;
+ }
+ STBI_FREE(p->out); p->out = NULL;
+ STBI_FREE(p->expanded); p->expanded = NULL;
+ STBI_FREE(p->idata); p->idata = NULL;
+
+ return result;
+}
+
+static void *stbi__png_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri)
+{
+ stbi__png p;
+ p.s = s;
+ return stbi__do_png(&p, x,y,comp,req_comp, ri);
+}
+
+static int stbi__png_test(stbi__context *s)
+{
+ int r;
+ r = stbi__check_png_header(s);
+ stbi__rewind(s);
+ return r;
+}
+
+static int stbi__png_info_raw(stbi__png *p, int *x, int *y, int *comp)
+{
+ if (!stbi__parse_png_file(p, STBI__SCAN_header, 0)) {
+ stbi__rewind( p->s );
+ return 0;
+ }
+ if (x) *x = p->s->img_x;
+ if (y) *y = p->s->img_y;
+ if (comp) *comp = p->s->img_n;
+ return 1;
+}
+
+static int stbi__png_info(stbi__context *s, int *x, int *y, int *comp)
+{
+ stbi__png p;
+ p.s = s;
+ return stbi__png_info_raw(&p, x, y, comp);
+}
+
+static int stbi__png_is16(stbi__context *s)
+{
+ stbi__png p;
+ p.s = s;
+ if (!stbi__png_info_raw(&p, NULL, NULL, NULL))
+ return 0;
+ if (p.depth != 16) {
+ stbi__rewind(p.s);
+ return 0;
+ }
+ return 1;
+}
+#endif
+
+// Microsoft/Windows BMP image
+
+#ifndef STBI_NO_BMP
+static int stbi__bmp_test_raw(stbi__context *s)
+{
+ int r;
+ int sz;
+ if (stbi__get8(s) != 'B') return 0;
+ if (stbi__get8(s) != 'M') return 0;
+ stbi__get32le(s); // discard filesize
+ stbi__get16le(s); // discard reserved
+ stbi__get16le(s); // discard reserved
+ stbi__get32le(s); // discard data offset
+ sz = stbi__get32le(s);
+ r = (sz == 12 || sz == 40 || sz == 56 || sz == 108 || sz == 124);
+ return r;
+}
+
+static int stbi__bmp_test(stbi__context *s)
+{
+ int r = stbi__bmp_test_raw(s);
+ stbi__rewind(s);
+ return r;
+}
+
+
+// returns 0..31 for the highest set bit
+static int stbi__high_bit(unsigned int z)
+{
+ int n=0;
+ if (z == 0) return -1;
+ if (z >= 0x10000) { n += 16; z >>= 16; }
+ if (z >= 0x00100) { n += 8; z >>= 8; }
+ if (z >= 0x00010) { n += 4; z >>= 4; }
+ if (z >= 0x00004) { n += 2; z >>= 2; }
+ if (z >= 0x00002) { n += 1;/* >>= 1;*/ }
+ return n;
+}
+
+static int stbi__bitcount(unsigned int a)
+{
+ a = (a & 0x55555555) + ((a >> 1) & 0x55555555); // max 2
+ a = (a & 0x33333333) + ((a >> 2) & 0x33333333); // max 4
+ a = (a + (a >> 4)) & 0x0f0f0f0f; // max 8 per 4, now 8 bits
+ a = (a + (a >> 8)); // max 16 per 8 bits
+ a = (a + (a >> 16)); // max 32 per 8 bits
+ return a & 0xff;
+}
+
+// extract an arbitrarily-aligned N-bit value (N=bits)
+// from v, and then make it 8-bits long and fractionally
+// extend it to full full range.
+static int stbi__shiftsigned(unsigned int v, int shift, int bits)
+{
+ static unsigned int mul_table[9] = {
+ 0,
+ 0xff/*0b11111111*/, 0x55/*0b01010101*/, 0x49/*0b01001001*/, 0x11/*0b00010001*/,
+ 0x21/*0b00100001*/, 0x41/*0b01000001*/, 0x81/*0b10000001*/, 0x01/*0b00000001*/,
+ };
+ static unsigned int shift_table[9] = {
+ 0, 0,0,1,0,2,4,6,0,
+ };
+ if (shift < 0)
+ v <<= -shift;
+ else
+ v >>= shift;
+ STBI_ASSERT(v < 256);
+ v >>= (8-bits);
+ STBI_ASSERT(bits >= 0 && bits <= 8);
+ return (int) ((unsigned) v * mul_table[bits]) >> shift_table[bits];
+}
+
+typedef struct
+{
+ int bpp, offset, hsz;
+ unsigned int mr,mg,mb,ma, all_a;
+ int extra_read;
+} stbi__bmp_data;
+
+static int stbi__bmp_set_mask_defaults(stbi__bmp_data *info, int compress)
+{
+ // BI_BITFIELDS specifies masks explicitly, don't override
+ if (compress == 3)
+ return 1;
+
+ if (compress == 0) {
+ if (info->bpp == 16) {
+ info->mr = 31u << 10;
+ info->mg = 31u << 5;
+ info->mb = 31u << 0;
+ } else if (info->bpp == 32) {
+ info->mr = 0xffu << 16;
+ info->mg = 0xffu << 8;
+ info->mb = 0xffu << 0;
+ info->ma = 0xffu << 24;
+ info->all_a = 0; // if all_a is 0 at end, then we loaded alpha channel but it was all 0
+ } else {
+ // otherwise, use defaults, which is all-0
+ info->mr = info->mg = info->mb = info->ma = 0;
+ }
+ return 1;
+ }
+ return 0; // error
+}
+
+static void *stbi__bmp_parse_header(stbi__context *s, stbi__bmp_data *info)
+{
+ int hsz;
+ if (stbi__get8(s) != 'B' || stbi__get8(s) != 'M') return stbi__errpuc("not BMP", "Corrupt BMP");
+ stbi__get32le(s); // discard filesize
+ stbi__get16le(s); // discard reserved
+ stbi__get16le(s); // discard reserved
+ info->offset = stbi__get32le(s);
+ info->hsz = hsz = stbi__get32le(s);
+ info->mr = info->mg = info->mb = info->ma = 0;
+ info->extra_read = 14;
+
+ if (info->offset < 0) return stbi__errpuc("bad BMP", "bad BMP");
+
+ if (hsz != 12 && hsz != 40 && hsz != 56 && hsz != 108 && hsz != 124) return stbi__errpuc("unknown BMP", "BMP type not supported: unknown");
+ if (hsz == 12) {
+ s->img_x = stbi__get16le(s);
+ s->img_y = stbi__get16le(s);
+ } else {
+ s->img_x = stbi__get32le(s);
+ s->img_y = stbi__get32le(s);
+ }
+ if (stbi__get16le(s) != 1) return stbi__errpuc("bad BMP", "bad BMP");
+ info->bpp = stbi__get16le(s);
+ if (hsz != 12) {
+ int compress = stbi__get32le(s);
+ if (compress == 1 || compress == 2) return stbi__errpuc("BMP RLE", "BMP type not supported: RLE");
+ if (compress >= 4) return stbi__errpuc("BMP JPEG/PNG", "BMP type not supported: unsupported compression"); // this includes PNG/JPEG modes
+ if (compress == 3 && info->bpp != 16 && info->bpp != 32) return stbi__errpuc("bad BMP", "bad BMP"); // bitfields requires 16 or 32 bits/pixel
+ stbi__get32le(s); // discard sizeof
+ stbi__get32le(s); // discard hres
+ stbi__get32le(s); // discard vres
+ stbi__get32le(s); // discard colorsused
+ stbi__get32le(s); // discard max important
+ if (hsz == 40 || hsz == 56) {
+ if (hsz == 56) {
+ stbi__get32le(s);
+ stbi__get32le(s);
+ stbi__get32le(s);
+ stbi__get32le(s);
+ }
+ if (info->bpp == 16 || info->bpp == 32) {
+ if (compress == 0) {
+ stbi__bmp_set_mask_defaults(info, compress);
+ } else if (compress == 3) {
+ info->mr = stbi__get32le(s);
+ info->mg = stbi__get32le(s);
+ info->mb = stbi__get32le(s);
+ info->extra_read += 12;
+ // not documented, but generated by photoshop and handled by mspaint
+ if (info->mr == info->mg && info->mg == info->mb) {
+ // ?!?!?
+ return stbi__errpuc("bad BMP", "bad BMP");
+ }
+ } else
+ return stbi__errpuc("bad BMP", "bad BMP");
+ }
+ } else {
+ // V4/V5 header
+ int i;
+ if (hsz != 108 && hsz != 124)
+ return stbi__errpuc("bad BMP", "bad BMP");
+ info->mr = stbi__get32le(s);
+ info->mg = stbi__get32le(s);
+ info->mb = stbi__get32le(s);
+ info->ma = stbi__get32le(s);
+ if (compress != 3) // override mr/mg/mb unless in BI_BITFIELDS mode, as per docs
+ stbi__bmp_set_mask_defaults(info, compress);
+ stbi__get32le(s); // discard color space
+ for (i=0; i < 12; ++i)
+ stbi__get32le(s); // discard color space parameters
+ if (hsz == 124) {
+ stbi__get32le(s); // discard rendering intent
+ stbi__get32le(s); // discard offset of profile data
+ stbi__get32le(s); // discard size of profile data
+ stbi__get32le(s); // discard reserved
+ }
+ }
+ }
+ return (void *) 1;
+}
+
+
+static void *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri)
+{
+ stbi_uc *out;
+ unsigned int mr=0,mg=0,mb=0,ma=0, all_a;
+ stbi_uc pal[256][4];
+ int psize=0,i,j,width;
+ int flip_vertically, pad, target;
+ stbi__bmp_data info;
+ STBI_NOTUSED(ri);
+
+ info.all_a = 255;
+ if (stbi__bmp_parse_header(s, &info) == NULL)
+ return NULL; // error code already set
+
+ flip_vertically = ((int) s->img_y) > 0;
+ s->img_y = abs((int) s->img_y);
+
+ if (s->img_y > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)");
+ if (s->img_x > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)");
+
+ mr = info.mr;
+ mg = info.mg;
+ mb = info.mb;
+ ma = info.ma;
+ all_a = info.all_a;
+
+ if (info.hsz == 12) {
+ if (info.bpp < 24)
+ psize = (info.offset - info.extra_read - 24) / 3;
+ } else {
+ if (info.bpp < 16)
+ psize = (info.offset - info.extra_read - info.hsz) >> 2;
+ }
+ if (psize == 0) {
+ // accept some number of extra bytes after the header, but if the offset points either to before
+ // the header ends or implies a large amount of extra data, reject the file as malformed
+ int bytes_read_so_far = s->callback_already_read + (int)(s->img_buffer - s->img_buffer_original);
+ int header_limit = 1024; // max we actually read is below 256 bytes currently.
+ int extra_data_limit = 256*4; // what ordinarily goes here is a palette; 256 entries*4 bytes is its max size.
+ if (bytes_read_so_far <= 0 || bytes_read_so_far > header_limit) {
+ return stbi__errpuc("bad header", "Corrupt BMP");
+ }
+ // we established that bytes_read_so_far is positive and sensible.
+ // the first half of this test rejects offsets that are either too small positives, or
+ // negative, and guarantees that info.offset >= bytes_read_so_far > 0. this in turn
+ // ensures the number computed in the second half of the test can't overflow.
+ if (info.offset < bytes_read_so_far || info.offset - bytes_read_so_far > extra_data_limit) {
+ return stbi__errpuc("bad offset", "Corrupt BMP");
+ } else {
+ stbi__skip(s, info.offset - bytes_read_so_far);
+ }
+ }
+
+ if (info.bpp == 24 && ma == 0xff000000)
+ s->img_n = 3;
+ else
+ s->img_n = ma ? 4 : 3;
+ if (req_comp && req_comp >= 3) // we can directly decode 3 or 4
+ target = req_comp;
+ else
+ target = s->img_n; // if they want monochrome, we'll post-convert
+
+ // sanity-check size
+ if (!stbi__mad3sizes_valid(target, s->img_x, s->img_y, 0))
+ return stbi__errpuc("too large", "Corrupt BMP");
+
+ out = (stbi_uc *) stbi__malloc_mad3(target, s->img_x, s->img_y, 0);
+ if (!out) return stbi__errpuc("outofmem", "Out of memory");
+ if (info.bpp < 16) {
+ int z=0;
+ if (psize == 0 || psize > 256) { STBI_FREE(out); return stbi__errpuc("invalid", "Corrupt BMP"); }
+ for (i=0; i < psize; ++i) {
+ pal[i][2] = stbi__get8(s);
+ pal[i][1] = stbi__get8(s);
+ pal[i][0] = stbi__get8(s);
+ if (info.hsz != 12) stbi__get8(s);
+ pal[i][3] = 255;
+ }
+ stbi__skip(s, info.offset - info.extra_read - info.hsz - psize * (info.hsz == 12 ? 3 : 4));
+ if (info.bpp == 1) width = (s->img_x + 7) >> 3;
+ else if (info.bpp == 4) width = (s->img_x + 1) >> 1;
+ else if (info.bpp == 8) width = s->img_x;
+ else { STBI_FREE(out); return stbi__errpuc("bad bpp", "Corrupt BMP"); }
+ pad = (-width)&3;
+ if (info.bpp == 1) {
+ for (j=0; j < (int) s->img_y; ++j) {
+ int bit_offset = 7, v = stbi__get8(s);
+ for (i=0; i < (int) s->img_x; ++i) {
+ int color = (v>>bit_offset)&0x1;
+ out[z++] = pal[color][0];
+ out[z++] = pal[color][1];
+ out[z++] = pal[color][2];
+ if (target == 4) out[z++] = 255;
+ if (i+1 == (int) s->img_x) break;
+ if((--bit_offset) < 0) {
+ bit_offset = 7;
+ v = stbi__get8(s);
+ }
+ }
+ stbi__skip(s, pad);
+ }
+ } else {
+ for (j=0; j < (int) s->img_y; ++j) {
+ for (i=0; i < (int) s->img_x; i += 2) {
+ int v=stbi__get8(s),v2=0;
+ if (info.bpp == 4) {
+ v2 = v & 15;
+ v >>= 4;
+ }
+ out[z++] = pal[v][0];
+ out[z++] = pal[v][1];
+ out[z++] = pal[v][2];
+ if (target == 4) out[z++] = 255;
+ if (i+1 == (int) s->img_x) break;
+ v = (info.bpp == 8) ? stbi__get8(s) : v2;
+ out[z++] = pal[v][0];
+ out[z++] = pal[v][1];
+ out[z++] = pal[v][2];
+ if (target == 4) out[z++] = 255;
+ }
+ stbi__skip(s, pad);
+ }
+ }
+ } else {
+ int rshift=0,gshift=0,bshift=0,ashift=0,rcount=0,gcount=0,bcount=0,acount=0;
+ int z = 0;
+ int easy=0;
+ stbi__skip(s, info.offset - info.extra_read - info.hsz);
+ if (info.bpp == 24) width = 3 * s->img_x;
+ else if (info.bpp == 16) width = 2*s->img_x;
+ else /* bpp = 32 and pad = 0 */ width=0;
+ pad = (-width) & 3;
+ if (info.bpp == 24) {
+ easy = 1;
+ } else if (info.bpp == 32) {
+ if (mb == 0xff && mg == 0xff00 && mr == 0x00ff0000 && ma == 0xff000000)
+ easy = 2;
+ }
+ if (!easy) {
+ if (!mr || !mg || !mb) { STBI_FREE(out); return stbi__errpuc("bad masks", "Corrupt BMP"); }
+ // right shift amt to put high bit in position #7
+ rshift = stbi__high_bit(mr)-7; rcount = stbi__bitcount(mr);
+ gshift = stbi__high_bit(mg)-7; gcount = stbi__bitcount(mg);
+ bshift = stbi__high_bit(mb)-7; bcount = stbi__bitcount(mb);
+ ashift = stbi__high_bit(ma)-7; acount = stbi__bitcount(ma);
+ if (rcount > 8 || gcount > 8 || bcount > 8 || acount > 8) { STBI_FREE(out); return stbi__errpuc("bad masks", "Corrupt BMP"); }
+ }
+ for (j=0; j < (int) s->img_y; ++j) {
+ if (easy) {
+ for (i=0; i < (int) s->img_x; ++i) {
+ unsigned char a;
+ out[z+2] = stbi__get8(s);
+ out[z+1] = stbi__get8(s);
+ out[z+0] = stbi__get8(s);
+ z += 3;
+ a = (easy == 2 ? stbi__get8(s) : 255);
+ all_a |= a;
+ if (target == 4) out[z++] = a;
+ }
+ } else {
+ int bpp = info.bpp;
+ for (i=0; i < (int) s->img_x; ++i) {
+ stbi__uint32 v = (bpp == 16 ? (stbi__uint32) stbi__get16le(s) : stbi__get32le(s));
+ unsigned int a;
+ out[z++] = STBI__BYTECAST(stbi__shiftsigned(v & mr, rshift, rcount));
+ out[z++] = STBI__BYTECAST(stbi__shiftsigned(v & mg, gshift, gcount));
+ out[z++] = STBI__BYTECAST(stbi__shiftsigned(v & mb, bshift, bcount));
+ a = (ma ? stbi__shiftsigned(v & ma, ashift, acount) : 255);
+ all_a |= a;
+ if (target == 4) out[z++] = STBI__BYTECAST(a);
+ }
+ }
+ stbi__skip(s, pad);
+ }
+ }
+
+ // if alpha channel is all 0s, replace with all 255s
+ if (target == 4 && all_a == 0)
+ for (i=4*s->img_x*s->img_y-1; i >= 0; i -= 4)
+ out[i] = 255;
+
+ if (flip_vertically) {
+ stbi_uc t;
+ for (j=0; j < (int) s->img_y>>1; ++j) {
+ stbi_uc *p1 = out + j *s->img_x*target;
+ stbi_uc *p2 = out + (s->img_y-1-j)*s->img_x*target;
+ for (i=0; i < (int) s->img_x*target; ++i) {
+ t = p1[i]; p1[i] = p2[i]; p2[i] = t;
+ }
+ }
+ }
+
+ if (req_comp && req_comp != target) {
+ out = stbi__convert_format(out, target, req_comp, s->img_x, s->img_y);
+ if (out == NULL) return out; // stbi__convert_format frees input on failure
+ }
+
+ *x = s->img_x;
+ *y = s->img_y;
+ if (comp) *comp = s->img_n;
+ return out;
+}
+#endif
+
+// Targa Truevision - TGA
+// by Jonathan Dummer
+#ifndef STBI_NO_TGA
+// returns STBI_rgb or whatever, 0 on error
+static int stbi__tga_get_comp(int bits_per_pixel, int is_grey, int* is_rgb16)
+{
+ // only RGB or RGBA (incl. 16bit) or grey allowed
+ if (is_rgb16) *is_rgb16 = 0;
+ switch(bits_per_pixel) {
+ case 8: return STBI_grey;
+ case 16: if(is_grey) return STBI_grey_alpha;
+ // fallthrough
+ case 15: if(is_rgb16) *is_rgb16 = 1;
+ return STBI_rgb;
+ case 24: // fallthrough
+ case 32: return bits_per_pixel/8;
+ default: return 0;
+ }
+}
+
+static int stbi__tga_info(stbi__context *s, int *x, int *y, int *comp)
+{
+ int tga_w, tga_h, tga_comp, tga_image_type, tga_bits_per_pixel, tga_colormap_bpp;
+ int sz, tga_colormap_type;
+ stbi__get8(s); // discard Offset
+ tga_colormap_type = stbi__get8(s); // colormap type
+ if( tga_colormap_type > 1 ) {
+ stbi__rewind(s);
+ return 0; // only RGB or indexed allowed
+ }
+ tga_image_type = stbi__get8(s); // image type
+ if ( tga_colormap_type == 1 ) { // colormapped (paletted) image
+ if (tga_image_type != 1 && tga_image_type != 9) {
+ stbi__rewind(s);
+ return 0;
+ }
+ stbi__skip(s,4); // skip index of first colormap entry and number of entries
+ sz = stbi__get8(s); // check bits per palette color entry
+ if ( (sz != 8) && (sz != 15) && (sz != 16) && (sz != 24) && (sz != 32) ) {
+ stbi__rewind(s);
+ return 0;
+ }
+ stbi__skip(s,4); // skip image x and y origin
+ tga_colormap_bpp = sz;
+ } else { // "normal" image w/o colormap - only RGB or grey allowed, +/- RLE
+ if ( (tga_image_type != 2) && (tga_image_type != 3) && (tga_image_type != 10) && (tga_image_type != 11) ) {
+ stbi__rewind(s);
+ return 0; // only RGB or grey allowed, +/- RLE
+ }
+ stbi__skip(s,9); // skip colormap specification and image x/y origin
+ tga_colormap_bpp = 0;
+ }
+ tga_w = stbi__get16le(s);
+ if( tga_w < 1 ) {
+ stbi__rewind(s);
+ return 0; // test width
+ }
+ tga_h = stbi__get16le(s);
+ if( tga_h < 1 ) {
+ stbi__rewind(s);
+ return 0; // test height
+ }
+ tga_bits_per_pixel = stbi__get8(s); // bits per pixel
+ stbi__get8(s); // ignore alpha bits
+ if (tga_colormap_bpp != 0) {
+ if((tga_bits_per_pixel != 8) && (tga_bits_per_pixel != 16)) {
+ // when using a colormap, tga_bits_per_pixel is the size of the indexes
+ // I don't think anything but 8 or 16bit indexes makes sense
+ stbi__rewind(s);
+ return 0;
+ }
+ tga_comp = stbi__tga_get_comp(tga_colormap_bpp, 0, NULL);
+ } else {
+ tga_comp = stbi__tga_get_comp(tga_bits_per_pixel, (tga_image_type == 3) || (tga_image_type == 11), NULL);
+ }
+ if(!tga_comp) {
+ stbi__rewind(s);
+ return 0;
+ }
+ if (x) *x = tga_w;
+ if (y) *y = tga_h;
+ if (comp) *comp = tga_comp;
+ return 1; // seems to have passed everything
+}
+
+static int stbi__tga_test(stbi__context *s)
+{
+ int res = 0;
+ int sz, tga_color_type;
+ stbi__get8(s); // discard Offset
+ tga_color_type = stbi__get8(s); // color type
+ if ( tga_color_type > 1 ) goto errorEnd; // only RGB or indexed allowed
+ sz = stbi__get8(s); // image type
+ if ( tga_color_type == 1 ) { // colormapped (paletted) image
+ if (sz != 1 && sz != 9) goto errorEnd; // colortype 1 demands image type 1 or 9
+ stbi__skip(s,4); // skip index of first colormap entry and number of entries
+ sz = stbi__get8(s); // check bits per palette color entry
+ if ( (sz != 8) && (sz != 15) && (sz != 16) && (sz != 24) && (sz != 32) ) goto errorEnd;
+ stbi__skip(s,4); // skip image x and y origin
+ } else { // "normal" image w/o colormap
+ if ( (sz != 2) && (sz != 3) && (sz != 10) && (sz != 11) ) goto errorEnd; // only RGB or grey allowed, +/- RLE
+ stbi__skip(s,9); // skip colormap specification and image x/y origin
+ }
+ if ( stbi__get16le(s) < 1 ) goto errorEnd; // test width
+ if ( stbi__get16le(s) < 1 ) goto errorEnd; // test height
+ sz = stbi__get8(s); // bits per pixel
+ if ( (tga_color_type == 1) && (sz != 8) && (sz != 16) ) goto errorEnd; // for colormapped images, bpp is size of an index
+ if ( (sz != 8) && (sz != 15) && (sz != 16) && (sz != 24) && (sz != 32) ) goto errorEnd;
+
+ res = 1; // if we got this far, everything's good and we can return 1 instead of 0
+
+errorEnd:
+ stbi__rewind(s);
+ return res;
+}
+
+// read 16bit value and convert to 24bit RGB
+static void stbi__tga_read_rgb16(stbi__context *s, stbi_uc* out)
+{
+ stbi__uint16 px = (stbi__uint16)stbi__get16le(s);
+ stbi__uint16 fiveBitMask = 31;
+ // we have 3 channels with 5bits each
+ int r = (px >> 10) & fiveBitMask;
+ int g = (px >> 5) & fiveBitMask;
+ int b = px & fiveBitMask;
+ // Note that this saves the data in RGB(A) order, so it doesn't need to be swapped later
+ out[0] = (stbi_uc)((r * 255)/31);
+ out[1] = (stbi_uc)((g * 255)/31);
+ out[2] = (stbi_uc)((b * 255)/31);
+
+ // some people claim that the most significant bit might be used for alpha
+ // (possibly if an alpha-bit is set in the "image descriptor byte")
+ // but that only made 16bit test images completely translucent..
+ // so let's treat all 15 and 16bit TGAs as RGB with no alpha.
+}
+
+static void *stbi__tga_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri)
+{
+ // read in the TGA header stuff
+ int tga_offset = stbi__get8(s);
+ int tga_indexed = stbi__get8(s);
+ int tga_image_type = stbi__get8(s);
+ int tga_is_RLE = 0;
+ int tga_palette_start = stbi__get16le(s);
+ int tga_palette_len = stbi__get16le(s);
+ int tga_palette_bits = stbi__get8(s);
+ int tga_x_origin = stbi__get16le(s);
+ int tga_y_origin = stbi__get16le(s);
+ int tga_width = stbi__get16le(s);
+ int tga_height = stbi__get16le(s);
+ int tga_bits_per_pixel = stbi__get8(s);
+ int tga_comp, tga_rgb16=0;
+ int tga_inverted = stbi__get8(s);
+ // int tga_alpha_bits = tga_inverted & 15; // the 4 lowest bits - unused (useless?)
+ // image data
+ unsigned char *tga_data;
+ unsigned char *tga_palette = NULL;
+ int i, j;
+ unsigned char raw_data[4] = {0};
+ int RLE_count = 0;
+ int RLE_repeating = 0;
+ int read_next_pixel = 1;
+ STBI_NOTUSED(ri);
+ STBI_NOTUSED(tga_x_origin); // @TODO
+ STBI_NOTUSED(tga_y_origin); // @TODO
+
+ if (tga_height > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)");
+ if (tga_width > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)");
+
+ // do a tiny bit of precessing
+ if ( tga_image_type >= 8 )
+ {
+ tga_image_type -= 8;
+ tga_is_RLE = 1;
+ }
+ tga_inverted = 1 - ((tga_inverted >> 5) & 1);
+
+ // If I'm paletted, then I'll use the number of bits from the palette
+ if ( tga_indexed ) tga_comp = stbi__tga_get_comp(tga_palette_bits, 0, &tga_rgb16);
+ else tga_comp = stbi__tga_get_comp(tga_bits_per_pixel, (tga_image_type == 3), &tga_rgb16);
+
+ if(!tga_comp) // shouldn't really happen, stbi__tga_test() should have ensured basic consistency
+ return stbi__errpuc("bad format", "Can't find out TGA pixelformat");
+
+ // tga info
+ *x = tga_width;
+ *y = tga_height;
+ if (comp) *comp = tga_comp;
+
+ if (!stbi__mad3sizes_valid(tga_width, tga_height, tga_comp, 0))
+ return stbi__errpuc("too large", "Corrupt TGA");
+
+ tga_data = (unsigned char*)stbi__malloc_mad3(tga_width, tga_height, tga_comp, 0);
+ if (!tga_data) return stbi__errpuc("outofmem", "Out of memory");
+
+ // skip to the data's starting position (offset usually = 0)
+ stbi__skip(s, tga_offset );
+
+ if ( !tga_indexed && !tga_is_RLE && !tga_rgb16 ) {
+ for (i=0; i < tga_height; ++i) {
+ int row = tga_inverted ? tga_height -i - 1 : i;
+ stbi_uc *tga_row = tga_data + row*tga_width*tga_comp;
+ stbi__getn(s, tga_row, tga_width * tga_comp);
+ }
+ } else {
+ // do I need to load a palette?
+ if ( tga_indexed)
+ {
+ if (tga_palette_len == 0) { /* you have to have at least one entry! */
+ STBI_FREE(tga_data);
+ return stbi__errpuc("bad palette", "Corrupt TGA");
+ }
+
+ // any data to skip? (offset usually = 0)
+ stbi__skip(s, tga_palette_start );
+ // load the palette
+ tga_palette = (unsigned char*)stbi__malloc_mad2(tga_palette_len, tga_comp, 0);
+ if (!tga_palette) {
+ STBI_FREE(tga_data);
+ return stbi__errpuc("outofmem", "Out of memory");
+ }
+ if (tga_rgb16) {
+ stbi_uc *pal_entry = tga_palette;
+ STBI_ASSERT(tga_comp == STBI_rgb);
+ for (i=0; i < tga_palette_len; ++i) {
+ stbi__tga_read_rgb16(s, pal_entry);
+ pal_entry += tga_comp;
+ }
+ } else if (!stbi__getn(s, tga_palette, tga_palette_len * tga_comp)) {
+ STBI_FREE(tga_data);
+ STBI_FREE(tga_palette);
+ return stbi__errpuc("bad palette", "Corrupt TGA");
+ }
+ }
+ // load the data
+ for (i=0; i < tga_width * tga_height; ++i)
+ {
+ // if I'm in RLE mode, do I need to get a RLE stbi__pngchunk?
+ if ( tga_is_RLE )
+ {
+ if ( RLE_count == 0 )
+ {
+ // yep, get the next byte as a RLE command
+ int RLE_cmd = stbi__get8(s);
+ RLE_count = 1 + (RLE_cmd & 127);
+ RLE_repeating = RLE_cmd >> 7;
+ read_next_pixel = 1;
+ } else if ( !RLE_repeating )
+ {
+ read_next_pixel = 1;
+ }
+ } else
+ {
+ read_next_pixel = 1;
+ }
+ // OK, if I need to read a pixel, do it now
+ if ( read_next_pixel )
+ {
+ // load however much data we did have
+ if ( tga_indexed )
+ {
+ // read in index, then perform the lookup
+ int pal_idx = (tga_bits_per_pixel == 8) ? stbi__get8(s) : stbi__get16le(s);
+ if ( pal_idx >= tga_palette_len ) {
+ // invalid index
+ pal_idx = 0;
+ }
+ pal_idx *= tga_comp;
+ for (j = 0; j < tga_comp; ++j) {
+ raw_data[j] = tga_palette[pal_idx+j];
+ }
+ } else if(tga_rgb16) {
+ STBI_ASSERT(tga_comp == STBI_rgb);
+ stbi__tga_read_rgb16(s, raw_data);
+ } else {
+ // read in the data raw
+ for (j = 0; j < tga_comp; ++j) {
+ raw_data[j] = stbi__get8(s);
+ }
+ }
+ // clear the reading flag for the next pixel
+ read_next_pixel = 0;
+ } // end of reading a pixel
+
+ // copy data
+ for (j = 0; j < tga_comp; ++j)
+ tga_data[i*tga_comp+j] = raw_data[j];
+
+ // in case we're in RLE mode, keep counting down
+ --RLE_count;
+ }
+ // do I need to invert the image?
+ if ( tga_inverted )
+ {
+ for (j = 0; j*2 < tga_height; ++j)
+ {
+ int index1 = j * tga_width * tga_comp;
+ int index2 = (tga_height - 1 - j) * tga_width * tga_comp;
+ for (i = tga_width * tga_comp; i > 0; --i)
+ {
+ unsigned char temp = tga_data[index1];
+ tga_data[index1] = tga_data[index2];
+ tga_data[index2] = temp;
+ ++index1;
+ ++index2;
+ }
+ }
+ }
+ // clear my palette, if I had one
+ if ( tga_palette != NULL )
+ {
+ STBI_FREE( tga_palette );
+ }
+ }
+
+ // swap RGB - if the source data was RGB16, it already is in the right order
+ if (tga_comp >= 3 && !tga_rgb16)
+ {
+ unsigned char* tga_pixel = tga_data;
+ for (i=0; i < tga_width * tga_height; ++i)
+ {
+ unsigned char temp = tga_pixel[0];
+ tga_pixel[0] = tga_pixel[2];
+ tga_pixel[2] = temp;
+ tga_pixel += tga_comp;
+ }
+ }
+
+ // convert to target component count
+ if (req_comp && req_comp != tga_comp)
+ tga_data = stbi__convert_format(tga_data, tga_comp, req_comp, tga_width, tga_height);
+
+ // the things I do to get rid of an error message, and yet keep
+ // Microsoft's C compilers happy... [8^(
+ tga_palette_start = tga_palette_len = tga_palette_bits =
+ tga_x_origin = tga_y_origin = 0;
+ STBI_NOTUSED(tga_palette_start);
+ // OK, done
+ return tga_data;
+}
+#endif
+
+// *************************************************************************************************
+// Photoshop PSD loader -- PD by Thatcher Ulrich, integration by Nicolas Schulz, tweaked by STB
+
+#ifndef STBI_NO_PSD
+static int stbi__psd_test(stbi__context *s)
+{
+ int r = (stbi__get32be(s) == 0x38425053);
+ stbi__rewind(s);
+ return r;
+}
+
+static int stbi__psd_decode_rle(stbi__context *s, stbi_uc *p, int pixelCount)
+{
+ int count, nleft, len;
+
+ count = 0;
+ while ((nleft = pixelCount - count) > 0) {
+ len = stbi__get8(s);
+ if (len == 128) {
+ // No-op.
+ } else if (len < 128) {
+ // Copy next len+1 bytes literally.
+ len++;
+ if (len > nleft) return 0; // corrupt data
+ count += len;
+ while (len) {
+ *p = stbi__get8(s);
+ p += 4;
+ len--;
+ }
+ } else if (len > 128) {
+ stbi_uc val;
+ // Next -len+1 bytes in the dest are replicated from next source byte.
+ // (Interpret len as a negative 8-bit int.)
+ len = 257 - len;
+ if (len > nleft) return 0; // corrupt data
+ val = stbi__get8(s);
+ count += len;
+ while (len) {
+ *p = val;
+ p += 4;
+ len--;
+ }
+ }
+ }
+
+ return 1;
+}
+
+static void *stbi__psd_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri, int bpc)
+{
+ int pixelCount;
+ int channelCount, compression;
+ int channel, i;
+ int bitdepth;
+ int w,h;
+ stbi_uc *out;
+ STBI_NOTUSED(ri);
+
+ // Check identifier
+ if (stbi__get32be(s) != 0x38425053) // "8BPS"
+ return stbi__errpuc("not PSD", "Corrupt PSD image");
+
+ // Check file type version.
+ if (stbi__get16be(s) != 1)
+ return stbi__errpuc("wrong version", "Unsupported version of PSD image");
+
+ // Skip 6 reserved bytes.
+ stbi__skip(s, 6 );
+
+ // Read the number of channels (R, G, B, A, etc).
+ channelCount = stbi__get16be(s);
+ if (channelCount < 0 || channelCount > 16)
+ return stbi__errpuc("wrong channel count", "Unsupported number of channels in PSD image");
+
+ // Read the rows and columns of the image.
+ h = stbi__get32be(s);
+ w = stbi__get32be(s);
+
+ if (h > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)");
+ if (w > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)");
+
+ // Make sure the depth is 8 bits.
+ bitdepth = stbi__get16be(s);
+ if (bitdepth != 8 && bitdepth != 16)
+ return stbi__errpuc("unsupported bit depth", "PSD bit depth is not 8 or 16 bit");
+
+ // Make sure the color mode is RGB.
+ // Valid options are:
+ // 0: Bitmap
+ // 1: Grayscale
+ // 2: Indexed color
+ // 3: RGB color
+ // 4: CMYK color
+ // 7: Multichannel
+ // 8: Duotone
+ // 9: Lab color
+ if (stbi__get16be(s) != 3)
+ return stbi__errpuc("wrong color format", "PSD is not in RGB color format");
+
+ // Skip the Mode Data. (It's the palette for indexed color; other info for other modes.)
+ stbi__skip(s,stbi__get32be(s) );
+
+ // Skip the image resources. (resolution, pen tool paths, etc)
+ stbi__skip(s, stbi__get32be(s) );
+
+ // Skip the reserved data.
+ stbi__skip(s, stbi__get32be(s) );
+
+ // Find out if the data is compressed.
+ // Known values:
+ // 0: no compression
+ // 1: RLE compressed
+ compression = stbi__get16be(s);
+ if (compression > 1)
+ return stbi__errpuc("bad compression", "PSD has an unknown compression format");
+
+ // Check size
+ if (!stbi__mad3sizes_valid(4, w, h, 0))
+ return stbi__errpuc("too large", "Corrupt PSD");
+
+ // Create the destination image.
+
+ if (!compression && bitdepth == 16 && bpc == 16) {
+ out = (stbi_uc *) stbi__malloc_mad3(8, w, h, 0);
+ ri->bits_per_channel = 16;
+ } else
+ out = (stbi_uc *) stbi__malloc(4 * w*h);
+
+ if (!out) return stbi__errpuc("outofmem", "Out of memory");
+ pixelCount = w*h;
+
+ // Initialize the data to zero.
+ //memset( out, 0, pixelCount * 4 );
+
+ // Finally, the image data.
+ if (compression) {
+ // RLE as used by .PSD and .TIFF
+ // Loop until you get the number of unpacked bytes you are expecting:
+ // Read the next source byte into n.
+ // If n is between 0 and 127 inclusive, copy the next n+1 bytes literally.
+ // Else if n is between -127 and -1 inclusive, copy the next byte -n+1 times.
+ // Else if n is 128, noop.
+ // Endloop
+
+ // The RLE-compressed data is preceded by a 2-byte data count for each row in the data,
+ // which we're going to just skip.
+ stbi__skip(s, h * channelCount * 2 );
+
+ // Read the RLE data by channel.
+ for (channel = 0; channel < 4; channel++) {
+ stbi_uc *p;
+
+ p = out+channel;
+ if (channel >= channelCount) {
+ // Fill this channel with default data.
+ for (i = 0; i < pixelCount; i++, p += 4)
+ *p = (channel == 3 ? 255 : 0);
+ } else {
+ // Read the RLE data.
+ if (!stbi__psd_decode_rle(s, p, pixelCount)) {
+ STBI_FREE(out);
+ return stbi__errpuc("corrupt", "bad RLE data");
+ }
+ }
+ }
+
+ } else {
+ // We're at the raw image data. It's each channel in order (Red, Green, Blue, Alpha, ...)
+ // where each channel consists of an 8-bit (or 16-bit) value for each pixel in the image.
+
+ // Read the data by channel.
+ for (channel = 0; channel < 4; channel++) {
+ if (channel >= channelCount) {
+ // Fill this channel with default data.
+ if (bitdepth == 16 && bpc == 16) {
+ stbi__uint16 *q = ((stbi__uint16 *) out) + channel;
+ stbi__uint16 val = channel == 3 ? 65535 : 0;
+ for (i = 0; i < pixelCount; i++, q += 4)
+ *q = val;
+ } else {
+ stbi_uc *p = out+channel;
+ stbi_uc val = channel == 3 ? 255 : 0;
+ for (i = 0; i < pixelCount; i++, p += 4)
+ *p = val;
+ }
+ } else {
+ if (ri->bits_per_channel == 16) { // output bpc
+ stbi__uint16 *q = ((stbi__uint16 *) out) + channel;
+ for (i = 0; i < pixelCount; i++, q += 4)
+ *q = (stbi__uint16) stbi__get16be(s);
+ } else {
+ stbi_uc *p = out+channel;
+ if (bitdepth == 16) { // input bpc
+ for (i = 0; i < pixelCount; i++, p += 4)
+ *p = (stbi_uc) (stbi__get16be(s) >> 8);
+ } else {
+ for (i = 0; i < pixelCount; i++, p += 4)
+ *p = stbi__get8(s);
+ }
+ }
+ }
+ }
+ }
+
+ // remove weird white matte from PSD
+ if (channelCount >= 4) {
+ if (ri->bits_per_channel == 16) {
+ for (i=0; i < w*h; ++i) {
+ stbi__uint16 *pixel = (stbi__uint16 *) out + 4*i;
+ if (pixel[3] != 0 && pixel[3] != 65535) {
+ float a = pixel[3] / 65535.0f;
+ float ra = 1.0f / a;
+ float inv_a = 65535.0f * (1 - ra);
+ pixel[0] = (stbi__uint16) (pixel[0]*ra + inv_a);
+ pixel[1] = (stbi__uint16) (pixel[1]*ra + inv_a);
+ pixel[2] = (stbi__uint16) (pixel[2]*ra + inv_a);
+ }
+ }
+ } else {
+ for (i=0; i < w*h; ++i) {
+ unsigned char *pixel = out + 4*i;
+ if (pixel[3] != 0 && pixel[3] != 255) {
+ float a = pixel[3] / 255.0f;
+ float ra = 1.0f / a;
+ float inv_a = 255.0f * (1 - ra);
+ pixel[0] = (unsigned char) (pixel[0]*ra + inv_a);
+ pixel[1] = (unsigned char) (pixel[1]*ra + inv_a);
+ pixel[2] = (unsigned char) (pixel[2]*ra + inv_a);
+ }
+ }
+ }
+ }
+
+ // convert to desired output format
+ if (req_comp && req_comp != 4) {
+ if (ri->bits_per_channel == 16)
+ out = (stbi_uc *) stbi__convert_format16((stbi__uint16 *) out, 4, req_comp, w, h);
+ else
+ out = stbi__convert_format(out, 4, req_comp, w, h);
+ if (out == NULL) return out; // stbi__convert_format frees input on failure
+ }
+
+ if (comp) *comp = 4;
+ *y = h;
+ *x = w;
+
+ return out;
+}
+#endif
+
+// *************************************************************************************************
+// Softimage PIC loader
+// by Tom Seddon
+//
+// See http://softimage.wiki.softimage.com/index.php/INFO:_PIC_file_format
+// See http://ozviz.wasp.uwa.edu.au/~pbourke/dataformats/softimagepic/
+
+#ifndef STBI_NO_PIC
+static int stbi__pic_is4(stbi__context *s,const char *str)
+{
+ int i;
+ for (i=0; i<4; ++i)
+ if (stbi__get8(s) != (stbi_uc)str[i])
+ return 0;
+
+ return 1;
+}
+
+static int stbi__pic_test_core(stbi__context *s)
+{
+ int i;
+
+ if (!stbi__pic_is4(s,"\x53\x80\xF6\x34"))
+ return 0;
+
+ for(i=0;i<84;++i)
+ stbi__get8(s);
+
+ if (!stbi__pic_is4(s,"PICT"))
+ return 0;
+
+ return 1;
+}
+
+typedef struct
+{
+ stbi_uc size,type,channel;
+} stbi__pic_packet;
+
+static stbi_uc *stbi__readval(stbi__context *s, int channel, stbi_uc *dest)
+{
+ int mask=0x80, i;
+
+ for (i=0; i<4; ++i, mask>>=1) {
+ if (channel & mask) {
+ if (stbi__at_eof(s)) return stbi__errpuc("bad file","PIC file too short");
+ dest[i]=stbi__get8(s);
+ }
+ }
+
+ return dest;
+}
+
+static void stbi__copyval(int channel,stbi_uc *dest,const stbi_uc *src)
+{
+ int mask=0x80,i;
+
+ for (i=0;i<4; ++i, mask>>=1)
+ if (channel&mask)
+ dest[i]=src[i];
+}
+
+static stbi_uc *stbi__pic_load_core(stbi__context *s,int width,int height,int *comp, stbi_uc *result)
+{
+ int act_comp=0,num_packets=0,y,chained;
+ stbi__pic_packet packets[10];
+
+ // this will (should...) cater for even some bizarre stuff like having data
+ // for the same channel in multiple packets.
+ do {
+ stbi__pic_packet *packet;
+
+ if (num_packets==sizeof(packets)/sizeof(packets[0]))
+ return stbi__errpuc("bad format","too many packets");
+
+ packet = &packets[num_packets++];
+
+ chained = stbi__get8(s);
+ packet->size = stbi__get8(s);
+ packet->type = stbi__get8(s);
+ packet->channel = stbi__get8(s);
+
+ act_comp |= packet->channel;
+
+ if (stbi__at_eof(s)) return stbi__errpuc("bad file","file too short (reading packets)");
+ if (packet->size != 8) return stbi__errpuc("bad format","packet isn't 8bpp");
+ } while (chained);
+
+ *comp = (act_comp & 0x10 ? 4 : 3); // has alpha channel?
+
+ for(y=0; y<height; ++y) {
+ int packet_idx;
+
+ for(packet_idx=0; packet_idx < num_packets; ++packet_idx) {
+ stbi__pic_packet *packet = &packets[packet_idx];
+ stbi_uc *dest = result+y*width*4;
+
+ switch (packet->type) {
+ default:
+ return stbi__errpuc("bad format","packet has bad compression type");
+
+ case 0: {//uncompressed
+ int x;
+
+ for(x=0;x<width;++x, dest+=4)
+ if (!stbi__readval(s,packet->channel,dest))
+ return 0;
+ break;
+ }
+
+ case 1://Pure RLE
+ {
+ int left=width, i;
+
+ while (left>0) {
+ stbi_uc count,value[4];
+
+ count=stbi__get8(s);
+ if (stbi__at_eof(s)) return stbi__errpuc("bad file","file too short (pure read count)");
+
+ if (count > left)
+ count = (stbi_uc) left;
+
+ if (!stbi__readval(s,packet->channel,value)) return 0;
+
+ for(i=0; i<count; ++i,dest+=4)
+ stbi__copyval(packet->channel,dest,value);
+ left -= count;
+ }
+ }
+ break;
+
+ case 2: {//Mixed RLE
+ int left=width;
+ while (left>0) {
+ int count = stbi__get8(s), i;
+ if (stbi__at_eof(s)) return stbi__errpuc("bad file","file too short (mixed read count)");
+
+ if (count >= 128) { // Repeated
+ stbi_uc value[4];
+
+ if (count==128)
+ count = stbi__get16be(s);
+ else
+ count -= 127;
+ if (count > left)
+ return stbi__errpuc("bad file","scanline overrun");
+
+ if (!stbi__readval(s,packet->channel,value))
+ return 0;
+
+ for(i=0;i<count;++i, dest += 4)
+ stbi__copyval(packet->channel,dest,value);
+ } else { // Raw
+ ++count;
+ if (count>left) return stbi__errpuc("bad file","scanline overrun");
+
+ for(i=0;i<count;++i, dest+=4)
+ if (!stbi__readval(s,packet->channel,dest))
+ return 0;
+ }
+ left-=count;
+ }
+ break;
+ }
+ }
+ }
+ }
+
+ return result;
+}
+
+static void *stbi__pic_load(stbi__context *s,int *px,int *py,int *comp,int req_comp, stbi__result_info *ri)
+{
+ stbi_uc *result;
+ int i, x,y, internal_comp;
+ STBI_NOTUSED(ri);
+
+ if (!comp) comp = &internal_comp;
+
+ for (i=0; i<92; ++i)
+ stbi__get8(s);
+
+ x = stbi__get16be(s);
+ y = stbi__get16be(s);
+
+ if (y > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)");
+ if (x > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)");
+
+ if (stbi__at_eof(s)) return stbi__errpuc("bad file","file too short (pic header)");
+ if (!stbi__mad3sizes_valid(x, y, 4, 0)) return stbi__errpuc("too large", "PIC image too large to decode");
+
+ stbi__get32be(s); //skip `ratio'
+ stbi__get16be(s); //skip `fields'
+ stbi__get16be(s); //skip `pad'
+
+ // intermediate buffer is RGBA
+ result = (stbi_uc *) stbi__malloc_mad3(x, y, 4, 0);
+ if (!result) return stbi__errpuc("outofmem", "Out of memory");
+ memset(result, 0xff, x*y*4);
+
+ if (!stbi__pic_load_core(s,x,y,comp, result)) {
+ STBI_FREE(result);
+ result=0;
+ }
+ *px = x;
+ *py = y;
+ if (req_comp == 0) req_comp = *comp;
+ result=stbi__convert_format(result,4,req_comp,x,y);
+
+ return result;
+}
+
+static int stbi__pic_test(stbi__context *s)
+{
+ int r = stbi__pic_test_core(s);
+ stbi__rewind(s);
+ return r;
+}
+#endif
+
+// *************************************************************************************************
+// GIF loader -- public domain by Jean-Marc Lienher -- simplified/shrunk by stb
+
+#ifndef STBI_NO_GIF
+typedef struct
+{
+ stbi__int16 prefix;
+ stbi_uc first;
+ stbi_uc suffix;
+} stbi__gif_lzw;
+
+typedef struct
+{
+ int w,h;
+ stbi_uc *out; // output buffer (always 4 components)
+ stbi_uc *background; // The current "background" as far as a gif is concerned
+ stbi_uc *history;
+ int flags, bgindex, ratio, transparent, eflags;
+ stbi_uc pal[256][4];
+ stbi_uc lpal[256][4];
+ stbi__gif_lzw codes[8192];
+ stbi_uc *color_table;
+ int parse, step;
+ int lflags;
+ int start_x, start_y;
+ int max_x, max_y;
+ int cur_x, cur_y;
+ int line_size;
+ int delay;
+} stbi__gif;
+
+static int stbi__gif_test_raw(stbi__context *s)
+{
+ int sz;
+ if (stbi__get8(s) != 'G' || stbi__get8(s) != 'I' || stbi__get8(s) != 'F' || stbi__get8(s) != '8') return 0;
+ sz = stbi__get8(s);
+ if (sz != '9' && sz != '7') return 0;
+ if (stbi__get8(s) != 'a') return 0;
+ return 1;
+}
+
+static int stbi__gif_test(stbi__context *s)
+{
+ int r = stbi__gif_test_raw(s);
+ stbi__rewind(s);
+ return r;
+}
+
+static void stbi__gif_parse_colortable(stbi__context *s, stbi_uc pal[256][4], int num_entries, int transp)
+{
+ int i;
+ for (i=0; i < num_entries; ++i) {
+ pal[i][2] = stbi__get8(s);
+ pal[i][1] = stbi__get8(s);
+ pal[i][0] = stbi__get8(s);
+ pal[i][3] = transp == i ? 0 : 255;
+ }
+}
+
+static int stbi__gif_header(stbi__context *s, stbi__gif *g, int *comp, int is_info)
+{
+ stbi_uc version;
+ if (stbi__get8(s) != 'G' || stbi__get8(s) != 'I' || stbi__get8(s) != 'F' || stbi__get8(s) != '8')
+ return stbi__err("not GIF", "Corrupt GIF");
+
+ version = stbi__get8(s);
+ if (version != '7' && version != '9') return stbi__err("not GIF", "Corrupt GIF");
+ if (stbi__get8(s) != 'a') return stbi__err("not GIF", "Corrupt GIF");
+
+ stbi__g_failure_reason = "";
+ g->w = stbi__get16le(s);
+ g->h = stbi__get16le(s);
+ g->flags = stbi__get8(s);
+ g->bgindex = stbi__get8(s);
+ g->ratio = stbi__get8(s);
+ g->transparent = -1;
+
+ if (g->w > STBI_MAX_DIMENSIONS) return stbi__err("too large","Very large image (corrupt?)");
+ if (g->h > STBI_MAX_DIMENSIONS) return stbi__err("too large","Very large image (corrupt?)");
+
+ if (comp != 0) *comp = 4; // can't actually tell whether it's 3 or 4 until we parse the comments
+
+ if (is_info) return 1;
+
+ if (g->flags & 0x80)
+ stbi__gif_parse_colortable(s,g->pal, 2 << (g->flags & 7), -1);
+
+ return 1;
+}
+
+static int stbi__gif_info_raw(stbi__context *s, int *x, int *y, int *comp)
+{
+ stbi__gif* g = (stbi__gif*) stbi__malloc(sizeof(stbi__gif));
+ if (!g) return stbi__err("outofmem", "Out of memory");
+ if (!stbi__gif_header(s, g, comp, 1)) {
+ STBI_FREE(g);
+ stbi__rewind( s );
+ return 0;
+ }
+ if (x) *x = g->w;
+ if (y) *y = g->h;
+ STBI_FREE(g);
+ return 1;
+}
+
+static void stbi__out_gif_code(stbi__gif *g, stbi__uint16 code)
+{
+ stbi_uc *p, *c;
+ int idx;
+
+ // recurse to decode the prefixes, since the linked-list is backwards,
+ // and working backwards through an interleaved image would be nasty
+ if (g->codes[code].prefix >= 0)
+ stbi__out_gif_code(g, g->codes[code].prefix);
+
+ if (g->cur_y >= g->max_y) return;
+
+ idx = g->cur_x + g->cur_y;
+ p = &g->out[idx];
+ g->history[idx / 4] = 1;
+
+ c = &g->color_table[g->codes[code].suffix * 4];
+ if (c[3] > 128) { // don't render transparent pixels;
+ p[0] = c[2];
+ p[1] = c[1];
+ p[2] = c[0];
+ p[3] = c[3];
+ }
+ g->cur_x += 4;
+
+ if (g->cur_x >= g->max_x) {
+ g->cur_x = g->start_x;
+ g->cur_y += g->step;
+
+ while (g->cur_y >= g->max_y && g->parse > 0) {
+ g->step = (1 << g->parse) * g->line_size;
+ g->cur_y = g->start_y + (g->step >> 1);
+ --g->parse;
+ }
+ }
+}
+
+static stbi_uc *stbi__process_gif_raster(stbi__context *s, stbi__gif *g)
+{
+ stbi_uc lzw_cs;
+ stbi__int32 len, init_code;
+ stbi__uint32 first;
+ stbi__int32 codesize, codemask, avail, oldcode, bits, valid_bits, clear;
+ stbi__gif_lzw *p;
+
+ lzw_cs = stbi__get8(s);
+ if (lzw_cs > 12) return NULL;
+ clear = 1 << lzw_cs;
+ first = 1;
+ codesize = lzw_cs + 1;
+ codemask = (1 << codesize) - 1;
+ bits = 0;
+ valid_bits = 0;
+ for (init_code = 0; init_code < clear; init_code++) {
+ g->codes[init_code].prefix = -1;
+ g->codes[init_code].first = (stbi_uc) init_code;
+ g->codes[init_code].suffix = (stbi_uc) init_code;
+ }
+
+ // support no starting clear code
+ avail = clear+2;
+ oldcode = -1;
+
+ len = 0;
+ for(;;) {
+ if (valid_bits < codesize) {
+ if (len == 0) {
+ len = stbi__get8(s); // start new block
+ if (len == 0)
+ return g->out;
+ }
+ --len;
+ bits |= (stbi__int32) stbi__get8(s) << valid_bits;
+ valid_bits += 8;
+ } else {
+ stbi__int32 code = bits & codemask;
+ bits >>= codesize;
+ valid_bits -= codesize;
+ // @OPTIMIZE: is there some way we can accelerate the non-clear path?
+ if (code == clear) { // clear code
+ codesize = lzw_cs + 1;
+ codemask = (1 << codesize) - 1;
+ avail = clear + 2;
+ oldcode = -1;
+ first = 0;
+ } else if (code == clear + 1) { // end of stream code
+ stbi__skip(s, len);
+ while ((len = stbi__get8(s)) > 0)
+ stbi__skip(s,len);
+ return g->out;
+ } else if (code <= avail) {
+ if (first) {
+ return stbi__errpuc("no clear code", "Corrupt GIF");
+ }
+
+ if (oldcode >= 0) {
+ p = &g->codes[avail++];
+ if (avail > 8192) {
+ return stbi__errpuc("too many codes", "Corrupt GIF");
+ }
+
+ p->prefix = (stbi__int16) oldcode;
+ p->first = g->codes[oldcode].first;
+ p->suffix = (code == avail) ? p->first : g->codes[code].first;
+ } else if (code == avail)
+ return stbi__errpuc("illegal code in raster", "Corrupt GIF");
+
+ stbi__out_gif_code(g, (stbi__uint16) code);
+
+ if ((avail & codemask) == 0 && avail <= 0x0FFF) {
+ codesize++;
+ codemask = (1 << codesize) - 1;
+ }
+
+ oldcode = code;
+ } else {
+ return stbi__errpuc("illegal code in raster", "Corrupt GIF");
+ }
+ }
+ }
+}
+
+// this function is designed to support animated gifs, although stb_image doesn't support it
+// two back is the image from two frames ago, used for a very specific disposal format
+static stbi_uc *stbi__gif_load_next(stbi__context *s, stbi__gif *g, int *comp, int req_comp, stbi_uc *two_back)
+{
+ int dispose;
+ int first_frame;
+ int pi;
+ int pcount;
+ STBI_NOTUSED(req_comp);
+
+ // on first frame, any non-written pixels get the background colour (non-transparent)
+ first_frame = 0;
+ if (g->out == 0) {
+ if (!stbi__gif_header(s, g, comp,0)) return 0; // stbi__g_failure_reason set by stbi__gif_header
+ if (!stbi__mad3sizes_valid(4, g->w, g->h, 0))
+ return stbi__errpuc("too large", "GIF image is too large");
+ pcount = g->w * g->h;
+ g->out = (stbi_uc *) stbi__malloc(4 * pcount);
+ g->background = (stbi_uc *) stbi__malloc(4 * pcount);
+ g->history = (stbi_uc *) stbi__malloc(pcount);
+ if (!g->out || !g->background || !g->history)
+ return stbi__errpuc("outofmem", "Out of memory");
+
+ // image is treated as "transparent" at the start - ie, nothing overwrites the current background;
+ // background colour is only used for pixels that are not rendered first frame, after that "background"
+ // color refers to the color that was there the previous frame.
+ memset(g->out, 0x00, 4 * pcount);
+ memset(g->background, 0x00, 4 * pcount); // state of the background (starts transparent)
+ memset(g->history, 0x00, pcount); // pixels that were affected previous frame
+ first_frame = 1;
+ } else {
+ // second frame - how do we dispose of the previous one?
+ dispose = (g->eflags & 0x1C) >> 2;
+ pcount = g->w * g->h;
+
+ if ((dispose == 3) && (two_back == 0)) {
+ dispose = 2; // if I don't have an image to revert back to, default to the old background
+ }
+
+ if (dispose == 3) { // use previous graphic
+ for (pi = 0; pi < pcount; ++pi) {
+ if (g->history[pi]) {
+ memcpy( &g->out[pi * 4], &two_back[pi * 4], 4 );
+ }
+ }
+ } else if (dispose == 2) {
+ // restore what was changed last frame to background before that frame;
+ for (pi = 0; pi < pcount; ++pi) {
+ if (g->history[pi]) {
+ memcpy( &g->out[pi * 4], &g->background[pi * 4], 4 );
+ }
+ }
+ } else {
+ // This is a non-disposal case eithe way, so just
+ // leave the pixels as is, and they will become the new background
+ // 1: do not dispose
+ // 0: not specified.
+ }
+
+ // background is what out is after the undoing of the previou frame;
+ memcpy( g->background, g->out, 4 * g->w * g->h );
+ }
+
+ // clear my history;
+ memset( g->history, 0x00, g->w * g->h ); // pixels that were affected previous frame
+
+ for (;;) {
+ int tag = stbi__get8(s);
+ switch (tag) {
+ case 0x2C: /* Image Descriptor */
+ {
+ stbi__int32 x, y, w, h;
+ stbi_uc *o;
+
+ x = stbi__get16le(s);
+ y = stbi__get16le(s);
+ w = stbi__get16le(s);
+ h = stbi__get16le(s);
+ if (((x + w) > (g->w)) || ((y + h) > (g->h)))
+ return stbi__errpuc("bad Image Descriptor", "Corrupt GIF");
+
+ g->line_size = g->w * 4;
+ g->start_x = x * 4;
+ g->start_y = y * g->line_size;
+ g->max_x = g->start_x + w * 4;
+ g->max_y = g->start_y + h * g->line_size;
+ g->cur_x = g->start_x;
+ g->cur_y = g->start_y;
+
+ // if the width of the specified rectangle is 0, that means
+ // we may not see *any* pixels or the image is malformed;
+ // to make sure this is caught, move the current y down to
+ // max_y (which is what out_gif_code checks).
+ if (w == 0)
+ g->cur_y = g->max_y;
+
+ g->lflags = stbi__get8(s);
+
+ if (g->lflags & 0x40) {
+ g->step = 8 * g->line_size; // first interlaced spacing
+ g->parse = 3;
+ } else {
+ g->step = g->line_size;
+ g->parse = 0;
+ }
+
+ if (g->lflags & 0x80) {
+ stbi__gif_parse_colortable(s,g->lpal, 2 << (g->lflags & 7), g->eflags & 0x01 ? g->transparent : -1);
+ g->color_table = (stbi_uc *) g->lpal;
+ } else if (g->flags & 0x80) {
+ g->color_table = (stbi_uc *) g->pal;
+ } else
+ return stbi__errpuc("missing color table", "Corrupt GIF");
+
+ o = stbi__process_gif_raster(s, g);
+ if (!o) return NULL;
+
+ // if this was the first frame,
+ pcount = g->w * g->h;
+ if (first_frame && (g->bgindex > 0)) {
+ // if first frame, any pixel not drawn to gets the background color
+ for (pi = 0; pi < pcount; ++pi) {
+ if (g->history[pi] == 0) {
+ g->pal[g->bgindex][3] = 255; // just in case it was made transparent, undo that; It will be reset next frame if need be;
+ memcpy( &g->out[pi * 4], &g->pal[g->bgindex], 4 );
+ }
+ }
+ }
+
+ return o;
+ }
+
+ case 0x21: // Comment Extension.
+ {
+ int len;
+ int ext = stbi__get8(s);
+ if (ext == 0xF9) { // Graphic Control Extension.
+ len = stbi__get8(s);
+ if (len == 4) {
+ g->eflags = stbi__get8(s);
+ g->delay = 10 * stbi__get16le(s); // delay - 1/100th of a second, saving as 1/1000ths.
+
+ // unset old transparent
+ if (g->transparent >= 0) {
+ g->pal[g->transparent][3] = 255;
+ }
+ if (g->eflags & 0x01) {
+ g->transparent = stbi__get8(s);
+ if (g->transparent >= 0) {
+ g->pal[g->transparent][3] = 0;
+ }
+ } else {
+ // don't need transparent
+ stbi__skip(s, 1);
+ g->transparent = -1;
+ }
+ } else {
+ stbi__skip(s, len);
+ break;
+ }
+ }
+ while ((len = stbi__get8(s)) != 0) {
+ stbi__skip(s, len);
+ }
+ break;
+ }
+
+ case 0x3B: // gif stream termination code
+ return (stbi_uc *) s; // using '1' causes warning on some compilers
+
+ default:
+ return stbi__errpuc("unknown code", "Corrupt GIF");
+ }
+ }
+}
+
+static void *stbi__load_gif_main_outofmem(stbi__gif *g, stbi_uc *out, int **delays)
+{
+ STBI_FREE(g->out);
+ STBI_FREE(g->history);
+ STBI_FREE(g->background);
+
+ if (out) STBI_FREE(out);
+ if (delays && *delays) STBI_FREE(*delays);
+ return stbi__errpuc("outofmem", "Out of memory");
+}
+
+static void *stbi__load_gif_main(stbi__context *s, int **delays, int *x, int *y, int *z, int *comp, int req_comp)
+{
+ if (stbi__gif_test(s)) {
+ int layers = 0;
+ stbi_uc *u = 0;
+ stbi_uc *out = 0;
+ stbi_uc *two_back = 0;
+ stbi__gif g;
+ int stride;
+ int out_size = 0;
+ int delays_size = 0;
+
+ STBI_NOTUSED(out_size);
+ STBI_NOTUSED(delays_size);
+
+ memset(&g, 0, sizeof(g));
+ if (delays) {
+ *delays = 0;
+ }
+
+ do {
+ u = stbi__gif_load_next(s, &g, comp, req_comp, two_back);
+ if (u == (stbi_uc *) s) u = 0; // end of animated gif marker
+
+ if (u) {
+ *x = g.w;
+ *y = g.h;
+ ++layers;
+ stride = g.w * g.h * 4;
+
+ if (out) {
+ void *tmp = (stbi_uc*) STBI_REALLOC_SIZED( out, out_size, layers * stride );
+ if (!tmp)
+ return stbi__load_gif_main_outofmem(&g, out, delays);
+ else {
+ out = (stbi_uc*) tmp;
+ out_size = layers * stride;
+ }
+
+ if (delays) {
+ int *new_delays = (int*) STBI_REALLOC_SIZED( *delays, delays_size, sizeof(int) * layers );
+ if (!new_delays)
+ return stbi__load_gif_main_outofmem(&g, out, delays);
+ *delays = new_delays;
+ delays_size = layers * sizeof(int);
+ }
+ } else {
+ out = (stbi_uc*)stbi__malloc( layers * stride );
+ if (!out)
+ return stbi__load_gif_main_outofmem(&g, out, delays);
+ out_size = layers * stride;
+ if (delays) {
+ *delays = (int*) stbi__malloc( layers * sizeof(int) );
+ if (!*delays)
+ return stbi__load_gif_main_outofmem(&g, out, delays);
+ delays_size = layers * sizeof(int);
+ }
+ }
+ memcpy( out + ((layers - 1) * stride), u, stride );
+ if (layers >= 2) {
+ two_back = out - 2 * stride;
+ }
+
+ if (delays) {
+ (*delays)[layers - 1U] = g.delay;
+ }
+ }
+ } while (u != 0);
+
+ // free temp buffer;
+ STBI_FREE(g.out);
+ STBI_FREE(g.history);
+ STBI_FREE(g.background);
+
+ // do the final conversion after loading everything;
+ if (req_comp && req_comp != 4)
+ out = stbi__convert_format(out, 4, req_comp, layers * g.w, g.h);
+
+ *z = layers;
+ return out;
+ } else {
+ return stbi__errpuc("not GIF", "Image was not as a gif type.");
+ }
+}
+
+static void *stbi__gif_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri)
+{
+ stbi_uc *u = 0;
+ stbi__gif g;
+ memset(&g, 0, sizeof(g));
+ STBI_NOTUSED(ri);
+
+ u = stbi__gif_load_next(s, &g, comp, req_comp, 0);
+ if (u == (stbi_uc *) s) u = 0; // end of animated gif marker
+ if (u) {
+ *x = g.w;
+ *y = g.h;
+
+ // moved conversion to after successful load so that the same
+ // can be done for multiple frames.
+ if (req_comp && req_comp != 4)
+ u = stbi__convert_format(u, 4, req_comp, g.w, g.h);
+ } else if (g.out) {
+ // if there was an error and we allocated an image buffer, free it!
+ STBI_FREE(g.out);
+ }
+
+ // free buffers needed for multiple frame loading;
+ STBI_FREE(g.history);
+ STBI_FREE(g.background);
+
+ return u;
+}
+
+static int stbi__gif_info(stbi__context *s, int *x, int *y, int *comp)
+{
+ return stbi__gif_info_raw(s,x,y,comp);
+}
+#endif
+
+// *************************************************************************************************
+// Radiance RGBE HDR loader
+// originally by Nicolas Schulz
+#ifndef STBI_NO_HDR
+static int stbi__hdr_test_core(stbi__context *s, const char *signature)
+{
+ int i;
+ for (i=0; signature[i]; ++i)
+ if (stbi__get8(s) != signature[i])
+ return 0;
+ stbi__rewind(s);
+ return 1;
+}
+
+static int stbi__hdr_test(stbi__context* s)
+{
+ int r = stbi__hdr_test_core(s, "#?RADIANCE\n");
+ stbi__rewind(s);
+ if(!r) {
+ r = stbi__hdr_test_core(s, "#?RGBE\n");
+ stbi__rewind(s);
+ }
+ return r;
+}
+
+#define STBI__HDR_BUFLEN 1024
+static char *stbi__hdr_gettoken(stbi__context *z, char *buffer)
+{
+ int len=0;
+ char c = '\0';
+
+ c = (char) stbi__get8(z);
+
+ while (!stbi__at_eof(z) && c != '\n') {
+ buffer[len++] = c;
+ if (len == STBI__HDR_BUFLEN-1) {
+ // flush to end of line
+ while (!stbi__at_eof(z) && stbi__get8(z) != '\n')
+ ;
+ break;
+ }
+ c = (char) stbi__get8(z);
+ }
+
+ buffer[len] = 0;
+ return buffer;
+}
+
+static void stbi__hdr_convert(float *output, stbi_uc *input, int req_comp)
+{
+ if ( input[3] != 0 ) {
+ float f1;
+ // Exponent
+ f1 = (float) ldexp(1.0f, input[3] - (int)(128 + 8));
+ if (req_comp <= 2)
+ output[0] = (input[0] + input[1] + input[2]) * f1 / 3;
+ else {
+ output[0] = input[0] * f1;
+ output[1] = input[1] * f1;
+ output[2] = input[2] * f1;
+ }
+ if (req_comp == 2) output[1] = 1;
+ if (req_comp == 4) output[3] = 1;
+ } else {
+ switch (req_comp) {
+ case 4: output[3] = 1; /* fallthrough */
+ case 3: output[0] = output[1] = output[2] = 0;
+ break;
+ case 2: output[1] = 1; /* fallthrough */
+ case 1: output[0] = 0;
+ break;
+ }
+ }
+}
+
+static float *stbi__hdr_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri)
+{
+ char buffer[STBI__HDR_BUFLEN];
+ char *token;
+ int valid = 0;
+ int width, height;
+ stbi_uc *scanline;
+ float *hdr_data;
+ int len;
+ unsigned char count, value;
+ int i, j, k, c1,c2, z;
+ const char *headerToken;
+ STBI_NOTUSED(ri);
+
+ // Check identifier
+ headerToken = stbi__hdr_gettoken(s,buffer);
+ if (strcmp(headerToken, "#?RADIANCE") != 0 && strcmp(headerToken, "#?RGBE") != 0)
+ return stbi__errpf("not HDR", "Corrupt HDR image");
+
+ // Parse header
+ for(;;) {
+ token = stbi__hdr_gettoken(s,buffer);
+ if (token[0] == 0) break;
+ if (strcmp(token, "FORMAT=32-bit_rle_rgbe") == 0) valid = 1;
+ }
+
+ if (!valid) return stbi__errpf("unsupported format", "Unsupported HDR format");
+
+ // Parse width and height
+ // can't use sscanf() if we're not using stdio!
+ token = stbi__hdr_gettoken(s,buffer);
+ if (strncmp(token, "-Y ", 3)) return stbi__errpf("unsupported data layout", "Unsupported HDR format");
+ token += 3;
+ height = (int) strtol(token, &token, 10);
+ while (*token == ' ') ++token;
+ if (strncmp(token, "+X ", 3)) return stbi__errpf("unsupported data layout", "Unsupported HDR format");
+ token += 3;
+ width = (int) strtol(token, NULL, 10);
+
+ if (height > STBI_MAX_DIMENSIONS) return stbi__errpf("too large","Very large image (corrupt?)");
+ if (width > STBI_MAX_DIMENSIONS) return stbi__errpf("too large","Very large image (corrupt?)");
+
+ *x = width;
+ *y = height;
+
+ if (comp) *comp = 3;
+ if (req_comp == 0) req_comp = 3;
+
+ if (!stbi__mad4sizes_valid(width, height, req_comp, sizeof(float), 0))
+ return stbi__errpf("too large", "HDR image is too large");
+
+ // Read data
+ hdr_data = (float *) stbi__malloc_mad4(width, height, req_comp, sizeof(float), 0);
+ if (!hdr_data)
+ return stbi__errpf("outofmem", "Out of memory");
+
+ // Load image data
+ // image data is stored as some number of sca
+ if ( width < 8 || width >= 32768) {
+ // Read flat data
+ for (j=0; j < height; ++j) {
+ for (i=0; i < width; ++i) {
+ stbi_uc rgbe[4];
+ main_decode_loop:
+ stbi__getn(s, rgbe, 4);
+ stbi__hdr_convert(hdr_data + j * width * req_comp + i * req_comp, rgbe, req_comp);
+ }
+ }
+ } else {
+ // Read RLE-encoded data
+ scanline = NULL;
+
+ for (j = 0; j < height; ++j) {
+ c1 = stbi__get8(s);
+ c2 = stbi__get8(s);
+ len = stbi__get8(s);
+ if (c1 != 2 || c2 != 2 || (len & 0x80)) {
+ // not run-length encoded, so we have to actually use THIS data as a decoded
+ // pixel (note this can't be a valid pixel--one of RGB must be >= 128)
+ stbi_uc rgbe[4];
+ rgbe[0] = (stbi_uc) c1;
+ rgbe[1] = (stbi_uc) c2;
+ rgbe[2] = (stbi_uc) len;
+ rgbe[3] = (stbi_uc) stbi__get8(s);
+ stbi__hdr_convert(hdr_data, rgbe, req_comp);
+ i = 1;
+ j = 0;
+ STBI_FREE(scanline);
+ goto main_decode_loop; // yes, this makes no sense
+ }
+ len <<= 8;
+ len |= stbi__get8(s);
+ if (len != width) { STBI_FREE(hdr_data); STBI_FREE(scanline); return stbi__errpf("invalid decoded scanline length", "corrupt HDR"); }
+ if (scanline == NULL) {
+ scanline = (stbi_uc *) stbi__malloc_mad2(width, 4, 0);
+ if (!scanline) {
+ STBI_FREE(hdr_data);
+ return stbi__errpf("outofmem", "Out of memory");
+ }
+ }
+
+ for (k = 0; k < 4; ++k) {
+ int nleft;
+ i = 0;
+ while ((nleft = width - i) > 0) {
+ count = stbi__get8(s);
+ if (count > 128) {
+ // Run
+ value = stbi__get8(s);
+ count -= 128;
+ if ((count == 0) || (count > nleft)) { STBI_FREE(hdr_data); STBI_FREE(scanline); return stbi__errpf("corrupt", "bad RLE data in HDR"); }
+ for (z = 0; z < count; ++z)
+ scanline[i++ * 4 + k] = value;
+ } else {
+ // Dump
+ if ((count == 0) || (count > nleft)) { STBI_FREE(hdr_data); STBI_FREE(scanline); return stbi__errpf("corrupt", "bad RLE data in HDR"); }
+ for (z = 0; z < count; ++z)
+ scanline[i++ * 4 + k] = stbi__get8(s);
+ }
+ }
+ }
+ for (i=0; i < width; ++i)
+ stbi__hdr_convert(hdr_data+(j*width + i)*req_comp, scanline + i*4, req_comp);
+ }
+ if (scanline)
+ STBI_FREE(scanline);
+ }
+
+ return hdr_data;
+}
+
+static int stbi__hdr_info(stbi__context *s, int *x, int *y, int *comp)
+{
+ char buffer[STBI__HDR_BUFLEN];
+ char *token;
+ int valid = 0;
+ int dummy;
+
+ if (!x) x = &dummy;
+ if (!y) y = &dummy;
+ if (!comp) comp = &dummy;
+
+ if (stbi__hdr_test(s) == 0) {
+ stbi__rewind( s );
+ return 0;
+ }
+
+ for(;;) {
+ token = stbi__hdr_gettoken(s,buffer);
+ if (token[0] == 0) break;
+ if (strcmp(token, "FORMAT=32-bit_rle_rgbe") == 0) valid = 1;
+ }
+
+ if (!valid) {
+ stbi__rewind( s );
+ return 0;
+ }
+ token = stbi__hdr_gettoken(s,buffer);
+ if (strncmp(token, "-Y ", 3)) {
+ stbi__rewind( s );
+ return 0;
+ }
+ token += 3;
+ *y = (int) strtol(token, &token, 10);
+ while (*token == ' ') ++token;
+ if (strncmp(token, "+X ", 3)) {
+ stbi__rewind( s );
+ return 0;
+ }
+ token += 3;
+ *x = (int) strtol(token, NULL, 10);
+ *comp = 3;
+ return 1;
+}
+#endif // STBI_NO_HDR
+
+#ifndef STBI_NO_BMP
+static int stbi__bmp_info(stbi__context *s, int *x, int *y, int *comp)
+{
+ void *p;
+ stbi__bmp_data info;
+
+ info.all_a = 255;
+ p = stbi__bmp_parse_header(s, &info);
+ if (p == NULL) {
+ stbi__rewind( s );
+ return 0;
+ }
+ if (x) *x = s->img_x;
+ if (y) *y = s->img_y;
+ if (comp) {
+ if (info.bpp == 24 && info.ma == 0xff000000)
+ *comp = 3;
+ else
+ *comp = info.ma ? 4 : 3;
+ }
+ return 1;
+}
+#endif
+
+#ifndef STBI_NO_PSD
+static int stbi__psd_info(stbi__context *s, int *x, int *y, int *comp)
+{
+ int channelCount, dummy, depth;
+ if (!x) x = &dummy;
+ if (!y) y = &dummy;
+ if (!comp) comp = &dummy;
+ if (stbi__get32be(s) != 0x38425053) {
+ stbi__rewind( s );
+ return 0;
+ }
+ if (stbi__get16be(s) != 1) {
+ stbi__rewind( s );
+ return 0;
+ }
+ stbi__skip(s, 6);
+ channelCount = stbi__get16be(s);
+ if (channelCount < 0 || channelCount > 16) {
+ stbi__rewind( s );
+ return 0;
+ }
+ *y = stbi__get32be(s);
+ *x = stbi__get32be(s);
+ depth = stbi__get16be(s);
+ if (depth != 8 && depth != 16) {
+ stbi__rewind( s );
+ return 0;
+ }
+ if (stbi__get16be(s) != 3) {
+ stbi__rewind( s );
+ return 0;
+ }
+ *comp = 4;
+ return 1;
+}
+
+static int stbi__psd_is16(stbi__context *s)
+{
+ int channelCount, depth;
+ if (stbi__get32be(s) != 0x38425053) {
+ stbi__rewind( s );
+ return 0;
+ }
+ if (stbi__get16be(s) != 1) {
+ stbi__rewind( s );
+ return 0;
+ }
+ stbi__skip(s, 6);
+ channelCount = stbi__get16be(s);
+ if (channelCount < 0 || channelCount > 16) {
+ stbi__rewind( s );
+ return 0;
+ }
+ STBI_NOTUSED(stbi__get32be(s));
+ STBI_NOTUSED(stbi__get32be(s));
+ depth = stbi__get16be(s);
+ if (depth != 16) {
+ stbi__rewind( s );
+ return 0;
+ }
+ return 1;
+}
+#endif
+
+#ifndef STBI_NO_PIC
+static int stbi__pic_info(stbi__context *s, int *x, int *y, int *comp)
+{
+ int act_comp=0,num_packets=0,chained,dummy;
+ stbi__pic_packet packets[10];
+
+ if (!x) x = &dummy;
+ if (!y) y = &dummy;
+ if (!comp) comp = &dummy;
+
+ if (!stbi__pic_is4(s,"\x53\x80\xF6\x34")) {
+ stbi__rewind(s);
+ return 0;
+ }
+
+ stbi__skip(s, 88);
+
+ *x = stbi__get16be(s);
+ *y = stbi__get16be(s);
+ if (stbi__at_eof(s)) {
+ stbi__rewind( s);
+ return 0;
+ }
+ if ( (*x) != 0 && (1 << 28) / (*x) < (*y)) {
+ stbi__rewind( s );
+ return 0;
+ }
+
+ stbi__skip(s, 8);
+
+ do {
+ stbi__pic_packet *packet;
+
+ if (num_packets==sizeof(packets)/sizeof(packets[0]))
+ return 0;
+
+ packet = &packets[num_packets++];
+ chained = stbi__get8(s);
+ packet->size = stbi__get8(s);
+ packet->type = stbi__get8(s);
+ packet->channel = stbi__get8(s);
+ act_comp |= packet->channel;
+
+ if (stbi__at_eof(s)) {
+ stbi__rewind( s );
+ return 0;
+ }
+ if (packet->size != 8) {
+ stbi__rewind( s );
+ return 0;
+ }
+ } while (chained);
+
+ *comp = (act_comp & 0x10 ? 4 : 3);
+
+ return 1;
+}
+#endif
+
+// *************************************************************************************************
+// Portable Gray Map and Portable Pixel Map loader
+// by Ken Miller
+//
+// PGM: http://netpbm.sourceforge.net/doc/pgm.html
+// PPM: http://netpbm.sourceforge.net/doc/ppm.html
+//
+// Known limitations:
+// Does not support comments in the header section
+// Does not support ASCII image data (formats P2 and P3)
+
+#ifndef STBI_NO_PNM
+
+static int stbi__pnm_test(stbi__context *s)
+{
+ char p, t;
+ p = (char) stbi__get8(s);
+ t = (char) stbi__get8(s);
+ if (p != 'P' || (t != '5' && t != '6')) {
+ stbi__rewind( s );
+ return 0;
+ }
+ return 1;
+}
+
+static void *stbi__pnm_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri)
+{
+ stbi_uc *out;
+ STBI_NOTUSED(ri);
+
+ ri->bits_per_channel = stbi__pnm_info(s, (int *)&s->img_x, (int *)&s->img_y, (int *)&s->img_n);
+ if (ri->bits_per_channel == 0)
+ return 0;
+
+ if (s->img_y > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)");
+ if (s->img_x > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)");
+
+ *x = s->img_x;
+ *y = s->img_y;
+ if (comp) *comp = s->img_n;
+
+ if (!stbi__mad4sizes_valid(s->img_n, s->img_x, s->img_y, ri->bits_per_channel / 8, 0))
+ return stbi__errpuc("too large", "PNM too large");
+
+ out = (stbi_uc *) stbi__malloc_mad4(s->img_n, s->img_x, s->img_y, ri->bits_per_channel / 8, 0);
+ if (!out) return stbi__errpuc("outofmem", "Out of memory");
+ if (!stbi__getn(s, out, s->img_n * s->img_x * s->img_y * (ri->bits_per_channel / 8))) {
+ STBI_FREE(out);
+ return stbi__errpuc("bad PNM", "PNM file truncated");
+ }
+
+ if (req_comp && req_comp != s->img_n) {
+ if (ri->bits_per_channel == 16) {
+ out = (stbi_uc *) stbi__convert_format16((stbi__uint16 *) out, s->img_n, req_comp, s->img_x, s->img_y);
+ } else {
+ out = stbi__convert_format(out, s->img_n, req_comp, s->img_x, s->img_y);
+ }
+ if (out == NULL) return out; // stbi__convert_format frees input on failure
+ }
+ return out;
+}
+
+static int stbi__pnm_isspace(char c)
+{
+ return c == ' ' || c == '\t' || c == '\n' || c == '\v' || c == '\f' || c == '\r';
+}
+
+static void stbi__pnm_skip_whitespace(stbi__context *s, char *c)
+{
+ for (;;) {
+ while (!stbi__at_eof(s) && stbi__pnm_isspace(*c))
+ *c = (char) stbi__get8(s);
+
+ if (stbi__at_eof(s) || *c != '#')
+ break;
+
+ while (!stbi__at_eof(s) && *c != '\n' && *c != '\r' )
+ *c = (char) stbi__get8(s);
+ }
+}
+
+static int stbi__pnm_isdigit(char c)
+{
+ return c >= '0' && c <= '9';
+}
+
+static int stbi__pnm_getinteger(stbi__context *s, char *c)
+{
+ int value = 0;
+
+ while (!stbi__at_eof(s) && stbi__pnm_isdigit(*c)) {
+ value = value*10 + (*c - '0');
+ *c = (char) stbi__get8(s);
+ if((value > 214748364) || (value == 214748364 && *c > '7'))
+ return stbi__err("integer parse overflow", "Parsing an integer in the PPM header overflowed a 32-bit int");
+ }
+
+ return value;
+}
+
+static int stbi__pnm_info(stbi__context *s, int *x, int *y, int *comp)
+{
+ int maxv, dummy;
+ char c, p, t;
+
+ if (!x) x = &dummy;
+ if (!y) y = &dummy;
+ if (!comp) comp = &dummy;
+
+ stbi__rewind(s);
+
+ // Get identifier
+ p = (char) stbi__get8(s);
+ t = (char) stbi__get8(s);
+ if (p != 'P' || (t != '5' && t != '6')) {
+ stbi__rewind(s);
+ return 0;
+ }
+
+ *comp = (t == '6') ? 3 : 1; // '5' is 1-component .pgm; '6' is 3-component .ppm
+
+ c = (char) stbi__get8(s);
+ stbi__pnm_skip_whitespace(s, &c);
+
+ *x = stbi__pnm_getinteger(s, &c); // read width
+ if(*x == 0)
+ return stbi__err("invalid width", "PPM image header had zero or overflowing width");
+ stbi__pnm_skip_whitespace(s, &c);
+
+ *y = stbi__pnm_getinteger(s, &c); // read height
+ if (*y == 0)
+ return stbi__err("invalid width", "PPM image header had zero or overflowing width");
+ stbi__pnm_skip_whitespace(s, &c);
+
+ maxv = stbi__pnm_getinteger(s, &c); // read max value
+ if (maxv > 65535)
+ return stbi__err("max value > 65535", "PPM image supports only 8-bit and 16-bit images");
+ else if (maxv > 255)
+ return 16;
+ else
+ return 8;
+}
+
+static int stbi__pnm_is16(stbi__context *s)
+{
+ if (stbi__pnm_info(s, NULL, NULL, NULL) == 16)
+ return 1;
+ return 0;
+}
+#endif
+
+static int stbi__info_main(stbi__context *s, int *x, int *y, int *comp)
+{
+ #ifndef STBI_NO_JPEG
+ if (stbi__jpeg_info(s, x, y, comp)) return 1;
+ #endif
+
+ #ifndef STBI_NO_PNG
+ if (stbi__png_info(s, x, y, comp)) return 1;
+ #endif
+
+ #ifndef STBI_NO_GIF
+ if (stbi__gif_info(s, x, y, comp)) return 1;
+ #endif
+
+ #ifndef STBI_NO_BMP
+ if (stbi__bmp_info(s, x, y, comp)) return 1;
+ #endif
+
+ #ifndef STBI_NO_PSD
+ if (stbi__psd_info(s, x, y, comp)) return 1;
+ #endif
+
+ #ifndef STBI_NO_PIC
+ if (stbi__pic_info(s, x, y, comp)) return 1;
+ #endif
+
+ #ifndef STBI_NO_PNM
+ if (stbi__pnm_info(s, x, y, comp)) return 1;
+ #endif
+
+ #ifndef STBI_NO_HDR
+ if (stbi__hdr_info(s, x, y, comp)) return 1;
+ #endif
+
+ // test tga last because it's a crappy test!
+ #ifndef STBI_NO_TGA
+ if (stbi__tga_info(s, x, y, comp))
+ return 1;
+ #endif
+ return stbi__err("unknown image type", "Image not of any known type, or corrupt");
+}
+
+static int stbi__is_16_main(stbi__context *s)
+{
+ #ifndef STBI_NO_PNG
+ if (stbi__png_is16(s)) return 1;
+ #endif
+
+ #ifndef STBI_NO_PSD
+ if (stbi__psd_is16(s)) return 1;
+ #endif
+
+ #ifndef STBI_NO_PNM
+ if (stbi__pnm_is16(s)) return 1;
+ #endif
+ return 0;
+}
+
+#ifndef STBI_NO_STDIO
+STBIDEF int stbi_info(char const *filename, int *x, int *y, int *comp)
+{
+ FILE *f = stbi__fopen(filename, "rb");
+ int result;
+ if (!f) return stbi__err("can't fopen", "Unable to open file");
+ result = stbi_info_from_file(f, x, y, comp);
+ fclose(f);
+ return result;
+}
+
+STBIDEF int stbi_info_from_file(FILE *f, int *x, int *y, int *comp)
+{
+ int r;
+ stbi__context s;
+ long pos = ftell(f);
+ stbi__start_file(&s, f);
+ r = stbi__info_main(&s,x,y,comp);
+ fseek(f,pos,SEEK_SET);
+ return r;
+}
+
+STBIDEF int stbi_is_16_bit(char const *filename)
+{
+ FILE *f = stbi__fopen(filename, "rb");
+ int result;
+ if (!f) return stbi__err("can't fopen", "Unable to open file");
+ result = stbi_is_16_bit_from_file(f);
+ fclose(f);
+ return result;
+}
+
+STBIDEF int stbi_is_16_bit_from_file(FILE *f)
+{
+ int r;
+ stbi__context s;
+ long pos = ftell(f);
+ stbi__start_file(&s, f);
+ r = stbi__is_16_main(&s);
+ fseek(f,pos,SEEK_SET);
+ return r;
+}
+#endif // !STBI_NO_STDIO
+
+STBIDEF int stbi_info_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp)
+{
+ stbi__context s;
+ stbi__start_mem(&s,buffer,len);
+ return stbi__info_main(&s,x,y,comp);
+}
+
+STBIDEF int stbi_info_from_callbacks(stbi_io_callbacks const *c, void *user, int *x, int *y, int *comp)
+{
+ stbi__context s;
+ stbi__start_callbacks(&s, (stbi_io_callbacks *) c, user);
+ return stbi__info_main(&s,x,y,comp);
+}
+
+STBIDEF int stbi_is_16_bit_from_memory(stbi_uc const *buffer, int len)
+{
+ stbi__context s;
+ stbi__start_mem(&s,buffer,len);
+ return stbi__is_16_main(&s);
+}
+
+STBIDEF int stbi_is_16_bit_from_callbacks(stbi_io_callbacks const *c, void *user)
+{
+ stbi__context s;
+ stbi__start_callbacks(&s, (stbi_io_callbacks *) c, user);
+ return stbi__is_16_main(&s);
+}
+
+#endif // STB_IMAGE_IMPLEMENTATION
+
+/*
+ revision history:
+ 2.20 (2019-02-07) support utf8 filenames in Windows; fix warnings and platform ifdefs
+ 2.19 (2018-02-11) fix warning
+ 2.18 (2018-01-30) fix warnings
+ 2.17 (2018-01-29) change sbti__shiftsigned to avoid clang -O2 bug
+ 1-bit BMP
+ *_is_16_bit api
+ avoid warnings
+ 2.16 (2017-07-23) all functions have 16-bit variants;
+ STBI_NO_STDIO works again;
+ compilation fixes;
+ fix rounding in unpremultiply;
+ optimize vertical flip;
+ disable raw_len validation;
+ documentation fixes
+ 2.15 (2017-03-18) fix png-1,2,4 bug; now all Imagenet JPGs decode;
+ warning fixes; disable run-time SSE detection on gcc;
+ uniform handling of optional "return" values;
+ thread-safe initialization of zlib tables
+ 2.14 (2017-03-03) remove deprecated STBI_JPEG_OLD; fixes for Imagenet JPGs
+ 2.13 (2016-11-29) add 16-bit API, only supported for PNG right now
+ 2.12 (2016-04-02) fix typo in 2.11 PSD fix that caused crashes
+ 2.11 (2016-04-02) allocate large structures on the stack
+ remove white matting for transparent PSD
+ fix reported channel count for PNG & BMP
+ re-enable SSE2 in non-gcc 64-bit
+ support RGB-formatted JPEG
+ read 16-bit PNGs (only as 8-bit)
+ 2.10 (2016-01-22) avoid warning introduced in 2.09 by STBI_REALLOC_SIZED
+ 2.09 (2016-01-16) allow comments in PNM files
+ 16-bit-per-pixel TGA (not bit-per-component)
+ info() for TGA could break due to .hdr handling
+ info() for BMP to shares code instead of sloppy parse
+ can use STBI_REALLOC_SIZED if allocator doesn't support realloc
+ code cleanup
+ 2.08 (2015-09-13) fix to 2.07 cleanup, reading RGB PSD as RGBA
+ 2.07 (2015-09-13) fix compiler warnings
+ partial animated GIF support
+ limited 16-bpc PSD support
+ #ifdef unused functions
+ bug with < 92 byte PIC,PNM,HDR,TGA
+ 2.06 (2015-04-19) fix bug where PSD returns wrong '*comp' value
+ 2.05 (2015-04-19) fix bug in progressive JPEG handling, fix warning
+ 2.04 (2015-04-15) try to re-enable SIMD on MinGW 64-bit
+ 2.03 (2015-04-12) extra corruption checking (mmozeiko)
+ stbi_set_flip_vertically_on_load (nguillemot)
+ fix NEON support; fix mingw support
+ 2.02 (2015-01-19) fix incorrect assert, fix warning
+ 2.01 (2015-01-17) fix various warnings; suppress SIMD on gcc 32-bit without -msse2
+ 2.00b (2014-12-25) fix STBI_MALLOC in progressive JPEG
+ 2.00 (2014-12-25) optimize JPG, including x86 SSE2 & NEON SIMD (ryg)
+ progressive JPEG (stb)
+ PGM/PPM support (Ken Miller)
+ STBI_MALLOC,STBI_REALLOC,STBI_FREE
+ GIF bugfix -- seemingly never worked
+ STBI_NO_*, STBI_ONLY_*
+ 1.48 (2014-12-14) fix incorrectly-named assert()
+ 1.47 (2014-12-14) 1/2/4-bit PNG support, both direct and paletted (Omar Cornut & stb)
+ optimize PNG (ryg)
+ fix bug in interlaced PNG with user-specified channel count (stb)
+ 1.46 (2014-08-26)
+ fix broken tRNS chunk (colorkey-style transparency) in non-paletted PNG
+ 1.45 (2014-08-16)
+ fix MSVC-ARM internal compiler error by wrapping malloc
+ 1.44 (2014-08-07)
+ various warning fixes from Ronny Chevalier
+ 1.43 (2014-07-15)
+ fix MSVC-only compiler problem in code changed in 1.42
+ 1.42 (2014-07-09)
+ don't define _CRT_SECURE_NO_WARNINGS (affects user code)
+ fixes to stbi__cleanup_jpeg path
+ added STBI_ASSERT to avoid requiring assert.h
+ 1.41 (2014-06-25)
+ fix search&replace from 1.36 that messed up comments/error messages
+ 1.40 (2014-06-22)
+ fix gcc struct-initialization warning
+ 1.39 (2014-06-15)
+ fix to TGA optimization when req_comp != number of components in TGA;
+ fix to GIF loading because BMP wasn't rewinding (whoops, no GIFs in my test suite)
+ add support for BMP version 5 (more ignored fields)
+ 1.38 (2014-06-06)
+ suppress MSVC warnings on integer casts truncating values
+ fix accidental rename of 'skip' field of I/O
+ 1.37 (2014-06-04)
+ remove duplicate typedef
+ 1.36 (2014-06-03)
+ convert to header file single-file library
+ if de-iphone isn't set, load iphone images color-swapped instead of returning NULL
+ 1.35 (2014-05-27)
+ various warnings
+ fix broken STBI_SIMD path
+ fix bug where stbi_load_from_file no longer left file pointer in correct place
+ fix broken non-easy path for 32-bit BMP (possibly never used)
+ TGA optimization by Arseny Kapoulkine
+ 1.34 (unknown)
+ use STBI_NOTUSED in stbi__resample_row_generic(), fix one more leak in tga failure case
+ 1.33 (2011-07-14)
+ make stbi_is_hdr work in STBI_NO_HDR (as specified), minor compiler-friendly improvements
+ 1.32 (2011-07-13)
+ support for "info" function for all supported filetypes (SpartanJ)
+ 1.31 (2011-06-20)
+ a few more leak fixes, bug in PNG handling (SpartanJ)
+ 1.30 (2011-06-11)
+ added ability to load files via callbacks to accomidate custom input streams (Ben Wenger)
+ removed deprecated format-specific test/load functions
+ removed support for installable file formats (stbi_loader) -- would have been broken for IO callbacks anyway
+ error cases in bmp and tga give messages and don't leak (Raymond Barbiero, grisha)
+ fix inefficiency in decoding 32-bit BMP (David Woo)
+ 1.29 (2010-08-16)
+ various warning fixes from Aurelien Pocheville
+ 1.28 (2010-08-01)
+ fix bug in GIF palette transparency (SpartanJ)
+ 1.27 (2010-08-01)
+ cast-to-stbi_uc to fix warnings
+ 1.26 (2010-07-24)
+ fix bug in file buffering for PNG reported by SpartanJ
+ 1.25 (2010-07-17)
+ refix trans_data warning (Won Chun)
+ 1.24 (2010-07-12)
+ perf improvements reading from files on platforms with lock-heavy fgetc()
+ minor perf improvements for jpeg
+ deprecated type-specific functions so we'll get feedback if they're needed
+ attempt to fix trans_data warning (Won Chun)
+ 1.23 fixed bug in iPhone support
+ 1.22 (2010-07-10)
+ removed image *writing* support
+ stbi_info support from Jetro Lauha
+ GIF support from Jean-Marc Lienher
+ iPhone PNG-extensions from James Brown
+ warning-fixes from Nicolas Schulz and Janez Zemva (i.stbi__err. Janez (U+017D)emva)
+ 1.21 fix use of 'stbi_uc' in header (reported by jon blow)
+ 1.20 added support for Softimage PIC, by Tom Seddon
+ 1.19 bug in interlaced PNG corruption check (found by ryg)
+ 1.18 (2008-08-02)
+ fix a threading bug (local mutable static)
+ 1.17 support interlaced PNG
+ 1.16 major bugfix - stbi__convert_format converted one too many pixels
+ 1.15 initialize some fields for thread safety
+ 1.14 fix threadsafe conversion bug
+ header-file-only version (#define STBI_HEADER_FILE_ONLY before including)
+ 1.13 threadsafe
+ 1.12 const qualifiers in the API
+ 1.11 Support installable IDCT, colorspace conversion routines
+ 1.10 Fixes for 64-bit (don't use "unsigned long")
+ optimized upsampling by Fabian "ryg" Giesen
+ 1.09 Fix format-conversion for PSD code (bad global variables!)
+ 1.08 Thatcher Ulrich's PSD code integrated by Nicolas Schulz
+ 1.07 attempt to fix C++ warning/errors again
+ 1.06 attempt to fix C++ warning/errors again
+ 1.05 fix TGA loading to return correct *comp and use good luminance calc
+ 1.04 default float alpha is 1, not 255; use 'void *' for stbi_image_free
+ 1.03 bugfixes to STBI_NO_STDIO, STBI_NO_HDR
+ 1.02 support for (subset of) HDR files, float interface for preferred access to them
+ 1.01 fix bug: possible bug in handling right-side up bmps... not sure
+ fix bug: the stbi__bmp_load() and stbi__tga_load() functions didn't work at all
+ 1.00 interface to zlib that skips zlib header
+ 0.99 correct handling of alpha in palette
+ 0.98 TGA loader by lonesock; dynamically add loaders (untested)
+ 0.97 jpeg errors on too large a file; also catch another malloc failure
+ 0.96 fix detection of invalid v value - particleman@mollyrocket forum
+ 0.95 during header scan, seek to markers in case of padding
+ 0.94 STBI_NO_STDIO to disable stdio usage; rename all #defines the same
+ 0.93 handle jpegtran output; verbose errors
+ 0.92 read 4,8,16,24,32-bit BMP files of several formats
+ 0.91 output 24-bit Windows 3.0 BMP files
+ 0.90 fix a few more warnings; bump version number to approach 1.0
+ 0.61 bugfixes due to Marc LeBlanc, Christopher Lloyd
+ 0.60 fix compiling as c++
+ 0.59 fix warnings: merge Dave Moore's -Wall fixes
+ 0.58 fix bug: zlib uncompressed mode len/nlen was wrong endian
+ 0.57 fix bug: jpg last huffman symbol before marker was >9 bits but less than 16 available
+ 0.56 fix bug: zlib uncompressed mode len vs. nlen
+ 0.55 fix bug: restart_interval not initialized to 0
+ 0.54 allow NULL for 'int *comp'
+ 0.53 fix bug in png 3->4; speedup png decoding
+ 0.52 png handles req_comp=3,4 directly; minor cleanup; jpeg comments
+ 0.51 obey req_comp requests, 1-component jpegs return as 1-component,
+ on 'test' only check type, not whether we support this variant
+ 0.50 (2006-11-19)
+ first released version
+*/
+
+
+/*
+------------------------------------------------------------------------------
+This software is available under 2 licenses -- choose whichever you prefer.
+------------------------------------------------------------------------------
+ALTERNATIVE A - MIT License
+Copyright (c) 2017 Sean Barrett
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+of the Software, and to permit persons to whom the Software is furnished to do
+so, subject to the following conditions:
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+------------------------------------------------------------------------------
+ALTERNATIVE B - Public Domain (www.unlicense.org)
+This is free and unencumbered software released into the public domain.
+Anyone is free to copy, modify, publish, use, compile, sell, or distribute this
+software, either in source code form or as a compiled binary, for any purpose,
+commercial or non-commercial, and by any means.
+In jurisdictions that recognize copyright laws, the author or authors of this
+software dedicate any and all copyright interest in the software to the public
+domain. We make this dedication for the benefit of the public at large and to
+the detriment of our heirs and successors. We intend this dedication to be an
+overt act of relinquishment in perpetuity of all present and future rights to
+this software under copyright law.
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+------------------------------------------------------------------------------
+*/
diff --git a/Rend/demos/teapot/texture.frag.spv b/Rend/demos/teapot/texture.frag.spv
new file mode 100644
index 0000000..09a2e00
--- /dev/null
+++ b/Rend/demos/teapot/texture.frag.spv
Binary files differ
diff --git a/Rend/demos/teapot/texture.vert.spv b/Rend/demos/teapot/texture.vert.spv
new file mode 100644
index 0000000..9e6c442
--- /dev/null
+++ b/Rend/demos/teapot/texture.vert.spv
Binary files differ
diff --git a/Rend/demos/teapot/wal.jpg b/Rend/demos/teapot/wal.jpg
new file mode 100644
index 0000000..d30a9a2
--- /dev/null
+++ b/Rend/demos/teapot/wal.jpg
Binary files differ
diff --git a/Rend/nogl.h b/Rend/nogl.h
new file mode 100644
index 0000000..ab45c90
--- /dev/null
+++ b/Rend/nogl.h
@@ -0,0 +1,141 @@
+/*
+Ideas for Rend 2.0 aka NoGL
+Inspiried by https://www.sebastianaaltonen.com/blog/no-graphics-api
+
+## Style Guide
+
+### Order of Code
+
+1. Includes.
+2. Macros.
+3. Types.
+4. Function declarations.
+5. Global variables.
+6. Function definitions.
+
+### Naming Conventions
+
+1. Use snake_case for variables and functions.
+2. Functions in the format `module_type_action`:
+ - `ui_align_left`
+ - `ui_button_create`
+ - `pl_window_size`
+ 3. Types are in PascalCase, prefixed also by the module name.
+ - `UI_Align`, `PL_Window`.
+ 4. Macros are in UPPERCASE_SNAKE_CASE.
+
+*/
+
+#include <stddef.h>
+#include <stdint.h>
+
+typedef struct NOGL_CommandBufferSpan {
+ struct NOGL_CommandBuffer* data;
+ size_t count;
+} NOGL_CommandBufferSpan;
+
+typedef enum NOGL_Memory {
+ NOGL_MEMORY_DEFAULT,
+ NOGL_MEMORY_UPLOAD,
+ NOGL_MEMORY_READBACK,
+} NOGL_Memory;
+
+typedef enum NOGL_Stage {
+ NOGL_STAGE_NONE,
+ NOGL_STAGE_TRANSFER,
+ NOGL_STAGE_COMPUTE,
+ NOGL_STAGE_VERTEX,
+ NOGL_STAGE_PIXEL,
+} NOGL_Stage;
+
+typedef enum NOGL_Op {
+ NOGL_OP_EQUAL,
+ NOGL_OP_NOT_EQUAL,
+ NOGL_OP_GREATER,
+ NOGL_OP_GREATER_EQUAL,
+ NOGL_OP_LESS,
+ NOGL_OP_LESS_EQUAL,
+} NOGL_Op;
+
+typedef enum NOGL_Signal {
+ NOGL_SIGNAL_FENCE,
+ NOGL_SIGNAL_TIMELINE,
+} NOGL_Signal;
+
+typedef uint32_t NOGL_HazardFlags;
+
+typedef struct NOGL_TextureDesc NOGL_TextureDesc;
+typedef struct NOGL_ViewDesc NOGL_ViewDesc;
+typedef struct NOGL_RasterDesc NOGL_RasterDesc;
+typedef struct NOGL_DepthStencilDesc NOGL_DepthStencilDesc;
+typedef struct NOGL_BlendDesc NOGL_BlendDesc;
+typedef struct NOGL_RenderPassDesc NOGL_RenderPassDesc;
+
+typedef struct NOGL_TextureSizeAlign {
+ size_t size;
+ size_t align;
+} NOGL_TextureSizeAlign;
+
+typedef struct NOGL_Texture { uint64_t handle; } NOGL_Texture;
+typedef struct NOGL_TextureDescriptor { uint64_t handle; } NOGL_TextureDescriptor;
+typedef struct NOGL_Pipeline { uint64_t handle; } NOGL_Pipeline;
+typedef struct NOGL_DepthStencilState { uint64_t handle; } NOGL_DepthStencilState;
+typedef struct NOGL_BlendState { uint64_t handle; } NOGL_BlendState;
+typedef struct NOGL_Queue { uint64_t handle; } NOGL_Queue;
+typedef struct NOGL_CommandBuffer { uint64_t handle; } NOGL_CommandBuffer;
+typedef struct NOGL_Semaphore { uint64_t handle; } NOGL_Semaphore;
+
+void* nogl_mem_alloc(size_t bytes, NOGL_Memory memory = NOGL_MEMORY_DEFAULT);
+void* nogl_mem_alloc_aligned(size_t bytes, size_t align, NOGL_Memory memory = NOGL_MEMORY_DEFAULT);
+void nogl_mem_free(void* ptr);
+void* nogl_mem_host_to_device_ptr(void* ptr);
+
+NOGL_TextureSizeAlign nogl_texture_size_align(NOGL_TextureDesc desc);
+NOGL_Texture nogl_texture_create(NOGL_TextureDesc desc, void* ptr_gpu);
+NOGL_TextureDescriptor nogl_texture_view_descriptor(NOGL_Texture texture, NOGL_ViewDesc desc);
+NOGL_TextureDescriptor nogl_texture_rw_view_descriptor(NOGL_Texture texture, NOGL_ViewDesc desc);
+
+NOGL_Pipeline nogl_pipeline_create_compute_spirv(uint8_t *bytes, size_t size);
+NOGL_Pipeline nogl_pipeline_create_graphics_spirv(uint8_t *vertex_bytes, size_t vertex_size, uint8_t *frag_bytes, size_t frag_size, NOGL_RasterDesc desc);
+NOGL_Pipeline nogl_pipeline_create_meshlet_spirv(uint8_t *meshlet_bytes, size_t meshlet_size, uint8_t *frag_bytes, size_t frag_size, NOGL_RasterDesc desc);
+void nogl_pipeline_destroy(NOGL_Pipeline pipeline);
+
+NOGL_DepthStencilState nogl_depth_stencil_state_create(NOGL_DepthStencilDesc desc);
+NOGL_BlendState nogl_blend_state_create(NOGL_BlendDesc desc);
+void nogl_depth_stencil_state_free(NOGL_DepthStencilState state);
+void nogl_blend_state_free(NOGL_BlendState state);
+
+NOGL_Queue nogl_queue_create(/* device & queue creation details omitted */);
+NOGL_CommandBuffer nogl_command_buffer_start(NOGL_Queue queue);
+void nogl_queue_submit(NOGL_Queue queue, NOGL_CommandBufferSpan command_buffers);
+
+NOGL_Semaphore nogl_semaphore_create(uint64_t init_value);
+void nogl_semaphore_wait(NOGL_Semaphore sema, uint64_t value);
+void nogl_semaphore_destroy(NOGL_Semaphore sema);
+
+void nogl_cmd_mem_copy(NOGL_CommandBuffer cb, void* dest_gpu, void* src_gpu, size_t bytes);
+void nogl_cmd_copy_to_texture(NOGL_CommandBuffer cb, void* dest_gpu, void* src_gpu, NOGL_Texture texture);
+void nogl_cmd_copy_from_texture(NOGL_CommandBuffer cb, void* dest_gpu, void* src_gpu, NOGL_Texture texture);
+
+void nogl_cmd_set_active_texture_heap_ptr(NOGL_CommandBuffer cb, void* ptr_gpu);
+
+void nogl_cmd_barrier(NOGL_CommandBuffer cb, NOGL_Stage before, NOGL_Stage after, NOGL_HazardFlags hazards = 0);
+void nogl_cmd_signal_after(NOGL_CommandBuffer cb, NOGL_Stage before, void* ptr_gpu, uint64_t value, NOGL_Signal signal);
+void nogl_cmd_wait_before(NOGL_CommandBuffer cb, NOGL_Stage after, void* ptr_gpu, uint64_t value, NOGL_Op op, NOGL_HazardFlags hazards, uint64_t mask);
+
+void nogl_cmd_set_pipeline(NOGL_CommandBuffer cb, NOGL_Pipeline pipeline);
+void nogl_cmd_set_depth_stencil_state(NOGL_CommandBuffer cb, NOGL_DepthStencilState state);
+void nogl_cmd_set_blend_state(NOGL_CommandBuffer cb, NOGL_BlendState state);
+
+void nogl_cmd_dispatch(NOGL_CommandBuffer cb, void* data_gpu, uint32_t count_x, uint32_t count_y, uint32_t count_z);
+void nogl_cmd_dispatch_indirect(NOGL_CommandBuffer cb, void* data_gpu, void* grid_dimensions_gpu);
+
+void nogl_cmd_render_pass_begin(NOGL_CommandBuffer cb, NOGL_RenderPassDesc desc);
+void nogl_cmd_render_pass_end(NOGL_CommandBuffer cb);
+
+void nogl_cmd_draw_indexed_instanced(NOGL_CommandBuffer cb, void* vertex_data_gpu, void* pixel_data_gpu, void* indices_gpu, uint32_t index_count, uint32_t instance_count);
+void nogl_cmd_draw_indexed_instanced_indirect(NOGL_CommandBuffer cb, void* vertex_data_gpu, void* pixel_data_gpu, void* indices_gpu, void* args_gpu);
+void nogl_cmd_draw_indexed_instanced_indirect_multi(NOGL_CommandBuffer cb, void* data_vx_gpu, uint32_t vx_stride, void* data_px_gpu, uint32_t px_stride, void* args_gpu, void* draw_count_gpu);
+
+void nogl_cmd_draw_meshlets(NOGL_CommandBuffer cb, void* meshlet_data_gpu, void* pixel_data_gpu, uint32_t count_x, uint32_t count_y, uint32_t count_z);
+void nogl_cmd_draw_meshlets_indirect(NOGL_CommandBuffer cb, void* meshlet_data_gpu, void* pixel_data_gpu, void* dim_gpu);
diff --git a/Rend/podium.h b/Rend/podium.h
new file mode 100644
index 0000000..517774e
--- /dev/null
+++ b/Rend/podium.h
@@ -0,0 +1,2282 @@
+/* ===========================================================================
+ * PODIUM - The Finished Platform Layer - Copyright (c) 2026 Vasco Alves
+ *
+ * ---------------------------------------------------------------------------
+ * To stand on the shoulders of giants...
+ * Giants must stand still!"
+ * - Eskil Steenberg - "You should finish your software" – BSC 2025
+ * ---------------------------------------------------------------------------
+ *
+ * PREFIX: P_ (types) or p_ (functions & variables)
+ *
+ * GOAL:
+ * Replace the standard library, always talk to the os directly.
+ * Besides some optimization and security benefits. Obviously some standard
+ * library functions are highly optimized, namely memory and math
+ * into our code and debug it. Still a lot is left to be desired
+ * and so this library includes it via "modules" which can be imported
+ * by flags.
+ *
+ * DESIGN:
+ * The API is finished. It's done. Newer modules may be added in the future
+ * but that should not change the underlying core. New platforms may also
+ * be added, but the API stays the same.
+ *
+ * COMPILE TIME FLAGS
+ * | Name | Description |
+ * |-----------------|---------------------------------------------------------|
+ * | PODIUM_WIN32 | Used to explicitly compile for Windows. |
+ * | PODIUM_LINUX | Used to explicitly compile for Linux and FreeBSD. |
+ *
+ * MODULES
+ * | Name | Description |
+ * |-----------------|---------------------------------------------------------|
+ * | P_MODULE_VULKAN | Gives access to vulkan related utilities. |
+ * | P_MODULE_STRING | Include string manipulation utilities. |
+ * | P_MODULE_MATH | Trigonometry and linear algebra functions. |
+ * | P_MODULE_ALLOC | Memory allocators: Arena, Stack & Pool. |
+ *
+ * =========================================================================== */
+
+#ifndef _PODIUM_H_
+#define _PODIUM_H_
+
+#define PODIUM_MAJOR "0" // needs more revisions and use to reach 1.0 status
+#define PODIUM_MINOR "2" // vulkan module
+#define PODIUM_PATCH "2" // gamepad
+
+#define POAPI static inline
+#define PODEF static inline
+
+/*
+ * Auto-detect platforms.
+ */
+
+/* Windows */
+#if defined(_WIN32) || defined(_WIN64) || defined(__WIN32__) || defined(__TOS_WIN__)
+ #define PODIUM_WIN32
+ #ifndef WIN32_LEAN_AND_MEAN
+ #define WIN32_LEAN_AND_MEAN
+ #endif
+/* Apple */
+#elif defined(__APPLE__) || defined(__MACH__)
+ #include <TargetConditionals.h>
+ #define PODIUM_APPLE
+ #if TARGET_OS_IPHONE
+ #define PODIUM_IOS
+ #else
+ #define PODIUM_MACOS
+ #endif
+/* Linux / BSD */
+#elif defined(__linux__) || defined(__FreeBSD__)
+ #define PODIUM_LINUX
+ #ifndef _POSIX_C_SOURCE
+ #define _POSIX_C_SOURCE 200112L
+ #endif
+#endif
+
+#include <stdarg.h>
+#include <stdint.h>
+#include <stddef.h>
+#include <string.h> /* memcpy */
+#include <stdio.h> /* vsnprintf */
+
+/*
+ * NOTE: The <REPLACE> comments are used by the build
+ * script to know what includes to inline into the
+ * final single header file!
+ */
+
+/* --- Start of p_types.h --- */
+#ifndef _PODIUM_TYPES_
+#define _PODIUM_TYPES_
+
+#define NANOS_PER_SEC (1000*1000*1000)
+#define P_PI_HALF 1.57079632679f
+#define P_PI 3.14159265f
+#define P_PI2 6.28318531f
+#define P_PI_POW2 9.86960440f
+
+#ifdef NDEBUG
+ #define assert(x) ((void)0)
+#else
+ #ifndef assert
+ #define assert(x) \
+ do { \
+ if (!(x)) { \
+ __builtin_trap(); \
+ } \
+ } while (0)
+ #endif
+#endif
+
+#ifndef BUFSIZ
+ #define BUFSIZ 8192
+#endif
+
+typedef unsigned char u8;
+typedef signed char i8;
+typedef unsigned short u16;
+typedef short i16;
+typedef unsigned int u32;
+typedef int i32;
+typedef unsigned long long u64;
+typedef long long i64;
+typedef float f32;
+typedef double f64;
+
+#ifndef __cplusplus
+#define bool _Bool
+#define false 0
+#define true 1
+#endif
+
+/* C++ uses static_assert, C11 uses _Static_assert */
+#ifdef __cplusplus
+ #define STATIC_ASSERT static_assert
+#else
+ #define STATIC_ASSERT _Static_assert
+#endif
+
+STATIC_ASSERT(sizeof(u8) == 1, "u8 must be 1 byte");
+STATIC_ASSERT(sizeof(u16) == 2, "u16 must be 2 bytes");
+STATIC_ASSERT(sizeof(u32) == 4, "u32 must be 4 bytes");
+STATIC_ASSERT(sizeof(u64) == 8, "u64 must be 8 bytes");
+
+STATIC_ASSERT(sizeof(i8) == 1, "i8 must be 1 byte");
+STATIC_ASSERT(sizeof(i16) == 2, "i16 must be 2 bytes");
+STATIC_ASSERT(sizeof(i32) == 4, "i32 must be 4 bytes");
+STATIC_ASSERT(sizeof(i64) == 8, "i64 must be 8 bytes");
+
+STATIC_ASSERT(sizeof(f32) == 4, "f32 must be 4 bytes");
+STATIC_ASSERT(sizeof(f64) == 8, "f64 must be 8 bytes");
+#define U8_MAX 255
+#define U16_MAX 65535
+#define U32_MAX 4294967295
+
+/* Architecture specific sizing */
+#if defined(__x86_64__) || defined(__aarch64__) || defined(_M_X64)
+ typedef u64 usize;
+ typedef u64 uintptr;
+ typedef u32 idx;
+ STATIC_ASSERT(sizeof(usize) == 8, "usize must be 8 bytes on 64-bit");
+#else
+ typedef u32 usize;
+ typedef u32 uintptr;
+ typedef u16 idx;
+ STATIC_ASSERT(sizeof(usize) == 4, "usize must be 4 bytes on 32-bit");
+#endif
+
+#ifndef NULL
+ #ifdef __cplusplus
+ #define NULL 0
+ #else
+ #define NULL ((void*)0)
+ #endif
+#endif
+
+#endif // _PODIUM_TYPES_
+/* --- End of p_types.h --- */
+/* --- Start of p_log.h --- */
+/*
+ * Logging!
+ */
+
+#include <stdlib.h>
+
+#ifdef DEBUG
+#define LOG_DEBUG(...) PRINTF(__VA_ARGS__)
+#else
+#define LOG_DEBUG(...) ((void)0)
+#endif
+
+/* fatal and error always enabled */
+#define PFATAL(message, ...) p_log_printf(P_LOG_LEVEL_FATAL, message, ##__VA_ARGS__)
+#define PERROR(message, ...) p_log_printf(P_LOG_LEVEL_ERROR, message, ##__VA_ARGS__)
+
+/* warn and info enabled by default but can be disabled */
+#define P_LOG_WARN_ENABLED 1
+#define P_LOG_INFO_ENABLED 1
+
+#if P_LOG_WARN_ENABLED == 1
+#define PWARN(message, ...) p_log_printf(P_LOG_LEVEL_WARN, message, ##__VA_ARGS__)
+#else
+#define PWARN(message, ...)
+#endif
+
+#if P_LOG_INFO_ENABLED == 1
+#define PINFO(message, ...) p_log_printf(P_LOG_LEVEL_INFO, message, ##__VA_ARGS__)
+#else
+#define PINFO(message, ...)
+#endif
+
+#if P_LOG_DEBUG_ENABLED == 1
+#define PDEBUG(message, ...) p_log_printf(P_LOG_LEVEL_DEBUG, message, ##__VA_ARGS__)
+#else
+#define PDEBUG(message, ...)
+#endif
+
+#if P_LOG_TRACE_ENABLED == 1
+#define PTRACE(message, ...) p_log_printf(P_LOG_LEVEL_TRACE, message, ##__VA_ARGS__)
+#else
+#define PTRACE(message, ...)
+#endif
+
+typedef enum P_Log_Level {
+ P_LOG_LEVEL_FATAL = 0,
+ P_LOG_LEVEL_ERROR,
+ P_LOG_LEVEL_WARN,
+ P_LOG_LEVEL_INFO,
+ P_LOG_LEVEL_DEBUG,
+ P_LOG_LEVEL_TRACE,
+ P_COUNT_LOG_LEVEL
+} P_Log_Level;
+
+#define P_PREFIX_LEN 7
+static const char *p_prefix[P_COUNT_LOG_LEVEL] = {
+ [P_LOG_LEVEL_FATAL] = "[FATAL]",
+ [P_LOG_LEVEL_ERROR] = "[ERROR]",
+ [P_LOG_LEVEL_WARN] = "[WARNI]",
+ [P_LOG_LEVEL_INFO] = "[INFOR]",
+ [P_LOG_LEVEL_DEBUG] = "[DEBUG]",
+ [P_LOG_LEVEL_TRACE] = "[TRACE]",
+};
+
+#define P_MAX_ALLOCS 512
+
+typedef struct P_DebugMemoryInfo {
+ void *ptr;
+ size_t size;
+ const char *file;
+ const char *func;
+ int line;
+} P_DebugMemoryInfo;
+
+static uint64_t p_alloc_count = 0;
+static P_DebugMemoryInfo p_ptr_array[P_MAX_ALLOCS];
+
+static inline void *
+p_debug_malloc_impl(size_t size, const char *file, int line, const char *func)
+{
+ void *ptr = malloc(size);
+ printf("[ALLOC] %p (%zu bytes) -> %s:%d %s()\n", ptr, size, file, line, func);
+
+ if (ptr) {
+ if (p_alloc_count < P_MAX_ALLOCS) {
+ p_ptr_array[p_alloc_count++] = (P_DebugMemoryInfo){
+ .ptr = ptr,
+ .size = size,
+ .file = file,
+ .func = func,
+ .line = line
+ };
+ } else {
+ fprintf(stderr, "[ERROR] Debug allocator tracking capacity (%d) exceeded!\n", P_MAX_ALLOCS);
+ }
+ }
+ return ptr;
+}
+
+static inline void
+p_debug_free_impl(void *ptr, const char *file, int line, const char *func)
+{
+ printf("[FREE] %p -> %s:%d %s()\n", ptr, file, line, func);
+
+ if (!ptr) return; // Standard C allows free(NULL)
+
+ bool found = false;
+ uint64_t index = 0;
+
+ /* Find allocation metadata */
+ for (index = 0; index < p_alloc_count; ++index) {
+ if (p_ptr_array[index].ptr == ptr) {
+ found = true;
+ break;
+ }
+ }
+
+ if (found) {
+ /* Shift array left to remove tracked struct */
+ for (uint64_t j = index; j < p_alloc_count - 1; ++j) {
+ p_ptr_array[j] = p_ptr_array[j + 1];
+ }
+ p_alloc_count--;
+ } else {
+ fprintf(stderr, "[WARNING] Attempted to free untracked/double-freed pointer %p at %s:%d %s()\n",
+ ptr, file, line, func);
+ }
+
+ free(ptr);
+}
+
+static inline void *
+p_debug_realloc_impl(void *ptr, size_t size, const char *file, int line, const char *func)
+{
+ if (!ptr) {
+ return p_debug_malloc_impl(size, file, line, func);
+ }
+ if (size == 0) {
+ p_debug_free_impl(ptr, file, line, func);
+ return NULL;
+ }
+
+ void *new_ptr = realloc(ptr, size);
+ printf("[REALLOC] %p -> %p (%zu bytes) -> %s:%d %s()\n", ptr, new_ptr, size, file, line, func);
+
+ if (new_ptr) {
+ bool found = false;
+ for (uint64_t i = 0; i < p_alloc_count; ++i) {
+ if (p_ptr_array[i].ptr == ptr) {
+ p_ptr_array[i].ptr = new_ptr;
+ p_ptr_array[i].size = size;
+ p_ptr_array[i].file = file;
+ p_ptr_array[i].line = line;
+ p_ptr_array[i].func = func;
+ found = true;
+ break;
+ }
+ }
+ if (!found) {
+ if (p_alloc_count < P_MAX_ALLOCS) {
+ p_ptr_array[p_alloc_count++] = (P_DebugMemoryInfo){
+ .ptr = new_ptr,
+ .size = size,
+ .file = file,
+ .func = func,
+ .line = line
+ };
+ }
+ }
+ }
+ return new_ptr;
+}
+
+static void
+p_debug_memory_report(void)
+{
+ printf("\n==================== MEMORY REPORT ====================\n");
+ printf("Remaining unfreed allocations: %lu\n", (unsigned long)p_alloc_count);
+
+ for (uint64_t i = 0; i < p_alloc_count; ++i) {
+ P_DebugMemoryInfo *info = &p_ptr_array[i];
+ printf("[LEAK] %p (%zu bytes) allocated at %s:%d in %s()\n",
+ info->ptr, info->size, info->file, info->line, info->func);
+ }
+ printf("=======================================================\n");
+}
+/* --- End of p_log.h --- */
+/* --- Start of p_ds.h --- */
+#define DEFAULT_ALIGNMENT (2 * sizeof(void *))
+#define ARRAY_GROW_FACTOR 2
+
+typedef struct {
+ u32 size;
+ u32 capacity;
+} DynamicArrayHeader;
+
+#define DARRAY_INIT_CAPACITY 64
+#define p_darray_push(array, var) \
+ do { \
+ if (array == NULL) { \
+ DynamicArrayHeader *header = \
+ malloc(DARRAY_INIT_CAPACITY * sizeof *array + sizeof *header); \
+ header->size = 0; \
+ header->capacity = DARRAY_INIT_CAPACITY; \
+ array = (void *)(header + 1); \
+ } \
+ DynamicArrayHeader *header = (DynamicArrayHeader *)(array) - 1; \
+ if (header->size >= header->capacity - 1) { \
+ unsigned long new_capacity = header->capacity * 2; \
+ DynamicArrayHeader *new_header = \
+ realloc(header, new_capacity * sizeof *array + sizeof *header); \
+ if (!new_header) \
+ break; \
+ header = new_header; \
+ array = (void *)(header + 1); \
+ header->capacity = new_capacity; \
+ } \
+ (array)[header->size++] = var; \
+ } while (0)
+
+#define p_darray_len(array) ((array) ? ((DynamicArrayHeader *)(array) - 1)->size : 0)
+#define p_darray_destroy(array) \
+{ \
+ free((DynamicArrayHeader *)(array) - 1); \
+}
+
+#define p_darray_shrink(array) \
+ do { \
+ DynamicArrayHeader *header = (array) ? ((DynamicArrayHeader *)(array) - 1) : 0;\
+ if (header) {\
+ if (header->capacity > 4) {\
+ unsigned long new_capacity = (header->capacity >> 1) + (header->capacity & 1); \
+ void *new_header = realloc(header, new_capacity * sizeof *array + sizeof *header); \
+ if (!new_header) break; \
+ header = new_header; \
+ array = (void *)(header + 1); \
+ header->capacity = new_capacity; \
+ }\
+ }\
+ } while (0)
+/* --- End of p_ds.h --- */
+
+/*
+ * Main Platform Types (Keyboard, Events, Context, etc.)
+ */
+
+typedef enum {
+ P_KEYMOD_ALT = 0,
+ P_KEYMOD_SHIFT,
+ P_KEYMOD_CTRL,
+ P_KEYMOD_CAPS,
+} P_KeyMod;
+
+typedef enum {
+ P_KEY_UNKNOWN = 0,
+ P_KEY_UP, P_KEY_DOWN, P_KEY_LEFT, P_KEY_RIGHT,
+ P_KEY_SPACE, P_KEY_ESCAPE, P_KEY_ENTER,
+ P_KEY_A, P_KEY_B, P_KEY_C, P_KEY_D, P_KEY_E, P_KEY_F, P_KEY_G, P_KEY_H, P_KEY_I,
+ P_KEY_J, P_KEY_K, P_KEY_L, P_KEY_M, P_KEY_N, P_KEY_O, P_KEY_P, P_KEY_Q, P_KEY_R,
+ P_KEY_S, P_KEY_T, P_KEY_U, P_KEY_V, P_KEY_W, P_KEY_X, P_KEY_Y, P_KEY_Z,
+} P_KeyCode;
+
+/* Platform event type */
+typedef enum {
+ P_EVENT_NONE = 0,
+ P_EVENT_KEY_DOWN,
+ P_EVENT_KEY_UP,
+ P_EVENT_WINDOW_CLOSE,
+ P_EVENT_WINDOW_RESIZE,
+ P_EVENT_POINTER,
+ P_EVENT_CONTROLLER_CONNECTED,
+ P_EVENT_CONTROLLER_DISCONNECTED,
+} P_EvenType;
+
+typedef enum {
+ P_POINTER_MOVED = 0,
+ P_POINTER_PRESSED,
+ P_POINTER_RELEASED
+} P_PointerState;
+
+typedef struct {
+ P_EvenType type;
+ union {
+ struct {P_KeyCode key; P_KeyMod mod; } key;
+ struct { u32 width, height; } resize;
+ struct { P_PointerState state; u32 button; u32 x, y; } pointer;
+ };
+} P_Event;
+
+/*
+ * Platform dependent functions to be implemented by each layer.
+ */
+
+POAPI u64 p_get_time(void); // Get time in nanoseconds.
+POAPI void p_sleep_ns(i64 ns); // Sleep for nanoseconds.
+
+POAPI void p_stdout(void *msg, usize bytes); // Print buffer to stdout.
+PODEF void p_log_printf(P_Log_Level level, const char* src, ...); // Print buffer to stdout.
+
+
+POAPI void* p_file_alloc(const char *path, unsigned long *buf_size);
+POAPI bool p_file_exists(const char *path); // Check if file exists.
+POAPI usize p_file_size(const char *path); // Check file size.
+POAPI void p_file_load(const char *path, void *buf_ptr, unsigned long buf_size); // Load file to buffer.
+PODEF void p_file_write(const char *path, void *buf_ptr, unsigned long buf_size); // Write buffer to file.
+
+typedef struct P_Window_Impl P_Window;
+POAPI bool p_window_open(P_Window *win, int width, int height, const char *title); // Opens a window. Returns false on failure.
+POAPI void p_window_close(P_Window *win); // Close window.
+POAPI bool p_window_is_open(P_Window *win); // Check if window is open.
+POAPI void p_window_size(P_Window *win, int *window_width, int *window_height); // Get window size.
+POAPI void p_window_draw(P_Window *win, u32 *pixels, int width, int height); // Draw directly to the window's buffer. Normally much slower than using the GPU.
+POAPI bool p_window_poll_event(P_Window *win, P_Event *ev); // Returns true while there are events to poll. Write event data to a pointer.
+
+POAPI void p_audio_init(const int sample_rate, const int channels, const char *name, const char *desc);
+POAPI void p_audio_quit();
+POAPI void p_audio_write(const i16 *samples, usize count);
+
+/*
+ * The Vulkan Module is platform specific
+ */
+
+#ifdef P_MODULE_VULKAN
+#include <vulkan/vulkan.h>
+POAPI char** p_vulkan_get_extensions();
+POAPI bool p_vulkan_create_surface(P_Window *window, VkInstance instance, const VkAllocationCallbacks* allocator, VkSurfaceKHR* out_surface);
+#endif
+
+/*
+ * The Remaining Modules are PLATFORM INDEPENDENT!
+ */
+
+#ifdef P_MODULE_STRING
+/* --- Start of p_string.h --- */
+typedef struct {
+ const char *cstr;
+ u32 len;
+} P_StringView;
+
+typedef struct {
+ P_StringView sv;
+} P_StringBuilder;
+
+/* Classic C string functions */
+PODEF char* p_find_char(char *buf, char needle);
+PODEF bool p_strcmp(const char *a, const char *b);
+PODEF int p_strlen(const char *a);
+PODEF int p_strtoi(const char *str);
+PODEF char* p_strtok(const char *str, char c);
+
+/* String views */
+PODEF P_StringView p_strview(const char *cstr);
+PODEF void p_strview_chop_left(P_StringView *sv, u32 n);
+PODEF void p_strview_chop_right(P_StringView *sv, u32 n);
+PODEF P_StringView p_strview_chop_delim(P_StringView *sv, char delim);
+PODEF P_StringView p_strview_chop_type(P_StringView *sv, int(*istype)(int));
+PODEF void p_strview_trim_left(P_StringView *sv);
+PODEF void p_strview_trim_right(P_StringView *sv);
+PODEF void p_strview_trim(P_StringView *sv);
+
+/* Classification */
+PODEF int p_is_space(int c);
+PODEF int p_is_digit(int c);
+PODEF int p_is_alpha(int c);
+PODEF int p_is_alnum(int c);
+PODEF int p_is_upper(int c);
+PODEF int p_is_lower(int c);
+PODEF int p_is_hex(int c);
+
+/* Transformation */
+PODEF int p_to_lower(int c);
+PODEF int p_to_upper(int c);
+/* --- End of p_string.h --- */
+#endif
+
+#ifdef P_MODULE_MATH
+/* --- Start of p_math.h --- */
+typedef struct {int x, y; } Vec2i;
+typedef struct {float x, y; } Vec2f;
+typedef struct {float x, y, z; } Vec3f;
+typedef struct { float m[16];} P_Mat4; // column-major: m[col * 4 + row]
+PODEF int p_ceil(float x);
+PODEF float p_cosf(float x);
+PODEF float p_sinf(float x);
+
+PODEF Vec2f p_vec2f(float, float);
+PODEF Vec2f p_vec2f_add(Vec2f, Vec2f);
+PODEF float p_vec2f_cross(Vec2f, Vec2f);
+PODEF float p_vec2f_dot(Vec2f, Vec2f);
+PODEF Vec2f p_vec2f_mult(Vec2f a, float b);
+PODEF Vec2f p_vec2f_sub(Vec2f, Vec2f);
+PODEF Vec2i p_vec2i(float, float);
+PODEF Vec2i p_vec2i_add(Vec2i, Vec2i);
+PODEF float p_vec2i_cross(Vec2i, Vec2i);
+PODEF float p_vec2i_dot(Vec2i, Vec2i);
+PODEF Vec2i p_vec2i_mult(Vec2i a, float b);
+PODEF Vec2i p_vec2i_sub(Vec2i, Vec2i);
+
+PODEF Vec3f p_vec3f(float, float, float);
+
+PODEF P_Mat4 p_mat4_identity(void);
+PODEF P_Mat4 p_mat4_mul(P_Mat4 a, P_Mat4 b);
+PODEF P_Mat4 p_mat4_translate(Vec3f v);
+PODEF P_Mat4 p_mat4_translate_by(P_Mat4 m, Vec3f v);
+PODEF P_Mat4 p_mat4_rotate_x(float rad);
+PODEF P_Mat4 p_mat4_rotate_x_by(P_Mat4 m, float rad);
+PODEF P_Mat4 p_mat4_rotate_y(float rad);
+PODEF P_Mat4 p_mat4_rotate_y_by(P_Mat4 m, float rad);
+PODEF P_Mat4 p_mat4_rotate_z(float rad);
+PODEF P_Mat4 p_mat4_perspective(float fov_rad, float aspect, float near_z, float far_z);
+/* --- End of p_math.h --- */
+#endif
+
+#ifdef P_MODULE_ALLOC
+/* --- Start of p_allocators.h --- */
+typedef struct Arena {
+ unsigned char *buf;
+ usize buf_len;
+ usize curr_offset;
+ usize prev_offset;
+} Arena;
+
+PODEF void p_arena_create(Arena *a, void *backing_buffer, usize backing_buffer_length);
+PODEF void* p_arena_alloc_align(Arena *a, usize s, usize align);
+PODEF void* p_arena_alloc(Arena *a, usize s);
+PODEF void* p_arena_resize_align(Arena *a, void *old_memory, usize old_size, usize new_size, usize align);
+PODEF void* p_arena_resize(Arena *a, void *old_memory, usize old_size, usize new_size);
+PODEF void p_arena_free_all(Arena *a);
+PODEF void p_arena_destroy(Arena* a);
+
+typedef struct { u8 padding; } Stack_Allocation_Header;
+typedef struct Stack {
+ unsigned char *buf;
+ usize buf_len;
+ usize offset;
+} Stack;
+
+PODEF void p_stack_create(Stack *s, void *backing_buffer, usize backing_buffer_length);
+PODEF usize calc_padding_with_header(uintptr ptr, uintptr alignment, usize header_size);
+PODEF void* p_stack_alloc(Stack *s, usize len, usize alignment);
+PODEF void p_stack_free(Stack *s, void *ptr);
+PODEF void p_stack_free_all(Stack* s);
+PODEF void p_stack_destroy(Stack* s);
+
+typedef struct Pool_Free_Node Pool_Free_Node;
+
+typedef struct Pool {
+ unsigned char *buf;
+ usize chunk_size;
+ usize pool_size;
+ Pool_Free_Node *head;
+} Pool;
+
+struct Pool_Free_Node { struct Pool_Free_Node *next; };
+PODEF void p_pool_create(Pool *p, void *buf, usize buf_len, usize chunk_size, usize chunk_align);
+PODEF void* p_pool_alloc(Pool *p);
+PODEF void p_pool_free(Pool *p, void *ptr);
+PODEF void p_pool_free_all(Pool *p);
+PODEF void p_pool_destroy(Pool *p);
+/* --- End of p_allocators.h --- */
+#endif
+
+#endif /* _PODIUM_H_ */
+
+#ifdef PODIUM_IMPLEMENTATION
+#undef PODIUM_IMPLEMENTATION
+
+#if defined(PODIUM_SDL)
+/* #include "p_platform_sdl.c" */
+#elif defined(PODIUM_WIN32)
+/* --- Start of p_platform_win32.c --- */
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#include <mmsystem.h>
+#include <xinput.h> /* gamepad support */
+
+typedef struct {
+ HWAVEOUT wave_out;
+ WAVEHDR wave_header;
+} P_Win32Ctx;
+
+struct P_Window_Impl {
+ HWND hwnd;
+ HDC hdc;
+ BITMAPINFO bitmap_info;
+ int width;
+ int height;
+ bool closed;
+};
+
+P_Win32Ctx p_ctx = {0};
+
+static inline P_KeyCode
+_win32_translate_vkey(WPARAM vk)
+{
+ switch (vk) {
+ case VK_LEFT: return P_KEY_LEFT;
+ case VK_RIGHT: return P_KEY_RIGHT;
+ case VK_UP: return P_KEY_UP;
+ case VK_DOWN: return P_KEY_DOWN;
+ case VK_SPACE: return P_KEY_SPACE;
+ case VK_ESCAPE: return P_KEY_ESCAPE;
+ case VK_RETURN: return P_KEY_ENTER;
+ case 'A': return P_KEY_A;
+ case 'B': return P_KEY_B;
+ case 'C': return P_KEY_C;
+ case 'D': return P_KEY_D;
+ case 'E': return P_KEY_E;
+ case 'F': return P_KEY_F;
+ case 'G': return P_KEY_G;
+ case 'H': return P_KEY_H;
+ case 'I': return P_KEY_I;
+ case 'J': return P_KEY_J;
+ case 'K': return P_KEY_K;
+ case 'L': return P_KEY_L;
+ case 'M': return P_KEY_M;
+ case 'N': return P_KEY_N;
+ case 'O': return P_KEY_O;
+ case 'P': return P_KEY_P;
+ case 'Q': return P_KEY_Q;
+ case 'R': return P_KEY_R;
+ case 'S': return P_KEY_S;
+ case 'T': return P_KEY_T;
+ case 'U': return P_KEY_U;
+ case 'V': return P_KEY_V;
+ case 'W': return P_KEY_W;
+ case 'X': return P_KEY_X;
+ case 'Y': return P_KEY_Y;
+ case 'Z': return P_KEY_Z;
+ default: return P_KEY_UNKNOWN;
+ }
+}
+
+POAPI u64
+p_get_time(void)
+{
+ LARGE_INTEGER count, freq;
+ QueryPerformanceCounter(&count);
+ QueryPerformanceFrequency(&freq);
+ return (u64)((count.QuadPart * 1000000000ULL) / freq.QuadPart);
+}
+
+POAPI void
+p_sleep_ns(i64 ns)
+{
+ /* windows sleep is millisecond-based........ */
+ Sleep((DWORD)(ns / 1000000));
+}
+
+POAPI void
+p_stdout(void *msg, usize bytes)
+{
+ HANDLE stdout_handle = GetStdHandle(STD_OUTPUT_HANDLE);
+ DWORD bytes_written;
+ WriteFile(stdout_handle, msg, bytes, &bytes_written, NULL);
+}
+
+POAPI bool
+p_file_exists(const char *path)
+{
+ DWORD attr = GetFileAttributesA(path);
+ return (attr != INVALID_FILE_ATTRIBUTES && !(attr & FILE_ATTRIBUTE_DIRECTORY));
+}
+
+POAPI usize
+p_file_size(const char *path)
+{
+ WIN32_FILE_ATTRIBUTE_DATA data;
+ if (GetFileAttributesExA(path, GetFileExInfoStandard, &data)) {
+ return data.nFileSizeLow;
+ }
+ return 0;
+}
+
+PODEF void
+p_file_load(const char *path, void *buf_ptr, unsigned long buf_size)
+{
+ HANDLE file = CreateFileA(path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
+ if (file != INVALID_HANDLE_VALUE) {
+ DWORD bytes_read;
+ ReadFile(file, buf_ptr, buf_size, &bytes_read, NULL);
+ CloseHandle(file);
+ }
+}
+
+PODEF void
+p_file_write(const char *path, void *buf_ptr, unsigned long buf_size)
+{
+ HANDLE file = CreateFileA(path, GENERIC_WRITE, 0, NULL,
+ CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
+ if (file != INVALID_HANDLE_VALUE) {
+ DWORD bytes_written;
+ WriteFile(file, buf_ptr, buf_size, &bytes_written, NULL);
+ CloseHandle(file);
+ }
+}
+
+static LRESULT CALLBACK
+_win32_wnd_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
+ P_Window *win = (P_Window*)GetWindowLongPtrA(hwnd, GWLP_USERDATA);
+ switch (msg) {
+ case WM_CLOSE:
+ /* Handled in poll_event; mark as closed */
+ if (win) win->closed = true;
+ return 0;
+ }
+ return DefWindowProcA(hwnd, msg, wparam, lparam);
+}
+
+POAPI bool
+p_window_open(P_Window *win, int width, int height, const char *title)
+{
+ HINSTANCE instance = GetModuleHandleA(NULL);
+
+ WNDCLASSA wc = {0};
+ wc.lpfnWndProc = _win32_wnd_proc;
+ wc.hInstance = instance;
+ wc.lpszClassName = "P_Window_Class";
+ wc.hCursor = LoadCursor(NULL, IDC_ARROW);
+
+ RegisterClassA(&wc);
+
+ win->hwnd = CreateWindowExA(0, wc.lpszClassName, title,
+ WS_OVERLAPPEDWINDOW | WS_VISIBLE,
+ CW_USEDEFAULT, CW_USEDEFAULT, width, height,
+ NULL, NULL, instance, NULL);
+
+ if (!win->hwnd) return false;
+
+ SetWindowLongPtrA(win->hwnd, GWLP_USERDATA, (LONG_PTR)win);
+ win->hdc = GetDC(win->hwnd);
+ win->width = width;
+ win->height = height;
+ win->closed = false;
+
+ return true;
+}
+
+POAPI void
+p_window_close(P_Window *win)
+{
+ if (!win) return;
+ if (win->hdc) ReleaseDC(win->hwnd, win->hdc);
+ if (win->hwnd) DestroyWindow(win->hwnd);
+ win->hdc = NULL;
+ win->hwnd = NULL;
+}
+
+POAPI bool
+p_window_is_open(P_Window *win)
+{
+ return win && win->hwnd != NULL;
+}
+
+POAPI void
+p_window_size(P_Window *win, int *window_width, int *window_height)
+{
+ if (!win) return;
+ RECT rect;
+ GetClientRect(win->hwnd, &rect);
+ *window_width = rect.right - rect.left;
+ *window_height = rect.bottom - rect.top;
+ win->width = *window_width;
+ win->height = *window_height;
+}
+
+POAPI void
+p_window_draw(P_Window *win, u32 *pixels, int width, int height)
+{
+ BITMAPINFO bmi = {0};
+ bmi.bmiHeader.biSize = sizeof(bmi.bmiHeader);
+ bmi.bmiHeader.biWidth = width;
+ bmi.bmiHeader.biHeight = -height; /* top-down */
+ bmi.bmiHeader.biPlanes = 1;
+ bmi.bmiHeader.biBitCount = 32;
+ bmi.bmiHeader.biCompression = BI_RGB;
+
+ StretchDIBits(win->hdc,
+ 0, 0, win->width, win->height,
+ 0, 0, width, height,
+ pixels, &bmi, DIB_RGB_COLORS, SRCCOPY);
+}
+
+POAPI bool
+p_window_poll_event(P_Window *win, P_Event *ev)
+{
+ if (win->closed) {
+ win->closed = false;
+ ev->type = P_EVENT_WINDOW_CLOSE;
+ return true;
+ }
+
+ MSG msg;
+ while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) {
+ switch (msg.message) {
+
+ case WM_QUIT:
+ ev->type = P_EVENT_WINDOW_CLOSE;
+ return true;
+
+ /* Key press */
+ case WM_KEYDOWN:
+ case WM_SYSKEYDOWN:
+ ev->type = P_EVENT_KEY_DOWN;
+ ev->key.key = _win32_translate_vkey(msg.wParam);
+ return true;
+
+ /* Key release */
+ case WM_KEYUP:
+ case WM_SYSKEYUP:
+ ev->type = P_EVENT_KEY_UP;
+ ev->key.key = _win32_translate_vkey(msg.wParam);
+ return true;
+
+ /* Mouse movement */
+ case WM_MOUSEMOVE:
+ ev->type = P_EVENT_POINTER;
+ ev->pointer.state = P_POINTER_MOVED;
+ ev->pointer.button = 0;
+ ev->pointer.x = (u32)(msg.lParam & 0xFFFF);
+ ev->pointer.y = (u32)((msg.lParam >> 16) & 0xFFFF);
+ return true;
+
+ /* Mouse buttons */
+ case WM_LBUTTONDOWN:
+ ev->type = P_EVENT_POINTER;
+ ev->pointer.state = P_POINTER_PRESSED;
+ ev->pointer.button = 1; /* 1 = LMB, matching X11 convention */
+ ev->pointer.x = (u32)(msg.lParam & 0xFFFF);
+ ev->pointer.y = (u32)((msg.lParam >> 16) & 0xFFFF);
+ return true;
+
+ case WM_LBUTTONUP:
+ ev->type = P_EVENT_POINTER;
+ ev->pointer.state = P_POINTER_RELEASED;
+ ev->pointer.button = 1;
+ ev->pointer.x = (u32)(msg.lParam & 0xFFFF);
+ ev->pointer.y = (u32)((msg.lParam >> 16) & 0xFFFF);
+ return true;
+
+ case WM_RBUTTONDOWN:
+ ev->type = P_EVENT_POINTER;
+ ev->pointer.state = P_POINTER_PRESSED;
+ ev->pointer.button = 3; /* 3 = RMB */
+ ev->pointer.x = (u32)(msg.lParam & 0xFFFF);
+ ev->pointer.y = (u32)((msg.lParam >> 16) & 0xFFFF);
+ return true;
+
+ case WM_RBUTTONUP:
+ ev->type = P_EVENT_POINTER;
+ ev->pointer.state = P_POINTER_RELEASED;
+ ev->pointer.button = 3;
+ ev->pointer.x = (u32)(msg.lParam & 0xFFFF);
+ ev->pointer.y = (u32)((msg.lParam >> 16) & 0xFFFF);
+ return true;
+
+ case WM_MBUTTONDOWN:
+ ev->type = P_EVENT_POINTER;
+ ev->pointer.state = P_POINTER_PRESSED;
+ ev->pointer.button = 2; /* 2 = MMB */
+ ev->pointer.x = (u32)(msg.lParam & 0xFFFF);
+ ev->pointer.y = (u32)((msg.lParam >> 16) & 0xFFFF);
+ return true;
+
+ case WM_MBUTTONUP:
+ ev->type = P_EVENT_POINTER;
+ ev->pointer.state = P_POINTER_RELEASED;
+ ev->pointer.button = 2;
+ ev->pointer.x = (u32)(msg.lParam & 0xFFFF);
+ ev->pointer.y = (u32)((msg.lParam >> 16) & 0xFFFF);
+ return true;
+
+ /* Window resize */
+ case WM_SIZE:
+ ev->type = P_EVENT_WINDOW_RESIZE;
+ ev->resize.width = (u32)(msg.lParam & 0xFFFF);
+ ev->resize.height = (u32)((msg.lParam >> 16) & 0xFFFF);
+ win->width = ev->resize.width;
+ win->height = ev->resize.height;
+ return true;
+
+ default:
+ TranslateMessage(&msg);
+ DispatchMessageA(&msg);
+ break;
+ }
+ }
+
+ ev->type = P_EVENT_NONE;
+ return false;
+}
+
+
+POAPI void
+p_audio_init(const int sample_rate, const int channels, const char *name, const char *desc)
+{
+ (void)name; (void)desc; /* WinMM doesn't use a stream name */
+
+ WAVEFORMATEX wfx = {0};
+ wfx.wFormatTag = WAVE_FORMAT_PCM;
+ wfx.nChannels = channels;
+ wfx.nSamplesPerSec = sample_rate;
+ wfx.wBitsPerSample = 16;
+ wfx.nBlockAlign = (wfx.nChannels * wfx.wBitsPerSample) / 8;
+ wfx.nAvgBytesPerSec = wfx.nSamplesPerSec * wfx.nBlockAlign;
+
+ if (waveOutOpen(&p_ctx.wave_out, WAVE_MAPPER, &wfx, 0, 0, CALLBACK_NULL) != MMSYSERR_NOERROR) {
+ exit(1);
+ }
+}
+
+POAPI void
+p_audio_quit()
+{
+ if (p_ctx.wave_out) {
+ waveOutReset(p_ctx.wave_out);
+ waveOutClose(p_ctx.wave_out);
+ p_ctx.wave_out = NULL;
+ }
+}
+
+POAPI void
+p_audio_write(const i16 *samples, usize count)
+{
+ if (!p_ctx.wave_out) return;
+
+ WAVEHDR header = {0};
+ header.lpData = (LPSTR)samples;
+ header.dwBufferLength = (DWORD)(count * sizeof(i16));
+
+ waveOutPrepareHeader(p_ctx.wave_out, &header, sizeof(WAVEHDR));
+ waveOutWrite(p_ctx.wave_out, &header, sizeof(WAVEHDR));
+
+ /* wait for playback to finish (synchronous, mirrors pa_simple_drain) */
+ while (!(header.dwFlags & WHDR_DONE)) Sleep(1);
+
+ waveOutUnprepareHeader(p_ctx.wave_out, &header, sizeof(WAVEHDR));
+}
+
+#ifdef P_MODULE_VULKAN
+
+#ifndef VK_USE_PLATFORM_WIN32_KHR
+#define VK_USE_PLATFORM_WIN32_KHR
+#endif
+#include <vulkan/vulkan_win32.h>
+
+POAPI char**
+p_vulkan_get_extensions()
+{
+ char **darr = NULL;
+ p_darray_push(darr, "VK_KHR_surface");
+ p_darray_push(darr, "VK_KHR_win32_surface");
+ return darr;
+}
+
+POAPI bool
+p_vulkan_create_surface(P_Window *window, VkInstance instance, const VkAllocationCallbacks* allocator, VkSurfaceKHR* out_surface)
+{
+ if (!instance || !window || !window->hwnd || !out_surface) {
+ return false;
+ }
+
+ VkWin32SurfaceCreateInfoKHR create_info = {0};
+ create_info.sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR;
+ create_info.pNext = NULL;
+ create_info.flags = 0;
+ create_info.hwnd = window->hwnd;
+ create_info.hinstance = GetModuleHandleA(NULL);
+
+ VkResult result = vkCreateWin32SurfaceKHR(instance, &create_info, allocator, out_surface);
+ return (result == VK_SUCCESS);
+}
+#endif
+/* --- End of p_platform_win32.c --- */
+#elif defined(PODIUM_LINUX)
+/* --- Start of p_platform_linux.c --- */
+/* linux */
+#include <time.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <dirent.h>
+#include <sys/stat.h>
+#include <errno.h>
+/* x11 */
+#include <X11/Xlib.h>
+#include <X11/keysym.h>
+/* pulse audio */
+#include <pulse/pulseaudio.h>
+#include <pulse/simple.h>
+#include <pulse/error.h>
+/* joystick */
+#include <linux/joystick.h>
+
+typedef struct {
+ pa_simple *audio_stream;
+} P_LinuxCtx;
+
+struct P_Window_Impl {
+ Display *display;
+ XImage *image;
+ Window window;
+ GC gc;
+ int screen;
+ int width;
+ int height;
+};
+
+P_LinuxCtx p_ctx = {0};
+
+static inline P_KeyCode
+_x11_translate_keycode(XEvent xev)
+{
+ static KeySym ks;
+ ks = XLookupKeysym(&xev.xkey, 0);
+ switch (ks) {
+ /* Arrow keys */
+ case XK_Left: return P_KEY_LEFT;
+ case XK_Right: return P_KEY_RIGHT;
+ case XK_Up: return P_KEY_UP;
+ case XK_Down: return P_KEY_DOWN;
+ /* Common keys */
+ case XK_space: return P_KEY_SPACE;
+ case XK_Escape: return P_KEY_ESCAPE;
+ case XK_Return: return P_KEY_ENTER;
+ case XK_A: case XK_a: return P_KEY_A;
+ case XK_B: case XK_b: return P_KEY_B;
+ case XK_C: case XK_c: return P_KEY_C;
+ case XK_D: case XK_d: return P_KEY_D;
+ case XK_E: case XK_e: return P_KEY_E;
+ case XK_F: case XK_f: return P_KEY_F;
+ case XK_G: case XK_g: return P_KEY_G;
+ case XK_H: case XK_h: return P_KEY_H;
+ case XK_I: case XK_i: return P_KEY_I;
+ case XK_J: case XK_j: return P_KEY_J;
+ case XK_K: case XK_k: return P_KEY_K;
+ case XK_L: case XK_l: return P_KEY_L;
+ case XK_M: case XK_m: return P_KEY_M;
+ case XK_N: case XK_n: return P_KEY_N;
+ case XK_O: case XK_o: return P_KEY_O;
+ case XK_P: case XK_p: return P_KEY_P;
+ case XK_Q: case XK_q: return P_KEY_Q;
+ case XK_R: case XK_r: return P_KEY_R;
+ case XK_S: case XK_s: return P_KEY_S;
+ case XK_T: case XK_t: return P_KEY_T;
+ case XK_U: case XK_u: return P_KEY_U;
+ case XK_V: case XK_v: return P_KEY_V;
+ case XK_W: case XK_w: return P_KEY_W;
+ case XK_X: case XK_x: return P_KEY_X;
+ case XK_Y: case XK_y: return P_KEY_Y;
+ case XK_Z: case XK_z: return P_KEY_Z;
+ default: return P_KEY_UNKNOWN;
+ }
+}
+
+POAPI u64
+p_get_time(void)
+{
+ struct timespec ts;
+ clock_gettime(CLOCK_MONOTONIC, &ts);
+ return NANOS_PER_SEC * ts.tv_sec + ts.tv_nsec;
+}
+
+POAPI void
+p_sleep_ns(i64 ns)
+{
+ struct timespec ts;
+ ts.tv_sec = ns / 1000000000L;
+ ts.tv_nsec = ns % 1000000000L;
+ clock_nanosleep(CLOCK_MONOTONIC, 0, &ts, NULL);
+}
+
+POAPI void
+p_stdout(void *msg, usize bytes)
+{
+ write(1, msg, bytes);
+}
+
+POAPI bool
+p_file_exists(const char *path)
+{
+ return (access(path, F_OK) == 0);
+}
+
+POAPI usize
+p_file_size(const char *path)
+{
+ struct stat st;
+ if (stat(path, &st) == 0) {
+ return st.st_size;
+ }
+ return 0;
+}
+
+PODEF void
+p_file_load(const char *path, void *buf_ptr, unsigned long buf_size)
+{
+ int fd = open(path, O_RDONLY);
+ if (fd >= 0) {
+ read(fd, buf_ptr, (size_t)buf_size);
+ close(fd);
+ }
+}
+
+PODEF void
+p_file_write(const char *path, void *buf_ptr, unsigned long buf_size)
+{
+ int fd = open(path, O_WRONLY | O_CREAT | O_APPEND, 0644);
+ if (fd >= 0) {
+ write(fd, buf_ptr, (size_t)buf_size);
+ close(fd);
+ }
+}
+
+POAPI bool
+p_window_open(P_Window *win, int width, int height, const char *title)
+{
+ win->width = width;
+ win->height = height;
+
+ XInitThreads();
+
+ win->display = XOpenDisplay(NULL);
+ if (win->display == NULL) {
+ PERROR("Cannot open display!");
+ return false;
+ }
+
+ int screen = DefaultScreen(win->display);
+ win->window = XCreateSimpleWindow(
+ win->display,
+ RootWindow(win->display, screen),
+ 0, 0, width, height,
+ 1,
+ BlackPixel(win->display, screen),
+ BlackPixel(win->display, screen)
+ );
+
+ win->screen = screen;
+
+ XStoreName(win->display, win->window, title);
+ XSelectInput(win->display, win->window,
+ KeyPressMask | KeyReleaseMask |
+ ButtonPressMask | ButtonReleaseMask |
+ PointerMotionMask | StructureNotifyMask);
+ XMapWindow(win->display, win->window);
+
+ win->gc = DefaultGC(win->display, screen);
+
+ Atom wm_delete = XInternAtom(win->display, "WM_DELETE_WINDOW", False);
+ XSetWMProtocols(win->display, win->window, &wm_delete, 1);
+
+ return true;
+}
+
+POAPI void
+p_window_close(P_Window *win)
+{
+ if (!win) return;
+
+ if (win->image) {
+ // XDestroyImage(win->image);
+ win->image = NULL;
+ }
+
+ if (win->display) {
+ Display *dpy = win->display;
+ Window w = win->window;
+ win->display = NULL;
+ win->window = 0;
+
+ if (w) {
+ XDestroyWindow(dpy, w);
+ }
+ XSync(dpy, False);
+ }
+}
+
+POAPI bool
+p_window_is_open(P_Window *win)
+{
+ return win && win->display != NULL;
+}
+
+POAPI void
+p_window_size(P_Window *win, int *window_width, int *window_height)
+{
+ if (!win) return;
+
+ XWindowAttributes attr;
+ XGetWindowAttributes(win->display, win->window, &attr);
+ *window_width = attr.width;
+ *window_height = attr.height;
+
+ win->width = attr.width;
+ win->height = attr.height;
+}
+
+POAPI void
+p_window_draw(P_Window *win, u32 *pixels, int width, int height)
+{
+ int screen = win->screen;
+
+ win->image = XCreateImage(
+ win->display,
+ DefaultVisual(win->display, screen),
+ DefaultDepth(win->display, screen),
+ ZPixmap,
+ 0,
+ (char*)pixels,
+ width,
+ height,
+ 32,
+ width * 4
+ );
+
+ int window_width, window_height;
+ p_window_size(win, &window_width, &window_height);
+
+ XPutImage(
+ win->display,
+ win->window,
+ win->gc,
+ win->image,
+ 0, 0,
+ 0, 0,
+ win->width,
+ win->height);
+
+ XFlush(win->display);
+}
+
+POAPI bool
+p_window_poll_event(P_Window *win, P_Event *ev)
+{
+ if (XPending(win->display)) {
+ static XEvent xev;
+ XNextEvent(win->display, &xev);
+
+ switch (xev.type) {
+
+ case KeyPress:
+ ev->type = P_EVENT_KEY_DOWN;
+ ev->key.key = _x11_translate_keycode(xev);
+ return true;
+
+ case KeyRelease:
+ ev->type = P_EVENT_KEY_UP;
+ ev->key.key = _x11_translate_keycode(xev);
+ return true;
+
+ case ConfigureNotify:
+ ev->type = P_EVENT_WINDOW_RESIZE;
+ ev->resize.width = xev.xconfigure.width;
+ ev->resize.height = xev.xconfigure.height;
+ return true;
+
+ case ClientMessage:
+ if ((Atom)xev.xclient.data.l[0] ==
+ XInternAtom(win->display, "WM_DELETE_WINDOW", False)) {
+ ev->type = P_EVENT_WINDOW_CLOSE;
+ return true;
+ }
+ break;
+
+ case MotionNotify:
+ ev->type = P_EVENT_POINTER;
+ ev->pointer.state = P_POINTER_MOVED;
+ ev->pointer.button = 0;
+ ev->pointer.x = xev.xmotion.x;
+ ev->pointer.y = xev.xmotion.y;
+ return true;
+
+ case ButtonPress:
+ ev->type = P_EVENT_POINTER;
+ ev->pointer.state = P_POINTER_PRESSED;
+ ev->pointer.button = xev.xbutton.button; /* 1=LMB, 2=MMB, 3=RMB */
+ ev->pointer.x = xev.xbutton.x;
+ ev->pointer.y = xev.xbutton.y;
+ return true;
+
+ case ButtonRelease:
+ ev->type = P_EVENT_POINTER;
+ ev->pointer.state = P_POINTER_RELEASED;
+ ev->pointer.button = xev.xbutton.button;
+ ev->pointer.x = xev.xbutton.x;
+ ev->pointer.y = xev.xbutton.y;
+ return true;
+ }
+ }
+
+ ev->type = P_EVENT_NONE;
+ return false;
+}
+
+POAPI void
+p_audio_init(const int sample_rate, const int channels, const char *name, const char *desc)
+{
+ pa_sample_spec ss = {
+ .format = PA_SAMPLE_S16LE,
+ .rate = sample_rate,
+ .channels = channels,
+ };
+
+ int error;
+ p_ctx.audio_stream = pa_simple_new(
+ NULL,
+ name,
+ PA_STREAM_PLAYBACK,
+ NULL,
+ desc,
+ &ss,
+ NULL,
+ NULL,
+ &error
+ );
+
+ if (!p_ctx.audio_stream) {
+ PERROR("PulseAudio init failed: %s\n", pa_strerror(error));
+ exit(1);
+ }
+}
+
+POAPI void
+p_audio_quit()
+{
+ if (p_ctx.audio_stream) {
+ pa_simple_free(p_ctx.audio_stream);
+ p_ctx.audio_stream = NULL;
+ }
+}
+
+POAPI void
+p_audio_write(const i16 *samples, usize count)
+{
+ if (!p_ctx.audio_stream) return;
+
+ int error;
+ if (pa_simple_write(p_ctx.audio_stream, samples, count * sizeof(i16), &error) < 0) {
+ PERROR("PulseAudio write failed: %s\n", pa_strerror(error));
+ }
+
+ pa_simple_drain(p_ctx.audio_stream, &error);
+}
+
+#ifdef P_MODULE_VULKAN
+
+#ifndef VK_USE_PLATFORM_XLIB_KHR
+#define VK_USE_PLATFORM_XLIB_KHR
+#endif
+#include <vulkan/vulkan_xlib.h>
+
+POAPI char**
+p_vulkan_get_extensions()
+{
+ char **darr = NULL;
+ p_darray_push(darr, "VK_KHR_surface");
+ p_darray_push(darr, "VK_KHR_xcb_surface");
+ p_darray_push(darr, "VK_KHR_xlib_surface");
+ return darr;
+}
+
+POAPI bool
+p_vulkan_create_surface(P_Window *window, VkInstance instance, const VkAllocationCallbacks* allocator, VkSurfaceKHR* out_surface)
+{
+ if (!instance || !window || !window->display || !window->window || !out_surface) {
+ return false;
+ }
+
+ VkXlibSurfaceCreateInfoKHR create_info = {0};
+ create_info.sType = VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR;
+ create_info.pNext = NULL;
+ create_info.flags = 0;
+ create_info.dpy = window->display;
+ create_info.window = window->window;
+
+ VkResult result = vkCreateXlibSurfaceKHR(instance, &create_info, allocator, out_surface);
+
+ return (result == VK_SUCCESS);
+}
+#endif
+/* --- End of p_platform_linux.c --- */
+#endif /* linux */
+
+
+POAPI void* p_file_alloc(const char *path, unsigned long *buf_size) {
+ if (p_file_exists(path) == false) {
+ return NULL;
+ }
+
+ usize file_size = p_file_size(path);
+ *buf_size = file_size;
+
+ void *ptr = malloc(file_size);
+ if (ptr) {
+ p_file_load(path, ptr, file_size); // Load file to buffer.
+ }
+ return ptr;
+}
+
+
+/*
+ * Import Module Code
+ */
+
+#ifdef P_MODULE_STRING
+/* --- Start of p_string.c --- */
+PODEF char*
+p_find_char(char *buf, char needle)
+{
+ while (buf && *buf != needle) buf++;
+ return buf;
+}
+
+PODEF bool
+p_strcmp(const char *a, const char *b)
+{
+ if (p_strlen(a) != p_strlen(b))
+ return false;
+
+ while (a && b && *a != '\0') {
+ if (*(a++) != *(b++)) return false;
+ }
+
+ return true;
+}
+
+PODEF int
+p_strlen(const char *a)
+{
+ int i = 0;
+ while (*a++ != '\0') i++;
+ return i;
+}
+
+PODEF int
+p_strtoi(const char *str)
+{
+ int res = 0;
+
+ while (*str) {
+ if (*str >= '0' && *str <= '9') {
+ res = res * 10 + (*str - '0');
+ } else {
+ return res;
+ }
+ str++;
+ }
+
+ return res;
+}
+
+PODEF char*
+p_strtok(const char *str, char c)
+{
+ while (*str != c && *str++ != '\0');
+ return (*str == c) ? (char*) ++str : 0;
+}
+
+PODEF P_StringView
+p_strview(const char *cstr)
+{
+ P_StringView sv = {0};
+ sv.cstr = cstr;
+ sv.len = p_strlen(cstr);
+ return sv;
+}
+
+PODEF void
+p_strview_chop_left(P_StringView *sv, u32 n)
+{
+ if (n > sv->len) n = sv->len;
+ sv->cstr += n;
+ sv->len -= n;
+}
+
+PODEF void
+p_strview_chop_right(P_StringView *sv, u32 n)
+{
+ if (n > sv->len) n = sv->len;
+ sv->len -= n;
+}
+
+PODEF P_StringView
+p_strview_chop_delim(P_StringView *sv, char delim)
+{
+ u32 i = 0;
+ while (i < sv->len && sv->cstr[i] != delim) {
+ i++;
+ }
+
+ P_StringView tok;
+ if (i < sv->len) {
+ tok.cstr = sv->cstr;
+ tok.len = i;
+ p_strview_chop_left(sv, i + 1);
+ return tok;
+ }
+
+ tok = *sv;
+ p_strview_chop_left(sv, sv->len);
+ return tok;
+}
+
+PODEF P_StringView
+p_strview_chop_type(P_StringView *sv, int(*istype)(int))
+{
+ u32 i = 0;
+ while (i < sv->len && istype(sv->cstr[i])) {
+ i++;
+ }
+
+ P_StringView tok;
+ if (i < sv->len) {
+ tok.cstr = sv->cstr;
+ tok.len = i;
+ p_strview_chop_left(sv, i + 1);
+ return tok;
+ }
+
+ tok = *sv;
+ p_strview_chop_left(sv, sv->len);
+ return tok;
+}
+
+
+PODEF void
+p_strview_trim_left(P_StringView *sv)
+{
+ while (sv->len > 0 && p_is_space(sv->cstr[0])) {
+ p_strview_chop_left(sv, 1);
+ }
+}
+
+PODEF void
+p_strview_trim_right(P_StringView *sv)
+{
+ while (sv->len > 0 && p_is_space(sv->cstr[sv->len-1])) {
+ p_strview_chop_right(sv, 1);
+ }
+}
+
+PODEF void
+p_strview_trim(P_StringView *sv)
+{
+ p_strview_trim_left(sv);
+ p_strview_trim_right(sv);
+}
+
+PODEF int
+p_is_space(int c)
+{
+ /* Checks for: space, form feed (\f), line feed (\n),
+ * carriage return (\r), horizontal tab (\t), vertical tab (\v) */
+ return (c == ' ' || (c >= '\t' && c <= '\r'));
+}
+
+PODEF int
+p_is_digit(int c)
+{
+ return (c >= '0' && c <= '9');
+}
+
+PODEF int
+p_is_alpha(int c)
+{
+ return ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'));
+}
+
+PODEF int
+p_is_alnum(int c)
+{
+ return (p_is_alpha(c) || p_is_digit(c));
+}
+
+PODEF int
+p_is_hex(int c)
+{
+ return (p_is_digit(c) ||
+ (c >= 'a' && c <= 'f') ||
+ (c >= 'A' && c <= 'F'));
+}
+
+PODEF int
+p_is_upper(int c)
+{
+ return (c >= 'A' && c <= 'Z');
+}
+
+PODEF int
+p_is_lower(int c)
+{
+ return (c >= 'a' && c <= 'z');
+}
+
+PODEF int
+p_to_lower(int c)
+{
+ if (p_is_upper(c)) return (c + ('a' - 'A'));
+ return c;
+}
+
+PODEF int
+p_to_upper(int c)
+{
+ if (p_is_lower(c)) return (c - ('a' - 'A'));
+ return c;
+}
+/* --- End of p_string.c --- */
+#endif
+
+#ifdef P_MODULE_MATH
+/* --- Start of p_math.c --- */
+PODEF
+int p_ceil(float x)
+{
+ int base = (int) x;
+ return (x > base) ? base + 1 : base;
+}
+
+PODEF float
+p_cosf(float x)
+{
+ x += 1.57079632679f;
+
+ while (x > P_PI) x -= P_PI2;
+ while (x < -P_PI) x += P_PI2;
+
+ const float B = 4.0f / P_PI;
+ const float C = -4.0f / P_PI_POW2;
+
+ float y = B * x + C * x * (x < 0 ? -x : x);
+
+ const float P = 0.225f;
+ y = P * (y * (y < 0 ? -y : y) - y) + y;
+
+ return y;
+}
+
+PODEF float
+p_sinf(float x)
+{
+ while (x > P_PI) x -= P_PI2;
+ while (x < -P_PI) x += P_PI2;
+
+ const float B = 4.0f / P_PI;
+ const float C = -4.0f / (P_PI_POW2);
+
+ float y = B * x + C * x * (x < 0 ? -x : x);
+
+ const float P = 0.225f;
+ y = P * (y * (y < 0 ? -y : y) - y) + y;
+
+ return y;
+}
+
+PODEF Vec2f
+p_vec2f(float x, float y)
+{
+ return (Vec2f) { .x = x, .y = y };
+}
+
+PODEF Vec2f
+p_vec2f_add(Vec2f a, Vec2f b)
+{
+ return (Vec2f) {
+ .x = a.x + b.x,
+ .y = a.y + b.y,
+ };
+}
+
+PODEF float
+p_vec2f_cross(Vec2f a, Vec2f b)
+{
+ // axby − aybx
+ return a.x * b.y - a.y * b.x;
+}
+
+PODEF float
+p_vec2f_dot(Vec2f a, Vec2f b)
+{
+ // a · b = ax × bx + ay × by
+ return a.x * b.x + a.y * b.y;
+}
+
+PODEF Vec2f
+p_vec2f_mult(Vec2f a, float b)
+{
+ return (Vec2f) {
+ .x = a.x * b,
+ .y = a.y * b,
+ };
+}
+
+PODEF Vec2f
+p_vec2f_sub(Vec2f a, Vec2f b)
+{
+ return (Vec2f) {
+ .x = a.x - b.x,
+ .y = a.y - b.y,
+ };
+}
+
+PODEF Vec2i
+p_vec2i(float x, float y)
+{
+ return (Vec2i) { .x = x, .y = y };
+}
+
+PODEF Vec2i
+p_vec2i_add(Vec2i a, Vec2i b)
+{
+ return (Vec2i) {
+ .x = a.x + b.x,
+ .y = a.y + b.y,
+ };
+}
+
+PODEF float
+p_vec2i_cross(Vec2i a, Vec2i b)
+{
+ // axby − aybx
+ return a.x * b.y - a.y * b.x;
+}
+
+PODEF float
+p_vec2i_dot(Vec2i a, Vec2i b)
+{
+ // a · b = ax × bx + ay × by
+ return a.x * b.x + a.y * b.y;
+}
+
+PODEF Vec2i
+p_vec2i_mult(Vec2i a, float b)
+{
+ return (Vec2i) {
+ .x = a.x * b,
+ .y = a.y * b,
+ };
+}
+
+PODEF Vec2i
+p_vec2i_sub(Vec2i a, Vec2i b)
+{
+ return (Vec2i) {
+ .x = a.x - b.x,
+ .y = a.y - b.y,
+ };
+}
+
+PODEF Vec3f
+p_vec3f(float x, float y, float z)
+{
+ return (Vec3f) { .x = x, .y = y, .z = z };
+}
+
+PODEF P_Mat4
+p_mat4_identity(void)
+{
+ P_Mat4 res = {0};
+ res.m[0] = 1.0f;
+ res.m[5] = 1.0f;
+ res.m[10] = 1.0f;
+ res.m[15] = 1.0f;
+ return res;
+}
+
+PODEF P_Mat4
+p_mat4_mul(P_Mat4 a, P_Mat4 b)
+{
+ P_Mat4 res = {0};
+ for (int col = 0; col < 4; ++col) {
+ for (int row = 0; row < 4; ++row) {
+ float sum = 0.0f;
+ for (int k = 0; k < 4; ++k) {
+ sum += a.m[k * 4 + row] * b.m[col * 4 + k];
+ }
+ res.m[col * 4 + row] = sum;
+ }
+ }
+ return res;
+}
+
+PODEF P_Mat4
+p_mat4_translate(Vec3f v)
+{
+ P_Mat4 res = p_mat4_identity();
+ res.m[12] = v.x;
+ res.m[13] = v.y;
+ res.m[14] = v.z;
+ return res;
+}
+
+PODEF P_Mat4
+p_mat4_translate_by(P_Mat4 m, Vec3f v)
+{
+ P_Mat4 res = m;
+ res.m[12] = m.m[0] * v.x + m.m[4] * v.y + m.m[8] * v.z + m.m[12];
+ res.m[13] = m.m[1] * v.x + m.m[5] * v.y + m.m[9] * v.z + m.m[13];
+ res.m[14] = m.m[2] * v.x + m.m[6] * v.y + m.m[10] * v.z + m.m[14];
+ res.m[15] = m.m[3] * v.x + m.m[7] * v.y + m.m[11] * v.z + m.m[15];
+ return res;
+}
+
+PODEF P_Mat4
+p_mat4_rotate_x(float rad)
+{
+ P_Mat4 res = p_mat4_identity();
+ float c = p_cosf(rad);
+ float s = p_sinf(rad);
+ res.m[5] = c;
+ res.m[6] = s;
+ res.m[9] = -s;
+ res.m[10] = c;
+ return res;
+}
+
+PODEF P_Mat4
+p_mat4_rotate_x_by(P_Mat4 m, float rad)
+{
+ return p_mat4_mul(m, p_mat4_rotate_x(rad));
+}
+
+PODEF P_Mat4
+p_mat4_rotate_y(float rad)
+{
+ P_Mat4 res = p_mat4_identity();
+ float c = p_cosf(rad);
+ float s = p_sinf(rad);
+ res.m[0] = c;
+ res.m[2] = -s;
+ res.m[8] = s;
+ res.m[10] = c;
+ return res;
+}
+
+PODEF P_Mat4
+p_mat4_rotate_y_by(P_Mat4 m, float rad)
+{
+ return p_mat4_mul(m, p_mat4_rotate_y(rad));
+}
+
+PODEF P_Mat4
+p_mat4_rotate_z(float rad)
+{
+ P_Mat4 res = p_mat4_identity();
+ float c = p_cosf(rad);
+ float s = p_sinf(rad);
+ res.m[0] = c;
+ res.m[1] = s;
+ res.m[4] = -s;
+ res.m[5] = c;
+ return res;
+}
+
+PODEF P_Mat4
+p_mat4_perspective(float fov_rad, float aspect, float near_z, float far_z)
+{
+ P_Mat4 res = {0};
+ float tan_half_fov = p_sinf(fov_rad * 0.5f) / p_cosf(fov_rad * 0.5f);
+
+ res.m[0] = 1.0f / (aspect * tan_half_fov);
+ res.m[5] = 1.0f / tan_half_fov;
+ res.m[10] = far_z / (near_z - far_z);
+ res.m[11] = -1.0f;
+ res.m[14] = (near_z * far_z) / (near_z - far_z);
+ return res;
+}
+/* --- End of p_math.c --- */
+#endif
+
+#ifdef P_MODULE_ALLOC
+/* --- Start of p_allocators.c --- */
+PODEF bool
+is_power_of_two(uintptr x) {
+ return (x & (x-1)) == 0;
+}
+
+PODEF uintptr
+align_forward(uintptr ptr, usize align)
+{
+ uintptr p, a, remainder;
+ assert(is_power_of_two(align));
+
+ p = ptr;
+ a = (uintptr)align;
+ remainder = p & (a-1);
+
+ return (remainder != 0) ? p + a - remainder : p;
+}
+
+PODEF void
+p_arena_create(Arena *a, void *backing_buffer, usize backing_buffer_length)
+{
+ a->buf = (unsigned char *)backing_buffer;
+ a->buf_len = backing_buffer_length;
+ a->curr_offset = 0;
+ a->prev_offset = 0;
+}
+
+PODEF void*
+p_arena_alloc_align(Arena *a, usize s, usize align)
+{
+
+ // Align 'curr_offset' forward to the specified alignment
+ uintptr curr_ptr = (uintptr)a->buf + (uintptr)a->curr_offset;
+ uintptr offset = align_forward(curr_ptr, align);
+ offset -= (uintptr)a->buf; // Change to relative offset
+
+ // Check to see if the backing memory has space left
+ if (offset+s <= a->buf_len) {
+ void *ptr = &a->buf[offset];
+ a->prev_offset = offset;
+ a->curr_offset = offset+s;
+
+ memset(ptr, 0, s);
+ return ptr;
+ }
+
+ return NULL;
+}
+
+PODEF void*
+p_arena_alloc(Arena *a, usize s) {
+ return p_arena_alloc_align(a, s, DEFAULT_ALIGNMENT);
+}
+
+PODEF void*
+p_arena_resize_align(Arena *a, void *old_memory, usize old_size, usize new_size, usize align)
+{
+ assert(is_power_of_two(align));
+ unsigned char *old_mem = (unsigned char *)old_memory;
+
+ if (old_mem == NULL || old_size == 0) {
+ return p_arena_alloc_align(a, new_size, align);
+ } else if (a->buf <= old_mem && old_mem < a->buf+a->buf_len) {
+ if (a->buf+a->prev_offset == old_mem) {
+ a->curr_offset = a->prev_offset + new_size;
+ if (new_size > old_size) {
+ // Zero the new memory by default
+ memset(&a->buf[a->curr_offset], 0, new_size-old_size);
+ }
+ return old_memory;
+ } else {
+ void *new_memory = p_arena_alloc_align(a, new_size, align);
+ size_t copy_size = old_size < new_size ? old_size : new_size;
+ memmove(new_memory, old_memory, copy_size);
+ return new_memory;
+ }
+
+ } else {
+ assert(0 && "Memory is out of bounds of the buffer in this arena");
+ return NULL;
+ }
+}
+
+PODEF void*
+p_arena_resize(Arena *a, void *old_memory, usize old_size, usize new_size)
+{
+ return p_arena_resize_align(a, old_memory, old_size, new_size, DEFAULT_ALIGNMENT);
+}
+
+PODEF void
+p_arena_free_all(Arena *a)
+{
+ a->curr_offset = 0;
+ a->prev_offset = 0;
+}
+
+PODEF void
+p_arena_destroy(Arena* a)
+{
+ a->buf_len = 0;
+ a->curr_offset = 0;
+ a->prev_offset = 0;
+}
+
+PODEF void
+p_stack_create(Stack *s, void *backing_buffer, usize backing_buffer_length)
+{
+ s->buf = (unsigned char*) backing_buffer;
+ s->buf_len = backing_buffer_length;
+ s->offset = 0;
+}
+
+PODEF usize
+calc_padding_with_header(uintptr ptr, uintptr alignment, usize header_size)
+{
+ uintptr p, a, modulo, padding, needed_space;
+
+ assert(is_power_of_two(alignment));
+
+ p = ptr;
+ a = alignment;
+ modulo = p & (a-1); // (p % a) as it assumes alignment is a power of two
+
+ padding = 0;
+ needed_space = 0;
+
+ if (modulo != 0) { // Same logic as 'align_forward'
+ padding = a - modulo;
+ }
+
+ needed_space = (uintptr)header_size;
+
+ if (padding < needed_space) {
+ needed_space -= padding;
+
+ if ((needed_space & (a-1)) != 0) {
+ padding += a * (1+(needed_space/a));
+ } else {
+ padding += a * (needed_space/a);
+ }
+ }
+
+ return (usize)padding;
+}
+
+PODEF void*
+p_stack_alloc(Stack *s, usize len, usize alignment)
+{
+ uintptr curr_addr, next_addr;
+ usize padding;
+ Stack_Allocation_Header *header;
+
+ assert(is_power_of_two(alignment));
+
+ if (alignment > 128) {
+ // As the padding is 8 bits (1 byte), the largest alignment that can
+ // be used is 128 bytes
+ alignment = 128;
+ }
+
+ curr_addr = (uintptr)s->buf + (uintptr)s->offset;
+ padding = calc_padding_with_header(curr_addr, (uintptr)alignment, sizeof(Stack_Allocation_Header));
+ if (s->offset + padding + len > s->buf_len) {
+ // Stack allocator is out of memory
+ return NULL;
+ }
+ s->offset += padding;
+
+ next_addr = curr_addr + (uintptr)padding;
+ header = (Stack_Allocation_Header *)(next_addr - sizeof(Stack_Allocation_Header));
+ header->padding = (u8)padding;
+
+ s->offset += len;
+
+ return memset((void *)next_addr, 0, len);
+}
+
+PODEF void
+p_stack_free(Stack *s, void *ptr)
+{
+ if (ptr != NULL) {
+ uintptr start, end, curr_addr;
+ Stack_Allocation_Header *header;
+ usize prev_offset;
+
+ start = (uintptr)s->buf;
+ end = start + (uintptr)s->buf_len;
+ curr_addr = (uintptr)ptr;
+
+ if (!(start <= curr_addr && curr_addr < end)) {
+ assert(0 && "Out of bounds memory address passed to stack allocator (free)");
+ return;
+ }
+
+ if (curr_addr >= start+(uintptr)s->offset) {
+ // Allow double frees
+ return;
+ }
+
+ header = (Stack_Allocation_Header *)(curr_addr - sizeof(Stack_Allocation_Header));
+ prev_offset = (usize)(curr_addr - (uintptr)header->padding - start);
+
+ s->offset = prev_offset;
+ }
+}
+
+PODEF void
+p_stack_free_all(Stack* s)
+{
+ s->offset = 0;
+}
+
+PODEF void
+p_stack_destroy(Stack* s)
+{
+ s->buf = 0;
+ s->buf_len = 0;
+ s->offset = 0;
+}
+
+PODEF void
+p_pool_create(Pool *p, void *buf, usize buf_len, usize chunk_size, usize chunk_align)
+{
+ /* align start */
+ uintptr start = (uintptr) buf;
+ uintptr aligned = align_forward(start, chunk_align);
+ buf_len -= (aligned - start);
+
+ /* align chunk usize */
+ chunk_size = (usize) align_forward(chunk_size, chunk_align);
+
+ assert(chunk_size >= sizeof(Pool_Free_Node) && "Chunk usize is too small");
+ assert(buf_len >= chunk_size && "Backing buffer length is smaller than the chunk size");
+
+ p->buf = (unsigned char *) buf;
+ p->pool_size = buf_len;
+ p->chunk_size = chunk_size;
+ p->head = NULL;
+
+ p_pool_free_all(p);
+}
+
+PODEF void*
+p_pool_alloc(Pool *p)
+{
+ Pool_Free_Node *node = p->head;
+
+ assert(node != NULL && "Pool allocator has no free memory");
+
+ p->head = p->head->next;
+
+ return memset(node, 0 , p->chunk_size);
+}
+
+PODEF void
+p_pool_free(Pool *p, void *ptr)
+{
+ Pool_Free_Node *node;
+
+ void *start = p->buf;
+ void *end = &p->buf[p->pool_size];
+
+ if (ptr == NULL) {
+ return;
+ }
+
+ if (!(start <= ptr && ptr < end)) {
+ assert(0 && "Memory is out of bounds of the buffer in this pool");
+ return;
+ }
+
+ node = (Pool_Free_Node *)ptr;
+ node->next = p->head;
+ p->head = node;
+}
+
+PODEF void
+p_pool_free_all(Pool *p)
+{
+ usize chunk_count = p->pool_size / p->chunk_size;
+ usize i;
+
+ for (i = 0; i < chunk_count; i++) {
+ void *ptr = &p->buf[i * p->chunk_size];
+ Pool_Free_Node *node = (Pool_Free_Node *)ptr;
+
+ // Push free node onto thte free list
+ node->next = p->head;
+ p->head = node;
+ }
+}
+
+PODEF void
+p_pool_destroy(Pool *p)
+{
+ p->buf = NULL;
+ p->pool_size = 0;
+ p->chunk_size = 0;
+ p->head = NULL;
+}
+
+/* --- End of p_allocators.c --- */
+#endif
+
+#define P_MAX_PRINTF_SIZE 1024
+PODEF void
+p_log_printf(P_Log_Level level, const char* src, ...)
+{
+ static char out_message[P_MAX_PRINTF_SIZE];
+ static u32 offset = P_PREFIX_LEN + 1;
+
+ memcpy(out_message, p_prefix[level], P_PREFIX_LEN); /* prefixes have a fixed len */
+ out_message[P_PREFIX_LEN] = ' '; /* write space */
+
+ __builtin_va_list arg_ptr;
+ va_start(arg_ptr, src);
+ int len = vsnprintf(out_message+offset, P_MAX_PRINTF_SIZE-offset, src, arg_ptr); // append message
+ va_end(arg_ptr);
+
+ if (len < 0) len = 0;
+ usize total_len = offset + len;
+ if (total_len > P_MAX_PRINTF_SIZE) {
+ total_len = P_MAX_PRINTF_SIZE;
+ }
+
+ p_stdout(out_message, total_len);
+ p_stdout("\n", 1);
+}
+
+#endif // PODIUM_IMPLEMENTATION
diff --git a/Rend/rend.c b/Rend/rend.c
new file mode 100644
index 0000000..9d31949
--- /dev/null
+++ b/Rend/rend.c
@@ -0,0 +1,617 @@
+#include <assert.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/param.h>
+#include <unistd.h>
+
+#include "rend.h"
+#include "rend_internal.h"
+#include "rend_vk.c"
+#include "rend_vk_internal.h"
+
+/* clean up functions */
+
+static void rend__renderer_destroy_recursive(RendRenderer renderer);
+static void rend__pipeline_destroy_recursive(RendPipeline pipeline);
+static bool rend__renderer_init_recursive(RendRenderer renderer, RendBackendType backend, bool auto_pick);
+
+static RendRenderer rend_renderers_head = NULL;
+
+// TODO: automatically clear buffers and textures
+// static RendBuffer rend_buffer_head = NULL;
+// static RendTexture rend_texture_head = NULL;
+
+bool rend_backend_vk_initialized = false;
+
+RendVTable rend_vtables[] = {
+ [REND_BACKEND_VULKAN_14] = {
+ .renderer_create = rend_vk_renderer_create,
+ .renderer_destroy = rend_vk_renderer_destroy,
+ .renderer_frame_begin = rend_vk_renderer_frame_begin,
+ .renderer_frame_end = rend_vk_renderer_frame_end,
+
+ .buffer_create_lifetime = rend_vk_buffer_create_lifetime,
+ .buffer_destroy = rend_vk_buffer_destroy,
+ .buffer_copy = rend_vk_buffer_copy,
+
+ .texture_create = rend_vk_texture_create,
+ .texture_destroy = rend_vk_texture_destroy,
+ .texture_copy_buffer = rend_vk_texture_copy_buffer,
+ .texture_blit = rend_vk_texture_blit,
+
+ .pipeline_create = rend_vk_pipeline_create,
+ .pipeline_bind = rend_vk_pipeline_bind,
+ .pipeline_push_constants = rend_vk_pipeline_push_constants,
+
+ .pipeline_bind_vertex_buffer = rend_vk_pipeline_bind_vertex_buffer,
+ .pipeline_bind_index_buffer = rend_vk_pipeline_bind_index_buffer,
+
+ .pipeline_dispatch = rend_vk_pipeline_dispatch,
+ .pipeline_draw = rend_vk_pipeline_draw,
+ .pipeline_draw_indexed = rend_vk_pipeline_draw_indexed,
+ .pipeline_set_blend = rend_vk_pipeline_set_blend,
+
+ .renderer_render_pass_begin = rend_vk_renderer_render_pass_begin,
+ .renderer_render_pass_begin_texture = rend_vk_renderer_render_pass_begin_texture,
+ .renderer_render_pass_end = rend_vk_renderer_render_pass_end,
+ .renderer_render_pass_end_texture = rend_vk_renderer_render_pass_end_texture,
+
+ .descriptor_write_buffer = rend_vk_descriptor_write_buffer,
+ .descriptor_write_texture = rend_vk_descriptor_write_texture,
+ },
+};
+
+extern void
+rend_quit()
+{
+ rend__renderer_destroy_recursive(rend_renderers_head);
+
+ if (rend_backend_vk_initialized) {
+ rend_vk_quit();
+ rend_backend_vk_initialized = false;
+ }
+
+}
+
+extern RendRenderer
+rend_renderer_create(P_Window *target, RendBackendType backend, void* device, bool vsync, RendBindingInfo *bind_info)
+{
+
+ RendRenderer rend = rmalloc(sizeof *rend);
+ rend->next = rend_renderers_head;
+ rend->prev = NULL;
+ rend_renderers_head = rend;
+ if(rend->next) {
+ rend->next->prev = rend;
+ }
+
+ rend__renderer_init_recursive(rend, backend, false);
+
+ rend->vsync = vsync;
+ rend->bind_info = *bind_info;
+ rend->window = target;
+ rend->pipeline_head = 0;
+
+ rend->context = rend_vtables[rend->backend].renderer_create();
+ if (rend->context) {
+ return rend;
+ }
+
+ return NULL;
+}
+
+extern void
+rend_renderer_destroy(RendRenderer renderer)
+{
+ RASSERT(renderer && renderer->context, "Invalid renderer.");
+ if (!renderer) return;
+
+ rend__pipeline_destroy_recursive(renderer->pipeline_head);
+
+ if (renderer->backend != 0) {
+ rend_vtables[renderer->backend].renderer_destroy(renderer->context);
+ }
+
+ if (renderer->prev) renderer->prev->next = renderer->next;
+ else rend_renderers_head = renderer->next;
+
+ if (renderer->next) renderer->next->prev = renderer->prev;
+
+ rfree(renderer);
+}
+
+extern bool
+rend_renderer_frame_begin(RendRenderer renderer)
+{
+ RASSERT(renderer && (uintptr_t)renderer != 0xffffffff00000000 && "Invalid renderer. (Possible stack corruption.)");
+ RASSERT(renderer->context, "Uninitialized renderer.");
+ RASSERT(!renderer->in_frame, "Must not be called inside a frame.");
+ RASSERT(!renderer->in_pass, "Must not be called inside a render pass.");
+
+ renderer->in_frame = 1;
+ return rend_vtables[renderer->backend].renderer_frame_begin(renderer->context);
+}
+
+extern void
+rend_renderer_frame_end(RendRenderer renderer, float *delta)
+{
+ RASSERT(renderer && (uintptr_t)renderer != 0xffffffff00000000 && "Invalid renderer. (Possible stack corruption.)");
+ RASSERT(renderer->context, "Uninitialized renderer.");
+ RASSERT(renderer->in_frame, "Must be called inside a frame.");
+ RASSERT(!renderer->in_pass, "Must not be called inside a render pass.");
+
+ renderer->in_frame = 0;
+ rend_vtables[renderer->backend].renderer_frame_end(renderer->context, delta);
+ renderer->frame_count++;
+}
+
+extern void
+rend_renderer_render_pass_begin(RendRenderer renderer, float r, float g ,float b, float a)
+{
+ renderer->in_pass = 1;
+ rend_vtables[renderer->backend].renderer_render_pass_begin(renderer, r, g, b, a);
+}
+
+extern void
+rend_renderer_render_pass_begin_texture(RendRenderer renderer, RendTexture *texture)
+{
+ renderer->in_pass = 1;
+ rend_vtables[renderer->backend].renderer_render_pass_begin_texture(renderer, texture);
+}
+
+extern void
+rend_renderer_render_pass_end_texture(RendRenderer renderer, RendTexture *texture)
+{
+ renderer->in_pass = 0;
+ rend_vtables[renderer->backend].renderer_render_pass_end_texture(renderer, texture);
+}
+
+
+extern void
+rend_renderer_render_pass_end(RendRenderer renderer)
+{
+ renderer->in_pass = 0;
+ rend_vtables[renderer->backend].renderer_render_pass_end(renderer);
+}
+
+
+extern void
+rend_descriptor_write_ubo(RendRenderer renderer, RendBuffer ubo, uint32_t binding, uint32_t slot)
+{
+ rend_vtables[renderer->backend].descriptor_write_buffer(renderer, ubo, binding, slot, 0, ubo.size, true);
+}
+
+extern void
+rend_descriptor_write_ssbo(RendRenderer renderer, RendBuffer ssbo, uint32_t binding, uint32_t slot)
+{
+ rend_vtables[renderer->backend].descriptor_write_buffer(renderer, ssbo, binding, slot, 0, ssbo.size, false);
+}
+
+extern RendBuffer
+rend_buffer_create(RendRenderer renderer, size_t size, RendBufferType type, bool gpu) {
+ RendBuffer buffer = rend_vtables[renderer->backend].buffer_create_lifetime(renderer, size, type, gpu, REND_LIFETIME_PERMANENT);
+ buffer.backend = renderer->backend;
+ return buffer;
+}
+
+extern void
+rend_buffer_destroy(RendBuffer *buffer) {
+ rend_vtables[buffer->backend].buffer_destroy(buffer);
+}
+
+extern void
+rend_buffer_write(RendRenderer renderer, RendBuffer *buffer, const void *data, size_t size, size_t offset)
+{
+ if (buffer->mapped_memory) {
+ uint8_t *ptr = buffer->mapped_memory;
+ memcpy(ptr + offset, data, size);
+ } else {
+ /* if the memory is bound to the device we must create and deallocate a transfer buffer */
+ RendBuffer transfer_buffer = rend_vtables[buffer->backend].buffer_create_lifetime(renderer, size, REND_BUFFER_TRANSFER, false, REND_LIFETIME_FRAME);
+ memcpy(transfer_buffer.mapped_memory, data, size);
+ rend_vtables[buffer->backend].buffer_copy(renderer, buffer, offset, &transfer_buffer, 0, size);
+ rend_vtables[buffer->backend].buffer_destroy(&transfer_buffer);
+ }
+}
+
+extern void
+rend_buffer_copy(RendRenderer renderer, RendBuffer *dest, size_t dest_offset, RendBuffer *src, size_t src_offset, size_t bytes)
+{
+ rend_vtables[renderer->backend].buffer_copy(renderer, dest, dest_offset, src, src_offset, bytes);
+}
+
+extern uint64_t
+rend_buffer_address(RendBuffer *buffer)
+{
+ RASSERT(buffer != NULL);
+ return buffer->gpu_address;
+}
+
+extern RendTexture
+rend_texture_create(RendRenderer renderer, uint32_t width, uint32_t height, uint32_t depth, uint32_t mip_levels, uint32_t layers, RendFormat format)
+{
+ RendTexture tex = rend_vtables[renderer->backend].texture_create(renderer, width, height, depth, mip_levels, layers, format);
+ tex.backend = renderer->backend;
+ return tex;
+}
+
+extern RendTexture
+rend_texture_create_from_data(RendRenderer renderer, const void *data, uint32_t width, uint32_t height, RendFormat format)
+{
+ RendTexture tex = rend_vtables[renderer->backend].texture_create(renderer, width, height, 1, 1, 1, format);
+ tex.backend = renderer->backend;
+
+ uint32_t size = width * height * rend_format_size[format];
+
+ RendBuffer staging_buffer = rend_vtables[renderer->backend].buffer_create_lifetime(renderer, size, REND_BUFFER_TRANSFER, false, REND_LIFETIME_FRAME);
+ memcpy(staging_buffer.mapped_memory, data, size);
+ rend_vtables[renderer->backend].texture_copy_buffer(renderer, &tex, &staging_buffer);
+ rend_vtables[renderer->backend].buffer_destroy(&staging_buffer);
+ return tex;
+}
+
+extern void
+rend_texture_copy_data(RendRenderer renderer, RendTexture *texture, const void *data, size_t size)
+{
+ RendBuffer staging_buffer = rend_vtables[renderer->backend].buffer_create_lifetime(renderer, size, REND_BUFFER_TRANSFER, false, REND_LIFETIME_FRAME);
+ memcpy(staging_buffer.mapped_memory, data, size);
+ rend_vtables[renderer->backend].texture_copy_buffer(renderer, texture, &staging_buffer);
+ rend_vtables[renderer->backend].buffer_destroy(&staging_buffer);
+}
+
+
+extern void
+rend_texture_copy_buffer(RendRenderer renderer, RendTexture *texture, RendBuffer *buffer)
+{
+ rend_vtables[renderer->backend].texture_copy_buffer(renderer, texture, buffer);
+}
+
+extern void
+rend_texture_blit(RendRenderer renderer, RendTexture *src, RendTexture *dst, uint32_t src_x, uint32_t src_y, uint32_t src_w, uint32_t src_h, uint32_t dst_x, uint32_t dst_y, uint32_t dst_w, uint32_t dst_h)
+{
+ rend_vtables[renderer->backend].texture_blit(renderer, src, dst, src_x, src_y, src_w, src_h, dst_x, dst_y, dst_w, dst_h);
+}
+
+extern uint64_t
+rend_texture_id(RendTexture *texture)
+{
+ return texture->id;
+}
+
+extern void
+rend_texture_destroy(RendRenderer renderer, RendTexture *tex)
+{
+ rend_vtables[renderer->backend].texture_destroy(renderer, tex);
+}
+
+extern void
+rend_pipeline_push_constants(RendPipeline pipeline, void *push_data, size_t size)
+{
+ RASSERT(pipeline != NULL && "Pipeline handle is NULL!");
+ RASSERT(rend_vtables[pipeline->backend].pipeline_push_constants && "Backend function not implemented!");
+ rend_vtables[pipeline->backend].pipeline_push_constants(pipeline, push_data, size);
+}
+
+extern void
+rend_pipeline_bind_vertex_buffer(RendPipeline pipeline, uint32_t binding, RendBuffer buffer, size_t offset)
+{
+ rend_vtables[pipeline->backend].pipeline_bind_vertex_buffer(pipeline, binding, buffer, offset);
+}
+
+extern void
+rend_pipeline_bind_index_buffer(RendPipeline pipeline, RendBuffer buffer, size_t offset, RendIndexType index_type)
+{
+ rend_vtables[pipeline->backend].pipeline_bind_index_buffer(pipeline, buffer, offset, index_type);
+}
+
+extern void
+rend_pipeline_bind_texture(RendPipeline pipeline, RendTexture *texture, uint32_t binding, uint32_t slot)
+{
+ rend_vtables[pipeline->backend].descriptor_write_texture(pipeline->backend_ctx, texture, binding, slot);
+}
+
+extern void
+rend_descriptor_write_texture(RendRenderer renderer, RendTexture *texture, uint32_t binding, uint32_t slot)
+{
+ rend_vtables[renderer->backend].descriptor_write_texture(renderer->context, texture, binding, slot);
+}
+
+
+extern RendPipeline
+rend_pipeline_create_graphics_spirv(RendRenderer renderer, uint8_t *vertex_bytes, size_t vertex_size, uint8_t *frag_bytes, size_t frag_size, const RendVertexBinding *vertex_bindings, uint32_t vertex_binding_count, const RendVertexAttributes *vertex_attributes, uint32_t vertex_attribute_count, const RendPushConstantInfo *push_constants, uint32_t push_constant_count, RendPolygonMode polygon_mode, RendCullMode cull_mode, RendTopology topology, RendFormat color_format, bool depth_test_enable)
+{
+ RendPipeline pipeline = rmalloc(sizeof *pipeline);
+
+ Rend__PipelineConfig config = {
+ .vertex_bindings = vertex_bindings,
+ .vertex_binding_count = vertex_binding_count,
+ .vertex_attributes = vertex_attributes,
+ .vertex_attribute_count = vertex_attribute_count,
+ .push_constants = push_constants,
+ .push_constant_count = push_constant_count,
+ .polygon_mode = polygon_mode,
+ .cull_mode = cull_mode,
+ .topology = topology,
+ .depth_test_enable = depth_test_enable,
+
+ .color_format = color_format,
+ };
+
+ if (rend_vtables[renderer->backend].pipeline_create(renderer, pipeline, config, REND__PIPELINE_GRAPHICS, vertex_bytes, vertex_size, frag_bytes, frag_size, NULL, 0)) {
+ pipeline->backend = renderer->backend;
+
+ pipeline->next = renderer->pipeline_head;
+ pipeline->prev = NULL;
+ renderer->pipeline_head = pipeline;
+ pipeline->type = REND__PIPELINE_GRAPHICS;
+ if(pipeline->next) {
+ pipeline->next->prev = pipeline;
+ }
+
+ return pipeline;
+ }
+ rfree(pipeline);
+ return NULL;
+}
+
+extern RendPipeline
+rend_pipeline_create_graphics_bindless_spirv(RendRenderer renderer, uint8_t *vertex_bytes, size_t vertex_size, uint8_t *frag_bytes, size_t frag_size, const RendPushConstantInfo *push_constants, uint32_t push_constant_count, RendPolygonMode polygon_mode, RendCullMode cull_mode, RendTopology topology, RendFormat color_format, bool depth_test_enable)
+{
+ RendPipeline pipeline = rmalloc(sizeof *pipeline);
+
+ Rend__PipelineConfig config = {
+ .vertex_bindings = NULL,
+ .vertex_binding_count = 0,
+ .vertex_attributes = NULL,
+ .vertex_attribute_count = 0,
+ .push_constants = push_constants,
+ .push_constant_count = push_constant_count,
+ .polygon_mode = polygon_mode,
+ .cull_mode = cull_mode,
+ .topology = topology,
+ .depth_test_enable = depth_test_enable,
+
+ .color_format = color_format,
+ };
+
+ if (rend_vtables[renderer->backend].pipeline_create(renderer, pipeline, config, REND__PIPELINE_GRAPHICS, vertex_bytes, vertex_size, frag_bytes, frag_size, NULL, 0)) {
+ pipeline->backend = renderer->backend;
+
+ pipeline->next = renderer->pipeline_head;
+ pipeline->prev = NULL;
+ renderer->pipeline_head = pipeline;
+ pipeline->type = REND__PIPELINE_GRAPHICS;
+ if(pipeline->next) {
+ pipeline->next->prev = pipeline;
+ }
+
+ return pipeline;
+ }
+ rfree(pipeline);
+ return NULL;
+}
+
+extern RendPipeline
+rend_pipeline_create_compute_spirv(RendRenderer renderer, const uint8_t *compute_bytes, size_t compute_size, const RendPushConstantInfo *push_constants, uint32_t push_constant_count)
+{
+ RendPipeline pipeline = rmalloc(sizeof *pipeline);
+ Rend__PipelineConfig config = {
+ .push_constants = push_constants,
+ .push_constant_count = push_constant_count,
+ };
+
+ if (rend_vtables[renderer->backend].pipeline_create(renderer, pipeline, config, REND__PIPELINE_COMPUTE, compute_bytes, compute_size, NULL, 0, NULL, 0)) {
+ pipeline->backend = renderer->backend;
+ pipeline->type = REND__PIPELINE_COMPUTE;
+
+ pipeline->next = renderer->pipeline_head;
+ pipeline->prev = NULL;
+ renderer->pipeline_head = pipeline;
+ if(pipeline->next) {
+ pipeline->next->prev = pipeline;
+ }
+
+ return pipeline;
+ }
+ rfree(pipeline);
+ return NULL;
+}
+
+extern RendPipeline
+rend_pipeline_create_meshlet_spirv(RendRenderer renderer, uint8_t *meshlet_bytes, size_t meshlet_size, uint8_t *frag_bytes, size_t frag_size, const RendPushConstantInfo *push_constants, uint32_t push_constant_count, RendPolygonMode polygon_mode, RendCullMode cull_mode, bool depth_test_enable)
+{
+ RendPipeline pipeline = rmalloc(sizeof *pipeline);
+ Rend__PipelineConfig config = {
+ .push_constants = push_constants,
+ .push_constant_count = push_constant_count,
+ .polygon_mode = polygon_mode,
+ .cull_mode = cull_mode,
+ .depth_test_enable = depth_test_enable
+ };
+ if (rend_vtables[renderer->backend].pipeline_create(renderer, pipeline, config, REND__PIPELINE_MESH, meshlet_bytes, meshlet_size, frag_bytes, frag_size, NULL, 0)) {
+ pipeline->backend = renderer->backend;
+ pipeline->type = REND__PIPELINE_MESH;
+
+ pipeline->next = renderer->pipeline_head;
+ pipeline->prev = NULL;
+ renderer->pipeline_head = pipeline;
+ if(pipeline->next) {
+ pipeline->next->prev = pipeline;
+ }
+
+ return pipeline;
+ }
+ rfree(pipeline);
+ return NULL;
+}
+
+extern void
+rend_pipeline_bind(RendPipeline pipeline)
+{
+ rend_vtables[pipeline->backend].pipeline_bind(pipeline);
+}
+
+extern void
+rend_pipeline_dispatch(RendPipeline pipeline, uint32_t x, uint32_t y, uint32_t z)
+{
+ rend_vtables[pipeline->backend].pipeline_dispatch(pipeline, x, y, z);
+}
+
+extern void
+rend_pipeline_draw(RendPipeline pipeline, size_t count, uint32_t instance_count)
+{
+ rend_vtables[pipeline->backend].pipeline_draw(pipeline, count, instance_count);
+}
+
+extern void
+rend_pipeline_draw_indexed(RendPipeline pipeline, uint32_t index_count, uint32_t first_index, int32_t vertex_offset, uint32_t instance_count)
+{
+ rend_vtables[pipeline->backend].pipeline_draw_indexed(pipeline, index_count, first_index, vertex_offset, instance_count);
+}
+
+extern void
+rend_pipeline_set_blend(RendPipeline pipeline, bool blend)
+{
+ rend_vtables[pipeline->backend].pipeline_set_blend(pipeline, blend);
+}
+
+extern void
+rend_cmd_render_begin(RendRenderer renderer, float r, float g, float b, float a)
+{
+ renderer->in_pass = 1;
+ rend_vtables[renderer->backend].renderer_render_pass_begin(renderer, r, g, b, a);
+}
+
+extern void
+rend_cmd_render_begin_texture(RendRenderer renderer, RendTexture *texture)
+{
+ renderer->in_pass = 1;
+ rend_vtables[renderer->backend].renderer_render_pass_begin_texture(renderer, texture);
+}
+
+extern void
+rend_cmd_render_end(RendRenderer renderer)
+{
+ renderer->in_pass = 0;
+ rend_vtables[renderer->backend].renderer_render_pass_end(renderer);
+}
+
+extern void
+rend_cmd_render_end_texture(RendRenderer renderer, RendTexture *texture)
+{
+ renderer->in_pass = 0;
+ rend_vtables[renderer->backend].renderer_render_pass_end_texture(renderer, texture);
+}
+
+extern void
+rend_cmd_bind_pipeline(RendPipeline pipeline)
+{
+ rend_vtables[pipeline->backend].pipeline_bind(pipeline);
+}
+
+extern void
+rend_cmd_bind_vertex_buffer(RendPipeline pipeline, uint32_t binding, RendBuffer buffer, size_t offset)
+{
+ rend_vtables[pipeline->backend].pipeline_bind_vertex_buffer(pipeline, binding, buffer, offset);
+}
+
+extern void
+rend_cmd_bind_index_buffer(RendPipeline pipeline, RendBuffer buffer, size_t offset, RendIndexType index_type)
+{
+ rend_vtables[pipeline->backend].pipeline_bind_index_buffer(pipeline, buffer, offset, index_type);
+}
+
+extern void
+rend_cmd_push_constants(RendPipeline pipeline, void *push_data, size_t size)
+{
+ assert(pipeline != NULL && "Pipeline handle is NULL!");
+ assert(rend_vtables[pipeline->backend].pipeline_push_constants && "Backend function not implemented!");
+ rend_vtables[pipeline->backend].pipeline_push_constants(pipeline, push_data, size);
+}
+
+extern void
+rend_cmd_dispatch(RendPipeline pipeline, uint32_t x, uint32_t y, uint32_t z)
+{
+ rend_vtables[pipeline->backend].pipeline_dispatch(pipeline, x, y, z);
+}
+
+extern void
+rend_cmd_draw(RendPipeline pipeline, size_t count, uint32_t instance_count)
+{
+ rend_vtables[pipeline->backend].pipeline_draw(pipeline, count, instance_count);
+}
+
+extern void
+rend_cmd_draw_indexed(RendPipeline pipeline, uint32_t index_count, uint32_t first_index, int32_t vertex_offset, uint32_t instance_count)
+{
+ rend_vtables[pipeline->backend].pipeline_draw_indexed(pipeline, index_count, first_index, vertex_offset, instance_count);
+}
+
+extern void
+rend_cmd_blit(RendRenderer renderer, RendTexture *src, RendTexture *dst, uint32_t src_x, uint32_t src_y, uint32_t src_w, uint32_t src_h, uint32_t dst_x, uint32_t dst_y, uint32_t dst_w, uint32_t dst_h)
+{
+ RASSERT(renderer->in_frame && "Must be called while rendering a frame!");
+ RASSERT(!renderer->in_pass && "Must be called outside a render pass!");
+ renderer->in_pass = true;
+ rend_vtables[renderer->backend].texture_blit(renderer, src, dst, src_x, src_y, src_w, src_h, dst_x, dst_y, dst_w, dst_h);
+}
+
+static bool
+rend__renderer_init_recursive(RendRenderer renderer, RendBackendType backend, bool auto_pick)
+{
+ /* set autopick to true and set backend to first backend*/
+ if (backend == REND_BACKEND_AUTO) {
+ backend++;
+ auto_pick = true;
+ }
+
+ switch (backend) {
+ default:
+ /* unless using auto pick to pick renderers, crash */
+ if (!auto_pick) REND__CRASH("Invalid backend type!");
+
+ case REND_BACKEND_VULKAN_14:
+ if (rend_vk_init()) {
+ rend_backend_vk_initialized = true;
+ renderer->backend = REND_BACKEND_VULKAN_14;
+ return true;
+ }
+ break;
+ }
+
+ if (auto_pick) {
+ backend++;
+ if (backend >= REND_BACKEND_COUNT) {
+ return false;
+ }
+
+ /* recursively try next backend */
+ return rend__renderer_init_recursive(renderer, backend, auto_pick);
+ }
+
+ return false;
+}
+
+static void
+rend__renderer_destroy_recursive(RendRenderer renderer)
+{
+ if (renderer == NULL) return;
+
+ rend__renderer_destroy_recursive(renderer->next);
+
+ if (renderer->backend != 0) {
+ rend_vtables[renderer->backend].renderer_destroy(renderer);
+ }
+
+ rend__pipeline_destroy_recursive(renderer->pipeline_head);
+ rfree(renderer);
+}
+
+static void
+rend__pipeline_destroy_recursive(RendPipeline pipeline)
+{
+ if (pipeline == NULL) return;
+ rend__pipeline_destroy_recursive(pipeline->next);
+ rfree(pipeline);
+}
diff --git a/Rend/rend.h b/Rend/rend.h
new file mode 100644
index 0000000..a9a4a81
--- /dev/null
+++ b/Rend/rend.h
@@ -0,0 +1,331 @@
+/* ===========================================================================
+ * REND - Renderer Library - Copyright (c) 2026 Vasco Alves
+ *
+ * DESCRIPTION:
+ * - High level graphics rendering API around Vulkan 1.4
+ * - Pushes data to the GPU in a highly configurable and STABLE fashion.
+ * - Is not responsible for initializing windows.
+ * - Is not responsible for compiling shaders.
+ * - Depends on PODIUM to be cross-platform.
+ *
+ * =========================================================================== */
+
+#ifndef _REND_H_
+#define _REND_H_
+
+#define REND_MAJOR 1 // breaking API changes
+#define REND_MINOR 0 // non-breaking features
+#define REND_PATCH 1 // non-breaking patches and bug fixes
+
+#define P_MODULE_VULKAN
+#define P_MODULE_MATH
+#include "podium.h"
+
+typedef struct rend_renderer_t* RendRenderer; // renderer target handle
+typedef struct rend_pipeline_t* RendPipeline; // represents a baked shader + gpu pipeline state (blend mode, depth, vertex format)
+
+typedef struct RendMemory RendMemory;
+typedef struct RendSpecs RendSpecs;
+typedef struct RendBuffer RendBuffer;
+typedef struct RendTexture RendTexture;
+
+/* Typedef enums as 16 bit unsigned integers */
+typedef uint16_t RendBackendType;
+typedef uint16_t RendLifetime;
+typedef uint16_t RendFormat;
+typedef uint16_t RendTopology;
+typedef uint16_t RendCullMode;
+typedef uint16_t RendPolygonMode;
+typedef uint16_t RendBufferType;
+
+typedef enum RendInputRate { REND_INPUT_RATE_INSTANCE, REND_INPUT_RATE_VERTEX } RendInputRate;
+typedef enum RendIndexType { REND_INDEX_UINT16 = 16, REND_INDEX_UINT32 = 32 } RendIndexType;
+
+typedef struct {
+ uint64_t binding;
+ uint64_t stride;
+ uint8_t input_rate;
+} RendVertexBinding;
+
+typedef struct {
+ uint64_t location;
+ uint64_t binding;
+ uint64_t offset;
+ RendFormat format;
+} RendVertexAttributes;
+
+typedef struct {
+ uint32_t offset;
+ uint32_t size;
+} RendPushConstantInfo;
+
+#define REND_MAX_BINDINGS 8
+
+typedef struct {
+ uint32_t ubo_bindings[REND_MAX_BINDINGS];
+ uint32_t ubo_array_sizes[REND_MAX_BINDINGS];
+ uint32_t ubo_binding_count;
+
+ uint32_t ssbo_bindings[REND_MAX_BINDINGS];
+ uint32_t ssbo_array_sizes[REND_MAX_BINDINGS];
+ uint32_t ssbo_binding_count;
+
+ uint32_t texture_bindings[REND_MAX_BINDINGS];
+ uint32_t texture_array_sizes[REND_MAX_BINDINGS];
+ uint32_t texture_binding_count;
+} RendBindingInfo; // the binding of rend: rebirth
+
+/* Clean up */
+extern void rend_quit(void); // Will free ALL resources created by the library such as RendRenderer, RendPipeline, RendBuffer and RendTexture.
+
+/* Renderer */
+extern RendRenderer rend_renderer_create(P_Window*, RendBackendType backend, void* device, bool vsync, RendBindingInfo *bind_info); // Create Renderer that renders to a target window with
+extern void rend_renderer_destroy(RendRenderer renderer); // Destroy renderer. Unless you need to freely create and destroy renderers, you can rely on rend_quit to clean up.
+extern bool rend_renderer_frame_begin(RendRenderer renderer); // May fail. Acquires backbuffer and starts recording commands!
+extern void rend_renderer_frame_end(RendRenderer renderer, float *delta); // Stops recording commands and presents the contents to the screen.
+
+/* Write to Descriptor Sets */
+extern void rend_descriptor_write_ubo(RendRenderer, RendBuffer ubo, uint32_t binding, uint32_t slot); //
+extern void rend_descriptor_write_ssbo(RendRenderer, RendBuffer ssbo, uint32_t binding, uint32_t slot);
+extern void rend_descriptor_write_texture(RendRenderer, RendTexture *texture, uint32_t binding, uint32_t slot); // Writes texture to a slot in the texture array. Does not need to be in the main render loop.
+
+/* Buffers */
+extern RendBuffer rend_buffer_create(RendRenderer renderer, size_t size, RendBufferType type, bool gpu); // Create a buffer. The type flags define what usage is passed to the backend. Setting gpu to true will make the memory static, otherwise memory will be dynamic.
+extern void rend_buffer_destroy(RendBuffer *buffer); // Destroy a buffer. Does not deallocate it's memory.
+extern void rend_buffer_write(RendRenderer renderer, RendBuffer *buffer, const void *data, size_t size, size_t offset); // Write to buffer. Works for dynamically and statically allocated buffers.
+extern void rend_buffer_copy(RendRenderer renderer, RendBuffer *dest, size_t dest_offset, RendBuffer *src, size_t src_offset, size_t bytes);
+extern uint64_t rend_buffer_address(RendBuffer *buffer); // Returns 64 bit address to buffer memory.
+
+/* Textures */
+extern RendTexture rend_texture_create(RendRenderer renderer, uint32_t width, uint32_t height, uint32_t depth, uint32_t mip_levels, uint32_t layers, RendFormat format); // Create a texture.
+extern RendTexture rend_texture_create_from_data(RendRenderer renderer, const void *data, uint32_t width, uint32_t height, RendFormat format); // Create texture and copy data to it immediately.
+extern void rend_texture_destroy(RendRenderer renderer, RendTexture *texture); // Destroy texture. Does not deallocate it's memory from the bump allocator.
+extern void rend_texture_copy_data(RendRenderer renderer, RendTexture *texture, const void *data, size_t size); // Copy data to texture. MUST be the same size as the format expects (width x height x sizeof format).
+extern void rend_texture_copy_buffer(RendRenderer renderer, RendTexture *texture, RendBuffer *buffer); // Copy buffer to texture.
+
+/* Create, Configure, and Destroy Rendering Pipelines */
+extern RendPipeline rend_pipeline_create_graphics_spirv(RendRenderer renderer, uint8_t *vertex_bytes, size_t vertex_size, uint8_t *frag_bytes, size_t frag_size, const RendVertexBinding *vertex_bindings, uint32_t vertex_binding_count, const RendVertexAttributes *vertex_attributes, uint32_t vertex_attribute_count, const RendPushConstantInfo *push_constants, uint32_t push_constant_count, RendPolygonMode polygon_mode, RendCullMode cull_mode, RendTopology topology, RendFormat color_format, bool depth_test_enable); // Create a pipeline for a renderer using a configuration handle.
+extern RendPipeline rend_pipeline_create_graphics_bindless_spirv(RendRenderer renderer, uint8_t *vertex_bytes, size_t vertex_size, uint8_t *frag_bytes, size_t frag_size, const RendPushConstantInfo *push_constants, uint32_t push_constant_count, RendPolygonMode polygon_mode, RendCullMode cull_mode, RendTopology topology, RendFormat color_format, bool depth_test_enable); // Create a pipeline for a renderer using a configuration handle.
+extern RendPipeline rend_pipeline_create_meshlet_spirv(RendRenderer renderer, uint8_t *meshlet_bytes, size_t meshlet_size, uint8_t *frag_bytes, size_t frag_size, const RendPushConstantInfo *push_constants, uint32_t push_constant_count, RendPolygonMode polygon_mode, RendCullMode cull_mode, bool depth_test_enable); // Creates a meshlet rendering pipeline.
+extern RendPipeline rend_pipeline_create_compute_spirv(RendRenderer renderer, const uint8_t *compute_bytes, size_t compute_size, const RendPushConstantInfo *push_constants, uint32_t push_constant_count); // Create a compute pipeline.
+
+/* Commands */
+extern void rend_cmd_render_begin(RendRenderer renderer, float r, float g, float b, float a); // Begin render pass to default target the window.
+extern void rend_cmd_render_begin_texture(RendRenderer renderer, RendTexture *texture); // Begin render pass with a texture as the target.
+extern void rend_cmd_render_end(RendRenderer renderer); // End render pass.
+extern void rend_cmd_render_end_texture(RendRenderer renderer, RendTexture *texture); // End render pass that targets texture. Transition texture to read optimal format.
+extern void rend_cmd_bind_pipeline(RendPipeline pipeline); // Bind the pipeline to this frame.
+extern void rend_cmd_bind_vertex_buffer(RendPipeline pipeline, uint32_t binding, RendBuffer buffer, size_t offset); // Bind vertex buffer to this graphics pipeline.
+extern void rend_cmd_bind_index_buffer(RendPipeline pipeline, RendBuffer buffer, size_t offset, RendIndexType index_type); // Bind index buffer to this graphics pipeline.
+extern void rend_cmd_push_constants(RendPipeline pipeline, void *push_data, size_t size); // Send push constants to this pipeline / command buffer.
+extern void rend_cmd_dispatch(RendPipeline pipeline, uint32_t x, uint32_t y, uint32_t z); // Dispatch compute commands to group with dimensions x, y, z!
+extern void rend_cmd_draw(RendPipeline pipeline, size_t count, uint32_t instance_count); // Calls draw command on the pipeline.
+extern void rend_cmd_draw_indexed(RendPipeline pipeline, uint32_t index_count, uint32_t first_index, int32_t vertex_offset, uint32_t instance_count); // Draw the pipeline using indexed rendering.
+extern void rend_cmd_blit(RendRenderer renderer, RendTexture *src, RendTexture *dst, uint32_t src_x, uint32_t src_y, uint32_t src_w, uint32_t src_h, uint32_t dst_x, uint32_t dst_y, uint32_t dst_w, uint32_t dst_h); // Blit a section of one texture onto another texture.
+
+enum RendBackendType_t {
+ REND_BACKEND_AUTO = 0,
+ REND_BACKEND_VULKAN_14,
+ REND_BACKEND_COUNT
+};
+
+enum RendLifetime_t {
+ REND_LIFETIME_FRAME = 0,
+ REND_LIFETIME_PERMANENT
+};
+
+enum RendTopology_t {
+ REND_TOPOLOGY_TRIANGLE_LIST = 0,
+ REND_TOPOLOGY_TRIANGLE_STRIP,
+ REND_TOPOLOGY_LINE_LIST,
+ REND_TOPOLOGY_LINE_STRIP,
+ REND_TOPOLOGY_POINT_LIST,
+};
+
+enum RendCullMode_t {
+ REND_CULL_MODE_NONE = 0,
+ REND_CULL_MODE_FRONT,
+ REND_CULL_MODE_BACK,
+ REND_CULL_MODE_FRONT_AND_BACK,
+};
+
+enum RendPolygonMode_t {
+ REND_POLYGON_MODE_FILL = 0,
+ REND_POLYGON_MODE_LINE,
+ REND_POLYGON_MODE_POINT,
+};
+
+enum RendFormat_t {
+ REND_FORMAT_UNDEFINED = 0,
+ REND_FORMAT_R8_UNORM,
+ REND_FORMAT_R8G8_UNORM,
+ REND_FORMAT_R8G8B8A8_UNORM,
+ REND_FORMAT_B8G8R8A8_UNORM,
+
+ REND_FORMAT_R8G8B8A8_SRGB,
+ REND_FORMAT_B8G8R8A8_SRGB,
+
+ REND_FORMAT_R32_SFLOAT,
+ REND_FORMAT_R32G32_SFLOAT,
+ REND_FORMAT_R32G32B32_SFLOAT,
+ REND_FORMAT_R32G32B32A32_SFLOAT,
+
+ /* useful aliases */
+ REND_FORMAT_1_SFLOAT32 = REND_FORMAT_R32_SFLOAT,
+ REND_FORMAT_2_SFLOAT32 = REND_FORMAT_R32G32_SFLOAT,
+ REND_FORMAT_3_SFLOAT32 = REND_FORMAT_R32G32B32_SFLOAT,
+ REND_FORMAT_4_SFLOAT32 = REND_FORMAT_R32G32B32A32_SFLOAT,
+
+ REND_FORMAT_R16_SFLOAT,
+ REND_FORMAT_R16G16_SFLOAT,
+ REND_FORMAT_R16G16B16A16_SFLOAT,
+
+ REND_FORMAT_R8G8B8A8_UINT,
+ REND_FORMAT_R16G16B16A16_UINT,
+ REND_FORMAT_R32_UINT,
+ REND_FORMAT_R32_SINT,
+ REND_FORMAT_R32G32B32A32_UINT,
+
+ REND_FORMAT_D32_SFLOAT,
+ REND_FORMAT_D24_UNORM_S8_UINT,
+ REND_FORMAT_D32_SFLOAT_S8_UINT,
+
+ REND_FORMAT_COUNT
+};
+
+static size_t rend_format_size[REND_FORMAT_COUNT] = {
+ [REND_FORMAT_UNDEFINED] = 0,
+
+ [REND_FORMAT_R8_UNORM] = 1,
+ [REND_FORMAT_R8G8_UNORM] = 2,
+ [REND_FORMAT_R8G8B8A8_UNORM] = 4,
+ [REND_FORMAT_B8G8R8A8_UNORM] = 4,
+
+ [REND_FORMAT_R8G8B8A8_SRGB] = 4,
+ [REND_FORMAT_B8G8R8A8_SRGB] = 4,
+
+ [REND_FORMAT_R32_SFLOAT] = 4,
+ [REND_FORMAT_R32G32_SFLOAT] = 8,
+ [REND_FORMAT_R32G32B32_SFLOAT] = 12,
+ [REND_FORMAT_R32G32B32A32_SFLOAT] = 16,
+
+ [REND_FORMAT_R16_SFLOAT] = 2,
+ [REND_FORMAT_R16G16_SFLOAT] = 4,
+ [REND_FORMAT_R16G16B16A16_SFLOAT] = 8,
+
+ [REND_FORMAT_R8G8B8A8_UINT] = 4,
+ [REND_FORMAT_R16G16B16A16_UINT] = 8,
+ [REND_FORMAT_R32_UINT] = 4,
+ [REND_FORMAT_R32_SINT] = 4,
+ [REND_FORMAT_R32G32B32A32_UINT] = 16,
+
+ [REND_FORMAT_D32_SFLOAT] = 4,
+ [REND_FORMAT_D24_UNORM_S8_UINT] = 4,
+ [REND_FORMAT_D32_SFLOAT_S8_UINT] = 8, // typically padded to 64-bit alignment by GPU drivers
+};
+
+enum RendBufferType_t {
+ REND_BUFFER_VERTEX ,
+ REND_BUFFER_INDEX ,
+ REND_BUFFER_UNIFORM ,
+ REND_BUFFER_STORAGE ,
+ REND_BUFFER_INDIRECT ,
+ REND_BUFFER_TRANSFER ,
+ REND_BUFFER_COUNT ,
+};
+
+
+
+/* CHANGE LOG
+ * 0.1.0 - @vasco - vulkan instance
+ * 0.1.1 - @vasco - swapchain
+ * 0.1.2 - @vasco - command buffers
+ * 0.2.0 - @vasco - push basic vertex data to the gpu
+ * 0.3.1 - @vasco - Fixed rend_quit not freeing all objects.
+ * 0.4.0 - @vasco - Added resource sets.
+ * 0.4.1 - @vasco - Fixed binding descriptor sets.
+ * 0.4.2 - @vasco - Fixed capped framerate due to FIFO being always enabled and added vsync option.
+ * 0.4.3 - @vasco - Replaced bad fence based synchronization with a single timeline semaphore.
+ * 0.4.4 - @vasco - Deprecated pipeline destruction and clearing because it doesnt make any sense.
+ * 0.4.5 - @vasco - Exposed depth testing.
+ * 0.5.0 - @vasco - Host-visible buffers
+ * 0.5.1 - @vasco - Removed RendMemProperties from public API.
+ * 0.5.2 - @vasco - push_data is now push_vertices_and_draw and pipeline_draw not takes vertex count
+ * 0.6.0 - @vasco - indexed rendering
+ * 0.6.1 - @vasco - cool beans
+ * 0.6.2 - @vasco - Removed RendMemProperties is back.
+ * 0.6.3 - @vasco - push_data removed in favor of making the pipeline more low level. A prebuilt "gfx" pipeline can be added in the future.
+ * 0.6.4 - @vasco - Moved to push constants and bindless descriptors unde the hood.
+ * 0.7.0 - @vasco - Low level buffer creation API if you want device-local data.
+ * 0.7.1 - @vasco - typedefs for ease of use
+ * 0.8.0 - @vasco - bindless resources
+ * 0.8.1 - @vasco - remove old binding code from backend
+ * 0.8.2 - @vasco - nothing works!!!
+ * 0.8.3 - @vasco - pool allocator
+ * 0.8.4 - @vasco - buffers 2.0
+ * 0.8.5 - @vasco - memory 2.0
+ * 0.8.6 - @vasco - arena allocator
+ * 0.8.7 - @vasco - everything works!!!
+ * 0.8.8 - @vasco - fix device selection
+ * 0.8.9 - @vasco - images 2.0
+ * 0.9.0 - @vasco - textures!!!!!
+ * 0.9.1 - @vasco - clear to color
+ * 0.10.0 - @vasco - instanced rendering
+ * 0.10.1 - @vasco - API clean up pt. 1 (remove RendShader in favor of pointers to data)
+ * 0.10.2 - @vasco - API clean up pt. 2 (remove RendPipelineConfig in favor of large functions)
+ * 0.11.0 - @vasco - compute shaders, dispatch command and render pass is now separate
+ * 0.11.1 - @vasco - better descriptor binding, multiple ubo, ssbo and texture arrays
+ * 0.11.2 - @vasco - cool beans
+ * 1.0.0 - @vasco - finished API release
+ * 1.0.1 - @vasco - render pass that targets textures
+ *
+ * 1.0.0 finished API release
+ *
+ * -------------------------------------------
+ *
+ * 1.1.0 shader hot realoading plugin (need to add settings managament and dll loading to Podium)
+ */
+
+/*
+------------------------------------------------------------------------------
+This software is available under 2 licenses -- choose whichever you prefer.
+------------------------------------------------------------------------------
+ALTERNATIVE A - MIT License
+Copyright (c) 2026 Vasco Alves
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+of the Software, and to permit persons to whom the Software is furnished to do
+so, subject to the following conditions:
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+------------------------------------------------------------------------------
+ALTERNATIVE B - Public Domain (www.unlicense.org)
+This is free and unencumbered software released into the public domain.
+Anyone is free to copy, modify, publish, use, compile, sell, or distribute this
+software, either in source code form or as a compiled binary, for any purpose,
+commercial or non-commercial, and by any means.
+In jurisdictions that recognize copyright laws, the author or authors of this
+software dedicate any and all copyright interest in the software to the public
+domain. We make this dedication for the benefit of the public at large and to
+the detriment of our heirs and successors. We intend this dedication to be an
+overt act of relinquishment in perpetuity of all present and future rights to
+this software under copyright law.
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+------------------------------------------------------------------------------
+*/
+
+#endif
diff --git a/Rend/rend_internal.h b/Rend/rend_internal.h
new file mode 100644
index 0000000..03e6634
--- /dev/null
+++ b/Rend/rend_internal.h
@@ -0,0 +1,205 @@
+#ifndef REND_INTERNAL_H
+#define REND_INTERNAL_H
+
+#include "rend_vk_internal.h"
+
+
+#if defined(REND_DEBUG)
+#define P_LOG_DEBUG_ENABLED 1
+#define RASSERT(a, s) assert((a) && s)
+#else
+#define RASSERT(a,s) ((void*)0)
+#endif
+
+#if defined(REND_DEBUG_MEMORY)
+#define rmalloc(size) p_debug_malloc_impl((size), __FILE__, __LINE__, __func__)
+#define rrealloc(ptr, size) p_debug_realloc_impl((ptr), (size), __FILE__, __LINE__, __func__)
+#define rfree(ptr) p_debug_free_impl((ptr), __FILE__, __LINE__, __func__)
+#else
+#define rmalloc malloc
+#define rrealloc(ptr, size) realloc((ptr), (size))
+#define rfree free
+#endif
+
+#define REND_TODO \
+ do { \
+ fprintf(stderr, "REND TODO: %s() in %s:%d\n", __func__, __FILE__, __LINE__); \
+ abort(); \
+ } while(0)
+
+#define REND__CRASH(...)\
+ PERROR(__VA_ARGS__);\
+ exit(1);
+
+#define REND__WARN(...) PWARN("[REND] "__VA_ARGS__);
+
+#include "podium.h"
+#include "rend.h"
+
+#include <stdint.h>
+
+typedef void* RendContextHandle;
+
+enum RendPipelineType {
+ REND__PIPELINE_GRAPHICS,
+ REND__PIPELINE_COMPUTE,
+ REND__PIPELINE_MESH,
+};
+
+typedef struct rend_pipeline_config_t {
+
+ const RendVertexBinding *vertex_bindings;
+ const RendVertexAttributes *vertex_attributes;
+ const RendPushConstantInfo *push_constants;
+
+ uint32_t vertex_binding_count;
+ uint32_t vertex_attribute_count;
+ uint32_t push_constant_count;
+
+ uint16_t color_format;
+ uint16_t depth_format;
+
+ uint16_t polygon_mode;
+ uint16_t cull_mode;
+ uint16_t topology;
+
+ uint8_t depth_test_enable;
+} Rend__PipelineConfig;
+
+typedef struct {
+ RendContextHandle (*renderer_create)();
+
+ void (*renderer_destroy)(RendContextHandle);
+
+ bool (*renderer_frame_begin)(RendContextHandle);
+ void (*renderer_frame_end)(RendContextHandle, float *delta);
+
+ void (*descriptor_write_buffer)(RendRenderer renderer, RendBuffer ubo, uint32_t binding, uint32_t slot, uint32_t offset, uint32_t size, bool is_ubo);
+ void (*descriptor_write_texture)(void *ctx, RendTexture *texture, uint32_t binding, uint32_t slot);
+
+ RendBuffer (*buffer_create_lifetime)(RendRenderer renderer, size_t size, RendBufferType type, bool gpu, int lifetime);
+ void (*buffer_destroy)(RendBuffer *buffer);
+ void (*buffer_copy)(RendRenderer renderer, RendBuffer *dest, size_t dest_offset, RendBuffer *src, size_t src_offset, size_t bytes);
+
+ RendTexture (*texture_create)(RendRenderer renderer, uint32_t width, uint32_t height, uint32_t depth, uint32_t mip_levels, uint32_t layers, RendFormat format);
+ void (*texture_destroy)(RendRenderer renderer, RendTexture *tex);
+ void (*texture_copy_buffer)(RendRenderer renderer, RendTexture *texture, RendBuffer *buffer);
+ void (*texture_blit)(RendRenderer renderer, RendTexture *src, RendTexture *dst, uint32_t src_x, uint32_t src_y, uint32_t src_w, uint32_t src_h, uint32_t dst_x, uint32_t dst_y, uint32_t dst_w, uint32_t dst_h);
+
+ bool (*pipeline_create)(RendRenderer, RendPipeline, Rend__PipelineConfig, uint8_t type, const uint8_t *shader1, size_t bytes1, const uint8_t *shader2, size_t bytes2, const uint8_t *shader3, size_t bytes3);
+ void (*pipeline_bind)(RendPipeline);
+ void (*pipeline_push_constants)(RendPipeline pipeline, void *push_data, size_t size);
+
+ void (*pipeline_bind_vertex_buffer)(RendPipeline pipeline, uint32_t binding, RendBuffer buffer, size_t offset);
+ void (*pipeline_bind_index_buffer)(RendPipeline pipeline, RendBuffer buffer, size_t offset, RendIndexType index_type);
+
+ void (*pipeline_dispatch)(RendPipeline pipeline, uint32_t x, uint32_t y, uint32_t z);
+ void (*pipeline_draw)(RendPipeline, size_t count, uint32_t instance_count);
+ void (*pipeline_draw_indexed)(RendPipeline pipeline, uint32_t index_count, uint32_t first_index, int32_t vertex_offset, uint32_t instance_count);
+ void (*pipeline_set_blend)(RendPipeline, bool);
+
+ void (*renderer_render_pass_begin)(RendRenderer renderer, float r, float g, float b, float a);
+ void (*renderer_render_pass_begin_texture)(RendRenderer, RendTexture*);
+ void (*renderer_render_pass_end)(RendRenderer renderer);
+ void (*renderer_render_pass_end_texture)(RendRenderer renderer, RendTexture*);
+} RendVTable;
+
+
+struct rend_pipeline_t {
+ struct rend_pipeline_t *next;
+ struct rend_pipeline_t *prev;
+ void *backend_ctx;
+ uint32_t idx; // index into renderers internal array of pipelines
+ uint32_t frame_count;
+ uint8_t backend;
+ uint8_t type;
+};
+
+struct rend_renderer_t {
+ struct rend_renderer_t *next;
+ struct rend_renderer_t *prev;
+
+ struct rend_pipeline_t *pipeline_head;
+ RendContextHandle context; // backend specific internal data
+ P_Window *window;
+ uint64_t frame_count;
+
+ RendBindingInfo bind_info;
+
+ uint32_t texture_binding;
+ uint32_t texture_count;
+ uint32_t ubo_binding;
+ uint32_t ubo_count;
+
+ uint8_t backend;
+ uint8_t in_frame;
+ uint8_t in_pass;
+ uint8_t vsync;
+};
+
+
+/* NOTE(vasco): Its simpler if backeds all use a uniform struct than
+ * every single one having to basically redefine the same thing
+ */
+
+struct RendMemory {
+ void *host_mapped_memory; // pointer if memory is host visible
+ uint64_t device_memory; // original device memory pointer
+ uint64_t size; // size of the memory allocation AFTER THE OFFSET
+ uint64_t offset; // we must sum the offset to device memory
+ uint32_t heap_index; // heap index where the memory is located
+ uint32_t id; // used by custom allocators
+};
+
+struct RendBuffer {
+ RendMemory memory;
+ void *mapped_memory; // pointer to offset memory
+ void *allocator;
+ void *logical_device;
+ uint64_t handle;
+ uint64_t gpu_address; // addresses must be buffer specific and cannot be generalized into memory because of how vulkan works
+ uint32_t usage;
+ uint32_t size;
+ uint8_t backend;
+};
+
+struct RendTexture {
+
+ RendMemory memory;
+ void *ctx;
+
+ uint64_t handle;
+ uint64_t view;
+ uint64_t sampler;
+
+ uint64_t id;
+
+ uint32_t width;
+ uint32_t height;
+
+ uint32_t format;
+
+ uint32_t depth;
+ uint32_t mip_levels;
+ uint32_t layers;
+
+ uint32_t img_type;
+ uint32_t usage;
+ uint32_t sample_count_flags;
+ uint32_t sharing_mode;
+
+ uint32_t layout;
+
+ uint8_t backend;
+};
+
+struct RendSpecs {
+ bool graphics;
+ bool transfer;
+ bool compute;
+ bool present;
+ bool sampler_anisotropy;
+ bool discrete_gpu;
+};
+
+#endif
diff --git a/Rend/rend_vk.c b/Rend/rend_vk.c
new file mode 100644
index 0000000..ad1cc34
--- /dev/null
+++ b/Rend/rend_vk.c
@@ -0,0 +1,2149 @@
+#pragma once
+#include "rend.h"
+#include "rend_internal.h"
+#include <stdint.h>
+#include <vulkan/vulkan.h>
+#include <vulkan/vulkan_core.h>
+
+#include "rend_vk_internal.h"
+#include "rend_vk_allocator.c"
+#include "rend_vk_device.c"
+#include "rend_vk_arena.c"
+#include "rend_vk_image.c"
+
+#define REND_MIN_FRAMES_IN_FLIGHT 2 // double buffering!
+#define REND_MAX_FRAMES_IN_FLIGHT 4 // quadruple buffering!
+
+#define REND_VK_MAX_PIPELINES 100
+
+typedef struct {
+ VkSwapchainKHR handle;
+ VkSurfaceFormatKHR format;
+ VkExtent2D extent;
+
+ uint32_t image_count;
+ VkImage *images;
+ VkImageView *views;
+
+ RendVkImage depth_attachment;
+} RendVkSwapchain;
+
+typedef struct {
+ VkCommandPool command_pool;
+ VkCommandBuffer command_buffer;
+ VkSemaphore image_acquired_semaphore;
+} RendVkFrameResources;
+
+typedef struct {
+ uint8_t push_data[128];
+ uint32_t size;
+} RendVkResourceSet;
+
+typedef struct RendVkPipeline {
+ void *ctx;
+ VkPipeline handle;
+ VkPipelineLayout layout;
+ uint32_t vertex_count;
+ uint32_t vertex_stride;
+ uint32_t push_constants_range;
+
+ bool blend_enable;
+} RendVkPipeline;
+
+
+/*
+ * per renderer context, separate from global vk_ variables
+ * such as the instance, the allocator, the devices etc...
+ */
+typedef struct RendVk14Context {
+
+ RendVkDevice device; // SPEC: All objects created or allocated from a VkDevice are private to that device, and must not be used on other devices.
+
+ P_Window *window;
+ VkSurfaceKHR surface;
+ RendVkPipeline pipelines[REND_VK_MAX_PIPELINES];
+ RendVkFrameResources frame_resources[REND_MAX_FRAMES_IN_FLIGHT];
+ RendVkSwapchain swapchain;
+ VkSemaphore timeline_semaphore;
+ VkSemaphore render_complete_semaphores[REND_MAX_FRAMES_IN_FLIGHT];
+
+ VkCommandPool upload_command_pool;
+ VkCommandPool graphics_command_pool;
+
+ RendVkArenaAllocator arena_persistent; // magical arena allocator for every type of memory
+ RendVkArenaAllocator arena_frame;
+
+ uint64_t frame;
+ uint64_t frame_index;
+ uint64_t signal_value;
+ uint64_t next_signal_value;
+ uint64_t max_frames_in_flight;
+ uint32_t pipeline_count;
+ uint32_t image_index;
+
+ bool require_swapchain_recreation;
+
+ bool vsync;
+ bool in_frame;
+
+ VkDescriptorPool descriptor_pool;
+ VkDescriptorSet desc_set;
+ VkDescriptorSetLayout desc_layout;
+
+} RendVk14Context;
+
+
+/* function declarations */
+extern bool rend_vk_init();
+extern void rend_vk_quit();
+
+extern RendContextHandle rend_vk_renderer_create(P_Window *window);
+extern void rend_vk_renderer_destroy(RendContextHandle handle);
+extern bool rend_vk_renderer_frame_begin(RendContextHandle handle);
+extern void rend_vk_renderer_frame_end(RendContextHandle handle, float *delta);
+
+static inline void rend_vk__renderer_render_pass_begin_internal(RendContextHandle handle, float r, float g, float b, float a, uint64_t view_handle, uint64_t depth_attachment_view_handle, uint32_t offset_x, uint32_t offset_y, uint32_t width, uint32_t height);
+
+extern void rend_vk_renderer_render_pass_begin(RendRenderer renderer, float r, float g, float b, float a);
+extern void rend_vk_renderer_render_pass_begin_texture(RendRenderer renderer, RendTexture *texture);
+extern void rend_vk_renderer_render_pass_end(RendRenderer renderer);
+extern void rend_vk_renderer_render_pass_end_texture(RendRenderer renderer, RendTexture *texture);
+
+extern void rend_vk_descriptor_write_buffer(RendRenderer renderer, RendBuffer ubo, uint32_t binding, uint32_t slot, uint32_t offset, uint32_t size, bool is_ubo);
+extern void rend_vk_descriptor_write_texture(void *ctx, RendTexture *texture, uint32_t binding, uint32_t slot);
+
+extern RendBuffer rend_vk_buffer_create_lifetime(RendRenderer renderer, size_t size, RendBufferType type, bool gpu, int lifetime);
+extern void rend_vk_buffer_destroy(RendBuffer *buffer);
+extern void rend_vk_buffer_copy(RendRenderer renderer, RendBuffer *dest, size_t dest_offset, RendBuffer *src, size_t src_offset, size_t bytes);
+
+extern RendTexture rend_vk_texture_create(RendRenderer renderer, uint32_t width, uint32_t height, uint32_t depth, uint32_t mip_levels, uint32_t layers, RendFormat format);
+extern void rend_vk_texture_destroy(RendRenderer renderer, RendTexture *tex);
+extern void rend_vk_texture_transition_layout(RendRenderer renderer, VkCommandBuffer cmd, RendTexture *texture, VkImageLayout new_layout);
+extern void rend_vk_texture_transfer_ownership_release(RendRenderer renderer, VkCommandBuffer cmd, RendTexture *texture, uint32_t src_family, uint32_t dst_family, VkImageLayout new_layout);
+extern void rend_vk_texture_transfer_ownership_acquire(RendRenderer renderer, VkCommandBuffer cmd, RendTexture *texture, uint32_t src_family, uint32_t dst_family, VkImageLayout new_layout);
+extern void rend_vk_texture_copy_buffer(RendRenderer renderer, RendTexture *texture, RendBuffer *buffer);
+extern void rend_vk_texture_blit(RendRenderer renderer, RendTexture *src, RendTexture *dst, uint32_t src_x, uint32_t src_y, uint32_t src_w, uint32_t src_h, uint32_t dst_x, uint32_t dst_y, uint32_t dst_w, uint32_t dst_h);
+
+static VkCommandBuffer rend_vk_cmdbuffer_single_use_begin(VkCommandPool pool);
+static void rend_vk_cmdbuffer_single_use_end(VkCommandPool pool, VkCommandBuffer cmd, VkQueue q);
+
+extern bool rend_vk_pipeline_create(RendRenderer renderer, RendPipeline pipeline, Rend__PipelineConfig config, uint8_t type, const uint8_t *shader1, size_t bytes1, const uint8_t *shader2, size_t bytes2, const uint8_t *shader3, size_t bytes3);
+extern void rend_vk_pipeline_bind(RendPipeline);
+extern void rend_vk_pipeline_push_constants(RendPipeline pipeline, void *push_data, size_t size);
+
+extern void rend_vk_pipeline_bind_vertex_buffer(RendPipeline pipeline, uint32_t binding, RendBuffer buffer, size_t offset);
+extern void rend_vk_pipeline_bind_index_buffer(RendPipeline pipeline, RendBuffer buffer, size_t offset, RendIndexType index_type);
+
+extern void rend_vk_pipeline_dispatch(RendPipeline pipeline, uint32_t x, uint32_t y, uint32_t z);
+extern void rend_vk_pipeline_draw(RendPipeline, size_t count, uint32_t instance_count);
+extern void rend_vk_pipeline_draw_indexed(RendPipeline pipeline, uint32_t index_count, uint32_t first_index, int32_t vertex_offset, uint32_t instance_count);
+extern void rend_vk_pipeline_set_blend(RendPipeline, bool);
+
+VKAPI_ATTR VkBool32 VKAPI_CALL rend_vk_debug_func( VkDebugUtilsMessageSeverityFlagBitsEXT message_severity, VkDebugUtilsMessageTypeFlagsEXT message_types, const VkDebugUtilsMessengerCallbackDataEXT *callback_data, void *user_data);
+static void rend_vk_pipeline_destroy(RendVkPipeline *pipeline);
+static void rend_vk_swapchain_create(RendVk14Context *ctx, RendVkSwapchain *swapchain);
+static void rend_vk_swapchain_destroy(RendVk14Context *ctx, RendVkSwapchain *swapchain);
+
+static VkShaderModule rend_vk_shader_module_create(const void *data, size_t size);
+static uint32_t rend_vk_get_heap_index(uint32_t memory_type_bits, uint32_t preferred_index);
+
+
+extern bool
+rend_vk_init()
+{
+ RASSERT(sizeof(void*) == 8 && sizeof(int64_t) == 8 && sizeof(double) == 8, "SPEC: Host device 64-bit integer and floating-point types.");
+
+ /* trying to init another renderer with the same backend */
+ if (vk_instance) {
+ return true;
+ }
+
+ /* create instance if does not exist */
+ VkApplicationInfo vk_app_info = {VK_STRUCTURE_TYPE_APPLICATION_INFO};
+ vk_app_info.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
+ vk_app_info.pApplicationName = "REND";
+ vk_app_info.applicationVersion = VK_MAKE_VERSION(REND_MAJOR, REND_MINOR, REND_PATCH);
+ vk_app_info.apiVersion = VK_API_VERSION_1_4;
+ vk_app_info.pEngineName = "REND Renderer";
+ vk_app_info.engineVersion = VK_MAKE_VERSION(REND_MAJOR, REND_MINOR, REND_PATCH);
+
+ const char **extensions_darray = (const char **)p_vulkan_get_extensions();
+ p_darray_push(extensions_darray, VK_KHR_SURFACE_EXTENSION_NAME);
+
+#ifdef REND_DEBUG
+ p_darray_push(extensions_darray, VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
+ // p_darray_push(extensions_darray, VK_NV_DEVICE_DIAGNOSTIC_CHECKPOINTS_EXTENSION_NAME);
+ PDEBUG("Vulkan Extensions: ");
+ for (int i = 0; i < p_darray_len(extensions_darray); i++)
+ PDEBUG("%s", extensions_darray[i]);
+#endif
+
+ const char **required_validation_layers = NULL;
+
+#ifdef REND_DEBUG
+ p_darray_push(required_validation_layers, "VK_LAYER_KHRONOS_validation");
+
+ PDEBUG("Required Validation Layers: ");
+ for (uint32_t i = 0; i < p_darray_len(required_validation_layers); i++) {
+ PDEBUG(" - %s", required_validation_layers[i]);
+ }
+
+ VkValidationFeatureEnableEXT enabled_validation_features[] = {
+ // VK_VALIDATION_FEATURE_ENABLE_GPU_ASSISTED_EXT,
+ // VK_VALIDATION_FEATURE_ENABLE_GPU_ASSISTED_RESERVE_BINDING_SLOT_EXT,
+ };
+
+ VkValidationFeaturesEXT validation_features = {
+ .sType = VK_STRUCTURE_TYPE_VALIDATION_FEATURES_EXT,
+ .pNext = NULL,
+ // .enabledValidationFeatureCount = sizeof(enabled_validation_features) / sizeof(enabled_validation_features[0]),
+ // .pEnabledValidationFeatures = enabled_validation_features,
+ };
+#endif
+
+ VkInstanceCreateInfo vk_create_info = { VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO};
+ vk_create_info.pApplicationInfo = &vk_app_info;
+ vk_create_info.ppEnabledExtensionNames = extensions_darray;
+ vk_create_info.enabledExtensionCount = p_darray_len(extensions_darray);
+ vk_create_info.pApplicationInfo = &vk_app_info;
+#ifdef REND_DEBUG
+ vk_create_info.enabledLayerCount = p_darray_len(required_validation_layers);
+ vk_create_info.ppEnabledLayerNames = required_validation_layers;
+ vk_create_info.pNext = &validation_features;
+#else
+ vk_create_info.enabledLayerCount = 0;
+ vk_create_info.ppEnabledLayerNames = NULL;
+#endif
+
+ VkResult res = vkCreateInstance(&vk_create_info, vk_allocator, &vk_instance);
+ CHECK_VK_RESULT(res);
+
+ PDEBUG("Vulkan instance created!");
+ p_darray_destroy(extensions_darray);
+#ifdef REND_DEBUG
+ p_darray_destroy(required_validation_layers);
+#endif
+
+#ifdef REND_DEBUG
+ uint32_t log_severity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT;
+ VkDebugUtilsMessengerCreateInfoEXT debug_create_info = { VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT};
+ debug_create_info.messageSeverity = log_severity;
+ debug_create_info.messageType =
+ VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT |
+ VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT |
+ VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT;
+ debug_create_info.pfnUserCallback = rend_vk_debug_func;
+
+ PFN_vkCreateDebugUtilsMessengerEXT func = (PFN_vkCreateDebugUtilsMessengerEXT)vkGetInstanceProcAddr( vk_instance, "vkCreateDebugUtilsMessengerEXT");
+ if (!func) {
+ PDEBUG("Failed to create vulkan debug messenger!");
+ return false;
+ }
+ func(vk_instance, &debug_create_info, vk_allocator, &vk_debug_messenger);
+#endif
+ return true;
+}
+
+extern void
+rend_vk_quit()
+{
+ PDEBUG("[REND_VK14] Destroying device.");
+
+ /* we destroy the device on quit */
+ if (vk_device.logical_device != 0) {
+ rend_vk_device_destroy(&vk_device);
+ }
+
+ if (vk_debug_messenger) {
+ PFN_vkDestroyDebugUtilsMessengerEXT func = (PFN_vkDestroyDebugUtilsMessengerEXT)vkGetInstanceProcAddr( vk_instance, "vkDestroyDebugUtilsMessengerEXT");
+ func(vk_instance, vk_debug_messenger, vk_allocator);
+ vk_debug_messenger = 0;
+ }
+
+ vkDestroyInstance(vk_instance, vk_allocator);
+ vk_instance = 0;
+}
+
+extern RendContextHandle
+rend_vk_renderer_create(P_Window *window)
+{
+ RendVk14Context *ctx = rmalloc(sizeof(*ctx));
+ if (!ctx) {
+ PERROR("Failed to allocate internal vulkan context.");
+ return NULL;
+ }
+
+ memset(ctx, 0, sizeof *ctx);
+
+ /* get surface from window */
+ if (!p_vulkan_create_surface(window, vk_instance, vk_allocator, &ctx->surface)) {
+ PERROR("Failed to create vulkan surface!");
+ rfree(ctx);
+ return NULL;
+ }
+
+ RendSpecs specs = {
+ .sampler_anisotropy = true,
+ .graphics = true,
+ .transfer = true,
+ .discrete_gpu = false, // even though its not a requirement, I expect discrete gpu to be picked
+ };
+
+ /* we lazily create the logical device only after creating the first renderer
+ * because we need the surface first */
+ if (vk_device.logical_device == 0) {
+ rend_vk_device_create(ctx->surface, specs, &vk_device, rend_vk_device_score_default);
+ }
+
+ /* we must create arena before swapchain */
+ ctx->arena_persistent = rend_vk_arena_create(
+ vk_device.logical_device,
+ vk_device.physical_device,
+ vk_device.properties.limits,
+ vk_allocator);
+
+ ctx->arena_frame = rend_vk_arena_create(
+ vk_device.logical_device,
+ vk_device.physical_device,
+ vk_device.properties.limits,
+ vk_allocator);
+
+ /* create swapchain */
+ rend_vk_swapchain_create(ctx, &ctx->swapchain);
+
+ /* timeline semaphore */
+ VkSemaphoreTypeCreateInfo timeline_type_info = {VK_STRUCTURE_TYPE_SEMAPHORE_TYPE_CREATE_INFO};
+ timeline_type_info.semaphoreType = VK_SEMAPHORE_TYPE_TIMELINE;
+ timeline_type_info.initialValue = ctx->max_frames_in_flight;
+
+ VkSemaphoreCreateInfo timeline_semaphore_info = {VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO};
+ timeline_semaphore_info.pNext = &timeline_type_info;
+
+ if (vkCreateSemaphore(vk_device.logical_device, &timeline_semaphore_info, vk_allocator, &ctx->timeline_semaphore) != VK_SUCCESS) {
+ PERROR("Unable to create the timeline semaphore for the renderer!");
+ rfree(ctx);
+ return NULL;
+ }
+
+ /* create per frame semaphores */
+ VkSemaphoreCreateInfo frame_semaphore_info = {VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO};
+ for (uint32_t u = 0; u < REND_MAX_FRAMES_IN_FLIGHT; ++u) {
+ if (vkCreateSemaphore(
+ vk_device.logical_device,
+ &frame_semaphore_info,
+ vk_allocator,
+ &ctx->frame_resources[u].image_acquired_semaphore) != VK_SUCCESS) {
+ PERROR("Unable to create semaphore for frame #%u!", u);
+ rfree(ctx);
+ return NULL;
+ }
+
+ if (vkCreateSemaphore(
+ vk_device.logical_device,
+ &frame_semaphore_info,
+ vk_allocator,
+ &ctx->render_complete_semaphores[u]) != VK_SUCCESS) {
+ PERROR("Unable to create render complete semaphore #%u!", u);
+ rfree(ctx);
+ return NULL;
+ }
+
+ VkCommandPoolCreateInfo pool_info = {VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO};
+ pool_info.queueFamilyIndex = vk_device.graphics_family_index;
+ if (vkCreateCommandPool(vk_device.logical_device, &pool_info, vk_allocator, &ctx->frame_resources[u].command_pool) != VK_SUCCESS) {
+ PERROR("Unable to create command pool for frame #%u!", u);
+ rfree(ctx);
+ return NULL;
+ }
+
+ VkCommandBufferAllocateInfo cmdbuf_info = {VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO};
+ cmdbuf_info.commandPool = ctx->frame_resources[u].command_pool;
+ cmdbuf_info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
+ cmdbuf_info.commandBufferCount = 1;
+ if (vkAllocateCommandBuffers(vk_device.logical_device, &cmdbuf_info, &ctx->frame_resources[u].command_buffer) != VK_SUCCESS) {
+ PERROR("Unable to create command buffer for frame #%u!", u);
+ rfree(ctx);
+ return NULL;
+ }
+
+ }
+
+ VkCommandPoolCreateInfo pool_info = {
+ .sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,
+ .queueFamilyIndex = vk_device.transfer_family_index,
+ .flags = VK_COMMAND_POOL_CREATE_TRANSIENT_BIT
+ };
+
+ if (vkCreateCommandPool(vk_device.logical_device, &pool_info, vk_allocator, &ctx->upload_command_pool) != VK_SUCCESS) {
+ PERROR("Unable to create upload command pool!");
+ rfree(ctx);
+ return NULL;
+ }
+
+ pool_info.queueFamilyIndex = vk_device.graphics_family_index;
+ if (vkCreateCommandPool(vk_device.logical_device, &pool_info, vk_allocator, &ctx->graphics_command_pool) != VK_SUCCESS) {
+ PERROR("Unable to create graphics command pool!");
+ rfree(ctx);
+ return NULL;
+ }
+
+ ctx->frame = 0;
+ ctx->frame_index = 0;
+ ctx->next_signal_value = ctx->max_frames_in_flight + 1; /* start at frame zero */
+
+ /*
+ * Descriptor Pool
+ */
+ {
+ RendBindingInfo bind_info = renderer->bind_info;
+
+ uint32_t total_ubos = 0;
+ for (uint32_t i = 0; i < bind_info.ubo_binding_count; ++i) {
+ total_ubos += bind_info.ubo_array_sizes[i];
+ }
+
+ uint32_t total_ssbos = 0;
+ for (uint32_t i = 0; i < bind_info.ssbo_binding_count; ++i) {
+ total_ssbos += bind_info.ssbo_array_sizes[i];
+ }
+
+ uint32_t total_textures = 0;
+ for (uint32_t i = 0; i < bind_info.texture_binding_count; ++i) {
+ total_textures += bind_info.texture_array_sizes[i];
+ }
+
+ const uint32_t pool_count = 3;
+ VkDescriptorPoolSize pool_sizes[3] = {
+ { .type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, .descriptorCount = (total_ubos > 0) ? total_ubos : 1 },
+ { .type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, .descriptorCount = (total_ssbos > 0) ? total_ssbos : 1 },
+ { .type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, .descriptorCount = (total_textures > 0) ? total_textures : 1 }
+ };
+
+ VkDescriptorPoolCreateInfo pool_info = {
+ .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO,
+ .flags = 0,
+ .maxSets = 1,
+ .poolSizeCount = pool_count,
+ .pPoolSizes = pool_sizes,
+ .pNext = NULL,
+ };
+
+ VkResult result = vkCreateDescriptorPool(vk_device.logical_device, &pool_info, vk_allocator, &ctx->descriptor_pool);
+ if (result != VK_SUCCESS) {
+ rfree(ctx);
+ return NULL;
+ }
+
+
+ /*
+ * Descriptor Sets!!!!!!
+ */
+
+ const uint32_t binding_count = bind_info.ubo_binding_count + bind_info.ssbo_binding_count + bind_info.texture_binding_count;
+ VkDescriptorSetLayoutBinding binding_array[binding_count];
+
+ for (uint32_t i = 0; i < bind_info.ubo_binding_count; ++i) {
+ binding_array[i] = (VkDescriptorSetLayoutBinding) {
+ .binding = bind_info.ubo_bindings[i],
+ .descriptorCount = bind_info.ubo_array_sizes[i],
+ .descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
+ .stageFlags = VK_SHADER_STAGE_ALL,
+ .pImmutableSamplers = 0,
+ };
+ };
+
+ uint32_t offset = bind_info.ubo_binding_count;
+ for (uint32_t i = 0; i < bind_info.ssbo_binding_count; ++i) {
+ binding_array[i + offset] = (VkDescriptorSetLayoutBinding) {
+ .binding = bind_info.ssbo_bindings[i],
+ .descriptorCount = bind_info.ssbo_array_sizes[i],
+ .descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
+ .stageFlags = VK_SHADER_STAGE_ALL,
+ .pImmutableSamplers = 0,
+ };
+ };
+
+ offset += bind_info.ssbo_binding_count;
+ for (uint32_t i = 0; i < bind_info.texture_binding_count; ++i) {
+ binding_array[i + offset] = (VkDescriptorSetLayoutBinding) {
+ .binding = bind_info.texture_bindings[i],
+ .descriptorCount = bind_info.texture_array_sizes[i],
+ .descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
+ .stageFlags = VK_SHADER_STAGE_ALL,
+ .pImmutableSamplers = 0,
+ };
+ };
+
+ VkDescriptorBindingFlags binding_flags[binding_count];
+ for (uint32_t u = 0; u < binding_count; ++u) {
+ binding_flags[u] = VK_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT;
+ }
+
+ VkDescriptorSetLayoutBindingFlagsCreateInfo desc_flags_info = {
+ .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_BINDING_FLAGS_CREATE_INFO,
+ .bindingCount = binding_count,
+ .pBindingFlags = binding_flags
+ };
+
+ VkDescriptorSetLayoutCreateInfo desc_layout_info = {
+ .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,
+ .flags = 0,
+ .bindingCount = binding_count,
+ .pBindings = binding_array,
+ .pNext = &desc_flags_info,
+ };
+
+ result = vkCreateDescriptorSetLayout(vk_device.logical_device, &desc_layout_info, vk_allocator, &ctx->desc_layout);
+ if (result != VK_SUCCESS) {
+ PERROR("Failed to create descriptor set layout!");
+ rfree(ctx);
+ return NULL;
+ }
+
+ VkDescriptorSetAllocateInfo alloc_info = {
+ .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO,
+ .descriptorPool = ctx->descriptor_pool,
+ .descriptorSetCount = 1, // ONLY ONE DESCRIPTOR SET
+ .pSetLayouts = &ctx->desc_layout,
+ .pNext = NULL,
+ };
+
+ result = vkAllocateDescriptorSets(vk_device.logical_device, &alloc_info, &ctx->desc_set);
+ if (result != VK_SUCCESS) {
+ PERROR("Failed to allocate descriptors!!!");
+ rfree(ctx);
+ return NULL;
+ }
+ }
+
+ return ctx;
+}
+
+extern void
+rend_vk_renderer_destroy(RendContextHandle handle)
+{
+ RASSERT(handle, "Invalid context handle.");
+
+ RendVk14Context *ctx = (RendVk14Context *)handle;
+
+ VkDevice dev = vk_device.logical_device;
+
+ PDEBUG("[REND] Waiting for device...");
+ vkDeviceWaitIdle(dev);
+
+ PDEBUG("[REND] Destroying renderer...");
+ vkDestroySemaphore(dev, ctx->timeline_semaphore, vk_allocator);
+
+ /* destroy per frame semaphores */
+ for (uint32_t u = 0; u < REND_MAX_FRAMES_IN_FLIGHT; ++u) {
+ vkDestroySemaphore(dev, ctx->frame_resources[u].image_acquired_semaphore, vk_allocator);
+ vkDestroySemaphore(dev, ctx->render_complete_semaphores[u], vk_allocator);
+ vkDestroyCommandPool(dev, ctx->frame_resources[u].command_pool, vk_allocator);
+ ctx->frame_resources[u].image_acquired_semaphore = 0;
+ ctx->frame_resources[u].command_pool = 0;
+ ctx->frame_resources[u].command_buffer = 0;
+ }
+
+ vkDestroyCommandPool(vk_device.logical_device, ctx->upload_command_pool, vk_allocator);
+ vkDestroyCommandPool(vk_device.logical_device, ctx->graphics_command_pool, vk_allocator);
+
+ rend_vk_arena_destroy(&ctx->arena_persistent);
+ rend_vk_arena_destroy(&ctx->arena_frame);
+
+
+ vkDestroyDescriptorSetLayout(dev, ctx->desc_layout, vk_allocator);
+ vkDestroyDescriptorPool(dev, ctx->descriptor_pool, vk_allocator);
+
+ PDEBUG("[REND] Destroying pipelines...");
+ for (uint32_t u = 0; u < ctx->pipeline_count; ++u) {
+ rend_vk_pipeline_destroy(&ctx->pipelines[u]);
+ }
+
+ PDEBUG("[REND] Destroying swapchain...");
+ rend_vk_swapchain_destroy(ctx, &ctx->swapchain);
+ ctx->swapchain.handle = 0;
+
+ PDEBUG("[REND] Destroying surface...");
+ RASSERT(vk_instance);
+ vkDestroySurfaceKHR(vk_instance, ctx->surface, vk_allocator);
+ ctx->surface = 0;
+
+ /* handle is guarranteed to be allocated */
+ rfree(handle);
+}
+
+extern bool
+rend_vk_renderer_frame_begin(RendContextHandle handle)
+{
+ RASSERT(handle, "Invalid handle.");
+
+ RendVk14Context *ctx = (RendVk14Context *) handle;
+
+ /* check if swapchain needs recreation */
+ if (ctx->require_swapchain_recreation) {
+ PDEBUG("[REND] Awaiting device...");
+ vkDeviceWaitIdle(vk_device.logical_device);
+ PDEBUG("[REND] Recreating swapchain...");
+ rend_vk_swapchain_destroy(ctx, &ctx->swapchain);
+ rend_vk_swapchain_create(ctx, &ctx->swapchain);
+ ctx->require_swapchain_recreation = false;
+ }
+
+ VkDevice dev = vk_device.logical_device;
+
+ /* wait on timeline semaphore */
+ const uint64_t frame_res_index = ctx->frame % ctx->max_frames_in_flight;
+ ctx->frame_index = frame_res_index;
+
+ const uint64_t signal_value = ctx->next_signal_value++;
+ const uint64_t wait_value = signal_value - ctx->max_frames_in_flight;
+ ctx->signal_value = signal_value;
+
+ VkSemaphoreWaitInfo timeline_wait_info = {
+ .sType = VK_STRUCTURE_TYPE_SEMAPHORE_WAIT_INFO,
+ .semaphoreCount = 1,
+ .pSemaphores = &ctx->timeline_semaphore,
+ .pValues = &wait_value
+ };
+
+ vkWaitSemaphores(vk_device.logical_device, &timeline_wait_info, UINT64_MAX);
+
+ RendVkFrameResources frame_resource = ctx->frame_resources[frame_res_index];
+ vkResetCommandPool(dev, frame_resource.command_pool, 0);
+
+ /* acquire next image */
+ VkResult acquire_image = vkAcquireNextImageKHR(
+ vk_device.logical_device,
+ ctx->swapchain.handle,
+ UINT64_MAX,
+ frame_resource.image_acquired_semaphore,
+ VK_NULL_HANDLE,
+ &ctx->image_index);
+
+ if (acquire_image == VK_ERROR_OUT_OF_DATE_KHR) {
+ /* out of date images, may need recreating */
+ ctx->require_swapchain_recreation = true;
+ ctx->frame++;
+ return false;
+ } else if (acquire_image == VK_SUBOPTIMAL_KHR) {
+ /* requires recreation but CAN CONTINUE RENDERING */
+ ctx->require_swapchain_recreation = true;
+ }
+
+ VkCommandBufferBeginInfo cmd_begin_info = {
+ .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
+ .flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT
+ };
+
+ vkBeginCommandBuffer(frame_resource.command_buffer, &cmd_begin_info);
+
+ static const size_t NUM_LAYOUT_BARRIERS = 2;
+ VkImageMemoryBarrier2 layout_barriers[NUM_LAYOUT_BARRIERS];
+ layout_barriers[0] = (VkImageMemoryBarrier2) {
+ .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2,
+
+ .srcStageMask = VK_PIPELINE_STAGE_2_COLOR_ATTACHMENT_OUTPUT_BIT,
+ .srcAccessMask = 0,
+
+ .dstStageMask = VK_PIPELINE_STAGE_2_COLOR_ATTACHMENT_OUTPUT_BIT,
+ .dstAccessMask = VK_ACCESS_2_COLOR_ATTACHMENT_READ_BIT_KHR,
+
+ .oldLayout = VK_IMAGE_LAYOUT_UNDEFINED,
+ .newLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
+
+ .image = ctx->swapchain.images[ctx->image_index],
+
+ .subresourceRange = (VkImageSubresourceRange) {
+ .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
+ .baseMipLevel = 0,
+ .levelCount = 1,
+ .baseArrayLayer = 0,
+ .layerCount = 1
+ },
+
+ // .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
+ // .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
+ };
+ layout_barriers[1] = (VkImageMemoryBarrier2) {
+ .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2,
+
+ .srcStageMask = VK_PIPELINE_STAGE_2_EARLY_FRAGMENT_TESTS_BIT,
+ .srcAccessMask = 0,
+
+ .dstStageMask = VK_PIPELINE_STAGE_2_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_2_LATE_FRAGMENT_TESTS_BIT,
+ .dstAccessMask = VK_ACCESS_2_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,
+
+ .oldLayout = VK_IMAGE_LAYOUT_UNDEFINED,
+ .newLayout = VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL,
+
+ .image = ctx->swapchain.depth_attachment.handle,
+
+ .subresourceRange = (VkImageSubresourceRange) {
+ .aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT,
+ .baseMipLevel = 0,
+ .levelCount = 1,
+ .baseArrayLayer = 0,
+ .layerCount = 1
+ },
+ };
+
+ VkMemoryBarrier2 memory_barrier = {
+ .sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER_2,
+ .srcStageMask = VK_PIPELINE_STAGE_2_HOST_BIT,
+ .srcAccessMask = VK_ACCESS_2_HOST_WRITE_BIT,
+ .dstStageMask = VK_PIPELINE_STAGE_2_VERTEX_SHADER_BIT,
+ .dstAccessMask = VK_ACCESS_2_SHADER_READ_BIT,
+ };
+
+ VkDependencyInfo dep_info = {VK_STRUCTURE_TYPE_DEPENDENCY_INFO};
+ dep_info.memoryBarrierCount = 1;
+ dep_info.pMemoryBarriers = &memory_barrier;
+ dep_info.imageMemoryBarrierCount = (uint32_t) NUM_LAYOUT_BARRIERS;
+ dep_info.pImageMemoryBarriers = layout_barriers;
+
+ vkCmdPipelineBarrier2(frame_resource.command_buffer, &dep_info);
+
+ ctx->in_frame = true;
+ return true;
+}
+
+extern void
+rend_vk_renderer_frame_end(RendRenderer renderer, float *delta)
+{
+
+ RASSERT(renderer && (uintptr_t)renderer != 0xffffffff00000000 && "Invalid renderer. (Possible stack corruption.)");
+ RASSERT(renderer->context, "Uninitialized renderer.");
+ RASSERT(renderer->in_frame, "Must be called inside a frame.");
+ RASSERT(!renderer->in_pass, "Must not be called inside a render pass.");
+
+ RendVk14Context *ctx = (RendVk14Context *)renderer->context;
+
+ RendVkFrameResources res = ctx->frame_resources[ctx->frame_index];
+
+ VkImageMemoryBarrier2 present_barrier;
+ present_barrier = (VkImageMemoryBarrier2) {
+ .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2,
+
+ .srcStageMask = VK_PIPELINE_STAGE_2_COLOR_ATTACHMENT_OUTPUT_BIT,
+ .srcAccessMask = VK_ACCESS_2_COLOR_ATTACHMENT_WRITE_BIT,
+
+ .dstStageMask = VK_PIPELINE_STAGE_2_NONE,
+ .dstAccessMask = 0,
+
+ .oldLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
+ .newLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
+
+ .image = ctx->swapchain.images[ctx->image_index],
+
+ .subresourceRange = (VkImageSubresourceRange) {
+ .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
+ .baseMipLevel = 0,
+ .levelCount = 1,
+ .baseArrayLayer = 0,
+ .layerCount = 1
+ }
+
+ };
+
+ VkDependencyInfo dep_info = {VK_STRUCTURE_TYPE_DEPENDENCY_INFO};
+ dep_info.imageMemoryBarrierCount = 1;
+ dep_info.pImageMemoryBarriers = &present_barrier;
+
+ vkCmdPipelineBarrier2(res.command_buffer, &dep_info);
+ vkEndCommandBuffer(res.command_buffer);
+
+ /* ensure swapchain image is available */
+ VkSemaphoreSubmitInfo image_acquire_await_info = {
+ .sType = VK_STRUCTURE_TYPE_SEMAPHORE_SUBMIT_INFO,
+ .semaphore = res.image_acquired_semaphore,
+ .stageMask = VK_PIPELINE_STAGE_2_COLOR_ATTACHMENT_OUTPUT_BIT
+ };
+
+ /* signal that the image is presented */
+ VkSemaphoreSubmitInfo semaphore_signals[2] = {
+ [0] = {
+ .sType = VK_STRUCTURE_TYPE_SEMAPHORE_SUBMIT_INFO,
+ .semaphore = ctx->render_complete_semaphores[ctx->image_index],
+ .stageMask = VK_PIPELINE_STAGE_2_ALL_GRAPHICS_BIT
+ },
+ [1] = {
+ .sType = VK_STRUCTURE_TYPE_SEMAPHORE_SUBMIT_INFO,
+ .semaphore = ctx->timeline_semaphore,
+ .value = ctx->signal_value,
+ .stageMask = VK_PIPELINE_STAGE_2_ALL_GRAPHICS_BIT
+ },
+ };
+
+ VkCommandBufferSubmitInfo cmd_submit_info = {
+ .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_SUBMIT_INFO,
+ .commandBuffer = res.command_buffer,
+ };
+
+ VkSubmitInfo2 submit_info = {
+ .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO_2,
+ .waitSemaphoreInfoCount = 1,
+ .pWaitSemaphoreInfos = &image_acquire_await_info,
+ .commandBufferInfoCount = 1,
+ .pCommandBufferInfos = &cmd_submit_info,
+ .signalSemaphoreInfoCount = 2,
+ .pSignalSemaphoreInfos = semaphore_signals
+ };
+
+ vkQueueSubmit2(vk_device.graphics_queue, 1, &submit_info, VK_NULL_HANDLE);
+
+ VkPresentInfoKHR present_info = {
+ .sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR,
+ .waitSemaphoreCount = 1,
+ .pWaitSemaphores = &ctx->render_complete_semaphores[ctx->image_index],
+ .swapchainCount = 1,
+ .pSwapchains = &ctx->swapchain.handle,
+ .pImageIndices = &ctx->image_index,
+ .pResults = NULL,
+ };
+
+ vkQueuePresentKHR(vk_device.graphics_queue, &present_info);
+
+ ctx->frame++;
+ ctx->in_frame = false;
+ uint64_t f = ctx->frame_index;
+
+ /* clear host mapped memory */
+ rend_vk_arena_clear_all(&ctx->arena_frame);
+ rend_vk_arena_clear(&ctx->arena_persistent, vk_device.host_index);
+}
+
+static inline void
+rend_vk__renderer_render_pass_begin_internal(RendRenderer renderer, float r, float g, float b, float a, uint64_t view_handle, uint64_t depth_attachment_view_handle, uint32_t offset_x, uint32_t offset_y, uint32_t width, uint32_t height)
+{
+ RendVk14Context *ctx = (RendVk14Context*) renderer->context;
+ RASSERT(ctx->in_frame && "must begin render pass inside a frame");
+
+ RendVkFrameResources frame_resource = ctx->frame_resources[ctx->frame_index];
+
+ VkRenderingAttachmentInfo color_attachment = {
+ .sType = VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO,
+ .imageView = (VkImageView) view_handle,
+ .imageLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
+ .loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR, // clear image
+ .storeOp = VK_ATTACHMENT_STORE_OP_STORE, // store for presentation
+ .clearValue = (VkClearValue) {
+ .color = {r, g, b, a},
+ }
+ };
+
+ VkRenderingAttachmentInfo depth_attachment = {
+ .sType = VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO,
+ .imageView = (VkImageView) depth_attachment_view_handle,
+ .imageLayout = VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL,
+ .loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR, // clear depth data
+ .storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE, // don't care after rendering
+ .clearValue = (VkClearValue) {
+ .depthStencil = (VkClearDepthStencilValue) {1.0f, 0},
+ },
+ };
+
+ VkRenderingInfo rendering_info = {
+ .sType = VK_STRUCTURE_TYPE_RENDERING_INFO,
+ .renderArea.offset = (VkOffset2D) {offset_x, offset_y},
+ .renderArea.extent = (VkExtent2D) {width, height},
+ .layerCount = 1,
+ .colorAttachmentCount = 1,
+ .pColorAttachments = &color_attachment,
+ .pDepthAttachment = &depth_attachment,
+ };
+
+ vkCmdBeginRendering(frame_resource.command_buffer, &rendering_info);
+
+ VkViewport viewport = {
+ .x = offset_x,
+ .y = offset_y,
+ .width = width,
+ .height = height,
+ .minDepth = 0.0f,
+ .maxDepth = 1.0f
+ };
+
+ vkCmdSetViewport(frame_resource.command_buffer, 0, 1, &viewport);
+
+ VkRect2D scissor = {{offset_x, offset_y}, {width, height}};
+ vkCmdSetScissor(frame_resource.command_buffer, 0, 1, &scissor);
+}
+
+
+extern void
+rend_vk_renderer_render_pass_begin(RendRenderer renderer, float r, float g, float b, float a)
+{
+
+ RendVk14Context *ctx = (RendVk14Context*) renderer->context;
+
+ rend_vk__renderer_render_pass_begin_internal(
+ renderer,
+ r, g, b, a,
+ (uint64_t) ctx->swapchain.views[ctx->image_index],
+ (uint64_t) ctx->swapchain.depth_attachment.view,
+ 0, 0,
+ ctx->swapchain.extent.width, ctx->swapchain.extent.height
+ );
+}
+
+extern void
+rend_vk_renderer_render_pass_begin_texture(RendRenderer renderer, RendTexture *texture)
+{
+
+ RendVk14Context *ctx = (RendVk14Context*) renderer->context;
+
+ RendVkFrameResources frame_resource = ctx->frame_resources[ctx->frame_index];
+
+ rend_vk_texture_transition_layout(renderer, ctx->frame_resources[ctx->frame_index].command_buffer, texture, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
+
+ VkRenderingAttachmentInfo color_attachment = {
+ .sType = VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO,
+ .imageView = (VkImageView) texture->view,
+ .imageLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
+ .loadOp = VK_ATTACHMENT_LOAD_OP_LOAD, // load image instead of clearing
+ .storeOp = VK_ATTACHMENT_STORE_OP_STORE, // store for presentation
+ };
+
+ VkRenderingAttachmentInfo depth_attachment = {
+ .sType = VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO,
+ .imageView = (VkImageView) ctx->swapchain.depth_attachment.view,
+ .imageLayout = VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL,
+ .loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR, // clear depth data
+ .storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE, // don't care after rendering
+ .clearValue = (VkClearValue) {
+ .depthStencil = (VkClearDepthStencilValue) {1.0f, 0},
+ },
+ };
+
+ VkRenderingInfo rendering_info = {
+ .sType = VK_STRUCTURE_TYPE_RENDERING_INFO,
+ .renderArea.offset = (VkOffset2D) {0, 0},
+ .renderArea.extent = (VkExtent2D) {texture->width, texture->height},
+ .layerCount = 1,
+ .colorAttachmentCount = 1,
+ .pColorAttachments = &color_attachment,
+ .pDepthAttachment = &depth_attachment,
+ };
+
+ vkCmdBeginRendering(frame_resource.command_buffer, &rendering_info);
+
+ VkViewport viewport = {
+ .x = 0,
+ .y = 0,
+ .width = texture->width,
+ .height = texture->height,
+ .minDepth = 0.0f,
+ .maxDepth = 1.0f
+ };
+
+ vkCmdSetViewport(frame_resource.command_buffer, 0, 1, &viewport);
+
+ VkRect2D scissor = {{0, 0}, {texture->width, texture->height}};
+ vkCmdSetScissor(frame_resource.command_buffer, 0, 1, &scissor);
+}
+
+extern void
+rend_vk_renderer_render_pass_end_texture(RendRenderer renderer, RendTexture *texture)
+{
+
+ RendVk14Context *ctx = (RendVk14Context*) renderer->context;
+ rend_vk_texture_transition_layout(renderer, ctx->frame_resources[ctx->frame_index].command_buffer, texture, VK_IMAGE_LAYOUT_READ_ONLY_OPTIMAL);
+ rend_vk_renderer_render_pass_end(renderer);
+}
+
+
+extern void
+rend_vk_renderer_render_pass_end(RendRenderer renderer)
+{
+ RendVk14Context *ctx = (RendVk14Context*) renderer->context;
+ RASSERT(ctx->in_frame && "must end render pass inside a frame");
+ RendVkFrameResources res = ctx->frame_resources[ctx->frame_index];
+ vkCmdEndRendering(res.command_buffer);
+}
+
+extern void
+rend_vk_descriptor_write_buffer(RendRenderer renderer, RendBuffer ubo, uint32_t binding, uint32_t slot, uint32_t offset, uint32_t size, bool is_ubo)
+{
+ RendVk14Context *ctx = renderer->context;
+
+ VkDescriptorBufferInfo buffer_info = {
+ .buffer = (VkBuffer) ubo.handle,
+ .offset = offset,
+ .range = size,
+ };
+
+ VkWriteDescriptorSet descriptor_write = {
+ .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
+ .dstSet = ctx->desc_set,
+ .dstBinding = binding,
+ .dstArrayElement = slot, // write texture to slot
+ .descriptorCount = 1,
+ .descriptorType = (is_ubo) ? VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER : VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
+ .pBufferInfo = &buffer_info,
+ };
+
+ vkUpdateDescriptorSets(vk_device.logical_device, 1, &descriptor_write, 0, NULL);
+}
+
+
+extern RendBuffer
+rend_vk_buffer_create_lifetime(RendRenderer renderer, size_t size, RendBufferType type, bool gpu, int lifetime)
+{
+ RendVk14Context *ctx = (RendVk14Context *)renderer->context;
+ int32_t index = (gpu) ? vk_device.device_index : vk_device.host_index;
+
+ VkBufferUsageFlags vk_usage = 0;
+ switch (type) {
+ case REND_BUFFER_VERTEX:
+ vk_usage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT;
+ break;
+ case REND_BUFFER_INDEX:
+ vk_usage = VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT;
+ break;
+ case REND_BUFFER_UNIFORM:
+ vk_usage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT;
+ break;
+ case REND_BUFFER_STORAGE:
+ vk_usage = VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
+ break;
+ case REND_BUFFER_TRANSFER:
+ vk_usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT;
+ break;
+ default:
+ REND__CRASH("Invalid buffer type!");
+ break;
+ }
+
+ RendBuffer buffer = {0};
+ buffer.usage = vk_usage | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT;
+
+ bool is_concurrent = (gpu && (vk_device.graphics_family_index != vk_device.transfer_family_index));
+ int32_t family[] = { vk_device.graphics_family_index, vk_device.transfer_family_index };
+
+ VkBufferCreateInfo buffer_info = {
+ .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
+ .size = size,
+ .usage = buffer.usage,
+ .sharingMode = is_concurrent ? VK_SHARING_MODE_CONCURRENT : VK_SHARING_MODE_EXCLUSIVE,
+ .queueFamilyIndexCount = is_concurrent ? 2 : 1,
+ .pQueueFamilyIndices = is_concurrent ? family : NULL,
+ };
+
+ if (vkCreateBuffer(vk_device.logical_device, &buffer_info, vk_allocator, (VkBuffer*) &buffer.handle) != VK_SUCCESS) {
+ REND__CRASH("Failed to create VkBuffer!");
+ }
+
+ VkMemoryRequirements mem_reqs;
+ vkGetBufferMemoryRequirements(vk_device.logical_device, (VkBuffer) buffer.handle, &mem_reqs);
+
+ RASSERT((mem_reqs.memoryTypeBits & (1u << index)) && "Buffer incompatible with chosen memory type!");
+
+ RendVkArenaAllocator *arena = (lifetime == REND_LIFETIME_FRAME) ? &ctx->arena_frame : &ctx->arena_persistent;
+ RendMemory vk_memory = rend_vk_arena_alloc(arena, mem_reqs.size, index);
+
+ if (vkBindBufferMemory(vk_device.logical_device, (VkBuffer) buffer.handle, (VkDeviceMemory) vk_memory.device_memory, vk_memory.offset) != VK_SUCCESS) {
+ REND__CRASH("Failed to bind VkBuffer memory!");
+ }
+
+ buffer.memory = vk_memory;
+
+ VkBufferDeviceAddressInfo address_info = {
+ .sType = VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO,
+ .buffer = (VkBuffer) buffer.handle,
+ };
+
+ if (!gpu && vk_memory.host_mapped_memory) {
+ buffer.mapped_memory = vk_memory.host_mapped_memory;
+ } else {
+ buffer.mapped_memory = NULL;
+ }
+
+ buffer.gpu_address = vkGetBufferDeviceAddress(vk_device.logical_device, &address_info);
+ buffer.size = size;
+ return buffer;
+}
+
+extern void
+rend_vk_buffer_destroy(RendBuffer *buffer)
+{
+ // NOTE: this function is meant to be called by the user
+ // when freeing his buffers mid frame, there may be a better
+ // way using fences perhaps? or by checking the timeline semaphore?
+ vkDeviceWaitIdle(vk_device.logical_device);
+ vkDestroyBuffer(vk_device.logical_device, (VkBuffer) buffer->handle, vk_allocator);
+ memset(buffer, 0xC0FFEE, sizeof *buffer); // fill buffer with coffee
+}
+
+extern void
+rend_vk_buffer_copy(RendRenderer renderer, RendBuffer *dest, size_t dest_offset, RendBuffer *src, size_t src_offset, size_t bytes)
+{
+ RASSERT(src && dest); // check that im not sending null pointers
+ RASSERT(src->usage & VK_BUFFER_USAGE_TRANSFER_SRC_BIT); // source buffer must be marked as transfer src
+ RASSERT(dest->usage & VK_BUFFER_USAGE_TRANSFER_DST_BIT); // dest buffer must be marked as transfer dest
+
+ RendVk14Context *ctx = (RendVk14Context *)renderer->context;
+ VkBuffer src_vk = (VkBuffer)(uintptr_t)src->handle;
+ VkBuffer dest_vk = (VkBuffer)(uintptr_t)dest->handle;
+
+ VkCommandBuffer transfer_cmd = VK_NULL_HANDLE;
+
+ VkCommandBufferAllocateInfo alloc_info = {
+ .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
+ .commandBufferCount = 1,
+ .commandPool = ctx->upload_command_pool,
+ .level = VK_COMMAND_BUFFER_LEVEL_PRIMARY,
+ .pNext = NULL,
+ };
+
+ if (vkAllocateCommandBuffers(vk_device.logical_device, &alloc_info, &transfer_cmd) != VK_SUCCESS) {
+ REND__CRASH("Failed to allocate transfer command buffer!");
+ }
+
+ VkCommandBufferBeginInfo begin_info = {
+ .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
+ .flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT,
+ };
+ vkBeginCommandBuffer(transfer_cmd, &begin_info);
+
+ VkBufferCopy buffer_copy = {
+ .srcOffset = (VkDeviceSize)src_offset,
+ .dstOffset = (VkDeviceSize)dest_offset,
+ .size = (VkDeviceSize)bytes,
+ };
+
+ vkCmdCopyBuffer(transfer_cmd, src_vk, dest_vk, 1, &buffer_copy);
+ vkEndCommandBuffer(transfer_cmd);
+
+ VkCommandBufferSubmitInfo cmd_info = {
+ .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_SUBMIT_INFO,
+ .commandBuffer = transfer_cmd,
+ .deviceMask = 0,
+ };
+
+ VkSubmitInfo2 submit_info = {
+ .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO_2,
+ .commandBufferInfoCount = 1,
+ .pCommandBufferInfos = &cmd_info,
+ };
+
+ vkQueueSubmit2(vk_device.transfer_queue, 1, &submit_info, VK_NULL_HANDLE);
+
+ vkQueueWaitIdle(vk_device.transfer_queue);
+ vkFreeCommandBuffers(vk_device.logical_device, ctx->upload_command_pool, 1, &transfer_cmd);
+}
+
+
+extern RendTexture
+rend_vk_texture_create(RendRenderer renderer, uint32_t width, uint32_t height, uint32_t depth, uint32_t mip_levels, uint32_t layers, RendFormat format)
+{
+ RASSERT(format < REND_FORMAT_COUNT && "Invalid format!");
+
+ RendVk14Context *ctx = (RendVk14Context*) renderer->context;
+ VkFormat vk_format = vk_format_from_rend_format[format];
+
+ uint32_t safe_depth = (depth > 0) ? depth : 1;
+ uint32_t safe_mips = (mip_levels > 0) ? mip_levels : 1;
+ uint32_t safe_layers = (layers > 0) ? layers : 1;
+
+ RendTexture tex = {
+ .handle = 0,
+ .width = width,
+ .height = height,
+ .depth = safe_depth,
+ .mip_levels = safe_mips,
+ .layers = safe_layers,
+ .format = vk_format,
+ .layout = VK_IMAGE_LAYOUT_UNDEFINED,
+ };
+
+ VkImageCreateInfo image_info = {
+ .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
+ .imageType = (safe_depth > 1) ? VK_IMAGE_TYPE_3D : VK_IMAGE_TYPE_2D,
+ .extent = { .width = width, .height = height, .depth = safe_depth },
+ .mipLevels = tex.mip_levels,
+ .arrayLayers = tex.layers,
+ .format = vk_format,
+ .tiling = VK_IMAGE_TILING_OPTIMAL,
+ .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED,
+ .usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT,
+ .sharingMode = VK_SHARING_MODE_EXCLUSIVE,
+ .samples = VK_SAMPLE_COUNT_1_BIT,
+ .flags = 0,
+ };
+
+ if (vkCreateImage(vk_device.logical_device, &image_info, vk_allocator, (VkImage*)&tex.handle) != VK_SUCCESS) {
+ REND__CRASH("failed to create image!");
+ return tex;
+ }
+
+ VkMemoryRequirements mem_requirements;
+ vkGetImageMemoryRequirements(vk_device.logical_device, (VkImage)tex.handle, &mem_requirements);
+
+ uint32_t index = rend_vk_get_heap_index(mem_requirements.memoryTypeBits, vk_device.device_index);
+ tex.memory = rend_vk_arena_alloc(&ctx->arena_persistent, mem_requirements.size, index);
+
+ vkBindImageMemory(vk_device.logical_device, (VkImage)tex.handle, (VkDeviceMemory)tex.memory.device_memory, (VkDeviceSize)tex.memory.offset);
+
+ // Correct ImageView creation using strict VkImageViewType and derived format
+ VkImageViewCreateInfo view_info = {
+ .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
+ .image = (VkImage)tex.handle,
+ .viewType = (safe_depth > 1) ? VK_IMAGE_VIEW_TYPE_3D : VK_IMAGE_VIEW_TYPE_2D,
+ .format = vk_format,
+ .subresourceRange = {
+ .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
+ .baseMipLevel = 0,
+ .levelCount = tex.mip_levels,
+ .baseArrayLayer = 0,
+ .layerCount = tex.layers,
+ },
+ };
+
+ if (vkCreateImageView(vk_device.logical_device, &view_info, vk_allocator, (VkImageView*)&tex.view) != VK_SUCCESS) {
+ REND__CRASH("failed to create image view!");
+ return tex;
+ }
+
+ /* per-texture sampler */
+ VkSamplerCreateInfo sampler_info = {
+ .sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO,
+ .magFilter = VK_FILTER_LINEAR, // force sharp upscaling
+ .minFilter = VK_FILTER_LINEAR, // TODO: add filter setting to texture
+ .addressModeU = VK_SAMPLER_ADDRESS_MODE_REPEAT,
+ .addressModeV = VK_SAMPLER_ADDRESS_MODE_REPEAT,
+ .addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT,
+
+ .mipmapMode = (tex.mip_levels > 1) ? VK_SAMPLER_MIPMAP_MODE_LINEAR : VK_SAMPLER_MIPMAP_MODE_NEAREST,
+ .minLod = 0.0f,
+ .maxLod = (tex.mip_levels > 1) ? (float)tex.mip_levels : 0.0f,
+
+ .anisotropyEnable = (tex.mip_levels > 1 && vk_device.features.samplerAnisotropy) ? VK_TRUE : VK_FALSE,
+ .maxAnisotropy = 8.0f,
+ };
+
+ if (vkCreateSampler(vk_device.logical_device, &sampler_info, vk_allocator, (VkSampler*)&tex.sampler) != VK_SUCCESS) {
+ REND__CRASH("failed to create sampler!");
+ }
+
+ return tex;
+}
+
+extern void
+rend_vk_texture_destroy(RendRenderer renderer, RendTexture *tex)
+{
+ RASSERT(renderer && tex);
+ RendVk14Context *ctx = (RendVk14Context*)renderer->context;
+
+ if (tex->handle) {
+ vkDestroyImage(vk_device.logical_device, (VkImage) tex->handle, vk_allocator);
+ tex->handle = 0;
+ }
+
+ if (tex->view) {
+ vkDestroyImageView(vk_device.logical_device, (VkImageView) tex->view, vk_allocator);
+ tex->view = 0;
+ }
+
+ if (tex->sampler) {
+ vkDestroySampler(vk_device.logical_device, (VkSampler)tex->sampler, vk_allocator);
+ tex->sampler = 0;
+ }
+
+ // memset(tex, 0xBABE, sizeof *tex);
+}
+
+extern void
+rend_vk_texture_transition_layout(RendRenderer renderer, VkCommandBuffer cmd, RendTexture *texture, VkImageLayout new_layout)
+{
+ RendVk14Context *ctx = renderer->context;
+ VkCommandPool pool = ctx->upload_command_pool;
+
+ VkImageMemoryBarrier2 barrier = {
+ .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2,
+ .oldLayout = texture->layout,
+ .newLayout = new_layout,
+
+ .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
+ .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
+
+ .image = (VkImage) texture->handle,
+
+ .subresourceRange = (VkImageSubresourceRange) {
+ .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
+ .baseMipLevel = 0,
+ .levelCount = texture->mip_levels,
+ .baseArrayLayer = 0,
+ .layerCount = texture->layers,
+ },
+
+ .srcAccessMask = 0, // TODO
+ .dstAccessMask = 0, // TODO
+
+ };
+
+ if (texture->layout == VK_IMAGE_LAYOUT_UNDEFINED && new_layout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL) {
+ barrier.srcAccessMask = 0;
+ barrier.dstAccessMask = VK_ACCESS_2_TRANSFER_WRITE_BIT;
+ barrier.srcStageMask = VK_PIPELINE_STAGE_2_TOP_OF_PIPE_BIT;
+ barrier.dstStageMask = VK_PIPELINE_STAGE_2_TRANSFER_BIT;
+ } else if (texture->layout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL && new_layout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL) {
+ barrier.srcAccessMask = VK_ACCESS_2_TRANSFER_WRITE_BIT;
+ barrier.dstAccessMask = VK_ACCESS_2_SHADER_READ_BIT;
+ barrier.srcStageMask = VK_PIPELINE_STAGE_2_TRANSFER_BIT;
+ barrier.dstStageMask = VK_PIPELINE_STAGE_2_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT;
+ } else {
+ barrier.srcAccessMask = VK_ACCESS_2_MEMORY_WRITE_BIT;
+ barrier.dstAccessMask = VK_ACCESS_2_MEMORY_READ_BIT | VK_ACCESS_2_MEMORY_WRITE_BIT;
+ barrier.srcStageMask = VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT;
+ barrier.dstStageMask = VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT;
+ }
+
+ VkDependencyInfo dep = {
+ .sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO,
+ .pImageMemoryBarriers = &barrier,
+ .imageMemoryBarrierCount = 1,
+ };
+
+ texture->layout = new_layout;
+ vkCmdPipelineBarrier2(cmd, &dep);
+}
+
+extern void
+rend_vk_texture_transfer_ownership_release(RendRenderer renderer, VkCommandBuffer cmd, RendTexture *texture, uint32_t src_family, uint32_t dst_family, VkImageLayout new_layout)
+{
+ RendVk14Context *ctx = renderer->context;
+ (void) ctx; // reserved in case you need it for stage/access lookups later
+
+ VkImageMemoryBarrier2 barrier = {
+ .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2,
+ .oldLayout = texture->layout,
+ .newLayout = new_layout,
+ .srcQueueFamilyIndex = src_family,
+ .dstQueueFamilyIndex = dst_family,
+ .image = (VkImage) texture->handle,
+ .subresourceRange = (VkImageSubresourceRange) {
+ .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
+ .baseMipLevel = 0,
+ .levelCount = texture->mip_levels,
+ .baseArrayLayer = 0,
+ .layerCount = texture->layers,
+ },
+ };
+
+ if (texture->layout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL && new_layout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL) {
+ barrier.srcAccessMask = VK_ACCESS_2_TRANSFER_WRITE_BIT;
+ barrier.dstAccessMask = 0;
+ barrier.srcStageMask = VK_PIPELINE_STAGE_2_TRANSFER_BIT;
+ barrier.dstStageMask = VK_PIPELINE_STAGE_2_BOTTOM_OF_PIPE_BIT;
+ } else {
+ barrier.srcAccessMask = VK_ACCESS_2_MEMORY_WRITE_BIT;
+ barrier.dstAccessMask = 0;
+ barrier.srcStageMask = VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT;
+ barrier.dstStageMask = VK_PIPELINE_STAGE_2_BOTTOM_OF_PIPE_BIT;
+ }
+
+ VkDependencyInfo dep = {
+ .sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO,
+ .pImageMemoryBarriers = &barrier,
+ .imageMemoryBarrierCount = 1,
+ };
+
+ texture->layout = new_layout;
+ vkCmdPipelineBarrier2(cmd, &dep);
+}
+
+extern void
+rend_vk_texture_transfer_ownership_acquire(RendRenderer renderer, VkCommandBuffer cmd, RendTexture *texture, uint32_t src_family, uint32_t dst_family, VkImageLayout new_layout)
+{
+ RendVk14Context *ctx = renderer->context;
+ (void) ctx;
+
+ VkImageMemoryBarrier2 barrier = {
+ .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2,
+ .oldLayout = texture->layout,
+ .newLayout = new_layout,
+ .srcQueueFamilyIndex = src_family,
+ .dstQueueFamilyIndex = dst_family,
+ .image = (VkImage) texture->handle,
+
+ .subresourceRange = (VkImageSubresourceRange) {
+ .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
+ .baseMipLevel = 0,
+ .levelCount = texture->mip_levels,
+ .baseArrayLayer = 0,
+ .layerCount = texture->layers,
+ },
+ };
+
+ if (texture->layout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL && new_layout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL) {
+ barrier.srcAccessMask = 0;
+ barrier.dstAccessMask = VK_ACCESS_2_SHADER_READ_BIT;
+ barrier.srcStageMask = VK_PIPELINE_STAGE_2_TOP_OF_PIPE_BIT;
+ barrier.dstStageMask = VK_PIPELINE_STAGE_2_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT;
+ } else {
+ barrier.srcAccessMask = 0;
+ barrier.dstAccessMask = VK_ACCESS_2_MEMORY_READ_BIT | VK_ACCESS_2_MEMORY_WRITE_BIT;
+ barrier.srcStageMask = VK_PIPELINE_STAGE_2_TOP_OF_PIPE_BIT;
+ barrier.dstStageMask = VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT;
+ }
+
+ VkDependencyInfo dep = {
+ .sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO,
+ .pImageMemoryBarriers = &barrier,
+ .imageMemoryBarrierCount = 1,
+ };
+
+ texture->layout = new_layout;
+ vkCmdPipelineBarrier2(cmd, &dep);
+}
+
+extern void
+rend_vk_texture_copy_buffer(RendRenderer renderer, RendTexture *texture, RendBuffer *buffer)
+{
+ RendVk14Context *ctx = renderer->context;
+
+ VkCommandBuffer cmd_transfer = rend_vk_cmdbuffer_single_use_begin(ctx->upload_command_pool); {
+ rend_vk_texture_transition_layout(renderer, cmd_transfer, texture, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
+ VkBufferImageCopy region = {
+ .imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
+ .imageSubresource.layerCount = texture->layers,
+ .imageExtent = (VkExtent3D) { texture->width, texture->height, texture->depth },
+ };
+
+ vkCmdCopyBufferToImage(cmd_transfer, (VkBuffer) buffer->handle, (VkImage) texture->handle, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &region);
+ rend_vk_texture_transfer_ownership_release(renderer, cmd_transfer, texture, vk_device.transfer_family_index, vk_device.graphics_family_index, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
+ } rend_vk_cmdbuffer_single_use_end(ctx->upload_command_pool, cmd_transfer, vk_device.transfer_queue);
+
+ VkCommandBuffer cmd_graphics = rend_vk_cmdbuffer_single_use_begin(ctx->graphics_command_pool); {
+ rend_vk_texture_transfer_ownership_acquire(renderer, cmd_graphics, texture, vk_device.transfer_family_index, vk_device.graphics_family_index, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
+ } rend_vk_cmdbuffer_single_use_end(ctx->graphics_command_pool, cmd_graphics, vk_device.graphics_queue);
+}
+
+extern void
+rend_vk_texture_blit(RendRenderer renderer, RendTexture *src, RendTexture *dst, uint32_t src_x, uint32_t src_y, uint32_t src_w, uint32_t src_h, uint32_t dst_x, uint32_t dst_y, uint32_t dst_w, uint32_t dst_h)
+{
+
+ RendVk14Context *ctx = (RendVk14Context*) renderer->context;
+ VkCommandBuffer cmd = ctx->frame_resources[ctx->frame_index].command_buffer;
+
+ rend_vk_texture_transition_layout(renderer, cmd, src, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL);
+ rend_vk_texture_transition_layout(renderer, cmd, dst, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
+
+ VkImageBlit2 blit_region = {
+ .sType = VK_STRUCTURE_TYPE_IMAGE_BLIT_2,
+ .srcSubresource = {
+ .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
+ .mipLevel = 0,
+ .baseArrayLayer = 0,
+ .layerCount = 1,
+ },
+ .srcOffsets = {
+ { src_x, src_y, 0 },
+ { src_x + src_w, src_y + src_h, 1 }
+ },
+ .dstSubresource = {
+ .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
+ .mipLevel = 0,
+ .baseArrayLayer = 0,
+ .layerCount = 1,
+ },
+ .dstOffsets = {
+ { dst_x, dst_y, 0 },
+ { dst_x + dst_w, dst_y + dst_h, 1 }
+ }
+ };
+
+ VkBlitImageInfo2 blit_info = {
+ .sType = VK_STRUCTURE_TYPE_BLIT_IMAGE_INFO_2,
+ .srcImage = (VkImage) src->handle,
+ .srcImageLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
+ .dstImage = (VkImage) dst->handle,
+ .dstImageLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
+ .regionCount = 1,
+ .pRegions = &blit_region,
+
+ .filter = VK_FILTER_NEAREST // crispy
+ };
+
+ vkCmdBlitImage2(cmd, &blit_info);
+}
+
+static VkCommandBuffer
+rend_vk_cmdbuffer_single_use_begin(VkCommandPool pool)
+{
+ VkCommandBufferAllocateInfo alloc_info = {
+ .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
+ .level = VK_COMMAND_BUFFER_LEVEL_PRIMARY,
+ .commandPool = pool,
+ .commandBufferCount = 1,
+ };
+
+ VkCommandBuffer cmd;
+ vkAllocateCommandBuffers(vk_device.logical_device, &alloc_info, &cmd);
+
+ VkCommandBufferBeginInfo begin = {
+ .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
+ .flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT,
+ };
+
+ vkBeginCommandBuffer(cmd, &begin);
+
+ return cmd;
+}
+
+static void
+rend_vk_cmdbuffer_single_use_end(VkCommandPool pool, VkCommandBuffer cmd, VkQueue q)
+{
+ vkEndCommandBuffer(cmd);
+
+ VkSubmitInfo submit_info = {
+ .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO,
+ .commandBufferCount = 1,
+ .pCommandBuffers = &cmd,
+ };
+
+ vkQueueSubmit(q, 1, &submit_info, VK_NULL_HANDLE);
+ vkQueueWaitIdle(q);
+
+ vkFreeCommandBuffers(vk_device.logical_device, pool, 1, &cmd);
+}
+
+extern bool
+rend_vk_pipeline_create(RendRenderer renderer, RendPipeline pipeline, Rend__PipelineConfig config, uint8_t type, const uint8_t *shader1, size_t bytes1, const uint8_t *shader2, size_t bytes2, const uint8_t *shader3, size_t bytes3)
+{
+
+ RendVk14Context *ctx = (RendVk14Context *)renderer->context;
+ pipeline->idx = ctx->pipeline_count++;
+ pipeline->backend_ctx = ctx; // useful for when we only have RendPipeline as an argument
+
+ RendVkPipeline *vk_pipeline = &ctx->pipelines[pipeline->idx];
+ vk_pipeline->blend_enable = false;
+
+ /*
+ * set color and depth format
+ */
+ VkFormat color_format = (config.color_format != REND_FORMAT_UNDEFINED)
+ ? vk_format_from_rend_format[config.color_format]
+ : ctx->swapchain.format.format;
+
+ VkFormat depth_format = (config.depth_format != REND_FORMAT_UNDEFINED)
+ ? vk_format_from_rend_format[config.depth_format]
+ : vk_device.depth_format;
+
+ /*
+ * Pipeline Layout
+ */
+
+ vk_pipeline->push_constants_range = 0;
+ uint32_t total_size = 0;
+ for (uint32_t u = 0; u < config.push_constant_count; ++u) {
+ total_size += config.push_constants[u].size;
+ }
+
+ vk_pipeline->push_constants_range = total_size;
+
+ VkPushConstantRange pc_range = {
+ .offset = 0,
+ .size = total_size,
+ .stageFlags = VK_SHADER_STAGE_ALL,
+ };
+
+ VkPipelineLayoutCreateInfo layout_info = {
+ .sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
+ .pSetLayouts = &ctx->desc_layout,
+ .setLayoutCount = 1,
+ .pPushConstantRanges = (total_size > 0) ? &pc_range : NULL,
+ .pushConstantRangeCount = (total_size > 0) ? 1 : 0,
+ };
+
+ CHECK_VK_RESULT(vkCreatePipelineLayout(vk_device.logical_device, &layout_info, vk_allocator, &vk_pipeline->layout));
+
+ /*
+ * Setup shaders based on pipeline type
+ */
+ VkPipelineShaderStageCreateInfo shader_stages[3] = {0};
+ VkShaderModule shader_modules[3] = {0};
+ uint32_t shader_count = 0;
+
+ if (type == REND__PIPELINE_GRAPHICS) {
+ shader_count = 2;
+ shader_modules[0] = rend_vk_shader_module_create(shader1, bytes1);
+ shader_modules[1] = rend_vk_shader_module_create(shader2, bytes2);
+
+ shader_stages[0] = (VkPipelineShaderStageCreateInfo) {
+ .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
+ .stage = VK_SHADER_STAGE_VERTEX_BIT,
+ .module = shader_modules[0],
+ .pName = "main"
+ };
+
+ shader_stages[1] = (VkPipelineShaderStageCreateInfo) {
+ .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
+ .stage = VK_SHADER_STAGE_FRAGMENT_BIT,
+ .module = shader_modules[1],
+ .pName = "main",
+ };
+
+ } else if (type == REND__PIPELINE_MESH) {
+ shader_count = 2;
+ shader_modules[0] = rend_vk_shader_module_create(shader1, bytes1);
+ shader_modules[1] = rend_vk_shader_module_create(shader2, bytes2);
+
+ shader_stages[0] = (VkPipelineShaderStageCreateInfo) {
+ .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
+ .stage = VK_SHADER_STAGE_MESH_BIT_EXT,
+ .module = shader_modules[0],
+ .pName = "main"
+ };
+
+ shader_stages[1] = (VkPipelineShaderStageCreateInfo) {
+ .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
+ .stage = VK_SHADER_STAGE_FRAGMENT_BIT,
+ .module = shader_modules[1],
+ .pName = "main",
+ };
+
+ } else if (type == REND__PIPELINE_COMPUTE) {
+ shader_count = 1;
+ shader_modules[0] = rend_vk_shader_module_create(shader1, bytes1);
+
+ shader_stages[0] = (VkPipelineShaderStageCreateInfo) {
+ .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
+ .stage = VK_SHADER_STAGE_COMPUTE_BIT,
+ .module = shader_modules[0],
+ .pName = "main"
+ };
+ } else {
+ REND__CRASH("Invalid pipeline type");
+ }
+
+ /*
+ * Compute Pipeline Branch
+ */
+ if (type == REND__PIPELINE_COMPUTE) {
+ VkComputePipelineCreateInfo compute_pipeline_info = {
+ .sType = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO,
+ .stage = shader_stages[0],
+ .layout = vk_pipeline->layout,
+ .basePipelineHandle = VK_NULL_HANDLE,
+ .basePipelineIndex = -1,
+ };
+
+ CHECK_VK_RESULT(vkCreateComputePipelines(vk_device.logical_device, VK_NULL_HANDLE, 1, &compute_pipeline_info, vk_allocator, &vk_pipeline->handle));
+
+ PINFO("Successfully created compute pipeline!");
+ }
+ /*
+ * Graphics / Mesh Pipeline Branch
+ */
+ else {
+ VkPipelineRenderingCreateInfo rendering_info = {VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO};
+ rendering_info.colorAttachmentCount = 1;
+ rendering_info.pColorAttachmentFormats = &color_format;
+ rendering_info.depthAttachmentFormat = depth_format;
+
+ VkPipelineViewportStateCreateInfo viewport_state = {VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO};
+ viewport_state.viewportCount = 1;
+ viewport_state.scissorCount = 1;
+
+ VkPipelineRasterizationStateCreateInfo rasterizer = {VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO};
+ rasterizer.depthClampEnable = VK_FALSE;
+ rasterizer.rasterizerDiscardEnable = VK_FALSE;
+ rasterizer.polygonMode = vk_polymode[config.polygon_mode];
+ rasterizer.lineWidth = 1.0f;
+ rasterizer.cullMode = vk_cullflags[config.cull_mode];
+ rasterizer.frontFace = VK_FRONT_FACE_CLOCKWISE;
+ rasterizer.depthBiasEnable = VK_FALSE;
+
+ VkPipelineMultisampleStateCreateInfo multisampling = {VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO};
+ multisampling.sampleShadingEnable = VK_FALSE;
+ multisampling.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;
+
+ VkPipelineColorBlendAttachmentState color_blend_attachment = {0};
+ color_blend_attachment.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
+ color_blend_attachment.blendEnable = VK_FALSE;
+
+ VkPipelineColorBlendStateCreateInfo color_blending = { VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO};
+ color_blending.logicOpEnable = VK_FALSE;
+ color_blending.logicOp = VK_LOGIC_OP_COPY;
+ color_blending.attachmentCount = 1;
+ color_blending.pAttachments = &color_blend_attachment;
+
+ VkPipelineDepthStencilStateCreateInfo depth_stencil = { VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO};
+ depth_stencil.depthTestEnable = config.depth_test_enable;
+ depth_stencil.depthWriteEnable = VK_TRUE;
+ depth_stencil.depthCompareOp = VK_COMPARE_OP_LESS;
+ depth_stencil.depthBoundsTestEnable = VK_FALSE;
+ depth_stencil.stencilTestEnable = VK_FALSE;
+
+ VkDynamicState dynamic_states[] = {VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR};
+ VkPipelineDynamicStateCreateInfo dynamic_state = { VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO};
+ dynamic_state.dynamicStateCount = 2;
+ dynamic_state.pDynamicStates = dynamic_states;
+
+ VkPipelineVertexInputStateCreateInfo vertex_input_info = { VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO};
+ VkPipelineInputAssemblyStateCreateInfo input_assembly = {VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO};
+ VkVertexInputBindingDescription* vk_bindings = NULL;
+ VkVertexInputAttributeDescription* vk_attributes = NULL;
+
+ if (type == REND__PIPELINE_GRAPHICS) {
+ uint32_t binding_count = config.vertex_binding_count;
+ uint32_t attribute_count = config.vertex_attribute_count;
+
+ /*
+ * Bind Vertex Attributes
+ */
+ if (binding_count > 0) {
+ vk_bindings = rmalloc(sizeof(VkVertexInputBindingDescription) * binding_count);
+ for (uint32_t i = 0; i < binding_count; i++) {
+ RendVertexBinding rb = config.vertex_bindings[i];
+ vk_bindings[i].binding = rb.binding;
+ vk_bindings[i].stride = rb.stride;
+ vk_bindings[i].inputRate = (rb.input_rate == REND_INPUT_RATE_INSTANCE) ? VK_VERTEX_INPUT_RATE_INSTANCE : VK_VERTEX_INPUT_RATE_VERTEX;
+ }
+ }
+
+ if (attribute_count > 0) {
+ vk_attributes = rmalloc(sizeof(VkVertexInputAttributeDescription) * attribute_count);
+ for (uint32_t i = 0; i < attribute_count; i++) {
+ RendVertexAttributes ra = config.vertex_attributes[i];
+ vk_attributes[i].binding = ra.binding;
+ vk_attributes[i].location = ra.location;
+ vk_attributes[i].offset = ra.offset;
+ vk_attributes[i].format = vk_format_from_rend_format[ra.format];
+ }
+ }
+
+ vertex_input_info.vertexBindingDescriptionCount = binding_count;
+ vertex_input_info.pVertexBindingDescriptions = vk_bindings;
+ vertex_input_info.vertexAttributeDescriptionCount = attribute_count;
+ vertex_input_info.pVertexAttributeDescriptions = vk_attributes;
+
+ input_assembly.topology = vk_topology[config.topology];
+ input_assembly.primitiveRestartEnable = VK_FALSE;
+ }
+
+ VkGraphicsPipelineCreateInfo pipeline_info = { VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO};
+ pipeline_info.pNext = &rendering_info;
+ pipeline_info.stageCount = shader_count;
+ pipeline_info.pStages = shader_stages;
+ pipeline_info.pVertexInputState = &vertex_input_info;
+ pipeline_info.pInputAssemblyState = &input_assembly;
+ pipeline_info.pViewportState = &viewport_state;
+ pipeline_info.pRasterizationState = &rasterizer;
+ pipeline_info.pMultisampleState = &multisampling;
+ pipeline_info.pColorBlendState = &color_blending;
+ pipeline_info.pDepthStencilState = &depth_stencil;
+ pipeline_info.pDynamicState = &dynamic_state;
+ pipeline_info.layout = vk_pipeline->layout;
+ pipeline_info.renderPass = VK_NULL_HANDLE;
+
+ CHECK_VK_RESULT(vkCreateGraphicsPipelines(vk_device.logical_device, VK_NULL_HANDLE, 1, &pipeline_info, vk_allocator, &vk_pipeline->handle));
+
+ if (vk_bindings) rfree(vk_bindings);
+ if (vk_attributes) rfree(vk_attributes);
+
+ }
+
+ /* destroy shader modules */
+ for (uint32_t i = 0; i < shader_count; ++i) {
+ if (shader_modules[i] != VK_NULL_HANDLE) {
+ vkDestroyShaderModule(vk_device.logical_device, shader_modules[i], vk_allocator);
+ }
+ }
+
+ return true;
+}
+
+
+extern void
+rend_vk_pipeline_bind(RendPipeline pipeline)
+{
+ RendVk14Context *ctx = pipeline->backend_ctx;
+ RendVkPipeline vk_pipeline = ctx->pipelines[pipeline->idx];
+ VkCommandBuffer cmd = ctx->frame_resources[ctx->frame_index].command_buffer;
+ VkPipelineBindPoint bind_point = (pipeline->type == REND__PIPELINE_COMPUTE) ? VK_PIPELINE_BIND_POINT_COMPUTE : VK_PIPELINE_BIND_POINT_GRAPHICS;
+ vkCmdBindPipeline(cmd, bind_point, vk_pipeline.handle);
+ vkCmdBindDescriptorSets(cmd, bind_point, vk_pipeline.layout, 0, 1, &ctx->desc_set, 0, NULL);
+}
+
+extern void
+rend_vk_pipeline_push_constants(RendPipeline pipeline, void *push_data, size_t size)
+{
+ RASSERT(pipeline && push_data);
+
+ RendVk14Context *ctx = pipeline->backend_ctx;
+ RendVkPipeline p = ctx->pipelines[pipeline->idx];
+ RASSERT(size <= p.push_constants_range && "Size exceeds bound push constant range!");
+ vkCmdPushConstants(ctx->frame_resources[ctx->frame_index].command_buffer, p.layout, VK_SHADER_STAGE_ALL, 0, size, push_data);
+}
+
+extern void
+rend_vk_pipeline_bind_vertex_buffer(RendPipeline pipeline, uint32_t binding, RendBuffer buffer, size_t offset)
+{
+ RendVk14Context *ctx = pipeline->backend_ctx;
+ VkBuffer buf = (VkBuffer)(uintptr_t)buffer.handle;
+ VkCommandBuffer cmd = ctx->frame_resources[ctx->frame_index].command_buffer;
+
+ VkDeviceSize vk_offset = (VkDeviceSize)offset;
+ vkCmdBindVertexBuffers(cmd, binding, 1, &buf, &vk_offset);
+}
+
+extern void
+rend_vk_pipeline_bind_index_buffer(RendPipeline pipeline, RendBuffer buffer, size_t offset, RendIndexType index_type)
+{
+ RendVk14Context *ctx = pipeline->backend_ctx;
+ VkBuffer buf = (VkBuffer)(uintptr_t)buffer.handle;
+ VkCommandBuffer cmd = ctx->frame_resources[ctx->frame_index].command_buffer;
+
+ VkIndexType vk_index_type = (index_type == REND_INDEX_UINT16) ? VK_INDEX_TYPE_UINT16 : VK_INDEX_TYPE_UINT32;
+
+ vkCmdBindIndexBuffer(cmd, buf, (VkDeviceSize)offset, vk_index_type);
+}
+
+extern void
+rend_vk_descriptor_write_texture(void *ctx, RendTexture *texture, uint32_t binding, uint32_t slot)
+{
+ RendVk14Context *vk_ctx = (RendVk14Context*) ctx;
+
+ VkDescriptorImageInfo image_info = {
+ .sampler = (VkSampler) texture->sampler,
+ .imageView = (VkImageView) texture->view,
+ .imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
+ };
+
+ VkWriteDescriptorSet descriptor_write = {
+ .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
+ .dstSet = vk_ctx->desc_set,
+ .dstBinding = binding,
+ .dstArrayElement = slot, // write texture to slot
+ .descriptorCount = 1,
+ .descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
+ .pImageInfo = &image_info,
+ };
+
+ vkUpdateDescriptorSets(vk_device.logical_device, 1, &descriptor_write, 0, NULL);
+}
+
+extern void
+rend_vk_pipeline_dispatch(RendPipeline pipeline, uint32_t x, uint32_t y, uint32_t z)
+{
+ RendVk14Context *ctx = pipeline->backend_ctx;
+ VkCommandBuffer cmd = ctx->frame_resources[ctx->frame_index].command_buffer;
+ vkCmdDispatch(cmd, x, y, z);
+}
+
+extern void
+rend_vk_pipeline_draw(RendPipeline pipeline, size_t count, uint32_t instance_count)
+{
+ RendVk14Context *ctx = pipeline->backend_ctx;
+ VkCommandBuffer cmd = ctx->frame_resources[ctx->frame_index].command_buffer;
+ vkCmdDraw(cmd, count, instance_count, 0, 0);
+}
+
+extern void
+rend_vk_pipeline_draw_indexed(RendPipeline pipeline, uint32_t index_count, uint32_t first_index, int32_t vertex_offset, uint32_t instance_count)
+{
+ RendVk14Context *ctx = pipeline->backend_ctx;
+ VkCommandBuffer cmd = ctx->frame_resources[ctx->frame_index].command_buffer;
+ vkCmdDrawIndexed(cmd, index_count, instance_count, first_index, vertex_offset, 0);
+}
+
+extern void
+rend_vk_pipeline_set_blend(RendPipeline pipeline, bool blend)
+{
+ RendVk14Context *ctx = pipeline->backend_ctx;
+ RendVkPipeline *vk_pipeline = &ctx->pipelines[pipeline->idx];
+ vk_pipeline->blend_enable = blend;
+}
+
+extern void
+rend_vk_pipeline_draw_instanced(RendPipeline pipeline, uint32_t index_count, uint32_t instance_count)
+{
+ RendVk14Context *ctx = pipeline->backend_ctx;
+ VkCommandBuffer cmd = ctx->frame_resources[ctx->frame_index].command_buffer;
+ vkCmdDraw(cmd, index_count, instance_count, 0, 0);
+}
+
+extern VKAPI_ATTR VkBool32 VKAPI_CALL
+rend_vk_debug_func(VkDebugUtilsMessageSeverityFlagBitsEXT message_severity, VkDebugUtilsMessageTypeFlagsEXT message_types, const VkDebugUtilsMessengerCallbackDataEXT *callback_data, void *user_data)
+{
+ switch (message_severity) {
+ default:
+ case VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT:
+ PERROR(callback_data->pMessage);
+ break;
+ case VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT:
+ PWARN(callback_data->pMessage);
+ break;
+ case VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT:
+ PINFO(callback_data->pMessage);
+ break;
+ case VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT:
+ PTRACE(callback_data->pMessage);
+ break;
+ }
+ return VK_FALSE;
+}
+
+
+
+static void
+rend_vk_pipeline_destroy(RendVkPipeline *pipeline)
+{
+ VkDevice dev = vk_device.logical_device;
+
+ if (pipeline->handle != VK_NULL_HANDLE) {
+ vkDestroyPipeline(dev, pipeline->handle, vk_allocator);
+ }
+
+ if (pipeline->layout != VK_NULL_HANDLE) {
+ vkDestroyPipelineLayout(dev, pipeline->layout, vk_allocator);
+ }
+}
+
+static void
+rend_vk_swapchain_create(RendVk14Context *ctx, RendVkSwapchain *swapchain)
+{
+ RASSERT(ctx && "No context provided.");
+ RASSERT(swapchain && "No swapchain provided.");
+
+ VkSurfaceCapabilitiesKHR surface_caps;
+ vkGetPhysicalDeviceSurfaceCapabilitiesKHR(vk_device.physical_device, ctx->surface, &surface_caps);
+ uint32_t width = surface_caps.currentExtent.width;
+ uint32_t height = surface_caps.currentExtent.height;
+
+ VkExtent2D swapchain_extent = {width, height};
+
+ ctx->max_frames_in_flight = REND_MIN_FRAMES_IN_FLIGHT;
+
+ if (surface_caps.minImageCount > ctx->max_frames_in_flight) {
+ ctx->max_frames_in_flight = surface_caps.minImageCount;
+ }
+
+ if (surface_caps.maxImageCount < ctx->max_frames_in_flight) {
+ ctx->max_frames_in_flight = surface_caps.maxImageCount;
+ }
+
+ bool found = false;
+ for (uint32_t i = 0; i < vk_device.swapchain_support.format_count; i++) {
+ VkSurfaceFormatKHR format = vk_device.swapchain_support.format[i];
+
+ /* preferred format */
+ if (format.format == VK_FORMAT_B8G8R8A8_UNORM &&
+ format.colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) {
+ swapchain->format = format;
+ found = true;
+ break;
+ }
+ }
+
+ /* default format */
+ if (!found) {
+ swapchain->format = vk_device.swapchain_support.format[0];
+ }
+
+ /* NOTE: mailbox is probably the best for most applications
+ * but I may want the ability to pick a different mode in
+ * very niche circumstances.
+ *
+ * We also may want immediate mode if we want to disable VSYNC.
+ */
+
+ /* default present mode */
+ VkPresentModeKHR present_mode = VK_PRESENT_MODE_FIFO_KHR;
+ for (uint32_t i = 0; i < vk_device.swapchain_support.present_mode_count; i++) {
+ VkPresentModeKHR pres = vk_device.swapchain_support.present_modes[i];
+ /* preferred format is mailbox */
+ if (ctx->vsync) {
+ if (pres == VK_PRESENT_MODE_MAILBOX_KHR) {
+ present_mode = pres;
+ break;
+ }
+ } else {
+ if (pres == VK_PRESENT_MODE_IMMEDIATE_KHR) {
+ present_mode = pres;
+ break;
+ }
+ }
+ }
+
+#ifdef REND_DEBUG
+ static const char* present_mode_names[] = {
+ [VK_PRESENT_MODE_IMMEDIATE_KHR] = "IMMEDIATE",
+ [VK_PRESENT_MODE_MAILBOX_KHR] = "MAILBOX",
+ [VK_PRESENT_MODE_FIFO_KHR] = "FIFO",
+ [VK_PRESENT_MODE_FIFO_RELAXED_KHR] = "FIFO_RELAXED"
+ };
+ PDEBUG("Present mode %s was chosen!", present_mode_names[present_mode]);
+#endif
+
+ VkExtent2D min = surface_caps.minImageExtent;
+ VkExtent2D max = surface_caps.maxImageExtent;
+ swapchain_extent.width = (swapchain_extent.width < min.width) ? min.width : swapchain_extent.width;
+ swapchain_extent.width = (swapchain_extent.width > max.width) ? max.width : swapchain_extent.width;
+ swapchain_extent.height = (swapchain_extent.height < min.height) ? min.height : swapchain_extent.height;
+ swapchain_extent.height = (swapchain_extent.height > max.height) ? max.height : swapchain_extent.height;
+
+ uint32_t img_count = surface_caps.minImageCount + 1;
+ if (surface_caps.maxImageCount > 0 && img_count > surface_caps.maxImageCount) {
+ img_count = surface_caps.maxImageCount;
+ }
+
+ VkSwapchainCreateInfoKHR swapchain_create_info = { VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR};
+ swapchain_create_info.surface = ctx->surface;
+ swapchain_create_info.minImageCount = img_count;
+ swapchain_create_info.imageFormat = swapchain->format.format;
+ swapchain_create_info.imageColorSpace = swapchain->format.colorSpace;
+ swapchain_create_info.imageExtent = swapchain_extent;
+ swapchain_create_info.imageArrayLayers = 1;
+ swapchain_create_info.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
+
+ /* index sharing */
+ if (vk_device.graphics_family_index != vk_device.present_family_index) {
+ uint32_t queueFamilyIndices[] = {vk_device.graphics_family_index, vk_device.present_family_index};
+ swapchain_create_info.imageSharingMode = VK_SHARING_MODE_CONCURRENT;
+ swapchain_create_info.queueFamilyIndexCount = 2;
+ swapchain_create_info.pQueueFamilyIndices = queueFamilyIndices;
+ } else {
+ swapchain_create_info.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
+ swapchain_create_info.queueFamilyIndexCount = 0;
+ swapchain_create_info.pQueueFamilyIndices = 0;
+ }
+
+ swapchain_create_info.preTransform = surface_caps.currentTransform;
+ swapchain_create_info.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
+ swapchain_create_info.presentMode = present_mode;
+ swapchain_create_info.clipped = VK_TRUE;
+ swapchain_create_info.oldSwapchain = 0;
+
+ if (vkCreateSwapchainKHR(vk_device.logical_device, &swapchain_create_info, vk_allocator, &swapchain->handle) != VK_SUCCESS) {
+ REND__CRASH("Swapchain creation failed, you are probably trying to create two renderers for the same surface!");
+ }
+
+ swapchain->image_count = 0;
+ CHECK_VK_RESULT(vkGetSwapchainImagesKHR(vk_device.logical_device, swapchain->handle, &swapchain->image_count, 0));
+
+ if (!swapchain->images) {
+ swapchain->images = rmalloc(swapchain->image_count * sizeof *swapchain->images);
+ }
+ if (!swapchain->views) {
+ swapchain->views = rmalloc(swapchain->image_count * sizeof *swapchain->views);
+ }
+
+ CHECK_VK_RESULT( vkGetSwapchainImagesKHR(vk_device.logical_device, swapchain->handle, &swapchain->image_count, swapchain->images));
+
+ for (uint32_t i = 0; i < swapchain->image_count; i++) {
+
+ VkImageViewCreateInfo view_info = { VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO};
+ view_info.image = swapchain->images[i];
+ view_info.viewType = VK_IMAGE_VIEW_TYPE_2D;
+ view_info.format = swapchain->format.format;
+ view_info.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
+ view_info.subresourceRange.baseMipLevel = 0;
+ view_info.subresourceRange.levelCount = 1;
+ view_info.subresourceRange.baseArrayLayer = 0;
+ view_info.subresourceRange.layerCount = 1;
+
+ CHECK_VK_RESULT(vkCreateImageView(vk_device.logical_device, &view_info, vk_allocator, &swapchain->views[i]));
+ }
+
+ /* depth resources */
+ if (!rend_vk_device_detect_depth_format(&vk_device)) {
+ vk_device.depth_format = VK_FORMAT_UNDEFINED;
+ PFATAL("Failed to find a supported depth buffer format!");
+ }
+
+ swapchain->depth_attachment = rend_vk_image_create(
+ vk_device.logical_device,
+ VK_IMAGE_TYPE_2D,
+ swapchain_extent.width, swapchain_extent.height,
+ vk_device.depth_format,
+ VK_IMAGE_TILING_OPTIMAL,
+ VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT,
+ VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
+ 1, // depth
+ 1, // mip level
+ 1, // layers
+ VK_SAMPLE_COUNT_1_BIT,
+ VK_SHARING_MODE_EXCLUSIVE
+ );
+
+ uint32_t mem_type = rend_vk_image_required_memory_type(&swapchain->depth_attachment);
+ uint32_t depth_index = rend_vk_get_heap_index(mem_type, vk_device.device_index);
+
+ RASSERT(ctx);
+ RendMemory depth_mem = rend_vk_arena_alloc(&ctx->arena_persistent, swapchain->depth_attachment.requirements.size, depth_index);
+
+ rend_vk_image_bind_memory(&swapchain->depth_attachment, &depth_mem);
+
+ rend_vk_image_view_create(
+ &swapchain->depth_attachment,
+ VK_IMAGE_VIEW_TYPE_2D,
+ VK_IMAGE_ASPECT_DEPTH_BIT
+ );
+
+ swapchain->extent = swapchain_extent;
+
+}
+
+static void
+rend_vk_swapchain_destroy(RendVk14Context *ctx, RendVkSwapchain *swapchain)
+{
+ if (!swapchain || swapchain->handle == VK_NULL_HANDLE) return;
+ RASSERT(vk_device.logical_device);
+
+ rend_vk_image_destroy(&swapchain->depth_attachment);
+
+ if (swapchain->views) {
+ for (uint32_t i = 0; i < swapchain->image_count; i++) {
+ vkDestroyImageView(vk_device.logical_device, swapchain->views[i], vk_allocator);
+ }
+ rfree(swapchain->views);
+ swapchain->views = 0;
+ }
+
+ if (swapchain->images) {
+ rfree(swapchain->images);
+ swapchain->images = 0;
+ }
+
+ swapchain->image_count = 0;
+ vkDestroySwapchainKHR(vk_device.logical_device, swapchain->handle, vk_allocator);
+ swapchain->handle = VK_NULL_HANDLE;
+}
+
+static VkShaderModule
+rend_vk_shader_module_create(const void *data, size_t size)
+{
+
+ VkShaderModuleCreateInfo create_info = { VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO};
+ create_info.codeSize = size;
+ create_info.pCode = (const uint32_t *)data;
+
+ VkShaderModule module;
+ VkResult res = vkCreateShaderModule(vk_device.logical_device, &create_info, vk_allocator, &module);
+
+ if (res != VK_SUCCESS) {
+ PWARN("Failed to create shader module for %p", data);
+ return VK_NULL_HANDLE;
+ }
+
+ return module;
+}
+
+static uint32_t
+rend_vk_get_heap_index(uint32_t memory_type_bits, uint32_t preferred_index)
+{
+ if (memory_type_bits & (1u << preferred_index)) {
+ return preferred_index;
+ }
+
+ for (uint32_t i = 0; i < 32; i++) {
+ if (memory_type_bits & (1u << i)) {
+ return i;
+ }
+ }
+
+ return UINT32_MAX;
+}
diff --git a/Rend/rend_vk_allocator.c b/Rend/rend_vk_allocator.c
new file mode 100644
index 0000000..737e566
--- /dev/null
+++ b/Rend/rend_vk_allocator.c
@@ -0,0 +1,118 @@
+#pragma once
+#include "rend_internal.h"
+#include <stdint.h>
+#include <vulkan/vulkan.h>
+#include <vulkan/vulkan_core.h>
+
+typedef struct RendVkAllocatorState {
+ const char *name;
+} RendVkAllocatorState;
+
+typedef struct RendVkAllocatorHeader {
+ uint32_t offset;
+} RendVkAllocatorHeader;
+
+static bool rend_vk_allocator_is_power_of_two(uintptr_t x);
+static void *rend_vk_allocator_alloc(void *pUserData, size_t size, size_t alignment, VkSystemAllocationScope allocationScope);
+static void *rend_vk_allocator_realloc(void *pUserData, void *pOriginal, size_t size, size_t alignment, VkSystemAllocationScope allocationScope);
+static void rend_vk_allocator_free(void *pUserData, void *pMemory);
+static void rend_vk_allocator_internal_notification(void *pUserData, size_t size, VkInternalAllocationType allocationType, VkSystemAllocationScope allocationScope);
+static void rend_vk_allocator_free_notification(void *pUserData, size_t size, VkInternalAllocationType allocationType, VkSystemAllocationScope allocationScope);
+
+static VkAllocationCallbacks rend_vk_allocator = {
+ .pfnAllocation = rend_vk_allocator_alloc,
+ .pfnReallocation = rend_vk_allocator_realloc,
+ .pfnFree = rend_vk_allocator_free,
+ .pfnInternalAllocation = rend_vk_allocator_internal_notification,
+ .pfnInternalFree = rend_vk_allocator_free_notification,
+};
+
+static const char* rend_vk_allocator_scope_name[] = {
+ [VK_SYSTEM_ALLOCATION_SCOPE_CACHE] = "Cache",
+ [VK_SYSTEM_ALLOCATION_SCOPE_COMMAND] = "Command",
+ [VK_SYSTEM_ALLOCATION_SCOPE_DEVICE] = "Device",
+ [VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE] = "Instance",
+ [VK_SYSTEM_ALLOCATION_SCOPE_OBJECT] = "Object",
+};
+
+
+static bool
+rend_vk_allocator_is_power_of_two(uintptr_t x)
+{
+ return (x & (x-1)) == 0;
+}
+
+static uintptr_t
+rend_vk_allocator_align_forward(uintptr_t ptr, size_t align)
+{
+ uintptr_t p, a, modulo;
+
+ assert(rend_vk_allocator_is_power_of_two(align));
+
+ p = ptr;
+ a = (uintptr_t)align;
+ modulo = p & (a-1);
+
+ if (modulo != 0) {
+ p += a - modulo;
+ }
+ return p;
+}
+
+static void*
+rend_vk_allocator_alloc(void *pUserData, size_t size, size_t alignment, VkSystemAllocationScope allocationScope)
+{
+ size_t total_size = size + alignment + sizeof (RendVkAllocatorHeader);
+ uint8_t *raw_ptr = malloc(total_size);
+ uintptr_t unaligned_addr = (uintptr_t)(raw_ptr + sizeof (RendVkAllocatorHeader));
+
+ uint8_t *aligned_ptr = (uint8_t*)rend_vk_allocator_align_forward(unaligned_addr, alignment);
+ RendVkAllocatorHeader *header = (RendVkAllocatorHeader*) aligned_ptr - 1;
+ header->offset = aligned_ptr - raw_ptr;
+
+ PDEBUG("[VK_ALLOC] %p - bytes %lu with alignment %lu - scope %s",
+ aligned_ptr, size, alignment, rend_vk_allocator_scope_name[allocationScope]);
+
+ return (void*) aligned_ptr;
+}
+
+static void*
+rend_vk_allocator_realloc(void *pUserData, void *pOriginal, size_t size, size_t alignment, VkSystemAllocationScope allocationScope)
+{
+ if (!pOriginal) return rend_vk_allocator_alloc(pUserData, size, alignment, allocationScope);
+ if (size == 0) {
+ rend_vk_allocator_free(pUserData, pOriginal);
+ return NULL;
+ }
+ void *new_ptr = rend_vk_allocator_alloc(pUserData, size, alignment, allocationScope);
+ if (!new_ptr) return NULL;
+ memcpy(new_ptr, pOriginal, size);
+ rend_vk_allocator_free(pUserData, pOriginal);
+ return new_ptr;
+}
+
+static void
+rend_vk_allocator_free(void *pUserData, void *pMemory)
+{
+ RendVkAllocatorHeader *ptr = pMemory;
+ uint8_t *raw_ptr = pMemory;
+ raw_ptr -= (ptr-1)->offset;
+
+ PDEBUG("[VK_FREE] %p", ptr);
+ free(raw_ptr);
+}
+
+static void
+rend_vk_allocator_internal_notification(void *pUserData, size_t size, VkInternalAllocationType allocationType, VkSystemAllocationScope allocationScope)
+{
+ PDEBUG("[VK_ALLOC_INTERNAL] bytes %lu - scope %s",
+ size, rend_vk_allocator_scope_name[allocationScope]);
+
+}
+
+static void
+rend_vk_allocator_free_notification(void *pUserData, size_t size, VkInternalAllocationType allocationType, VkSystemAllocationScope allocationScope)
+{
+ PDEBUG("[VK_FREE_INTERNAL] bytes %lu - scope %s",
+ size, rend_vk_allocator_scope_name[allocationScope]);
+}
diff --git a/Rend/rend_vk_arena.c b/Rend/rend_vk_arena.c
new file mode 100644
index 0000000..b936be4
--- /dev/null
+++ b/Rend/rend_vk_arena.c
@@ -0,0 +1,264 @@
+#pragma once
+#include "rend_internal.h"
+#include "rend_vk_internal.h"
+#include <vulkan/vulkan_core.h>
+
+/* arenas need to be subdivided into blocks
+ * just like pools because we must respect page size */
+typedef struct RendVkPage {
+ RendMemory memory;
+ size_t head;
+ int reserved;
+} RendVkPage;
+
+typedef struct RendVkPagedArena {
+ RendVkPage *page_darr;
+ uint32_t capacity;
+ uint32_t elements;
+} RendVkPagedArena;
+
+struct RendVkArenaAllocator {
+ VkAllocationCallbacks *allocator;
+ size_t *heap_idx_alloc_sizes; // allocation size per type of memory available on the gpu
+ RendVkPagedArena *mem_arenas; // memory arena per type of memory available on the gpu
+ VkDevice logical_device; // virtual device
+ VkPhysicalDevice physical_device; // physical device we are allocating memory from
+ VkDeviceSize gpu_alignment; // allocations must respect the physical limitations of the gpu
+ VkDeviceSize block_min_size; // minimum size per block of memory
+ uint64_t total_allocations;
+ uint32_t heap_index_count;
+ VkPhysicalDeviceMemoryProperties properties; // useful for getting properties per heap index
+};
+
+static RendVkArenaAllocator
+rend_vk_arena_create(VkDevice logical_device, VkPhysicalDevice physical_device, VkPhysicalDeviceLimits device_limits, VkAllocationCallbacks *allocator)
+{
+ RendVkArenaAllocator arena = {
+ .allocator = allocator,
+ .heap_idx_alloc_sizes = NULL,
+ .logical_device = logical_device,
+ .physical_device = physical_device,
+ .gpu_alignment = 0,
+ .block_min_size = 0,
+ .total_allocations = 0,
+ .heap_index_count = 0,
+ .mem_arenas = 0,
+ };
+
+ VkPhysicalDeviceMemoryProperties mem_properties;
+ vkGetPhysicalDeviceMemoryProperties(physical_device, &mem_properties);
+ arena.properties = mem_properties;
+
+ uint32_t count = mem_properties.memoryTypeCount;
+ arena.heap_index_count = count;
+
+ arena.heap_idx_alloc_sizes = rmalloc(count * sizeof *arena.heap_idx_alloc_sizes);
+ memset(arena.heap_idx_alloc_sizes, 0, count * sizeof *arena.heap_idx_alloc_sizes);
+
+ arena.mem_arenas = rmalloc(count * sizeof *arena.mem_arenas);
+ for (uint32_t u = 0; u < count; ++u) {
+ arena.mem_arenas[u].capacity = 2;
+ arena.mem_arenas[u].elements = 0;
+ arena.mem_arenas[u].page_darr = rmalloc(2 * sizeof *arena.mem_arenas[u].page_darr);
+ memset(arena.mem_arenas[u].page_darr, 0, 2 * sizeof *arena.mem_arenas[u].page_darr);
+ }
+
+ VkDeviceSize alignment = device_limits.bufferImageGranularity;
+ if (device_limits.nonCoherentAtomSize > alignment) {
+ alignment = device_limits.nonCoherentAtomSize;
+ }
+
+ arena.gpu_alignment = alignment;
+ arena.block_min_size = arena.gpu_alignment * 10;
+
+ return arena;
+}
+
+static uint32_t
+rend_vk_arena_add_page(RendVkArenaAllocator *arena, VkDeviceSize size, uint32_t heap_index, bool fit_to_alloc)
+{
+ VkDeviceSize new_arena_size = fit_to_alloc ? size : (size * 2);
+ new_arena_size = (new_arena_size < arena->block_min_size) ? arena->block_min_size : new_arena_size;
+
+ VkMemoryPropertyFlags properties = arena->properties.memoryTypes[heap_index].propertyFlags;
+
+ RendVkPage page = (RendVkPage) {0};
+ page.head = 0;
+
+ VkMemoryAllocateFlagsInfo flags_info = {
+ .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_FLAGS_INFO,
+ .pNext = NULL,
+ .flags = VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT,
+ .deviceMask = 0
+ };
+
+ VkMemoryAllocateInfo alloc_info = {
+ .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
+ .allocationSize = new_arena_size,
+ .pNext = &flags_info,
+ .memoryTypeIndex = heap_index
+ };
+
+ page.memory = (RendMemory) {0};
+ page.memory.offset = 0;
+ page.memory.size = new_arena_size;
+
+ VkResult res = vkAllocateMemory(arena->logical_device, &alloc_info, arena->allocator, (VkDeviceMemory*) &page.memory.device_memory);
+ if (res != VK_SUCCESS) {
+ return UINT32_MAX;
+ }
+
+ if (properties & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) {
+ vkMapMemory(
+ arena->logical_device,
+ (VkDeviceMemory) page.memory.device_memory,
+ 0, // Offset inside VkDeviceMemory!!!1
+ new_arena_size, // MUST match alloc_info.allocationSize and NOT raw size!!!
+ 0,
+ &page.memory.host_mapped_memory
+ );
+ }
+
+ RendVkPagedArena *mem_arena = &arena->mem_arenas[heap_index];
+
+ if (mem_arena->elements + 1 >= mem_arena->capacity) {
+ uint32_t new_capacity = mem_arena->capacity * 2;
+ void *new_darr = rrealloc(mem_arena->page_darr, new_capacity * sizeof *mem_arena->page_darr);
+ if (!new_darr) {
+ vkFreeMemory(arena->logical_device, (VkDeviceMemory) page.memory.device_memory, arena->allocator);
+ return UINT32_MAX;
+ }
+ mem_arena->page_darr = new_darr;
+ mem_arena->capacity = new_capacity;
+ }
+
+ uint32_t page_index = mem_arena->elements;
+ mem_arena->page_darr[mem_arena->elements++] = page;
+
+ arena->total_allocations++;
+
+ return page_index;
+}
+
+static RendMemory
+rend_vk_arena_alloc(RendVkArenaAllocator *arena, VkDeviceSize size, uint32_t heap_index)
+{
+ assert(heap_index < 32 && "Unusual heap index. Did you pass the memory type instead?");
+ RendVkPagedArena *mem_arena = &arena->mem_arenas[heap_index];
+
+ VkMemoryPropertyFlags properties = arena->properties.memoryTypes[heap_index].propertyFlags;
+
+ /* align to allocation to fit page size */
+ VkDeviceSize align = arena->gpu_alignment;
+ VkDeviceSize aligned_size = (size + align - 1) & ~(align - 1);
+
+ /* check if fits in previous blocks */
+ int whole_page = !(properties & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
+ uint32_t page_idx = UINT32_MAX;
+ for (uint32_t u = 0; u < mem_arena->elements; ++u) {
+ RendVkPage page = mem_arena->page_darr[u];
+ int valid = (whole_page) ? (page.head == 0) : 1;
+ if ((page.head + aligned_size <= page.memory.size) && valid) {
+ page_idx = u;
+ break;
+ }
+ }
+
+ /* page not found, add new page */
+ if (page_idx == UINT32_MAX) {
+ page_idx = rend_vk_arena_add_page(arena, aligned_size, heap_index, whole_page);
+ if (page_idx == UINT32_MAX) {
+ REND__CRASH("[REND_VK] Arena page allocation failed!");
+ }
+ }
+
+ mem_arena->page_darr[page_idx].reserved = whole_page;
+
+ RendMemory memory = {
+ .device_memory = mem_arena->page_darr[page_idx].memory.device_memory,
+ .size = aligned_size,
+ .offset = mem_arena->page_darr[page_idx].head,
+ .host_mapped_memory = 0,
+ .heap_index = heap_index,
+ .id = page_idx,
+ };
+
+ if (properties & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) {
+ memory.host_mapped_memory = mem_arena->page_darr[page_idx].memory.host_mapped_memory + memory.offset;
+ }
+
+ /* move head */
+ arena->heap_idx_alloc_sizes[heap_index] += aligned_size;
+ mem_arena->page_darr[page_idx].head += aligned_size;
+ return memory;
+}
+
+
+static void
+rend_vk_arena_clear(RendVkArenaAllocator *arena, uint32_t heap_index)
+{
+ assert(heap_index < 32 && "Unusual heap index. Did you pass the memory type instead?");
+ RendVkPagedArena mem_arena = arena->mem_arenas[heap_index];
+ if (mem_arena.page_darr) {
+ for (uint32_t u = 0; u < mem_arena.elements; ++u) {
+ mem_arena.page_darr[u].head = 0;
+ mem_arena.page_darr[u].reserved = 0;
+ }
+ }
+}
+
+static void
+rend_vk_arena_clear_all(RendVkArenaAllocator *arena)
+{
+ for (uint32_t u = 0; u < arena->properties.memoryTypeCount; ++u) {
+ rend_vk_arena_clear(arena, u);
+ }
+}
+
+static void
+rend_vk_arena_shrink(RendVkArenaAllocator *arena, uint32_t heap_index)
+{
+ assert(heap_index < 32 && "Unusual heap index. Did you pass the memory type instead?");
+ RendVkPagedArena *mem_arena = &arena->mem_arenas[heap_index];
+ if (mem_arena->capacity > 4) {
+ uint32_t new_capacity = mem_arena->capacity / 2;
+ void *new_darr = rrealloc(mem_arena->page_darr, new_capacity * sizeof *mem_arena->page_darr);
+ if (!new_darr) return;
+ mem_arena->page_darr = new_darr;
+ mem_arena->capacity = new_capacity;
+ }
+}
+
+static void
+rend_vk_arena_destroy(RendVkArenaAllocator *arena)
+{
+ if (arena->mem_arenas) {
+ for (size_t u = 0; u < arena->heap_index_count; ++u) {
+ RendVkPagedArena *mem_arena = &arena->mem_arenas[u];
+ for (uint32_t p = 0; p < mem_arena->elements; ++p) {
+
+ RendMemory memory = mem_arena->page_darr[p].memory ;
+ if (memory.offset == 0) {
+ if (memory.host_mapped_memory) {
+ vkUnmapMemory(arena->logical_device, (VkDeviceMemory) memory.device_memory);
+ }
+ vkFreeMemory(arena->logical_device, (VkDeviceMemory) memory.device_memory, arena->allocator);
+ } else {
+ PWARN("[REND_VK] Attempted to free memory with an offset!");
+ }
+
+ }
+ if (mem_arena->page_darr) {
+ rfree(mem_arena->page_darr);
+ mem_arena->page_darr = 0;
+ }
+ }
+ rfree(arena->mem_arenas);
+ arena->mem_arenas = 0;
+ }
+ if (arena->heap_idx_alloc_sizes) {
+ rfree(arena->heap_idx_alloc_sizes);
+ arena->heap_idx_alloc_sizes = 0;
+ }
+ memset(arena, 0, sizeof *arena);
+}
diff --git a/Rend/rend_vk_device.c b/Rend/rend_vk_device.c
new file mode 100644
index 0000000..cb9f8f8
--- /dev/null
+++ b/Rend/rend_vk_device.c
@@ -0,0 +1,383 @@
+#pragma once
+#include "rend_internal.h"
+#include "rend_vk_internal.h"
+#include <vulkan/vulkan_core.h>
+
+// struct RendDevice {
+// bool anisotropy_support;
+// bool bindless_support;
+// };
+
+
+static bool
+rend_vk_device_create(VkSurfaceKHR surface, RendSpecs specs, RendVkDevice *out_device, uint32_t (*score_devices)(RendVkDevice *, RendSpecs, char **))
+{
+ assert(out_device);
+
+ uint32_t device_count = 0;
+ CHECK_VK_RESULT(vkEnumeratePhysicalDevices(vk_instance, &device_count, VK_NULL_HANDLE));
+ if (device_count == 0) {
+ PFATAL("No GPU with Vulkan support found!");
+ return false;
+ }
+
+ VkPhysicalDevice physical_devices[device_count];
+ CHECK_VK_RESULT(vkEnumeratePhysicalDevices(vk_instance, &device_count, physical_devices));
+
+ char **extension_names_darray = NULL;
+ p_darray_push(extension_names_darray, VK_KHR_SWAPCHAIN_EXTENSION_NAME);
+
+ uint32_t best_score = 1; // 1 so that devices that do not meet specs get ignored
+ RendVkDevice best_device = {0};
+
+ PDEBUG("DEVICE SCORE");
+ for (uint32_t i = 0; i < device_count; i++) {
+
+ /* populate device struct */
+ RendVkDevice scoring = {0};
+ scoring.surface = surface;
+ scoring.physical_device = physical_devices[i];
+ vkGetPhysicalDeviceProperties(physical_devices[i], &scoring.properties);
+ vkGetPhysicalDeviceFeatures(physical_devices[i], &scoring.features);
+ vkGetPhysicalDeviceMemoryProperties(physical_devices[i], &scoring.memory);
+
+ /* score device */
+ uint32_t dev_score = score_devices(&scoring, specs, extension_names_darray);
+ PDEBUG("%-20.20s %5d", scoring.properties.deviceName, dev_score);
+ if (dev_score >= best_score) {
+ if (best_device.swapchain_support.format) {
+ rfree(best_device.swapchain_support.format);
+ }
+ if (best_device.swapchain_support.present_modes) {
+ rfree(best_device.swapchain_support.present_modes);
+ }
+ best_score = dev_score;
+ best_device = scoring;
+ } else {
+ if (scoring.swapchain_support.format) {
+ rfree(scoring.swapchain_support.format);
+ }
+ if (scoring.swapchain_support.present_modes) {
+ rfree(scoring.swapchain_support.present_modes);
+ }
+ }
+
+ }
+
+ /* free extensions array after scoring */
+ p_darray_destroy(extension_names_darray);
+
+ if (best_score > 1) {
+ PDEBUG("Driver version %d.%d.%d", VK_VERSION_MAJOR(best_device.properties.driverVersion), VK_VERSION_MINOR(best_device.properties.driverVersion), VK_VERSION_PATCH(best_device.properties.driverVersion));
+ PDEBUG("Vulkan API version %d.%d.%d", VK_VERSION_MAJOR(best_device.properties.apiVersion), VK_VERSION_MINOR(best_device.properties.apiVersion), VK_VERSION_PATCH(best_device.properties.apiVersion));
+ }
+
+ if (!best_device.physical_device) {
+ PERROR("No physical devices were found that meet specs!");
+ return false;
+ }
+
+ /* update out device to use best selected device */
+ *out_device = best_device;
+
+ PDEBUG("Graphics Family Index: %u", out_device->graphics_family_index);
+ PDEBUG("Present Family Index: %u", out_device->present_family_index);
+ PDEBUG("Compute Family Index: %u", out_device->compute_family_index);
+ PDEBUG("Transfer Family Index: %u", out_device->transfer_family_index);
+
+ bool present_shares_graphics_q = out_device->present_family_index == out_device->graphics_family_index;
+ bool transfer_shares_graphics_q = out_device->transfer_family_index == out_device->graphics_family_index;
+
+ uint32_t index_count = 1;
+ if (!present_shares_graphics_q) index_count++;
+ if (!transfer_shares_graphics_q) index_count++;
+
+ uint32_t indices[index_count];
+ uint8_t index = 0;
+
+ indices[index++] = out_device->graphics_family_index;
+ if (!present_shares_graphics_q) {
+ indices[index++] = out_device->present_family_index;
+ }
+ if (!transfer_shares_graphics_q) {
+ indices[index++] = out_device->transfer_family_index;
+ }
+
+ VkDeviceQueueCreateInfo q_create_info[index_count];
+
+ f32 queue_priority[2] = {1.0f, 1.0f};
+ for (uint32_t i = 0; i < index_count; i++) {
+ q_create_info[i].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
+ q_create_info[i].queueFamilyIndex = indices[i];
+ // TODO: request 2 queues when possible
+ // q_create_info[i].queueCount = (indices[i] == out_device->graphics_family_index) ? 2 : 1;
+ q_create_info[i].queueCount = 1;
+ q_create_info[i].flags = 0;
+ q_create_info[i].pNext = 0;
+ q_create_info[i].pQueuePriorities = queue_priority;
+ }
+
+ // TODO: driven by the same config as the check_specs function
+ // used earlier
+
+ VkPhysicalDeviceFeatures device_features = {0};
+ device_features.samplerAnisotropy = specs.sampler_anisotropy;
+ device_features.fillModeNonSolid = VK_TRUE;
+ device_features.shaderInt64 = VK_TRUE;
+
+ // vulkan 1.3 features (dynamic rendering + sync2)
+ VkPhysicalDeviceVulkan13Features vk13_features = {0};
+ vk13_features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_3_FEATURES;
+ vk13_features.dynamicRendering = VK_TRUE;
+ vk13_features.synchronization2 = VK_TRUE;
+
+ // vulkan 1.2 features (timeline semaphores)
+ VkPhysicalDeviceVulkan12Features vk12_features = {0};
+ vk12_features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES;
+ vk12_features.timelineSemaphore = VK_TRUE;
+
+ // vk12_features.descriptorIndexing = VK_TRUE;
+ // vk12_features.descriptorBindingSampledImageUpdateAfterBind = VK_TRUE;
+ vk12_features.descriptorBindingPartiallyBound = VK_TRUE;
+ // vk12_features.descriptorBindingUniformBufferUpdateAfterBind = VK_TRUE;
+ // vk12_features.descriptorBindingVariableDescriptorCount = VK_TRUE;
+ // vk12_features.runtimeDescriptorArray = VK_TRUE;
+
+ vk12_features.bufferDeviceAddress = VK_TRUE;
+ vk12_features.scalarBlockLayout = VK_TRUE;
+ vk12_features.pNext = &vk13_features;
+
+ // vulkan 1.1 features (draw parameters)
+ VkPhysicalDeviceVulkan11Features vk11_features = {0};
+ vk11_features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_1_FEATURES;
+ vk11_features.shaderDrawParameters = VK_TRUE;
+ vk11_features.pNext = &vk12_features;
+
+ VkDeviceCreateInfo device_create_info = { VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO };
+ device_create_info.pNext = &vk11_features;
+ device_create_info.queueCreateInfoCount = index_count;
+ device_create_info.pQueueCreateInfos = q_create_info;
+ device_create_info.pEnabledFeatures = &device_features;
+ device_create_info.enabledExtensionCount = 1;
+
+ const char *extention_names = VK_KHR_SWAPCHAIN_EXTENSION_NAME;
+ device_create_info.ppEnabledExtensionNames = &extention_names;
+
+ /* deprecated and ignored */
+ device_create_info.enabledLayerCount = 0;
+ device_create_info.ppEnabledLayerNames = 0;
+
+ CHECK_VK_RESULT(vkCreateDevice(out_device->physical_device, &device_create_info, vk_allocator, &out_device->logical_device));
+
+ vkGetDeviceQueue(out_device->logical_device, out_device->graphics_family_index, 0, &out_device->graphics_queue);
+ vkGetDeviceQueue(out_device->logical_device, out_device->present_family_index, 0, &out_device->present_queue);
+ vkGetDeviceQueue(out_device->logical_device, out_device->transfer_family_index, 0, &out_device->transfer_queue);
+
+ PDEBUG("GRAPHICS | PRESENT | COMPUTE | TRANSFER | DEVICE");
+ PDEBUG(" %02d | %02d | %02d | %02d | %s",
+ out_device->graphics_family_index != UINT32_MAX,
+ out_device->present_family_index != UINT32_MAX,
+ out_device->compute_family_index != UINT32_MAX,
+ out_device->transfer_family_index != UINT32_MAX,
+ out_device->properties.deviceName);
+
+ VkPhysicalDeviceMemoryProperties mem_props = out_device->memory;
+ out_device->device_index = UINT32_MAX;
+ for (uint32_t i = 0; i < mem_props.memoryTypeCount; i++) {
+ if ((mem_props.memoryTypes[i].propertyFlags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) == VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) {
+ out_device->device_index = i;
+ break;
+ }
+ }
+
+ VkMemoryPropertyFlags host_flags = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT;
+ out_device->host_index = UINT32_MAX;
+ for (uint32_t i = 0; i < mem_props.memoryTypeCount; i++) {
+ if ((mem_props.memoryTypes[i].propertyFlags & host_flags) == host_flags) {
+ out_device->host_index = i;
+ break;
+ }
+ }
+
+ PDEBUG("Device local heap: %2u", out_device->device_index);
+ PDEBUG("Host mapped heap: %2u", out_device->host_index);
+ return true;
+}
+
+static void
+rend_vk_device_destroy(RendVkDevice *device)
+{
+ RASSERT(device && device->logical_device, "Invalid or uninitialized device.");
+
+ vkDeviceWaitIdle(device->logical_device); // safe when destroying device
+ vkDestroyDevice(device->logical_device, vk_allocator);
+ if (device->swapchain_support.format) rfree(vk_device.swapchain_support.format);
+ if (device->swapchain_support.present_modes) rfree(vk_device.swapchain_support.present_modes);
+
+ *device = (RendVkDevice){0};
+}
+
+static void
+rend_vk_device_query_swapchain_support(RendVkDevice *device)
+{
+ RASSERT(device->physical_device, "Invalid device pointer.");
+
+ /* surface capabilities */
+ CHECK_VK_RESULT(vkGetPhysicalDeviceSurfaceCapabilitiesKHR(device->physical_device, device->surface, &device->swapchain_support.capabilities));
+
+ /* surface formats */
+ CHECK_VK_RESULT(vkGetPhysicalDeviceSurfaceFormatsKHR(device->physical_device, device->surface, &device->swapchain_support.format_count, VK_NULL_HANDLE));
+ if (device->swapchain_support.format_count != 0) {
+ if (!device->swapchain_support.format) {
+ device->swapchain_support.format = rmalloc(device->swapchain_support.format_count * sizeof(*device->swapchain_support.format));
+ }
+ CHECK_VK_RESULT(vkGetPhysicalDeviceSurfaceFormatsKHR(device->physical_device, device->surface, &device->swapchain_support.format_count, device->swapchain_support.format));
+ }
+
+ /* present modes */
+ CHECK_VK_RESULT(vkGetPhysicalDeviceSurfacePresentModesKHR(device->physical_device, device->surface, &device->swapchain_support.present_mode_count, VK_NULL_HANDLE));
+ if (device->swapchain_support.present_mode_count != 0) {
+ if (!device->swapchain_support.present_modes) {
+ device->swapchain_support.present_modes = rmalloc(device->swapchain_support.present_mode_count * sizeof(*device->swapchain_support.present_modes));
+ }
+ CHECK_VK_RESULT(vkGetPhysicalDeviceSurfacePresentModesKHR(device->physical_device, device->surface, &device->swapchain_support.present_mode_count, device->swapchain_support.present_modes));
+ }
+}
+
+static bool
+rend_vk_device_detect_depth_format(RendVkDevice *device)
+{
+ const uint64_t candidate_count = 3;
+ VkFormat candidates[] = {VK_FORMAT_D32_SFLOAT, VK_FORMAT_D32_SFLOAT_S8_UINT, VK_FORMAT_D24_UNORM_S8_UINT};
+
+ uint32_t flags = VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT;
+ for (uint32_t i = 0; i < candidate_count; i++) {
+ VkFormatProperties properties;
+ vkGetPhysicalDeviceFormatProperties(device->physical_device, candidates[i], &properties);
+ if ((properties.linearTilingFeatures & flags) == flags) {
+ device->depth_format = candidates[i];
+ return true;
+ } else if ((properties.optimalTilingFeatures & flags) == flags) {
+ device->depth_format = candidates[i];
+ return true;
+ }
+ }
+
+ return false;
+}
+
+static uint32_t
+rend_vk_device_score_default(RendVkDevice *device, RendSpecs minimum_specs, char **required_extensions)
+{
+ /* NOTE: When we score the device we will also check for specs. Not meeting a spec
+ * leads to 0 score and continue. We will assume device already contains some information
+ * about properties when this function is called. */
+
+ uint32_t score = 0;
+
+ device->graphics_family_index = UINT32_MAX;
+ device->present_family_index = UINT32_MAX;
+ device->compute_family_index = UINT32_MAX;
+ device->transfer_family_index = UINT32_MAX;
+
+ if (minimum_specs.discrete_gpu) {
+ if (device->properties.deviceType != VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU) {
+ return 0;
+ }
+ }
+
+ uint32_t q_family_count = 0;
+ vkGetPhysicalDeviceQueueFamilyProperties(device->physical_device, &q_family_count, VK_NULL_HANDLE);
+
+ VkQueueFamilyProperties q_family[q_family_count];
+ vkGetPhysicalDeviceQueueFamilyProperties(device->physical_device, &q_family_count, q_family);
+
+ uint8_t min_transfer_score = 255;
+ for (uint32_t i = 0; i < q_family_count; i++) {
+
+ uint8_t transfer_score = 0;
+ if (q_family[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) {
+ device->graphics_family_index = i;
+ transfer_score++;
+ }
+
+ if (q_family[i].queueFlags & VK_QUEUE_COMPUTE_BIT) {
+ device->compute_family_index = i;
+ transfer_score++;
+ }
+
+ if (q_family[i].queueFlags & VK_QUEUE_TRANSFER_BIT) {
+ // take the index if the transfer score is minimal
+ if (transfer_score <= min_transfer_score) {
+ min_transfer_score = transfer_score;
+ device->transfer_family_index = i;
+ }
+ }
+
+ VkBool32 supports_present = VK_FALSE;
+ CHECK_VK_RESULT(vkGetPhysicalDeviceSurfaceSupportKHR(device->physical_device, i, device->surface, &supports_present));
+ if (supports_present) {
+ device->present_family_index = i;
+ }
+ }
+
+ if ( (minimum_specs.graphics && device->graphics_family_index == UINT32_MAX) ||
+ (minimum_specs.present && device->present_family_index == UINT32_MAX) ||
+ (minimum_specs.compute && device->compute_family_index == UINT32_MAX) ||
+ (minimum_specs.transfer && device->transfer_family_index == UINT32_MAX)) {
+ return 0;
+ }
+
+ // swapchain support
+ rend_vk_device_query_swapchain_support(device);
+
+ if (device->swapchain_support.format_count < 1 || device->swapchain_support.present_mode_count < 1) {
+ return 0;
+ }
+
+ // check for extension specs
+ if (required_extensions) {
+ uint32_t available_extentions_count = 0;
+ VkExtensionProperties *available_extentions = NULL;
+ CHECK_VK_RESULT(vkEnumerateDeviceExtensionProperties(device->physical_device, VK_NULL_HANDLE, &available_extentions_count, VK_NULL_HANDLE));
+
+ if (available_extentions_count != 0) {
+
+ available_extentions = rmalloc(available_extentions_count * sizeof(*available_extentions));
+ CHECK_VK_RESULT(vkEnumerateDeviceExtensionProperties(device->physical_device, VK_NULL_HANDLE, &available_extentions_count, available_extentions));
+
+ uint32_t required_extention_count = p_darray_len(required_extensions);
+
+ bool overall_found = true;
+ for (uint32_t i = 0; i < required_extention_count; ++i) {
+ bool found = false;
+ for (uint32_t j = 0; j < available_extentions_count; ++j) {
+ if (strcmp(required_extensions[i], available_extentions[j].extensionName) == 0) {
+ found = true;
+ break;
+ }
+ }
+ if (!found) {
+ overall_found = false;
+ break;
+ }
+ }
+
+ rfree(available_extentions);
+ if (!overall_found) {
+ return 0;
+ }
+ }
+ }
+
+ if (minimum_specs.sampler_anisotropy && !device->features.samplerAnisotropy) {
+ return 0;
+ }
+
+ score = 10;
+ if (device->properties.deviceType == VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU) {
+ score += 1000;
+ }
+
+ return score;
+}
diff --git a/Rend/rend_vk_image.c b/Rend/rend_vk_image.c
new file mode 100644
index 0000000..e842bf0
--- /dev/null
+++ b/Rend/rend_vk_image.c
@@ -0,0 +1,125 @@
+#pragma once
+#include "rend_internal.h"
+#include "rend_vk_internal.h"
+#include <vulkan/vulkan_core.h>
+
+struct RendVkImage {
+ VkDevice logical_device;
+ VkImage handle;
+ VkImageView view;
+
+ VkMemoryRequirements requirements;
+
+ VkImageType img_type;
+ uint32_t width, height;
+ VkFormat format;
+ VkImageTiling tiling;
+ VkImageUsageFlags usage;
+ uint32_t depth;
+ uint32_t mip_levels;
+ uint32_t layers;
+ VkSampleCountFlags sample_count_flags;
+ VkSharingMode sharing_mode;
+
+ RendMemory *memory;
+};
+
+static RendVkImage
+rend_vk_image_create(VkDevice logical_device, VkImageType img_type, uint32_t width, uint32_t height, VkFormat format, VkImageTiling tiling,
+ VkImageUsageFlags usage, VkMemoryPropertyFlags memory_flags, uint32_t depth, uint32_t mip_levels, uint32_t layers,
+ VkSampleCountFlags sample_count_flags, VkSharingMode sharing_mode)
+{
+ RendVkImage image = {
+ .handle = VK_NULL_HANDLE,
+ .memory = VK_NULL_HANDLE,
+ .logical_device = logical_device,
+ .img_type = img_type,
+ .width = width,
+ .height = height,
+ .format = format,
+ .tiling = tiling,
+ .usage = usage,
+ .depth = depth,
+ .mip_levels = mip_levels,
+ .layers = layers,
+ .sample_count_flags = sample_count_flags,
+ .sharing_mode = sharing_mode
+ };
+
+ VkImageCreateInfo img_create_info = {VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO};
+ img_create_info.imageType = img_type;
+ img_create_info.extent.width = width;
+ img_create_info.extent.height = height;
+ img_create_info.extent.depth = depth;
+ img_create_info.mipLevels = mip_levels;
+ img_create_info.arrayLayers = layers;
+ img_create_info.format = format;
+ img_create_info.tiling = tiling;
+ img_create_info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
+ img_create_info.usage = usage;
+ img_create_info.samples = sample_count_flags;
+ img_create_info.sharingMode = sharing_mode;
+
+
+ if (vkCreateImage(logical_device, &img_create_info, vk_allocator, &image.handle) != VK_SUCCESS) {
+ return image;
+ }
+
+ return image;
+}
+
+static uint32_t
+rend_vk_image_required_memory_type(RendVkImage *img)
+{
+ assert(img->memory == NULL && "Image already bound to memory");
+ VkMemoryRequirements memory_requirements = {0};
+ vkGetImageMemoryRequirements(img->logical_device, img->handle, &memory_requirements);
+ img->requirements = memory_requirements;
+ return memory_requirements.memoryTypeBits;
+}
+
+static void
+rend_vk_image_bind_memory(RendVkImage *img, RendMemory *memory)
+{
+ assert(img->memory == NULL && "Image already bound to memory");
+ vkBindImageMemory(img->logical_device, img->handle, (VkDeviceMemory) memory->device_memory, memory->offset);
+}
+
+static void
+rend_vk_image_destroy(RendVkImage *img)
+{
+ if (img->view) {
+ vkDestroyImageView(img->logical_device, img->view, vk_allocator);
+ img->view = 0;
+ }
+
+ if (img->handle) {
+ vkDestroyImage(img->logical_device, img->handle, vk_allocator);
+ img->handle = 0;
+ }
+}
+
+static void
+rend_vk_image_view_create(RendVkImage *image, VkImageViewType view_type, VkImageAspectFlags view_aspect_flags)
+{
+ VkImageViewCreateInfo view_create_info = {
+ .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
+ .image = image->handle,
+ .format = image->format,
+ .viewType = view_type,
+ .subresourceRange.aspectMask = view_aspect_flags,
+ .subresourceRange.baseMipLevel = 0, // offset starts at 0
+ .subresourceRange.levelCount = image->mip_levels, // number of mips
+ .subresourceRange.baseArrayLayer = 0, // offset starts at 0
+ .subresourceRange.layerCount = image->layers, // number of layers
+ };
+
+ vkCreateImageView(image->logical_device, &view_create_info, vk_allocator, &image->view);
+}
+
+static uint64_t
+rend_vk_image_address(RendVkImage *image)
+{
+ assert(image->memory == NULL && "Image already bound to memory");
+ return (uint64_t) image->memory->device_memory + image->memory->offset;
+}
diff --git a/Rend/rend_vk_internal.h b/Rend/rend_vk_internal.h
new file mode 100644
index 0000000..5039c61
--- /dev/null
+++ b/Rend/rend_vk_internal.h
@@ -0,0 +1,177 @@
+#ifndef REND_VK_INTERNAL_H
+#define REND_VK_INTERNAL_H
+
+#include <vulkan/vulkan.h>
+#include <vulkan/vulkan_core.h>
+#include <assert.h>
+
+#define CHECK_VK_RESULT(r) \
+{ \
+ assert(r == VK_SUCCESS && __LINE__); \
+}
+
+
+typedef struct RendVkImage RendVkImage;
+typedef struct RendVkArenaAllocator RendVkArenaAllocator;
+typedef struct RendVkSbta RendVkSbta;
+
+typedef struct RendVkPendingCmd RendVkPendingCmd;
+typedef struct RendVkDeferredCmds RendVkDeferredCmds;
+
+typedef struct {
+ const char **extention_names_darray;
+ bool sampler_anisotropy;
+ bool discrete_gpu;
+ bool graphics;
+ bool present;
+ bool compute;
+ bool transfer;
+} RendVkDevicespecs;
+
+typedef struct {
+ uint32_t graphics_family_index;
+ uint32_t present_family_index;
+ uint32_t compute_family_index;
+ uint32_t transfer_family_index;
+} RendVkQueueFamily;
+
+typedef struct {
+ VkSurfaceCapabilitiesKHR capabilities;
+ VkSurfaceFormatKHR *format;
+ VkPresentModeKHR *present_modes;
+ uint32_t format_count;
+ uint32_t present_mode_count;
+} RendVkSwapchainSupport;
+
+typedef struct {
+ /* logical device handle */
+ VkDevice logical_device;
+
+ /* physical device limitation */
+ VkPhysicalDeviceProperties properties;
+ VkPhysicalDeviceMemoryProperties memory;
+ VkPhysicalDevice physical_device;
+ VkPhysicalDeviceFeatures features;
+ VkPhysicalDeviceDescriptorBufferPropertiesEXT desc_props;
+
+ /* swapchain support */
+ VkSurfaceKHR surface;
+ RendVkSwapchainSupport swapchain_support;
+ VkFormat depth_format;
+
+ /* queues */
+ VkQueue graphics_queue;
+ VkQueue present_queue;
+ VkQueue compute_queue;
+ VkQueue transfer_queue;
+ uint32_t graphics_family_index;
+ uint32_t present_family_index;
+ uint32_t compute_family_index;
+ uint32_t transfer_family_index;
+
+ /* memory heap indices */
+ uint32_t host_index;
+ uint32_t device_index;
+} RendVkDevice;
+
+static VkInstance vk_instance = 0;
+static VkDebugUtilsMessengerEXT vk_debug_messenger = 0;
+static RendVkDevice vk_device = {0};
+
+/* helper functions */
+static int32_t rend_vk_memory_find_index(VkPhysicalDevice device, uint32_t type_filter, VkMemoryPropertyFlags property_flags);
+
+/* rend_vk_device.c */
+static bool rend_vk_device_create(VkSurfaceKHR surface, RendSpecs specs, RendVkDevice *out_device, uint32_t (*score_devices)(RendVkDevice *, RendSpecs, char **));
+static uint32_t rend_vk_device_score_default(RendVkDevice *device, RendSpecs minimum_specs, char **required_extensions);
+static void rend_vk_physical_device_query_swapchain_support(RendVkDevice *device);
+static bool rend_vk_device_detect_depth_format(RendVkDevice *device);
+static void rend_vk_device_destroy(RendVkDevice *device);
+
+/* rend_vk_arena.c */
+static RendVkArenaAllocator rend_vk_arena_create(VkDevice logical_device, VkPhysicalDevice physical_device, VkPhysicalDeviceLimits device_limits, VkAllocationCallbacks *allocator);
+static uint32_t rend_vk_arena_add_page(RendVkArenaAllocator *arena, VkDeviceSize size, uint32_t heap_index, bool fit_to_alloc);
+static RendMemory rend_vk_arena_alloc(RendVkArenaAllocator *arena, VkDeviceSize size, uint32_t heap_index);
+static void rend_vk_arena_clear(RendVkArenaAllocator *arena, uint32_t memory_type);
+static void rend_vk_arena_clear_all(RendVkArenaAllocator *arena);
+static void rend_vk_arena_shrink(RendVkArenaAllocator *arena, uint32_t memory_type);
+static void rend_vk_arena_destroy(RendVkArenaAllocator *arena);
+
+/* rend_vk_command_queue.c */
+static inline RendVkDeferredCmds rend_vk_cmdbuf_deferred_create(void);
+static inline void rend_vk_cmdbuf_deferred_destroy(RendVkDeferredCmds *tracker);
+static inline uint64_t rend_vk_cmdbuf_deferred_submit(RendVkDeferredCmds *tracker, VkCommandPool pool, VkCommandBuffer cmd, VkQueue queue, uint64_t wait_value, VkPipelineStageFlags2 wait_stage, VkPipelineStageFlags2 signal_stage);
+static inline void rend_vk_cmdbuf_deferred_push(RendVkDeferredCmds *tracker, VkCommandPool pool, VkCommandBuffer cmd, uint64_t wait_value);
+static inline void rend_vk_cmdbuf_deferred_flush(RendVkDeferredCmds *tracker);
+
+/* rend_vk_image.c */
+static RendVkImage rend_vk_image_create(VkDevice logical_device, VkImageType img_type, uint32_t width, uint32_t height, VkFormat format, VkImageTiling tiling, VkImageUsageFlags usage, VkMemoryPropertyFlags memory_flags, uint32_t depth, uint32_t mip_levels, uint32_t layers, VkSampleCountFlags sample_count_flags, VkSharingMode sharing_mode);
+static uint32_t rend_vk_image_required_memory_type(RendVkImage *img);
+static void rend_vk_image_bind_memory(RendVkImage *image, RendMemory *memory);
+static void rend_vk_image_destroy(RendVkImage *img);
+static void rend_vk_image_view_create(RendVkImage *image, VkImageViewType view_type, VkImageAspectFlags view_aspect_flags);
+static uint64_t rend_vk_image_address(RendVkImage *image);
+
+
+static VkAllocationCallbacks *vk_allocator = 0; // we are only ever going to use one, either the default one or the custom one
+
+static VkFormat vk_format_from_rend_format[] = {
+ [REND_FORMAT_R8_UNORM] = VK_FORMAT_R8_UNORM,
+ [REND_FORMAT_R8G8_UNORM] = VK_FORMAT_R8G8_UNORM,
+ [REND_FORMAT_R8G8B8A8_UNORM] = VK_FORMAT_R8G8B8A8_UNORM,
+ [REND_FORMAT_B8G8R8A8_UNORM] = VK_FORMAT_B8G8R8A8_UNORM,
+ [REND_FORMAT_R8G8B8A8_SRGB] = VK_FORMAT_R8G8B8A8_SRGB,
+ [REND_FORMAT_B8G8R8A8_SRGB] = VK_FORMAT_B8G8R8A8_SRGB,
+ [REND_FORMAT_R32_SFLOAT] = VK_FORMAT_R32_SFLOAT,
+ [REND_FORMAT_R32G32_SFLOAT] = VK_FORMAT_R32G32_SFLOAT,
+ [REND_FORMAT_R32G32B32_SFLOAT] = VK_FORMAT_R32G32B32_SFLOAT,
+ [REND_FORMAT_R32G32B32A32_SFLOAT]= VK_FORMAT_R32G32B32A32_SFLOAT,
+ [REND_FORMAT_R16_SFLOAT] = VK_FORMAT_R16_SFLOAT,
+ [REND_FORMAT_R16G16_SFLOAT] = VK_FORMAT_R16G16_SFLOAT,
+ [REND_FORMAT_R16G16B16A16_SFLOAT]= VK_FORMAT_R16G16B16A16_SFLOAT,
+ [REND_FORMAT_R32_UINT] = VK_FORMAT_R32_UINT,
+ [REND_FORMAT_R32_SINT] = VK_FORMAT_R32_SINT,
+ [REND_FORMAT_R32G32B32A32_UINT] = VK_FORMAT_R32G32B32A32_UINT,
+ [REND_FORMAT_R16G16B16A16_UINT] = VK_FORMAT_R16G16B16A16_UINT,
+ [REND_FORMAT_R8G8B8A8_UINT] = VK_FORMAT_R8G8B8A8_UINT,
+ [REND_FORMAT_D32_SFLOAT] = VK_FORMAT_D32_SFLOAT,
+ [REND_FORMAT_D24_UNORM_S8_UINT] = VK_FORMAT_D24_UNORM_S8_UINT,
+ [REND_FORMAT_D32_SFLOAT_S8_UINT] = VK_FORMAT_D32_SFLOAT_S8_UINT,
+};
+
+static VkPrimitiveTopology vk_topology[] = {
+ [REND_TOPOLOGY_TRIANGLE_LIST] = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST,
+ [REND_TOPOLOGY_TRIANGLE_STRIP] = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP,
+ [REND_TOPOLOGY_LINE_LIST] = VK_PRIMITIVE_TOPOLOGY_LINE_LIST,
+ [REND_TOPOLOGY_LINE_STRIP] = VK_PRIMITIVE_TOPOLOGY_LINE_STRIP,
+ [REND_TOPOLOGY_POINT_LIST] = VK_PRIMITIVE_TOPOLOGY_POINT_LIST
+};
+
+static VkPolygonMode vk_polymode[] = {
+ [REND_POLYGON_MODE_FILL] = VK_POLYGON_MODE_FILL,
+ [REND_POLYGON_MODE_LINE] = VK_POLYGON_MODE_LINE,
+ [REND_POLYGON_MODE_POINT] = VK_POLYGON_MODE_POINT,
+};
+
+static VkCullModeFlags vk_cullflags[] = {
+ [REND_CULL_MODE_NONE] = VK_CULL_MODE_NONE,
+ [REND_CULL_MODE_FRONT] = VK_CULL_MODE_FRONT_BIT,
+ [REND_CULL_MODE_BACK] = VK_CULL_MODE_BACK_BIT,
+ [REND_CULL_MODE_FRONT_AND_BACK] = VK_CULL_MODE_FRONT_AND_BACK,
+};
+
+static int32_t
+rend_vk_memory_find_index(VkPhysicalDevice device, uint32_t type_filter, VkMemoryPropertyFlags property_flags)
+{
+ VkPhysicalDeviceMemoryProperties memory_properties;
+ vkGetPhysicalDeviceMemoryProperties(device, &memory_properties);
+ for (uint32_t i = 0; i < memory_properties.memoryTypeCount; i++) {
+ if (type_filter & (1 << i) && (memory_properties.memoryTypes[i].propertyFlags & property_flags) == property_flags) {
+ return i;
+ }
+ }
+
+ return -1;
+}
+
+#endif
diff --git a/Rend/unused code/rend_vk_buffer.c b/Rend/unused code/rend_vk_buffer.c
new file mode 100644
index 0000000..37f3e06
--- /dev/null
+++ b/Rend/unused code/rend_vk_buffer.c
@@ -0,0 +1,116 @@
+#pragma once
+#include "rend_internal.h"
+#include "rend_vk_internal.h"
+#include <vulkan/vulkan_core.h>
+
+#if 0
+static RendBuffer
+rend_vk_buffer_create(VkDevice logical_device, VkAllocationCallbacks *allocator, VkDeviceSize size, VkBufferUsageFlags usage, uint32_t *family_indices, uint32_t family_indices_count)
+{
+ RendBuffer buffer = {
+ .handle = 0,
+ .logical_device = logical_device,
+ .memory = NULL,
+ .allocator = allocator,
+ .usage = usage | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT,
+ };
+
+ VkBufferCreateInfo buffer_info = {
+ .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
+ .size = size,
+ .usage = usage,
+ .sharingMode = (family_indices_count > 1) ? VK_SHARING_MODE_CONCURRENT : VK_SHARING_MODE_EXCLUSIVE,
+ .queueFamilyIndexCount = family_indices_count,
+ .pQueueFamilyIndices = family_indices
+ };
+
+ vkCreateBuffer(logical_device, &buffer_info, allocator, &buffer.handle);
+ return buffer;
+}
+
+static uint32_t
+rend_vk_buffer_required_memory_type(RendBuffer *buffer)
+{
+ assert(buffer->memory == NULL && "Buffer already bound to memory");
+ VkMemoryRequirements mem_requirements;
+ vkGetBufferMemoryRequirements(buffer->logical_device, buffer->handle, &mem_requirements);
+ return mem_requirements.memoryTypeBits;
+}
+
+static void
+rend_vk_buffer_bind_memory(RendBuffer *buffer, RendVkMemory *memory)
+{
+ assert(buffer->memory == NULL && "Buffer already bound to memory");
+ vkBindBufferMemory(buffer->logical_device, buffer->handle, memory->device_memory, 0);
+ buffer->memory = memory;
+}
+
+static void
+rend_vk_buffer_destroy(RendBuffer *buffer)
+{
+ assert(buffer && buffer->handle != 0);
+ vkDestroyBuffer(buffer->logical_device, buffer->handle, buffer->allocator);
+ buffer->handle = 0;
+ buffer->memory = 0;
+}
+
+static void
+rend_vk_buffer_copy_device(VkQueue queue, VkCommandPool pool, RendBuffer *dest, size_t dest_offset, size_t bytes, RendBuffer *src, size_t src_offset, VkFence fence)
+{
+ assert(src && dest); // check that im not sending null pointers
+ assert(src->usage & VK_BUFFER_USAGE_TRANSFER_SRC_BIT); // source buffer must be marked as transfer src
+ assert(dest->usage & VK_BUFFER_USAGE_TRANSFER_DST_BIT); // dest buffer must be marked as transfer dest
+
+ VkCommandBuffer transfer_cmd = VK_NULL_HANDLE;
+
+ VkCommandBufferAllocateInfo alloc_info = {
+ .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
+ .commandBufferCount = 1,
+ .commandPool = pool,
+ .level = VK_COMMAND_BUFFER_LEVEL_PRIMARY,
+ .pNext = NULL,
+ };
+
+ vkAllocateCommandBuffers(dest->logical_device, &alloc_info, &transfer_cmd);
+
+ VkCommandBufferBeginInfo begin_info = {
+ .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
+ .flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT,
+ };
+ vkBeginCommandBuffer(transfer_cmd, &begin_info);
+
+ VkBufferCopy buffer_copy = {
+ .srcOffset = (VkDeviceSize)src_offset,
+ .dstOffset = (VkDeviceSize)dest_offset,
+ .size = (VkDeviceSize)bytes,
+ };
+
+ vkCmdCopyBuffer(transfer_cmd, src->handle, dest->handle, 1, &buffer_copy);
+ vkEndCommandBuffer(transfer_cmd);
+
+ VkCommandBufferSubmitInfo cmd_info = {
+ .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_SUBMIT_INFO,
+ .commandBuffer = transfer_cmd,
+ .deviceMask = 0,
+ };
+
+ VkSubmitInfo2 submit_info = {
+ .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO_2,
+ .commandBufferInfoCount = 1,
+ .pCommandBufferInfos = &cmd_info,
+ };
+
+ vkQueueSubmit2(queue, 1, &submit_info, fence);
+ vkQueueWaitIdle(queue);
+ vkFreeCommandBuffers(dest->logical_device, pool, 1, &transfer_cmd);
+}
+
+static uint64_t
+rend_vk_buffer_address(RendBuffer *buffer, VkDevice device)
+{
+ VkBufferDeviceAddressInfoKHR address_info = {VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO_KHR};
+ address_info.buffer = buffer->handle;
+ VkDeviceAddress address = vkGetBufferDeviceAddress(device, &address_info);
+ return (uint64_t) address;
+}
+#endif
diff --git a/Rend/unused code/rend_vk_command_queue.c b/Rend/unused code/rend_vk_command_queue.c
new file mode 100644
index 0000000..1ddd780
--- /dev/null
+++ b/Rend/unused code/rend_vk_command_queue.c
@@ -0,0 +1,153 @@
+#pragma once
+#include "rend_internal.h"
+#include "rend_vk_internal.h"
+#include <vulkan/vulkan_core.h>
+#include <stdatomic.h>
+#include <stdlib.h>
+
+/* DEFERRED COMMANDS:
+ * Tracks single-use command buffers submitted for async GPU work,
+ * so callers don't have to block (vkQueueWaitIdle) to know when it's
+ * safe to free/reset them. One shared timeline semaphore; every
+ * submission claims the next monotonic value.
+ */
+
+struct RendVkPendingCmd {
+ VkCommandPool pool;
+ VkCommandBuffer cmd;
+ uint64_t wait_value;
+};
+
+struct RendVkDeferredCmds {
+ VkSemaphore timeline;
+ RendVkPendingCmd *darray;
+ size_t count;
+ size_t capacity;
+};
+
+#define RENDER_VK_DEFERRED_CMDS_INITIAL_CAPACITY 16
+
+static inline RendVkDeferredCmds
+rend_vk_cmdbuf_deferred_create(void)
+{
+ RendVkDeferredCmds tracker = {0};
+
+ VkSemaphoreTypeCreateInfo type_info = {
+ .sType = VK_STRUCTURE_TYPE_SEMAPHORE_TYPE_CREATE_INFO,
+ .semaphoreType = VK_SEMAPHORE_TYPE_TIMELINE,
+ .initialValue = 0,
+ };
+ VkSemaphoreCreateInfo sem_info = {
+ .sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO,
+ .pNext = &type_info,
+ };
+ vkCreateSemaphore(vk_device.logical_device, &sem_info, vk_allocator, &tracker.timeline);
+
+ tracker.capacity = RENDER_VK_DEFERRED_CMDS_INITIAL_CAPACITY;
+ tracker.darray = rmalloc(sizeof(RendVkPendingCmd) * tracker.capacity);
+ tracker.count = 0;
+
+ return tracker;
+}
+
+static inline void
+rend_vk_cmdbuf_deferred_destroy(RendVkDeferredCmds *tracker)
+{
+ vkDestroySemaphore(vk_device.logical_device, tracker->timeline, vk_allocator);
+ rfree(tracker->darray);
+ *tracker = (RendVkDeferredCmds) {0};
+}
+
+static inline void rend_vk_cmdbuf_deferred_lock(RendVkDeferredCmds *t) { (void)t; }
+static inline void rend_vk_cmdbuf_deferred_unlock(RendVkDeferredCmds *t) { (void)t; }
+
+static inline VkCommandBuffer
+rend_vk_cmdbuf_deferred_begin(VkCommandPool pool)
+{
+ VkCommandBufferAllocateInfo alloc_info = {
+ .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
+ .level = VK_COMMAND_BUFFER_LEVEL_PRIMARY,
+ .commandPool = pool,
+ .commandBufferCount = 1,
+ };
+
+ VkCommandBuffer cmd;
+ vkAllocateCommandBuffers(vk_device.logical_device, &alloc_info, &cmd);
+
+ VkCommandBufferBeginInfo begin = {
+ .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
+ .flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT,
+ };
+
+ vkBeginCommandBuffer(cmd, &begin);
+ return cmd;
+}
+
+static inline void
+rend_vk_cmdbuf_deferred_push(RendVkDeferredCmds *tracker, VkCommandPool pool, VkCommandBuffer cmd, uint64_t wait_value)
+{
+ rend_vk_cmdbuf_deferred_lock(tracker);
+ if (tracker->count == tracker->capacity) {
+ tracker->capacity *= 2;
+ tracker->darray = realloc(tracker->darray, sizeof(RendVkPendingCmd) * tracker->capacity);
+ }
+ tracker->darray[tracker->count++] = (RendVkPendingCmd) {
+ .pool = pool,
+ .cmd = cmd,
+ .wait_value = wait_value,
+ };
+ rend_vk_cmdbuf_deferred_unlock(tracker);
+}
+
+static inline uint64_t
+rend_vk_cmdbuf_deferred_submit(RendVkDeferredCmds *tracker, VkCommandPool pool, VkCommandBuffer cmd, VkQueue queue, uint64_t wait_value, VkPipelineStageFlags2 wait_stage, VkPipelineStageFlags2 signal_stage)
+{
+ uint64_t signal_value = wait_value + 1;
+
+ VkCommandBufferSubmitInfo cmd_info = {
+ .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_SUBMIT_INFO,
+ .commandBuffer = cmd,
+ };
+ VkSemaphoreSubmitInfo wait_info = {
+ .sType = VK_STRUCTURE_TYPE_SEMAPHORE_SUBMIT_INFO,
+ .semaphore = tracker->timeline,
+ .value = wait_value,
+ .stageMask = wait_stage,
+ };
+ VkSemaphoreSubmitInfo signal_info = {
+ .sType = VK_STRUCTURE_TYPE_SEMAPHORE_SUBMIT_INFO,
+ .semaphore = tracker->timeline,
+ .value = signal_value,
+ .stageMask = signal_stage,
+ };
+ VkSubmitInfo2 submit = {
+ .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO_2,
+ .waitSemaphoreInfoCount = wait_value ? 1 : 0,
+ .pWaitSemaphoreInfos = &wait_info,
+ .commandBufferInfoCount = 1,
+ .pCommandBufferInfos = &cmd_info,
+ .signalSemaphoreInfoCount = 1,
+ .pSignalSemaphoreInfos = &signal_info,
+ };
+
+ vkQueueSubmit2(queue, 1, &submit, VK_NULL_HANDLE);
+
+ rend_vk_cmdbuf_deferred_push(tracker, pool, cmd, signal_value);
+ return signal_value;
+}
+
+static inline void
+rend_vk_cmdbuf_deferred_flush(RendVkDeferredCmds *tracker)
+{
+ uint64_t completed;
+ vkGetSemaphoreCounterValue(vk_device.logical_device, tracker->timeline, &completed);
+
+ for (size_t i = 0; i < tracker->count; ) {
+ if (completed >= tracker->darray[i].wait_value) {
+ vkFreeCommandBuffers(vk_device.logical_device, tracker->darray[i].pool, 1, &tracker->darray[i].cmd);
+ tracker->darray[i] = tracker->darray[--tracker->count];
+ } else {
+ i++;
+ }
+ }
+}
diff --git a/Rend/unused code/rend_vk_memory.c b/Rend/unused code/rend_vk_memory.c
new file mode 100644
index 0000000..4782b46
--- /dev/null
+++ b/Rend/unused code/rend_vk_memory.c
@@ -0,0 +1,100 @@
+#pragma once
+
+#include "rend_internal.h"
+#include "rend_vk_internal.h"
+#include <vulkan/vulkan_core.h>
+
+
+#if 0
+static RendVkMemory
+rend_vk_memory_malloc(size_t size, VkDevice logical_device, VkPhysicalDevice physical_device, uint32_t heap_index, VkAllocationCallbacks *allocator)
+{
+ RendVkMemory memory = {
+ .host_mapped_memory = NULL,
+ .device_memory = 0,
+ .logical_device = logical_device,
+ .heap_index = heap_index
+ };
+
+ VkMemoryAllocateFlagsInfo flags_info = {
+ .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_FLAGS_INFO,
+ .pNext = NULL,
+ .flags = VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT, /* REQUIRED for BDA buffers */
+ .deviceMask = 0
+ };
+
+ VkMemoryAllocateInfo alloc_info = {
+ .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
+ .allocationSize = size,
+ .pNext = &flags_info,
+ .memoryTypeIndex = heap_index
+ };
+
+ vkAllocateMemory(logical_device, &alloc_info, allocator, &memory.device_memory);
+ return memory;
+}
+
+static void
+rend_vk_memory_free(RendVkMemory *memory)
+{
+ if (memory->host_mapped_memory) {
+ rend_vk_memory_unmap(memory);
+ }
+ if (memory->offset == 0) {
+ vkFreeMemory(memory->logical_device, memory->device_memory, memory->allocator);
+ memset(memory, 0, sizeof *memory);
+ } else {
+ PWARN("[REND_VK] Attempted to free memory with an offset!");
+ }
+}
+
+static void*
+rend_vk_memory_map(RendVkMemory *memory)
+{
+ // SPEC: memory must have been created with a memory type that reports VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT
+ // vkMapMemory will fail if the implementation is unable to allocate an appropriately sized contiguous virtual address range,
+ // e.g. due to virtual address space fragmentation or platform limits.
+ // In such cases, vkMapMemory must return VK_ERROR_MEMORY_MAP_FAILED.
+ // The application can improve the likelihood of success by reducing the size of the mapped range and/or removing unneeded mappings using vkUnmapMemory.
+
+ vkMapMemory(memory->logical_device, memory->device_memory, memory->offset, memory->size, 0, &memory->host_mapped_memory);
+ return memory->host_mapped_memory;
+}
+
+static void
+rend_vk_memory_unmap(RendVkMemory *memory)
+{
+ if (memory->offset == 0) {
+ vkUnmapMemory(memory->logical_device, memory->device_memory);
+ memory->host_mapped_memory = 0;
+ } else {
+ PWARN("[REND_VK] Attempted to unmap memory with an offset!");
+ }
+}
+
+static void
+rend_vk_memory_copy(RendVkMemory *memory, size_t offset, const void *data, size_t size)
+{
+ /* bounds check */
+ if (offset + size > memory->size) {
+ REND__WARN("Memory write out of bounds!");
+ return;
+ }
+
+ /* important to cast this */
+ uint8_t *dest = memory->host_mapped_memory;
+ memcpy(dest + offset, data, size);
+
+ /* flush host writes if memory is non-coherent */
+ // VkMappedMemoryRange range = {
+ // .sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE,
+ // .memory = memory->device_memory,
+ // .offset = offset,
+ // .size = size
+ // };
+ //
+ // vkFlushMappedMemoryRanges(memory->logical_device, 1, &range);
+
+}
+
+#endif
diff --git a/Rend/unused code/rend_vk_pool.c b/Rend/unused code/rend_vk_pool.c
new file mode 100644
index 0000000..e527354
--- /dev/null
+++ b/Rend/unused code/rend_vk_pool.c
@@ -0,0 +1,221 @@
+#pragma once
+#include "rend_internal.h"
+#include "rend_vk_internal.h"
+#include <vulkan/vulkan_core.h>
+
+/* NOTE(vasco):
+ * Check out https://kylehalladay.com/blog/tutorial/2017/12/13/Custom-Allocators-Vulkan.html
+ * for a basic grasp on what it entails to actually write a memory allocator for vulkan.
+ *
+ * This allocator isnt anything particularly amazing but it works so I'm keeping this code.
+ * Based on the framework presented here we could implement other more efficient allocators.
+ * Which is what I did for the arena allocator.
+ */
+
+#if 0
+typedef struct RendVkAddress {
+ VkDeviceMemory handle;
+ uint32_t type;
+ uint32_t id;
+ VkDeviceSize size;
+ VkDeviceSize offset;
+} RendVkAddress;
+
+typedef struct RendVkPoolLayout {
+ uint64_t offset, size;
+} RendVkPoolLayout;
+
+typedef struct RendVKPoolBlock {
+ RendVkAddress address;
+ RendVkPoolLayout *layout_darr;
+ uint8_t reserved;
+} RendVKPoolBlock;
+
+typedef struct RendVkPoolMemory {
+ RendVKPoolBlock *block_darr;
+} RendVkPoolMemory;
+
+struct RendVkPoolAllocator {
+ VkAllocationCallbacks *allocator;
+ size_t *mem_type_alloc_sizes; // allocation size per type of memory available on the gpu
+ RendVkPoolMemory *mem_pools; // memory pools per type of memory available on the gpu
+ VkDevice logical_device; // virtual device
+ VkPhysicalDevice physical_device; // physical device we are allocating memory from
+ VkDeviceSize page_size; // allocations must respect the physical limitations of the gpu
+ VkDeviceSize block_min_size; // minimum size per block of memory
+ uint64_t total_allocations;
+ uint32_t memory_type_count;
+};
+
+static RendVkPoolAllocator
+rend_vk_pool_create(VkDevice logical_device, VkPhysicalDevice physical_device, VkPhysicalDeviceLimits device_limits, VkAllocationCallbacks *allocator)
+{
+ RendVkPoolAllocator pool = {
+ .allocator = allocator,
+ .mem_type_alloc_sizes = NULL,
+ .mem_pools = NULL,
+ .logical_device = logical_device,
+ .physical_device = physical_device,
+ .page_size = 0,
+ .block_min_size = 0,
+ .total_allocations = 0,
+ .memory_type_count = 0,
+ };
+
+ VkPhysicalDeviceMemoryProperties mem_properties;
+ vkGetPhysicalDeviceMemoryProperties(physical_device, &mem_properties);
+
+ pool.mem_type_alloc_sizes = malloc(mem_properties.memoryTypeCount * sizeof *pool.mem_type_alloc_sizes);
+ memset(pool.mem_type_alloc_sizes, 0, mem_properties.memoryTypeCount * sizeof *pool.mem_type_alloc_sizes);
+
+ pool.mem_pools = malloc(mem_properties.memoryTypeCount * sizeof *pool.mem_pools);
+ memset(pool.mem_pools, 0, mem_properties.memoryTypeCount * sizeof *pool.mem_pools);
+
+ pool.memory_type_count = mem_properties.memoryTypeCount;
+ pool.page_size = device_limits.bufferImageGranularity;
+ pool.block_min_size = pool.page_size * 10;
+
+ return pool;
+}
+
+static uint32_t
+rend_vk_pool_add_block(RendVkPoolAllocator *pool, VkDeviceSize size, uint32_t memory_type, VkMemoryPropertyFlags properties, bool fit_to_alloc)
+{
+ VkDeviceSize new_pool_size = size * 2;
+ new_pool_size = (new_pool_size < pool->block_min_size) ? pool->block_min_size : new_pool_size;
+
+ VkMemoryAllocateInfo alloc_info = {
+ .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
+ .allocationSize = new_pool_size,
+ .memoryTypeIndex = rend_vk_memory_find_index(pool->physical_device, memory_type, properties)
+ };
+
+ RendVKPoolBlock block = {0};
+ VkResult res = vkAllocateMemory(pool->logical_device, &alloc_info, pool->allocator, &block.address.handle);
+ block.address.type = memory_type;
+ block.address.size = new_pool_size;
+
+ RendVkPoolMemory *mem_pool = &pool->mem_pools[memory_type];
+ p_darray_push(mem_pool->block_darr, block);
+
+ RendVkPoolLayout layout = {
+ .offset = 0,
+ .size = new_pool_size
+ };
+ p_darray_push(mem_pool->block_darr[pool_size - 1].layout_darr, layout);
+
+ pool->total_allocations++;
+
+ size_t pool_size = p_darray_len(mem_pool->block_darr);
+ return pool_size - 1;
+}
+
+static RendVkMemory
+rend_vk_pool_alloc(RendVkPoolAllocator *pool, VkDeviceSize size, uint32_t usage, uint32_t memory_type, VkMemoryPropertyFlags properties)
+{
+ RendVkPoolMemory *mem_pool = &pool->mem_pools[memory_type];
+
+ VkDeviceSize requested_alloc_size = ((size / pool->page_size) + 1) * pool->page_size;
+ pool->mem_type_alloc_sizes[memory_type] += requested_alloc_size;
+
+ /* find free chunk for allocation
+ * TODO: free list?
+ */
+ int whole_page = usage != VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
+ uint64_t block_idx = UINT64_MAX;
+ uint64_t span_idx = UINT64_MAX;
+ for (uint32_t i = 0; i < p_darray_len(mem_pool->block_darr); ++i) {
+ for (uint32_t j = 0; j < p_darray_len(mem_pool->block_darr[i].layout_darr); ++j) {
+ int valid = (whole_page) ? mem_pool->block_darr[i].layout_darr[j].offset == 0 : 1;
+ if (mem_pool->block_darr[i].layout_darr[j].size >= size && valid) {
+ block_idx = i;
+ span_idx = j;
+ }
+ }
+ }
+
+ if (block_idx == UINT64_MAX || span_idx == UINT64_MAX) {
+ block_idx = rend_vk_pool_add_block(pool, size, memory_type, properites, whole_page);
+ span_idx = 0;
+ }
+
+ mem_pool->block_darr[block_idx].reserved = whole_page;
+
+ RendVkMemory memory = {
+ .device_memory = mem_pool->block_darr[block_idx].address.handle,
+ .size = size,
+ .offset = mem_pool->block_darr[block_idx].layout_darr[span_idx].offset,
+ .type = memory_type,
+
+ .logical_device = pool->logical_device,
+ .allocator = pool->allocator,
+ .host_mapped_memory = 0,
+ .physical_device = pool->physical_device,
+ .properties = properties,
+
+ .id = block_idx,
+ };
+
+ /* mark chunck */
+ mem_pool->block_darr[block_idx].layout_darr[span_idx].offset += size;
+ mem_pool->block_darr[block_idx].layout_darr[span_idx].size -= size;
+ return memory;
+}
+
+
+static void
+rend_vk_pool_free(RendVkPoolAllocator *pool, RendVkMemory *memory)
+{
+ VkDeviceSize requested = ((memory->size / pool->page_size) + 1) * pool->page_size;
+
+ RendVkPoolMemory *mem_pool = &pool->mem_pools[memory->type];
+
+ pool->blocks_[allocation.id].pageReserved = false;
+
+ mem_pool->block_darr[block_idx].layout_darr[span_idx].offset += size;
+ mem_pool->block_darr[block_idx].layout_darr[span_idx].size -= size;
+
+ OffsetSize span = {allocation.offset, requestedAllocSize };
+ bool found = false;
+
+ uint32_t numLayoutMems = pool.blocks[allocation.id].layout.size();
+ for (uint32_t j = 0; j < numLayoutMems; ++j)
+ {
+ if (pool.blocks[allocation.id].layout[j].offset == requestedAllocSize +allocation.offset)
+ {
+ pool.blocks[allocation.id].layout[j].offset = allocation.offset;
+ pool.blocks[allocation.id].layout[j].size += requestedAllocSize;
+ found = true;
+ break;
+ }
+ }
+
+ if (!found)
+ {
+ state.memPools[allocation.type].blocks[allocation.id].layout.push_back(span);
+ state.memTypeAllocSizes[allocation.type] -= requestedAllocSize;
+ }
+}
+
+static void
+rend_vk_pool_destroy(RendVkPoolAllocator *pool)
+{
+ if (pool->mem_pools) {
+ for (size_t u = 0; u < pool->memory_type_count; ++u) {
+ RendVkPoolMemory mem_pool = pool->mem_pools[u];
+ for (size_t b = 0; b < p_darray_len(mem_pool.block_darr); ++b) {
+ RendVKPoolBlock block = mem_pool.block_darr[b];
+ p_darray_destroy(block.layout_darr);
+ }
+ p_darray_destroy(mem_pool.block_darr);
+ }
+ free(pool->mem_pools);
+ pool->mem_pools = 0;
+ }
+ if (pool->mem_type_alloc_sizes) {
+ free(pool->mem_type_alloc_sizes);
+ pool->mem_type_alloc_sizes = 0;
+ }
+ memset(pool, 0, sizeof *pool);
+}
+#endif
diff --git a/Rend/unused code/rend_vk_sbta.c b/Rend/unused code/rend_vk_sbta.c
new file mode 100644
index 0000000..7bc51c4
--- /dev/null
+++ b/Rend/unused code/rend_vk_sbta.c
@@ -0,0 +1,331 @@
+#pragma once
+#include "rend_internal.h"
+#include "rend_vk_internal.h"
+#include <vulkan/vulkan_core.h>
+
+/*
+ * Sparse Bindless Texture Array (SBTA)
+ *
+ */
+
+struct RendVkSbta {
+ VkDevice logical_device;
+ RendVkImage image; /* single 2D array image, arrayLayers = max_layers */
+ VkImageView *views; /* per-layer VkImageView array */
+ VkFormat format;
+ VkExtent2D extent;
+ uint32_t max_layers;
+ uint32_t mip_levels;
+ uint64_t *bitmap; /* 1 bit per layer slot */
+ uint32_t bitmap_word_count;
+ uint32_t allocated_count;
+ RendMemory memory;
+};
+
+static inline uint32_t
+rend_vk_sbta_mip_count(uint32_t w, uint32_t h)
+{
+ uint32_t v = (w > h) ? w : h;
+ uint32_t levels = 1;
+ while (v >>= 1) { levels++; }
+ return levels;
+}
+
+static void
+rend_vk_sbta_create(RendVkSbta *sbta, VkDevice logical_device, VkExtent2D extent, uint32_t layers)
+{
+ memset(sbta, 0, sizeof *sbta);
+ sbta->logical_device = logical_device;
+ sbta->format = VK_FORMAT_R8G8B8A8_SRGB;
+ sbta->extent = extent;
+ sbta->max_layers = layers;
+ sbta->mip_levels = rend_vk_sbta_mip_count(extent.width, extent.height);
+
+ /* create image */
+ sbta->image = rend_vk_image_create(
+ logical_device,
+ VK_IMAGE_TYPE_2D,
+ extent.width, extent.height,
+ sbta->format,
+ VK_IMAGE_TILING_OPTIMAL,
+ VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_SAMPLED_BIT,
+ VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
+ 1, /* depth */
+ sbta->mip_levels,
+ layers,
+ VK_SAMPLE_COUNT_1_BIT,
+ VK_SHARING_MODE_EXCLUSIVE
+ );
+
+ /* allocate per-layer views array */
+ sbta->views = rmalloc(layers * sizeof *sbta->views);
+ memset(sbta->views, 0, layers * sizeof *sbta->views);
+
+ /* bitmap: ceil(layers / 64) words */
+ sbta->bitmap_word_count = (layers + 63) / 64;
+ sbta->bitmap = rmalloc(sbta->bitmap_word_count * sizeof *sbta->bitmap);
+ memset(sbta->bitmap, 0, sbta->bitmap_word_count * sizeof *sbta->bitmap);
+ sbta->allocated_count = 0;
+}
+
+static void
+rend_vk_sbta_create_views(RendVkSbta *sbta)
+{
+ for (uint32_t i = 0; i < sbta->max_layers; ++i) {
+ VkImageViewCreateInfo view_info = {
+ .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
+ .image = sbta->image.handle,
+ .format = sbta->format,
+ .viewType = VK_IMAGE_VIEW_TYPE_2D,
+ .subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
+ .subresourceRange.baseMipLevel = 0,
+ .subresourceRange.levelCount = sbta->mip_levels,
+ .subresourceRange.baseArrayLayer = i,
+ .subresourceRange.layerCount = 1,
+ };
+ vkCreateImageView(sbta->logical_device, &view_info, vk_allocator, &sbta->views[i]);
+ }
+}
+
+static void
+rend_vk_sbta_destroy(RendVkSbta *sbta)
+{
+ for (uint32_t i = 0; i < sbta->max_layers; ++i) {
+ if (sbta->views[i]) {
+ vkDestroyImageView(sbta->logical_device, sbta->views[i], vk_allocator);
+ }
+ }
+
+ rend_vk_image_destroy(&sbta->image);
+
+ rfree(sbta->views);
+ rfree(sbta->bitmap);
+ memset(sbta, 0, sizeof *sbta);
+}
+
+static uint64_t
+rend_vk_sbta_alloc(RendVkSbta *sbta)
+{
+ for (uint32_t w = 0; w < sbta->bitmap_word_count; ++w) {
+ if (sbta->bitmap[w] == ~(uint64_t)0) continue; /* word full */
+
+ /* find first zero bit */
+ uint64_t word = sbta->bitmap[w];
+ uint64_t bit = ~word & (word + 1); /* isolate lowest zero bit */
+ uint32_t bit_index = 0;
+ uint64_t tmp = bit;
+ while (tmp >>= 1) { bit_index++; }
+
+ uint64_t slot = (uint64_t)w * 64 + bit_index;
+ if (slot >= sbta->max_layers) return UINT64_MAX; /* past capacity */
+
+ sbta->bitmap[w] |= bit;
+ sbta->allocated_count++;
+ return slot;
+ }
+ return UINT64_MAX; /* full */
+}
+
+static void
+rend_vk_sbta_free(RendVkSbta *sbta, uint64_t idx)
+{
+ assert(idx < sbta->max_layers && "SBTA free: index out of range");
+
+ uint32_t word = (uint32_t)(idx / 64);
+ uint32_t bit = (uint32_t)(idx % 64);
+ assert((sbta->bitmap[word] & (1ULL << bit)) && "SBTA free: slot not allocated (double free?)");
+
+ sbta->bitmap[word] &= ~(1ULL << bit);
+ sbta->allocated_count--;
+}
+
+static void
+rend_vk_sbta_upload(RendVkSbta *sbta, VkCommandBuffer cmd, RendVkArenaAllocator *staging_arena, uint64_t slot, void *pixels, uint64_t size)
+{
+ assert(slot < sbta->max_layers);
+ assert(pixels && size > 0);
+
+ /* ---- staging buffer ---- */
+ VkBufferCreateInfo buf_info = {
+ .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
+ .size = size,
+ .usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
+ };
+
+ VkBuffer staging_buf;
+ vkCreateBuffer(sbta->logical_device, &buf_info, vk_allocator, &staging_buf);
+
+ VkMemoryRequirements staging_reqs;
+ vkGetBufferMemoryRequirements(sbta->logical_device, staging_buf, &staging_reqs);
+
+ uint32_t host_index = vk_device.host_index;
+ RendMemory staging_mem = rend_vk_arena_alloc(staging_arena, staging_reqs.size, host_index);
+ vkBindBufferMemory(sbta->logical_device, staging_buf, (VkDeviceMemory) staging_mem.device_memory, staging_mem.offset);
+
+ /* copy pixels into staging */
+ memcpy(staging_mem.host_mapped_memory, pixels, size);
+
+ /* ---- transition layer mip 0: UNDEFINED -> TRANSFER_DST ---- */
+ VkImageMemoryBarrier2 barrier_to_dst = {
+ .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2,
+ .srcStageMask = VK_PIPELINE_STAGE_2_NONE,
+ .srcAccessMask = VK_ACCESS_2_NONE,
+ .dstStageMask = VK_PIPELINE_STAGE_2_TRANSFER_BIT,
+ .dstAccessMask = VK_ACCESS_2_TRANSFER_WRITE_BIT,
+ .oldLayout = VK_IMAGE_LAYOUT_UNDEFINED,
+ .newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
+ .image = sbta->image.handle,
+ .subresourceRange = {
+ .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
+ .baseMipLevel = 0,
+ .levelCount = sbta->mip_levels,
+ .baseArrayLayer = (uint32_t)slot,
+ .layerCount = 1,
+ },
+ };
+
+ VkDependencyInfo dep_to_dst = {
+ .sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO,
+ .imageMemoryBarrierCount = 1,
+ .pImageMemoryBarriers = &barrier_to_dst,
+ };
+ vkCmdPipelineBarrier2(cmd, &dep_to_dst);
+
+ /* ---- copy staging -> image mip 0 ---- */
+ VkBufferImageCopy copy_region = {
+ .bufferOffset = 0,
+ .imageSubresource = {
+ .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
+ .mipLevel = 0,
+ .baseArrayLayer = (uint32_t)slot,
+ .layerCount = 1,
+ },
+ .imageExtent = { sbta->extent.width, sbta->extent.height, 1 },
+ };
+
+ vkCmdCopyBufferToImage(cmd, staging_buf, sbta->image.handle, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &copy_region);
+
+ /* ---- generate mipmaps via blit chain ---- */
+ int32_t mip_w = (int32_t)sbta->extent.width;
+ int32_t mip_h = (int32_t)sbta->extent.height;
+
+ for (uint32_t mip = 1; mip < sbta->mip_levels; ++mip) {
+ /* transition previous mip: TRANSFER_DST -> TRANSFER_SRC */
+ VkImageMemoryBarrier2 barrier_src = {
+ .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2,
+ .srcStageMask = VK_PIPELINE_STAGE_2_TRANSFER_BIT,
+ .srcAccessMask = VK_ACCESS_2_TRANSFER_WRITE_BIT,
+ .dstStageMask = VK_PIPELINE_STAGE_2_TRANSFER_BIT,
+ .dstAccessMask = VK_ACCESS_2_TRANSFER_READ_BIT,
+ .oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
+ .newLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
+ .image = sbta->image.handle,
+ .subresourceRange = {
+ .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
+ .baseMipLevel = mip - 1,
+ .levelCount = 1,
+ .baseArrayLayer = (uint32_t)slot,
+ .layerCount = 1,
+ },
+ };
+
+ VkDependencyInfo dep_src = {
+ .sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO,
+ .imageMemoryBarrierCount = 1,
+ .pImageMemoryBarriers = &barrier_src,
+ };
+ vkCmdPipelineBarrier2(cmd, &dep_src);
+
+ /* blit from mip-1 to mip */
+ int32_t next_w = (mip_w > 1) ? mip_w / 2 : 1;
+ int32_t next_h = (mip_h > 1) ? mip_h / 2 : 1;
+
+ VkImageBlit2 blit = {
+ .sType = VK_STRUCTURE_TYPE_IMAGE_BLIT_2,
+ .srcSubresource = {
+ .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
+ .mipLevel = mip - 1,
+ .baseArrayLayer = (uint32_t)slot,
+ .layerCount = 1,
+ },
+ .srcOffsets = { {0, 0, 0}, {mip_w, mip_h, 1} },
+ .dstSubresource = {
+ .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
+ .mipLevel = mip,
+ .baseArrayLayer = (uint32_t)slot,
+ .layerCount = 1,
+ },
+ .dstOffsets = { {0, 0, 0}, {next_w, next_h, 1} },
+ };
+
+ VkBlitImageInfo2 blit_info = {
+ .sType = VK_STRUCTURE_TYPE_BLIT_IMAGE_INFO_2,
+ .srcImage = sbta->image.handle,
+ .srcImageLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
+ .dstImage = sbta->image.handle,
+ .dstImageLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
+ .regionCount = 1,
+ .pRegions = &blit,
+ .filter = VK_FILTER_LINEAR,
+ };
+ vkCmdBlitImage2(cmd, &blit_info);
+
+ mip_w = next_w;
+ mip_h = next_h;
+ }
+
+ /* ---- final transition: all mips -> SHADER_READ_ONLY ---- */
+ /* last mip is still TRANSFER_DST, all others are TRANSFER_SRC */
+
+ /* transition last mip: TRANSFER_DST -> SHADER_READ_ONLY */
+ VkImageMemoryBarrier2 barriers_final[2] = {
+ /* mips 0..N-2: TRANSFER_SRC -> SHADER_READ_ONLY */
+ {
+ .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2,
+ .srcStageMask = VK_PIPELINE_STAGE_2_TRANSFER_BIT,
+ .srcAccessMask = VK_ACCESS_2_TRANSFER_READ_BIT,
+ .dstStageMask = VK_PIPELINE_STAGE_2_FRAGMENT_SHADER_BIT,
+ .dstAccessMask = VK_ACCESS_2_SHADER_SAMPLED_READ_BIT,
+ .oldLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
+ .newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
+ .image = sbta->image.handle,
+ .subresourceRange = {
+ .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
+ .baseMipLevel = 0,
+ .levelCount = (sbta->mip_levels > 1) ? sbta->mip_levels - 1 : 1,
+ .baseArrayLayer = (uint32_t)slot,
+ .layerCount = 1,
+ },
+ },
+ /* last mip: TRANSFER_DST -> SHADER_READ_ONLY */
+ {
+ .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2,
+ .srcStageMask = VK_PIPELINE_STAGE_2_TRANSFER_BIT,
+ .srcAccessMask = VK_ACCESS_2_TRANSFER_WRITE_BIT,
+ .dstStageMask = VK_PIPELINE_STAGE_2_FRAGMENT_SHADER_BIT,
+ .dstAccessMask = VK_ACCESS_2_SHADER_SAMPLED_READ_BIT,
+ .oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
+ .newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
+ .image = sbta->image.handle,
+ .subresourceRange = {
+ .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
+ .baseMipLevel = sbta->mip_levels - 1,
+ .levelCount = 1,
+ .baseArrayLayer = (uint32_t)slot,
+ .layerCount = 1,
+ },
+ },
+ };
+
+ uint32_t barrier_count = (sbta->mip_levels > 1) ? 2 : 1;
+
+ /* if only 1 mip, use second barrier (TRANSFER_DST path) */
+ VkImageMemoryBarrier2 *barrier_ptr = (sbta->mip_levels > 1) ? barriers_final : &barriers_final[1];
+
+ VkDependencyInfo dep_final = {
+ .sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO,
+ .imageMemoryBarrierCount = barrier_count,
+ .pImageMemoryBarriers = barrier_ptr,
+ };
+ vkCmdPipelineBarrier2(cmd, &dep_final);
+}
diff --git a/build.c b/build.c
new file mode 100644
index 0000000..b07404d
--- /dev/null
+++ b/build.c
@@ -0,0 +1,33 @@
+#define POOF_IMPLEMENTATION
+#include "../Poof/poof.h"
+
+void Peak() {
+ Poof_Cmd cmd = {0};
+ poof_cmd_append(&cmd, "python", "bundle_header.py", "src/peak_header.h");
+ poof_cmd_run(&cmd);
+
+ poof_copy_file("Peak/src/peak_header.h.out", "Peak/peak.h");
+
+ Poof_CC cc = {0};
+ poof_cc_init(&cc, POOF_CC_GCC | POOF_CC_CLANG, POOF_TARGET_HOST);
+ cc.debug_mode = true;
+ cc.optimization = POOF_O0;
+ cc.output = "Peak/demos/demo";
+ poof_cc_append(&cc.inputs, "Peak/demos/demo.c");
+ poof_cc_append(&cc.extra_flags, "-std=c99", "-Wall", "-Wno-deprecated-declarations");
+ poof_cc_append(&cc.libs, "m");
+ poof_cc_run(&cc);
+
+ cc.debug_mode = true;
+ cc.optimization = POOF_O0;
+ cc.output = "Peak/demos/demo_main";
+ poof_cc_append(&cc.inputs, "Peak/demos/demo_replace_main.c");
+ poof_cc_append(&cc.extra_flags, "-std=c99", "-Wall", "-Wno-deprecated-declarations");
+ poof_cc_append(&cc.libs, "m");
+ poof_cc_run(&cc);
+}
+
+int main(int argc, char **argv) {
+ POOF_GO_REBUILD_URSELF(argc, argv);
+ Peak();
+}
diff --git a/bundle_header.py b/bundle_header.py
new file mode 100644
index 0000000..0073163
--- /dev/null
+++ b/bundle_header.py
@@ -0,0 +1,46 @@
+import re
+import sys
+from pathlib import Path
+
+def bundle_header(input_path: Path):
+ """
+ Looks for #include "filename" // <REPLACE>
+ And inlines that file directly into the code.
+ """
+ output_path = input_path.with_suffix(input_path.suffix + ".out")
+
+ include_pattern = re.compile(r'#include\s+["<](?P<filename>.*)[">]\s*//\s*<REPLACE>')
+
+ def process_file(file_path: Path) -> str:
+ if not file_path.exists():
+ print(f"Warning: {file_path} not found.")
+ return f"// Error: {file_path} not found\n"
+
+ lines = []
+ with open(file_path, 'r') as f:
+ for line in f:
+ match = include_pattern.search(line)
+ if match:
+ include_name = match.group('filename')
+ # Look for the file relative to the current file's directory
+ nested_path = file_path.parent / include_name
+ lines.append(f"/* --- Start of {include_name} --- */\n")
+ lines.append(process_file(nested_path))
+ lines.append(f"/* --- End of {include_name} --- */\n")
+ else:
+ lines.append(line)
+ return "".join(lines)
+
+ content = process_file(input_path)
+
+ with open(output_path, 'w') as f:
+ f.write(content)
+
+ print(f"Successfully bundled into: {output_path}")
+
+if __name__ == "__main__":
+ if len(sys.argv) < 2:
+ print("Usage: python build.py <path_to_header>")
+ sys.exit(1)
+
+ bundle_header(Path(sys.argv[1]))