You've already forked flecs_tests
Rebuild from scratch with a new strategy using compute shaders and SDF.
This commit is contained in:
@@ -5,12 +5,12 @@ LIB_DIR="lib"
|
||||
|
||||
echo "=== Fetching library dependencies ==="
|
||||
|
||||
# 1. Sokol (single-file headers)
|
||||
mkdir -p "$LIB_DIR/sokol"
|
||||
mkdir -p "$LIB_DIR/imgui"
|
||||
mkdir -p "$LIB_DIR/util"
|
||||
mkdir -p "$LIB_DIR/cglm"
|
||||
|
||||
# 1. Sokol (single-file headers)
|
||||
if [ ! -f "$LIB_DIR/sokol/sokol_gfx.h" ]; then
|
||||
echo " > Fetching sokol (pinned to emdawnwebgpu-compatible version)..."
|
||||
git clone --depth 500 https://github.com/floooh/sokol.git "$LIB_DIR/sokol_tmp"
|
||||
@@ -59,4 +59,14 @@ else
|
||||
echo " > cglm already present"
|
||||
fi
|
||||
|
||||
# 5. sokol_gp.h
|
||||
if [ ! -f "$LIB_DIR/sokol/sokol_gp.h" ]; then
|
||||
echo " > Fetching cglm..."
|
||||
git clone --depth 1 https://github.com/edubart/sokol_gp.git "$LIB_DIR/sokol_gp_tmp"
|
||||
cp -r "$LIB_DIR/sokol_gp_tmp/sokol_gp.h" "$LIB_DIR/sokol/sokol_gp.h"
|
||||
rm -rf "$LIB_DIR/sokol_gp_tmp"
|
||||
else
|
||||
echo " > sokol_gp.h already present"
|
||||
fi
|
||||
|
||||
echo "=== Done ==="
|
||||
|
||||
3
makefile
3
makefile
@@ -31,7 +31,8 @@ EMCC_FLAGS = --use-port=emdawnwebgpu \
|
||||
-sALLOW_MEMORY_GROWTH \
|
||||
-msimd128 \
|
||||
-sFILESYSTEM=0 \
|
||||
-flto
|
||||
-flto \
|
||||
-Rpass=loop-vectorize
|
||||
|
||||
# Shell template
|
||||
SHELL_FILE = shell.html
|
||||
|
||||
59
src/api.h
59
src/api.h
@@ -6,67 +6,12 @@
|
||||
#define SOKOL_IMPL
|
||||
#define SOKOL_WGPU
|
||||
#define SOKOL_IMGUI_IMPL
|
||||
#define SOKOL_VALIDATE_NON_FATAL
|
||||
|
||||
#include "sokol_gfx.h"
|
||||
#include "sokol_app.h"
|
||||
#include "sokol_glue.h"
|
||||
#include "sokol_log.h"
|
||||
#include "cimgui.h"
|
||||
#include "sokol_imgui.h"
|
||||
#include "sokol_memtrack.h"
|
||||
#include "sokol_shape.h"
|
||||
|
||||
#define ALLOC(arg) smemtrack_alloc(arg, NULL)
|
||||
#define FREE(arg) smemtrack_free(arg, NULL)
|
||||
|
||||
#include "cglm/cglm.h"
|
||||
|
||||
#include "rand.h"
|
||||
#include "camera.h"
|
||||
|
||||
#include "generated/sprite.h"
|
||||
#include "generated/shape.h"
|
||||
#include "generated/overlay.h"
|
||||
|
||||
// Log-to-panel infrastructure — ctx pointer passed explicitly.
|
||||
// The panel_log function writes into the panel's ring buffer through the
|
||||
// callback registered in panel_log_ctx_t. This avoids a global function
|
||||
// pointer that would restrict the codebase to a single compilation unit.
|
||||
typedef struct {
|
||||
void (*fn)(void*, int, const char*);
|
||||
void *ud;
|
||||
} panel_log_ctx_t;
|
||||
|
||||
static void panel_log(panel_log_ctx_t *pl, int level, const char *fmt, ...) {
|
||||
if (!pl || !pl->fn) return;
|
||||
char buf[256];
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
vsnprintf(buf, sizeof(buf), fmt, ap);
|
||||
va_end(ap);
|
||||
pl->fn(pl->ud, level, buf);
|
||||
}
|
||||
|
||||
// Debug-level log calls are stripped in release builds. All panel_log(3, ...)
|
||||
// calls should use this macro so they compile to nothing with -O3.
|
||||
#ifdef NDEBUG
|
||||
#define panel_log_debug(pl, fmt, ...) ((void)0)
|
||||
#else
|
||||
#define panel_log_debug(pl, fmt, ...) panel_log(pl, 3, fmt, ##__VA_ARGS__)
|
||||
#endif
|
||||
|
||||
#include "util.h"
|
||||
#include "shape.h"
|
||||
#include "render.h"
|
||||
#include "spatial.h"
|
||||
#include "history.h"
|
||||
#include "types.h"
|
||||
#include "interact.h"
|
||||
#include "overlay.h"
|
||||
#include "draw.h"
|
||||
#include "input.h"
|
||||
#include "ui_panels.h"
|
||||
|
||||
#include <emscripten.h>
|
||||
#include <stdio.h>
|
||||
@@ -74,4 +19,8 @@ static void panel_log(panel_log_ctx_t *pl, int level, const char *fmt, ...) {
|
||||
#include <math.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#include "shape.h"
|
||||
#include "generated/compute.h"
|
||||
#include "generated/display.h"
|
||||
|
||||
#endif
|
||||
40
src/camera.h
40
src/camera.h
@@ -1,40 +0,0 @@
|
||||
#ifndef CAMERA_H
|
||||
#define CAMERA_H
|
||||
|
||||
#include "api.h"
|
||||
|
||||
typedef struct {
|
||||
bool dragging;
|
||||
float origin_x, origin_y;
|
||||
} pan_state_t;
|
||||
|
||||
typedef struct {
|
||||
int width, height;
|
||||
float half_width, half_height;
|
||||
vec2 pan;
|
||||
float zoom;
|
||||
float hover_tol;
|
||||
pan_state_t pan_state;
|
||||
} camera_t;
|
||||
|
||||
// Build a view-projection matrix that maps world coordinates to clip space.
|
||||
// Uses glm_ortho rather than manual element assignment — the previous
|
||||
// hand-rolled version was equivalent but obscured the intent.
|
||||
static void compute_mvp(camera_t *cam, mat4 *mvp)
|
||||
{
|
||||
float l = (-cam->pan[0] - cam->half_width) / cam->zoom;
|
||||
float r = (-cam->pan[0] + cam->half_width) / cam->zoom;
|
||||
float b = (-cam->pan[1] - cam->half_height) / cam->zoom;
|
||||
float t = (-cam->pan[1] + cam->half_height) / cam->zoom;
|
||||
glm_ortho(l, r, b, t, -1.0f, 1.0f, *mvp);
|
||||
}
|
||||
|
||||
static void screen_to_world(camera_t *cam, float mx, float my, float *wx, float *wy)
|
||||
{
|
||||
const float sx = mx - cam->half_width;
|
||||
const float sy = cam->half_height - my;
|
||||
*wx = (sx - cam->pan[0]) / cam->zoom;
|
||||
*wy = (sy - cam->pan[1]) / cam->zoom;
|
||||
}
|
||||
|
||||
#endif
|
||||
353
src/draw.h
353
src/draw.h
@@ -1,353 +0,0 @@
|
||||
#ifndef DRAW_H
|
||||
#define DRAW_H
|
||||
|
||||
#include "api.h"
|
||||
#include "types.h"
|
||||
|
||||
static void draw_shapes(userdata_t *ud)
|
||||
{
|
||||
bool pool_was_dirty = ud->shape_pool.pool_dirty;
|
||||
if (ud->shape_pool.pool_dirty) {
|
||||
shape_pool_rebuild(&ud->shape_pool, &ud->panel_log_ctx, &ud->shapes);
|
||||
ud->shape_pool.data_dirty = true;
|
||||
}
|
||||
|
||||
int n = ud->shapes.count;
|
||||
if (n == 0) return;
|
||||
|
||||
if (ud->shape_pool.states_dirty) {
|
||||
for (int i = 0; i < n; i++) {
|
||||
shape_t *s = (shape_t*) vec_get(&ud->shapes, i);
|
||||
shape_set_state(&ud->shape_pool, s, s->hovered, s->selected);
|
||||
}
|
||||
ud->shape_pool.states_dirty = false;
|
||||
}
|
||||
|
||||
if (ud->shape_pool.data_dirty) {
|
||||
shape_upload_data(&ud->shape_pool, &ud->shapes);
|
||||
ud->shape_pool.data_dirty = false;
|
||||
}
|
||||
|
||||
// -- frustum culling: viewport world bounds --
|
||||
float vp_min_x = -(ud->camera.pan[0] + ud->camera.half_width) / ud->camera.zoom;
|
||||
float vp_max_x = (ud->camera.half_width - ud->camera.pan[0]) / ud->camera.zoom;
|
||||
float vp_min_y = -(ud->camera.half_height + ud->camera.pan[1]) / ud->camera.zoom;
|
||||
float vp_max_y = (ud->camera.half_height - ud->camera.pan[1]) / ud->camera.zoom;
|
||||
float margin = FRUSTUM_CULL_MARGIN;
|
||||
vp_min_x -= margin; vp_max_x += margin;
|
||||
vp_min_y -= margin; vp_max_y += margin;
|
||||
|
||||
static uint32_t *imap = NULL;
|
||||
static int imap_cap = 0;
|
||||
static uint32_t *gi_counts = NULL;
|
||||
static uint32_t *gi_starts = NULL;
|
||||
static int gi_cap = 0;
|
||||
static bool imap_valid = false;
|
||||
static int *visible = NULL;
|
||||
static int visible_cap = 0;
|
||||
|
||||
int draw_count;
|
||||
bool any_drag = ud->interact.move.dragging || ud->interact.rotate.dragging ||
|
||||
ud->interact.resize.dragging;
|
||||
bool use_culling = !any_drag;
|
||||
|
||||
if (use_culling) {
|
||||
if (n > visible_cap) {
|
||||
if (visible) FREE(visible);
|
||||
visible = (int*) ALLOC((size_t)n * sizeof(int));
|
||||
visible_cap = n;
|
||||
}
|
||||
|
||||
int cell_min_x = (int) floorf(vp_min_x / SPATIAL_CELL_SIZE);
|
||||
int cell_max_x = (int) floorf(vp_max_x / SPATIAL_CELL_SIZE);
|
||||
int cell_min_y = (int) floorf(vp_min_y / SPATIAL_CELL_SIZE);
|
||||
int cell_max_y = (int) floorf(vp_max_y / SPATIAL_CELL_SIZE);
|
||||
int cell_count = (cell_max_x - cell_min_x + 1) * (cell_max_y - cell_min_y + 1);
|
||||
|
||||
if (cell_count <= SPATIAL_HASH_SIZE) {
|
||||
draw_count = spatial_query_viewport(&ud->spatial_grid,
|
||||
vp_min_x, vp_min_y, vp_max_x, vp_max_y,
|
||||
visible, n);
|
||||
} else {
|
||||
// Viewport too large for cell iteration — linear scan
|
||||
draw_count = 0;
|
||||
for (int i = 0; i < n; i++) {
|
||||
shape_t *s = (shape_t*) vec_get(&ud->shapes, i);
|
||||
if (s->cx + s->aabb_hx < vp_min_x || s->cx - s->aabb_hx > vp_max_x ||
|
||||
s->cy + s->aabb_hy < vp_min_y || s->cy - s->aabb_hy > vp_max_y)
|
||||
continue;
|
||||
visible[draw_count++] = i;
|
||||
}
|
||||
}
|
||||
imap_valid = false;
|
||||
} else {
|
||||
draw_count = n;
|
||||
if (pool_was_dirty) imap_valid = false;
|
||||
}
|
||||
|
||||
if (draw_count == 0) return;
|
||||
|
||||
// Shrink draw buffers when usage drops far below peak for 60+ frames.
|
||||
// Prevents WASM memory from being held at a transient high-water mark
|
||||
// (e.g. after a large paste that was then undone).
|
||||
{
|
||||
static int peak_draw_count = 0;
|
||||
static int peak_gi_cap = 0;
|
||||
static int peak_visible_cap = 0;
|
||||
static int frames_at_peak = 0;
|
||||
|
||||
int cur_gi_size = ud->shape_pool.group_count;
|
||||
|
||||
if (draw_count > peak_draw_count || cur_gi_size > peak_gi_cap || n > peak_visible_cap) {
|
||||
peak_draw_count = draw_count;
|
||||
peak_gi_cap = cur_gi_size;
|
||||
peak_visible_cap = use_culling ? n : peak_visible_cap;
|
||||
frames_at_peak = 0;
|
||||
} else {
|
||||
frames_at_peak++;
|
||||
}
|
||||
|
||||
if (frames_at_peak > 60) {
|
||||
// Halve buffers when peak is more than 4× current usage
|
||||
if (imap_cap > 64 && imap_cap > draw_count * 4) {
|
||||
int new_cap = imap_cap / 2;
|
||||
if (new_cap < draw_count) new_cap = draw_count;
|
||||
uint32_t *new_imap = (uint32_t*) ALLOC((size_t)new_cap * sizeof(uint32_t));
|
||||
memcpy(new_imap, imap, (size_t)draw_count * sizeof(uint32_t));
|
||||
FREE(imap);
|
||||
imap = new_imap;
|
||||
imap_cap = new_cap;
|
||||
imap_valid = false;
|
||||
peak_draw_count = draw_count;
|
||||
}
|
||||
if (gi_cap > 64 && gi_cap > cur_gi_size * 4) {
|
||||
int new_cap = gi_cap / 2;
|
||||
if (new_cap < cur_gi_size) new_cap = cur_gi_size;
|
||||
uint32_t *new_gc = (uint32_t*) ALLOC((size_t)new_cap * sizeof(uint32_t));
|
||||
uint32_t *new_gs = (uint32_t*) ALLOC((size_t)new_cap * sizeof(uint32_t));
|
||||
if (cur_gi_size > 0) memcpy(new_gc, gi_counts, (size_t)cur_gi_size * sizeof(uint32_t));
|
||||
FREE(gi_counts);
|
||||
FREE(gi_starts);
|
||||
gi_counts = new_gc;
|
||||
gi_starts = new_gs;
|
||||
gi_cap = new_cap;
|
||||
peak_gi_cap = cur_gi_size;
|
||||
}
|
||||
if (visible_cap > 64 && visible_cap > n * 4) {
|
||||
int new_cap = visible_cap / 2;
|
||||
if (new_cap < n) new_cap = n;
|
||||
int *new_vis = (int*) ALLOC((size_t)new_cap * sizeof(int));
|
||||
FREE(visible);
|
||||
visible = new_vis;
|
||||
visible_cap = new_cap;
|
||||
peak_visible_cap = n;
|
||||
}
|
||||
frames_at_peak = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (draw_count > imap_cap) {
|
||||
if (imap) FREE(imap);
|
||||
imap = (uint32_t*) ALLOC((size_t)draw_count * sizeof(uint32_t));
|
||||
imap_cap = draw_count;
|
||||
imap_valid = false;
|
||||
}
|
||||
|
||||
if (!imap_valid) {
|
||||
// Sort visible shape indices by group_index so that shapes sharing
|
||||
// the same vertex buffer are consecutive. This lets the draw loop
|
||||
// issue one instanced draw call per group run rather than per shape.
|
||||
int n_groups = ud->shape_pool.group_count;
|
||||
int max_gi = n_groups - 1;
|
||||
|
||||
int gi_size = max_gi >= 0 ? max_gi + 1 : 0;
|
||||
if (gi_size > gi_cap) {
|
||||
if (gi_counts) FREE(gi_counts);
|
||||
if (gi_starts) FREE(gi_starts);
|
||||
gi_counts = (uint32_t*) ALLOC((size_t)gi_size * sizeof(uint32_t));
|
||||
gi_starts = (uint32_t*) ALLOC((size_t)gi_size * sizeof(uint32_t));
|
||||
gi_cap = gi_size;
|
||||
}
|
||||
memset(gi_counts, 0, (size_t)gi_size * sizeof(uint32_t));
|
||||
|
||||
for (int i = 0; i < draw_count; i++) {
|
||||
int si = use_culling ? visible[i] : i;
|
||||
int gi = ((shape_t*) vec_get(&ud->shapes, si))->group_index;
|
||||
if (gi < 0 || gi >= gi_size) gi = 0;
|
||||
gi_counts[gi]++;
|
||||
}
|
||||
|
||||
uint32_t pos = 0;
|
||||
for (int gi = 0; gi < gi_size; gi++) {
|
||||
gi_starts[gi] = pos;
|
||||
pos += gi_counts[gi];
|
||||
gi_counts[gi] = 0;
|
||||
}
|
||||
|
||||
for (int i = 0; i < draw_count; i++) {
|
||||
int si = use_culling ? visible[i] : i;
|
||||
int gi = ((shape_t*) vec_get(&ud->shapes, si))->group_index;
|
||||
if (gi < 0 || gi >= gi_size) gi = 0;
|
||||
imap[gi_starts[gi] + gi_counts[gi]++] = (uint32_t)si;
|
||||
}
|
||||
|
||||
shape_upload_instance_map(&ud->shape_pool, imap, draw_count);
|
||||
imap_valid = true;
|
||||
}
|
||||
|
||||
sg_apply_pipeline(ud->pipelines.shape_pipeline);
|
||||
|
||||
int base = 0;
|
||||
while (base < draw_count) {
|
||||
shape_t *s = (shape_t*) vec_get(&ud->shapes, imap[base]);
|
||||
int gi = s->group_index;
|
||||
if (gi < 0 || gi >= ud->shape_pool.group_count) gi = 0;
|
||||
uint32_t ne = s->num_elements;
|
||||
int count = 1;
|
||||
while (base + count < draw_count) {
|
||||
shape_t *ns = (shape_t*) vec_get(&ud->shapes, imap[base + count]);
|
||||
int ngi = ns->group_index;
|
||||
if (ngi < 0 || ngi >= ud->shape_pool.group_count) ngi = 0;
|
||||
if (ngi != gi) break;
|
||||
count++;
|
||||
}
|
||||
|
||||
sg_buffer group_vbuf = ud->shape_pool.groups[gi].vbuf;
|
||||
|
||||
struct { mat4 mvp; uint32_t base; uint8_t _pad[12]; } vs_u;
|
||||
memcpy(vs_u.mvp, ud->renderer.uniform.mvp, sizeof(mat4));
|
||||
vs_u.base = (uint32_t)base;
|
||||
memset(vs_u._pad, 0, 12);
|
||||
sg_apply_uniforms(0, &SG_RANGE(vs_u));
|
||||
|
||||
sg_apply_bindings(&(sg_bindings){
|
||||
.vertex_buffers[0] = group_vbuf,
|
||||
.views[0] = ud->shape_pool.data_view,
|
||||
.views[1] = ud->shape_pool.instance_map_view,
|
||||
});
|
||||
sg_draw(0, (int)ne, count);
|
||||
|
||||
base += count;
|
||||
}
|
||||
}
|
||||
|
||||
static void draw_overlay_and_handles(userdata_t *ud, bool has_overlay, bool show_handle)
|
||||
{
|
||||
sg_apply_pipeline(ud->pipelines.overlay_pipeline);
|
||||
panel_log_debug(&ud->panel_log_ctx, "[shapes] draw_overlay: pipeline=%d has_ov=%d show_h=%d",
|
||||
ud->pipelines.overlay_pipeline.id, has_overlay, show_handle);
|
||||
|
||||
if (has_overlay) {
|
||||
shape_uniform_t u;
|
||||
glm_mat4_identity(u.transform);
|
||||
u.state = 0;
|
||||
memset(u._pad, 0, sizeof(u._pad));
|
||||
|
||||
sg_apply_uniforms(0, &SG_RANGE(ud->renderer.uniform.mvp));
|
||||
sg_apply_uniforms(1, &SG_RANGE(u));
|
||||
sg_apply_bindings(&(sg_bindings){
|
||||
.vertex_buffers[0] = ud->rect_vbuf,
|
||||
.index_buffer = ud->rect_ibuf,
|
||||
});
|
||||
sg_draw(0, 5, 1);
|
||||
}
|
||||
|
||||
if (show_handle) {
|
||||
shape_uniform_t hu;
|
||||
glm_mat4_identity(hu.transform);
|
||||
hu.state = 0;
|
||||
memset(hu._pad, 0, sizeof(hu._pad));
|
||||
|
||||
sg_apply_uniforms(0, &SG_RANGE(ud->renderer.uniform.mvp));
|
||||
sg_apply_uniforms(1, &SG_RANGE(hu));
|
||||
sg_apply_bindings(&(sg_bindings){
|
||||
.vertex_buffers[0] = ud->handle_vbuf,
|
||||
.index_buffer = ud->handle_ibuf,
|
||||
});
|
||||
sg_draw(0, HANDLE_CIRCLE_SEGMENTS + 1, 1);
|
||||
|
||||
{
|
||||
shape_uniform_t cu;
|
||||
glm_mat4_identity(cu.transform);
|
||||
cu.state = 0;
|
||||
memset(cu._pad, 0, sizeof(cu._pad));
|
||||
|
||||
sg_apply_uniforms(0, &SG_RANGE(ud->renderer.uniform.mvp));
|
||||
sg_apply_uniforms(1, &SG_RANGE(cu));
|
||||
sg_apply_bindings(&(sg_bindings){
|
||||
.vertex_buffers[0] = ud->corner_vbuf,
|
||||
.index_buffer = ud->corner_ibuf,
|
||||
});
|
||||
for (int h = 0; h < 8; h++) sg_draw(h * 5, 5, 1);
|
||||
}
|
||||
}
|
||||
|
||||
// Pen preview
|
||||
if (ud->pen.drawing && ud->pen.preview_count >= 2) {
|
||||
sg_update_buffer(ud->pen_vbuf, &(sg_range){
|
||||
ud->pen.preview_verts,
|
||||
(size_t)ud->pen.preview_count * sizeof(shape_vertex_t)
|
||||
});
|
||||
|
||||
shape_uniform_t pu;
|
||||
glm_mat4_identity(pu.transform);
|
||||
pu.state = 0;
|
||||
memset(pu._pad, 0, sizeof(pu._pad));
|
||||
|
||||
sg_apply_uniforms(0, &SG_RANGE(ud->renderer.uniform.mvp));
|
||||
sg_apply_uniforms(1, &SG_RANGE(pu));
|
||||
sg_apply_bindings(&(sg_bindings){
|
||||
.vertex_buffers[0] = ud->pen_vbuf,
|
||||
.index_buffer = ud->pen_ibuf,
|
||||
});
|
||||
sg_draw(0, ud->pen.preview_count, 1);
|
||||
}
|
||||
|
||||
// Edit mode overlays
|
||||
if (ud->interact.editing_shape_idx >= 0) {
|
||||
shape_uniform_t eu;
|
||||
glm_mat4_identity(eu.transform);
|
||||
|
||||
// Handle lines (anchor → handle) — drawn as separate 2-vert segments
|
||||
if (ud->ed_handle_line_count >= 2) {
|
||||
eu.state = 0;
|
||||
memset(eu._pad, 0, sizeof(eu._pad));
|
||||
sg_apply_uniforms(0, &SG_RANGE(ud->renderer.uniform.mvp));
|
||||
sg_apply_uniforms(1, &SG_RANGE(eu));
|
||||
sg_apply_bindings(&(sg_bindings){
|
||||
.vertex_buffers[0] = ud->ed_handle_line_vbuf,
|
||||
.index_buffer = ud->ed_shared_ibuf,
|
||||
});
|
||||
int n_lines = ud->ed_handle_line_count / 2;
|
||||
for (int i = 0; i < n_lines; i++) sg_draw(i * 2, 2, 1);
|
||||
}
|
||||
|
||||
// Handle squares
|
||||
if (ud->ed_handle_count > 0) {
|
||||
eu.state = 0;
|
||||
memset(eu._pad, 0, sizeof(eu._pad));
|
||||
sg_apply_uniforms(0, &SG_RANGE(ud->renderer.uniform.mvp));
|
||||
sg_apply_uniforms(1, &SG_RANGE(eu));
|
||||
sg_apply_bindings(&(sg_bindings){
|
||||
.vertex_buffers[0] = ud->ed_handle_vbuf,
|
||||
.index_buffer = ud->ed_shared_ibuf,
|
||||
});
|
||||
for (int h = 0; h < ud->ed_handle_count; h++) sg_draw(h * 5, 5, 1);
|
||||
}
|
||||
|
||||
// Anchor squares (drawn last so they're on top)
|
||||
if (ud->ed_anchor_count > 0) {
|
||||
eu.state = 0;
|
||||
memset(eu._pad, 0, sizeof(eu._pad));
|
||||
sg_apply_uniforms(0, &SG_RANGE(ud->renderer.uniform.mvp));
|
||||
sg_apply_uniforms(1, &SG_RANGE(eu));
|
||||
sg_apply_bindings(&(sg_bindings){
|
||||
.vertex_buffers[0] = ud->ed_anchor_vbuf,
|
||||
.index_buffer = ud->ed_shared_ibuf,
|
||||
});
|
||||
for (int h = 0; h < ud->ed_anchor_count; h++) sg_draw(h * 5, 5, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
627
src/generated/compute.h
Normal file
627
src/generated/compute.h
Normal file
@@ -0,0 +1,627 @@
|
||||
unsigned char src_shaders_compute_wgsl[] = {
|
||||
0x2f, 0x2f, 0x20, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d,
|
||||
0x2d, 0x20, 0x42, 0x69, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x73, 0x20, 0x28,
|
||||
0x65, 0x78, 0x61, 0x63, 0x74, 0x6c, 0x79, 0x20, 0x61, 0x73, 0x20, 0x79,
|
||||
0x6f, 0x75, 0x20, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x65, 0x64, 0x29, 0x20,
|
||||
0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0d, 0x0a,
|
||||
0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x20, 0x53, 0x65, 0x67, 0x6d, 0x65,
|
||||
0x6e, 0x74, 0x20, 0x7b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x70, 0x30,
|
||||
0x3a, 0x20, 0x76, 0x65, 0x63, 0x32, 0x66, 0x2c, 0x0d, 0x0a, 0x20, 0x20,
|
||||
0x20, 0x20, 0x70, 0x31, 0x3a, 0x20, 0x76, 0x65, 0x63, 0x32, 0x66, 0x2c,
|
||||
0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x70, 0x32, 0x3a, 0x20, 0x76, 0x65,
|
||||
0x63, 0x32, 0x66, 0x2c, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x70, 0x33,
|
||||
0x3a, 0x20, 0x76, 0x65, 0x63, 0x32, 0x66, 0x2c, 0x0d, 0x0a, 0x7d, 0x0d,
|
||||
0x0a, 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x20, 0x53, 0x68, 0x61, 0x70,
|
||||
0x65, 0x4d, 0x65, 0x74, 0x61, 0x20, 0x7b, 0x0d, 0x0a, 0x20, 0x20, 0x20,
|
||||
0x20, 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f, 0x73, 0x65, 0x67, 0x6d, 0x65,
|
||||
0x6e, 0x74, 0x3a, 0x20, 0x75, 0x33, 0x32, 0x2c, 0x0d, 0x0a, 0x20, 0x20,
|
||||
0x20, 0x20, 0x73, 0x65, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x63, 0x6f,
|
||||
0x75, 0x6e, 0x74, 0x3a, 0x20, 0x75, 0x33, 0x32, 0x2c, 0x0d, 0x0a, 0x20,
|
||||
0x20, 0x20, 0x20, 0x62, 0x62, 0x6f, 0x78, 0x5f, 0x6d, 0x69, 0x6e, 0x3a,
|
||||
0x20, 0x76, 0x65, 0x63, 0x32, 0x66, 0x2c, 0x0d, 0x0a, 0x20, 0x20, 0x20,
|
||||
0x20, 0x62, 0x62, 0x6f, 0x78, 0x5f, 0x6d, 0x61, 0x78, 0x3a, 0x20, 0x76,
|
||||
0x65, 0x63, 0x32, 0x66, 0x2c, 0x0d, 0x0a, 0x7d, 0x0d, 0x0a, 0x0d, 0x0a,
|
||||
0x40, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x28, 0x31, 0x29, 0x20, 0x40, 0x62,
|
||||
0x69, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x28, 0x30, 0x29, 0x20, 0x76, 0x61,
|
||||
0x72, 0x3c, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x3e, 0x20, 0x73,
|
||||
0x65, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x3a, 0x20, 0x61, 0x72, 0x72,
|
||||
0x61, 0x79, 0x3c, 0x53, 0x65, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x3e, 0x3b,
|
||||
0x0d, 0x0a, 0x40, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x28, 0x31, 0x29, 0x20,
|
||||
0x40, 0x62, 0x69, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x28, 0x31, 0x29, 0x20,
|
||||
0x76, 0x61, 0x72, 0x3c, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x3e,
|
||||
0x20, 0x73, 0x68, 0x61, 0x70, 0x65, 0x73, 0x3a, 0x20, 0x61, 0x72, 0x72,
|
||||
0x61, 0x79, 0x3c, 0x53, 0x68, 0x61, 0x70, 0x65, 0x4d, 0x65, 0x74, 0x61,
|
||||
0x3e, 0x3b, 0x0d, 0x0a, 0x40, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x28, 0x31,
|
||||
0x29, 0x20, 0x40, 0x62, 0x69, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x28, 0x32,
|
||||
0x29, 0x20, 0x76, 0x61, 0x72, 0x3c, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67,
|
||||
0x65, 0x2c, 0x20, 0x72, 0x65, 0x61, 0x64, 0x5f, 0x77, 0x72, 0x69, 0x74,
|
||||
0x65, 0x3e, 0x20, 0x73, 0x64, 0x66, 0x5f, 0x62, 0x75, 0x66, 0x66, 0x65,
|
||||
0x72, 0x3a, 0x20, 0x61, 0x72, 0x72, 0x61, 0x79, 0x3c, 0x66, 0x33, 0x32,
|
||||
0x3e, 0x3b, 0x0d, 0x0a, 0x0d, 0x0a, 0x73, 0x74, 0x72, 0x75, 0x63, 0x74,
|
||||
0x20, 0x55, 0x6e, 0x69, 0x66, 0x6f, 0x72, 0x6d, 0x73, 0x20, 0x7b, 0x0d,
|
||||
0x0a, 0x20, 0x20, 0x20, 0x20, 0x70, 0x61, 0x6e, 0x3a, 0x20, 0x76, 0x65,
|
||||
0x63, 0x32, 0x66, 0x2c, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x7a, 0x6f,
|
||||
0x6f, 0x6d, 0x3a, 0x20, 0x66, 0x33, 0x32, 0x2c, 0x0d, 0x0a, 0x7d, 0x3b,
|
||||
0x0d, 0x0a, 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x20, 0x54, 0x69, 0x6c,
|
||||
0x65, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x20, 0x7b, 0x0d, 0x0a, 0x20,
|
||||
0x20, 0x20, 0x20, 0x6c, 0x6f, 0x64, 0x3a, 0x20, 0x75, 0x33, 0x32, 0x2c,
|
||||
0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x74, 0x69, 0x6c, 0x65, 0x5f, 0x73,
|
||||
0x69, 0x7a, 0x65, 0x3a, 0x20, 0x66, 0x33, 0x32, 0x2c, 0x0d, 0x0a, 0x20,
|
||||
0x20, 0x20, 0x20, 0x77, 0x6f, 0x72, 0x6c, 0x64, 0x5f, 0x6d, 0x69, 0x6e,
|
||||
0x3a, 0x20, 0x76, 0x65, 0x63, 0x32, 0x66, 0x2c, 0x0d, 0x0a, 0x20, 0x20,
|
||||
0x20, 0x20, 0x77, 0x6f, 0x72, 0x6c, 0x64, 0x5f, 0x6d, 0x61, 0x78, 0x3a,
|
||||
0x20, 0x76, 0x65, 0x63, 0x32, 0x66, 0x2c, 0x0d, 0x0a, 0x7d, 0x3b, 0x0d,
|
||||
0x0a, 0x0d, 0x0a, 0x40, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x28, 0x30, 0x29,
|
||||
0x20, 0x40, 0x62, 0x69, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x28, 0x30, 0x29,
|
||||
0x20, 0x76, 0x61, 0x72, 0x3c, 0x75, 0x6e, 0x69, 0x66, 0x6f, 0x72, 0x6d,
|
||||
0x3e, 0x20, 0x75, 0x6e, 0x69, 0x66, 0x6f, 0x72, 0x6d, 0x73, 0x3a, 0x20,
|
||||
0x55, 0x6e, 0x69, 0x66, 0x6f, 0x72, 0x6d, 0x73, 0x3b, 0x0d, 0x0a, 0x40,
|
||||
0x67, 0x72, 0x6f, 0x75, 0x70, 0x28, 0x30, 0x29, 0x20, 0x40, 0x62, 0x69,
|
||||
0x6e, 0x64, 0x69, 0x6e, 0x67, 0x28, 0x31, 0x29, 0x20, 0x76, 0x61, 0x72,
|
||||
0x3c, 0x75, 0x6e, 0x69, 0x66, 0x6f, 0x72, 0x6d, 0x3e, 0x20, 0x74, 0x69,
|
||||
0x6c, 0x65, 0x5f, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x3a, 0x20, 0x54,
|
||||
0x69, 0x6c, 0x65, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x3b, 0x0d, 0x0a,
|
||||
0x0d, 0x0a, 0x0d, 0x0a, 0x2f, 0x2f, 0x20, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d,
|
||||
0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x20, 0x43, 0x75, 0x62, 0x69, 0x63, 0x20,
|
||||
0x42, 0xc3, 0xa9, 0x7a, 0x69, 0x65, 0x72, 0x20, 0x68, 0x65, 0x6c, 0x70,
|
||||
0x65, 0x72, 0x73, 0x20, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d,
|
||||
0x2d, 0x2d, 0x0d, 0x0a, 0x66, 0x6e, 0x20, 0x65, 0x76, 0x61, 0x6c, 0x5f,
|
||||
0x63, 0x75, 0x62, 0x69, 0x63, 0x28, 0x74, 0x3a, 0x20, 0x66, 0x33, 0x32,
|
||||
0x2c, 0x20, 0x70, 0x30, 0x3a, 0x20, 0x76, 0x65, 0x63, 0x32, 0x66, 0x2c,
|
||||
0x20, 0x70, 0x31, 0x3a, 0x20, 0x76, 0x65, 0x63, 0x32, 0x66, 0x2c, 0x20,
|
||||
0x70, 0x32, 0x3a, 0x20, 0x76, 0x65, 0x63, 0x32, 0x66, 0x2c, 0x20, 0x70,
|
||||
0x33, 0x3a, 0x20, 0x76, 0x65, 0x63, 0x32, 0x66, 0x29, 0x20, 0x2d, 0x3e,
|
||||
0x20, 0x76, 0x65, 0x63, 0x32, 0x66, 0x20, 0x7b, 0x0d, 0x0a, 0x20, 0x20,
|
||||
0x20, 0x20, 0x6c, 0x65, 0x74, 0x20, 0x6d, 0x74, 0x20, 0x3d, 0x20, 0x31,
|
||||
0x2e, 0x30, 0x20, 0x2d, 0x20, 0x74, 0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20,
|
||||
0x20, 0x6c, 0x65, 0x74, 0x20, 0x6d, 0x74, 0x32, 0x20, 0x3d, 0x20, 0x6d,
|
||||
0x74, 0x20, 0x2a, 0x20, 0x6d, 0x74, 0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20,
|
||||
0x20, 0x6c, 0x65, 0x74, 0x20, 0x74, 0x32, 0x20, 0x3d, 0x20, 0x74, 0x20,
|
||||
0x2a, 0x20, 0x74, 0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65,
|
||||
0x74, 0x75, 0x72, 0x6e, 0x20, 0x6d, 0x74, 0x32, 0x20, 0x2a, 0x20, 0x6d,
|
||||
0x74, 0x20, 0x2a, 0x20, 0x70, 0x30, 0x20, 0x2b, 0x20, 0x33, 0x2e, 0x30,
|
||||
0x20, 0x2a, 0x20, 0x6d, 0x74, 0x32, 0x20, 0x2a, 0x20, 0x74, 0x20, 0x2a,
|
||||
0x20, 0x70, 0x31, 0x20, 0x2b, 0x20, 0x33, 0x2e, 0x30, 0x20, 0x2a, 0x20,
|
||||
0x6d, 0x74, 0x20, 0x2a, 0x20, 0x74, 0x32, 0x20, 0x2a, 0x20, 0x70, 0x32,
|
||||
0x20, 0x2b, 0x20, 0x74, 0x32, 0x20, 0x2a, 0x20, 0x74, 0x20, 0x2a, 0x20,
|
||||
0x70, 0x33, 0x3b, 0x0d, 0x0a, 0x7d, 0x0d, 0x0a, 0x0d, 0x0a, 0x66, 0x6e,
|
||||
0x20, 0x65, 0x76, 0x61, 0x6c, 0x5f, 0x63, 0x75, 0x62, 0x69, 0x63, 0x5f,
|
||||
0x64, 0x65, 0x72, 0x69, 0x76, 0x61, 0x74, 0x69, 0x76, 0x65, 0x28, 0x74,
|
||||
0x3a, 0x20, 0x66, 0x33, 0x32, 0x2c, 0x20, 0x70, 0x30, 0x3a, 0x20, 0x76,
|
||||
0x65, 0x63, 0x32, 0x66, 0x2c, 0x20, 0x70, 0x31, 0x3a, 0x20, 0x76, 0x65,
|
||||
0x63, 0x32, 0x66, 0x2c, 0x20, 0x70, 0x32, 0x3a, 0x20, 0x76, 0x65, 0x63,
|
||||
0x32, 0x66, 0x2c, 0x20, 0x70, 0x33, 0x3a, 0x20, 0x76, 0x65, 0x63, 0x32,
|
||||
0x66, 0x29, 0x20, 0x2d, 0x3e, 0x20, 0x76, 0x65, 0x63, 0x32, 0x66, 0x20,
|
||||
0x7b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x65, 0x74, 0x20, 0x6d,
|
||||
0x74, 0x20, 0x3d, 0x20, 0x31, 0x2e, 0x30, 0x20, 0x2d, 0x20, 0x74, 0x3b,
|
||||
0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e,
|
||||
0x20, 0x33, 0x2e, 0x30, 0x20, 0x2a, 0x20, 0x6d, 0x74, 0x20, 0x2a, 0x20,
|
||||
0x6d, 0x74, 0x20, 0x2a, 0x20, 0x28, 0x70, 0x31, 0x20, 0x2d, 0x20, 0x70,
|
||||
0x30, 0x29, 0x20, 0x2b, 0x20, 0x36, 0x2e, 0x30, 0x20, 0x2a, 0x20, 0x6d,
|
||||
0x74, 0x20, 0x2a, 0x20, 0x74, 0x20, 0x2a, 0x20, 0x28, 0x70, 0x32, 0x20,
|
||||
0x2d, 0x20, 0x70, 0x31, 0x29, 0x20, 0x2b, 0x20, 0x33, 0x2e, 0x30, 0x20,
|
||||
0x2a, 0x20, 0x74, 0x20, 0x2a, 0x20, 0x74, 0x20, 0x2a, 0x20, 0x28, 0x70,
|
||||
0x33, 0x20, 0x2d, 0x20, 0x70, 0x32, 0x29, 0x3b, 0x0d, 0x0a, 0x7d, 0x0d,
|
||||
0x0a, 0x0d, 0x0a, 0x2f, 0x2f, 0x20, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d,
|
||||
0x2d, 0x2d, 0x2d, 0x2d, 0x20, 0x44, 0x69, 0x73, 0x74, 0x61, 0x6e, 0x63,
|
||||
0x65, 0x20, 0x74, 0x6f, 0x20, 0x61, 0x20, 0x63, 0x75, 0x62, 0x69, 0x63,
|
||||
0x20, 0x42, 0xc3, 0xa9, 0x7a, 0x69, 0x65, 0x72, 0x20, 0x28, 0x73, 0x61,
|
||||
0x6d, 0x70, 0x6c, 0x69, 0x6e, 0x67, 0x20, 0x2b, 0x20, 0x4e, 0x65, 0x77,
|
||||
0x74, 0x6f, 0x6e, 0x20, 0x72, 0x65, 0x66, 0x69, 0x6e, 0x65, 0x6d, 0x65,
|
||||
0x6e, 0x74, 0x29, 0x20, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d,
|
||||
0x2d, 0x2d, 0x0d, 0x0a, 0x66, 0x6e, 0x20, 0x64, 0x69, 0x73, 0x74, 0x61,
|
||||
0x6e, 0x63, 0x65, 0x5f, 0x74, 0x6f, 0x5f, 0x63, 0x75, 0x62, 0x69, 0x63,
|
||||
0x28, 0x70, 0x3a, 0x20, 0x76, 0x65, 0x63, 0x32, 0x66, 0x2c, 0x20, 0x73,
|
||||
0x65, 0x67, 0x3a, 0x20, 0x53, 0x65, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x29,
|
||||
0x20, 0x2d, 0x3e, 0x20, 0x66, 0x33, 0x32, 0x20, 0x7b, 0x0d, 0x0a, 0x20,
|
||||
0x20, 0x20, 0x20, 0x6c, 0x65, 0x74, 0x20, 0x70, 0x30, 0x20, 0x3d, 0x20,
|
||||
0x73, 0x65, 0x67, 0x2e, 0x70, 0x30, 0x3b, 0x20, 0x6c, 0x65, 0x74, 0x20,
|
||||
0x70, 0x31, 0x20, 0x3d, 0x20, 0x73, 0x65, 0x67, 0x2e, 0x70, 0x31, 0x3b,
|
||||
0x20, 0x6c, 0x65, 0x74, 0x20, 0x70, 0x32, 0x20, 0x3d, 0x20, 0x73, 0x65,
|
||||
0x67, 0x2e, 0x70, 0x32, 0x3b, 0x20, 0x6c, 0x65, 0x74, 0x20, 0x70, 0x33,
|
||||
0x20, 0x3d, 0x20, 0x73, 0x65, 0x67, 0x2e, 0x70, 0x33, 0x3b, 0x0d, 0x0a,
|
||||
0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x2f, 0x2f, 0x20, 0x55, 0x6e, 0x69,
|
||||
0x66, 0x6f, 0x72, 0x6d, 0x20, 0x73, 0x61, 0x6d, 0x70, 0x6c, 0x69, 0x6e,
|
||||
0x67, 0x20, 0x74, 0x6f, 0x20, 0x66, 0x69, 0x6e, 0x64, 0x20, 0x61, 0x20,
|
||||
0x67, 0x6f, 0x6f, 0x64, 0x20, 0x73, 0x74, 0x61, 0x72, 0x74, 0x69, 0x6e,
|
||||
0x67, 0x20, 0x74, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x65, 0x74,
|
||||
0x20, 0x73, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x20, 0x3d, 0x20, 0x31,
|
||||
0x36, 0x75, 0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x76, 0x61, 0x72,
|
||||
0x20, 0x62, 0x65, 0x73, 0x74, 0x5f, 0x74, 0x20, 0x3d, 0x20, 0x30, 0x2e,
|
||||
0x30, 0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x76, 0x61, 0x72, 0x20,
|
||||
0x62, 0x65, 0x73, 0x74, 0x5f, 0x64, 0x69, 0x73, 0x74, 0x20, 0x3d, 0x20,
|
||||
0x31, 0x65, 0x32, 0x30, 0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x66,
|
||||
0x6f, 0x72, 0x20, 0x28, 0x76, 0x61, 0x72, 0x20, 0x69, 0x20, 0x3d, 0x20,
|
||||
0x30, 0x75, 0x3b, 0x20, 0x69, 0x20, 0x3c, 0x20, 0x73, 0x61, 0x6d, 0x70,
|
||||
0x6c, 0x65, 0x73, 0x3b, 0x20, 0x69, 0x2b, 0x2b, 0x29, 0x20, 0x7b, 0x0d,
|
||||
0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x65, 0x74,
|
||||
0x20, 0x74, 0x20, 0x3d, 0x20, 0x66, 0x33, 0x32, 0x28, 0x69, 0x29, 0x20,
|
||||
0x2f, 0x20, 0x66, 0x33, 0x32, 0x28, 0x73, 0x61, 0x6d, 0x70, 0x6c, 0x65,
|
||||
0x73, 0x20, 0x2d, 0x20, 0x31, 0x75, 0x29, 0x3b, 0x0d, 0x0a, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x65, 0x74, 0x20, 0x71, 0x20,
|
||||
0x3d, 0x20, 0x65, 0x76, 0x61, 0x6c, 0x5f, 0x63, 0x75, 0x62, 0x69, 0x63,
|
||||
0x28, 0x74, 0x2c, 0x20, 0x70, 0x30, 0x2c, 0x20, 0x70, 0x31, 0x2c, 0x20,
|
||||
0x70, 0x32, 0x2c, 0x20, 0x70, 0x33, 0x29, 0x3b, 0x0d, 0x0a, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x65, 0x74, 0x20, 0x64, 0x20,
|
||||
0x3d, 0x20, 0x64, 0x69, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x28, 0x70,
|
||||
0x2c, 0x20, 0x71, 0x29, 0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x64, 0x20, 0x3c, 0x20, 0x62, 0x65,
|
||||
0x73, 0x74, 0x5f, 0x64, 0x69, 0x73, 0x74, 0x20, 0x7b, 0x0d, 0x0a, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x62,
|
||||
0x65, 0x73, 0x74, 0x5f, 0x64, 0x69, 0x73, 0x74, 0x20, 0x3d, 0x20, 0x64,
|
||||
0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x62, 0x65, 0x73, 0x74, 0x5f, 0x74, 0x20, 0x3d, 0x20,
|
||||
0x74, 0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x7d, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x0d, 0x0a, 0x0d, 0x0a,
|
||||
0x20, 0x20, 0x20, 0x20, 0x2f, 0x2f, 0x20, 0x4e, 0x65, 0x77, 0x74, 0x6f,
|
||||
0x6e, 0x20, 0x72, 0x65, 0x66, 0x69, 0x6e, 0x65, 0x6d, 0x65, 0x6e, 0x74,
|
||||
0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x71, 0x75, 0x61,
|
||||
0x72, 0x65, 0x64, 0x20, 0x64, 0x69, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65,
|
||||
0x20, 0x28, 0x6d, 0x61, 0x78, 0x20, 0x34, 0x20, 0x69, 0x74, 0x65, 0x72,
|
||||
0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x29, 0x0d, 0x0a, 0x20, 0x20, 0x20,
|
||||
0x20, 0x76, 0x61, 0x72, 0x20, 0x74, 0x20, 0x3d, 0x20, 0x63, 0x6c, 0x61,
|
||||
0x6d, 0x70, 0x28, 0x62, 0x65, 0x73, 0x74, 0x5f, 0x74, 0x2c, 0x20, 0x30,
|
||||
0x2e, 0x30, 0x2c, 0x20, 0x31, 0x2e, 0x30, 0x29, 0x3b, 0x0d, 0x0a, 0x20,
|
||||
0x20, 0x20, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x28, 0x76, 0x61, 0x72, 0x20,
|
||||
0x69, 0x74, 0x65, 0x72, 0x20, 0x3d, 0x20, 0x30, 0x75, 0x3b, 0x20, 0x69,
|
||||
0x74, 0x65, 0x72, 0x20, 0x3c, 0x20, 0x34, 0x75, 0x3b, 0x20, 0x69, 0x74,
|
||||
0x65, 0x72, 0x2b, 0x2b, 0x29, 0x20, 0x7b, 0x0d, 0x0a, 0x20, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x65, 0x74, 0x20, 0x42, 0x20, 0x3d,
|
||||
0x20, 0x65, 0x76, 0x61, 0x6c, 0x5f, 0x63, 0x75, 0x62, 0x69, 0x63, 0x28,
|
||||
0x74, 0x2c, 0x20, 0x70, 0x30, 0x2c, 0x20, 0x70, 0x31, 0x2c, 0x20, 0x70,
|
||||
0x32, 0x2c, 0x20, 0x70, 0x33, 0x29, 0x20, 0x2d, 0x20, 0x70, 0x3b, 0x0d,
|
||||
0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x65, 0x74,
|
||||
0x20, 0x42, 0x70, 0x20, 0x3d, 0x20, 0x65, 0x76, 0x61, 0x6c, 0x5f, 0x63,
|
||||
0x75, 0x62, 0x69, 0x63, 0x5f, 0x64, 0x65, 0x72, 0x69, 0x76, 0x61, 0x74,
|
||||
0x69, 0x76, 0x65, 0x28, 0x74, 0x2c, 0x20, 0x70, 0x30, 0x2c, 0x20, 0x70,
|
||||
0x31, 0x2c, 0x20, 0x70, 0x32, 0x2c, 0x20, 0x70, 0x33, 0x29, 0x3b, 0x0d,
|
||||
0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x65, 0x74,
|
||||
0x20, 0x66, 0x20, 0x3d, 0x20, 0x64, 0x6f, 0x74, 0x28, 0x42, 0x2c, 0x20,
|
||||
0x42, 0x70, 0x29, 0x3b, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x2f, 0x2f, 0x20, 0xc2, 0xbd,
|
||||
0x20, 0x64, 0x65, 0x72, 0x69, 0x76, 0x61, 0x74, 0x69, 0x76, 0x65, 0x20,
|
||||
0x6f, 0x66, 0x20, 0x7c, 0x42, 0x7c, 0xc2, 0xb2, 0x0d, 0x0a, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x65, 0x74, 0x20, 0x64, 0x66,
|
||||
0x20, 0x3d, 0x20, 0x64, 0x6f, 0x74, 0x28, 0x42, 0x70, 0x2c, 0x20, 0x42,
|
||||
0x70, 0x29, 0x20, 0x2b, 0x20, 0x64, 0x6f, 0x74, 0x28, 0x42, 0x2c, 0x20,
|
||||
0x33, 0x2e, 0x30, 0x20, 0x2a, 0x20, 0x28, 0x70, 0x32, 0x20, 0x2d, 0x20,
|
||||
0x70, 0x31, 0x20, 0x2b, 0x20, 0x28, 0x70, 0x33, 0x20, 0x2d, 0x20, 0x70,
|
||||
0x32, 0x20, 0x2d, 0x20, 0x70, 0x32, 0x20, 0x2b, 0x20, 0x70, 0x31, 0x29,
|
||||
0x20, 0x2a, 0x20, 0x32, 0x2e, 0x30, 0x20, 0x2a, 0x20, 0x74, 0x29, 0x29,
|
||||
0x3b, 0x20, 0x2f, 0x2f, 0x20, 0x73, 0x69, 0x6d, 0x70, 0x6c, 0x69, 0x66,
|
||||
0x69, 0x65, 0x64, 0x20, 0x32, 0x6e, 0x64, 0x20, 0x64, 0x65, 0x72, 0x69,
|
||||
0x76, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69,
|
||||
0x66, 0x20, 0x61, 0x62, 0x73, 0x28, 0x64, 0x66, 0x29, 0x20, 0x3c, 0x20,
|
||||
0x31, 0x65, 0x2d, 0x31, 0x32, 0x20, 0x7b, 0x20, 0x62, 0x72, 0x65, 0x61,
|
||||
0x6b, 0x3b, 0x20, 0x7d, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x20, 0x20, 0x6c, 0x65, 0x74, 0x20, 0x73, 0x74, 0x65, 0x70, 0x20, 0x3d,
|
||||
0x20, 0x66, 0x20, 0x2f, 0x20, 0x64, 0x66, 0x3b, 0x0d, 0x0a, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x74, 0x20, 0x3d, 0x20, 0x63, 0x6c,
|
||||
0x61, 0x6d, 0x70, 0x28, 0x74, 0x20, 0x2d, 0x20, 0x73, 0x74, 0x65, 0x70,
|
||||
0x2c, 0x20, 0x30, 0x2e, 0x30, 0x2c, 0x20, 0x31, 0x2e, 0x30, 0x29, 0x3b,
|
||||
0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66,
|
||||
0x20, 0x61, 0x62, 0x73, 0x28, 0x73, 0x74, 0x65, 0x70, 0x29, 0x20, 0x3c,
|
||||
0x20, 0x31, 0x65, 0x2d, 0x36, 0x20, 0x7b, 0x20, 0x62, 0x72, 0x65, 0x61,
|
||||
0x6b, 0x3b, 0x20, 0x7d, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x0d,
|
||||
0x0a, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x65, 0x74, 0x20, 0x71, 0x5f, 0x66,
|
||||
0x69, 0x6e, 0x61, 0x6c, 0x20, 0x3d, 0x20, 0x65, 0x76, 0x61, 0x6c, 0x5f,
|
||||
0x63, 0x75, 0x62, 0x69, 0x63, 0x28, 0x74, 0x2c, 0x20, 0x70, 0x30, 0x2c,
|
||||
0x20, 0x70, 0x31, 0x2c, 0x20, 0x70, 0x32, 0x2c, 0x20, 0x70, 0x33, 0x29,
|
||||
0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72,
|
||||
0x6e, 0x20, 0x64, 0x69, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x28, 0x70,
|
||||
0x2c, 0x20, 0x71, 0x5f, 0x66, 0x69, 0x6e, 0x61, 0x6c, 0x29, 0x3b, 0x0d,
|
||||
0x0a, 0x7d, 0x0d, 0x0a, 0x0d, 0x0a, 0x2f, 0x2f, 0x20, 0x2d, 0x2d, 0x2d,
|
||||
0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x20, 0x41, 0x6e, 0x61, 0x6c,
|
||||
0x79, 0x74, 0x69, 0x63, 0x61, 0x6c, 0x20, 0x63, 0x75, 0x62, 0x69, 0x63,
|
||||
0x20, 0x72, 0x6f, 0x6f, 0x74, 0x20, 0x73, 0x6f, 0x6c, 0x76, 0x65, 0x72,
|
||||
0x20, 0x28, 0x66, 0x6f, 0x72, 0x20, 0x79, 0x2d, 0x63, 0x72, 0x6f, 0x73,
|
||||
0x73, 0x69, 0x6e, 0x67, 0x29, 0x20, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d,
|
||||
0x2d, 0x2d, 0x2d, 0x2d, 0x0d, 0x0a, 0x2f, 0x2f, 0x20, 0x52, 0x65, 0x74,
|
||||
0x75, 0x72, 0x6e, 0x73, 0x20, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x20,
|
||||
0x6f, 0x66, 0x20, 0x72, 0x65, 0x61, 0x6c, 0x20, 0x72, 0x6f, 0x6f, 0x74,
|
||||
0x73, 0x20, 0x69, 0x6e, 0x20, 0x5b, 0x30, 0x2c, 0x31, 0x5d, 0x2c, 0x20,
|
||||
0x73, 0x74, 0x6f, 0x72, 0x65, 0x64, 0x20, 0x69, 0x6e, 0x20, 0x72, 0x6f,
|
||||
0x6f, 0x74, 0x73, 0x20, 0x61, 0x72, 0x72, 0x61, 0x79, 0x20, 0x28, 0x75,
|
||||
0x70, 0x20, 0x74, 0x6f, 0x20, 0x33, 0x29, 0x2e, 0x0d, 0x0a, 0x66, 0x6e,
|
||||
0x20, 0x73, 0x6f, 0x6c, 0x76, 0x65, 0x5f, 0x63, 0x75, 0x62, 0x69, 0x63,
|
||||
0x5f, 0x69, 0x6e, 0x5f, 0x30, 0x31, 0x28, 0x63, 0x33, 0x3a, 0x20, 0x66,
|
||||
0x33, 0x32, 0x2c, 0x20, 0x63, 0x32, 0x3a, 0x20, 0x66, 0x33, 0x32, 0x2c,
|
||||
0x20, 0x63, 0x31, 0x3a, 0x20, 0x66, 0x33, 0x32, 0x2c, 0x20, 0x63, 0x30,
|
||||
0x3a, 0x20, 0x66, 0x33, 0x32, 0x2c, 0x20, 0x72, 0x6f, 0x6f, 0x74, 0x73,
|
||||
0x3a, 0x20, 0x70, 0x74, 0x72, 0x3c, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69,
|
||||
0x6f, 0x6e, 0x2c, 0x20, 0x61, 0x72, 0x72, 0x61, 0x79, 0x3c, 0x66, 0x33,
|
||||
0x32, 0x2c, 0x20, 0x33, 0x3e, 0x3e, 0x29, 0x20, 0x2d, 0x3e, 0x20, 0x75,
|
||||
0x33, 0x32, 0x20, 0x7b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x2f, 0x2f,
|
||||
0x20, 0x4e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x69, 0x73, 0x65, 0x3a, 0x20,
|
||||
0x63, 0x33, 0x20, 0x2a, 0x20, 0x74, 0x5e, 0x33, 0x20, 0x2b, 0x20, 0x63,
|
||||
0x32, 0x20, 0x2a, 0x20, 0x74, 0x5e, 0x32, 0x20, 0x2b, 0x20, 0x63, 0x31,
|
||||
0x20, 0x2a, 0x20, 0x74, 0x20, 0x2b, 0x20, 0x63, 0x30, 0x20, 0x3d, 0x20,
|
||||
0x30, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x61, 0x62,
|
||||
0x73, 0x28, 0x63, 0x33, 0x29, 0x20, 0x3c, 0x20, 0x31, 0x65, 0x2d, 0x39,
|
||||
0x20, 0x7b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x2f, 0x2f, 0x20, 0x51, 0x75, 0x61, 0x64, 0x72, 0x61, 0x74, 0x69, 0x63,
|
||||
0x20, 0x66, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x0d, 0x0a, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x61, 0x62,
|
||||
0x73, 0x28, 0x63, 0x32, 0x29, 0x20, 0x3c, 0x20, 0x31, 0x65, 0x2d, 0x39,
|
||||
0x20, 0x7b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x61, 0x62, 0x73, 0x28, 0x63,
|
||||
0x31, 0x29, 0x20, 0x3c, 0x20, 0x31, 0x65, 0x2d, 0x39, 0x20, 0x7b, 0x20,
|
||||
0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x30, 0x75, 0x3b, 0x20, 0x7d,
|
||||
0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x20, 0x20, 0x6c, 0x65, 0x74, 0x20, 0x74, 0x20, 0x3d, 0x20, 0x2d, 0x63,
|
||||
0x30, 0x20, 0x2f, 0x20, 0x63, 0x31, 0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20,
|
||||
0x74, 0x20, 0x3e, 0x3d, 0x20, 0x30, 0x2e, 0x30, 0x20, 0x26, 0x26, 0x20,
|
||||
0x74, 0x20, 0x3c, 0x3d, 0x20, 0x31, 0x2e, 0x30, 0x20, 0x7b, 0x0d, 0x0a,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x28, 0x2a, 0x72, 0x6f, 0x6f, 0x74, 0x73, 0x29,
|
||||
0x5b, 0x30, 0x5d, 0x20, 0x3d, 0x20, 0x74, 0x3b, 0x0d, 0x0a, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x31, 0x75, 0x3b,
|
||||
0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x20, 0x20, 0x7d, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20,
|
||||
0x30, 0x75, 0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x20, 0x7d, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x6c, 0x65, 0x74, 0x20, 0x64, 0x69, 0x73, 0x63, 0x20, 0x3d, 0x20, 0x63,
|
||||
0x31, 0x20, 0x2a, 0x20, 0x63, 0x31, 0x20, 0x2d, 0x20, 0x34, 0x2e, 0x30,
|
||||
0x20, 0x2a, 0x20, 0x63, 0x32, 0x20, 0x2a, 0x20, 0x63, 0x30, 0x3b, 0x0d,
|
||||
0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20,
|
||||
0x64, 0x69, 0x73, 0x63, 0x20, 0x3c, 0x20, 0x30, 0x2e, 0x30, 0x20, 0x7b,
|
||||
0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x30, 0x75, 0x3b, 0x20,
|
||||
0x7d, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6c,
|
||||
0x65, 0x74, 0x20, 0x73, 0x64, 0x20, 0x3d, 0x20, 0x73, 0x71, 0x72, 0x74,
|
||||
0x28, 0x64, 0x69, 0x73, 0x63, 0x29, 0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x65, 0x74, 0x20, 0x74, 0x30, 0x20,
|
||||
0x3d, 0x20, 0x28, 0x2d, 0x63, 0x31, 0x20, 0x2b, 0x20, 0x73, 0x64, 0x29,
|
||||
0x20, 0x2f, 0x20, 0x28, 0x32, 0x2e, 0x30, 0x20, 0x2a, 0x20, 0x63, 0x32,
|
||||
0x29, 0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x6c, 0x65, 0x74, 0x20, 0x74, 0x31, 0x20, 0x3d, 0x20, 0x28, 0x2d, 0x63,
|
||||
0x31, 0x20, 0x2d, 0x20, 0x73, 0x64, 0x29, 0x20, 0x2f, 0x20, 0x28, 0x32,
|
||||
0x2e, 0x30, 0x20, 0x2a, 0x20, 0x63, 0x32, 0x29, 0x3b, 0x0d, 0x0a, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x76, 0x61, 0x72, 0x20, 0x63,
|
||||
0x6f, 0x75, 0x6e, 0x74, 0x20, 0x3d, 0x20, 0x30, 0x75, 0x3b, 0x0d, 0x0a,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x74,
|
||||
0x30, 0x20, 0x3e, 0x3d, 0x20, 0x30, 0x2e, 0x30, 0x20, 0x26, 0x26, 0x20,
|
||||
0x74, 0x30, 0x20, 0x3c, 0x3d, 0x20, 0x31, 0x2e, 0x30, 0x20, 0x7b, 0x20,
|
||||
0x28, 0x2a, 0x72, 0x6f, 0x6f, 0x74, 0x73, 0x29, 0x5b, 0x63, 0x6f, 0x75,
|
||||
0x6e, 0x74, 0x5d, 0x20, 0x3d, 0x20, 0x74, 0x30, 0x3b, 0x20, 0x63, 0x6f,
|
||||
0x75, 0x6e, 0x74, 0x2b, 0x2b, 0x3b, 0x20, 0x7d, 0x0d, 0x0a, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x74, 0x31, 0x20,
|
||||
0x3e, 0x3d, 0x20, 0x30, 0x2e, 0x30, 0x20, 0x26, 0x26, 0x20, 0x74, 0x31,
|
||||
0x20, 0x3c, 0x3d, 0x20, 0x31, 0x2e, 0x30, 0x20, 0x7b, 0x20, 0x28, 0x2a,
|
||||
0x72, 0x6f, 0x6f, 0x74, 0x73, 0x29, 0x5b, 0x63, 0x6f, 0x75, 0x6e, 0x74,
|
||||
0x5d, 0x20, 0x3d, 0x20, 0x74, 0x31, 0x3b, 0x20, 0x63, 0x6f, 0x75, 0x6e,
|
||||
0x74, 0x2b, 0x2b, 0x3b, 0x20, 0x7d, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x63,
|
||||
0x6f, 0x75, 0x6e, 0x74, 0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x7d,
|
||||
0x0d, 0x0a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x2f, 0x2f, 0x20, 0x44,
|
||||
0x65, 0x70, 0x72, 0x65, 0x73, 0x73, 0x65, 0x64, 0x20, 0x63, 0x75, 0x62,
|
||||
0x69, 0x63, 0x3a, 0x20, 0x6c, 0x65, 0x74, 0x20, 0x74, 0x20, 0x3d, 0x20,
|
||||
0x78, 0x20, 0x2d, 0x20, 0x63, 0x32, 0x2f, 0x28, 0x33, 0x2a, 0x63, 0x33,
|
||||
0x29, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x65, 0x74, 0x20, 0x61,
|
||||
0x20, 0x3d, 0x20, 0x63, 0x32, 0x20, 0x2f, 0x20, 0x63, 0x33, 0x3b, 0x0d,
|
||||
0x0a, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x65, 0x74, 0x20, 0x62, 0x20, 0x3d,
|
||||
0x20, 0x63, 0x31, 0x20, 0x2f, 0x20, 0x63, 0x33, 0x3b, 0x0d, 0x0a, 0x20,
|
||||
0x20, 0x20, 0x20, 0x6c, 0x65, 0x74, 0x20, 0x63, 0x20, 0x3d, 0x20, 0x63,
|
||||
0x30, 0x20, 0x2f, 0x20, 0x63, 0x33, 0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20,
|
||||
0x20, 0x6c, 0x65, 0x74, 0x20, 0x70, 0x20, 0x3d, 0x20, 0x62, 0x20, 0x2d,
|
||||
0x20, 0x61, 0x20, 0x2a, 0x20, 0x61, 0x20, 0x2f, 0x20, 0x33, 0x2e, 0x30,
|
||||
0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x65, 0x74, 0x20, 0x71,
|
||||
0x20, 0x3d, 0x20, 0x32, 0x2e, 0x30, 0x20, 0x2a, 0x20, 0x61, 0x20, 0x2a,
|
||||
0x20, 0x61, 0x20, 0x2a, 0x20, 0x61, 0x20, 0x2f, 0x20, 0x32, 0x37, 0x2e,
|
||||
0x30, 0x20, 0x2d, 0x20, 0x61, 0x20, 0x2a, 0x20, 0x62, 0x20, 0x2f, 0x20,
|
||||
0x33, 0x2e, 0x30, 0x20, 0x2b, 0x20, 0x63, 0x3b, 0x0d, 0x0a, 0x20, 0x20,
|
||||
0x20, 0x20, 0x6c, 0x65, 0x74, 0x20, 0x64, 0x69, 0x73, 0x63, 0x20, 0x3d,
|
||||
0x20, 0x71, 0x20, 0x2a, 0x20, 0x71, 0x20, 0x2f, 0x20, 0x34, 0x2e, 0x30,
|
||||
0x20, 0x2b, 0x20, 0x70, 0x20, 0x2a, 0x20, 0x70, 0x20, 0x2a, 0x20, 0x70,
|
||||
0x20, 0x2f, 0x20, 0x32, 0x37, 0x2e, 0x30, 0x3b, 0x0d, 0x0a, 0x0d, 0x0a,
|
||||
0x20, 0x20, 0x20, 0x20, 0x76, 0x61, 0x72, 0x20, 0x63, 0x6f, 0x75, 0x6e,
|
||||
0x74, 0x20, 0x3d, 0x20, 0x30, 0x75, 0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20,
|
||||
0x20, 0x6c, 0x65, 0x74, 0x20, 0x73, 0x68, 0x69, 0x66, 0x74, 0x20, 0x3d,
|
||||
0x20, 0x61, 0x20, 0x2f, 0x20, 0x33, 0x2e, 0x30, 0x3b, 0x0d, 0x0a, 0x0d,
|
||||
0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x64, 0x69, 0x73, 0x63,
|
||||
0x20, 0x3e, 0x20, 0x30, 0x2e, 0x30, 0x20, 0x7b, 0x0d, 0x0a, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x65, 0x74, 0x20, 0x73, 0x64,
|
||||
0x20, 0x3d, 0x20, 0x73, 0x71, 0x72, 0x74, 0x28, 0x64, 0x69, 0x73, 0x63,
|
||||
0x29, 0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x6c, 0x65, 0x74, 0x20, 0x75, 0x20, 0x3d, 0x20, 0x73, 0x69, 0x67, 0x6e,
|
||||
0x28, 0x2d, 0x71, 0x2f, 0x32, 0x2e, 0x30, 0x20, 0x2b, 0x20, 0x73, 0x64,
|
||||
0x29, 0x20, 0x2a, 0x20, 0x70, 0x6f, 0x77, 0x28, 0x61, 0x62, 0x73, 0x28,
|
||||
0x2d, 0x71, 0x2f, 0x32, 0x2e, 0x30, 0x20, 0x2b, 0x20, 0x73, 0x64, 0x29,
|
||||
0x2c, 0x20, 0x31, 0x2e, 0x30, 0x2f, 0x33, 0x2e, 0x30, 0x29, 0x3b, 0x0d,
|
||||
0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x65, 0x74,
|
||||
0x20, 0x76, 0x20, 0x3d, 0x20, 0x73, 0x69, 0x67, 0x6e, 0x28, 0x2d, 0x71,
|
||||
0x2f, 0x32, 0x2e, 0x30, 0x20, 0x2d, 0x20, 0x73, 0x64, 0x29, 0x20, 0x2a,
|
||||
0x20, 0x70, 0x6f, 0x77, 0x28, 0x61, 0x62, 0x73, 0x28, 0x2d, 0x71, 0x2f,
|
||||
0x32, 0x2e, 0x30, 0x20, 0x2d, 0x20, 0x73, 0x64, 0x29, 0x2c, 0x20, 0x31,
|
||||
0x2e, 0x30, 0x2f, 0x33, 0x2e, 0x30, 0x29, 0x3b, 0x0d, 0x0a, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x65, 0x74, 0x20, 0x78, 0x31,
|
||||
0x20, 0x3d, 0x20, 0x75, 0x20, 0x2b, 0x20, 0x76, 0x3b, 0x0d, 0x0a, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x65, 0x74, 0x20, 0x74,
|
||||
0x20, 0x3d, 0x20, 0x78, 0x31, 0x20, 0x2d, 0x20, 0x73, 0x68, 0x69, 0x66,
|
||||
0x74, 0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x69, 0x66, 0x20, 0x74, 0x20, 0x3e, 0x3d, 0x20, 0x30, 0x2e, 0x30, 0x20,
|
||||
0x26, 0x26, 0x20, 0x74, 0x20, 0x3c, 0x3d, 0x20, 0x31, 0x2e, 0x30, 0x20,
|
||||
0x7b, 0x20, 0x28, 0x2a, 0x72, 0x6f, 0x6f, 0x74, 0x73, 0x29, 0x5b, 0x63,
|
||||
0x6f, 0x75, 0x6e, 0x74, 0x5d, 0x20, 0x3d, 0x20, 0x74, 0x3b, 0x20, 0x63,
|
||||
0x6f, 0x75, 0x6e, 0x74, 0x2b, 0x2b, 0x3b, 0x20, 0x7d, 0x0d, 0x0a, 0x20,
|
||||
0x20, 0x20, 0x20, 0x7d, 0x20, 0x65, 0x6c, 0x73, 0x65, 0x20, 0x69, 0x66,
|
||||
0x20, 0x64, 0x69, 0x73, 0x63, 0x20, 0x3d, 0x3d, 0x20, 0x30, 0x2e, 0x30,
|
||||
0x20, 0x7b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x6c, 0x65, 0x74, 0x20, 0x75, 0x20, 0x3d, 0x20, 0x73, 0x69, 0x67, 0x6e,
|
||||
0x28, 0x2d, 0x71, 0x2f, 0x32, 0x2e, 0x30, 0x29, 0x20, 0x2a, 0x20, 0x70,
|
||||
0x6f, 0x77, 0x28, 0x61, 0x62, 0x73, 0x28, 0x2d, 0x71, 0x2f, 0x32, 0x2e,
|
||||
0x30, 0x29, 0x2c, 0x20, 0x31, 0x2e, 0x30, 0x2f, 0x33, 0x2e, 0x30, 0x29,
|
||||
0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6c,
|
||||
0x65, 0x74, 0x20, 0x78, 0x31, 0x20, 0x3d, 0x20, 0x32, 0x2e, 0x30, 0x20,
|
||||
0x2a, 0x20, 0x75, 0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x20, 0x20, 0x6c, 0x65, 0x74, 0x20, 0x78, 0x32, 0x20, 0x3d, 0x20, 0x2d,
|
||||
0x75, 0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x6c, 0x65, 0x74, 0x20, 0x74, 0x31, 0x20, 0x3d, 0x20, 0x78, 0x31, 0x20,
|
||||
0x2d, 0x20, 0x73, 0x68, 0x69, 0x66, 0x74, 0x3b, 0x0d, 0x0a, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x65, 0x74, 0x20, 0x74, 0x32,
|
||||
0x20, 0x3d, 0x20, 0x78, 0x32, 0x20, 0x2d, 0x20, 0x73, 0x68, 0x69, 0x66,
|
||||
0x74, 0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x69, 0x66, 0x20, 0x74, 0x31, 0x20, 0x3e, 0x3d, 0x20, 0x30, 0x2e, 0x30,
|
||||
0x20, 0x26, 0x26, 0x20, 0x74, 0x31, 0x20, 0x3c, 0x3d, 0x20, 0x31, 0x2e,
|
||||
0x30, 0x20, 0x7b, 0x20, 0x28, 0x2a, 0x72, 0x6f, 0x6f, 0x74, 0x73, 0x29,
|
||||
0x5b, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x5d, 0x20, 0x3d, 0x20, 0x74, 0x31,
|
||||
0x3b, 0x20, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x2b, 0x2b, 0x3b, 0x20, 0x7d,
|
||||
0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66,
|
||||
0x20, 0x74, 0x32, 0x20, 0x3e, 0x3d, 0x20, 0x30, 0x2e, 0x30, 0x20, 0x26,
|
||||
0x26, 0x20, 0x74, 0x32, 0x20, 0x3c, 0x3d, 0x20, 0x31, 0x2e, 0x30, 0x20,
|
||||
0x7b, 0x20, 0x28, 0x2a, 0x72, 0x6f, 0x6f, 0x74, 0x73, 0x29, 0x5b, 0x63,
|
||||
0x6f, 0x75, 0x6e, 0x74, 0x5d, 0x20, 0x3d, 0x20, 0x74, 0x32, 0x3b, 0x20,
|
||||
0x63, 0x6f, 0x75, 0x6e, 0x74, 0x2b, 0x2b, 0x3b, 0x20, 0x7d, 0x0d, 0x0a,
|
||||
0x20, 0x20, 0x20, 0x20, 0x7d, 0x20, 0x65, 0x6c, 0x73, 0x65, 0x20, 0x7b,
|
||||
0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x65,
|
||||
0x74, 0x20, 0x70, 0x68, 0x69, 0x20, 0x3d, 0x20, 0x61, 0x63, 0x6f, 0x73,
|
||||
0x28, 0x20, 0x2d, 0x71, 0x20, 0x2f, 0x20, 0x28, 0x32, 0x2e, 0x30, 0x20,
|
||||
0x2a, 0x20, 0x73, 0x71, 0x72, 0x74, 0x28, 0x2d, 0x70, 0x2a, 0x70, 0x2a,
|
||||
0x70, 0x2f, 0x32, 0x37, 0x2e, 0x30, 0x29, 0x29, 0x20, 0x29, 0x3b, 0x0d,
|
||||
0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x65, 0x74,
|
||||
0x20, 0x72, 0x20, 0x3d, 0x20, 0x32, 0x2e, 0x30, 0x20, 0x2a, 0x20, 0x73,
|
||||
0x71, 0x72, 0x74, 0x28, 0x2d, 0x70, 0x2f, 0x33, 0x2e, 0x30, 0x29, 0x3b,
|
||||
0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x66, 0x6f,
|
||||
0x72, 0x20, 0x28, 0x76, 0x61, 0x72, 0x20, 0x6b, 0x20, 0x3d, 0x20, 0x30,
|
||||
0x75, 0x3b, 0x20, 0x6b, 0x20, 0x3c, 0x20, 0x33, 0x75, 0x3b, 0x20, 0x6b,
|
||||
0x2b, 0x2b, 0x29, 0x20, 0x7b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x65, 0x74, 0x20, 0x78,
|
||||
0x20, 0x3d, 0x20, 0x72, 0x20, 0x2a, 0x20, 0x63, 0x6f, 0x73, 0x28, 0x28,
|
||||
0x70, 0x68, 0x69, 0x20, 0x2b, 0x20, 0x32, 0x2e, 0x30, 0x20, 0x2a, 0x20,
|
||||
0x33, 0x2e, 0x31, 0x34, 0x31, 0x35, 0x39, 0x32, 0x36, 0x35, 0x33, 0x35,
|
||||
0x20, 0x2a, 0x20, 0x66, 0x33, 0x32, 0x28, 0x6b, 0x29, 0x29, 0x20, 0x2f,
|
||||
0x20, 0x33, 0x2e, 0x30, 0x29, 0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x65, 0x74, 0x20,
|
||||
0x74, 0x20, 0x3d, 0x20, 0x78, 0x20, 0x2d, 0x20, 0x73, 0x68, 0x69, 0x66,
|
||||
0x74, 0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x74, 0x20, 0x3e, 0x3d, 0x20,
|
||||
0x30, 0x2e, 0x30, 0x20, 0x26, 0x26, 0x20, 0x74, 0x20, 0x3c, 0x3d, 0x20,
|
||||
0x31, 0x2e, 0x30, 0x20, 0x7b, 0x20, 0x28, 0x2a, 0x72, 0x6f, 0x6f, 0x74,
|
||||
0x73, 0x29, 0x5b, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x5d, 0x20, 0x3d, 0x20,
|
||||
0x74, 0x3b, 0x20, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x2b, 0x2b, 0x3b, 0x20,
|
||||
0x7d, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7d,
|
||||
0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x0d, 0x0a, 0x20, 0x20, 0x20,
|
||||
0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x63, 0x6f, 0x75, 0x6e,
|
||||
0x74, 0x3b, 0x0d, 0x0a, 0x7d, 0x0d, 0x0a, 0x0d, 0x0a, 0x2f, 0x2f, 0x20,
|
||||
0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x20, 0x57,
|
||||
0x69, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x20, 0x6e, 0x75, 0x6d, 0x62, 0x65,
|
||||
0x72, 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x69,
|
||||
0x6f, 0x6e, 0x20, 0x66, 0x72, 0x6f, 0x6d, 0x20, 0x6f, 0x6e, 0x65, 0x20,
|
||||
0x63, 0x75, 0x62, 0x69, 0x63, 0x20, 0x73, 0x65, 0x67, 0x6d, 0x65, 0x6e,
|
||||
0x74, 0x20, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d,
|
||||
0x0d, 0x0a, 0x66, 0x6e, 0x20, 0x72, 0x61, 0x79, 0x5f, 0x69, 0x6e, 0x74,
|
||||
0x65, 0x72, 0x73, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x5f, 0x63,
|
||||
0x75, 0x62, 0x69, 0x63, 0x28, 0x70, 0x3a, 0x20, 0x76, 0x65, 0x63, 0x32,
|
||||
0x66, 0x2c, 0x20, 0x73, 0x65, 0x67, 0x3a, 0x20, 0x53, 0x65, 0x67, 0x6d,
|
||||
0x65, 0x6e, 0x74, 0x29, 0x20, 0x2d, 0x3e, 0x20, 0x69, 0x33, 0x32, 0x20,
|
||||
0x7b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x2f, 0x2f, 0x20, 0x57, 0x65,
|
||||
0x20, 0x63, 0x61, 0x73, 0x74, 0x20, 0x61, 0x20, 0x68, 0x6f, 0x72, 0x69,
|
||||
0x7a, 0x6f, 0x6e, 0x74, 0x61, 0x6c, 0x20, 0x72, 0x61, 0x79, 0x20, 0x66,
|
||||
0x72, 0x6f, 0x6d, 0x20, 0x70, 0x20, 0x74, 0x6f, 0x20, 0x2b, 0x78, 0x3b,
|
||||
0x20, 0x66, 0x69, 0x6e, 0x64, 0x20, 0x74, 0x20, 0x77, 0x68, 0x65, 0x72,
|
||||
0x65, 0x20, 0x79, 0x28, 0x74, 0x29, 0x20, 0x3d, 0x20, 0x70, 0x2e, 0x79,
|
||||
0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x65, 0x74, 0x20, 0x79, 0x30,
|
||||
0x20, 0x3d, 0x20, 0x73, 0x65, 0x67, 0x2e, 0x70, 0x30, 0x2e, 0x79, 0x20,
|
||||
0x2d, 0x20, 0x70, 0x2e, 0x79, 0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20,
|
||||
0x6c, 0x65, 0x74, 0x20, 0x79, 0x31, 0x20, 0x3d, 0x20, 0x73, 0x65, 0x67,
|
||||
0x2e, 0x70, 0x31, 0x2e, 0x79, 0x20, 0x2d, 0x20, 0x70, 0x2e, 0x79, 0x3b,
|
||||
0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x65, 0x74, 0x20, 0x79, 0x32,
|
||||
0x20, 0x3d, 0x20, 0x73, 0x65, 0x67, 0x2e, 0x70, 0x32, 0x2e, 0x79, 0x20,
|
||||
0x2d, 0x20, 0x70, 0x2e, 0x79, 0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20,
|
||||
0x6c, 0x65, 0x74, 0x20, 0x79, 0x33, 0x20, 0x3d, 0x20, 0x73, 0x65, 0x67,
|
||||
0x2e, 0x70, 0x33, 0x2e, 0x79, 0x20, 0x2d, 0x20, 0x70, 0x2e, 0x79, 0x3b,
|
||||
0x0d, 0x0a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x2f, 0x2f, 0x20, 0x79,
|
||||
0x28, 0x74, 0x29, 0x20, 0x3d, 0x20, 0x28, 0x31, 0x2d, 0x74, 0x29, 0x5e,
|
||||
0x33, 0x2a, 0x79, 0x30, 0x20, 0x2b, 0x20, 0x33, 0x28, 0x31, 0x2d, 0x74,
|
||||
0x29, 0x5e, 0x32, 0x20, 0x74, 0x20, 0x2a, 0x20, 0x79, 0x31, 0x20, 0x2b,
|
||||
0x20, 0x33, 0x28, 0x31, 0x2d, 0x74, 0x29, 0x20, 0x74, 0x5e, 0x32, 0x20,
|
||||
0x2a, 0x20, 0x79, 0x32, 0x20, 0x2b, 0x20, 0x74, 0x5e, 0x33, 0x20, 0x2a,
|
||||
0x20, 0x79, 0x33, 0x20, 0x3d, 0x20, 0x30, 0x0d, 0x0a, 0x20, 0x20, 0x20,
|
||||
0x20, 0x2f, 0x2f, 0x20, 0x45, 0x78, 0x70, 0x61, 0x6e, 0x64, 0x20, 0x70,
|
||||
0x6f, 0x6c, 0x79, 0x6e, 0x6f, 0x6d, 0x69, 0x61, 0x6c, 0x3a, 0x20, 0x63,
|
||||
0x33, 0x20, 0x74, 0x5e, 0x33, 0x20, 0x2b, 0x20, 0x63, 0x32, 0x20, 0x74,
|
||||
0x5e, 0x32, 0x20, 0x2b, 0x20, 0x63, 0x31, 0x20, 0x74, 0x20, 0x2b, 0x20,
|
||||
0x63, 0x30, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x65, 0x74, 0x20,
|
||||
0x63, 0x30, 0x20, 0x3d, 0x20, 0x79, 0x30, 0x3b, 0x0d, 0x0a, 0x20, 0x20,
|
||||
0x20, 0x20, 0x6c, 0x65, 0x74, 0x20, 0x63, 0x31, 0x20, 0x3d, 0x20, 0x33,
|
||||
0x2e, 0x30, 0x20, 0x2a, 0x20, 0x28, 0x79, 0x31, 0x20, 0x2d, 0x20, 0x79,
|
||||
0x30, 0x29, 0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x65, 0x74,
|
||||
0x20, 0x63, 0x32, 0x20, 0x3d, 0x20, 0x33, 0x2e, 0x30, 0x20, 0x2a, 0x20,
|
||||
0x28, 0x79, 0x32, 0x20, 0x2d, 0x20, 0x32, 0x2e, 0x30, 0x20, 0x2a, 0x20,
|
||||
0x79, 0x31, 0x20, 0x2b, 0x20, 0x79, 0x30, 0x29, 0x3b, 0x0d, 0x0a, 0x20,
|
||||
0x20, 0x20, 0x20, 0x6c, 0x65, 0x74, 0x20, 0x63, 0x33, 0x20, 0x3d, 0x20,
|
||||
0x79, 0x33, 0x20, 0x2d, 0x20, 0x33, 0x2e, 0x30, 0x20, 0x2a, 0x20, 0x79,
|
||||
0x32, 0x20, 0x2b, 0x20, 0x33, 0x2e, 0x30, 0x20, 0x2a, 0x20, 0x79, 0x31,
|
||||
0x20, 0x2d, 0x20, 0x79, 0x30, 0x3b, 0x0d, 0x0a, 0x0d, 0x0a, 0x20, 0x20,
|
||||
0x20, 0x20, 0x76, 0x61, 0x72, 0x20, 0x72, 0x6f, 0x6f, 0x74, 0x73, 0x3a,
|
||||
0x20, 0x61, 0x72, 0x72, 0x61, 0x79, 0x3c, 0x66, 0x33, 0x32, 0x2c, 0x20,
|
||||
0x33, 0x3e, 0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x65, 0x74,
|
||||
0x20, 0x6e, 0x75, 0x6d, 0x20, 0x3d, 0x20, 0x73, 0x6f, 0x6c, 0x76, 0x65,
|
||||
0x5f, 0x63, 0x75, 0x62, 0x69, 0x63, 0x5f, 0x69, 0x6e, 0x5f, 0x30, 0x31,
|
||||
0x28, 0x63, 0x33, 0x2c, 0x20, 0x63, 0x32, 0x2c, 0x20, 0x63, 0x31, 0x2c,
|
||||
0x20, 0x63, 0x30, 0x2c, 0x20, 0x26, 0x72, 0x6f, 0x6f, 0x74, 0x73, 0x29,
|
||||
0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x76, 0x61, 0x72, 0x20, 0x77,
|
||||
0x69, 0x6e, 0x64, 0x20, 0x3d, 0x20, 0x30, 0x69, 0x3b, 0x0d, 0x0a, 0x20,
|
||||
0x20, 0x20, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x28, 0x76, 0x61, 0x72, 0x20,
|
||||
0x69, 0x20, 0x3d, 0x20, 0x30, 0x75, 0x3b, 0x20, 0x69, 0x20, 0x3c, 0x20,
|
||||
0x6e, 0x75, 0x6d, 0x3b, 0x20, 0x69, 0x2b, 0x2b, 0x29, 0x20, 0x7b, 0x0d,
|
||||
0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x65, 0x74,
|
||||
0x20, 0x74, 0x20, 0x3d, 0x20, 0x72, 0x6f, 0x6f, 0x74, 0x73, 0x5b, 0x69,
|
||||
0x5d, 0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x6c, 0x65, 0x74, 0x20, 0x78, 0x20, 0x3d, 0x20, 0x65, 0x76, 0x61, 0x6c,
|
||||
0x5f, 0x63, 0x75, 0x62, 0x69, 0x63, 0x28, 0x74, 0x2c, 0x20, 0x73, 0x65,
|
||||
0x67, 0x2e, 0x70, 0x30, 0x2c, 0x20, 0x73, 0x65, 0x67, 0x2e, 0x70, 0x31,
|
||||
0x2c, 0x20, 0x73, 0x65, 0x67, 0x2e, 0x70, 0x32, 0x2c, 0x20, 0x73, 0x65,
|
||||
0x67, 0x2e, 0x70, 0x33, 0x29, 0x2e, 0x78, 0x3b, 0x0d, 0x0a, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x78, 0x20, 0x3e,
|
||||
0x20, 0x70, 0x2e, 0x78, 0x20, 0x7b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x65, 0x74, 0x20,
|
||||
0x64, 0x79, 0x20, 0x3d, 0x20, 0x65, 0x76, 0x61, 0x6c, 0x5f, 0x63, 0x75,
|
||||
0x62, 0x69, 0x63, 0x5f, 0x64, 0x65, 0x72, 0x69, 0x76, 0x61, 0x74, 0x69,
|
||||
0x76, 0x65, 0x28, 0x74, 0x2c, 0x20, 0x73, 0x65, 0x67, 0x2e, 0x70, 0x30,
|
||||
0x2c, 0x20, 0x73, 0x65, 0x67, 0x2e, 0x70, 0x31, 0x2c, 0x20, 0x73, 0x65,
|
||||
0x67, 0x2e, 0x70, 0x32, 0x2c, 0x20, 0x73, 0x65, 0x67, 0x2e, 0x70, 0x33,
|
||||
0x29, 0x2e, 0x79, 0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x64, 0x79, 0x20,
|
||||
0x3e, 0x20, 0x30, 0x2e, 0x30, 0x20, 0x7b, 0x20, 0x77, 0x69, 0x6e, 0x64,
|
||||
0x20, 0x2b, 0x3d, 0x20, 0x31, 0x69, 0x3b, 0x20, 0x7d, 0x0d, 0x0a, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x65,
|
||||
0x6c, 0x73, 0x65, 0x20, 0x69, 0x66, 0x20, 0x64, 0x79, 0x20, 0x3c, 0x20,
|
||||
0x30, 0x2e, 0x30, 0x20, 0x7b, 0x20, 0x77, 0x69, 0x6e, 0x64, 0x20, 0x2d,
|
||||
0x3d, 0x20, 0x31, 0x69, 0x3b, 0x20, 0x7d, 0x0d, 0x0a, 0x20, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20,
|
||||
0x7d, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72,
|
||||
0x6e, 0x20, 0x77, 0x69, 0x6e, 0x64, 0x3b, 0x0d, 0x0a, 0x7d, 0x0d, 0x0a,
|
||||
0x0d, 0x0a, 0x2f, 0x2f, 0x20, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d,
|
||||
0x2d, 0x2d, 0x2d, 0x20, 0x4d, 0x61, 0x69, 0x6e, 0x20, 0x63, 0x6f, 0x6d,
|
||||
0x70, 0x75, 0x74, 0x65, 0x20, 0x73, 0x68, 0x61, 0x64, 0x65, 0x72, 0x20,
|
||||
0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0d, 0x0a,
|
||||
0x40, 0x63, 0x6f, 0x6d, 0x70, 0x75, 0x74, 0x65, 0x20, 0x40, 0x77, 0x6f,
|
||||
0x72, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x5f, 0x73, 0x69, 0x7a, 0x65,
|
||||
0x28, 0x38, 0x2c, 0x20, 0x38, 0x29, 0x0d, 0x0a, 0x66, 0x6e, 0x20, 0x6d,
|
||||
0x61, 0x69, 0x6e, 0x28, 0x40, 0x62, 0x75, 0x69, 0x6c, 0x74, 0x69, 0x6e,
|
||||
0x28, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x5f, 0x69, 0x6e, 0x76, 0x6f,
|
||||
0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x29, 0x20, 0x69,
|
||||
0x64, 0x3a, 0x20, 0x76, 0x65, 0x63, 0x33, 0x3c, 0x75, 0x33, 0x32, 0x3e,
|
||||
0x29, 0x20, 0x7b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x65, 0x74,
|
||||
0x20, 0x74, 0x69, 0x6c, 0x65, 0x5f, 0x64, 0x69, 0x6d, 0x20, 0x3d, 0x20,
|
||||
0x76, 0x65, 0x63, 0x32, 0x66, 0x28, 0x74, 0x69, 0x6c, 0x65, 0x5f, 0x70,
|
||||
0x61, 0x72, 0x61, 0x6d, 0x73, 0x2e, 0x74, 0x69, 0x6c, 0x65, 0x5f, 0x73,
|
||||
0x69, 0x7a, 0x65, 0x29, 0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69,
|
||||
0x66, 0x20, 0x69, 0x64, 0x2e, 0x78, 0x20, 0x3e, 0x3d, 0x20, 0x75, 0x33,
|
||||
0x32, 0x28, 0x74, 0x69, 0x6c, 0x65, 0x5f, 0x64, 0x69, 0x6d, 0x2e, 0x78,
|
||||
0x29, 0x20, 0x7c, 0x7c, 0x20, 0x69, 0x64, 0x2e, 0x79, 0x20, 0x3e, 0x3d,
|
||||
0x20, 0x75, 0x33, 0x32, 0x28, 0x74, 0x69, 0x6c, 0x65, 0x5f, 0x64, 0x69,
|
||||
0x6d, 0x2e, 0x79, 0x29, 0x20, 0x7b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x3b, 0x0d,
|
||||
0x0a, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x0d, 0x0a, 0x0d, 0x0a, 0x20, 0x20,
|
||||
0x20, 0x20, 0x2f, 0x2f, 0x20, 0x50, 0x69, 0x78, 0x65, 0x6c, 0x20, 0x63,
|
||||
0x65, 0x6e, 0x74, 0x65, 0x72, 0x20, 0x55, 0x56, 0x2c, 0x20, 0x74, 0x68,
|
||||
0x65, 0x6e, 0x20, 0x6d, 0x61, 0x70, 0x20, 0x74, 0x6f, 0x20, 0x77, 0x6f,
|
||||
0x72, 0x6c, 0x64, 0x20, 0x73, 0x70, 0x61, 0x63, 0x65, 0x0d, 0x0a, 0x20,
|
||||
0x20, 0x20, 0x20, 0x6c, 0x65, 0x74, 0x20, 0x75, 0x76, 0x20, 0x3d, 0x20,
|
||||
0x28, 0x76, 0x65, 0x63, 0x32, 0x66, 0x28, 0x69, 0x64, 0x2e, 0x78, 0x79,
|
||||
0x29, 0x20, 0x2b, 0x20, 0x30, 0x2e, 0x35, 0x29, 0x20, 0x2f, 0x20, 0x74,
|
||||
0x69, 0x6c, 0x65, 0x5f, 0x64, 0x69, 0x6d, 0x3b, 0x0d, 0x0a, 0x20, 0x20,
|
||||
0x20, 0x20, 0x6c, 0x65, 0x74, 0x20, 0x77, 0x6f, 0x72, 0x6c, 0x64, 0x20,
|
||||
0x3d, 0x20, 0x6d, 0x69, 0x78, 0x28, 0x74, 0x69, 0x6c, 0x65, 0x5f, 0x70,
|
||||
0x61, 0x72, 0x61, 0x6d, 0x73, 0x2e, 0x77, 0x6f, 0x72, 0x6c, 0x64, 0x5f,
|
||||
0x6d, 0x69, 0x6e, 0x2c, 0x20, 0x74, 0x69, 0x6c, 0x65, 0x5f, 0x70, 0x61,
|
||||
0x72, 0x61, 0x6d, 0x73, 0x2e, 0x77, 0x6f, 0x72, 0x6c, 0x64, 0x5f, 0x6d,
|
||||
0x61, 0x78, 0x2c, 0x20, 0x75, 0x76, 0x29, 0x3b, 0x0d, 0x0a, 0x0d, 0x0a,
|
||||
0x20, 0x20, 0x20, 0x20, 0x76, 0x61, 0x72, 0x20, 0x6d, 0x69, 0x6e, 0x44,
|
||||
0x69, 0x73, 0x74, 0x3a, 0x20, 0x66, 0x33, 0x32, 0x20, 0x3d, 0x20, 0x31,
|
||||
0x65, 0x32, 0x30, 0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x76, 0x61,
|
||||
0x72, 0x20, 0x77, 0x69, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x3a, 0x20, 0x69,
|
||||
0x33, 0x32, 0x20, 0x3d, 0x20, 0x30, 0x3b, 0x0d, 0x0a, 0x0d, 0x0a, 0x20,
|
||||
0x20, 0x20, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x28, 0x76, 0x61, 0x72, 0x20,
|
||||
0x73, 0x20, 0x3d, 0x20, 0x30, 0x75, 0x3b, 0x20, 0x73, 0x20, 0x3c, 0x20,
|
||||
0x61, 0x72, 0x72, 0x61, 0x79, 0x4c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x28,
|
||||
0x26, 0x73, 0x68, 0x61, 0x70, 0x65, 0x73, 0x29, 0x3b, 0x20, 0x73, 0x2b,
|
||||
0x2b, 0x29, 0x20, 0x7b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x20, 0x20, 0x6c, 0x65, 0x74, 0x20, 0x73, 0x68, 0x61, 0x70, 0x65, 0x20,
|
||||
0x3d, 0x20, 0x73, 0x68, 0x61, 0x70, 0x65, 0x73, 0x5b, 0x73, 0x5d, 0x3b,
|
||||
0x0d, 0x0a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x2f, 0x2f, 0x20, 0x51, 0x75, 0x69, 0x63, 0x6b, 0x20, 0x62, 0x62, 0x6f,
|
||||
0x78, 0x20, 0x63, 0x75, 0x6c, 0x6c, 0x69, 0x6e, 0x67, 0x20, 0x69, 0x6e,
|
||||
0x20, 0x77, 0x6f, 0x72, 0x6c, 0x64, 0x20, 0x73, 0x70, 0x61, 0x63, 0x65,
|
||||
0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x65,
|
||||
0x74, 0x20, 0x62, 0x62, 0x6f, 0x78, 0x5f, 0x6d, 0x69, 0x6e, 0x20, 0x3d,
|
||||
0x20, 0x73, 0x68, 0x61, 0x70, 0x65, 0x2e, 0x62, 0x62, 0x6f, 0x78, 0x5f,
|
||||
0x6d, 0x69, 0x6e, 0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x20, 0x20, 0x6c, 0x65, 0x74, 0x20, 0x62, 0x62, 0x6f, 0x78, 0x5f, 0x6d,
|
||||
0x61, 0x78, 0x20, 0x3d, 0x20, 0x73, 0x68, 0x61, 0x70, 0x65, 0x2e, 0x62,
|
||||
0x62, 0x6f, 0x78, 0x5f, 0x6d, 0x61, 0x78, 0x3b, 0x0d, 0x0a, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x65, 0x74, 0x20, 0x64, 0x78,
|
||||
0x20, 0x3d, 0x20, 0x6d, 0x61, 0x78, 0x28, 0x62, 0x62, 0x6f, 0x78, 0x5f,
|
||||
0x6d, 0x69, 0x6e, 0x2e, 0x78, 0x20, 0x2d, 0x20, 0x77, 0x6f, 0x72, 0x6c,
|
||||
0x64, 0x2e, 0x78, 0x2c, 0x20, 0x6d, 0x61, 0x78, 0x28, 0x30, 0x2e, 0x30,
|
||||
0x2c, 0x20, 0x77, 0x6f, 0x72, 0x6c, 0x64, 0x2e, 0x78, 0x20, 0x2d, 0x20,
|
||||
0x62, 0x62, 0x6f, 0x78, 0x5f, 0x6d, 0x61, 0x78, 0x2e, 0x78, 0x29, 0x29,
|
||||
0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6c,
|
||||
0x65, 0x74, 0x20, 0x64, 0x79, 0x20, 0x3d, 0x20, 0x6d, 0x61, 0x78, 0x28,
|
||||
0x62, 0x62, 0x6f, 0x78, 0x5f, 0x6d, 0x69, 0x6e, 0x2e, 0x79, 0x20, 0x2d,
|
||||
0x20, 0x77, 0x6f, 0x72, 0x6c, 0x64, 0x2e, 0x79, 0x2c, 0x20, 0x6d, 0x61,
|
||||
0x78, 0x28, 0x30, 0x2e, 0x30, 0x2c, 0x20, 0x77, 0x6f, 0x72, 0x6c, 0x64,
|
||||
0x2e, 0x79, 0x20, 0x2d, 0x20, 0x62, 0x62, 0x6f, 0x78, 0x5f, 0x6d, 0x61,
|
||||
0x78, 0x2e, 0x79, 0x29, 0x29, 0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x6c, 0x65, 0x74, 0x20, 0x64, 0x69, 0x73, 0x74,
|
||||
0x5f, 0x74, 0x6f, 0x5f, 0x62, 0x6f, 0x78, 0x20, 0x3d, 0x20, 0x73, 0x71,
|
||||
0x72, 0x74, 0x28, 0x64, 0x78, 0x20, 0x2a, 0x20, 0x64, 0x78, 0x20, 0x2b,
|
||||
0x20, 0x64, 0x79, 0x20, 0x2a, 0x20, 0x64, 0x79, 0x29, 0x3b, 0x0d, 0x0a,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x64,
|
||||
0x69, 0x73, 0x74, 0x5f, 0x74, 0x6f, 0x5f, 0x62, 0x6f, 0x78, 0x20, 0x3e,
|
||||
0x3d, 0x20, 0x6d, 0x69, 0x6e, 0x44, 0x69, 0x73, 0x74, 0x20, 0x7b, 0x0d,
|
||||
0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x20, 0x63, 0x6f, 0x6e, 0x74, 0x69, 0x6e, 0x75, 0x65, 0x3b, 0x20, 0x20,
|
||||
0x20, 0x2f, 0x2f, 0x20, 0x54, 0x68, 0x69, 0x73, 0x20, 0x73, 0x68, 0x61,
|
||||
0x70, 0x65, 0x20, 0x63, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x20, 0x69, 0x6d,
|
||||
0x70, 0x72, 0x6f, 0x76, 0x65, 0x20, 0x74, 0x68, 0x65, 0x20, 0x64, 0x69,
|
||||
0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x7d, 0x0d, 0x0a, 0x0d, 0x0a, 0x20, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x2f, 0x2f, 0x20, 0x50, 0x72, 0x6f, 0x63,
|
||||
0x65, 0x73, 0x73, 0x20, 0x61, 0x6c, 0x6c, 0x20, 0x73, 0x65, 0x67, 0x6d,
|
||||
0x65, 0x6e, 0x74, 0x73, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20,
|
||||
0x73, 0x68, 0x61, 0x70, 0x65, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x28, 0x76, 0x61, 0x72, 0x20,
|
||||
0x69, 0x20, 0x3d, 0x20, 0x73, 0x68, 0x61, 0x70, 0x65, 0x2e, 0x73, 0x74,
|
||||
0x61, 0x72, 0x74, 0x5f, 0x73, 0x65, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x3b,
|
||||
0x20, 0x69, 0x20, 0x3c, 0x20, 0x73, 0x68, 0x61, 0x70, 0x65, 0x2e, 0x73,
|
||||
0x74, 0x61, 0x72, 0x74, 0x5f, 0x73, 0x65, 0x67, 0x6d, 0x65, 0x6e, 0x74,
|
||||
0x20, 0x2b, 0x20, 0x73, 0x68, 0x61, 0x70, 0x65, 0x2e, 0x73, 0x65, 0x67,
|
||||
0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x3b, 0x20,
|
||||
0x69, 0x2b, 0x2b, 0x29, 0x20, 0x7b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x65, 0x74, 0x20,
|
||||
0x73, 0x65, 0x67, 0x20, 0x3d, 0x20, 0x73, 0x65, 0x67, 0x6d, 0x65, 0x6e,
|
||||
0x74, 0x73, 0x5b, 0x69, 0x5d, 0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x65, 0x74, 0x20,
|
||||
0x64, 0x20, 0x3d, 0x20, 0x64, 0x69, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65,
|
||||
0x5f, 0x74, 0x6f, 0x5f, 0x63, 0x75, 0x62, 0x69, 0x63, 0x28, 0x77, 0x6f,
|
||||
0x72, 0x6c, 0x64, 0x2c, 0x20, 0x73, 0x65, 0x67, 0x29, 0x3b, 0x0d, 0x0a,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x6d, 0x69, 0x6e, 0x44, 0x69, 0x73, 0x74, 0x20, 0x3d, 0x20, 0x6d, 0x69,
|
||||
0x6e, 0x28, 0x6d, 0x69, 0x6e, 0x44, 0x69, 0x73, 0x74, 0x2c, 0x20, 0x64,
|
||||
0x29, 0x3b, 0x0d, 0x0a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x77, 0x69, 0x6e, 0x64, 0x69, 0x6e,
|
||||
0x67, 0x20, 0x2b, 0x3d, 0x20, 0x72, 0x61, 0x79, 0x5f, 0x69, 0x6e, 0x74,
|
||||
0x65, 0x72, 0x73, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x5f, 0x63,
|
||||
0x75, 0x62, 0x69, 0x63, 0x28, 0x77, 0x6f, 0x72, 0x6c, 0x64, 0x2c, 0x20,
|
||||
0x73, 0x65, 0x67, 0x29, 0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x7d, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x0d,
|
||||
0x0a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x65, 0x74, 0x20, 0x73,
|
||||
0x69, 0x67, 0x6e, 0x20, 0x3d, 0x20, 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74,
|
||||
0x28, 0x31, 0x2e, 0x30, 0x2c, 0x20, 0x2d, 0x31, 0x2e, 0x30, 0x2c, 0x20,
|
||||
0x77, 0x69, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x20, 0x21, 0x3d, 0x20, 0x30,
|
||||
0x69, 0x29, 0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x65, 0x74,
|
||||
0x20, 0x73, 0x64, 0x66, 0x20, 0x3d, 0x20, 0x73, 0x69, 0x67, 0x6e, 0x20,
|
||||
0x2a, 0x20, 0x6d, 0x69, 0x6e, 0x44, 0x69, 0x73, 0x74, 0x3b, 0x0d, 0x0a,
|
||||
0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x73, 0x64, 0x66, 0x5f, 0x62, 0x75,
|
||||
0x66, 0x66, 0x65, 0x72, 0x5b, 0x69, 0x64, 0x2e, 0x79, 0x20, 0x2a, 0x20,
|
||||
0x75, 0x33, 0x32, 0x28, 0x74, 0x69, 0x6c, 0x65, 0x5f, 0x70, 0x61, 0x72,
|
||||
0x61, 0x6d, 0x73, 0x2e, 0x74, 0x69, 0x6c, 0x65, 0x5f, 0x73, 0x69, 0x7a,
|
||||
0x65, 0x29, 0x20, 0x2b, 0x20, 0x69, 0x64, 0x2e, 0x78, 0x5d, 0x20, 0x3d,
|
||||
0x20, 0x73, 0x64, 0x66, 0x3b, 0x0d, 0x0a, 0x7d
|
||||
};
|
||||
unsigned int src_shaders_compute_wgsl_len = 7484;
|
||||
53
src/generated/display.h
Normal file
53
src/generated/display.h
Normal file
@@ -0,0 +1,53 @@
|
||||
unsigned char src_shaders_display_wgsl[] = {
|
||||
0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x20, 0x55, 0x6e, 0x69, 0x66, 0x6f,
|
||||
0x72, 0x6d, 0x73, 0x20, 0x7b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x70,
|
||||
0x61, 0x6e, 0x3a, 0x20, 0x76, 0x65, 0x63, 0x32, 0x66, 0x2c, 0x0d, 0x0a,
|
||||
0x20, 0x20, 0x20, 0x20, 0x7a, 0x6f, 0x6f, 0x6d, 0x3a, 0x20, 0x66, 0x33,
|
||||
0x32, 0x2c, 0x0d, 0x0a, 0x7d, 0x0d, 0x0a, 0x73, 0x74, 0x72, 0x75, 0x63,
|
||||
0x74, 0x20, 0x54, 0x69, 0x6c, 0x65, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73,
|
||||
0x20, 0x7b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x64, 0x3a,
|
||||
0x20, 0x75, 0x33, 0x32, 0x2c, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x74,
|
||||
0x69, 0x6c, 0x65, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x3a, 0x20, 0x66, 0x33,
|
||||
0x32, 0x2c, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x77, 0x6f, 0x72, 0x6c,
|
||||
0x64, 0x5f, 0x6d, 0x69, 0x6e, 0x3a, 0x20, 0x76, 0x65, 0x63, 0x32, 0x66,
|
||||
0x2c, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x77, 0x6f, 0x72, 0x6c, 0x64,
|
||||
0x5f, 0x6d, 0x61, 0x78, 0x3a, 0x20, 0x76, 0x65, 0x63, 0x32, 0x66, 0x2c,
|
||||
0x0d, 0x0a, 0x7d, 0x0d, 0x0a, 0x0d, 0x0a, 0x40, 0x67, 0x72, 0x6f, 0x75,
|
||||
0x70, 0x28, 0x30, 0x29, 0x20, 0x40, 0x62, 0x69, 0x6e, 0x64, 0x69, 0x6e,
|
||||
0x67, 0x28, 0x30, 0x29, 0x20, 0x76, 0x61, 0x72, 0x3c, 0x75, 0x6e, 0x69,
|
||||
0x66, 0x6f, 0x72, 0x6d, 0x3e, 0x20, 0x75, 0x6e, 0x69, 0x66, 0x6f, 0x72,
|
||||
0x6d, 0x73, 0x3a, 0x20, 0x55, 0x6e, 0x69, 0x66, 0x6f, 0x72, 0x6d, 0x73,
|
||||
0x3b, 0x0d, 0x0a, 0x40, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x28, 0x30, 0x29,
|
||||
0x20, 0x40, 0x62, 0x69, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x28, 0x31, 0x29,
|
||||
0x20, 0x76, 0x61, 0x72, 0x3c, 0x75, 0x6e, 0x69, 0x66, 0x6f, 0x72, 0x6d,
|
||||
0x3e, 0x20, 0x74, 0x69, 0x6c, 0x65, 0x5f, 0x70, 0x61, 0x72, 0x61, 0x6d,
|
||||
0x73, 0x3a, 0x20, 0x54, 0x69, 0x6c, 0x65, 0x50, 0x61, 0x72, 0x61, 0x6d,
|
||||
0x73, 0x3b, 0x0d, 0x0a, 0x0d, 0x0a, 0x40, 0x76, 0x65, 0x72, 0x74, 0x65,
|
||||
0x78, 0x20, 0x66, 0x6e, 0x20, 0x76, 0x73, 0x5f, 0x6d, 0x61, 0x69, 0x6e,
|
||||
0x28, 0x40, 0x62, 0x75, 0x69, 0x6c, 0x74, 0x69, 0x6e, 0x28, 0x76, 0x65,
|
||||
0x72, 0x74, 0x65, 0x78, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x29, 0x20,
|
||||
0x76, 0x65, 0x72, 0x74, 0x65, 0x78, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78,
|
||||
0x20, 0x3a, 0x20, 0x75, 0x33, 0x32, 0x29, 0x20, 0x2d, 0x3e, 0x20, 0x40,
|
||||
0x62, 0x75, 0x69, 0x6c, 0x74, 0x69, 0x6e, 0x28, 0x70, 0x6f, 0x73, 0x69,
|
||||
0x74, 0x69, 0x6f, 0x6e, 0x29, 0x20, 0x76, 0x65, 0x63, 0x34, 0x66, 0x20,
|
||||
0x7b, 0x0d, 0x0a, 0x20, 0x20, 0x63, 0x6f, 0x6e, 0x73, 0x74, 0x20, 0x70,
|
||||
0x6f, 0x73, 0x20, 0x3d, 0x20, 0x61, 0x72, 0x72, 0x61, 0x79, 0x28, 0x0d,
|
||||
0x0a, 0x20, 0x20, 0x20, 0x20, 0x76, 0x65, 0x63, 0x32, 0x28, 0x20, 0x30,
|
||||
0x2e, 0x30, 0x2c, 0x20, 0x20, 0x30, 0x2e, 0x35, 0x29, 0x2c, 0x0d, 0x0a,
|
||||
0x20, 0x20, 0x20, 0x20, 0x76, 0x65, 0x63, 0x32, 0x28, 0x2d, 0x30, 0x2e,
|
||||
0x35, 0x2c, 0x20, 0x2d, 0x30, 0x2e, 0x35, 0x29, 0x2c, 0x0d, 0x0a, 0x20,
|
||||
0x20, 0x20, 0x20, 0x76, 0x65, 0x63, 0x32, 0x28, 0x20, 0x30, 0x2e, 0x35,
|
||||
0x2c, 0x20, 0x2d, 0x30, 0x2e, 0x35, 0x29, 0x0d, 0x0a, 0x20, 0x20, 0x29,
|
||||
0x3b, 0x0d, 0x0a, 0x0d, 0x0a, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72,
|
||||
0x6e, 0x20, 0x76, 0x65, 0x63, 0x34, 0x66, 0x28, 0x70, 0x6f, 0x73, 0x5b,
|
||||
0x76, 0x65, 0x72, 0x74, 0x65, 0x78, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78,
|
||||
0x5d, 0x2c, 0x20, 0x30, 0x2c, 0x20, 0x31, 0x29, 0x3b, 0x0d, 0x0a, 0x7d,
|
||||
0x0d, 0x0a, 0x0d, 0x0a, 0x40, 0x66, 0x72, 0x61, 0x67, 0x6d, 0x65, 0x6e,
|
||||
0x74, 0x20, 0x66, 0x6e, 0x20, 0x66, 0x73, 0x5f, 0x6d, 0x61, 0x69, 0x6e,
|
||||
0x28, 0x29, 0x20, 0x2d, 0x3e, 0x20, 0x40, 0x6c, 0x6f, 0x63, 0x61, 0x74,
|
||||
0x69, 0x6f, 0x6e, 0x28, 0x30, 0x29, 0x20, 0x76, 0x65, 0x63, 0x34, 0x66,
|
||||
0x20, 0x7b, 0x0d, 0x0a, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e,
|
||||
0x20, 0x76, 0x65, 0x63, 0x34, 0x28, 0x31, 0x2c, 0x20, 0x30, 0x2c, 0x20,
|
||||
0x30, 0x2c, 0x20, 0x31, 0x29, 0x3b, 0x0d, 0x0a, 0x7d, 0x0d, 0x0a
|
||||
};
|
||||
unsigned int src_shaders_display_wgsl_len = 599;
|
||||
@@ -1,91 +0,0 @@
|
||||
unsigned char src_shaders_overlay_wgsl[] = {
|
||||
0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x20, 0x56, 0x73, 0x55, 0x6e, 0x69,
|
||||
0x66, 0x6f, 0x72, 0x6d, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6d,
|
||||
0x76, 0x70, 0x3a, 0x20, 0x6d, 0x61, 0x74, 0x34, 0x78, 0x34, 0x66, 0x2c,
|
||||
0x0a, 0x7d, 0x3b, 0x0a, 0x0a, 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x20,
|
||||
0x53, 0x68, 0x61, 0x70, 0x65, 0x55, 0x6e, 0x69, 0x66, 0x6f, 0x72, 0x6d,
|
||||
0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x74, 0x72, 0x61, 0x6e, 0x73,
|
||||
0x66, 0x6f, 0x72, 0x6d, 0x3a, 0x20, 0x6d, 0x61, 0x74, 0x34, 0x78, 0x34,
|
||||
0x66, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x73, 0x74, 0x61, 0x74, 0x65,
|
||||
0x3a, 0x20, 0x75, 0x33, 0x32, 0x2c, 0x0a, 0x7d, 0x3b, 0x0a, 0x0a, 0x73,
|
||||
0x74, 0x72, 0x75, 0x63, 0x74, 0x20, 0x56, 0x73, 0x49, 0x6e, 0x20, 0x7b,
|
||||
0x0a, 0x20, 0x20, 0x20, 0x20, 0x40, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69,
|
||||
0x6f, 0x6e, 0x28, 0x30, 0x29, 0x20, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69,
|
||||
0x6f, 0x6e, 0x3a, 0x20, 0x76, 0x65, 0x63, 0x32, 0x66, 0x2c, 0x0a, 0x7d,
|
||||
0x3b, 0x0a, 0x0a, 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x20, 0x56, 0x73,
|
||||
0x32, 0x46, 0x73, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x40, 0x62,
|
||||
0x75, 0x69, 0x6c, 0x74, 0x69, 0x6e, 0x28, 0x70, 0x6f, 0x73, 0x69, 0x74,
|
||||
0x69, 0x6f, 0x6e, 0x29, 0x20, 0x70, 0x6f, 0x73, 0x3a, 0x20, 0x76, 0x65,
|
||||
0x63, 0x34, 0x66, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x40, 0x6c, 0x6f,
|
||||
0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x30, 0x29, 0x20, 0x40, 0x69,
|
||||
0x6e, 0x74, 0x65, 0x72, 0x70, 0x6f, 0x6c, 0x61, 0x74, 0x65, 0x28, 0x6c,
|
||||
0x69, 0x6e, 0x65, 0x61, 0x72, 0x29, 0x20, 0x63, 0x6f, 0x6c, 0x6f, 0x72,
|
||||
0x3a, 0x20, 0x76, 0x65, 0x63, 0x34, 0x66, 0x2c, 0x0a, 0x7d, 0x3b, 0x0a,
|
||||
0x0a, 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x20, 0x46, 0x73, 0x4f, 0x75,
|
||||
0x74, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x40, 0x6c, 0x6f, 0x63,
|
||||
0x61, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x30, 0x29, 0x20, 0x63, 0x6f, 0x6c,
|
||||
0x6f, 0x72, 0x3a, 0x20, 0x76, 0x65, 0x63, 0x34, 0x66, 0x2c, 0x0a, 0x7d,
|
||||
0x3b, 0x0a, 0x0a, 0x40, 0x62, 0x69, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x28,
|
||||
0x30, 0x29, 0x20, 0x40, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x28, 0x30, 0x29,
|
||||
0x20, 0x76, 0x61, 0x72, 0x3c, 0x75, 0x6e, 0x69, 0x66, 0x6f, 0x72, 0x6d,
|
||||
0x3e, 0x20, 0x76, 0x73, 0x5f, 0x75, 0x6e, 0x69, 0x66, 0x6f, 0x72, 0x6d,
|
||||
0x73, 0x3a, 0x20, 0x56, 0x73, 0x55, 0x6e, 0x69, 0x66, 0x6f, 0x72, 0x6d,
|
||||
0x3b, 0x0a, 0x40, 0x62, 0x69, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x28, 0x31,
|
||||
0x29, 0x20, 0x40, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x28, 0x30, 0x29, 0x20,
|
||||
0x76, 0x61, 0x72, 0x3c, 0x75, 0x6e, 0x69, 0x66, 0x6f, 0x72, 0x6d, 0x3e,
|
||||
0x20, 0x73, 0x68, 0x61, 0x70, 0x65, 0x5f, 0x75, 0x6e, 0x69, 0x66, 0x6f,
|
||||
0x72, 0x6d, 0x3a, 0x20, 0x53, 0x68, 0x61, 0x70, 0x65, 0x55, 0x6e, 0x69,
|
||||
0x66, 0x6f, 0x72, 0x6d, 0x3b, 0x0a, 0x0a, 0x40, 0x76, 0x65, 0x72, 0x74,
|
||||
0x65, 0x78, 0x20, 0x66, 0x6e, 0x20, 0x76, 0x73, 0x5f, 0x6d, 0x61, 0x69,
|
||||
0x6e, 0x28, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x3a, 0x20, 0x56, 0x73, 0x49,
|
||||
0x6e, 0x29, 0x20, 0x2d, 0x3e, 0x20, 0x56, 0x73, 0x32, 0x46, 0x73, 0x20,
|
||||
0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x76, 0x61, 0x72, 0x20, 0x6f, 0x75,
|
||||
0x74, 0x70, 0x75, 0x74, 0x3a, 0x20, 0x56, 0x73, 0x32, 0x46, 0x73, 0x3b,
|
||||
0x0a, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x65, 0x74, 0x20, 0x77, 0x6f, 0x72,
|
||||
0x6c, 0x64, 0x5f, 0x70, 0x6f, 0x73, 0x20, 0x3d, 0x20, 0x73, 0x68, 0x61,
|
||||
0x70, 0x65, 0x5f, 0x75, 0x6e, 0x69, 0x66, 0x6f, 0x72, 0x6d, 0x2e, 0x74,
|
||||
0x72, 0x61, 0x6e, 0x73, 0x66, 0x6f, 0x72, 0x6d, 0x20, 0x2a, 0x20, 0x76,
|
||||
0x65, 0x63, 0x34, 0x66, 0x28, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x2e, 0x70,
|
||||
0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x78, 0x2c, 0x20, 0x69,
|
||||
0x6e, 0x70, 0x75, 0x74, 0x2e, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f,
|
||||
0x6e, 0x2e, 0x79, 0x2c, 0x20, 0x30, 0x2e, 0x30, 0x2c, 0x20, 0x31, 0x2e,
|
||||
0x30, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6f, 0x75, 0x74, 0x70,
|
||||
0x75, 0x74, 0x2e, 0x70, 0x6f, 0x73, 0x20, 0x3d, 0x20, 0x76, 0x73, 0x5f,
|
||||
0x75, 0x6e, 0x69, 0x66, 0x6f, 0x72, 0x6d, 0x73, 0x2e, 0x6d, 0x76, 0x70,
|
||||
0x20, 0x2a, 0x20, 0x77, 0x6f, 0x72, 0x6c, 0x64, 0x5f, 0x70, 0x6f, 0x73,
|
||||
0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x28, 0x73, 0x68,
|
||||
0x61, 0x70, 0x65, 0x5f, 0x75, 0x6e, 0x69, 0x66, 0x6f, 0x72, 0x6d, 0x2e,
|
||||
0x73, 0x74, 0x61, 0x74, 0x65, 0x20, 0x3d, 0x3d, 0x20, 0x32, 0x75, 0x29,
|
||||
0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6f,
|
||||
0x75, 0x74, 0x70, 0x75, 0x74, 0x2e, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x20,
|
||||
0x3d, 0x20, 0x76, 0x65, 0x63, 0x34, 0x66, 0x28, 0x31, 0x2e, 0x30, 0x2c,
|
||||
0x20, 0x30, 0x2e, 0x38, 0x34, 0x2c, 0x20, 0x30, 0x2e, 0x30, 0x2c, 0x20,
|
||||
0x31, 0x2e, 0x30, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x20,
|
||||
0x65, 0x6c, 0x73, 0x65, 0x20, 0x69, 0x66, 0x20, 0x28, 0x73, 0x68, 0x61,
|
||||
0x70, 0x65, 0x5f, 0x75, 0x6e, 0x69, 0x66, 0x6f, 0x72, 0x6d, 0x2e, 0x73,
|
||||
0x74, 0x61, 0x74, 0x65, 0x20, 0x3d, 0x3d, 0x20, 0x31, 0x75, 0x29, 0x20,
|
||||
0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6f, 0x75,
|
||||
0x74, 0x70, 0x75, 0x74, 0x2e, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x20, 0x3d,
|
||||
0x20, 0x76, 0x65, 0x63, 0x34, 0x66, 0x28, 0x30, 0x2e, 0x35, 0x2c, 0x20,
|
||||
0x30, 0x2e, 0x36, 0x2c, 0x20, 0x31, 0x2e, 0x30, 0x2c, 0x20, 0x31, 0x2e,
|
||||
0x30, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x20, 0x65, 0x6c,
|
||||
0x73, 0x65, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x20, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x2e, 0x63, 0x6f, 0x6c, 0x6f,
|
||||
0x72, 0x20, 0x3d, 0x20, 0x76, 0x65, 0x63, 0x34, 0x66, 0x28, 0x30, 0x2e,
|
||||
0x38, 0x2c, 0x20, 0x30, 0x2e, 0x38, 0x2c, 0x20, 0x30, 0x2e, 0x38, 0x2c,
|
||||
0x20, 0x31, 0x2e, 0x30, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x7d,
|
||||
0x0a, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20,
|
||||
0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x3b, 0x0a, 0x7d, 0x0a, 0x0a, 0x40,
|
||||
0x66, 0x72, 0x61, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x20, 0x66, 0x6e, 0x20,
|
||||
0x66, 0x73, 0x5f, 0x6d, 0x61, 0x69, 0x6e, 0x28, 0x69, 0x6e, 0x70, 0x75,
|
||||
0x74, 0x3a, 0x20, 0x56, 0x73, 0x32, 0x46, 0x73, 0x29, 0x20, 0x2d, 0x3e,
|
||||
0x20, 0x46, 0x73, 0x4f, 0x75, 0x74, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20,
|
||||
0x20, 0x76, 0x61, 0x72, 0x20, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x3a,
|
||||
0x20, 0x46, 0x73, 0x4f, 0x75, 0x74, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20,
|
||||
0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x2e, 0x63, 0x6f, 0x6c, 0x6f, 0x72,
|
||||
0x20, 0x3d, 0x20, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x2e, 0x63, 0x6f, 0x6c,
|
||||
0x6f, 0x72, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75,
|
||||
0x72, 0x6e, 0x20, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x3b, 0x0a, 0x7d,
|
||||
0x0a
|
||||
};
|
||||
unsigned int src_shaders_overlay_wgsl_len = 1045;
|
||||
@@ -1,110 +0,0 @@
|
||||
unsigned char src_shaders_shape_wgsl[] = {
|
||||
0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x20, 0x56, 0x73, 0x55, 0x6e, 0x69,
|
||||
0x66, 0x6f, 0x72, 0x6d, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6d,
|
||||
0x76, 0x70, 0x3a, 0x20, 0x6d, 0x61, 0x74, 0x34, 0x78, 0x34, 0x66, 0x2c,
|
||||
0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63,
|
||||
0x65, 0x5f, 0x62, 0x61, 0x73, 0x65, 0x3a, 0x20, 0x75, 0x33, 0x32, 0x2c,
|
||||
0x0a, 0x7d, 0x3b, 0x0a, 0x0a, 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x20,
|
||||
0x53, 0x68, 0x61, 0x70, 0x65, 0x44, 0x61, 0x74, 0x61, 0x20, 0x7b, 0x0a,
|
||||
0x20, 0x20, 0x20, 0x20, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x6f, 0x72,
|
||||
0x6d, 0x3a, 0x20, 0x6d, 0x61, 0x74, 0x34, 0x78, 0x34, 0x66, 0x2c, 0x0a,
|
||||
0x20, 0x20, 0x20, 0x20, 0x73, 0x74, 0x61, 0x74, 0x65, 0x3a, 0x20, 0x75,
|
||||
0x33, 0x32, 0x2c, 0x0a, 0x7d, 0x3b, 0x0a, 0x0a, 0x40, 0x62, 0x69, 0x6e,
|
||||
0x64, 0x69, 0x6e, 0x67, 0x28, 0x30, 0x29, 0x20, 0x40, 0x67, 0x72, 0x6f,
|
||||
0x75, 0x70, 0x28, 0x30, 0x29, 0x20, 0x76, 0x61, 0x72, 0x3c, 0x75, 0x6e,
|
||||
0x69, 0x66, 0x6f, 0x72, 0x6d, 0x3e, 0x20, 0x76, 0x73, 0x5f, 0x75, 0x6e,
|
||||
0x69, 0x66, 0x6f, 0x72, 0x6d, 0x73, 0x3a, 0x20, 0x56, 0x73, 0x55, 0x6e,
|
||||
0x69, 0x66, 0x6f, 0x72, 0x6d, 0x3b, 0x0a, 0x0a, 0x40, 0x62, 0x69, 0x6e,
|
||||
0x64, 0x69, 0x6e, 0x67, 0x28, 0x30, 0x29, 0x20, 0x40, 0x67, 0x72, 0x6f,
|
||||
0x75, 0x70, 0x28, 0x31, 0x29, 0x20, 0x76, 0x61, 0x72, 0x3c, 0x73, 0x74,
|
||||
0x6f, 0x72, 0x61, 0x67, 0x65, 0x3e, 0x20, 0x73, 0x68, 0x61, 0x70, 0x65,
|
||||
0x5f, 0x64, 0x61, 0x74, 0x61, 0x3a, 0x20, 0x61, 0x72, 0x72, 0x61, 0x79,
|
||||
0x3c, 0x53, 0x68, 0x61, 0x70, 0x65, 0x44, 0x61, 0x74, 0x61, 0x3e, 0x3b,
|
||||
0x0a, 0x40, 0x62, 0x69, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x28, 0x31, 0x29,
|
||||
0x20, 0x40, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x28, 0x31, 0x29, 0x20, 0x76,
|
||||
0x61, 0x72, 0x3c, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x3e, 0x20,
|
||||
0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x5f, 0x6d, 0x61, 0x70,
|
||||
0x3a, 0x20, 0x61, 0x72, 0x72, 0x61, 0x79, 0x3c, 0x75, 0x33, 0x32, 0x3e,
|
||||
0x3b, 0x0a, 0x0a, 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x20, 0x56, 0x73,
|
||||
0x49, 0x6e, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x40, 0x62, 0x75,
|
||||
0x69, 0x6c, 0x74, 0x69, 0x6e, 0x28, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e,
|
||||
0x63, 0x65, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x29, 0x20, 0x69, 0x6e,
|
||||
0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x78, 0x3a, 0x20,
|
||||
0x75, 0x33, 0x32, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x40, 0x6c, 0x6f,
|
||||
0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x30, 0x29, 0x20, 0x70, 0x6f,
|
||||
0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x20, 0x76, 0x65, 0x63, 0x32,
|
||||
0x66, 0x2c, 0x0a, 0x7d, 0x3b, 0x0a, 0x0a, 0x73, 0x74, 0x72, 0x75, 0x63,
|
||||
0x74, 0x20, 0x56, 0x73, 0x32, 0x46, 0x73, 0x20, 0x7b, 0x0a, 0x20, 0x20,
|
||||
0x20, 0x20, 0x40, 0x62, 0x75, 0x69, 0x6c, 0x74, 0x69, 0x6e, 0x28, 0x70,
|
||||
0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x29, 0x20, 0x70, 0x6f, 0x73,
|
||||
0x3a, 0x20, 0x76, 0x65, 0x63, 0x34, 0x66, 0x2c, 0x0a, 0x20, 0x20, 0x20,
|
||||
0x20, 0x40, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x30,
|
||||
0x29, 0x20, 0x40, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x70, 0x6f, 0x6c, 0x61,
|
||||
0x74, 0x65, 0x28, 0x6c, 0x69, 0x6e, 0x65, 0x61, 0x72, 0x29, 0x20, 0x63,
|
||||
0x6f, 0x6c, 0x6f, 0x72, 0x3a, 0x20, 0x76, 0x65, 0x63, 0x34, 0x66, 0x2c,
|
||||
0x0a, 0x7d, 0x3b, 0x0a, 0x0a, 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x20,
|
||||
0x46, 0x73, 0x4f, 0x75, 0x74, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20,
|
||||
0x40, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x30, 0x29,
|
||||
0x20, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x3a, 0x20, 0x76, 0x65, 0x63, 0x34,
|
||||
0x66, 0x2c, 0x0a, 0x7d, 0x3b, 0x0a, 0x0a, 0x40, 0x76, 0x65, 0x72, 0x74,
|
||||
0x65, 0x78, 0x20, 0x66, 0x6e, 0x20, 0x76, 0x73, 0x5f, 0x6d, 0x61, 0x69,
|
||||
0x6e, 0x28, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x3a, 0x20, 0x56, 0x73, 0x49,
|
||||
0x6e, 0x29, 0x20, 0x2d, 0x3e, 0x20, 0x56, 0x73, 0x32, 0x46, 0x73, 0x20,
|
||||
0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x76, 0x61, 0x72, 0x20, 0x6f, 0x75,
|
||||
0x74, 0x70, 0x75, 0x74, 0x3a, 0x20, 0x56, 0x73, 0x32, 0x46, 0x73, 0x3b,
|
||||
0x0a, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x65, 0x74, 0x20, 0x73, 0x68, 0x61,
|
||||
0x70, 0x65, 0x5f, 0x69, 0x64, 0x78, 0x20, 0x3d, 0x20, 0x69, 0x6e, 0x73,
|
||||
0x74, 0x61, 0x6e, 0x63, 0x65, 0x5f, 0x6d, 0x61, 0x70, 0x5b, 0x76, 0x73,
|
||||
0x5f, 0x75, 0x6e, 0x69, 0x66, 0x6f, 0x72, 0x6d, 0x73, 0x2e, 0x69, 0x6e,
|
||||
0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x5f, 0x62, 0x61, 0x73, 0x65, 0x20,
|
||||
0x2b, 0x20, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x2e, 0x69, 0x6e, 0x73, 0x74,
|
||||
0x61, 0x6e, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x78, 0x5d, 0x3b, 0x0a, 0x20,
|
||||
0x20, 0x20, 0x20, 0x6c, 0x65, 0x74, 0x20, 0x73, 0x68, 0x61, 0x70, 0x65,
|
||||
0x20, 0x3d, 0x20, 0x73, 0x68, 0x61, 0x70, 0x65, 0x5f, 0x64, 0x61, 0x74,
|
||||
0x61, 0x5b, 0x73, 0x68, 0x61, 0x70, 0x65, 0x5f, 0x69, 0x64, 0x78, 0x5d,
|
||||
0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x65, 0x74, 0x20, 0x77, 0x6f,
|
||||
0x72, 0x6c, 0x64, 0x5f, 0x70, 0x6f, 0x73, 0x20, 0x3d, 0x20, 0x73, 0x68,
|
||||
0x61, 0x70, 0x65, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x6f, 0x72,
|
||||
0x6d, 0x20, 0x2a, 0x20, 0x76, 0x65, 0x63, 0x34, 0x66, 0x28, 0x69, 0x6e,
|
||||
0x70, 0x75, 0x74, 0x2e, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e,
|
||||
0x2e, 0x78, 0x2c, 0x20, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x2e, 0x70, 0x6f,
|
||||
0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x79, 0x2c, 0x20, 0x30, 0x2e,
|
||||
0x30, 0x2c, 0x20, 0x31, 0x2e, 0x30, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x20,
|
||||
0x20, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x2e, 0x70, 0x6f, 0x73, 0x20,
|
||||
0x3d, 0x20, 0x76, 0x73, 0x5f, 0x75, 0x6e, 0x69, 0x66, 0x6f, 0x72, 0x6d,
|
||||
0x73, 0x2e, 0x6d, 0x76, 0x70, 0x20, 0x2a, 0x20, 0x77, 0x6f, 0x72, 0x6c,
|
||||
0x64, 0x5f, 0x70, 0x6f, 0x73, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69,
|
||||
0x66, 0x20, 0x28, 0x73, 0x68, 0x61, 0x70, 0x65, 0x2e, 0x73, 0x74, 0x61,
|
||||
0x74, 0x65, 0x20, 0x3d, 0x3d, 0x20, 0x32, 0x75, 0x29, 0x20, 0x7b, 0x0a,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6f, 0x75, 0x74, 0x70,
|
||||
0x75, 0x74, 0x2e, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x20, 0x3d, 0x20, 0x76,
|
||||
0x65, 0x63, 0x34, 0x66, 0x28, 0x31, 0x2e, 0x30, 0x2c, 0x20, 0x30, 0x2e,
|
||||
0x38, 0x34, 0x2c, 0x20, 0x30, 0x2e, 0x30, 0x2c, 0x20, 0x31, 0x2e, 0x30,
|
||||
0x29, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x20, 0x65, 0x6c, 0x73,
|
||||
0x65, 0x20, 0x69, 0x66, 0x20, 0x28, 0x73, 0x68, 0x61, 0x70, 0x65, 0x2e,
|
||||
0x73, 0x74, 0x61, 0x74, 0x65, 0x20, 0x3d, 0x3d, 0x20, 0x31, 0x75, 0x29,
|
||||
0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6f,
|
||||
0x75, 0x74, 0x70, 0x75, 0x74, 0x2e, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x20,
|
||||
0x3d, 0x20, 0x76, 0x65, 0x63, 0x34, 0x66, 0x28, 0x30, 0x2e, 0x35, 0x2c,
|
||||
0x20, 0x30, 0x2e, 0x36, 0x2c, 0x20, 0x31, 0x2e, 0x30, 0x2c, 0x20, 0x31,
|
||||
0x2e, 0x30, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x20, 0x65,
|
||||
0x6c, 0x73, 0x65, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x20, 0x20, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x2e, 0x63, 0x6f, 0x6c,
|
||||
0x6f, 0x72, 0x20, 0x3d, 0x20, 0x76, 0x65, 0x63, 0x34, 0x66, 0x28, 0x30,
|
||||
0x2e, 0x38, 0x2c, 0x20, 0x30, 0x2e, 0x38, 0x2c, 0x20, 0x30, 0x2e, 0x38,
|
||||
0x2c, 0x20, 0x31, 0x2e, 0x30, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20,
|
||||
0x7d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e,
|
||||
0x20, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x3b, 0x0a, 0x7d, 0x0a, 0x0a,
|
||||
0x40, 0x66, 0x72, 0x61, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x20, 0x66, 0x6e,
|
||||
0x20, 0x66, 0x73, 0x5f, 0x6d, 0x61, 0x69, 0x6e, 0x28, 0x69, 0x6e, 0x70,
|
||||
0x75, 0x74, 0x3a, 0x20, 0x56, 0x73, 0x32, 0x46, 0x73, 0x29, 0x20, 0x2d,
|
||||
0x3e, 0x20, 0x46, 0x73, 0x4f, 0x75, 0x74, 0x20, 0x7b, 0x0a, 0x20, 0x20,
|
||||
0x20, 0x20, 0x76, 0x61, 0x72, 0x20, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74,
|
||||
0x3a, 0x20, 0x46, 0x73, 0x4f, 0x75, 0x74, 0x3b, 0x0a, 0x20, 0x20, 0x20,
|
||||
0x20, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x2e, 0x63, 0x6f, 0x6c, 0x6f,
|
||||
0x72, 0x20, 0x3d, 0x20, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x2e, 0x63, 0x6f,
|
||||
0x6c, 0x6f, 0x72, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74,
|
||||
0x75, 0x72, 0x6e, 0x20, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x3b, 0x0a,
|
||||
0x7d, 0x0a
|
||||
};
|
||||
unsigned int src_shaders_shape_wgsl_len = 1274;
|
||||
@@ -1,92 +0,0 @@
|
||||
unsigned char src_shaders_sprite_wgsl[] = {
|
||||
0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x20, 0x53, 0x70, 0x72, 0x69, 0x74,
|
||||
0x65, 0x20, 0x7b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6d, 0x61, 0x74,
|
||||
0x72, 0x69, 0x78, 0x3a, 0x20, 0x6d, 0x61, 0x74, 0x34, 0x78, 0x34, 0x66,
|
||||
0x2c, 0x0d, 0x0a, 0x7d, 0x3b, 0x0d, 0x0a, 0x73, 0x74, 0x72, 0x75, 0x63,
|
||||
0x74, 0x20, 0x56, 0x73, 0x55, 0x6e, 0x69, 0x66, 0x6f, 0x72, 0x6d, 0x20,
|
||||
0x7b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6d, 0x76, 0x70, 0x3a, 0x20,
|
||||
0x6d, 0x61, 0x74, 0x34, 0x78, 0x34, 0x66, 0x2c, 0x0d, 0x0a, 0x7d, 0x3b,
|
||||
0x0d, 0x0a, 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x20, 0x56, 0x73, 0x49,
|
||||
0x20, 0x7b, 0x20, 0x2f, 0x2f, 0x56, 0x65, 0x72, 0x74, 0x65, 0x78, 0x20,
|
||||
0x73, 0x68, 0x61, 0x64, 0x65, 0x72, 0x20, 0x69, 0x6e, 0x70, 0x75, 0x74,
|
||||
0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x40, 0x62, 0x75, 0x69, 0x6c, 0x74,
|
||||
0x69, 0x6e, 0x28, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x5f,
|
||||
0x69, 0x6e, 0x64, 0x65, 0x78, 0x29, 0x20, 0x69, 0x6e, 0x73, 0x74, 0x61,
|
||||
0x6e, 0x63, 0x65, 0x3a, 0x20, 0x75, 0x33, 0x32, 0x2c, 0x0d, 0x0a, 0x20,
|
||||
0x20, 0x20, 0x20, 0x40, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e,
|
||||
0x28, 0x30, 0x29, 0x20, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e,
|
||||
0x3a, 0x20, 0x76, 0x65, 0x63, 0x32, 0x66, 0x2c, 0x0d, 0x0a, 0x20, 0x20,
|
||||
0x20, 0x20, 0x40, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x28,
|
||||
0x31, 0x29, 0x20, 0x75, 0x76, 0x3a, 0x20, 0x76, 0x65, 0x63, 0x32, 0x66,
|
||||
0x2c, 0x0d, 0x0a, 0x7d, 0x3b, 0x0d, 0x0a, 0x73, 0x74, 0x72, 0x75, 0x63,
|
||||
0x74, 0x20, 0x56, 0x73, 0x32, 0x46, 0x73, 0x20, 0x7b, 0x20, 0x2f, 0x2f,
|
||||
0x56, 0x65, 0x72, 0x74, 0x65, 0x78, 0x20, 0x73, 0x68, 0x61, 0x64, 0x65,
|
||||
0x72, 0x20, 0x74, 0x6f, 0x20, 0x46, 0x72, 0x61, 0x67, 0x6d, 0x65, 0x6e,
|
||||
0x74, 0x20, 0x73, 0x68, 0x61, 0x64, 0x65, 0x72, 0x0d, 0x0a, 0x20, 0x20,
|
||||
0x20, 0x20, 0x40, 0x62, 0x75, 0x69, 0x6c, 0x74, 0x69, 0x6e, 0x28, 0x70,
|
||||
0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x29, 0x20, 0x70, 0x6f, 0x73,
|
||||
0x3a, 0x20, 0x76, 0x65, 0x63, 0x34, 0x66, 0x2c, 0x0d, 0x0a, 0x20, 0x20,
|
||||
0x20, 0x20, 0x40, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x28,
|
||||
0x30, 0x29, 0x20, 0x40, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x70, 0x6f, 0x6c,
|
||||
0x61, 0x74, 0x65, 0x28, 0x6c, 0x69, 0x6e, 0x65, 0x61, 0x72, 0x29, 0x20,
|
||||
0x75, 0x76, 0x3a, 0x20, 0x76, 0x65, 0x63, 0x32, 0x66, 0x2c, 0x0d, 0x0a,
|
||||
0x7d, 0x3b, 0x0d, 0x0a, 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x20, 0x46,
|
||||
0x73, 0x4f, 0x20, 0x7b, 0x20, 0x2f, 0x2f, 0x46, 0x72, 0x61, 0x67, 0x6d,
|
||||
0x65, 0x6e, 0x74, 0x20, 0x73, 0x68, 0x61, 0x64, 0x65, 0x72, 0x20, 0x6f,
|
||||
0x75, 0x74, 0x70, 0x75, 0x74, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x40,
|
||||
0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x30, 0x29, 0x20,
|
||||
0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x3a, 0x20, 0x76, 0x65, 0x63, 0x34, 0x66,
|
||||
0x2c, 0x0d, 0x0a, 0x7d, 0x3b, 0x0d, 0x0a, 0x0d, 0x0a, 0x40, 0x62, 0x69,
|
||||
0x6e, 0x64, 0x69, 0x6e, 0x67, 0x28, 0x30, 0x29, 0x20, 0x40, 0x67, 0x72,
|
||||
0x6f, 0x75, 0x70, 0x28, 0x30, 0x29, 0x20, 0x76, 0x61, 0x72, 0x3c, 0x75,
|
||||
0x6e, 0x69, 0x66, 0x6f, 0x72, 0x6d, 0x3e, 0x20, 0x76, 0x73, 0x5f, 0x75,
|
||||
0x6e, 0x69, 0x66, 0x6f, 0x72, 0x6d, 0x73, 0x3a, 0x20, 0x56, 0x73, 0x55,
|
||||
0x6e, 0x69, 0x66, 0x6f, 0x72, 0x6d, 0x3b, 0x0d, 0x0a, 0x40, 0x62, 0x69,
|
||||
0x6e, 0x64, 0x69, 0x6e, 0x67, 0x28, 0x30, 0x29, 0x20, 0x40, 0x67, 0x72,
|
||||
0x6f, 0x75, 0x70, 0x28, 0x31, 0x29, 0x20, 0x76, 0x61, 0x72, 0x20, 0x74,
|
||||
0x65, 0x78, 0x3a, 0x20, 0x74, 0x65, 0x78, 0x74, 0x75, 0x72, 0x65, 0x5f,
|
||||
0x32, 0x64, 0x3c, 0x66, 0x33, 0x32, 0x3e, 0x3b, 0x0d, 0x0a, 0x40, 0x62,
|
||||
0x69, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x28, 0x31, 0x29, 0x20, 0x40, 0x67,
|
||||
0x72, 0x6f, 0x75, 0x70, 0x28, 0x31, 0x29, 0x20, 0x76, 0x61, 0x72, 0x20,
|
||||
0x73, 0x61, 0x6d, 0x70, 0x3a, 0x20, 0x73, 0x61, 0x6d, 0x70, 0x6c, 0x65,
|
||||
0x72, 0x3b, 0x0d, 0x0a, 0x40, 0x62, 0x69, 0x6e, 0x64, 0x69, 0x6e, 0x67,
|
||||
0x28, 0x32, 0x29, 0x20, 0x40, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x28, 0x31,
|
||||
0x29, 0x20, 0x76, 0x61, 0x72, 0x3c, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67,
|
||||
0x65, 0x3e, 0x20, 0x73, 0x70, 0x72, 0x69, 0x74, 0x65, 0x73, 0x3a, 0x20,
|
||||
0x61, 0x72, 0x72, 0x61, 0x79, 0x3c, 0x53, 0x70, 0x72, 0x69, 0x74, 0x65,
|
||||
0x3e, 0x3b, 0x0d, 0x0a, 0x0d, 0x0a, 0x40, 0x76, 0x65, 0x72, 0x74, 0x65,
|
||||
0x78, 0x20, 0x66, 0x6e, 0x20, 0x76, 0x73, 0x5f, 0x6d, 0x61, 0x69, 0x6e,
|
||||
0x28, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x3a, 0x20, 0x56, 0x73, 0x49, 0x29,
|
||||
0x20, 0x2d, 0x3e, 0x20, 0x56, 0x73, 0x32, 0x46, 0x73, 0x20, 0x7b, 0x0d,
|
||||
0x0a, 0x20, 0x20, 0x20, 0x20, 0x76, 0x61, 0x72, 0x20, 0x6f, 0x75, 0x74,
|
||||
0x70, 0x75, 0x74, 0x3a, 0x20, 0x56, 0x73, 0x32, 0x46, 0x73, 0x3b, 0x0d,
|
||||
0x0a, 0x20, 0x20, 0x20, 0x20, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6f,
|
||||
0x75, 0x74, 0x70, 0x75, 0x74, 0x2e, 0x70, 0x6f, 0x73, 0x20, 0x3d, 0x20,
|
||||
0x76, 0x65, 0x63, 0x34, 0x66, 0x28, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x2e,
|
||||
0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x78, 0x2c, 0x20,
|
||||
0x69, 0x6e, 0x70, 0x75, 0x74, 0x2e, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69,
|
||||
0x6f, 0x6e, 0x2e, 0x79, 0x2c, 0x20, 0x30, 0x2c, 0x20, 0x30, 0x29, 0x20,
|
||||
0x2a, 0x20, 0x73, 0x70, 0x72, 0x69, 0x74, 0x65, 0x73, 0x5b, 0x69, 0x6e,
|
||||
0x70, 0x75, 0x74, 0x2e, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65,
|
||||
0x5d, 0x2e, 0x6d, 0x61, 0x74, 0x72, 0x69, 0x78, 0x20, 0x2a, 0x20, 0x76,
|
||||
0x73, 0x5f, 0x75, 0x6e, 0x69, 0x66, 0x6f, 0x72, 0x6d, 0x73, 0x2e, 0x6d,
|
||||
0x76, 0x70, 0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6f, 0x75, 0x74,
|
||||
0x70, 0x75, 0x74, 0x2e, 0x75, 0x76, 0x20, 0x3d, 0x20, 0x69, 0x6e, 0x70,
|
||||
0x75, 0x74, 0x2e, 0x75, 0x76, 0x3b, 0x0d, 0x0a, 0x0d, 0x0a, 0x20, 0x20,
|
||||
0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x6f, 0x75, 0x74,
|
||||
0x70, 0x75, 0x74, 0x3b, 0x0d, 0x0a, 0x7d, 0x0d, 0x0a, 0x0d, 0x0a, 0x40,
|
||||
0x66, 0x72, 0x61, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x20, 0x66, 0x6e, 0x20,
|
||||
0x66, 0x73, 0x5f, 0x6d, 0x61, 0x69, 0x6e, 0x28, 0x69, 0x6e, 0x70, 0x75,
|
||||
0x74, 0x3a, 0x20, 0x56, 0x73, 0x32, 0x46, 0x73, 0x29, 0x20, 0x2d, 0x3e,
|
||||
0x20, 0x46, 0x73, 0x4f, 0x20, 0x7b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20,
|
||||
0x76, 0x61, 0x72, 0x20, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x3a, 0x20,
|
||||
0x46, 0x73, 0x4f, 0x3b, 0x0d, 0x0a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20,
|
||||
0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x2e, 0x63, 0x6f, 0x6c, 0x6f, 0x72,
|
||||
0x20, 0x3d, 0x20, 0x74, 0x65, 0x78, 0x74, 0x75, 0x72, 0x65, 0x53, 0x61,
|
||||
0x6d, 0x70, 0x6c, 0x65, 0x28, 0x74, 0x65, 0x78, 0x2c, 0x20, 0x73, 0x61,
|
||||
0x6d, 0x70, 0x2c, 0x20, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x2e, 0x75, 0x76,
|
||||
0x29, 0x3b, 0x0d, 0x0a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65,
|
||||
0x74, 0x75, 0x72, 0x6e, 0x20, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x3b,
|
||||
0x0d, 0x0a, 0x7d
|
||||
};
|
||||
unsigned int src_shaders_sprite_wgsl_len = 1059;
|
||||
@@ -1,14 +0,0 @@
|
||||
// Context struct declarations are now defined alongside the code they
|
||||
// belong to rather than in a single header:
|
||||
//
|
||||
// panel_log_ctx_t — api.h
|
||||
// shape_pool_ctx_t — shape.h (after shape_t / group_t)
|
||||
// group_index_ctx_t — shape.h
|
||||
// pipeline_ctx_t — render.h
|
||||
// shape_group_buf_t — shape.h
|
||||
//
|
||||
// This header exists only to avoid breaking includes elsewhere and can
|
||||
// be removed once all consumers are updated.
|
||||
#ifndef GLOBALS_H
|
||||
#define GLOBALS_H
|
||||
#endif
|
||||
499
src/history.h
499
src/history.h
@@ -1,499 +0,0 @@
|
||||
#ifndef HISTORY_H
|
||||
#define HISTORY_H
|
||||
|
||||
#include "api.h"
|
||||
|
||||
#define HISTORY_MAX_DEPTH 256
|
||||
|
||||
typedef enum {
|
||||
HIST_POSITION,
|
||||
HIST_SCALE,
|
||||
HIST_ROTATION,
|
||||
HIST_CREATE,
|
||||
HIST_DELETE,
|
||||
HIST_GROUP,
|
||||
HIST_GROUP_CREATE,
|
||||
HIST_GROUP_DELETE,
|
||||
HIST_GROUP_REPARENT,
|
||||
HIST_EDIT,
|
||||
} hist_prop_t;
|
||||
|
||||
typedef struct hist_change_t {
|
||||
int shape_index;
|
||||
hist_prop_t prop;
|
||||
float old_val[4];
|
||||
float new_val[4];
|
||||
|
||||
// Owned vertex+index buffer snapshot — only used for HIST_CREATE / HIST_DELETE
|
||||
// when the shape has no control points (pen paths).
|
||||
shape_vertex_t *vertex_data;
|
||||
uint16_t *index_data;
|
||||
int vertex_count;
|
||||
int index_count;
|
||||
|
||||
// Control point snapshot — used for HIST_CREATE / HIST_DELETE / HIST_EDIT.
|
||||
// For HIST_CREATE / HIST_DELETE, ctrl_* holds the saved shape data.
|
||||
// For HIST_EDIT, ctrl_* holds the old (pre-edit) state and
|
||||
// new_ctrl_* holds the new (post-edit) state.
|
||||
char name[64];
|
||||
shape_vertex_t *ctrl_points;
|
||||
shape_vertex_t *ctrl_handle_in;
|
||||
shape_vertex_t *ctrl_handle_out;
|
||||
int ctrl_count;
|
||||
bool closed;
|
||||
// Post-edit control point state (only used for HIST_EDIT)
|
||||
shape_vertex_t *new_ctrl_points;
|
||||
shape_vertex_t *new_ctrl_handle_in;
|
||||
shape_vertex_t *new_ctrl_handle_out;
|
||||
int new_ctrl_count;
|
||||
} hist_change_t;
|
||||
|
||||
typedef struct hist_entry_t {
|
||||
hist_change_t *changes;
|
||||
int count;
|
||||
} hist_entry_t;
|
||||
|
||||
typedef struct history_t {
|
||||
vector_t entries;
|
||||
int current;
|
||||
|
||||
bool capturing;
|
||||
int pending_shape_idx;
|
||||
hist_prop_t pending_prop;
|
||||
float pending_old[4];
|
||||
} history_t;
|
||||
|
||||
// -- helpers --
|
||||
|
||||
static void hist_read_prop(shape_t *s, hist_prop_t prop, float out[4]) {
|
||||
memset(out, 0, sizeof(float[4]));
|
||||
switch (prop) {
|
||||
case HIST_POSITION: out[0] = s->cx; out[1] = s->cy; break;
|
||||
case HIST_SCALE: out[0] = s->sx; out[1] = s->sy; break;
|
||||
case HIST_ROTATION: out[0] = s->rotation; break;
|
||||
case HIST_GROUP: out[0] = (float)s->group_id; break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
static void hist_apply_prop(shape_t *s, hist_prop_t prop, const float val[4]) {
|
||||
switch (prop) {
|
||||
case HIST_POSITION: s->cx = val[0]; s->cy = val[1]; break;
|
||||
case HIST_SCALE: s->sx = val[0]; s->sy = val[1]; break;
|
||||
case HIST_ROTATION: s->rotation = val[0]; break;
|
||||
case HIST_GROUP: s->group_id = (int)val[0]; break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
static void hist_free_change(hist_change_t *c) {
|
||||
if (c->vertex_data) FREE(c->vertex_data);
|
||||
if (c->index_data) FREE(c->index_data);
|
||||
if (c->ctrl_points) FREE(c->ctrl_points);
|
||||
if (c->ctrl_handle_in) FREE(c->ctrl_handle_in);
|
||||
if (c->ctrl_handle_out) FREE(c->ctrl_handle_out);
|
||||
if (c->new_ctrl_points) FREE(c->new_ctrl_points);
|
||||
if (c->new_ctrl_handle_in) FREE(c->new_ctrl_handle_in);
|
||||
if (c->new_ctrl_handle_out) FREE(c->new_ctrl_handle_out);
|
||||
memset(c, 0, sizeof(*c));
|
||||
}
|
||||
|
||||
static void history_init(history_t *h) {
|
||||
memset(h, 0, sizeof(*h));
|
||||
vec_init(&h->entries, sizeof(hist_entry_t));
|
||||
h->current = -1;
|
||||
}
|
||||
|
||||
static void history_destroy(history_t *h) {
|
||||
for (int i = 0; i < h->entries.count; i++) {
|
||||
hist_entry_t *e = (hist_entry_t*) vec_get(&h->entries, i);
|
||||
if (e->changes) {
|
||||
for (int j = 0; j < e->count; j++)
|
||||
hist_free_change(&e->changes[j]);
|
||||
FREE(e->changes);
|
||||
}
|
||||
}
|
||||
vec_free(&h->entries);
|
||||
memset(h, 0, sizeof(*h));
|
||||
h->current = -1;
|
||||
}
|
||||
|
||||
static void history_push_entry(history_t *h, hist_entry_t entry) {
|
||||
while (h->entries.count > h->current + 1) {
|
||||
hist_entry_t *e = (hist_entry_t*) vec_get(&h->entries, h->entries.count - 1);
|
||||
if (e->changes) {
|
||||
for (int j = 0; j < e->count; j++)
|
||||
hist_free_change(&e->changes[j]);
|
||||
FREE(e->changes);
|
||||
}
|
||||
vec_pop(&h->entries);
|
||||
}
|
||||
|
||||
*((hist_entry_t*) vec_push(&h->entries)) = entry;
|
||||
h->current = h->entries.count - 1;
|
||||
|
||||
while (h->entries.count > HISTORY_MAX_DEPTH) {
|
||||
hist_entry_t *e = (hist_entry_t*) vec_get(&h->entries, 0);
|
||||
if (e->changes) {
|
||||
for (int j = 0; j < e->count; j++)
|
||||
hist_free_change(&e->changes[j]);
|
||||
FREE(e->changes);
|
||||
}
|
||||
vec_remove_ordered(&h->entries, 0);
|
||||
h->current--;
|
||||
}
|
||||
}
|
||||
|
||||
static void history_begin_edit(history_t *h, vector_t *shapes,
|
||||
int shape_idx, hist_prop_t prop) {
|
||||
if (h->capturing) {
|
||||
shape_t *s = (shape_t*) vec_get(shapes, h->pending_shape_idx);
|
||||
float new_val[4];
|
||||
hist_read_prop(s, h->pending_prop, new_val);
|
||||
if (memcmp(h->pending_old, new_val, sizeof(float[4])) != 0) {
|
||||
hist_entry_t entry = { .changes = NULL, .count = 1 };
|
||||
entry.changes = (hist_change_t*) ALLOC(sizeof(hist_change_t));
|
||||
memset(entry.changes, 0, sizeof(hist_change_t));
|
||||
entry.changes->shape_index = h->pending_shape_idx;
|
||||
entry.changes->prop = h->pending_prop;
|
||||
memcpy(entry.changes->old_val, h->pending_old, sizeof(float[4]));
|
||||
memcpy(entry.changes->new_val, new_val, sizeof(float[4]));
|
||||
history_push_entry(h, entry);
|
||||
}
|
||||
h->capturing = false;
|
||||
}
|
||||
|
||||
h->capturing = true;
|
||||
h->pending_shape_idx = shape_idx;
|
||||
h->pending_prop = prop;
|
||||
shape_t *s = (shape_t*) vec_get(shapes, shape_idx);
|
||||
hist_read_prop(s, prop, h->pending_old);
|
||||
}
|
||||
|
||||
static void history_end_edit(history_t *h, vector_t *shapes) {
|
||||
if (!h->capturing) return;
|
||||
|
||||
shape_t *s = (shape_t*) vec_get(shapes, h->pending_shape_idx);
|
||||
float new_val[4];
|
||||
hist_read_prop(s, h->pending_prop, new_val);
|
||||
|
||||
if (memcmp(h->pending_old, new_val, sizeof(float[4])) != 0) {
|
||||
hist_entry_t entry = { .changes = NULL, .count = 1 };
|
||||
entry.changes = (hist_change_t*) ALLOC(sizeof(hist_change_t));
|
||||
memset(entry.changes, 0, sizeof(hist_change_t));
|
||||
entry.changes->shape_index = h->pending_shape_idx;
|
||||
entry.changes->prop = h->pending_prop;
|
||||
memcpy(entry.changes->old_val, h->pending_old, sizeof(float[4]));
|
||||
memcpy(entry.changes->new_val, new_val, sizeof(float[4]));
|
||||
history_push_entry(h, entry);
|
||||
}
|
||||
h->capturing = false;
|
||||
}
|
||||
|
||||
// -- batch API --
|
||||
|
||||
typedef struct {
|
||||
hist_change_t *changes;
|
||||
int count;
|
||||
int capacity;
|
||||
} hist_batch_t;
|
||||
|
||||
static void history_batch_init(hist_batch_t *batch, int count) {
|
||||
batch->changes = (hist_change_t*) ALLOC((size_t)count * sizeof(hist_change_t));
|
||||
memset(batch->changes, 0, (size_t)count * sizeof(hist_change_t));
|
||||
batch->count = 0;
|
||||
batch->capacity = count;
|
||||
}
|
||||
|
||||
// For property changes (POSITION, SCALE, ROTATION, GROUP)
|
||||
static void history_batch_add(hist_batch_t *batch, int shape_index, hist_prop_t prop,
|
||||
const float old_val[4], const float new_val[4]) {
|
||||
hist_change_t *c = &batch->changes[batch->count++];
|
||||
c->shape_index = shape_index;
|
||||
c->prop = prop;
|
||||
memcpy(c->old_val, old_val, sizeof(float[4]));
|
||||
memcpy(c->new_val, new_val, sizeof(float[4]));
|
||||
}
|
||||
|
||||
// Snapshot a shape's full data into a change entry.
|
||||
// old_val = { cx, cy, num_elements, 0 }
|
||||
// new_val = { sx, sy, rotation, group_id }
|
||||
// For procedural shapes (ctrl_count > 0), control points are deep-copied.
|
||||
// For pen paths (ctrl_count == 0), raw vertex/index data is deep-copied.
|
||||
static void hist_snapshot_shape_verts(hist_change_t *c, shape_t *s) {
|
||||
c->old_val[0] = s->cx;
|
||||
c->old_val[1] = s->cy;
|
||||
c->old_val[2] = (float)(int)s->num_elements;
|
||||
c->old_val[3] = 0;
|
||||
c->new_val[0] = s->sx;
|
||||
c->new_val[1] = s->sy;
|
||||
c->new_val[2] = s->rotation;
|
||||
c->new_val[3] = (float)s->group_id;
|
||||
|
||||
strncpy(c->name, s->name, sizeof(c->name) - 1);
|
||||
c->name[sizeof(c->name) - 1] = '\0';
|
||||
c->closed = s->closed;
|
||||
|
||||
if (s->ctrl_count > 0) {
|
||||
c->ctrl_count = s->ctrl_count;
|
||||
c->ctrl_points = (shape_vertex_t*) ALLOC((size_t)c->ctrl_count * sizeof(shape_vertex_t));
|
||||
c->ctrl_handle_in = (shape_vertex_t*) ALLOC((size_t)c->ctrl_count * sizeof(shape_vertex_t));
|
||||
c->ctrl_handle_out = (shape_vertex_t*) ALLOC((size_t)c->ctrl_count * sizeof(shape_vertex_t));
|
||||
memcpy(c->ctrl_points, s->ctrl_points, (size_t)c->ctrl_count * sizeof(shape_vertex_t));
|
||||
memcpy(c->ctrl_handle_in, s->ctrl_handle_in, (size_t)c->ctrl_count * sizeof(shape_vertex_t));
|
||||
memcpy(c->ctrl_handle_out, s->ctrl_handle_out, (size_t)c->ctrl_count * sizeof(shape_vertex_t));
|
||||
} else {
|
||||
int n = (int)s->num_elements;
|
||||
c->vertex_count = n;
|
||||
c->index_count = n;
|
||||
c->vertex_data = (shape_vertex_t*) ALLOC((size_t)n * sizeof(shape_vertex_t));
|
||||
c->index_data = (uint16_t*) ALLOC((size_t)n * sizeof(uint16_t));
|
||||
memcpy(c->vertex_data, s->verts, (size_t)n * sizeof(shape_vertex_t));
|
||||
memcpy(c->index_data, s->indices, (size_t)n * sizeof(uint16_t));
|
||||
}
|
||||
}
|
||||
|
||||
// Append a CREATE or DELETE entry to a batch, snapshotting the shape's data.
|
||||
static void history_batch_add_shape(hist_batch_t *batch, int shape_index,
|
||||
hist_prop_t prop, shape_t *s) {
|
||||
hist_change_t *c = &batch->changes[batch->count++];
|
||||
c->shape_index = shape_index;
|
||||
c->prop = prop;
|
||||
hist_snapshot_shape_verts(c, s);
|
||||
}
|
||||
|
||||
// Snapshot both old and new control point states for a HIST_EDIT change.
|
||||
static void history_batch_add_edit(hist_batch_t *batch, int shape_index, shape_t *s,
|
||||
const shape_vertex_t *old_pts,
|
||||
const shape_vertex_t *old_hin,
|
||||
const shape_vertex_t *old_hout,
|
||||
int old_count) {
|
||||
hist_change_t *c = &batch->changes[batch->count++];
|
||||
c->shape_index = shape_index;
|
||||
c->prop = HIST_EDIT;
|
||||
// Store shape metadata
|
||||
c->old_val[0] = s->cx;
|
||||
c->old_val[1] = s->cy;
|
||||
c->old_val[2] = (float)(int)s->num_elements;
|
||||
c->old_val[3] = 0;
|
||||
c->new_val[0] = s->sx;
|
||||
c->new_val[1] = s->sy;
|
||||
c->new_val[2] = s->rotation;
|
||||
c->new_val[3] = (float)s->group_id;
|
||||
strncpy(c->name, s->name, sizeof(c->name) - 1);
|
||||
c->name[sizeof(c->name) - 1] = '\0';
|
||||
c->closed = s->closed;
|
||||
// Snapshot old ctrl state
|
||||
c->ctrl_count = old_count;
|
||||
c->ctrl_points = (shape_vertex_t*) ALLOC((size_t)old_count * sizeof(shape_vertex_t));
|
||||
c->ctrl_handle_in = (shape_vertex_t*) ALLOC((size_t)old_count * sizeof(shape_vertex_t));
|
||||
c->ctrl_handle_out = (shape_vertex_t*) ALLOC((size_t)old_count * sizeof(shape_vertex_t));
|
||||
memcpy(c->ctrl_points, old_pts, (size_t)old_count * sizeof(shape_vertex_t));
|
||||
memcpy(c->ctrl_handle_in, old_hin, (size_t)old_count * sizeof(shape_vertex_t));
|
||||
memcpy(c->ctrl_handle_out, old_hout, (size_t)old_count * sizeof(shape_vertex_t));
|
||||
// Snapshot new ctrl state
|
||||
c->new_ctrl_count = s->ctrl_count;
|
||||
c->new_ctrl_points = (shape_vertex_t*) ALLOC((size_t)s->ctrl_count * sizeof(shape_vertex_t));
|
||||
c->new_ctrl_handle_in = (shape_vertex_t*) ALLOC((size_t)s->ctrl_count * sizeof(shape_vertex_t));
|
||||
c->new_ctrl_handle_out = (shape_vertex_t*) ALLOC((size_t)s->ctrl_count * sizeof(shape_vertex_t));
|
||||
memcpy(c->new_ctrl_points, s->ctrl_points, (size_t)s->ctrl_count * sizeof(shape_vertex_t));
|
||||
memcpy(c->new_ctrl_handle_in, s->ctrl_handle_in, (size_t)s->ctrl_count * sizeof(shape_vertex_t));
|
||||
memcpy(c->new_ctrl_handle_out, s->ctrl_handle_out, (size_t)s->ctrl_count * sizeof(shape_vertex_t));
|
||||
}
|
||||
|
||||
static void history_batch_commit(hist_batch_t *batch, history_t *h) {
|
||||
hist_entry_t entry = { .changes = batch->changes, .count = batch->count };
|
||||
history_push_entry(h, entry);
|
||||
}
|
||||
|
||||
// Reconstruct a shape_t from a HIST_CREATE / HIST_DELETE change snapshot.
|
||||
static shape_t hist_rebuild_shape_from_snapshot(shape_pool_ctx_t *sp, const hist_change_t *c) {
|
||||
float cx = c->old_val[0], cy = c->old_val[1];
|
||||
float sx = c->new_val[0], sy = c->new_val[1];
|
||||
float rot = c->new_val[2];
|
||||
int gid = (int)c->new_val[3];
|
||||
shape_t s;
|
||||
|
||||
if (c->ctrl_count > 0) {
|
||||
memset(&s, 0, sizeof(s));
|
||||
s.cx = cx;
|
||||
s.cy = cy;
|
||||
s.sx = sx;
|
||||
s.sy = sy;
|
||||
s.rotation = rot;
|
||||
shape_init_common(&s);
|
||||
strncpy(s.name, c->name, sizeof(s.name) - 1);
|
||||
s.closed = c->closed;
|
||||
s.ctrl_count = c->ctrl_count;
|
||||
s.ctrl_points = (shape_vertex_t*) ALLOC((size_t)c->ctrl_count * sizeof(shape_vertex_t));
|
||||
s.ctrl_handle_in = (shape_vertex_t*) ALLOC((size_t)c->ctrl_count * sizeof(shape_vertex_t));
|
||||
s.ctrl_handle_out = (shape_vertex_t*) ALLOC((size_t)c->ctrl_count * sizeof(shape_vertex_t));
|
||||
memcpy(s.ctrl_points, c->ctrl_points, (size_t)c->ctrl_count * sizeof(shape_vertex_t));
|
||||
memcpy(s.ctrl_handle_in, c->ctrl_handle_in, (size_t)c->ctrl_count * sizeof(shape_vertex_t));
|
||||
memcpy(s.ctrl_handle_out, c->ctrl_handle_out, (size_t)c->ctrl_count * sizeof(shape_vertex_t));
|
||||
shape_regenerate_from_ctrl(sp, &s);
|
||||
} else {
|
||||
memset(&s, 0, sizeof(s));
|
||||
s.cx = cx;
|
||||
s.cy = cy;
|
||||
s.rotation = rot;
|
||||
s.num_verts = (uint32_t)c->vertex_count;
|
||||
s.num_elements = (uint32_t)c->vertex_count;
|
||||
s.sx = sx;
|
||||
s.sy = sy;
|
||||
int n = c->vertex_count;
|
||||
s.verts = (shape_vertex_t*) ALLOC((size_t)n * sizeof(shape_vertex_t));
|
||||
s.indices = (uint16_t*) ALLOC((size_t)n * sizeof(uint16_t));
|
||||
memcpy(s.verts, c->vertex_data, (size_t)n * sizeof(shape_vertex_t));
|
||||
memcpy(s.indices, c->index_data, (size_t)n * sizeof(uint16_t));
|
||||
shape_init_common(&s);
|
||||
strncpy(s.name, c->name, sizeof(s.name) - 1);
|
||||
s.vertex_hash = hash_vertex_data(s.verts, s.num_elements);
|
||||
shape_build_transform(sp, &s);
|
||||
shape_update_aabb(&s);
|
||||
shape_make_buffers(sp, &s);
|
||||
}
|
||||
s.rotation = rot;
|
||||
s.group_id = gid;
|
||||
return s;
|
||||
}
|
||||
|
||||
static void history_apply_entry(history_t *h, vector_t *shapes,
|
||||
shape_pool_ctx_t *sp, vector_t *groups,
|
||||
group_index_ctx_t *gi, bool forward) {
|
||||
(void)h;
|
||||
hist_entry_t *entry = (hist_entry_t*) vec_get(&h->entries, h->current);
|
||||
bool has_shape_ops = false;
|
||||
for (int i = 0; i < entry->count; i++) {
|
||||
hist_prop_t p = entry->changes[i].prop;
|
||||
if (p == HIST_CREATE || p == HIST_DELETE ||
|
||||
p == HIST_GROUP_CREATE || p == HIST_GROUP_DELETE) { has_shape_ops = true; break; }
|
||||
}
|
||||
|
||||
int start = 0, end = entry->count, step = 1;
|
||||
if (has_shape_ops && !forward) {
|
||||
start = entry->count - 1;
|
||||
end = -1;
|
||||
step = -1;
|
||||
}
|
||||
|
||||
for (int i = start; i != end; i += step) {
|
||||
hist_change_t *c = &entry->changes[i];
|
||||
|
||||
if (c->prop == HIST_GROUP_CREATE) {
|
||||
int gid = (int)c->new_val[0];
|
||||
int parent_id = (int)c->new_val[1];
|
||||
if (forward) {
|
||||
group_t g = { .id = gid, .parent_id = parent_id, .collapsed = false };
|
||||
*((group_t*) vec_push(groups)) = g;
|
||||
} else {
|
||||
for (int g = 0; g < groups->count; g++) {
|
||||
group_t *grp = (group_t*) vec_get(groups, g);
|
||||
if (grp->id == gid) {
|
||||
if (grp->member_indices) FREE(grp->member_indices);
|
||||
vec_remove_ordered(groups, g);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
gi->dirty = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (c->prop == HIST_GROUP_DELETE) {
|
||||
int gid = (int)c->old_val[0];
|
||||
int parent_id = (int)c->old_val[1];
|
||||
if (forward) {
|
||||
for (int g = 0; g < groups->count; g++) {
|
||||
group_t *grp = (group_t*) vec_get(groups, g);
|
||||
if (grp->id == gid) {
|
||||
if (grp->member_indices) FREE(grp->member_indices);
|
||||
vec_remove_ordered(groups, g);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
group_t g = { .id = gid, .parent_id = parent_id, .collapsed = false };
|
||||
*((group_t*) vec_push(groups)) = g;
|
||||
}
|
||||
gi->dirty = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (c->prop == HIST_GROUP_REPARENT) {
|
||||
int gid = (int)c->new_val[0];
|
||||
int new_pid = forward ? (int)c->new_val[1] : (int)c->old_val[1];
|
||||
for (int g = 0; g < groups->count; g++) {
|
||||
group_t *grp = (group_t*) vec_get(groups, g);
|
||||
if (grp->id == gid) {
|
||||
grp->parent_id = new_pid;
|
||||
break;
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (c->prop == HIST_CREATE || c->prop == HIST_DELETE) {
|
||||
bool adding = (c->prop == HIST_CREATE) ? forward : !forward;
|
||||
if (adding) {
|
||||
if (c->shape_index < 0 || c->shape_index > shapes->count) continue;
|
||||
shape_t s = hist_rebuild_shape_from_snapshot(sp, c);
|
||||
*((shape_t*) vec_insert(shapes, c->shape_index)) = s;
|
||||
} else {
|
||||
if (c->shape_index < shapes->count) {
|
||||
shape_t *s = (shape_t*) vec_get(shapes, c->shape_index);
|
||||
shape_shutdown(sp, s);
|
||||
vec_remove_ordered(shapes, c->shape_index);
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (c->prop == HIST_EDIT) {
|
||||
if (c->shape_index >= shapes->count) continue;
|
||||
shape_t *s = (shape_t*) vec_get(shapes, c->shape_index);
|
||||
shape_vertex_t *pts = forward ? c->new_ctrl_points : c->ctrl_points;
|
||||
shape_vertex_t *hin = forward ? c->new_ctrl_handle_in : c->ctrl_handle_in;
|
||||
shape_vertex_t *hout = forward ? c->new_ctrl_handle_out : c->ctrl_handle_out;
|
||||
int cc = forward ? c->new_ctrl_count : c->ctrl_count;
|
||||
if (!pts || cc <= 0) continue;
|
||||
FREE(s->ctrl_points);
|
||||
FREE(s->ctrl_handle_in);
|
||||
FREE(s->ctrl_handle_out);
|
||||
s->ctrl_count = cc;
|
||||
s->ctrl_points = (shape_vertex_t*) ALLOC((size_t)cc * sizeof(shape_vertex_t));
|
||||
s->ctrl_handle_in = (shape_vertex_t*) ALLOC((size_t)cc * sizeof(shape_vertex_t));
|
||||
s->ctrl_handle_out = (shape_vertex_t*) ALLOC((size_t)cc * sizeof(shape_vertex_t));
|
||||
memcpy(s->ctrl_points, pts, (size_t)cc * sizeof(shape_vertex_t));
|
||||
memcpy(s->ctrl_handle_in, hin, (size_t)cc * sizeof(shape_vertex_t));
|
||||
memcpy(s->ctrl_handle_out, hout, (size_t)cc * sizeof(shape_vertex_t));
|
||||
shape_regenerate_from_ctrl(sp, s);
|
||||
shape_set_state(sp, s, s->hovered, s->selected);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (c->shape_index >= shapes->count) continue;
|
||||
shape_t *s = (shape_t*) vec_get(shapes, c->shape_index);
|
||||
hist_apply_prop(s, c->prop, forward ? c->new_val : c->old_val);
|
||||
shape_regenerate(sp, s);
|
||||
shape_set_state(sp, s, s->hovered, s->selected);
|
||||
}
|
||||
}
|
||||
|
||||
static bool history_undo(history_t *h, vector_t *shapes, shape_pool_ctx_t *sp,
|
||||
vector_t *groups, group_index_ctx_t *gi) {
|
||||
if (h->current < 0 || h->current >= h->entries.count) return false;
|
||||
history_apply_entry(h, shapes, sp, groups, gi, false);
|
||||
h->current--;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool history_redo(history_t *h, vector_t *shapes, shape_pool_ctx_t *sp,
|
||||
vector_t *groups, group_index_ctx_t *gi) {
|
||||
if (h->current + 1 >= h->entries.count) return false;
|
||||
h->current++;
|
||||
history_apply_entry(h, shapes, sp, groups, gi, true);
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif
|
||||
1248
src/input.h
1248
src/input.h
File diff suppressed because it is too large
Load Diff
113
src/interact.h
113
src/interact.h
@@ -1,113 +0,0 @@
|
||||
#ifndef INTERACT_H
|
||||
#define INTERACT_H
|
||||
|
||||
#include "api.h"
|
||||
#include "types.h"
|
||||
|
||||
// Forward-declared: defined in overlay.h (included after interact.h in api.h).
|
||||
static void overlay_invalidate(userdata_t *ud);
|
||||
|
||||
// Called after any operation that changes shape count or structure (undo,
|
||||
// redo, delete, paste, group, ungroup). Invalidates cached state so the next
|
||||
// frame rebuilds the spatial grid, overlay geometry, and GPU instance data.
|
||||
static void interact_structural_change(userdata_t *ud)
|
||||
{
|
||||
ud->interact.hovered_shape = -1;
|
||||
ud->shape_pool.pool_dirty = true;
|
||||
spatial_mark_dirty(&ud->spatial_grid);
|
||||
ud->interact.aabb_cached = false;
|
||||
ud->ui.display_cache_dirty = true;
|
||||
overlay_invalidate(ud);
|
||||
}
|
||||
|
||||
static void selected_aabb(userdata_t *ud, float *min_x, float *min_y,
|
||||
float *max_x, float *max_y)
|
||||
{
|
||||
bool first = true;
|
||||
for (int i = 0; i < ud->shapes.count; i++) {
|
||||
shape_t *s = (shape_t*) vec_get(&ud->shapes, i);
|
||||
if (!s->selected) continue;
|
||||
float smin_x = s->cx - s->aabb_hx;
|
||||
float smin_y = s->cy - s->aabb_hy;
|
||||
float smax_x = s->cx + s->aabb_hx;
|
||||
float smax_y = s->cy + s->aabb_hy;
|
||||
if (first) {
|
||||
*min_x = smin_x; *min_y = smin_y;
|
||||
*max_x = smax_x; *max_y = smax_y;
|
||||
first = false;
|
||||
} else {
|
||||
if (smin_x < *min_x) *min_x = smin_x;
|
||||
if (smin_y < *min_y) *min_y = smin_y;
|
||||
if (smax_x > *max_x) *max_x = smax_x;
|
||||
if (smax_y > *max_y) *max_y = smax_y;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void update_shape_states(userdata_t *ud)
|
||||
{
|
||||
ud->shape_pool.states_dirty = true;
|
||||
}
|
||||
|
||||
static void select_group_recursive(userdata_t *ud, int gid)
|
||||
{
|
||||
for (int i = 0; i < ud->shapes.count; i++) {
|
||||
shape_t *s = (shape_t*) vec_get(&ud->shapes, i);
|
||||
if (is_shape_in_group_hierarchy(&ud->group_idx,s->group_id, gid, &ud->groups)) {
|
||||
s->selected = true;
|
||||
ud->interact.selected_count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void deselect_and_select_group_recursive(userdata_t *ud, int gid)
|
||||
{
|
||||
for (int i = 0; i < ud->shapes.count; i++)
|
||||
((shape_t*) vec_get(&ud->shapes, i))->selected = false;
|
||||
ud->interact.selected_count = 0;
|
||||
select_group_recursive(ud, gid);
|
||||
}
|
||||
|
||||
static void toggle_group_recursive(userdata_t *ud, int gid)
|
||||
{
|
||||
int total = 0, sel = 0;
|
||||
for (int i = 0; i < ud->shapes.count; i++) {
|
||||
shape_t *s = (shape_t*) vec_get(&ud->shapes, i);
|
||||
if (is_shape_in_group_hierarchy(&ud->group_idx,s->group_id, gid, &ud->groups)) {
|
||||
total++;
|
||||
if (s->selected) sel++;
|
||||
}
|
||||
}
|
||||
bool all_sel = (sel == total && total > 0);
|
||||
for (int i = 0; i < ud->shapes.count; i++) {
|
||||
shape_t *s = (shape_t*) vec_get(&ud->shapes, i);
|
||||
if (is_shape_in_group_hierarchy(&ud->group_idx,s->group_id, gid, &ud->groups)) {
|
||||
s->selected = !all_sel;
|
||||
ud->interact.selected_count += s->selected ? 1 : -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int hit_test_resize_handles(userdata_t *ud, float wx, float wy, float tol)
|
||||
{
|
||||
if (ud->interact.selected_count <= 0) return -1;
|
||||
float omin[2], omax[2];
|
||||
if (ud->interact.aabb_cached) {
|
||||
omin[0] = ud->interact.cached_aabb[0]; omin[1] = ud->interact.cached_aabb[1];
|
||||
omax[0] = ud->interact.cached_aabb[2]; omax[1] = ud->interact.cached_aabb[3];
|
||||
} else {
|
||||
selected_aabb(ud, &omin[0], &omin[1], &omax[0], &omax[1]);
|
||||
}
|
||||
float hs = CORNER_SIZE_PX / ud->camera.zoom * 0.5f + tol;
|
||||
float mid_x = (omin[0] + omax[0]) * 0.5f;
|
||||
float mid_y = (omin[1] + omax[1]) * 0.5f;
|
||||
float hx[8] = {omin[0], mid_x, omax[0], omax[0], omax[0], mid_x, omin[0], omin[0]};
|
||||
float hy[8] = {omin[1], omin[1], omin[1], mid_y, omax[1], omax[1], omax[1], mid_y};
|
||||
for (int h = 0; h < 8; h++) {
|
||||
if (fabsf(wx - hx[h]) <= hs && fabsf(wy - hy[h]) <= hs)
|
||||
return h;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
#endif
|
||||
547
src/main.c
547
src/main.c
@@ -1,120 +1,62 @@
|
||||
#include "api.h"
|
||||
|
||||
static void log_capture(const char* tag, uint32_t log_level, uint32_t log_item,
|
||||
const char* message, uint32_t line_nr, const char* filename,
|
||||
void* user_data)
|
||||
typedef struct uniform_t {
|
||||
float x, y;
|
||||
float zoom;
|
||||
} uniform_t;
|
||||
|
||||
typedef struct renderer_t {
|
||||
sg_pipeline pipeline;
|
||||
sg_pass_action clear_pass;
|
||||
uniform_t uniforms;
|
||||
} renderer_t;
|
||||
|
||||
typedef struct compute_t {
|
||||
sg_pipeline pipeline;
|
||||
sg_bindings bindings;
|
||||
} compute_t;
|
||||
|
||||
typedef struct userdata_t {
|
||||
scene_t scene;
|
||||
renderer_t renderer;
|
||||
compute_t compute;
|
||||
} userdata_t;
|
||||
|
||||
static void log_fn(const char* tag, uint32_t log_level, uint32_t log_item_id, const char* message_or_null, uint32_t line_nr, const char* filename_or_null, void* user_data)
|
||||
{
|
||||
userdata_t* ud = (userdata_t*)user_data;
|
||||
|
||||
const char* level_str;
|
||||
switch (log_level) {
|
||||
case 0: level_str = "panic"; break;
|
||||
case 1: level_str = "error"; break;
|
||||
case 2: level_str = "warn"; break;
|
||||
default:level_str = "info"; break;
|
||||
}
|
||||
|
||||
char buf[256];
|
||||
int n = snprintf(buf, sizeof(buf), "[%s][%s][id:%u]", tag, level_str, log_item);
|
||||
if (filename) {
|
||||
n += snprintf(buf + n, sizeof(buf) - n, " %s:%u:", filename, line_nr);
|
||||
}
|
||||
if (message && n < (int)sizeof(buf) - 2) {
|
||||
snprintf(buf + n, sizeof(buf) - n, " %s", message);
|
||||
}
|
||||
|
||||
int idx = ud->ui.log_head;
|
||||
strncpy(ud->ui.log_ring[idx].text, buf, 255);
|
||||
ud->ui.log_ring[idx].text[255] = 0;
|
||||
ud->ui.log_ring[idx].level = log_level;
|
||||
ud->ui.log_ring[idx].hash = 0;
|
||||
ud->ui.log_head = (idx + 1) % LOG_RING_SIZE;
|
||||
if (ud->ui.log_count < LOG_RING_SIZE) ud->ui.log_count++;
|
||||
|
||||
fprintf(stderr, "%s\n", buf);
|
||||
if (log_level <= 1) ud->ui.log_show = true;
|
||||
if(log_level < 2) return;
|
||||
fprintf(stderr, "[%s - %s]: (%d) %s \nat %s:%d", tag, log_level == 0 ? "FATAL" : log_level == 1 ? "ERROR" : "WARNING", log_item_id, message_or_null, filename_or_null, line_nr);
|
||||
}
|
||||
|
||||
static uint64_t fnv1a_64(const char *msg) {
|
||||
uint64_t h = 14695981039346656037ULL;
|
||||
while (*msg) {
|
||||
h ^= (uint64_t)(unsigned char)*msg++;
|
||||
h *= 1099511628211ULL;
|
||||
}
|
||||
return h;
|
||||
}
|
||||
|
||||
static void panel_log_impl(void *ud_v, int level, const char *msg) {
|
||||
userdata_t *ud = (userdata_t*)ud_v;
|
||||
|
||||
// Use a 64-bit message hash to skip the O(n) strcmp scan for most
|
||||
// non-matches. Debug-level messages (3) skip dedup entirely — they are
|
||||
// expected to repeat and the linear scan cost isn't worth it.
|
||||
if (level < 3) {
|
||||
uint64_t h = fnv1a_64(msg);
|
||||
int total = ud->ui.log_count < LOG_RING_SIZE ? ud->ui.log_count : LOG_RING_SIZE;
|
||||
for (int i = 0; i < total; i++) {
|
||||
if (ud->ui.log_ring[i].hash == h &&
|
||||
strcmp(ud->ui.log_ring[i].text, msg) == 0) return;
|
||||
}
|
||||
ud->ui.log_ring[ud->ui.log_head].hash = h;
|
||||
} else {
|
||||
ud->ui.log_ring[ud->ui.log_head].hash = 0;
|
||||
}
|
||||
|
||||
int idx = ud->ui.log_head;
|
||||
strncpy(ud->ui.log_ring[idx].text, msg, 255);
|
||||
ud->ui.log_ring[idx].text[255] = 0;
|
||||
ud->ui.log_ring[idx].level = (uint32_t)level;
|
||||
ud->ui.log_head = (idx + 1) % LOG_RING_SIZE;
|
||||
if (ud->ui.log_count < LOG_RING_SIZE) ud->ui.log_count++;
|
||||
}
|
||||
|
||||
static void meter_fps(userdata_t *ud)
|
||||
static void draw_scene(userdata_t* ud)
|
||||
{
|
||||
float dt = (float)sapp_frame_duration();
|
||||
float instant_fps = dt > 0.0001f ? 1.0f / dt : 0.0f;
|
||||
ud->debug.fps_immediate += (instant_fps - ud->debug.fps_immediate) * 0.1f;
|
||||
|
||||
int idx = ud->debug.frame_time_head;
|
||||
if (ud->debug.frame_time_count == 60) {
|
||||
ud->debug.frame_time_sum -= ud->debug.frame_times[idx];
|
||||
} else {
|
||||
ud->debug.frame_time_count++;
|
||||
/* if(ud->scene.dirty)
|
||||
{
|
||||
//sg_update_buffer(ud->compute.shared_buffer, SG_RANGE(ud->scene));
|
||||
ud->scene.dirty = false;
|
||||
}
|
||||
ud->debug.frame_times[idx] = dt;
|
||||
ud->debug.frame_time_sum += dt;
|
||||
ud->debug.frame_time_head = (idx + 1) % 60;
|
||||
ud->debug.fps_average = ud->debug.frame_time_sum > 0.0001f
|
||||
? (float)ud->debug.frame_time_count / ud->debug.frame_time_sum : 0.0f;
|
||||
|
||||
sg_begin_pass(&(sg_pass){ .compute = true, label = "compute-pass" });
|
||||
sg_apply_pipeline(ud->compute.pipeline);
|
||||
sg_apply_uniforms(0, &SG_RANGE(ud->renderer.uniforms));
|
||||
sg_apply_bindings(&ud->compute.bindings);
|
||||
|
||||
sg_dispatch(1, 1, 1);
|
||||
|
||||
sg_end_pass(); */
|
||||
}
|
||||
|
||||
static void frame(void* _userdata)
|
||||
{
|
||||
userdata_t* ud = (userdata_t*) _userdata;
|
||||
shape_begin_frame();
|
||||
|
||||
meter_fps(ud);
|
||||
ud->time += (double)sapp_frame_duration();
|
||||
spatial_rebuild(&ud->spatial_grid, &ud->shapes);
|
||||
|
||||
float sel_cx, sel_cy, sel_hw, sel_hh, sel_angle;
|
||||
shape_vertex_t overlay_verts[5];
|
||||
bool has_overlay, show_handle;
|
||||
compute_overlay_geometry(ud, overlay_verts, &sel_cx, &sel_cy,
|
||||
&sel_hw, &sel_hh, &sel_angle, &has_overlay, &show_handle);
|
||||
|
||||
upload_overlay_buffers(ud, overlay_verts, sel_cx, sel_cy,
|
||||
sel_hw, sel_hh, sel_angle, has_overlay, show_handle);
|
||||
draw_scene(ud);
|
||||
|
||||
sg_begin_pass(&(sg_pass){
|
||||
.action = ud->renderer.clear_pass,
|
||||
.swapchain = sglue_swapchain(),
|
||||
});
|
||||
|
||||
draw_shapes(ud);
|
||||
draw_overlay_and_handles(ud, has_overlay, show_handle);
|
||||
|
||||
simgui_new_frame(&(simgui_frame_desc_t){
|
||||
.width = sapp_width(),
|
||||
.height = sapp_height(),
|
||||
@@ -122,10 +64,10 @@ static void frame(void* _userdata)
|
||||
.dpi_scale = sapp_dpi_scale(),
|
||||
});
|
||||
|
||||
draw_top_panel(ud);
|
||||
draw_shape_list_panel(ud);
|
||||
draw_properties_panel(ud);
|
||||
draw_log_panel(ud);
|
||||
igBegin("Framerate", (bool*) true, ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoTitleBar);
|
||||
igText("%.0f FPS", 1 / sapp_frame_duration());
|
||||
igText("%.3fms", sapp_frame_duration() * 1000);
|
||||
igEnd();
|
||||
|
||||
simgui_render();
|
||||
sg_end_pass();
|
||||
@@ -136,86 +78,120 @@ static void init(void* _userdata)
|
||||
{
|
||||
userdata_t* ud = (userdata_t*) _userdata;
|
||||
|
||||
rand_seed(&ud->rand_ctx, 1);
|
||||
|
||||
ud->panel_log_ctx.fn = panel_log_impl;
|
||||
ud->panel_log_ctx.ud = ud;
|
||||
|
||||
sg_desc sgdesc = {
|
||||
sg_setup(&(sg_desc){
|
||||
.environment = sglue_environment(),
|
||||
.logger.func = log_capture,
|
||||
.logger.user_data = ud,
|
||||
.uniform_buffer_size = 16 * 1024 * 1024,
|
||||
};
|
||||
sg_setup(&sgdesc);
|
||||
if (!sg_isvalid()) {
|
||||
fprintf(stderr, "Failed to create Sokol GFX context!\n");
|
||||
exit(-1);
|
||||
}
|
||||
.logger.func = log_fn,
|
||||
});
|
||||
simgui_setup(&(simgui_desc_t){0});
|
||||
|
||||
const vec2 quad[4] = {
|
||||
{-2.0f, 2.0f},
|
||||
{2.0f, 2.0f},
|
||||
{2.0f, -2.0f},
|
||||
{-2.0f, -2.0f},
|
||||
};
|
||||
const vec2 uv[4] = {
|
||||
{0.0f, 1.0f},
|
||||
{1.0f, 1.0f},
|
||||
{1.0f, 0.0f},
|
||||
{0.0f, 0.0f},
|
||||
};
|
||||
const uint16_t indices[] = {
|
||||
0, 1, 2, 0, 2, 3,
|
||||
ud->scene = (scene_t) {0};
|
||||
if(!scene_init(&ud->scene, 128, 1024)) return;
|
||||
|
||||
ud->compute = (compute_t) {
|
||||
.pipeline = sg_make_pipeline(&(sg_pipeline_desc){
|
||||
.compute = true,
|
||||
.shader = sg_make_shader(&(sg_shader_desc) {
|
||||
.compute_func = {
|
||||
.source = (const char*) src_shaders_compute_wgsl,
|
||||
.entry = "main",
|
||||
},
|
||||
.views = {
|
||||
[0] = {
|
||||
.storage_buffer = {
|
||||
.stage = SG_SHADERSTAGE_COMPUTE,
|
||||
.wgsl_group1_binding_n = 0,
|
||||
.readonly = true,
|
||||
}
|
||||
},
|
||||
[1] = {
|
||||
.storage_buffer = {
|
||||
.stage = SG_SHADERSTAGE_COMPUTE,
|
||||
.wgsl_group1_binding_n = 1,
|
||||
.readonly = true,
|
||||
}
|
||||
},
|
||||
[2] = {
|
||||
.storage_buffer = {
|
||||
.stage = SG_SHADERSTAGE_COMPUTE,
|
||||
.wgsl_group1_binding_n = 2,
|
||||
.readonly = false,
|
||||
}
|
||||
}
|
||||
},
|
||||
.uniform_blocks = {
|
||||
[0] = {
|
||||
.size = sizeof(uniform_t),
|
||||
.stage = SG_SHADERSTAGE_COMPUTE,
|
||||
.wgsl_group0_binding_n = 0,
|
||||
},
|
||||
[1] = {
|
||||
.size = sizeof(tile_ID),
|
||||
.stage = SG_SHADERSTAGE_COMPUTE,
|
||||
.wgsl_group0_binding_n = 1,
|
||||
},
|
||||
},
|
||||
.label = "SDF Compute Shader",
|
||||
}),
|
||||
.label = "SDF Compute Pipeline",
|
||||
}),
|
||||
.bindings = (sg_bindings) {
|
||||
.views[0] = sg_make_view(&(sg_view_desc) {
|
||||
.label = "Segments view",
|
||||
.storage_buffer = {
|
||||
.buffer = sg_make_buffer(&(sg_buffer_desc) {
|
||||
.label = "Segment buffer",
|
||||
.usage = {
|
||||
.storage_buffer = true,
|
||||
.stream_update = true,
|
||||
},
|
||||
.size = sizeof(segment_t),
|
||||
}),
|
||||
},
|
||||
}),
|
||||
.views[1] = sg_make_view(&(sg_view_desc) {
|
||||
.label = "Shapes metadata view",
|
||||
.storage_buffer = {
|
||||
.buffer = sg_make_buffer(&(sg_buffer_desc) {
|
||||
.label = "Shapes metadata buffer",
|
||||
.usage = {
|
||||
.storage_buffer = true,
|
||||
.stream_update = true,
|
||||
},
|
||||
.size = sizeof(shape_meta_t),
|
||||
}),
|
||||
},
|
||||
}),
|
||||
.views[2] = sg_make_view(&(sg_view_desc) {
|
||||
.label = "SDF field view",
|
||||
.storage_buffer = {
|
||||
.buffer = sg_make_buffer(&(sg_buffer_desc) {
|
||||
.label = "SDF field buffer",
|
||||
.size = sizeof(float),
|
||||
.usage.storage_buffer = true,
|
||||
}),
|
||||
},
|
||||
}),
|
||||
}
|
||||
};
|
||||
|
||||
ud->camera.width = sapp_width();
|
||||
ud->camera.height = sapp_height();
|
||||
ud->camera.half_width = ud->camera.width * 0.5f;
|
||||
ud->camera.half_height = ud->camera.height * 0.5f;
|
||||
glm_vec2_zero(ud->camera.pan);
|
||||
ud->camera.zoom = 0.5f;
|
||||
ud->camera.hover_tol = SHAPE_HOVER_PX / ud->camera.zoom;
|
||||
|
||||
ud->renderer.shader = sg_make_shader(&(sg_shader_desc) {
|
||||
ud->renderer = (renderer_t) {
|
||||
.pipeline = sg_make_pipeline(&(sg_pipeline_desc){
|
||||
.shader = sg_make_shader(&(sg_shader_desc) {
|
||||
.vertex_func = {
|
||||
.source = (const char*) src_shaders_sprite_wgsl,
|
||||
.source = (const char*) src_shaders_display_wgsl,
|
||||
.entry = "vs_main",
|
||||
},
|
||||
.fragment_func = {
|
||||
.source = (const char*) src_shaders_sprite_wgsl,
|
||||
.source = (const char*) src_shaders_display_wgsl,
|
||||
.entry = "fs_main",
|
||||
},
|
||||
.views = {
|
||||
[0] = {
|
||||
.texture = {
|
||||
.stage = SG_SHADERSTAGE_FRAGMENT,
|
||||
.image_type = SG_IMAGETYPE_2D,
|
||||
.wgsl_group1_binding_n = 0,
|
||||
.sample_type = SG_IMAGESAMPLETYPE_FLOAT,
|
||||
},
|
||||
},
|
||||
[1] = {
|
||||
.storage_buffer = {
|
||||
.stage = SG_SHADERSTAGE_VERTEX,
|
||||
.readonly = true,
|
||||
.wgsl_group1_binding_n = 2,
|
||||
},
|
||||
},
|
||||
},
|
||||
.samplers = {
|
||||
[0] = {
|
||||
.stage = SG_SHADERSTAGE_FRAGMENT,
|
||||
.sampler_type = SG_SAMPLERTYPE_FILTERING,
|
||||
.wgsl_group1_binding_n = 1,
|
||||
.readonly = true,
|
||||
}
|
||||
},
|
||||
.texture_sampler_pairs = {
|
||||
[0] = {
|
||||
.stage = SG_SHADERSTAGE_FRAGMENT,
|
||||
.view_slot = 0,
|
||||
.sampler_slot = 0,
|
||||
}
|
||||
},
|
||||
.uniform_blocks = {
|
||||
@@ -224,229 +200,28 @@ static void init(void* _userdata)
|
||||
.stage = SG_SHADERSTAGE_VERTEX,
|
||||
.wgsl_group0_binding_n = 0,
|
||||
},
|
||||
[1] = {
|
||||
.size = sizeof(tile_ID),
|
||||
.stage = SG_SHADERSTAGE_VERTEX,
|
||||
.wgsl_group0_binding_n = 1,
|
||||
},
|
||||
.attrs[0] = {
|
||||
.base_type = SG_SHADERATTRBASETYPE_FLOAT,
|
||||
},
|
||||
.label = "Sprite shader",
|
||||
});
|
||||
|
||||
ud->renderer.clear_pass = (sg_pass_action) {
|
||||
.label = "Display Shader",
|
||||
}),
|
||||
.label = "Render pipeline",
|
||||
}),
|
||||
.clear_pass = (sg_pass_action) {
|
||||
.colors[0] = { .clear_value = { 0.0f, 0.0f, 0.0f, 1.0f }, .load_action = SG_LOADACTION_CLEAR }
|
||||
}
|
||||
};
|
||||
ud->renderer.pipeline = sg_make_pipeline(&(sg_pipeline_desc) {
|
||||
.shader = ud->renderer.shader,
|
||||
.index_type = SG_INDEXTYPE_UINT16,
|
||||
.layout.attrs = {
|
||||
[0].format = SG_VERTEXFORMAT_FLOAT2,
|
||||
[1].format = SG_VERTEXFORMAT_FLOAT2,
|
||||
},
|
||||
.label = "Sprite pipeline",
|
||||
});
|
||||
ud->renderer.uniform = (uniform_t) {
|
||||
.mvp = {
|
||||
1.0f, 0.0f, 0.0f, 0.0f,
|
||||
0.0f, 1.0f, 0.0f, 0.0f,
|
||||
0.0f, 0.0f, 1.0f, 0.0f,
|
||||
0.0f, 0.0f, 0.0f, 1.0f
|
||||
},
|
||||
};
|
||||
|
||||
shape_init_pipeline(&ud->pipelines, &ud->panel_log_ctx);
|
||||
|
||||
vec_init(&ud->shapes, sizeof(shape_t));
|
||||
vec_init(&ud->groups, sizeof(group_t));
|
||||
vec_init(&ud->interact.drag_indices, sizeof(int));
|
||||
spatial_init(&ud->spatial_grid);
|
||||
ud->interact.selected_count = 0;
|
||||
ud->interact.hovered_shape = -1;
|
||||
ud->interact.select.active = false;
|
||||
ud->interact.select.dragging = false;
|
||||
ud->ui.right_panel_w = 300;
|
||||
ud->ui.left_panel_w = 220;
|
||||
ud->ui.list_last_shape = -1;
|
||||
ud->ui.list_prev_count = -1;
|
||||
ud->ui.display_cache = NULL;
|
||||
ud->ui.display_cache_len = 0;
|
||||
ud->ui.display_cache_dirty = true;
|
||||
ud->interact.move.dragging = false;
|
||||
ud->interact.rotate.dragging = false;
|
||||
ud->interact.resize.dragging = false;
|
||||
ud->interact.resize.angle = 0.0f;
|
||||
ud->interact.resize.init = NULL;
|
||||
overlay_invalidate(ud);
|
||||
ud->interact.resize.init_count = 0;
|
||||
ud->next_group_id = 1;
|
||||
ud->time = 0.0;
|
||||
ud->interact.last_click_time = 0.0;
|
||||
ud->interact.last_click_shape_idx = -1;
|
||||
ud->map_w = 0;
|
||||
ud->map_h = 0;
|
||||
ud->ui.log_head = 0;
|
||||
ud->ui.log_count = 0;
|
||||
ud->ui.log_show = true;
|
||||
ud->ui.active_tool = TOOL_SELECT;
|
||||
|
||||
{
|
||||
ud->rect_vbuf = sg_make_buffer(&(sg_buffer_desc){
|
||||
.size = 5 * sizeof(shape_vertex_t),
|
||||
.usage = { .stream_update = true },
|
||||
.label = "Sel rect verts",
|
||||
});
|
||||
uint16_t rect_idx[5] = {0, 1, 2, 3, 4};
|
||||
ud->rect_ibuf = sg_make_buffer(&(sg_buffer_desc){
|
||||
.usage = {.index_buffer = true},
|
||||
.data = {rect_idx, sizeof(rect_idx)},
|
||||
.label = "Sel rect indices",
|
||||
});
|
||||
}
|
||||
|
||||
{
|
||||
const int n = HANDLE_CIRCLE_SEGMENTS + 1;
|
||||
uint16_t handle_idx[HANDLE_CIRCLE_SEGMENTS + 1];
|
||||
for (int i = 0; i < n; i++) handle_idx[i] = (uint16_t)i;
|
||||
ud->handle_vbuf = sg_make_buffer(&(sg_buffer_desc){
|
||||
.size = (size_t)n * sizeof(shape_vertex_t),
|
||||
.usage = { .stream_update = true },
|
||||
.label = "Handle verts",
|
||||
});
|
||||
ud->handle_ibuf = sg_make_buffer(&(sg_buffer_desc){
|
||||
.usage = {.index_buffer = true},
|
||||
.data = {handle_idx, sizeof(handle_idx)},
|
||||
.label = "Handle indices",
|
||||
});
|
||||
}
|
||||
|
||||
{
|
||||
ud->corner_vbuf = sg_make_buffer(&(sg_buffer_desc){
|
||||
.size = 40 * sizeof(shape_vertex_t),
|
||||
.usage = { .stream_update = true },
|
||||
.label = "Corner verts",
|
||||
});
|
||||
uint16_t ci[40];
|
||||
for (int i = 0; i < 40; i++) ci[i] = (uint16_t)i;
|
||||
ud->corner_ibuf = sg_make_buffer(&(sg_buffer_desc){
|
||||
.usage = {.index_buffer = true},
|
||||
.data = {ci, sizeof(ci)},
|
||||
.label = "Corner indices",
|
||||
});
|
||||
}
|
||||
|
||||
*((shape_t*) vec_push(&ud->shapes)) = shape_circle(&ud->shape_pool, 300.0f, 0.0f, 120.0f);
|
||||
|
||||
// Pen tool buffers
|
||||
{
|
||||
ud->pen_vbuf = sg_make_buffer(&(sg_buffer_desc){
|
||||
.size = PEN_PREVIEW_MAX_VERTS * sizeof(shape_vertex_t),
|
||||
.usage = { .stream_update = true },
|
||||
.label = "Pen preview verts",
|
||||
});
|
||||
uint16_t *pen_idx = (uint16_t*) ALLOC(PEN_PREVIEW_MAX_VERTS * sizeof(uint16_t));
|
||||
for (int i = 0; i < PEN_PREVIEW_MAX_VERTS; i++) pen_idx[i] = (uint16_t)i;
|
||||
ud->pen_ibuf = sg_make_buffer(&(sg_buffer_desc){
|
||||
.usage = {.index_buffer = true},
|
||||
.data = {pen_idx, (size_t)PEN_PREVIEW_MAX_VERTS * sizeof(uint16_t)},
|
||||
.label = "Pen preview indices",
|
||||
});
|
||||
FREE(pen_idx);
|
||||
memset(&ud->pen, 0, sizeof(ud->pen));
|
||||
}
|
||||
|
||||
// Edit mode buffers
|
||||
{
|
||||
int amax = PEN_MAX_CONTROL_POINTS * 5; // anchors
|
||||
int hmax = PEN_MAX_CONTROL_POINTS * 10; // handles (2 per anchor, 5 verts each)
|
||||
int lmax = PEN_MAX_CONTROL_POINTS * 4; // lines (2 per anchor, 2 verts each)
|
||||
|
||||
ud->ed_anchor_vbuf = sg_make_buffer(&(sg_buffer_desc){
|
||||
.size = (size_t)amax * sizeof(shape_vertex_t),
|
||||
.usage = { .stream_update = true },
|
||||
.label = "Edit anchor verts",
|
||||
});
|
||||
ud->ed_handle_vbuf = sg_make_buffer(&(sg_buffer_desc){
|
||||
.size = (size_t)hmax * sizeof(shape_vertex_t),
|
||||
.usage = { .stream_update = true },
|
||||
.label = "Edit handle verts",
|
||||
});
|
||||
ud->ed_handle_line_vbuf = sg_make_buffer(&(sg_buffer_desc){
|
||||
.size = (size_t)lmax * sizeof(shape_vertex_t),
|
||||
.usage = { .stream_update = true },
|
||||
.label = "Edit handle lines",
|
||||
});
|
||||
|
||||
int ibmax = hmax > lmax ? hmax : lmax;
|
||||
if (amax > ibmax) ibmax = amax;
|
||||
uint16_t *ed_idx = (uint16_t*) ALLOC((size_t)ibmax * sizeof(uint16_t));
|
||||
for (int i = 0; i < ibmax; i++) ed_idx[i] = (uint16_t)i;
|
||||
ud->ed_shared_ibuf = sg_make_buffer(&(sg_buffer_desc){
|
||||
.usage = {.index_buffer = true},
|
||||
.data = {ed_idx, (size_t)ibmax * sizeof(uint16_t)},
|
||||
.label = "Edit shared indices",
|
||||
});
|
||||
FREE(ed_idx);
|
||||
|
||||
ud->ed_anchor_count = 0;
|
||||
ud->ed_handle_count = 0;
|
||||
ud->ed_handle_line_count = 0;
|
||||
ud->interact.editing_shape_idx = -1;
|
||||
}
|
||||
history_init(&ud->history);
|
||||
|
||||
EM_ASM({
|
||||
window.addEventListener('keydown', function(e) {
|
||||
if (e.ctrlKey && !e.altKey && !e.metaKey) {
|
||||
if (e.key === 'z' || e.key === 'y' || e.key === 'c' || e.key === 'v' || e.key === 'g') {
|
||||
e.preventDefault();
|
||||
}
|
||||
}
|
||||
}, true);
|
||||
Module._cartograph_canvas = document.querySelector('canvas');
|
||||
});
|
||||
|
||||
compute_mvp(&ud->camera, &ud->renderer.uniform.mvp);
|
||||
}
|
||||
|
||||
static void cleanup(void* _userdata)
|
||||
{
|
||||
userdata_t* ud = (userdata_t*) _userdata;
|
||||
|
||||
for (int i = 0; i < ud->shapes.count; i++) {
|
||||
shape_shutdown(&ud->shape_pool, (shape_t*) vec_get(&ud->shapes, i));
|
||||
}
|
||||
spatial_destroy(&ud->spatial_grid);
|
||||
vec_free(&ud->shapes);
|
||||
group_shutdown_members(&ud->groups);
|
||||
vec_free(&ud->groups);
|
||||
vec_free(&ud->interact.drag_indices);
|
||||
group_index_shutdown(&ud->group_idx);
|
||||
history_destroy(&ud->history);
|
||||
if (ud->interact.edit_saved_ctrl) { FREE(ud->interact.edit_saved_ctrl); FREE(ud->interact.edit_saved_hin); FREE(ud->interact.edit_saved_hout); }
|
||||
if (ud->interact.resize.init) FREE(ud->interact.resize.init);
|
||||
sg_destroy_buffer(ud->rect_vbuf);
|
||||
sg_destroy_buffer(ud->rect_ibuf);
|
||||
sg_destroy_buffer(ud->handle_vbuf);
|
||||
sg_destroy_buffer(ud->handle_ibuf);
|
||||
sg_destroy_buffer(ud->corner_vbuf);
|
||||
sg_destroy_buffer(ud->corner_ibuf);
|
||||
sg_destroy_buffer(ud->pen_vbuf);
|
||||
sg_destroy_buffer(ud->pen_ibuf);
|
||||
sg_destroy_buffer(ud->ed_anchor_vbuf);
|
||||
sg_destroy_buffer(ud->ed_handle_vbuf);
|
||||
sg_destroy_buffer(ud->ed_handle_line_vbuf);
|
||||
sg_destroy_buffer(ud->ed_shared_ibuf);
|
||||
sg_destroy_pipeline(ud->renderer.pipeline);
|
||||
sg_destroy_shader(ud->renderer.shader);
|
||||
shape_pool_shutdown(&ud->shape_pool);
|
||||
shape_shutdown_pipeline(&ud->pipelines);
|
||||
|
||||
for (int i = 0; i < ud->clipboard.shape_count; i++) {
|
||||
FREE(ud->clipboard.shapes[i].verts);
|
||||
FREE(ud->clipboard.shapes[i].indices);
|
||||
}
|
||||
FREE(ud->clipboard.shapes);
|
||||
FREE(ud->ui.display_cache);
|
||||
|
||||
FREE(ud);
|
||||
scene_shutdown(&ud->scene);
|
||||
free(ud);
|
||||
|
||||
simgui_shutdown();
|
||||
sg_shutdown();
|
||||
@@ -457,17 +232,17 @@ static void event(const sapp_event* event, void* _userdata)
|
||||
userdata_t* ud = (userdata_t*) _userdata;
|
||||
|
||||
if (event->type == SAPP_EVENTTYPE_RESIZED) {
|
||||
handle_resize(ud, event);
|
||||
//handle_resize(ud, event);
|
||||
}
|
||||
|
||||
if (event->type == SAPP_EVENTTYPE_KEY_DOWN) {
|
||||
if (handle_key_down(ud, event)) return;
|
||||
//if (handle_key_down(ud, event)) return;
|
||||
}
|
||||
|
||||
if (simgui_handle_event(event)) return;
|
||||
|
||||
switch (event->type) {
|
||||
case SAPP_EVENTTYPE_MOUSE_DOWN:
|
||||
/* case SAPP_EVENTTYPE_MOUSE_DOWN:
|
||||
handle_mouse_down(ud, event);
|
||||
break;
|
||||
case SAPP_EVENTTYPE_MOUSE_UP:
|
||||
@@ -478,7 +253,7 @@ static void event(const sapp_event* event, void* _userdata)
|
||||
break;
|
||||
case SAPP_EVENTTYPE_MOUSE_SCROLL:
|
||||
handle_scroll_zoom(ud, event);
|
||||
break;
|
||||
break; */
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -486,7 +261,7 @@ static void event(const sapp_event* event, void* _userdata)
|
||||
|
||||
sapp_desc sokol_main(int argc, char* argv[])
|
||||
{
|
||||
userdata_t* userdata = (userdata_t*) ALLOC(sizeof(userdata_t));
|
||||
userdata_t* userdata = (userdata_t*) malloc(sizeof(userdata_t));
|
||||
|
||||
(void)argc;
|
||||
(void)argv;
|
||||
@@ -497,10 +272,6 @@ sapp_desc sokol_main(int argc, char* argv[])
|
||||
.cleanup_userdata_cb = cleanup,
|
||||
.event_userdata_cb = event,
|
||||
.window_title = "Sokol",
|
||||
.logger.func = slog_func,
|
||||
.allocator = {
|
||||
.alloc_fn = smemtrack_alloc,
|
||||
.free_fn = smemtrack_free,
|
||||
},
|
||||
.logger.func = log_fn,
|
||||
};
|
||||
}
|
||||
|
||||
247
src/overlay.h
247
src/overlay.h
@@ -1,247 +0,0 @@
|
||||
#ifndef OVERLAY_H
|
||||
#define OVERLAY_H
|
||||
|
||||
#include "api.h"
|
||||
#include "types.h"
|
||||
#include "interact.h"
|
||||
|
||||
static void overlay_invalidate(userdata_t *ud)
|
||||
{
|
||||
memset(&ud->overlay_upload, 1, sizeof(ud->overlay_upload));
|
||||
}
|
||||
|
||||
static void compute_overlay_geometry(userdata_t *ud,
|
||||
shape_vertex_t overlay_verts[5],
|
||||
float *sel_cx, float *sel_cy, float *sel_hw, float *sel_hh, float *sel_angle,
|
||||
bool *has_overlay, bool *show_handle)
|
||||
{
|
||||
*has_overlay = false;
|
||||
*sel_cx = *sel_cy = *sel_angle = 0;
|
||||
*sel_hw = *sel_hh = 0;
|
||||
|
||||
// Suppress selection/resize/rotate overlay during vertex edit mode
|
||||
if (ud->interact.editing_shape_idx >= 0) { *show_handle = false; return; }
|
||||
|
||||
if (ud->interact.select.active && ud->interact.select.dragging) {
|
||||
float wx1, wy1, wx2, wy2;
|
||||
screen_to_world(&ud->camera, ud->interact.select.start_x, ud->interact.select.start_y, &wx1, &wy1);
|
||||
screen_to_world(&ud->camera, ud->interact.select.current_x, ud->interact.select.current_y, &wx2, &wy2);
|
||||
float x1 = fminf(wx1, wx2), y1 = fminf(wy1, wy2);
|
||||
float x2 = fmaxf(wx1, wx2), y2 = fmaxf(wy1, wy2);
|
||||
overlay_verts[0] = (shape_vertex_t){x1, y1};
|
||||
overlay_verts[1] = (shape_vertex_t){x2, y1};
|
||||
overlay_verts[2] = (shape_vertex_t){x2, y2};
|
||||
overlay_verts[3] = (shape_vertex_t){x1, y2};
|
||||
overlay_verts[4] = (shape_vertex_t){x1, y1};
|
||||
*has_overlay = true;
|
||||
} else if (ud->interact.selected_count >= 1) {
|
||||
if (ud->interact.move.dragging && ud->interact.aabb_cached) {
|
||||
float dx = ud->interact.move.total_dx;
|
||||
float dy = ud->interact.move.total_dy;
|
||||
float omin_x = ud->interact.cached_aabb[0] + dx;
|
||||
float omin_y = ud->interact.cached_aabb[1] + dy;
|
||||
float omax_x = ud->interact.cached_aabb[2] + dx;
|
||||
float omax_y = ud->interact.cached_aabb[3] + dy;
|
||||
float pad = 8.0f / ud->camera.zoom;
|
||||
overlay_verts[0] = (shape_vertex_t){omin_x - pad, omin_y - pad};
|
||||
overlay_verts[1] = (shape_vertex_t){omax_x + pad, omin_y - pad};
|
||||
overlay_verts[2] = (shape_vertex_t){omax_x + pad, omax_y + pad};
|
||||
overlay_verts[3] = (shape_vertex_t){omin_x - pad, omax_y + pad};
|
||||
overlay_verts[4] = overlay_verts[0];
|
||||
*sel_cx = (omin_x + omax_x) * 0.5f;
|
||||
*sel_cy = (omin_y + omax_y) * 0.5f;
|
||||
*sel_hw = (omax_x - omin_x) * 0.5f + pad;
|
||||
*sel_hh = (omax_y - omin_y) * 0.5f + pad;
|
||||
*sel_angle = 0;
|
||||
*has_overlay = true;
|
||||
} else if (ud->interact.selected_count == 1) {
|
||||
for (int i = 0; i < ud->shapes.count; i++) {
|
||||
shape_t *s = (shape_t*) vec_get(&ud->shapes, i);
|
||||
if (!s->selected) continue;
|
||||
*sel_cx = s->cx; *sel_cy = s->cy;
|
||||
*sel_angle = s->rotation;
|
||||
float x1, y1, x2, y2;
|
||||
selected_aabb(ud, &x1, &y1, &x2, &y2);
|
||||
*sel_hw = (x2 - x1) * 0.5f;
|
||||
*sel_hh = (y2 - y1) * 0.5f;
|
||||
ud->interact.cached_aabb[0] = x1; ud->interact.cached_aabb[1] = y1;
|
||||
ud->interact.cached_aabb[2] = x2; ud->interact.cached_aabb[3] = y2;
|
||||
ud->interact.aabb_cached = true;
|
||||
overlay_verts[0] = (shape_vertex_t){x1, y1};
|
||||
overlay_verts[1] = (shape_vertex_t){x2, y1};
|
||||
overlay_verts[2] = (shape_vertex_t){x2, y2};
|
||||
overlay_verts[3] = (shape_vertex_t){x1, y2};
|
||||
overlay_verts[4] = overlay_verts[0];
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
float omin[2], omax[2];
|
||||
float sum_sin = 0, sum_cos = 0;
|
||||
for (int i = 0; i < ud->shapes.count; i++) {
|
||||
shape_t *s = (shape_t*) vec_get(&ud->shapes, i);
|
||||
if (!s->selected) continue;
|
||||
sum_sin += s->sin_r;
|
||||
sum_cos += s->cos_r;
|
||||
}
|
||||
selected_aabb(ud, &omin[0], &omin[1], &omax[0], &omax[1]);
|
||||
ud->interact.cached_aabb[0] = omin[0]; ud->interact.cached_aabb[1] = omin[1];
|
||||
ud->interact.cached_aabb[2] = omax[0]; ud->interact.cached_aabb[3] = omax[1];
|
||||
ud->interact.aabb_cached = true;
|
||||
float pad = 8.0f / ud->camera.zoom;
|
||||
omin[0] -= pad; omin[1] -= pad;
|
||||
omax[0] += pad; omax[1] += pad;
|
||||
*sel_cx = (omin[0] + omax[0]) * 0.5f;
|
||||
*sel_cy = (omin[1] + omax[1]) * 0.5f;
|
||||
*sel_hw = (omax[0] - omin[0]) * 0.5f;
|
||||
*sel_hh = (omax[1] - omin[1]) * 0.5f;
|
||||
*sel_angle = atan2f(sum_sin, sum_cos);
|
||||
|
||||
overlay_verts[0] = (shape_vertex_t){omin[0], omin[1]};
|
||||
overlay_verts[1] = (shape_vertex_t){omax[0], omin[1]};
|
||||
overlay_verts[2] = (shape_vertex_t){omax[0], omax[1]};
|
||||
overlay_verts[3] = (shape_vertex_t){omin[0], omax[1]};
|
||||
overlay_verts[4] = overlay_verts[0];
|
||||
}
|
||||
*has_overlay = true;
|
||||
}
|
||||
|
||||
*show_handle = ud->interact.selected_count > 0 && !ud->interact.select.active;
|
||||
}
|
||||
|
||||
static void upload_overlay_buffers(userdata_t *ud,
|
||||
const shape_vertex_t overlay_verts[5],
|
||||
float sel_cx, float sel_cy, float sel_hw, float sel_hh, float sel_angle,
|
||||
bool has_overlay, bool show_handle)
|
||||
{
|
||||
bool need_upload = ud->overlay_upload.rect ||
|
||||
ud->interact.move.dragging || ud->interact.rotate.dragging ||
|
||||
ud->interact.resize.dragging || ud->interact.select.active ||
|
||||
(ud->interact.editing_shape_idx >= 0);
|
||||
|
||||
static shape_vertex_t ed_anchor_verts[128 * 5];
|
||||
static shape_vertex_t ed_handle_verts[256 * 5];
|
||||
static shape_vertex_t ed_line_verts[256 * 2];
|
||||
|
||||
if (has_overlay && need_upload) {
|
||||
sg_update_buffer(ud->rect_vbuf, &(sg_range){overlay_verts, (size_t)5 * sizeof(shape_vertex_t)});
|
||||
}
|
||||
|
||||
if (show_handle) {
|
||||
float pad = HANDLE_OFFSET_PX / ud->camera.zoom;
|
||||
float radius = sqrtf(sel_hw * sel_hw + sel_hh * sel_hh) + pad;
|
||||
|
||||
ud->interact.rotate.center_x = sel_cx;
|
||||
ud->interact.rotate.center_y = sel_cy;
|
||||
ud->interact.rotate.handle_radius = radius;
|
||||
|
||||
const int n = HANDLE_CIRCLE_SEGMENTS + 1;
|
||||
static shape_vertex_t unit_circle[HANDLE_CIRCLE_SEGMENTS + 1];
|
||||
static bool unit_circle_ready = false;
|
||||
if (!unit_circle_ready) {
|
||||
for (int i = 0; i < n; i++) {
|
||||
float a = (float)i / (float)HANDLE_CIRCLE_SEGMENTS * 2.0f * GLM_PIf;
|
||||
unit_circle[i] = (shape_vertex_t){cosf(a), sinf(a)};
|
||||
}
|
||||
unit_circle_ready = true;
|
||||
}
|
||||
shape_vertex_t hv[HANDLE_CIRCLE_SEGMENTS + 1];
|
||||
for (int i = 0; i < n; i++) {
|
||||
hv[i] = (shape_vertex_t){sel_cx + unit_circle[i].x * radius,
|
||||
sel_cy + unit_circle[i].y * radius};
|
||||
}
|
||||
if (need_upload)
|
||||
sg_update_buffer(ud->handle_vbuf, &(sg_range){hv, sizeof(hv)});
|
||||
|
||||
{
|
||||
float hs = CORNER_SIZE_PX / ud->camera.zoom * 0.5f;
|
||||
float mid_x = (overlay_verts[0].x + overlay_verts[1].x) * 0.5f;
|
||||
float mid_y = (overlay_verts[0].y + overlay_verts[2].y) * 0.5f;
|
||||
float handles[8][2] = {
|
||||
{overlay_verts[0].x, overlay_verts[0].y},
|
||||
{mid_x, overlay_verts[0].y},
|
||||
{overlay_verts[1].x, overlay_verts[1].y},
|
||||
{overlay_verts[1].x, mid_y },
|
||||
{overlay_verts[2].x, overlay_verts[2].y},
|
||||
{mid_x, overlay_verts[2].y},
|
||||
{overlay_verts[3].x, overlay_verts[3].y},
|
||||
{overlay_verts[3].x, mid_y },
|
||||
};
|
||||
shape_vertex_t cv[40];
|
||||
for (int h = 0; h < 8; h++) {
|
||||
float cx = handles[h][0], cy = handles[h][1];
|
||||
cv[h*5+0] = (shape_vertex_t){cx - hs, cy - hs};
|
||||
cv[h*5+1] = (shape_vertex_t){cx + hs, cy - hs};
|
||||
cv[h*5+2] = (shape_vertex_t){cx + hs, cy + hs};
|
||||
cv[h*5+3] = (shape_vertex_t){cx - hs, cy + hs};
|
||||
cv[h*5+4] = (shape_vertex_t){cx - hs, cy - hs};
|
||||
}
|
||||
if (need_upload)
|
||||
sg_update_buffer(ud->corner_vbuf, &(sg_range){cv, sizeof(cv)});
|
||||
}
|
||||
}
|
||||
|
||||
// Edit mode overlay
|
||||
if (ud->interact.editing_shape_idx >= 0 && need_upload) {
|
||||
shape_t *es = (shape_t*) vec_get(&ud->shapes, ud->interact.editing_shape_idx);
|
||||
int n = es->ctrl_count;
|
||||
if (n > 128) n = 128;
|
||||
|
||||
float as = EDIT_ANCHOR_SIZE_PX / ud->camera.zoom * 0.5f;
|
||||
float hs = EDIT_HANDLE_SIZE_PX / ud->camera.zoom * 0.5f;
|
||||
|
||||
int ac = 0, hc = 0, lc = 0;
|
||||
for (int i = 0; i < n; i++) {
|
||||
shape_vertex_t wa = local_to_world(es, es->ctrl_points[i].x, es->ctrl_points[i].y);
|
||||
// Anchor square
|
||||
int ba = ac * 5;
|
||||
ed_anchor_verts[ba+0] = (shape_vertex_t){wa.x - as, wa.y - as};
|
||||
ed_anchor_verts[ba+1] = (shape_vertex_t){wa.x + as, wa.y - as};
|
||||
ed_anchor_verts[ba+2] = (shape_vertex_t){wa.x + as, wa.y + as};
|
||||
ed_anchor_verts[ba+3] = (shape_vertex_t){wa.x - as, wa.y + as};
|
||||
ed_anchor_verts[ba+4] = (shape_vertex_t){wa.x - as, wa.y - as};
|
||||
ac++;
|
||||
|
||||
shape_vertex_t wh_in = local_to_world(es, es->ctrl_handle_in[i].x, es->ctrl_handle_in[i].y);
|
||||
shape_vertex_t wh_out = local_to_world(es, es->ctrl_handle_out[i].x, es->ctrl_handle_out[i].y);
|
||||
|
||||
// Handle line: anchor → in handle
|
||||
ed_line_verts[lc++] = wa;
|
||||
ed_line_verts[lc++] = wh_in;
|
||||
// Handle line: anchor → out handle
|
||||
ed_line_verts[lc++] = wa;
|
||||
ed_line_verts[lc++] = wh_out;
|
||||
|
||||
// In handle square
|
||||
int bh = hc * 5;
|
||||
ed_handle_verts[bh+0] = (shape_vertex_t){wh_in.x - hs, wh_in.y - hs};
|
||||
ed_handle_verts[bh+1] = (shape_vertex_t){wh_in.x + hs, wh_in.y - hs};
|
||||
ed_handle_verts[bh+2] = (shape_vertex_t){wh_in.x + hs, wh_in.y + hs};
|
||||
ed_handle_verts[bh+3] = (shape_vertex_t){wh_in.x - hs, wh_in.y + hs};
|
||||
ed_handle_verts[bh+4] = (shape_vertex_t){wh_in.x - hs, wh_in.y - hs};
|
||||
hc++;
|
||||
// Out handle square
|
||||
bh = hc * 5;
|
||||
ed_handle_verts[bh+0] = (shape_vertex_t){wh_out.x - hs, wh_out.y - hs};
|
||||
ed_handle_verts[bh+1] = (shape_vertex_t){wh_out.x + hs, wh_out.y - hs};
|
||||
ed_handle_verts[bh+2] = (shape_vertex_t){wh_out.x + hs, wh_out.y + hs};
|
||||
ed_handle_verts[bh+3] = (shape_vertex_t){wh_out.x - hs, wh_out.y + hs};
|
||||
ed_handle_verts[bh+4] = (shape_vertex_t){wh_out.x - hs, wh_out.y - hs};
|
||||
hc++;
|
||||
}
|
||||
|
||||
ud->ed_anchor_count = ac;
|
||||
ud->ed_handle_count = hc;
|
||||
ud->ed_handle_line_count = lc;
|
||||
|
||||
if (ac > 0)
|
||||
sg_update_buffer(ud->ed_anchor_vbuf, &(sg_range){ed_anchor_verts, (size_t)(ac * 5) * sizeof(shape_vertex_t)});
|
||||
if (hc > 0)
|
||||
sg_update_buffer(ud->ed_handle_vbuf, &(sg_range){ed_handle_verts, (size_t)(hc * 5) * sizeof(shape_vertex_t)});
|
||||
if (lc > 0)
|
||||
sg_update_buffer(ud->ed_handle_line_vbuf, &(sg_range){ed_line_verts, (size_t)lc * sizeof(shape_vertex_t)});
|
||||
}
|
||||
|
||||
memset(&ud->overlay_upload, 0, sizeof(ud->overlay_upload));
|
||||
}
|
||||
|
||||
#endif
|
||||
116
src/rand.h
116
src/rand.h
@@ -1,116 +0,0 @@
|
||||
#ifndef RAND_H
|
||||
#define RAND_H
|
||||
|
||||
#include "api.h"
|
||||
|
||||
typedef struct {
|
||||
uint32_t seed;
|
||||
} rand_ctx_t;
|
||||
|
||||
static uint32_t xorshift32(rand_ctx_t *r);
|
||||
static void rand_seed(rand_ctx_t *r, uint32_t _seed);
|
||||
static uint32_t next_int(rand_ctx_t *r);
|
||||
static uint32_t next_int_max(rand_ctx_t *r, uint32_t max);
|
||||
static uint32_t next_int_minmax(rand_ctx_t *r, uint32_t min, uint32_t max);
|
||||
static float next_float(rand_ctx_t *r);
|
||||
static float next_float_max(rand_ctx_t *r, float max);
|
||||
static float next_float_minmax(rand_ctx_t *r, float min, float max);
|
||||
|
||||
/**
|
||||
* Xorshift32 PRNG core. Advances the seed and returns the new value.
|
||||
*
|
||||
* @param r PRNG context
|
||||
* @return pseudo-random 32-bit integer
|
||||
*/
|
||||
static uint32_t xorshift32(rand_ctx_t *r)
|
||||
{
|
||||
r->seed ^= r->seed<<13;
|
||||
r->seed ^= r->seed>>17;
|
||||
r->seed ^= r->seed<<5;
|
||||
return r->seed;
|
||||
}
|
||||
/**
|
||||
* Seed the PRNG state. Zero is ignored (caller should pass a non-zero
|
||||
* seed). Runs the generator once after seeding to mix the state.
|
||||
*
|
||||
* @param r PRNG context
|
||||
* @param _seed non-zero 32-bit seed value
|
||||
*/
|
||||
static void rand_seed(rand_ctx_t *r, uint32_t _seed)
|
||||
{
|
||||
if(_seed == 0)
|
||||
return;
|
||||
|
||||
r->seed = _seed;
|
||||
xorshift32(r);
|
||||
}
|
||||
/**
|
||||
* Return a random integer in [0, UINT32_MAX].
|
||||
*
|
||||
* @param r PRNG context
|
||||
* @return pseudo-random 32-bit integer
|
||||
*/
|
||||
static uint32_t next_int(rand_ctx_t *r)
|
||||
{
|
||||
return xorshift32(r);
|
||||
}
|
||||
/**
|
||||
* Return a random integer in [0, max].
|
||||
*
|
||||
* @param r PRNG context
|
||||
* @param max inclusive upper bound
|
||||
* @return pseudo-random integer
|
||||
*/
|
||||
static uint32_t next_int_max(rand_ctx_t *r, uint32_t max)
|
||||
{
|
||||
return (uint32_t)((double)xorshift32(r) / (double)UINT32_MAX * max);
|
||||
}
|
||||
/**
|
||||
* Return a random integer in [min, max].
|
||||
*
|
||||
* @param r PRNG context
|
||||
* @param min inclusive lower bound
|
||||
* @param max inclusive upper bound
|
||||
* @return pseudo-random integer
|
||||
*/
|
||||
static uint32_t next_int_minmax(rand_ctx_t *r, uint32_t min, uint32_t max)
|
||||
{
|
||||
const double x = (double)xorshift32(r) / (double)UINT32_MAX;
|
||||
return (uint32_t)((1.0 - x) * min + x * max);
|
||||
}
|
||||
/**
|
||||
* Return a random float in [0, 1].
|
||||
*
|
||||
* @param r PRNG context
|
||||
* @return pseudo-random float
|
||||
*/
|
||||
static float next_float(rand_ctx_t *r)
|
||||
{
|
||||
return (float)((double)xorshift32(r) / (double)UINT32_MAX);
|
||||
}
|
||||
/**
|
||||
* Return a random float in [0, max].
|
||||
*
|
||||
* @param r PRNG context
|
||||
* @param max inclusive upper bound
|
||||
* @return pseudo-random float
|
||||
*/
|
||||
static float next_float_max(rand_ctx_t *r, float max)
|
||||
{
|
||||
return (float)((double)xorshift32(r) / (double)UINT32_MAX * max);
|
||||
}
|
||||
/**
|
||||
* Return a random float in [min, max].
|
||||
*
|
||||
* @param r PRNG context
|
||||
* @param min inclusive lower bound
|
||||
* @param max inclusive upper bound
|
||||
* @return pseudo-random float
|
||||
*/
|
||||
static float next_float_minmax(rand_ctx_t *r, float min, float max)
|
||||
{
|
||||
const double x = (double)xorshift32(r) / (double)UINT32_MAX;
|
||||
return (float)((1.0 - x) * min + x * max);
|
||||
}
|
||||
|
||||
#endif
|
||||
133
src/render.h
133
src/render.h
@@ -1,133 +0,0 @@
|
||||
#ifndef RENDER_H
|
||||
#define RENDER_H
|
||||
|
||||
#include "api.h"
|
||||
|
||||
// Pipeline state — was static globals, now owned by userdata_t.
|
||||
typedef struct {
|
||||
sg_pipeline shape_pipeline;
|
||||
sg_shader shape_shader;
|
||||
sg_pipeline overlay_pipeline;
|
||||
sg_shader overlay_shader;
|
||||
} pipeline_ctx_t;
|
||||
|
||||
static int g_shape_frame_id;
|
||||
|
||||
static void shape_begin_frame(void)
|
||||
{
|
||||
g_shape_frame_id++;
|
||||
}
|
||||
|
||||
// Pipeline state is owned by pipeline_ctx_t (embedded in userdata_t).
|
||||
// Previously these were file-scope statics, which prevented multi-TU builds.
|
||||
static void shape_init_pipeline(pipeline_ctx_t *p, panel_log_ctx_t *pl)
|
||||
{
|
||||
// Overlay shader/pipeline (simple, no storage buffers)
|
||||
p->overlay_shader = sg_make_shader(&(sg_shader_desc) {
|
||||
.vertex_func = {
|
||||
.source = (const char*) src_shaders_overlay_wgsl,
|
||||
.entry = "vs_main",
|
||||
},
|
||||
.fragment_func = {
|
||||
.source = (const char*) src_shaders_overlay_wgsl,
|
||||
.entry = "fs_main",
|
||||
},
|
||||
.uniform_blocks = {
|
||||
[0] = {
|
||||
.size = sizeof(mat4),
|
||||
.stage = SG_SHADERSTAGE_VERTEX,
|
||||
.wgsl_group0_binding_n = 0,
|
||||
},
|
||||
[1] = {
|
||||
.size = sizeof(shape_uniform_t),
|
||||
.stage = SG_SHADERSTAGE_VERTEX,
|
||||
.wgsl_group0_binding_n = 1,
|
||||
},
|
||||
},
|
||||
.attrs = {
|
||||
[0] = { .base_type = SG_SHADERATTRBASETYPE_FLOAT },
|
||||
},
|
||||
.label = "Overlay shader",
|
||||
});
|
||||
panel_log_debug(pl, "[shapes] overlay shader id=%d valid=%d", p->overlay_shader.id, sg_isvalid());
|
||||
if (p->overlay_shader.id == SG_INVALID_ID)
|
||||
panel_log(pl, 1, "[shapes] FAILED to create overlay shader");
|
||||
|
||||
p->overlay_pipeline = sg_make_pipeline(&(sg_pipeline_desc) {
|
||||
.shader = p->overlay_shader,
|
||||
.index_type = SG_INDEXTYPE_UINT16,
|
||||
.primitive_type = SG_PRIMITIVETYPE_LINE_STRIP,
|
||||
.layout.attrs = {
|
||||
[0].format = SG_VERTEXFORMAT_FLOAT2,
|
||||
},
|
||||
.label = "Overlay pipeline",
|
||||
});
|
||||
panel_log_debug(pl, "[shapes] overlay pipeline id=%d valid=%d", p->overlay_pipeline.id, sg_isvalid());
|
||||
if (p->overlay_pipeline.id == SG_INVALID_ID)
|
||||
panel_log(pl, 1, "[shapes] FAILED to create overlay pipeline");
|
||||
|
||||
// Shape shader/pipeline (storage buffers, instanced)
|
||||
p->shape_shader = sg_make_shader(&(sg_shader_desc) {
|
||||
.vertex_func = {
|
||||
.source = (const char*) src_shaders_shape_wgsl,
|
||||
.entry = "vs_main",
|
||||
},
|
||||
.fragment_func = {
|
||||
.source = (const char*) src_shaders_shape_wgsl,
|
||||
.entry = "fs_main",
|
||||
},
|
||||
.uniform_blocks = {
|
||||
[0] = {
|
||||
.size = 80,
|
||||
.stage = SG_SHADERSTAGE_VERTEX,
|
||||
.wgsl_group0_binding_n = 0,
|
||||
},
|
||||
},
|
||||
.views = {
|
||||
[0] = {
|
||||
.storage_buffer = {
|
||||
.stage = SG_SHADERSTAGE_VERTEX,
|
||||
.readonly = true,
|
||||
.wgsl_group1_binding_n = 0,
|
||||
},
|
||||
},
|
||||
[1] = {
|
||||
.storage_buffer = {
|
||||
.stage = SG_SHADERSTAGE_VERTEX,
|
||||
.readonly = true,
|
||||
.wgsl_group1_binding_n = 1,
|
||||
},
|
||||
},
|
||||
},
|
||||
.attrs = {
|
||||
[0] = { .base_type = SG_SHADERATTRBASETYPE_FLOAT },
|
||||
},
|
||||
.label = "Shape shader",
|
||||
});
|
||||
panel_log_debug(pl, "[shapes] shader id=%d valid=%d", p->shape_shader.id, sg_isvalid());
|
||||
if (p->shape_shader.id == SG_INVALID_ID)
|
||||
panel_log(pl, 1, "[shapes] FAILED to create shape shader");
|
||||
|
||||
p->shape_pipeline = sg_make_pipeline(&(sg_pipeline_desc) {
|
||||
.shader = p->shape_shader,
|
||||
.index_type = SG_INDEXTYPE_NONE,
|
||||
.primitive_type = SG_PRIMITIVETYPE_LINE_STRIP,
|
||||
.layout.attrs = {
|
||||
[0].format = SG_VERTEXFORMAT_FLOAT2,
|
||||
},
|
||||
.label = "Shape pipeline",
|
||||
});
|
||||
panel_log_debug(pl, "[shapes] pipeline id=%d valid=%d", p->shape_pipeline.id, sg_isvalid());
|
||||
if (p->shape_pipeline.id == SG_INVALID_ID)
|
||||
panel_log(pl, 1, "[shapes] FAILED to create shape pipeline");
|
||||
}
|
||||
|
||||
static void shape_shutdown_pipeline(pipeline_ctx_t *p)
|
||||
{
|
||||
sg_destroy_pipeline(p->shape_pipeline);
|
||||
sg_destroy_shader(p->shape_shader);
|
||||
sg_destroy_pipeline(p->overlay_pipeline);
|
||||
sg_destroy_shader(p->overlay_shader);
|
||||
}
|
||||
|
||||
#endif
|
||||
217
src/shaders/compute.wgsl
Normal file
217
src/shaders/compute.wgsl
Normal file
@@ -0,0 +1,217 @@
|
||||
// ---------- Bindings (exactly as you defined) ----------
|
||||
struct Segment {
|
||||
p0: vec2f,
|
||||
p1: vec2f,
|
||||
p2: vec2f,
|
||||
p3: vec2f,
|
||||
}
|
||||
struct ShapeMeta {
|
||||
start_segment: u32,
|
||||
segment_count: u32,
|
||||
bbox_min: vec2f,
|
||||
bbox_max: vec2f,
|
||||
}
|
||||
|
||||
@group(1) @binding(0) var<storage> segments: array<Segment>;
|
||||
@group(1) @binding(1) var<storage> shapes: array<ShapeMeta>;
|
||||
@group(1) @binding(2) var<storage, read_write> sdf_buffer: array<f32>;
|
||||
|
||||
struct Uniforms {
|
||||
pan: vec2f,
|
||||
zoom: f32,
|
||||
};
|
||||
struct TileParams {
|
||||
lod: u32,
|
||||
tile_size: f32,
|
||||
world_min: vec2f,
|
||||
world_max: vec2f,
|
||||
};
|
||||
|
||||
@group(0) @binding(0) var<uniform> uniforms: Uniforms;
|
||||
@group(0) @binding(1) var<uniform> tile_params: TileParams;
|
||||
|
||||
|
||||
// ---------- Cubic Bézier helpers ----------
|
||||
fn eval_cubic(t: f32, p0: vec2f, p1: vec2f, p2: vec2f, p3: vec2f) -> vec2f {
|
||||
let mt = 1.0 - t;
|
||||
let mt2 = mt * mt;
|
||||
let t2 = t * t;
|
||||
return mt2 * mt * p0 + 3.0 * mt2 * t * p1 + 3.0 * mt * t2 * p2 + t2 * t * p3;
|
||||
}
|
||||
|
||||
fn eval_cubic_derivative(t: f32, p0: vec2f, p1: vec2f, p2: vec2f, p3: vec2f) -> vec2f {
|
||||
let mt = 1.0 - t;
|
||||
return 3.0 * mt * mt * (p1 - p0) + 6.0 * mt * t * (p2 - p1) + 3.0 * t * t * (p3 - p2);
|
||||
}
|
||||
|
||||
// ---------- Distance to a cubic Bézier (sampling + Newton refinement) ----------
|
||||
fn distance_to_cubic(p: vec2f, seg: Segment) -> f32 {
|
||||
let p0 = seg.p0; let p1 = seg.p1; let p2 = seg.p2; let p3 = seg.p3;
|
||||
|
||||
// Uniform sampling to find a good starting t
|
||||
let samples = 16u;
|
||||
var best_t = 0.0;
|
||||
var best_dist = 1e20;
|
||||
for (var i = 0u; i < samples; i++) {
|
||||
let t = f32(i) / f32(samples - 1u);
|
||||
let q = eval_cubic(t, p0, p1, p2, p3);
|
||||
let d = distance(p, q);
|
||||
if d < best_dist {
|
||||
best_dist = d;
|
||||
best_t = t;
|
||||
}
|
||||
}
|
||||
|
||||
// Newton refinement on the squared distance (max 4 iterations)
|
||||
var t = clamp(best_t, 0.0, 1.0);
|
||||
for (var iter = 0u; iter < 4u; iter++) {
|
||||
let B = eval_cubic(t, p0, p1, p2, p3) - p;
|
||||
let Bp = eval_cubic_derivative(t, p0, p1, p2, p3);
|
||||
let f = dot(B, Bp); // ½ derivative of |B|²
|
||||
let df = dot(Bp, Bp) + dot(B, 3.0 * (p2 - p1 + (p3 - p2 - p2 + p1) * 2.0 * t)); // simplified 2nd deriv
|
||||
if abs(df) < 1e-12 { break; }
|
||||
let step = f / df;
|
||||
t = clamp(t - step, 0.0, 1.0);
|
||||
if abs(step) < 1e-6 { break; }
|
||||
}
|
||||
let q_final = eval_cubic(t, p0, p1, p2, p3);
|
||||
return distance(p, q_final);
|
||||
}
|
||||
|
||||
// ---------- Analytical cubic root solver (for y-crossing) ----------
|
||||
// Returns number of real roots in [0,1], stored in roots array (up to 3).
|
||||
fn solve_cubic_in_01(c3: f32, c2: f32, c1: f32, c0: f32, roots: ptr<function, array<f32, 3>>) -> u32 {
|
||||
// Normalise: c3 * t^3 + c2 * t^2 + c1 * t + c0 = 0
|
||||
if abs(c3) < 1e-9 {
|
||||
// Quadratic fallback
|
||||
if abs(c2) < 1e-9 {
|
||||
if abs(c1) < 1e-9 { return 0u; }
|
||||
let t = -c0 / c1;
|
||||
if t >= 0.0 && t <= 1.0 {
|
||||
(*roots)[0] = t;
|
||||
return 1u;
|
||||
}
|
||||
return 0u;
|
||||
}
|
||||
let disc = c1 * c1 - 4.0 * c2 * c0;
|
||||
if disc < 0.0 { return 0u; }
|
||||
let sd = sqrt(disc);
|
||||
let t0 = (-c1 + sd) / (2.0 * c2);
|
||||
let t1 = (-c1 - sd) / (2.0 * c2);
|
||||
var count = 0u;
|
||||
if t0 >= 0.0 && t0 <= 1.0 { (*roots)[count] = t0; count++; }
|
||||
if t1 >= 0.0 && t1 <= 1.0 { (*roots)[count] = t1; count++; }
|
||||
return count;
|
||||
}
|
||||
|
||||
// Depressed cubic: let t = x - c2/(3*c3)
|
||||
let a = c2 / c3;
|
||||
let b = c1 / c3;
|
||||
let c = c0 / c3;
|
||||
let p = b - a * a / 3.0;
|
||||
let q = 2.0 * a * a * a / 27.0 - a * b / 3.0 + c;
|
||||
let disc = q * q / 4.0 + p * p * p / 27.0;
|
||||
|
||||
var count = 0u;
|
||||
let shift = a / 3.0;
|
||||
|
||||
if disc > 0.0 {
|
||||
let sd = sqrt(disc);
|
||||
let u = sign(-q/2.0 + sd) * pow(abs(-q/2.0 + sd), 1.0/3.0);
|
||||
let v = sign(-q/2.0 - sd) * pow(abs(-q/2.0 - sd), 1.0/3.0);
|
||||
let x1 = u + v;
|
||||
let t = x1 - shift;
|
||||
if t >= 0.0 && t <= 1.0 { (*roots)[count] = t; count++; }
|
||||
} else if disc == 0.0 {
|
||||
let u = sign(-q/2.0) * pow(abs(-q/2.0), 1.0/3.0);
|
||||
let x1 = 2.0 * u;
|
||||
let x2 = -u;
|
||||
let t1 = x1 - shift;
|
||||
let t2 = x2 - shift;
|
||||
if t1 >= 0.0 && t1 <= 1.0 { (*roots)[count] = t1; count++; }
|
||||
if t2 >= 0.0 && t2 <= 1.0 { (*roots)[count] = t2; count++; }
|
||||
} else {
|
||||
let phi = acos( -q / (2.0 * sqrt(-p*p*p/27.0)) );
|
||||
let r = 2.0 * sqrt(-p/3.0);
|
||||
for (var k = 0u; k < 3u; k++) {
|
||||
let x = r * cos((phi + 2.0 * 3.1415926535 * f32(k)) / 3.0);
|
||||
let t = x - shift;
|
||||
if t >= 0.0 && t <= 1.0 { (*roots)[count] = t; count++; }
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
// ---------- Winding number contribution from one cubic segment ----------
|
||||
fn ray_intersections_cubic(p: vec2f, seg: Segment) -> i32 {
|
||||
// We cast a horizontal ray from p to +x; find t where y(t) = p.y
|
||||
let y0 = seg.p0.y - p.y;
|
||||
let y1 = seg.p1.y - p.y;
|
||||
let y2 = seg.p2.y - p.y;
|
||||
let y3 = seg.p3.y - p.y;
|
||||
|
||||
// y(t) = (1-t)^3*y0 + 3(1-t)^2 t * y1 + 3(1-t) t^2 * y2 + t^3 * y3 = 0
|
||||
// Expand polynomial: c3 t^3 + c2 t^2 + c1 t + c0
|
||||
let c0 = y0;
|
||||
let c1 = 3.0 * (y1 - y0);
|
||||
let c2 = 3.0 * (y2 - 2.0 * y1 + y0);
|
||||
let c3 = y3 - 3.0 * y2 + 3.0 * y1 - y0;
|
||||
|
||||
var roots: array<f32, 3>;
|
||||
let num = solve_cubic_in_01(c3, c2, c1, c0, &roots);
|
||||
var wind = 0i;
|
||||
for (var i = 0u; i < num; i++) {
|
||||
let t = roots[i];
|
||||
let x = eval_cubic(t, seg.p0, seg.p1, seg.p2, seg.p3).x;
|
||||
if x > p.x {
|
||||
let dy = eval_cubic_derivative(t, seg.p0, seg.p1, seg.p2, seg.p3).y;
|
||||
if dy > 0.0 { wind += 1i; }
|
||||
else if dy < 0.0 { wind -= 1i; }
|
||||
}
|
||||
}
|
||||
return wind;
|
||||
}
|
||||
|
||||
// ---------- Main compute shader ----------
|
||||
@compute @workgroup_size(8, 8)
|
||||
fn main(@builtin(global_invocation_id) id: vec3<u32>) {
|
||||
let tile_dim = vec2f(tile_params.tile_size);
|
||||
if id.x >= u32(tile_dim.x) || id.y >= u32(tile_dim.y) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Pixel center UV, then map to world space
|
||||
let uv = (vec2f(id.xy) + 0.5) / tile_dim;
|
||||
let world = mix(tile_params.world_min, tile_params.world_max, uv);
|
||||
|
||||
var minDist: f32 = 1e20;
|
||||
var winding: i32 = 0;
|
||||
|
||||
for (var s = 0u; s < arrayLength(&shapes); s++) {
|
||||
let shape = shapes[s];
|
||||
|
||||
// Quick bbox culling in world space
|
||||
let bbox_min = shape.bbox_min;
|
||||
let bbox_max = shape.bbox_max;
|
||||
let dx = max(bbox_min.x - world.x, max(0.0, world.x - bbox_max.x));
|
||||
let dy = max(bbox_min.y - world.y, max(0.0, world.y - bbox_max.y));
|
||||
let dist_to_box = sqrt(dx * dx + dy * dy);
|
||||
if dist_to_box >= minDist {
|
||||
continue; // This shape cannot improve the distance
|
||||
}
|
||||
|
||||
// Process all segments of the shape
|
||||
for (var i = shape.start_segment; i < shape.start_segment + shape.segment_count; i++) {
|
||||
let seg = segments[i];
|
||||
let d = distance_to_cubic(world, seg);
|
||||
minDist = min(minDist, d);
|
||||
|
||||
winding += ray_intersections_cubic(world, seg);
|
||||
}
|
||||
}
|
||||
|
||||
let sign = select(1.0, -1.0, winding != 0i);
|
||||
let sdf = sign * minDist;
|
||||
|
||||
sdf_buffer[id.y * u32(tile_params.tile_size) + id.x] = sdf;
|
||||
}
|
||||
27
src/shaders/display.wgsl
Normal file
27
src/shaders/display.wgsl
Normal file
@@ -0,0 +1,27 @@
|
||||
struct Uniforms {
|
||||
pan: vec2f,
|
||||
zoom: f32,
|
||||
}
|
||||
struct TileParams {
|
||||
lod: u32,
|
||||
tile_size: f32,
|
||||
world_min: vec2f,
|
||||
world_max: vec2f,
|
||||
}
|
||||
|
||||
@group(0) @binding(0) var<uniform> uniforms: Uniforms;
|
||||
@group(0) @binding(1) var<uniform> tile_params: TileParams;
|
||||
|
||||
@vertex fn vs_main(@builtin(vertex_index) vertex_index : u32) -> @builtin(position) vec4f {
|
||||
const pos = array(
|
||||
vec2( 0.0, 0.5),
|
||||
vec2(-0.5, -0.5),
|
||||
vec2( 0.5, -0.5)
|
||||
);
|
||||
|
||||
return vec4f(pos[vertex_index], 0, 1);
|
||||
}
|
||||
|
||||
@fragment fn fs_main() -> @location(0) vec4f {
|
||||
return vec4(1, 0, 0, 1);
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
struct VsUniform {
|
||||
mvp: mat4x4f,
|
||||
};
|
||||
|
||||
struct ShapeUniform {
|
||||
transform: mat4x4f,
|
||||
state: u32,
|
||||
};
|
||||
|
||||
struct VsIn {
|
||||
@location(0) position: vec2f,
|
||||
};
|
||||
|
||||
struct Vs2Fs {
|
||||
@builtin(position) pos: vec4f,
|
||||
@location(0) @interpolate(linear) color: vec4f,
|
||||
};
|
||||
|
||||
struct FsOut {
|
||||
@location(0) color: vec4f,
|
||||
};
|
||||
|
||||
@binding(0) @group(0) var<uniform> vs_uniforms: VsUniform;
|
||||
@binding(1) @group(0) var<uniform> shape_uniform: ShapeUniform;
|
||||
|
||||
@vertex fn vs_main(input: VsIn) -> Vs2Fs {
|
||||
var output: Vs2Fs;
|
||||
let world_pos = shape_uniform.transform * vec4f(input.position.x, input.position.y, 0.0, 1.0);
|
||||
output.pos = vs_uniforms.mvp * world_pos;
|
||||
if (shape_uniform.state == 2u) {
|
||||
output.color = vec4f(1.0, 0.84, 0.0, 1.0);
|
||||
} else if (shape_uniform.state == 1u) {
|
||||
output.color = vec4f(0.5, 0.6, 1.0, 1.0);
|
||||
} else {
|
||||
output.color = vec4f(0.8, 0.8, 0.8, 1.0);
|
||||
}
|
||||
return output;
|
||||
}
|
||||
|
||||
@fragment fn fs_main(input: Vs2Fs) -> FsOut {
|
||||
var output: FsOut;
|
||||
output.color = input.color;
|
||||
return output;
|
||||
}
|
||||
@@ -1,50 +0,0 @@
|
||||
struct VsUniform {
|
||||
mvp: mat4x4f,
|
||||
instance_base: u32,
|
||||
};
|
||||
|
||||
struct ShapeData {
|
||||
transform: mat4x4f,
|
||||
state: u32,
|
||||
};
|
||||
|
||||
@binding(0) @group(0) var<uniform> vs_uniforms: VsUniform;
|
||||
|
||||
@binding(0) @group(1) var<storage> shape_data: array<ShapeData>;
|
||||
@binding(1) @group(1) var<storage> instance_map: array<u32>;
|
||||
|
||||
struct VsIn {
|
||||
@builtin(instance_index) instance_idx: u32,
|
||||
@location(0) position: vec2f,
|
||||
};
|
||||
|
||||
struct Vs2Fs {
|
||||
@builtin(position) pos: vec4f,
|
||||
@location(0) @interpolate(linear) color: vec4f,
|
||||
};
|
||||
|
||||
struct FsOut {
|
||||
@location(0) color: vec4f,
|
||||
};
|
||||
|
||||
@vertex fn vs_main(input: VsIn) -> Vs2Fs {
|
||||
var output: Vs2Fs;
|
||||
let shape_idx = instance_map[vs_uniforms.instance_base + input.instance_idx];
|
||||
let shape = shape_data[shape_idx];
|
||||
let world_pos = shape.transform * vec4f(input.position.x, input.position.y, 0.0, 1.0);
|
||||
output.pos = vs_uniforms.mvp * world_pos;
|
||||
if (shape.state == 2u) {
|
||||
output.color = vec4f(1.0, 0.84, 0.0, 1.0);
|
||||
} else if (shape.state == 1u) {
|
||||
output.color = vec4f(0.5, 0.6, 1.0, 1.0);
|
||||
} else {
|
||||
output.color = vec4f(0.8, 0.8, 0.8, 1.0);
|
||||
}
|
||||
return output;
|
||||
}
|
||||
|
||||
@fragment fn fs_main(input: Vs2Fs) -> FsOut {
|
||||
var output: FsOut;
|
||||
output.color = input.color;
|
||||
return output;
|
||||
}
|
||||
@@ -1,40 +0,0 @@
|
||||
struct Sprite {
|
||||
matrix: mat4x4f,
|
||||
};
|
||||
struct VsUniform {
|
||||
mvp: mat4x4f,
|
||||
};
|
||||
struct VsI { //Vertex shader input
|
||||
@builtin(instance_index) instance: u32,
|
||||
@location(0) position: vec2f,
|
||||
@location(1) uv: vec2f,
|
||||
};
|
||||
struct Vs2Fs { //Vertex shader to Fragment shader
|
||||
@builtin(position) pos: vec4f,
|
||||
@location(0) @interpolate(linear) uv: vec2f,
|
||||
};
|
||||
struct FsO { //Fragment shader output
|
||||
@location(0) color: vec4f,
|
||||
};
|
||||
|
||||
@binding(0) @group(0) var<uniform> vs_uniforms: VsUniform;
|
||||
@binding(0) @group(1) var tex: texture_2d<f32>;
|
||||
@binding(1) @group(1) var samp: sampler;
|
||||
@binding(2) @group(1) var<storage> sprites: array<Sprite>;
|
||||
|
||||
@vertex fn vs_main(input: VsI) -> Vs2Fs {
|
||||
var output: Vs2Fs;
|
||||
|
||||
output.pos = vec4f(input.position.x, input.position.y, 0, 0) * sprites[input.instance].matrix * vs_uniforms.mvp;
|
||||
output.uv = input.uv;
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
@fragment fn fs_main(input: Vs2Fs) -> FsO {
|
||||
var output: FsO;
|
||||
|
||||
output.color = textureSample(tex, samp, input.uv);
|
||||
|
||||
return output;
|
||||
}
|
||||
1152
src/shape.h
1152
src/shape.h
File diff suppressed because it is too large
Load Diff
341
src/spatial.h
341
src/spatial.h
@@ -1,341 +0,0 @@
|
||||
#ifndef SPATIAL_H
|
||||
#define SPATIAL_H
|
||||
|
||||
#include "api.h"
|
||||
|
||||
#define SPATIAL_CELL_SIZE 250.0f
|
||||
#define SPATIAL_HASH_BITS 16
|
||||
#define SPATIAL_HASH_SIZE (1 << SPATIAL_HASH_BITS)
|
||||
#define SPATIAL_MAX_CELLS_PER_SHAPE 64
|
||||
|
||||
typedef struct {
|
||||
int shape_idx;
|
||||
float min_x, min_y, max_x, max_y;
|
||||
} spatial_entry_t;
|
||||
|
||||
typedef struct {
|
||||
bool occupied;
|
||||
int cx, cy;
|
||||
spatial_entry_t *entries;
|
||||
int count;
|
||||
int capacity;
|
||||
} spatial_slot_t;
|
||||
|
||||
typedef struct {
|
||||
spatial_slot_t slots[SPATIAL_HASH_SIZE];
|
||||
int *visited; // per-shape query-dedup frame tags
|
||||
int visited_cap;
|
||||
int query_frame; // increments per query, never 0
|
||||
bool dirty;
|
||||
} spatial_grid_t;
|
||||
|
||||
static int spatial_hash(int cx, int cy)
|
||||
{
|
||||
return (cx * 73856093) ^ (cy * 19349663);
|
||||
}
|
||||
|
||||
static void spatial_init(spatial_grid_t *grid)
|
||||
{
|
||||
memset(grid, 0, sizeof(*grid));
|
||||
grid->dirty = true;
|
||||
grid->query_frame = 1;
|
||||
}
|
||||
|
||||
static void spatial_mark_dirty(spatial_grid_t *grid)
|
||||
{
|
||||
grid->dirty = true;
|
||||
}
|
||||
|
||||
static void spatial_destroy(spatial_grid_t *grid)
|
||||
{
|
||||
for (int i = 0; i < SPATIAL_HASH_SIZE; i++) {
|
||||
if (grid->slots[i].entries) FREE(grid->slots[i].entries);
|
||||
}
|
||||
if (grid->visited) FREE(grid->visited);
|
||||
memset(grid, 0, sizeof(*grid));
|
||||
}
|
||||
|
||||
// Find or create the slot for cell (cx, cy). Returns the slot index.
|
||||
static int spatial_find_slot(spatial_grid_t *grid, int cx, int cy)
|
||||
{
|
||||
int idx = spatial_hash(cx, cy) & (SPATIAL_HASH_SIZE - 1);
|
||||
int probe = 0;
|
||||
while (grid->slots[idx].occupied && probe < SPATIAL_HASH_SIZE) {
|
||||
if (grid->slots[idx].cx == cx && grid->slots[idx].cy == cy) break;
|
||||
idx = (idx + 1) & (SPATIAL_HASH_SIZE - 1);
|
||||
probe++;
|
||||
}
|
||||
if (!grid->slots[idx].occupied) {
|
||||
grid->slots[idx].occupied = true;
|
||||
grid->slots[idx].cx = cx;
|
||||
grid->slots[idx].cy = cy;
|
||||
}
|
||||
return idx;
|
||||
}
|
||||
|
||||
// Enumerate the cells a shape's AABB overlaps. Returns the number of cells.
|
||||
// Capped at SPATIAL_MAX_CELLS_PER_SHAPE; falls back to the center cell for
|
||||
// degenerate huge shapes to avoid hash-table explosion.
|
||||
static int spatial_shape_cells(shape_t *s, int *cell_xs, int *cell_ys)
|
||||
{
|
||||
int cmin_x = (int)floorf((s->cx - s->aabb_hx) / SPATIAL_CELL_SIZE);
|
||||
int cmax_x = (int)floorf((s->cx + s->aabb_hx) / SPATIAL_CELL_SIZE);
|
||||
int cmin_y = (int)floorf((s->cy - s->aabb_hy) / SPATIAL_CELL_SIZE);
|
||||
int cmax_y = (int)floorf((s->cy + s->aabb_hy) / SPATIAL_CELL_SIZE);
|
||||
|
||||
int ncx = cmax_x - cmin_x + 1;
|
||||
int ncy = cmax_y - cmin_y + 1;
|
||||
|
||||
if (ncx <= 0 || ncy <= 0 || ncx * ncy > SPATIAL_MAX_CELLS_PER_SHAPE) {
|
||||
cell_xs[0] = (int)floorf(s->cx / SPATIAL_CELL_SIZE);
|
||||
cell_ys[0] = (int)floorf(s->cy / SPATIAL_CELL_SIZE);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int count = 0;
|
||||
for (int cy = cmin_y; cy <= cmax_y; cy++) {
|
||||
for (int cx = cmin_x; cx <= cmax_x; cx++) {
|
||||
cell_xs[count] = cx;
|
||||
cell_ys[count] = cy;
|
||||
count++;
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
static void spatial_rebuild(spatial_grid_t *grid, vector_t *shapes)
|
||||
{
|
||||
if (!grid->dirty) return;
|
||||
grid->dirty = false;
|
||||
|
||||
int n = shapes->count;
|
||||
|
||||
// Phase 0: clear occupied flags
|
||||
for (int i = 0; i < SPATIAL_HASH_SIZE; i++) {
|
||||
grid->slots[i].occupied = false;
|
||||
grid->slots[i].count = 0;
|
||||
}
|
||||
|
||||
if (n == 0) return;
|
||||
|
||||
// Grow visited array if needed (used for query-result dedup)
|
||||
if (n > grid->visited_cap) {
|
||||
if (grid->visited) FREE(grid->visited);
|
||||
grid->visited = (int*)ALLOC((size_t)n * sizeof(int));
|
||||
grid->visited_cap = n;
|
||||
}
|
||||
memset(grid->visited, 0, (size_t)n * sizeof(int));
|
||||
grid->query_frame = 1;
|
||||
|
||||
int cell_xs[128], cell_ys[128];
|
||||
|
||||
// Phase 1: count shapes per cell
|
||||
for (int i = 0; i < n; i++) {
|
||||
shape_t *s = (shape_t*)vec_get(shapes, i);
|
||||
int nc = spatial_shape_cells(s, cell_xs, cell_ys);
|
||||
for (int c = 0; c < nc; c++) {
|
||||
int idx = spatial_find_slot(grid, cell_xs[c], cell_ys[c]);
|
||||
grid->slots[idx].count++;
|
||||
}
|
||||
}
|
||||
|
||||
// Phase 2: resize entry arrays when needed
|
||||
for (int i = 0; i < SPATIAL_HASH_SIZE; i++) {
|
||||
if (!grid->slots[i].occupied) continue;
|
||||
int need = grid->slots[i].count;
|
||||
if (need > grid->slots[i].capacity) {
|
||||
if (grid->slots[i].entries) FREE(grid->slots[i].entries);
|
||||
grid->slots[i].entries = (spatial_entry_t*)ALLOC(
|
||||
(size_t)need * sizeof(spatial_entry_t));
|
||||
grid->slots[i].capacity = need;
|
||||
}
|
||||
grid->slots[i].count = 0;
|
||||
}
|
||||
|
||||
// Phase 3: fill entries — each shape is added to every cell its AABB overlaps
|
||||
for (int i = 0; i < n; i++) {
|
||||
shape_t *s = (shape_t*)vec_get(shapes, i);
|
||||
float min_x = s->cx - s->aabb_hx;
|
||||
float min_y = s->cy - s->aabb_hy;
|
||||
float max_x = s->cx + s->aabb_hx;
|
||||
float max_y = s->cy + s->aabb_hy;
|
||||
|
||||
int nc = spatial_shape_cells(s, cell_xs, cell_ys);
|
||||
for (int c = 0; c < nc; c++) {
|
||||
int idx = spatial_find_slot(grid, cell_xs[c], cell_ys[c]);
|
||||
spatial_entry_t *e = &grid->slots[idx].entries[grid->slots[idx].count++];
|
||||
e->shape_idx = i;
|
||||
e->min_x = min_x; e->min_y = min_y;
|
||||
e->max_x = max_x; e->max_y = max_y;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Point query — O(1) average. Only checks the cell containing the query point
|
||||
// because shapes are now inserted into every cell their AABB overlaps.
|
||||
static int spatial_query_point(spatial_grid_t *grid, vector_t *shapes,
|
||||
float wx, float wy, float world_tol)
|
||||
{
|
||||
int cx = (int)floorf(wx / SPATIAL_CELL_SIZE);
|
||||
int cy = (int)floorf(wy / SPATIAL_CELL_SIZE);
|
||||
|
||||
int idx = spatial_hash(cx, cy) & (SPATIAL_HASH_SIZE - 1);
|
||||
int probe_start = idx;
|
||||
|
||||
do {
|
||||
if (!grid->slots[idx].occupied) break;
|
||||
|
||||
if (grid->slots[idx].cx == cx && grid->slots[idx].cy == cy) {
|
||||
for (int e = 0; e < grid->slots[idx].count; e++) {
|
||||
spatial_entry_t *entry = &grid->slots[idx].entries[e];
|
||||
|
||||
if (wx < entry->min_x - world_tol ||
|
||||
wx > entry->max_x + world_tol ||
|
||||
wy < entry->min_y - world_tol ||
|
||||
wy > entry->max_y + world_tol)
|
||||
continue;
|
||||
|
||||
shape_t *s = (shape_t*)vec_get(shapes, entry->shape_idx);
|
||||
if (shape_hit_test(s, wx, wy, world_tol))
|
||||
return entry->shape_idx;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
idx = (idx + 1) & (SPATIAL_HASH_SIZE - 1);
|
||||
} while (idx != probe_start);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Rectangle selection for marquee. Uses a per-query frame counter for dedup
|
||||
// since shapes now appear in every cell they overlap.
|
||||
static int spatial_query_rect_select(spatial_grid_t *grid, vector_t *shapes,
|
||||
float min_x, float min_y,
|
||||
float max_x, float max_y)
|
||||
{
|
||||
int n = shapes->count;
|
||||
for (int i = 0; i < n; i++) {
|
||||
((shape_t*)vec_get(shapes, i))->selected = false;
|
||||
}
|
||||
int selected_count = 0;
|
||||
|
||||
grid->query_frame++;
|
||||
int frame = grid->query_frame;
|
||||
|
||||
int cell_min_x = (int)floorf(min_x / SPATIAL_CELL_SIZE);
|
||||
int cell_max_x = (int)floorf(max_x / SPATIAL_CELL_SIZE);
|
||||
int cell_min_y = (int)floorf(min_y / SPATIAL_CELL_SIZE);
|
||||
int cell_max_y = (int)floorf(max_y / SPATIAL_CELL_SIZE);
|
||||
|
||||
int cell_count = (cell_max_x - cell_min_x + 1) * (cell_max_y - cell_min_y + 1);
|
||||
if (cell_count > SPATIAL_HASH_SIZE) {
|
||||
for (int s = 0; s < SPATIAL_HASH_SIZE; s++) {
|
||||
if (!grid->slots[s].occupied) continue;
|
||||
for (int e = 0; e < grid->slots[s].count; e++) {
|
||||
spatial_entry_t *entry = &grid->slots[s].entries[e];
|
||||
if (grid->visited[entry->shape_idx] == frame) continue;
|
||||
grid->visited[entry->shape_idx] = frame;
|
||||
|
||||
if (entry->max_x < min_x || entry->min_x > max_x ||
|
||||
entry->max_y < min_y || entry->min_y > max_y)
|
||||
continue;
|
||||
shape_t *shape = (shape_t*)vec_get(shapes, entry->shape_idx);
|
||||
bool hit = (shape->cx >= min_x && shape->cx <= max_x &&
|
||||
shape->cy >= min_y && shape->cy <= max_y);
|
||||
float sx_cos = shape->sx * shape->cos_r;
|
||||
float sy_sin = shape->sy * shape->sin_r;
|
||||
float sx_sin = shape->sx * shape->sin_r;
|
||||
float sy_cos = shape->sy * shape->cos_r;
|
||||
for (uint32_t v = 0; !hit && v < shape->num_verts; v++) {
|
||||
float wx = shape->cx + shape->verts[v].x * sx_cos - shape->verts[v].y * sy_sin;
|
||||
float wy = shape->cy + shape->verts[v].x * sx_sin + shape->verts[v].y * sy_cos;
|
||||
if (wx >= min_x && wx <= max_x &&
|
||||
wy >= min_y && wy <= max_y)
|
||||
hit = true;
|
||||
}
|
||||
if (hit) { shape->selected = true; selected_count++; }
|
||||
}
|
||||
}
|
||||
return selected_count;
|
||||
}
|
||||
|
||||
for (int cy = cell_min_y; cy <= cell_max_y; cy++) {
|
||||
for (int cx = cell_min_x; cx <= cell_max_x; cx++) {
|
||||
int idx = spatial_hash(cx, cy) & (SPATIAL_HASH_SIZE - 1);
|
||||
int probe_start = idx;
|
||||
do {
|
||||
if (!grid->slots[idx].occupied) break;
|
||||
if (grid->slots[idx].cx == cx && grid->slots[idx].cy == cy) {
|
||||
for (int e = 0; e < grid->slots[idx].count; e++) {
|
||||
spatial_entry_t *entry = &grid->slots[idx].entries[e];
|
||||
if (grid->visited[entry->shape_idx] == frame) continue;
|
||||
grid->visited[entry->shape_idx] = frame;
|
||||
|
||||
if (entry->max_x < min_x || entry->min_x > max_x ||
|
||||
entry->max_y < min_y || entry->min_y > max_y)
|
||||
continue;
|
||||
shape_t *shape = (shape_t*)vec_get(shapes, entry->shape_idx);
|
||||
bool hit = (shape->cx >= min_x && shape->cx <= max_x &&
|
||||
shape->cy >= min_y && shape->cy <= max_y);
|
||||
float sc = shape->cos_r, ss = shape->sin_r;
|
||||
for (uint32_t v = 0; !hit && v < shape->num_verts; v++) {
|
||||
float lx = shape->verts[v].x * shape->sx;
|
||||
float ly = shape->verts[v].y * shape->sy;
|
||||
float wx = shape->cx + lx * sc - ly * ss;
|
||||
float wy = shape->cy + lx * ss + ly * sc;
|
||||
if (wx >= min_x && wx <= max_x &&
|
||||
wy >= min_y && wy <= max_y)
|
||||
hit = true;
|
||||
}
|
||||
if (hit) { shape->selected = true; selected_count++; }
|
||||
}
|
||||
break;
|
||||
}
|
||||
idx = (idx + 1) & (SPATIAL_HASH_SIZE - 1);
|
||||
} while (idx != probe_start);
|
||||
}
|
||||
}
|
||||
return selected_count;
|
||||
}
|
||||
|
||||
static int spatial_query_viewport(spatial_grid_t *grid,
|
||||
float min_x, float min_y, float max_x, float max_y,
|
||||
int *out_indices, int max_out)
|
||||
{
|
||||
grid->query_frame++;
|
||||
int frame = grid->query_frame;
|
||||
|
||||
int cell_min_x = (int)floorf(min_x / SPATIAL_CELL_SIZE);
|
||||
int cell_max_x = (int)floorf(max_x / SPATIAL_CELL_SIZE);
|
||||
int cell_min_y = (int)floorf(min_y / SPATIAL_CELL_SIZE);
|
||||
int cell_max_y = (int)floorf(max_y / SPATIAL_CELL_SIZE);
|
||||
|
||||
int count = 0;
|
||||
for (int cy = cell_min_y; cy <= cell_max_y && count < max_out; cy++) {
|
||||
for (int cx = cell_min_x; cx <= cell_max_x && count < max_out; cx++) {
|
||||
int idx = spatial_hash(cx, cy) & (SPATIAL_HASH_SIZE - 1);
|
||||
int probe_start = idx;
|
||||
do {
|
||||
if (!grid->slots[idx].occupied) break;
|
||||
if (grid->slots[idx].cx == cx && grid->slots[idx].cy == cy) {
|
||||
for (int e = 0; e < grid->slots[idx].count && count < max_out; e++) {
|
||||
spatial_entry_t *entry = &grid->slots[idx].entries[e];
|
||||
if (grid->visited[entry->shape_idx] == frame) continue;
|
||||
grid->visited[entry->shape_idx] = frame;
|
||||
|
||||
if (entry->max_x < min_x || entry->min_x > max_x ||
|
||||
entry->max_y < min_y || entry->min_y > max_y)
|
||||
continue;
|
||||
out_indices[count++] = entry->shape_idx;
|
||||
}
|
||||
break;
|
||||
}
|
||||
idx = (idx + 1) & (SPATIAL_HASH_SIZE - 1);
|
||||
} while (idx != probe_start);
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
#endif
|
||||
202
src/types.h
202
src/types.h
@@ -1,202 +0,0 @@
|
||||
#ifndef TYPES_H
|
||||
#define TYPES_H
|
||||
|
||||
#include "api.h"
|
||||
|
||||
#define LOG_RING_SIZE 256
|
||||
#define HANDLE_OFFSET_PX 0.0f
|
||||
#define HANDLE_RADIUS_PX 12.0f
|
||||
#define HANDLE_CIRCLE_SEGMENTS 64
|
||||
#define CORNER_SIZE_PX 8.0f
|
||||
#define TOP_PANEL_H 32.0f
|
||||
#define PEN_MAX_CONTROL_POINTS 256
|
||||
#define PEN_PREVIEW_MAX_VERTS 2048
|
||||
#define PEN_CLOSE_PX 10.0f
|
||||
#define EDIT_ANCHOR_SIZE_PX 8.0f
|
||||
#define EDIT_HANDLE_SIZE_PX 5.0f
|
||||
|
||||
#define DOUBLE_CLICK_TIME 0.3
|
||||
#define DRAG_THRESHOLD_SQ 9.0f
|
||||
#define FRUSTUM_CULL_MARGIN 300.0f
|
||||
#define CAMERA_ZOOM_MIN 0.1f
|
||||
#define CAMERA_ZOOM_MAX 6.0f
|
||||
|
||||
typedef enum {
|
||||
TOOL_SELECT,
|
||||
TOOL_PEN,
|
||||
TOOL_CIRCLE,
|
||||
TOOL_RECTANGLE,
|
||||
TOOL_COUNT
|
||||
} tool_t;
|
||||
|
||||
typedef struct log_entry_t {
|
||||
char text[256];
|
||||
uint32_t level;
|
||||
uint64_t hash;
|
||||
} log_entry_t;
|
||||
|
||||
typedef struct {
|
||||
mat4 mvp;
|
||||
} uniform_t;
|
||||
|
||||
typedef struct renderer_t {
|
||||
sg_pipeline pipeline;
|
||||
sg_shader shader;
|
||||
sg_pass_action clear_pass;
|
||||
uniform_t uniform;
|
||||
} renderer_t;
|
||||
|
||||
typedef struct {
|
||||
int idx;
|
||||
float init_sx, init_sy, init_cx, init_cy;
|
||||
float ext_x, ext_y;
|
||||
float lpi_x, lpi_y;
|
||||
} resize_init_t;
|
||||
|
||||
typedef struct {
|
||||
bool active;
|
||||
float start_x, start_y;
|
||||
float current_x, current_y;
|
||||
bool dragging;
|
||||
int clicked_shape;
|
||||
} select_state_t;
|
||||
|
||||
typedef struct {
|
||||
bool dragging;
|
||||
float start_wx, start_wy;
|
||||
float total_dx, total_dy;
|
||||
} move_state_t;
|
||||
|
||||
typedef struct {
|
||||
bool dragging;
|
||||
float center_x, center_y;
|
||||
float start_angle;
|
||||
float total_delta;
|
||||
float handle_radius;
|
||||
} rotate_state_t;
|
||||
|
||||
typedef struct {
|
||||
bool dragging;
|
||||
float pivot_x, pivot_y;
|
||||
float start_wx, start_wy;
|
||||
float total_scale_x, total_scale_y;
|
||||
float mask_x, mask_y;
|
||||
float angle;
|
||||
resize_init_t *init;
|
||||
int init_count;
|
||||
} resize_state_t;
|
||||
|
||||
typedef struct {
|
||||
int selected_count;
|
||||
int hovered_shape;
|
||||
|
||||
select_state_t select;
|
||||
move_state_t move;
|
||||
rotate_state_t rotate;
|
||||
resize_state_t resize;
|
||||
|
||||
float cached_aabb[4];
|
||||
bool aabb_cached;
|
||||
|
||||
double last_click_time;
|
||||
int last_click_shape_idx;
|
||||
|
||||
vector_t drag_indices;
|
||||
|
||||
// Edit mode
|
||||
int editing_shape_idx;
|
||||
bool edit_dragging;
|
||||
int edit_drag_idx;
|
||||
bool edit_handle_dragging;
|
||||
int edit_handle_idx;
|
||||
bool edit_handle_is_in;
|
||||
// Pre-drag control point snapshot (for undo)
|
||||
shape_vertex_t *edit_saved_ctrl;
|
||||
shape_vertex_t *edit_saved_hin;
|
||||
shape_vertex_t *edit_saved_hout;
|
||||
int edit_saved_count;
|
||||
} interact_state_t;
|
||||
|
||||
typedef struct {
|
||||
float fps_immediate;
|
||||
float fps_average;
|
||||
float frame_times[60];
|
||||
int frame_time_head;
|
||||
int frame_time_count;
|
||||
float frame_time_sum;
|
||||
} debug_stats_t;
|
||||
|
||||
typedef struct {
|
||||
float right_panel_w;
|
||||
float left_panel_w;
|
||||
log_entry_t log_ring[LOG_RING_SIZE];
|
||||
int log_head;
|
||||
int log_count;
|
||||
bool log_show;
|
||||
char log_filter[32];
|
||||
tool_t active_tool;
|
||||
int list_last_shape;
|
||||
int list_prev_count;
|
||||
int *display_cache;
|
||||
int display_cache_len;
|
||||
bool display_cache_dirty;
|
||||
} ui_state_t;
|
||||
|
||||
typedef struct {
|
||||
shape_t *shapes;
|
||||
int shape_count;
|
||||
} clipboard_t;
|
||||
|
||||
typedef struct {
|
||||
bool drawing;
|
||||
shape_vertex_t points[PEN_MAX_CONTROL_POINTS];
|
||||
int point_count;
|
||||
shape_vertex_t preview_verts[PEN_PREVIEW_MAX_VERTS];
|
||||
int preview_count;
|
||||
} pen_state_t;
|
||||
|
||||
// Per-overlay-buffer upload flags — replaces the single overlay_upload_needed
|
||||
// bool so that during drag we only upload the buffers that actually changed
|
||||
// (e.g. moving shapes only needs rect+corners, not edit-mode buffers).
|
||||
typedef struct {
|
||||
bool rect;
|
||||
bool handle_circle;
|
||||
bool corners;
|
||||
bool edit_anchors;
|
||||
bool edit_handles;
|
||||
bool edit_lines;
|
||||
bool pen;
|
||||
} overlay_upload_flags_t;
|
||||
|
||||
typedef struct userdata_t {
|
||||
camera_t camera;
|
||||
renderer_t renderer;
|
||||
shape_pool_ctx_t shape_pool;
|
||||
group_index_ctx_t group_idx;
|
||||
pipeline_ctx_t pipelines;
|
||||
panel_log_ctx_t panel_log_ctx;
|
||||
rand_ctx_t rand_ctx;
|
||||
vector_t shapes;
|
||||
spatial_grid_t spatial_grid;
|
||||
interact_state_t interact;
|
||||
history_t history;
|
||||
debug_stats_t debug;
|
||||
ui_state_t ui;
|
||||
overlay_upload_flags_t overlay_upload;
|
||||
sg_buffer rect_vbuf, rect_ibuf;
|
||||
sg_buffer handle_vbuf, handle_ibuf;
|
||||
sg_buffer corner_vbuf, corner_ibuf;
|
||||
int next_group_id;
|
||||
vector_t groups;
|
||||
clipboard_t clipboard;
|
||||
float map_w, map_h;
|
||||
float mouse_x, mouse_y;
|
||||
double time;
|
||||
pen_state_t pen;
|
||||
sg_buffer pen_vbuf, pen_ibuf;
|
||||
// Edit mode buffers
|
||||
sg_buffer ed_anchor_vbuf, ed_handle_vbuf, ed_handle_line_vbuf, ed_shared_ibuf;
|
||||
int ed_anchor_count, ed_handle_count, ed_handle_line_count;
|
||||
} userdata_t;
|
||||
|
||||
#endif
|
||||
503
src/ui_panels.h
503
src/ui_panels.h
@@ -1,503 +0,0 @@
|
||||
#ifndef UI_PANELS_H
|
||||
#define UI_PANELS_H
|
||||
|
||||
#include "api.h"
|
||||
#include "types.h"
|
||||
#include "interact.h"
|
||||
|
||||
static const char *shape_kind_label(const char *name) {
|
||||
if (name[0]) return name;
|
||||
return "Shape";
|
||||
}
|
||||
|
||||
static void build_display_recursive(vector_t *shapes, vector_t *groups, int parent_gid, int *display, int *dlen)
|
||||
{
|
||||
for (int g = 0; g < groups->count; g++) {
|
||||
group_t *grp = (group_t*) vec_get(groups, g);
|
||||
if (grp->parent_id != parent_gid) continue;
|
||||
for (int m = 0; m < grp->member_count; m++)
|
||||
display[(*dlen)++] = grp->member_indices[m];
|
||||
build_display_recursive(shapes, groups, grp->id, display, dlen);
|
||||
}
|
||||
if (parent_gid == 0) {
|
||||
for (int i = 0; i < shapes->count; i++) {
|
||||
if (((shape_t*) vec_get(shapes, i))->group_id == 0)
|
||||
display[(*dlen)++] = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Count shapes and group headers in a subtree (for collapsed path).
|
||||
static void count_subtree_items(vector_t *groups, int gid, int *shapes_out, int *headers_out)
|
||||
{
|
||||
int s = 0, h = 0;
|
||||
for (int g = 0; g < groups->count; g++) {
|
||||
group_t *grp = (group_t*) vec_get(groups, g);
|
||||
if (grp->id == gid) {
|
||||
s = grp->member_count;
|
||||
for (int k = 0; k < groups->count; k++) {
|
||||
group_t *child = (group_t*) vec_get(groups, k);
|
||||
if (child->parent_id == gid) {
|
||||
h += 1;
|
||||
int cs, ch;
|
||||
count_subtree_items(groups, child->id, &cs, &ch);
|
||||
s += cs; h += ch;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
*shapes_out = s;
|
||||
*headers_out = h;
|
||||
}
|
||||
|
||||
static void list_shape_clicked(userdata_t *ud, shape_t *s, int *display, int display_len, int display_pos)
|
||||
{
|
||||
int n = ud->shapes.count;
|
||||
bool ctrl = igGetIO_Nil()->KeyCtrl;
|
||||
bool shift = igGetIO_Nil()->KeyShift && ud->ui.list_last_shape >= 0;
|
||||
|
||||
if (shift) {
|
||||
int from = ud->ui.list_last_shape;
|
||||
int to = display_pos;
|
||||
if (from > to) { int tmp = from; from = to; to = tmp; }
|
||||
for (int j = 0; j < n; j++)
|
||||
((shape_t*) vec_get(&ud->shapes, j))->selected = false;
|
||||
ud->interact.selected_count = 0;
|
||||
for (int d = from; d <= to; d++) {
|
||||
shape_t *sv = (shape_t*) vec_get(&ud->shapes, display[d]);
|
||||
sv->selected = true;
|
||||
ud->interact.selected_count++;
|
||||
}
|
||||
} else if (ctrl) {
|
||||
s->selected = !s->selected;
|
||||
ud->interact.selected_count += s->selected ? 1 : -1;
|
||||
} else {
|
||||
for (int j = 0; j < n; j++)
|
||||
((shape_t*) vec_get(&ud->shapes, j))->selected = false;
|
||||
ud->interact.selected_count = 0;
|
||||
s->selected = true;
|
||||
ud->interact.selected_count = 1;
|
||||
}
|
||||
ud->ui.list_last_shape = display_pos;
|
||||
ud->interact.aabb_cached = false;
|
||||
overlay_invalidate(ud);
|
||||
update_shape_states(ud);
|
||||
}
|
||||
|
||||
// Count items that are currently visible (respecting collapse state).
|
||||
// Used to compute the exact scrollbar range.
|
||||
static int count_visible_items(vector_t *groups, int parent_gid)
|
||||
{
|
||||
int c = 0;
|
||||
for (int g = 0; g < groups->count; g++) {
|
||||
group_t *grp = (group_t*) vec_get(groups, g);
|
||||
if (grp->parent_id != parent_gid) continue;
|
||||
c += 1; // group header (always visible)
|
||||
if (!grp->collapsed) {
|
||||
c += grp->member_count;
|
||||
c += count_visible_items(groups, grp->id);
|
||||
}
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
// Render tree level with virtualized scrolling (ocornut's technique from imgui#3823).
|
||||
// `item_idx` tracks only VISIBLE items (collapsed subtrees don't contribute)
|
||||
// so that the scrollbar accurately reflects the viewable content. `pos` always
|
||||
// tracks the display-array position for shift-click range selection.
|
||||
static int render_tree_level(userdata_t *ud, int parent_gid, int *display, int display_len,
|
||||
int display_pos, int first_visible, int last_visible, int *item_idx)
|
||||
{
|
||||
int n = ud->shapes.count;
|
||||
int pos = display_pos;
|
||||
bool has_groups = (ud->groups.count > 0);
|
||||
|
||||
if (has_groups) {
|
||||
for (int g = 0; g < ud->groups.count; g++) {
|
||||
group_t *grp = (group_t*) vec_get(&ud->groups, g);
|
||||
if (grp->parent_id != parent_gid) continue;
|
||||
|
||||
int gid = grp->id;
|
||||
bool visible = (*item_idx >= first_visible && *item_idx < last_visible);
|
||||
(*item_idx)++;
|
||||
|
||||
if (visible) {
|
||||
// --- VISIBLE GROUP HEADER ---
|
||||
ImGuiID storage_id = (ImGuiID)gid;
|
||||
igSetNextItemStorageID(storage_id);
|
||||
|
||||
char hdr[64];
|
||||
snprintf(hdr, sizeof(hdr), "Group##g%d", gid);
|
||||
ImGuiTreeNodeFlags flags = ImGuiTreeNodeFlags_OpenOnArrow;
|
||||
if (!grp->collapsed) flags |= ImGuiTreeNodeFlags_DefaultOpen;
|
||||
bool open = igTreeNodeEx_Str(hdr, flags);
|
||||
grp->collapsed = !open;
|
||||
|
||||
if (igIsItemClicked(ImGuiMouseButton_Left)) {
|
||||
bool ctrl = igGetIO_Nil()->KeyCtrl;
|
||||
if (ctrl)
|
||||
toggle_group_recursive(ud, gid);
|
||||
else
|
||||
deselect_and_select_group_recursive(ud, gid);
|
||||
ud->ui.list_last_shape = display_pos;
|
||||
ud->interact.aabb_cached = false;
|
||||
overlay_invalidate(ud);
|
||||
update_shape_states(ud);
|
||||
}
|
||||
|
||||
if (open) {
|
||||
for (int m = 0; m < grp->member_count; m++) {
|
||||
int si = grp->member_indices[m];
|
||||
bool child_visible = (*item_idx >= first_visible && *item_idx < last_visible);
|
||||
(*item_idx)++;
|
||||
|
||||
if (child_visible) {
|
||||
shape_t *s = (shape_t*) vec_get(&ud->shapes, si);
|
||||
char label[128];
|
||||
snprintf(label, sizeof(label), " %s##s%d", shape_kind_label(s->name), si);
|
||||
if (igSelectable_Bool(label, s->selected, ImGuiSelectableFlags_None, (ImVec2){0,0}))
|
||||
list_shape_clicked(ud, s, display, display_len, pos);
|
||||
}
|
||||
pos++;
|
||||
}
|
||||
pos = render_tree_level(ud, gid, display, display_len, pos,
|
||||
first_visible, last_visible, item_idx);
|
||||
igTreePop();
|
||||
}
|
||||
// Closed node: no TreePop — TreePushOverrideID was not called.
|
||||
// Also no item_idx advance for the hidden subtree — only the
|
||||
// header counts toward the visible-total. Still advance pos
|
||||
// for display-index accuracy.
|
||||
if (!open) {
|
||||
int cs, ch;
|
||||
count_subtree_items(&ud->groups, gid, &cs, &ch);
|
||||
pos += cs;
|
||||
// item_idx NOT advanced: collapsed items are not visible
|
||||
}
|
||||
} else {
|
||||
// --- CLIPPED (OFF-SCREEN) GROUP ---
|
||||
if (grp->collapsed) {
|
||||
int cs, ch;
|
||||
count_subtree_items(&ud->groups, gid, &cs, &ch);
|
||||
pos += cs;
|
||||
// item_idx already incremented for header; collapsed
|
||||
// subtree adds nothing (not visible).
|
||||
} else {
|
||||
// Open but clipped: TreePush walks subtree via recursion.
|
||||
*item_idx += grp->member_count;
|
||||
pos += grp->member_count;
|
||||
|
||||
char label[64];
|
||||
snprintf(label, sizeof(label), "Group##g%d", gid);
|
||||
igTreePush_Str(label);
|
||||
pos = render_tree_level(ud, gid, display, display_len, pos,
|
||||
first_visible, last_visible, item_idx);
|
||||
igTreePop();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Ungrouped shapes — only at the top level
|
||||
if (parent_gid == 0) {
|
||||
for (int i = 0; i < n; i++) {
|
||||
shape_t *s = (shape_t*) vec_get(&ud->shapes, i);
|
||||
if (has_groups && s->group_id != 0) continue;
|
||||
|
||||
bool in_range = (*item_idx >= first_visible && *item_idx < last_visible);
|
||||
(*item_idx)++;
|
||||
|
||||
if (in_range) {
|
||||
char label[128];
|
||||
snprintf(label, sizeof(label), "%s##s%d", shape_kind_label(s->name), i);
|
||||
if (igSelectable_Bool(label, s->selected, ImGuiSelectableFlags_None, (ImVec2){0,0}))
|
||||
list_shape_clicked(ud, s, display, display_len, pos);
|
||||
}
|
||||
pos++;
|
||||
}
|
||||
}
|
||||
|
||||
return pos;
|
||||
}
|
||||
|
||||
static void draw_top_panel(userdata_t *ud)
|
||||
{
|
||||
igSetNextWindowPos((ImVec2){0, 0}, ImGuiCond_Always, (ImVec2){0, 0});
|
||||
igSetNextWindowSize((ImVec2){ud->camera.width, TOP_PANEL_H}, ImGuiCond_Always);
|
||||
igBegin("Toolbar", NULL,
|
||||
ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize |
|
||||
ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoScrollbar |
|
||||
ImGuiWindowFlags_NoCollapse);
|
||||
|
||||
for (int t = 0; t < TOOL_COUNT; t++) {
|
||||
const char *label = NULL;
|
||||
switch (t) {
|
||||
case TOOL_SELECT: label = "Sel"; break;
|
||||
case TOOL_PEN: label = "Pen"; break;
|
||||
case TOOL_CIRCLE: label = "Circle"; break;
|
||||
case TOOL_RECTANGLE: label = "Rect"; break;
|
||||
default: break;
|
||||
}
|
||||
if (t > 0) igSameLine(0.0f, 4.0f);
|
||||
bool active = (ud->ui.active_tool == t);
|
||||
if (active) {
|
||||
igPushStyleColor_Vec4(ImGuiCol_Button, (ImVec4){0.3f, 0.5f, 0.8f, 1.0f});
|
||||
igPushStyleColor_Vec4(ImGuiCol_ButtonHovered, (ImVec4){0.4f, 0.6f, 0.9f, 1.0f});
|
||||
}
|
||||
if (igButton(label, (ImVec2){0, 0})) {
|
||||
tool_t new_tool = (tool_t)t;
|
||||
if (new_tool != TOOL_SELECT && new_tool != ud->ui.active_tool) {
|
||||
for (int i = 0; i < ud->shapes.count; i++) {
|
||||
((shape_t*)vec_get(&ud->shapes, i))->selected = false;
|
||||
}
|
||||
ud->interact.selected_count = 0;
|
||||
overlay_invalidate(ud);
|
||||
update_shape_states(ud);
|
||||
}
|
||||
ud->ui.active_tool = new_tool;
|
||||
}
|
||||
if (active)
|
||||
igPopStyleColor(2);
|
||||
}
|
||||
|
||||
igSameLine(0.0f, 16.0f);
|
||||
|
||||
if (igButton("Undo", (ImVec2){0, 0})) {
|
||||
if (history_undo(&ud->history, &ud->shapes, &ud->shape_pool,
|
||||
&ud->groups, &ud->group_idx)) {
|
||||
group_rebuild_members(&ud->group_idx, &ud->groups, &ud->shapes);
|
||||
interact_structural_change(ud);
|
||||
}
|
||||
}
|
||||
|
||||
igSameLine(0.0f, 4.0f);
|
||||
|
||||
if (igButton("Redo", (ImVec2){0, 0})) {
|
||||
if (history_redo(&ud->history, &ud->shapes, &ud->shape_pool,
|
||||
&ud->groups, &ud->group_idx)) {
|
||||
group_rebuild_members(&ud->group_idx, &ud->groups, &ud->shapes);
|
||||
interact_structural_change(ud);
|
||||
}
|
||||
}
|
||||
|
||||
igEnd();
|
||||
}
|
||||
|
||||
static void draw_shape_list_panel(userdata_t *ud)
|
||||
{
|
||||
igSetNextWindowPos((ImVec2){0, TOP_PANEL_H}, ImGuiCond_Always, (ImVec2){0, 0});
|
||||
igSetNextWindowSize((ImVec2){ud->ui.left_panel_w, ud->camera.height - TOP_PANEL_H}, ImGuiCond_Always);
|
||||
igBegin("Shapes", NULL,
|
||||
ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse);
|
||||
|
||||
int n = ud->shapes.count;
|
||||
|
||||
if (n == 0) {
|
||||
igText("No shapes");
|
||||
igEnd();
|
||||
return;
|
||||
}
|
||||
|
||||
if (ud->ui.display_cache_dirty || ud->ui.display_cache_len != n) {
|
||||
FREE(ud->ui.display_cache);
|
||||
ud->ui.display_cache = (int*) ALLOC((size_t)n * sizeof(int));
|
||||
ud->ui.display_cache_len = 0;
|
||||
build_display_recursive(&ud->shapes, &ud->groups, 0, ud->ui.display_cache, &ud->ui.display_cache_len);
|
||||
ud->ui.display_cache_dirty = false;
|
||||
}
|
||||
int *display = ud->ui.display_cache;
|
||||
int display_len = ud->ui.display_cache_len;
|
||||
|
||||
if (n != ud->ui.list_prev_count) { ud->ui.list_last_shape = -1; ud->ui.list_prev_count = n; }
|
||||
if (ud->ui.list_last_shape >= display_len) ud->ui.list_last_shape = -1;
|
||||
|
||||
// Count only visible items (respects collapse state) for correct scrollbar.
|
||||
int total_items = count_visible_items(&ud->groups, 0);
|
||||
for (int i = 0; i < n; i++) {
|
||||
if (((shape_t*) vec_get(&ud->shapes, i))->group_id == 0)
|
||||
total_items++;
|
||||
}
|
||||
|
||||
igBeginChild_Str("ListScroll", (ImVec2){0, 0}, false, ImGuiWindowFlags_None);
|
||||
|
||||
float line_h = igGetTextLineHeightWithSpacing();
|
||||
float scroll_y = igGetScrollY();
|
||||
int first_visible = (int)(scroll_y / line_h);
|
||||
if (first_visible < 0) first_visible = 0;
|
||||
int visible_slack = (int)(igGetWindowHeight() / line_h) + 4;
|
||||
int last_visible = first_visible + visible_slack;
|
||||
if (last_visible > total_items) last_visible = total_items;
|
||||
if (first_visible > last_visible) first_visible = last_visible;
|
||||
|
||||
// Position cursor at first visible item, render, then set total content height.
|
||||
float cursor_base = igGetCursorPosY();
|
||||
igSetCursorPosY(cursor_base + first_visible * line_h);
|
||||
|
||||
int item_idx = 0;
|
||||
render_tree_level(ud, 0, display, display_len, 0,
|
||||
first_visible, last_visible, &item_idx);
|
||||
|
||||
// Stretch content height so the scrollbar reflects the total visible items.
|
||||
igSetCursorPosY(cursor_base + total_items * line_h);
|
||||
igDummy((ImVec2){0, 0});
|
||||
|
||||
igEndChild();
|
||||
igEnd();
|
||||
}
|
||||
|
||||
static void draw_properties_panel(userdata_t *ud)
|
||||
{
|
||||
igSetNextWindowPos((ImVec2){ud->camera.width - ud->ui.right_panel_w, TOP_PANEL_H}, ImGuiCond_Always, (ImVec2){0, 0});
|
||||
igSetNextWindowSize((ImVec2){ud->ui.right_panel_w, ud->camera.height - TOP_PANEL_H}, ImGuiCond_Always);
|
||||
igBegin("Properties", NULL,
|
||||
ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse);
|
||||
|
||||
if (ud->interact.selected_count == 0) {
|
||||
igText("No shape selected");
|
||||
} else if (ud->interact.selected_count > 1) {
|
||||
int common_gid = -1;
|
||||
bool same_group = true;
|
||||
for (int i = 0; i < ud->shapes.count; i++) {
|
||||
shape_t *s = (shape_t*) vec_get(&ud->shapes, i);
|
||||
if (!s->selected) continue;
|
||||
if (common_gid == -1) common_gid = s->group_id;
|
||||
else if (s->group_id != common_gid) { same_group = false; break; }
|
||||
}
|
||||
if (same_group && common_gid != 0) {
|
||||
igText("Group %d — %d shapes", common_gid, ud->interact.selected_count);
|
||||
} else {
|
||||
igText("%d shapes selected", ud->interact.selected_count);
|
||||
}
|
||||
} else {
|
||||
int idx = 0;
|
||||
while (idx < ud->shapes.count) {
|
||||
shape_t *tmp = (shape_t*) vec_get(&ud->shapes, idx);
|
||||
if (tmp->selected) break;
|
||||
idx++;
|
||||
}
|
||||
shape_t *s = (shape_t*) vec_get(&ud->shapes, idx);
|
||||
if (s->group_id != 0) {
|
||||
char path[256] = "";
|
||||
int gid = s->group_id;
|
||||
while (gid != 0) {
|
||||
char seg[32];
|
||||
snprintf(seg, sizeof(seg), "%d", gid);
|
||||
if (path[0]) {
|
||||
int plen = (int)strlen(path);
|
||||
int slen = (int)strlen(seg);
|
||||
memmove(path + slen + 3, path, (size_t)(plen + 1));
|
||||
memcpy(path, seg, (size_t)slen);
|
||||
path[slen] = ' '; path[slen + 1] = '>'; path[slen + 2] = ' ';
|
||||
} else {
|
||||
strcpy(path, seg);
|
||||
}
|
||||
group_t *g = find_group(&ud->group_idx, &ud->groups, gid);
|
||||
gid = g ? g->parent_id : 0;
|
||||
}
|
||||
int members = 0;
|
||||
for (int i = 0; i < ud->shapes.count; i++) {
|
||||
if (((shape_t*) vec_get(&ud->shapes, i))->group_id == s->group_id) members++;
|
||||
}
|
||||
igText("Group %s — %d member%s", path, members, members > 1 ? "s" : "");
|
||||
}
|
||||
bool changed = false;
|
||||
|
||||
changed |= igDragFloat2("Position", &s->cx, 1.0f, 0, 0, "%.1f", 0);
|
||||
if (igIsItemActivated()) history_begin_edit(&ud->history, &ud->shapes, idx, HIST_POSITION);
|
||||
changed |= igDragFloat2("Scale", &s->sx, 1.0f, -10.0f, 10.0f, "%.1f", 0);
|
||||
if (igIsItemActivated()) history_begin_edit(&ud->history, &ud->shapes, idx, HIST_SCALE);
|
||||
changed |= igDragFloat("Rotation", &s->rotation, 0.01f, 0, 0, "%.3f", 0);
|
||||
if (igIsItemActivated()) history_begin_edit(&ud->history, &ud->shapes, idx, HIST_ROTATION);
|
||||
|
||||
if (changed) { shape_regenerate(&ud->shape_pool, s); spatial_mark_dirty(&ud->spatial_grid); overlay_invalidate(ud); }
|
||||
|
||||
igSeparator();
|
||||
{
|
||||
mat4 *m = &s->uniform.transform;
|
||||
char dbg[512];
|
||||
snprintf(dbg, sizeof(dbg),
|
||||
"Transform Matrix:\n"
|
||||
"[%+.3f %+.3f %+.3f %+.3f]\n"
|
||||
"[%+.3f %+.3f %+.3f %+.3f]\n"
|
||||
"[%+.3f %+.3f %+.3f %+.3f]\n"
|
||||
"[%+.3f %+.3f %+.3f %+.3f]\n"
|
||||
"\nLocal vert[0]: (%.1f, %.1f)\n"
|
||||
"World vert[0]: (%.1f, %.1f)\n"
|
||||
"cx=%.1f cy=%.1f sx=%.1f sy=%.1f rot=%.3f",
|
||||
(*m)[0][0], (*m)[0][1], (*m)[0][2], (*m)[0][3],
|
||||
(*m)[1][0], (*m)[1][1], (*m)[1][2], (*m)[1][3],
|
||||
(*m)[2][0], (*m)[2][1], (*m)[2][2], (*m)[2][3],
|
||||
(*m)[3][0], (*m)[3][1], (*m)[3][2], (*m)[3][3],
|
||||
s->verts[0].x, s->verts[0].y,
|
||||
s->cx + s->verts[0].x * s->sx * s->cos_r - s->verts[0].y * s->sy * s->sin_r,
|
||||
s->cy + s->verts[0].x * s->sx * s->sin_r + s->verts[0].y * s->sy * s->cos_r,
|
||||
s->cx, s->cy, s->sx, s->sy, s->rotation);
|
||||
if (igButton("Copy Debug", (ImVec2){0, 0}))
|
||||
sapp_set_clipboard_string(dbg);
|
||||
}
|
||||
}
|
||||
|
||||
igEnd();
|
||||
|
||||
if (ud->history.capturing && !igIsAnyItemActive()) {
|
||||
history_end_edit(&ud->history, &ud->shapes);
|
||||
}
|
||||
}
|
||||
|
||||
static void draw_log_panel(userdata_t *ud)
|
||||
{
|
||||
if (!ud->ui.log_show) return;
|
||||
|
||||
igSetNextWindowPos((ImVec2){10.0f, ud->camera.height - 200.0f}, ImGuiCond_FirstUseEver, (ImVec2){0, 0});
|
||||
igSetNextWindowSize((ImVec2){400.0f, 180.0f}, ImGuiCond_FirstUseEver);
|
||||
igBegin("Log", &ud->ui.log_show, 0);
|
||||
if (igButton("Clear", (ImVec2){0, 0})) {
|
||||
ud->ui.log_head = 0;
|
||||
ud->ui.log_count = 0;
|
||||
}
|
||||
igSameLine(0.0f, 10.0f);
|
||||
if (igButton("Copy", (ImVec2){0, 0})) {
|
||||
int total = ud->ui.log_count < LOG_RING_SIZE ? ud->ui.log_count : LOG_RING_SIZE;
|
||||
int start = ud->ui.log_count < LOG_RING_SIZE ? 0 : ud->ui.log_head;
|
||||
int cap = total * 260;
|
||||
char *buf = (char*) ALLOC((size_t)cap);
|
||||
int off = 0;
|
||||
for (int i = 0; i < total; i++) {
|
||||
int idx = (start + i) % LOG_RING_SIZE;
|
||||
off += snprintf(buf + off, (size_t)(cap - off), "%s\n", ud->ui.log_ring[idx].text);
|
||||
}
|
||||
sapp_set_clipboard_string(buf);
|
||||
FREE(buf);
|
||||
}
|
||||
igSameLine(0.0f, 10.0f);
|
||||
igText("%d entries", ud->ui.log_count);
|
||||
igSameLine(0.0f, 10.0f);
|
||||
igText("FPS: %.0f (avg: %.0f)", ud->debug.fps_immediate, ud->debug.fps_average);
|
||||
igSameLine(0.0f, 10.0f);
|
||||
igText("%.3fms", sapp_frame_duration() * 1000);
|
||||
igSeparator();
|
||||
|
||||
igBeginChild_Str("LogScroll", (ImVec2){0, 0}, false, 0);
|
||||
int total = ud->ui.log_count < LOG_RING_SIZE ? ud->ui.log_count : LOG_RING_SIZE;
|
||||
int start = ud->ui.log_count < LOG_RING_SIZE ? 0 : ud->ui.log_head;
|
||||
for (int i = 0; i < total; i++) {
|
||||
int idx = (start + i) % LOG_RING_SIZE;
|
||||
log_entry_t *e = &ud->ui.log_ring[idx];
|
||||
ImVec4 color;
|
||||
switch (e->level) {
|
||||
case 0: color = (ImVec4){1.0f, 0.3f, 0.3f, 1.0f}; break;
|
||||
case 1: color = (ImVec4){1.0f, 0.5f, 0.3f, 1.0f}; break;
|
||||
case 2: color = (ImVec4){1.0f, 0.9f, 0.3f, 1.0f}; break;
|
||||
default:color = (ImVec4){0.7f, 0.7f, 0.7f, 1.0f}; break;
|
||||
}
|
||||
igPushStyleColor_Vec4(ImGuiCol_Text, color);
|
||||
igTextUnformatted(e->text, NULL);
|
||||
igPopStyleColor(1);
|
||||
}
|
||||
if (total > 0) igSetScrollHereY(1.0f);
|
||||
igEndChild();
|
||||
igEnd();
|
||||
}
|
||||
|
||||
#endif
|
||||
150
src/util.h
150
src/util.h
@@ -1,150 +0,0 @@
|
||||
#ifndef UTIL_H
|
||||
#define UTIL_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
typedef struct vector_t {
|
||||
uint8_t *data;
|
||||
int count;
|
||||
int capacity;
|
||||
int stride;
|
||||
} vector_t;
|
||||
|
||||
/**
|
||||
* Zero-initialize a vector with the given element stride.
|
||||
*
|
||||
* @param v vector to initialize
|
||||
* @param stride byte size of each element
|
||||
*/
|
||||
static void vec_init(vector_t *v, int stride) {
|
||||
memset(v, 0, sizeof(*v));
|
||||
v->stride = stride;
|
||||
}
|
||||
|
||||
/**
|
||||
* Grow the vector's backing array to at least min_capacity elements.
|
||||
* Doubles capacity (starting at 8) or uses min_capacity, whichever is larger.
|
||||
*
|
||||
* @param v vector to grow
|
||||
* @param min_capacity minimum element count required
|
||||
*/
|
||||
static void vec_grow(vector_t *v, int min_capacity) {
|
||||
int new_cap = v->capacity ? v->capacity * 2 : 8;
|
||||
if (new_cap < min_capacity) new_cap = min_capacity;
|
||||
uint8_t *new_data = (uint8_t*) ALLOC(new_cap * v->stride);
|
||||
if (!new_data) {
|
||||
EM_ASM({ console.error("vec_grow: ALLOC failed for %d elements of %d bytes", $0, $1); },
|
||||
new_cap, v->stride);
|
||||
return;
|
||||
}
|
||||
if (v->data) {
|
||||
memcpy(new_data, v->data, v->count * v->stride);
|
||||
FREE(v->data);
|
||||
}
|
||||
v->data = new_data;
|
||||
v->capacity = new_cap;
|
||||
}
|
||||
|
||||
/**
|
||||
* Append an uninitialized element to the end of the vector. Grows if needed.
|
||||
*
|
||||
* @param v vector to push into
|
||||
* @return pointer to the new (uninitialized) element
|
||||
*/
|
||||
static void *vec_push(vector_t *v) {
|
||||
if (v->count >= v->capacity) vec_grow(v, v->count + 1);
|
||||
return v->data + (v->count++) * v->stride;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the last element from the vector (decrements count, no free).
|
||||
*
|
||||
* @param v vector to pop from
|
||||
*/
|
||||
static void vec_pop(vector_t *v) {
|
||||
if (v->count > 0) v->count--;
|
||||
}
|
||||
|
||||
static void vec_remove_ordered(vector_t *v, int index) {
|
||||
if (index < 0 || index >= v->count) return;
|
||||
if (index < v->count - 1) {
|
||||
memmove(v->data + index * v->stride,
|
||||
v->data + (index + 1) * v->stride,
|
||||
(v->count - index - 1) * v->stride);
|
||||
}
|
||||
v->count--;
|
||||
}
|
||||
|
||||
// Remove `count` elements at given indices in a single compaction pass.
|
||||
// Indices must be sorted in ascending order and must be valid.
|
||||
static void vec_remove_ordered_bulk(vector_t *v, const int *indices, int count) {
|
||||
if (count <= 0) return;
|
||||
int write = indices[0];
|
||||
for (int k = 0; k < count; k++) {
|
||||
int gap_start = indices[k];
|
||||
int gap_end = (k + 1 < count) ? indices[k + 1] : v->count;
|
||||
int keep = gap_end - gap_start - 1;
|
||||
if (keep > 0) {
|
||||
memmove(v->data + write * v->stride,
|
||||
v->data + (gap_start + 1) * v->stride,
|
||||
(size_t)keep * (size_t)v->stride);
|
||||
write += keep;
|
||||
}
|
||||
}
|
||||
v->count -= count;
|
||||
}
|
||||
|
||||
static void *vec_insert(vector_t *v, int index) {
|
||||
if (index < 0 || index > v->count) return NULL;
|
||||
if (v->count >= v->capacity) vec_grow(v, v->count + 1);
|
||||
if (index < v->count) {
|
||||
memmove(v->data + (index + 1) * v->stride,
|
||||
v->data + index * v->stride,
|
||||
(v->count - index) * v->stride);
|
||||
}
|
||||
v->count++;
|
||||
return v->data + index * v->stride;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the element at index by swapping in the last element (O(1)).
|
||||
* Order is not preserved.
|
||||
*
|
||||
* @param v vector to remove from
|
||||
* @param index index of the element to remove
|
||||
*/
|
||||
static void vec_remove(vector_t *v, int index) {
|
||||
if (index < 0 || index >= v->count) return;
|
||||
if (index < v->count - 1) {
|
||||
memcpy(v->data + index * v->stride,
|
||||
v->data + (v->count - 1) * v->stride,
|
||||
v->stride);
|
||||
}
|
||||
v->count--;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a pointer to the element at index (no bounds check).
|
||||
*
|
||||
* @param v vector to access
|
||||
* @param index element index
|
||||
* @return pointer to the element
|
||||
*/
|
||||
static void *vec_get(vector_t *v, int index) {
|
||||
return v->data + index * v->stride;
|
||||
}
|
||||
|
||||
/**
|
||||
* Free the backing array and reset the vector to empty.
|
||||
*
|
||||
* @param v vector to free
|
||||
*/
|
||||
static void vec_free(vector_t *v) {
|
||||
if (v->data) FREE(v->data);
|
||||
v->data = NULL;
|
||||
v->count = 0;
|
||||
v->capacity = 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user