You've already forked flecs_tests
Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| af0a39166c | |||
| 8ea6a0bf3e | |||
| dc708de354 | |||
| beea8a0281 | |||
| 936043340c | |||
| 9789e449c3 |
87
README.md
87
README.md
@@ -1,31 +1,6 @@
|
|||||||
# Cartograph
|
# Cartograph
|
||||||
|
|
||||||
A browser-based world map creation tool inspired by Wonderdraft and Inkarnate. Uses line-strip vector shapes with procedural geometry.
|
A browser-based world map creation tool inspired by Wonderdraft and Inkarnate. Uses a hierarchical tile-based SDF rendering.
|
||||||
|
|
||||||
## Features
|
|
||||||
|
|
||||||
- **Shapes** — parametric circles, stars, rectangles; freeform pen tool with Catmull-Rom splines
|
|
||||||
- **Instanced rendering** — shapes with identical local-space geometry share vertex buffers; per-instance transforms (position, scale, rotation) uploaded via SSBO
|
|
||||||
- **Bezier editing** — double-click any shape to edit its Bezier control points and handles in local space
|
|
||||||
- **Shape editing** — select, move, rotate, scale individual shapes; rect-select multiple shapes
|
|
||||||
- **Groups** — group/ungroup shapes with nested hierarchy support, group-level selection and focus mode
|
|
||||||
- **Clipboard** — copy/paste shapes with deep-copy of geometry, group remapping for pasted items
|
|
||||||
- **Undo/redo** — property-level history stack (position, scale, rotation, vertex edits, create/delete, group) with batch operations
|
|
||||||
- **Pen tool** — click to place control points; Enter, double-click, or close-to-start to commit; Escape to cancel
|
|
||||||
- **Spatial index** — open-addressing hash grid for fast hit testing, rect-selection, and viewport culling on large shape counts
|
|
||||||
- **Viewport** — zoom (scroll) and pan (right-click drag) with screen↔world coordinate transforms
|
|
||||||
- **Debug panel** — toggleable log overlay (backtick), FPS meter with 60-frame rolling average, log filtering
|
|
||||||
|
|
||||||
## Tech stack
|
|
||||||
|
|
||||||
| Layer | Library |
|
|
||||||
|---|---|
|
|
||||||
| Language | C (C99) |
|
|
||||||
| Compiler | [Emscripten](https://emscripten.org/) (emcc) → WebAssembly |
|
|
||||||
| Graphics | [Sokol](https://github.com/floooh/sokol) with WebGPU backend |
|
|
||||||
| UI | [Dear ImGui](https://github.com/ocornut/imgui) via [cimgui](https://github.com/cimgui/cimgui) |
|
|
||||||
| Math | [cglm](https://github.com/recp/cglm) |
|
|
||||||
| Shaders | WGSL (compiled to C headers via `xxd -i`) |
|
|
||||||
|
|
||||||
## Build
|
## Build
|
||||||
|
|
||||||
@@ -42,66 +17,6 @@ make debug
|
|||||||
|
|
||||||
Output is `app.html`, served by Emscripten's built-in web server or any static server.
|
Output is `app.html`, served by Emscripten's built-in web server or any static server.
|
||||||
|
|
||||||
## Project structure
|
|
||||||
|
|
||||||
```
|
|
||||||
src/
|
|
||||||
main.c Entry point, sokol init, render loop, input dispatch, UI panels, debug stats
|
|
||||||
api.h Central include hub — backend defines, all library headers, ALLOC/FREE macros
|
|
||||||
types.h Shared type definitions, constants, userdata_t
|
|
||||||
camera.h Viewport state, zoom/pan, MVP matrix (via glm_ortho), screen↔world transforms
|
|
||||||
render.h Shape & overlay pipeline init/shutdown, shader definitions
|
|
||||||
shape.h Shape geometry types, procedural generation, Bezier editing, vertex hash grouping, instanced buffer pool
|
|
||||||
spatial.h Spatial hash grid with linear probing, AABB queries, viewport culling
|
|
||||||
history.h Undo/redo stack — property-level tracking, vertex snapshots, batch operations
|
|
||||||
interact.h Selection AABB, group recursive helpers, resize handle hit-test, group rebuild
|
|
||||||
overlay.h Selection overlay geometry, rotate/corner handles, edit-mode anchor & handle visualization
|
|
||||||
draw.h Draw dispatch — frustum culling, instance map sorting, instanced draw calls
|
|
||||||
input.h Mouse/keyboard event handlers — select, move, rotate, resize, pen, edit mode, clipboard
|
|
||||||
ui_panels.h ImGui panels — toolbar, shape list tree, properties, debug log
|
|
||||||
util.h Stripe-based vector_t (dynamic array)
|
|
||||||
rand.h Xorshift32 PRNG
|
|
||||||
shaders/ WGSL shader sources (sprite, shape, overlay)
|
|
||||||
generated/ xxd-generated C headers from shaders
|
|
||||||
lib/
|
|
||||||
sokol/ Sokol single-file headers (gfx, app, glue, log, memtrack)
|
|
||||||
imgui/ Dear ImGui + cimgui
|
|
||||||
cglm/ C linear math library
|
|
||||||
util/ Sokol utility headers
|
|
||||||
```
|
|
||||||
|
|
||||||
## Architecture notes
|
|
||||||
|
|
||||||
### Instanced rendering with vertex hash grouping
|
|
||||||
|
|
||||||
Shapes share vertex buffers when their local-space geometry is identical. Each shape stores a 64-bit FNV-1a hash of its vertex data. The geometry pool groups shapes by `(num_elements, vertex_hash)` — not just vertex count. This means:
|
|
||||||
|
|
||||||
- **Parametric shapes** (circles, stars, rectangles from fixed formulas): all instances of the same type naturally produce the same hash, so they share one vertex buffer regardless of count.
|
|
||||||
- **Freeform paths** (pen tool): each path gets a unique hash, guaranteeing its own vertex buffer and preventing geometry corruption.
|
|
||||||
- **Bezier edits**: `shape_regenerate_from_ctrl` updates the hash and modifies the group buffer in-place via `sg_update_buffer` rather than destroying/recreating it.
|
|
||||||
|
|
||||||
The previous implementation grouped only by vertex count, which caused pen-drawn paths with matching counts to silently share the wrong geometry.
|
|
||||||
|
|
||||||
### Lazy group index rebuild
|
|
||||||
|
|
||||||
The `g_group_by_id` lookup array is rebuilt lazily. Operations that modify groups set a `g_group_index_dirty` flag; the actual rebuild happens on the first `find_group()` call afterward. This avoids redundant rebuilds when multiple group operations occur within the same frame (e.g., undo then redo, or group then ungroup).
|
|
||||||
|
|
||||||
### Hover state optimization
|
|
||||||
|
|
||||||
`handle_hover` (called every frame) tracks the previous set of highlighted shapes (up to 64) and only toggles state on shapes entering or leaving the highlight set. The O(n) full-array sweep is only used as a fallback when the highlight set exceeds 64 shapes.
|
|
||||||
|
|
||||||
### Pool rebuild granularity
|
|
||||||
|
|
||||||
When the geometry pool rebuilds, existing group vertex buffers whose `(num_elements, vertex_hash)` key still exists are preserved rather than destroyed and recreated. Only new keys trigger buffer creation, and only orphaned keys trigger destruction. The shape data SSBO is also preserved when its size hasn't changed.
|
|
||||||
|
|
||||||
### Spatial grid memory reuse
|
|
||||||
|
|
||||||
The spatial hash grid retains per-slot entry arrays across rebuilds. Only slots whose shape count has grown beyond their current capacity trigger a reallocation.
|
|
||||||
|
|
||||||
### Log deduplication
|
|
||||||
|
|
||||||
The debug log ring buffer uses a 64-bit message hash for fast deduplication of warnings and errors (levels 0-2). Debug-level messages (level 3) skip dedup entirely to avoid the linear scan cost when verbose logging is active.
|
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
MIT
|
MIT
|
||||||
|
|||||||
@@ -5,12 +5,12 @@ LIB_DIR="lib"
|
|||||||
|
|
||||||
echo "=== Fetching library dependencies ==="
|
echo "=== Fetching library dependencies ==="
|
||||||
|
|
||||||
# 1. Sokol (single-file headers)
|
|
||||||
mkdir -p "$LIB_DIR/sokol"
|
mkdir -p "$LIB_DIR/sokol"
|
||||||
mkdir -p "$LIB_DIR/imgui"
|
mkdir -p "$LIB_DIR/imgui"
|
||||||
mkdir -p "$LIB_DIR/util"
|
mkdir -p "$LIB_DIR/util"
|
||||||
mkdir -p "$LIB_DIR/cglm"
|
mkdir -p "$LIB_DIR/cglm"
|
||||||
|
|
||||||
|
# 1. Sokol (single-file headers)
|
||||||
if [ ! -f "$LIB_DIR/sokol/sokol_gfx.h" ]; then
|
if [ ! -f "$LIB_DIR/sokol/sokol_gfx.h" ]; then
|
||||||
echo " > Fetching sokol (pinned to emdawnwebgpu-compatible version)..."
|
echo " > Fetching sokol (pinned to emdawnwebgpu-compatible version)..."
|
||||||
git clone --depth 500 https://github.com/floooh/sokol.git "$LIB_DIR/sokol_tmp"
|
git clone --depth 500 https://github.com/floooh/sokol.git "$LIB_DIR/sokol_tmp"
|
||||||
@@ -59,4 +59,14 @@ else
|
|||||||
echo " > cglm already present"
|
echo " > cglm already present"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# 5. stb_ds.h
|
||||||
|
if [ ! -f "$LIB_DIR/util/stb_ds.h" ]; then
|
||||||
|
echo " > Fetching STB..."
|
||||||
|
git clone --depth 1 https://github.com/nothings/stb.git "$LIB_DIR/stb_tmp"
|
||||||
|
cp -r "$LIB_DIR/stb_tmp/stb_ds.h" "$LIB_DIR/util/stb_ds.h"
|
||||||
|
rm -rf "$LIB_DIR/stb_tmp"
|
||||||
|
else
|
||||||
|
echo " > stb_ds.h already present"
|
||||||
|
fi
|
||||||
|
|
||||||
echo "=== Done ==="
|
echo "=== Done ==="
|
||||||
|
|||||||
4
makefile
4
makefile
@@ -31,6 +31,7 @@ EMCC_FLAGS = --use-port=emdawnwebgpu \
|
|||||||
-sALLOW_MEMORY_GROWTH \
|
-sALLOW_MEMORY_GROWTH \
|
||||||
-msimd128 \
|
-msimd128 \
|
||||||
-sFILESYSTEM=0 \
|
-sFILESYSTEM=0 \
|
||||||
|
-sMALLOC=emmalloc \
|
||||||
-flto
|
-flto
|
||||||
|
|
||||||
# Shell template
|
# Shell template
|
||||||
@@ -45,6 +46,7 @@ $(TARGET): $(SHADER_HEADERS) $(C_SOURCES) $(IMGUI_SOURCES) $(CGLM_SOURCES) $(SHE
|
|||||||
-o $(TARGET) \
|
-o $(TARGET) \
|
||||||
$(EMCC_FLAGS) \
|
$(EMCC_FLAGS) \
|
||||||
-O3 \
|
-O3 \
|
||||||
|
--closure 1 \
|
||||||
-I$(LIB_DIR)/sokol \
|
-I$(LIB_DIR)/sokol \
|
||||||
-I$(LIB_DIR)/imgui \
|
-I$(LIB_DIR)/imgui \
|
||||||
-I$(LIB_DIR)/imgui/imgui \
|
-I$(LIB_DIR)/imgui/imgui \
|
||||||
@@ -65,7 +67,7 @@ debug: $(FETCH) $(SHADER_HEADERS) $(C_SOURCES) $(IMGUI_SOURCES) $(CGLM_SOURCES)
|
|||||||
$(CC) $(C_SOURCES) $(IMGUI_SOURCES) $(CGLM_SOURCES) \
|
$(CC) $(C_SOURCES) $(IMGUI_SOURCES) $(CGLM_SOURCES) \
|
||||||
-o $(TARGET) \
|
-o $(TARGET) \
|
||||||
$(EMCC_FLAGS) \
|
$(EMCC_FLAGS) \
|
||||||
-g --profiling-funcs -gsource-map=inline \
|
-g3 --profiling-funcs -gsource-map \
|
||||||
-sASSERTIONS \
|
-sASSERTIONS \
|
||||||
-I$(LIB_DIR)/sokol \
|
-I$(LIB_DIR)/sokol \
|
||||||
-I$(LIB_DIR)/imgui \
|
-I$(LIB_DIR)/imgui \
|
||||||
|
|||||||
116
src/api.h
116
src/api.h
@@ -1,77 +1,59 @@
|
|||||||
#ifndef API_DEFINITION
|
#ifndef API_DEFINITION
|
||||||
#define API_DEFINITION
|
#define API_DEFINITION
|
||||||
|
|
||||||
#define CIMGUI_DEFINE_ENUMS_AND_STRUCTS
|
|
||||||
|
|
||||||
#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 <emscripten.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
|
|
||||||
|
#include <emscripten/emmalloc.h>
|
||||||
|
|
||||||
|
#define CIMGUI_DEFINE_ENUMS_AND_STRUCTS
|
||||||
|
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "[%s - %s]: (%d) %s \tat %s:%d\r\n", tag, log_level == 0 ? "FATAL" : log_level == 1 ? "ERROR" : log_level == 2 ? "WARNING" : "INFO", log_item_id, message_or_null, filename_or_null, line_nr);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define SOKOL_ASSERT(x) ((void)((x) || (log_fn("ASSERT", 1, 1, "Assertion failed", __LINE__, __FILE__, NULL),0)))
|
||||||
|
|
||||||
|
#define SOKOL_IMPL
|
||||||
|
#define SOKOL_WGPU
|
||||||
|
#define SOKOL_IMGUI_IMPL
|
||||||
|
|
||||||
|
#define STB_DS_IMPLEMENTATION
|
||||||
|
#define STBDS_NO_SHORT_NAMES
|
||||||
|
|
||||||
|
#define STBDS_REALLOC(context,ptr,size) emmalloc_realloc(ptr, size)
|
||||||
|
#define STBDS_FREE(context,ptr) emmalloc_free(ptr)
|
||||||
|
|
||||||
|
#define COMPUTE_VIEWIDX_segments 0
|
||||||
|
#define COMPUTE_VIEWIDX_shapes 1
|
||||||
|
#define COMPUTE_VIEWIDX_circles 2
|
||||||
|
#define COMPUTE_VIEWIDX_tiles 3
|
||||||
|
#define COMPUTE_VIEWIDX_indices 4
|
||||||
|
#define COMPUTE_VIEWIDX_SDF 5
|
||||||
|
|
||||||
|
#define DISPLAY_VIEWIDX_SDF 0
|
||||||
|
#define DISPLAY_VIEWIDX_Sampler 1
|
||||||
|
|
||||||
|
static float clampf(float x, float a, float b)
|
||||||
|
{
|
||||||
|
return x < a ? a : (x > b ? b : x);
|
||||||
|
}
|
||||||
|
|
||||||
|
#include "sokol_gfx.h"
|
||||||
|
#include "sokol_app.h"
|
||||||
|
#include "sokol_glue.h"
|
||||||
|
#include "cimgui.h"
|
||||||
|
#include "sokol_imgui.h"
|
||||||
|
#include "stb_ds.h"
|
||||||
|
|
||||||
|
#include "shape.h"
|
||||||
|
//#include "cache.h"
|
||||||
|
#include "pool.h"
|
||||||
|
#include "generated/compute.h"
|
||||||
|
#include "generated/display.h"
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
107
src/cache.h
Normal file
107
src/cache.h
Normal file
@@ -0,0 +1,107 @@
|
|||||||
|
#include "api.h"
|
||||||
|
|
||||||
|
tile_slot_t* cache_evict(scene_t* s)
|
||||||
|
{
|
||||||
|
tile_slot_t* best = NULL;
|
||||||
|
uint64_t oldest = UINT64_MAX;
|
||||||
|
|
||||||
|
for(uint32_t i = 0; i < TILE_LAYERS; i++)
|
||||||
|
{
|
||||||
|
tile_slot_t* slot = &s->cache.slots[i];
|
||||||
|
if(slot->key.lod == UINT32_MAX) continue; // LOD == UINT32_MAX means the slot is free.
|
||||||
|
|
||||||
|
//Found a better candidate
|
||||||
|
if(slot->last_used < oldest)
|
||||||
|
{
|
||||||
|
oldest = slot->last_used;
|
||||||
|
best = slot;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(best == NULL)
|
||||||
|
return best;
|
||||||
|
|
||||||
|
stbds_hmdel(s->cache.map, best->key);
|
||||||
|
|
||||||
|
s->cache.free_layers[s->cache.free_count] = best->layer;
|
||||||
|
s->cache.free_count++;
|
||||||
|
s->cache.slots[best->layer].key.lod = UINT32_MAX; //Mark the slot as free for the evict scan using lod == UINT32_MAX
|
||||||
|
|
||||||
|
return best;
|
||||||
|
}
|
||||||
|
uint32_t cache_allocate(scene_t* s)
|
||||||
|
{
|
||||||
|
assert(s->cache.free_count > 0);
|
||||||
|
s->cache.free_count--;
|
||||||
|
uint32_t layer = s->cache.free_layers[s->cache.free_count];
|
||||||
|
|
||||||
|
return layer;
|
||||||
|
}
|
||||||
|
tile_slot_t* cache_search(scene_t* s, tile_key_t* key, uint64_t frame_count)
|
||||||
|
{
|
||||||
|
uint32_t index = stbds_hmgeti(s->cache.map, *key);
|
||||||
|
|
||||||
|
if(index >= 0)
|
||||||
|
{
|
||||||
|
uint32_t layer = s->cache.map[index].value;
|
||||||
|
tile_slot_t* slot = &s->cache.slots[layer];
|
||||||
|
slot->last_used = frame_count;
|
||||||
|
return slot;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Evict the least recently used (LRU) slot
|
||||||
|
if(stbds_hmlen(s->cache.map) >= TILE_LAYERS)
|
||||||
|
{
|
||||||
|
tile_slot_t* evict = cache_evict(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Allocate a free layer
|
||||||
|
uint32_t layer = cache_allocate(s);
|
||||||
|
tile_slot_t* slot = &s->cache.slots[layer];
|
||||||
|
slot->key.lod = key->lod; slot->key.tx = key->tx; slot->key.ty = key->ty;
|
||||||
|
slot->layer = layer;
|
||||||
|
slot->state = TILE_STATE_DIRTY;
|
||||||
|
slot->last_used = frame_count;
|
||||||
|
|
||||||
|
stbds_hmput(s->cache.map, *key, layer);
|
||||||
|
return slot;
|
||||||
|
}
|
||||||
|
// Works in 3 steps, first we select every required tiles and store the mising one from the cache
|
||||||
|
// Then we evict the LRU cache until we have enough space for the missing tiles
|
||||||
|
// Finally we allocate the missing tiles
|
||||||
|
static int cache_query(scene_t* s, uint32_t lod, box_t* box, tile_key_t** buffer)
|
||||||
|
{
|
||||||
|
uint64_t frame = sapp_frame_count();
|
||||||
|
tile_key_t tile_key = { lod, 0, 0 };
|
||||||
|
|
||||||
|
for(uint32_t ty = box->min_y; ty < box->max_y; ty++)
|
||||||
|
{
|
||||||
|
tile_key.ty = ty;
|
||||||
|
for(uint32_t tx = box->min_x; tx < box->max_x; tx++)
|
||||||
|
{
|
||||||
|
tile_key.tx = tx;
|
||||||
|
stbds_hmget(s->cache.map, tile_key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
static int cache_cull(scene_t* s, uint32_t tile_count)
|
||||||
|
{
|
||||||
|
uint32_t count = 0;
|
||||||
|
for(uint32_t i = 0; i < tile_count; i++)
|
||||||
|
{
|
||||||
|
tile_slot_t slot = s->cache.slots[i];
|
||||||
|
tile_task_t* tile = &s->cache.tiles[i];
|
||||||
|
tile->bounds.min_x = slot.key.tx * s->LODs[slot.key.lod].texel_size;
|
||||||
|
tile->bounds.min_y = slot.key.ty * s->LODs[slot.key.lod].texel_size;
|
||||||
|
tile->bounds.max_x = (slot.key.tx + 1) * s->LODs[slot.key.lod].texel_size;
|
||||||
|
tile->bounds.max_y = (slot.key.ty + 1) * s->LODs[slot.key.lod].texel_size;
|
||||||
|
tile->layer = slot.layer;
|
||||||
|
|
||||||
|
uint32_t start = count;
|
||||||
|
for(uint32_t j = 0; j < s->num_shapes; j++)
|
||||||
|
{
|
||||||
|
if(BOX_INTERSECTS(tile->bounds, s->shapes[j].aabb)) s->cache.indices[count++] = j;
|
||||||
|
}
|
||||||
|
tile->offset = start; tile->count = count - start;
|
||||||
|
}
|
||||||
|
}
|
||||||
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
|
|
||||||
686
src/generated/compute.h
Normal file
686
src/generated/compute.h
Normal file
@@ -0,0 +1,686 @@
|
|||||||
|
unsigned char src_shaders_compute_wgsl[] = {
|
||||||
|
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, 0x20, 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, 0x20, 0x2f, 0x2f,
|
||||||
|
0x4f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x20, 0x69, 0x6e, 0x20, 0x74, 0x68,
|
||||||
|
0x65, 0x20, 0x73, 0x65, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x20, 0x62,
|
||||||
|
0x75, 0x66, 0x66, 0x65, 0x72, 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, 0x73, 0x74, 0x72, 0x75, 0x63,
|
||||||
|
0x74, 0x20, 0x43, 0x69, 0x72, 0x63, 0x6c, 0x65, 0x20, 0x7b, 0x0d, 0x0a,
|
||||||
|
0x20, 0x20, 0x20, 0x20, 0x63, 0x65, 0x6e, 0x74, 0x65, 0x72, 0x3a, 0x20,
|
||||||
|
0x76, 0x65, 0x63, 0x32, 0x66, 0x2c, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20,
|
||||||
|
0x72, 0x61, 0x64, 0x69, 0x75, 0x73, 0x3a, 0x20, 0x66, 0x33, 0x32, 0x2c,
|
||||||
|
0x0d, 0x0a, 0x7d, 0x0d, 0x0a, 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x20,
|
||||||
|
0x54, 0x69, 0x6c, 0x65, 0x20, 0x7b, 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, 0x20, 0x20, 0x20, 0x20, 0x6f, 0x66,
|
||||||
|
0x66, 0x73, 0x65, 0x74, 0x3a, 0x20, 0x75, 0x33, 0x32, 0x2c, 0x0d, 0x0a,
|
||||||
|
0x20, 0x20, 0x20, 0x20, 0x63, 0x69, 0x72, 0x63, 0x6c, 0x65, 0x5f, 0x63,
|
||||||
|
0x6f, 0x75, 0x6e, 0x74, 0x3a, 0x20, 0x75, 0x33, 0x32, 0x2c, 0x0d, 0x0a,
|
||||||
|
0x20, 0x20, 0x20, 0x20, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x3a, 0x20, 0x75,
|
||||||
|
0x33, 0x32, 0x2c, 0x0d, 0x0a, 0x7d, 0x3b, 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,
|
||||||
|
0x3e, 0x20, 0x63, 0x69, 0x72, 0x63, 0x6c, 0x65, 0x73, 0x3a, 0x20, 0x61,
|
||||||
|
0x72, 0x72, 0x61, 0x79, 0x3c, 0x43, 0x69, 0x72, 0x63, 0x6c, 0x65, 0x3e,
|
||||||
|
0x3b, 0x0d, 0x0a, 0x40, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x28, 0x31, 0x29,
|
||||||
|
0x20, 0x40, 0x62, 0x69, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x28, 0x33, 0x29,
|
||||||
|
0x20, 0x76, 0x61, 0x72, 0x3c, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65,
|
||||||
|
0x3e, 0x20, 0x74, 0x69, 0x6c, 0x65, 0x73, 0x3a, 0x20, 0x61, 0x72, 0x72,
|
||||||
|
0x61, 0x79, 0x3c, 0x54, 0x69, 0x6c, 0x65, 0x3e, 0x3b, 0x0d, 0x0a, 0x40,
|
||||||
|
0x67, 0x72, 0x6f, 0x75, 0x70, 0x28, 0x31, 0x29, 0x20, 0x40, 0x62, 0x69,
|
||||||
|
0x6e, 0x64, 0x69, 0x6e, 0x67, 0x28, 0x34, 0x29, 0x20, 0x76, 0x61, 0x72,
|
||||||
|
0x3c, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x3e, 0x20, 0x69, 0x6e,
|
||||||
|
0x64, 0x69, 0x63, 0x65, 0x73, 0x3a, 0x20, 0x61, 0x72, 0x72, 0x61, 0x79,
|
||||||
|
0x3c, 0x75, 0x33, 0x32, 0x3e, 0x3b, 0x0d, 0x0a, 0x40, 0x67, 0x72, 0x6f,
|
||||||
|
0x75, 0x70, 0x28, 0x31, 0x29, 0x20, 0x40, 0x62, 0x69, 0x6e, 0x64, 0x69,
|
||||||
|
0x6e, 0x67, 0x28, 0x35, 0x29, 0x20, 0x76, 0x61, 0x72, 0x20, 0x73, 0x64,
|
||||||
|
0x66, 0x5f, 0x62, 0x75, 0x66, 0x66, 0x65, 0x72, 0x3a, 0x20, 0x74, 0x65,
|
||||||
|
0x78, 0x74, 0x75, 0x72, 0x65, 0x5f, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67,
|
||||||
|
0x65, 0x5f, 0x32, 0x64, 0x3c, 0x72, 0x31, 0x36, 0x66, 0x6c, 0x6f, 0x61,
|
||||||
|
0x74, 0x2c, 0x20, 0x77, 0x72, 0x69, 0x74, 0x65, 0x3e, 0x3b, 0x0d, 0x0a,
|
||||||
|
0x0d, 0x0a, 0x6f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x20, 0x54,
|
||||||
|
0x49, 0x4c, 0x45, 0x5f, 0x53, 0x49, 0x5a, 0x45, 0x3a, 0x20, 0x75, 0x33,
|
||||||
|
0x32, 0x20, 0x3d, 0x20, 0x32, 0x35, 0x36, 0x75, 0x3b, 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, 0x77, 0x6f,
|
||||||
|
0x72, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x5f, 0x69, 0x64, 0x29, 0x20,
|
||||||
|
0x77, 0x67, 0x3a, 0x20, 0x76, 0x65, 0x63, 0x33, 0x3c, 0x75, 0x33, 0x32,
|
||||||
|
0x3e, 0x2c, 0x20, 0x2f, 0x2f, 0x20, 0x65, 0x61, 0x63, 0x68, 0x20, 0x77,
|
||||||
|
0x6f, 0x72, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x20, 0x69, 0x73, 0x20,
|
||||||
|
0x61, 0x20, 0x74, 0x69, 0x6c, 0x65, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20,
|
||||||
|
0x20, 0x20, 0x20, 0x20, 0x40, 0x62, 0x75, 0x69, 0x6c, 0x74, 0x69, 0x6e,
|
||||||
|
0x28, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x5f, 0x69, 0x6e, 0x76, 0x6f, 0x63,
|
||||||
|
0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x29, 0x20, 0x6c, 0x6f,
|
||||||
|
0x63, 0x61, 0x6c, 0x3a, 0x20, 0x76, 0x65, 0x63, 0x33, 0x3c, 0x75, 0x33,
|
||||||
|
0x32, 0x3e, 0x29, 0x20, 0x2f, 0x2f, 0x20, 0x65, 0x61, 0x63, 0x68, 0x20,
|
||||||
|
0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x69, 0x6e, 0x76, 0x6f, 0x63, 0x61,
|
||||||
|
0x74, 0x69, 0x6f, 0x6e, 0x20, 0x69, 0x73, 0x20, 0x61, 0x20, 0x70, 0x69,
|
||||||
|
0x78, 0x65, 0x6c, 0x0d, 0x0a, 0x7b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20,
|
||||||
|
0x6c, 0x65, 0x74, 0x20, 0x74, 0x69, 0x6c, 0x65, 0x5f, 0x69, 0x64, 0x78,
|
||||||
|
0x20, 0x3d, 0x20, 0x77, 0x67, 0x2e, 0x78, 0x20, 0x2f, 0x20, 0x31, 0x36,
|
||||||
|
0x75, 0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x65, 0x74, 0x20,
|
||||||
|
0x74, 0x69, 0x6c, 0x65, 0x20, 0x3d, 0x20, 0x74, 0x69, 0x6c, 0x65, 0x73,
|
||||||
|
0x5b, 0x74, 0x69, 0x6c, 0x65, 0x5f, 0x69, 0x64, 0x78, 0x5d, 0x3b, 0x0d,
|
||||||
|
0x0a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x65, 0x74, 0x20, 0x70,
|
||||||
|
0x78, 0x20, 0x3d, 0x20, 0x28, 0x77, 0x67, 0x2e, 0x78, 0x20, 0x25, 0x20,
|
||||||
|
0x31, 0x36, 0x75, 0x29, 0x20, 0x2a, 0x20, 0x38, 0x75, 0x20, 0x2b, 0x20,
|
||||||
|
0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x2e, 0x78, 0x3b, 0x0d, 0x0a, 0x20, 0x20,
|
||||||
|
0x20, 0x20, 0x6c, 0x65, 0x74, 0x20, 0x70, 0x79, 0x20, 0x3d, 0x20, 0x77,
|
||||||
|
0x67, 0x2e, 0x79, 0x20, 0x2a, 0x20, 0x38, 0x75, 0x20, 0x2b, 0x20, 0x6c,
|
||||||
|
0x6f, 0x63, 0x61, 0x6c, 0x2e, 0x79, 0x3b, 0x0d, 0x0a, 0x0d, 0x0a, 0x20,
|
||||||
|
0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x28, 0x70, 0x78, 0x20, 0x3e, 0x3d,
|
||||||
|
0x20, 0x54, 0x49, 0x4c, 0x45, 0x5f, 0x53, 0x49, 0x5a, 0x45, 0x20, 0x7c,
|
||||||
|
0x7c, 0x20, 0x70, 0x79, 0x20, 0x3e, 0x3d, 0x20, 0x54, 0x49, 0x4c, 0x45,
|
||||||
|
0x5f, 0x53, 0x49, 0x5a, 0x45, 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, 0x6c, 0x65, 0x74, 0x20, 0x75, 0x76, 0x20, 0x3d,
|
||||||
|
0x20, 0x28, 0x76, 0x65, 0x63, 0x32, 0x66, 0x28, 0x66, 0x33, 0x32, 0x28,
|
||||||
|
0x70, 0x78, 0x29, 0x2c, 0x20, 0x66, 0x33, 0x32, 0x28, 0x70, 0x79, 0x29,
|
||||||
|
0x29, 0x20, 0x2b, 0x20, 0x30, 0x2e, 0x35, 0x29, 0x20, 0x2f, 0x20, 0x66,
|
||||||
|
0x33, 0x32, 0x28, 0x54, 0x49, 0x4c, 0x45, 0x5f, 0x53, 0x49, 0x5a, 0x45,
|
||||||
|
0x29, 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, 0x2e, 0x77, 0x6f, 0x72, 0x6c, 0x64, 0x5f, 0x6d,
|
||||||
|
0x69, 0x6e, 0x2c, 0x20, 0x74, 0x69, 0x6c, 0x65, 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, 0x73, 0x64, 0x66, 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, 0x74, 0x69, 0x6c, 0x65, 0x2e, 0x63,
|
||||||
|
0x6f, 0x75, 0x6e, 0x74, 0x3b, 0x20, 0x73, 0x2b, 0x2b, 0x29, 0x20, 0x7b,
|
||||||
|
0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x2f, 0x2f,
|
||||||
|
0x20, 0x55, 0x73, 0x65, 0x20, 0x61, 0x20, 0x70, 0x72, 0x65, 0x2d, 0x63,
|
||||||
|
0x75, 0x6c, 0x6c, 0x65, 0x64, 0x20, 0x73, 0x68, 0x61, 0x70, 0x65, 0x20,
|
||||||
|
0x72, 0x61, 0x6e, 0x67, 0x65, 0x20, 0x70, 0x65, 0x72, 0x20, 0x74, 0x69,
|
||||||
|
0x6c, 0x65, 0x20, 0x74, 0x6f, 0x20, 0x72, 0x65, 0x64, 0x75, 0x63, 0x65,
|
||||||
|
0x20, 0x74, 0x68, 0x65, 0x20, 0x70, 0x65, 0x72, 0x2d, 0x70, 0x69, 0x78,
|
||||||
|
0x65, 0x6c, 0x20, 0x70, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x69, 0x6e,
|
||||||
|
0x67, 0x20, 0x74, 0x69, 0x6d, 0x65, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20,
|
||||||
|
0x20, 0x20, 0x20, 0x20, 0x6c, 0x65, 0x74, 0x20, 0x69, 0x6e, 0x64, 0x65,
|
||||||
|
0x78, 0x20, 0x3d, 0x20, 0x69, 0x6e, 0x64, 0x69, 0x63, 0x65, 0x73, 0x5b,
|
||||||
|
0x74, 0x69, 0x6c, 0x65, 0x2e, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x20,
|
||||||
|
0x2b, 0x20, 0x73, 0x5d, 0x3b, 0x0d, 0x0a, 0x0d, 0x0a, 0x20, 0x20, 0x20,
|
||||||
|
0x20, 0x20, 0x20, 0x20, 0x20, 0x2f, 0x2f, 0x20, 0x49, 0x66, 0x20, 0x74,
|
||||||
|
0x68, 0x65, 0x20, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x20, 0x69, 0x73, 0x20,
|
||||||
|
0x6c, 0x6f, 0x77, 0x65, 0x72, 0x20, 0x74, 0x68, 0x61, 0x6e, 0x20, 0x74,
|
||||||
|
0x68, 0x65, 0x20, 0x63, 0x69, 0x72, 0x63, 0x6c, 0x65, 0x20, 0x63, 0x6f,
|
||||||
|
0x75, 0x6e, 0x74, 0x2c, 0x20, 0x69, 0x74, 0x20, 0x6d, 0x65, 0x61, 0x6e,
|
||||||
|
0x20, 0x77, 0x65, 0x20, 0x61, 0x72, 0x65, 0x20, 0x70, 0x72, 0x6f, 0x63,
|
||||||
|
0x65, 0x73, 0x73, 0x69, 0x6e, 0x67, 0x20, 0x63, 0x69, 0x72, 0x63, 0x6c,
|
||||||
|
0x65, 0x73, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||||
|
0x69, 0x66, 0x28, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x20, 0x3c, 0x20, 0x74,
|
||||||
|
0x69, 0x6c, 0x65, 0x2e, 0x63, 0x69, 0x72, 0x63, 0x6c, 0x65, 0x5f, 0x63,
|
||||||
|
0x6f, 0x75, 0x6e, 0x74, 0x29, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||||
|
0x20, 0x20, 0x20, 0x7b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||||
|
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x65, 0x74, 0x20, 0x63, 0x20,
|
||||||
|
0x3d, 0x20, 0x63, 0x69, 0x72, 0x63, 0x6c, 0x65, 0x73, 0x5b, 0x69, 0x6e,
|
||||||
|
0x64, 0x65, 0x78, 0x5d, 0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||||
|
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x64, 0x66, 0x20, 0x3d,
|
||||||
|
0x20, 0x6d, 0x69, 0x6e, 0x28, 0x73, 0x64, 0x66, 0x2c, 0x20, 0x6c, 0x65,
|
||||||
|
0x6e, 0x67, 0x74, 0x68, 0x28, 0x77, 0x6f, 0x72, 0x6c, 0x64, 0x20, 0x2d,
|
||||||
|
0x20, 0x63, 0x2e, 0x63, 0x65, 0x6e, 0x74, 0x65, 0x72, 0x29, 0x20, 0x2d,
|
||||||
|
0x20, 0x63, 0x2e, 0x72, 0x61, 0x64, 0x69, 0x75, 0x73, 0x29, 0x3b, 0x0d,
|
||||||
|
0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x0d, 0x0a,
|
||||||
|
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x65, 0x6c, 0x73, 0x65,
|
||||||
|
0x20, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7b,
|
||||||
|
0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 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, 0x69, 0x6e, 0x64,
|
||||||
|
0x65, 0x78, 0x5d, 0x3b, 0x0d, 0x0a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20,
|
||||||
|
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x2f, 0x2a, 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, 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, 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, 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, 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,
|
||||||
|
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, 0x20, 0x20, 0x20,
|
||||||
|
0x20, 0x63, 0x6f, 0x6e, 0x74, 0x69, 0x6e, 0x75, 0x65, 0x3b, 0x0d, 0x0a,
|
||||||
|
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||||
|
0x7d, 0x2a, 0x2f, 0x0d, 0x0a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 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, 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, 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, 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, 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,
|
||||||
|
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, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x0d, 0x0a, 0x0d, 0x0a, 0x20, 0x20,
|
||||||
|
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 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,
|
||||||
|
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x64, 0x66, 0x20,
|
||||||
|
0x3d, 0x20, 0x6d, 0x69, 0x6e, 0x28, 0x73, 0x64, 0x66, 0x2c, 0x20, 0x73,
|
||||||
|
0x69, 0x67, 0x6e, 0x20, 0x2a, 0x20, 0x6d, 0x69, 0x6e, 0x44, 0x69, 0x73,
|
||||||
|
0x74, 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, 0x74, 0x65, 0x78, 0x74, 0x75, 0x72, 0x65,
|
||||||
|
0x53, 0x74, 0x6f, 0x72, 0x65, 0x28, 0x73, 0x64, 0x66, 0x5f, 0x62, 0x75,
|
||||||
|
0x66, 0x66, 0x65, 0x72, 0x2c, 0x20, 0x76, 0x65, 0x63, 0x32, 0x28, 0x75,
|
||||||
|
0x33, 0x32, 0x28, 0x77, 0x6f, 0x72, 0x6c, 0x64, 0x2e, 0x78, 0x29, 0x2c,
|
||||||
|
0x20, 0x75, 0x33, 0x32, 0x28, 0x77, 0x6f, 0x72, 0x6c, 0x64, 0x2e, 0x79,
|
||||||
|
0x29, 0x29, 0x2c, 0x20, 0x76, 0x65, 0x63, 0x34, 0x66, 0x28, 0x73, 0x64,
|
||||||
|
0x66, 0x2c, 0x20, 0x30, 0x2e, 0x30, 0x2c, 0x20, 0x30, 0x2e, 0x30, 0x2c,
|
||||||
|
0x20, 0x31, 0x2e, 0x30, 0x29, 0x29, 0x3b, 0x0d, 0x0a, 0x7d
|
||||||
|
};
|
||||||
|
unsigned int src_shaders_compute_wgsl_len = 8194;
|
||||||
47
src/generated/display.h
Normal file
47
src/generated/display.h
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
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, 0x74,
|
||||||
|
0x69, 0x6d, 0x65, 0x3a, 0x20, 0x75, 0x33, 0x32, 0x2c, 0x0d, 0x0a, 0x20,
|
||||||
|
0x20, 0x20, 0x20, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x3a, 0x20, 0x75, 0x33,
|
||||||
|
0x32, 0x2c, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6d, 0x76, 0x70, 0x3a,
|
||||||
|
0x20, 0x6d, 0x61, 0x74, 0x34, 0x78, 0x34, 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,
|
||||||
|
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, 0x20, 0x73, 0x64, 0x66, 0x20, 0x3a, 0x20, 0x74, 0x65,
|
||||||
|
0x78, 0x74, 0x75, 0x72, 0x65, 0x5f, 0x32, 0x64, 0x3c, 0x66, 0x33, 0x32,
|
||||||
|
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, 0x20, 0x73, 0x64, 0x66, 0x5f, 0x73, 0x61,
|
||||||
|
0x6d, 0x70, 0x6c, 0x65, 0x72, 0x20, 0x3a, 0x20, 0x73, 0x61, 0x6d, 0x70,
|
||||||
|
0x6c, 0x65, 0x72, 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, 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, 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,
|
||||||
|
0x0d, 0x0a, 0x7b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74,
|
||||||
|
0x75, 0x72, 0x6e, 0x20, 0x76, 0x65, 0x63, 0x34, 0x66, 0x28, 0x70, 0x6f,
|
||||||
|
0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x2c, 0x20, 0x30, 0x2e, 0x30, 0x2c,
|
||||||
|
0x20, 0x31, 0x2e, 0x30, 0x29, 0x20, 0x2a, 0x20, 0x75, 0x6e, 0x69, 0x66,
|
||||||
|
0x6f, 0x72, 0x6d, 0x73, 0x2e, 0x6d, 0x76, 0x70, 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, 0x40, 0x62, 0x75, 0x69, 0x6c, 0x74, 0x69, 0x6e, 0x28, 0x70, 0x6f,
|
||||||
|
0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x29, 0x20, 0x70, 0x6f, 0x73, 0x69,
|
||||||
|
0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x20, 0x76, 0x65, 0x63, 0x34, 0x66, 0x29,
|
||||||
|
0x20, 0x2d, 0x3e, 0x20, 0x40, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f,
|
||||||
|
0x6e, 0x28, 0x30, 0x29, 0x20, 0x76, 0x65, 0x63, 0x34, 0x66, 0x0d, 0x0a,
|
||||||
|
0x7b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72,
|
||||||
|
0x6e, 0x20, 0x74, 0x65, 0x78, 0x74, 0x75, 0x72, 0x65, 0x53, 0x61, 0x6d,
|
||||||
|
0x70, 0x6c, 0x65, 0x28, 0x73, 0x64, 0x66, 0x2c, 0x20, 0x73, 0x64, 0x66,
|
||||||
|
0x5f, 0x73, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x72, 0x2c, 0x20, 0x70, 0x6f,
|
||||||
|
0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x78, 0x79, 0x29, 0x3b, 0x0d,
|
||||||
|
0x0a, 0x7d
|
||||||
|
};
|
||||||
|
unsigned int src_shaders_display_wgsl_len = 518;
|
||||||
@@ -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
|
|
||||||
774
src/main.c
774
src/main.c
@@ -1,131 +1,164 @@
|
|||||||
#include "api.h"
|
#include "api.h"
|
||||||
|
|
||||||
static void log_capture(const char* tag, uint32_t log_level, uint32_t log_item,
|
typedef struct display_uniforms {
|
||||||
const char* message, uint32_t line_nr, const char* filename,
|
uint32_t frame;
|
||||||
void* user_data)
|
uint32_t time;
|
||||||
|
|
||||||
|
float mvp[16];
|
||||||
|
} display_uniforms;
|
||||||
|
|
||||||
|
typedef struct renderer_t {
|
||||||
|
sg_pipeline pipeline;
|
||||||
|
sg_pass_action clear_pass;
|
||||||
|
sg_bindings bindings;
|
||||||
|
|
||||||
|
display_uniforms uniforms;
|
||||||
|
} renderer_t;
|
||||||
|
|
||||||
|
typedef struct compute_t {
|
||||||
|
sg_pipeline pipeline;
|
||||||
|
sg_bindings bindings;
|
||||||
|
sg_pass pass;
|
||||||
|
} compute_t;
|
||||||
|
|
||||||
|
typedef struct userdata_t {
|
||||||
|
scene_t scene;
|
||||||
|
renderer_t renderer;
|
||||||
|
compute_t compute;
|
||||||
|
|
||||||
|
//Viewport related values
|
||||||
|
float pan_x, pan_y;
|
||||||
|
float zoom, rotation;
|
||||||
|
} userdata_t;
|
||||||
|
|
||||||
|
static void* _malloc(size_t size, void* userdata)
|
||||||
{
|
{
|
||||||
userdata_t* ud = (userdata_t*)user_data;
|
(void) userdata;
|
||||||
|
return emmalloc_malloc(size);
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
static void _free(void* ptr, void* userdata)
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
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)
|
|
||||||
{
|
{
|
||||||
float dt = (float)sapp_frame_duration();
|
(void) userdata;
|
||||||
float instant_fps = dt > 0.0001f ? 1.0f / dt : 0.0f;
|
emmalloc_free(ptr);
|
||||||
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++;
|
|
||||||
}
|
}
|
||||||
ud->debug.frame_times[idx] = dt;
|
|
||||||
ud->debug.frame_time_sum += dt;
|
static void refresh_SDF(userdata_t* ud)
|
||||||
ud->debug.frame_time_head = (idx + 1) % 60;
|
{
|
||||||
ud->debug.fps_average = ud->debug.frame_time_sum > 0.0001f
|
//Get visible tiles
|
||||||
? (float)ud->debug.frame_time_count / ud->debug.frame_time_sum : 0.0f;
|
float view_world_w = sapp_widthf() * ud->zoom;
|
||||||
|
float view_world_h = sapp_heightf() * ud->zoom;
|
||||||
|
box_t viewport = (box_t) {
|
||||||
|
ud->pan_x - view_world_w * 0.5f,
|
||||||
|
ud->pan_y - view_world_h * 0.5f,
|
||||||
|
ud->pan_x + view_world_w * 0.5f,
|
||||||
|
ud->pan_y + view_world_h * 0.5f,
|
||||||
|
};
|
||||||
|
|
||||||
|
bool dirty = false;
|
||||||
|
if(ud->scene.segment_dirty)
|
||||||
|
{
|
||||||
|
pool_view_grow(ud->compute.bindings.views[COMPUTE_VIEWIDX_segments], sizeof(segment_t), ud->scene.shapes.num_segments, ud->scene.shapes.segments);
|
||||||
|
ud->scene.segment_dirty = false;
|
||||||
|
dirty = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(ud->scene.shape_dirty)
|
||||||
|
{
|
||||||
|
pool_view_grow(ud->compute.bindings.views[COMPUTE_VIEWIDX_shapes], sizeof(shape_meta_t), ud->scene.shapes.num_shapes, ud->scene.shapes.shapes);
|
||||||
|
ud->scene.shape_dirty = false;
|
||||||
|
dirty = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(ud->scene.circle_dirty)
|
||||||
|
{
|
||||||
|
pool_view_grow(ud->compute.bindings.views[COMPUTE_VIEWIDX_circles], sizeof(circle_t), ud->scene.circles.num_circles, ud->scene.circles.circles);
|
||||||
|
ud->scene.circle_dirty = false;
|
||||||
|
dirty = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(dirty)
|
||||||
|
{
|
||||||
|
uint32_t tile_count = scene_process_tiles(&ud->scene, ud->pan_x, ud->pan_y, ud->zoom, &ud->compute.bindings);
|
||||||
|
|
||||||
|
if(tile_count > 0)
|
||||||
|
{
|
||||||
|
pool_view_grow(ud->compute.bindings.views[COMPUTE_VIEWIDX_tiles], sizeof(tile_task_t), tile_count, ud->scene.cache.tiles);
|
||||||
|
pool_view_grow(ud->compute.bindings.views[COMPUTE_VIEWIDX_indices], sizeof(uint32_t), ud->scene.cache.num_indices, ud->scene.cache.indices);
|
||||||
|
|
||||||
|
sg_begin_pass(&ud->compute.pass);
|
||||||
|
sg_apply_pipeline(ud->compute.pipeline);
|
||||||
|
sg_apply_bindings(&ud->compute.bindings);
|
||||||
|
|
||||||
|
sg_dispatch(tile_count * 16, 16, 1);
|
||||||
|
|
||||||
|
sg_end_pass();
|
||||||
|
}
|
||||||
|
dirty = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static sg_pass pass = (sg_pass){
|
||||||
|
.label = "Render pass",
|
||||||
|
};
|
||||||
|
static simgui_frame_desc_t imgui_frame = {0};
|
||||||
|
|
||||||
|
static void compute_mvp(userdata_t *ud)
|
||||||
|
{
|
||||||
|
const float w = sapp_widthf();
|
||||||
|
const float h = sapp_heightf();
|
||||||
|
const float z = ud->zoom;
|
||||||
|
const float px = ud->pan_x;
|
||||||
|
const float py = ud->pan_y;
|
||||||
|
float* mvp = ud->renderer.uniforms.mvp;
|
||||||
|
|
||||||
|
mvp[0] = (2.0f / w) * z;
|
||||||
|
mvp[1] = 0.0f;
|
||||||
|
mvp[2] = 0.0f;
|
||||||
|
mvp[3] = (2.0f / w) * px;
|
||||||
|
|
||||||
|
mvp[4] = 0.0f;
|
||||||
|
mvp[5] = (2.0f / h) * z;
|
||||||
|
mvp[6] = 0.0f;
|
||||||
|
mvp[7] = (2.0f / h) * py;
|
||||||
|
|
||||||
|
mvp[8] = 0.0f;
|
||||||
|
mvp[9] = 0.0f;
|
||||||
|
mvp[10] = 0.0f;
|
||||||
|
mvp[11] = 0.0f;
|
||||||
|
|
||||||
|
mvp[12] = 0.0f;
|
||||||
|
mvp[13] = 0.0f;
|
||||||
|
mvp[14] = 0.0f;
|
||||||
|
mvp[15] = 1.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void frame(void* _userdata)
|
static void frame(void* _userdata)
|
||||||
{
|
{
|
||||||
userdata_t* ud = (userdata_t*) _userdata;
|
userdata_t* ud = (userdata_t*) _userdata;
|
||||||
shape_begin_frame();
|
|
||||||
|
|
||||||
meter_fps(ud);
|
ud->renderer.uniforms.frame = sapp_frame_count();
|
||||||
ud->time += (double)sapp_frame_duration();
|
ud->renderer.uniforms.time += (uint32_t) ceil(sapp_frame_duration_unfiltered() / 1000.0f);
|
||||||
spatial_rebuild(&ud->spatial_grid, &ud->shapes);
|
|
||||||
|
|
||||||
float sel_cx, sel_cy, sel_hw, sel_hh, sel_angle;
|
refresh_SDF(ud);
|
||||||
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,
|
pass.swapchain = sglue_swapchain();
|
||||||
sel_hw, sel_hh, sel_angle, has_overlay, show_handle);
|
sg_begin_pass(&pass);
|
||||||
|
|
||||||
sg_begin_pass(&(sg_pass){
|
imgui_frame.width = sapp_width(),
|
||||||
.action = ud->renderer.clear_pass,
|
imgui_frame.height = sapp_height(),
|
||||||
.swapchain = sglue_swapchain(),
|
imgui_frame.delta_time = sapp_frame_duration_unfiltered(),
|
||||||
});
|
imgui_frame.dpi_scale = sapp_dpi_scale(),
|
||||||
|
simgui_new_frame(&imgui_frame);
|
||||||
|
|
||||||
draw_shapes(ud);
|
igBegin("Framerate", (bool*) true, ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoTitleBar);
|
||||||
draw_overlay_and_handles(ud, has_overlay, show_handle);
|
igText("%.0f FPS", 1 / sapp_frame_duration_unfiltered());
|
||||||
|
igText("%.3fms", sapp_frame_duration_unfiltered() * 1000);
|
||||||
|
igEnd();
|
||||||
|
|
||||||
simgui_new_frame(&(simgui_frame_desc_t){
|
sg_apply_pipeline(ud->renderer.pipeline);
|
||||||
.width = sapp_width(),
|
sg_apply_uniforms(0, &SG_RANGE(ud->renderer.uniforms));
|
||||||
.height = sapp_height(),
|
sg_apply_bindings(&ud->renderer.bindings);
|
||||||
.delta_time = sapp_frame_duration(),
|
sg_draw(0, 6, 1);
|
||||||
.dpi_scale = sapp_dpi_scale(),
|
|
||||||
});
|
|
||||||
|
|
||||||
draw_top_panel(ud);
|
|
||||||
draw_shape_list_panel(ud);
|
|
||||||
draw_properties_panel(ud);
|
|
||||||
draw_log_panel(ud);
|
|
||||||
|
|
||||||
simgui_render();
|
simgui_render();
|
||||||
sg_end_pass();
|
sg_end_pass();
|
||||||
@@ -136,317 +169,262 @@ static void init(void* _userdata)
|
|||||||
{
|
{
|
||||||
userdata_t* ud = (userdata_t*) _userdata;
|
userdata_t* ud = (userdata_t*) _userdata;
|
||||||
|
|
||||||
rand_seed(&ud->rand_ctx, 1);
|
sg_setup(&(sg_desc){
|
||||||
|
|
||||||
ud->panel_log_ctx.fn = panel_log_impl;
|
|
||||||
ud->panel_log_ctx.ud = ud;
|
|
||||||
|
|
||||||
sg_desc sgdesc = {
|
|
||||||
.environment = sglue_environment(),
|
.environment = sglue_environment(),
|
||||||
.logger.func = log_capture,
|
.logger.func = log_fn,
|
||||||
.logger.user_data = ud,
|
.allocator = {
|
||||||
.uniform_buffer_size = 16 * 1024 * 1024,
|
.alloc_fn = _malloc,
|
||||||
};
|
.free_fn = _free,
|
||||||
sg_setup(&sgdesc);
|
},
|
||||||
if (!sg_isvalid()) {
|
});
|
||||||
fprintf(stderr, "Failed to create Sokol GFX context!\n");
|
simgui_setup(&(simgui_desc_t){
|
||||||
exit(-1);
|
.allocator = {
|
||||||
|
.alloc_fn = _malloc,
|
||||||
|
.free_fn = _free,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
ud->scene = (scene_t) {0};
|
||||||
|
if(!scene_init(&ud->scene, (vec2) { 8192.0f, 8192.0f })) 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 = {
|
||||||
|
[COMPUTE_VIEWIDX_segments] = {
|
||||||
|
.storage_buffer = {
|
||||||
|
.stage = SG_SHADERSTAGE_COMPUTE,
|
||||||
|
.wgsl_group1_binding_n = COMPUTE_VIEWIDX_segments,
|
||||||
|
.readonly = true,
|
||||||
}
|
}
|
||||||
simgui_setup(&(simgui_desc_t){0});
|
},
|
||||||
|
[COMPUTE_VIEWIDX_shapes] = {
|
||||||
|
.storage_buffer = {
|
||||||
|
.stage = SG_SHADERSTAGE_COMPUTE,
|
||||||
|
.wgsl_group1_binding_n = COMPUTE_VIEWIDX_shapes,
|
||||||
|
.readonly = true,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[COMPUTE_VIEWIDX_circles] = {
|
||||||
|
.storage_buffer = {
|
||||||
|
.stage = SG_SHADERSTAGE_COMPUTE,
|
||||||
|
.wgsl_group1_binding_n = COMPUTE_VIEWIDX_circles,
|
||||||
|
.readonly = true,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[COMPUTE_VIEWIDX_tiles] = {
|
||||||
|
.storage_buffer = {
|
||||||
|
.stage = SG_SHADERSTAGE_COMPUTE,
|
||||||
|
.wgsl_group1_binding_n = COMPUTE_VIEWIDX_tiles,
|
||||||
|
.readonly = true,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[COMPUTE_VIEWIDX_indices] = {
|
||||||
|
.storage_buffer = {
|
||||||
|
.stage = SG_SHADERSTAGE_COMPUTE,
|
||||||
|
.wgsl_group1_binding_n = COMPUTE_VIEWIDX_indices,
|
||||||
|
.readonly = true,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[COMPUTE_VIEWIDX_SDF] = {
|
||||||
|
.storage_image = {
|
||||||
|
.stage = SG_SHADERSTAGE_COMPUTE,
|
||||||
|
.wgsl_group1_binding_n = COMPUTE_VIEWIDX_SDF,
|
||||||
|
.access_format = SG_PIXELFORMAT_R16F,
|
||||||
|
.image_type = SG_IMAGETYPE_2D,
|
||||||
|
.writeonly = true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
.label = "SDF Compute Shader",
|
||||||
|
}),
|
||||||
|
.label = "SDF Compute Pipeline",
|
||||||
|
}),
|
||||||
|
.bindings = (sg_bindings) {
|
||||||
|
.views[COMPUTE_VIEWIDX_segments] = 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) * INITIAL_SEGMENTS_SIZE,
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
.views[COMPUTE_VIEWIDX_shapes] = 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) * INITIAL_SHAPE_SIZE,
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
.views[COMPUTE_VIEWIDX_circles] = sg_make_view(&(sg_view_desc) {
|
||||||
|
.label = "Circles view",
|
||||||
|
.storage_buffer = {
|
||||||
|
.buffer = sg_make_buffer(&(sg_buffer_desc) {
|
||||||
|
.label = "Circles buffer",
|
||||||
|
.usage = {
|
||||||
|
.storage_buffer = true,
|
||||||
|
.stream_update = true,
|
||||||
|
},
|
||||||
|
.size = sizeof(circle_t) * INITIAL_CIRCLE_SIZE,
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
.views[COMPUTE_VIEWIDX_tiles] = sg_make_view(&(sg_view_desc) {
|
||||||
|
.label = "Tiles rebuild view",
|
||||||
|
.storage_buffer = {
|
||||||
|
.buffer = sg_make_buffer(&(sg_buffer_desc) {
|
||||||
|
.label = "Tiles rebuild buffer",
|
||||||
|
.usage = {
|
||||||
|
.storage_buffer = true,
|
||||||
|
.stream_update = true,
|
||||||
|
},
|
||||||
|
.size = sizeof(tile_task_t) * 256,
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
.views[COMPUTE_VIEWIDX_indices] = sg_make_view(&(sg_view_desc) {
|
||||||
|
.label = "Culling indices view",
|
||||||
|
.storage_buffer = {
|
||||||
|
.buffer = sg_make_buffer(&(sg_buffer_desc) {
|
||||||
|
.label = "Culling indices buffer",
|
||||||
|
.usage = {
|
||||||
|
.storage_buffer = true,
|
||||||
|
.stream_update = true,
|
||||||
|
},
|
||||||
|
.size = sizeof(uint32_t) * INITIAL_INDICES_SIZE,
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
.views[COMPUTE_VIEWIDX_SDF] = ud->scene.texture,
|
||||||
|
},
|
||||||
|
.pass = { .compute = true, .label = "Compute Pass" }
|
||||||
|
};
|
||||||
|
|
||||||
const vec2 quad[4] = {
|
const vec2 quad[4] = {
|
||||||
{-2.0f, 2.0f},
|
{ 0.0f, 1.0f }, // bottom left
|
||||||
{2.0f, 2.0f},
|
{ 1.0f, 1.0f }, // bottom right
|
||||||
{2.0f, -2.0f},
|
{ 1.0f, 0.0f }, // top right
|
||||||
{-2.0f, -2.0f},
|
{ 0.0f, 0.0f }, // top left
|
||||||
};
|
|
||||||
const vec2 uv[4] = {
|
|
||||||
{0.0f, 1.0f},
|
|
||||||
{1.0f, 1.0f},
|
|
||||||
{1.0f, 0.0f},
|
|
||||||
{0.0f, 0.0f},
|
|
||||||
};
|
};
|
||||||
const uint16_t indices[] = {
|
const uint16_t indices[] = {
|
||||||
0, 1, 2, 0, 2, 3,
|
0, 1, 2, 0, 2, 3,
|
||||||
};
|
};
|
||||||
|
|
||||||
ud->camera.width = sapp_width();
|
ud->renderer = (renderer_t) {
|
||||||
ud->camera.height = sapp_height();
|
.pipeline = sg_make_pipeline(&(sg_pipeline_desc) {
|
||||||
ud->camera.half_width = ud->camera.width * 0.5f;
|
.shader = sg_make_shader(&(sg_shader_desc) {
|
||||||
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) {
|
|
||||||
.vertex_func = {
|
.vertex_func = {
|
||||||
.source = (const char*) src_shaders_sprite_wgsl,
|
.source = (const char*) src_shaders_display_wgsl,
|
||||||
.entry = "vs_main",
|
.entry = "vs_main",
|
||||||
},
|
},
|
||||||
.fragment_func = {
|
.fragment_func = {
|
||||||
.source = (const char*) src_shaders_sprite_wgsl,
|
.source = (const char*) src_shaders_display_wgsl,
|
||||||
.entry = "fs_main",
|
.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,
|
|
||||||
}
|
|
||||||
},
|
|
||||||
.texture_sampler_pairs = {
|
|
||||||
[0] = {
|
|
||||||
.stage = SG_SHADERSTAGE_FRAGMENT,
|
|
||||||
.view_slot = 0,
|
|
||||||
.sampler_slot = 0,
|
|
||||||
}
|
|
||||||
},
|
|
||||||
.uniform_blocks = {
|
|
||||||
[0] = {
|
|
||||||
.size = sizeof(uniform_t),
|
|
||||||
.stage = SG_SHADERSTAGE_VERTEX,
|
|
||||||
.wgsl_group0_binding_n = 0,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
.attrs[0] = {
|
.attrs[0] = {
|
||||||
.base_type = SG_SHADERATTRBASETYPE_FLOAT,
|
.base_type = SG_SHADERATTRBASETYPE_FLOAT,
|
||||||
},
|
},
|
||||||
.label = "Sprite shader",
|
.views = {
|
||||||
});
|
[DISPLAY_VIEWIDX_SDF] = {
|
||||||
|
.texture = {
|
||||||
ud->renderer.clear_pass = (sg_pass_action) {
|
.image_type = SG_IMAGETYPE_2D,
|
||||||
.colors[0] = { .clear_value = { 0.0f, 0.0f, 0.0f, 1.0f }, .load_action = SG_LOADACTION_CLEAR }
|
.stage = SG_SHADERSTAGE_FRAGMENT,
|
||||||
};
|
.wgsl_group1_binding_n = DISPLAY_VIEWIDX_SDF,
|
||||||
ud->renderer.pipeline = sg_make_pipeline(&(sg_pipeline_desc) {
|
.sample_type = SG_IMAGESAMPLETYPE_FLOAT,
|
||||||
.shader = ud->renderer.shader,
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
.uniform_blocks = {
|
||||||
|
[0] = {
|
||||||
|
.size = sizeof(display_uniforms),
|
||||||
|
.stage = SG_SHADERSTAGE_VERTEX,
|
||||||
|
.wgsl_group0_binding_n = 0,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
.label = "Display Shader",
|
||||||
|
.samplers[DISPLAY_VIEWIDX_Sampler] = {
|
||||||
|
.sampler_type = SG_SAMPLERTYPE_FILTERING,
|
||||||
|
.stage = SG_SHADERSTAGE_FRAGMENT,
|
||||||
|
.wgsl_group1_binding_n = DISPLAY_VIEWIDX_Sampler,
|
||||||
|
},
|
||||||
|
.texture_sampler_pairs[0] = {
|
||||||
|
.sampler_slot = DISPLAY_VIEWIDX_Sampler,
|
||||||
|
.view_slot = DISPLAY_VIEWIDX_SDF,
|
||||||
|
.stage = SG_SHADERSTAGE_FRAGMENT,
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
.cull_mode = SG_CULLMODE_NONE,
|
||||||
.index_type = SG_INDEXTYPE_UINT16,
|
.index_type = SG_INDEXTYPE_UINT16,
|
||||||
.layout.attrs = {
|
.layout.attrs = {
|
||||||
[0].format = SG_VERTEXFORMAT_FLOAT2,
|
[0].format = SG_VERTEXFORMAT_FLOAT2,
|
||||||
[1].format = SG_VERTEXFORMAT_FLOAT2,
|
|
||||||
},
|
},
|
||||||
.label = "Sprite pipeline",
|
.label = "Render pipeline",
|
||||||
});
|
}),
|
||||||
ud->renderer.uniform = (uniform_t) {
|
.bindings = {
|
||||||
.mvp = {
|
.index_buffer = sg_make_buffer(&(sg_buffer_desc) {
|
||||||
1.0f, 0.0f, 0.0f, 0.0f,
|
.label = "Index buffer",
|
||||||
0.0f, 1.0f, 0.0f, 0.0f,
|
.usage.index_buffer = true,
|
||||||
0.0f, 0.0f, 1.0f, 0.0f,
|
.size = sizeof(indices),
|
||||||
0.0f, 0.0f, 0.0f, 1.0f
|
.data = SG_RANGE(indices),
|
||||||
|
}),
|
||||||
|
.vertex_buffers = {
|
||||||
|
[0] = sg_make_buffer(&(sg_buffer_desc) {
|
||||||
|
.label = "Vertex buffer",
|
||||||
|
.usage.vertex_buffer = true,
|
||||||
|
.size = sizeof(quad),
|
||||||
|
.data = SG_RANGE(quad),
|
||||||
|
})
|
||||||
|
},
|
||||||
|
.views = {
|
||||||
|
[DISPLAY_VIEWIDX_SDF] = sg_make_view(&(sg_view_desc) {
|
||||||
|
.texture.image = sg_query_view_image(ud->scene.texture),
|
||||||
|
.label = "SDF texture view",
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
.samplers = {
|
||||||
|
[DISPLAY_VIEWIDX_Sampler] = sg_make_sampler(&(sg_sampler_desc) {
|
||||||
|
.label = "SDF sampler",
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
},
|
||||||
|
.uniforms = {
|
||||||
|
.frame = 0,
|
||||||
|
.time = 0,
|
||||||
|
.mvp = { 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0 },
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
compute_mvp(ud);
|
||||||
|
|
||||||
shape_init_pipeline(&ud->pipelines, &ud->panel_log_ctx);
|
pass.action = (sg_pass_action) {
|
||||||
|
.colors[0] = { .clear_value = { 0.0f, 0.0f, 0.0f, 1.0f }, .load_action = SG_LOADACTION_CLEAR }
|
||||||
|
};
|
||||||
|
|
||||||
vec_init(&ud->shapes, sizeof(shape_t));
|
add_rectangle(&ud->scene, (vec2) { 200.0f, 100.0f }, (vec2) { 100.0f, 150.0f });
|
||||||
vec_init(&ud->groups, sizeof(group_t));
|
add_circle(&ud->scene, (vec2) { 400.0f, 300.0f }, 125.0f);
|
||||||
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)
|
static void cleanup(void* _userdata)
|
||||||
{
|
{
|
||||||
userdata_t* ud = (userdata_t*) _userdata;
|
userdata_t* ud = (userdata_t*) _userdata;
|
||||||
|
|
||||||
for (int i = 0; i < ud->shapes.count; i++) {
|
scene_shutdown(&ud->scene);
|
||||||
shape_shutdown(&ud->shape_pool, (shape_t*) vec_get(&ud->shapes, i));
|
emmalloc_free(ud);
|
||||||
}
|
|
||||||
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);
|
|
||||||
|
|
||||||
simgui_shutdown();
|
simgui_shutdown();
|
||||||
sg_shutdown();
|
sg_shutdown();
|
||||||
@@ -457,17 +435,17 @@ static void event(const sapp_event* event, void* _userdata)
|
|||||||
userdata_t* ud = (userdata_t*) _userdata;
|
userdata_t* ud = (userdata_t*) _userdata;
|
||||||
|
|
||||||
if (event->type == SAPP_EVENTTYPE_RESIZED) {
|
if (event->type == SAPP_EVENTTYPE_RESIZED) {
|
||||||
handle_resize(ud, event);
|
//handle_resize(ud, event);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (event->type == SAPP_EVENTTYPE_KEY_DOWN) {
|
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;
|
if (simgui_handle_event(event)) return;
|
||||||
|
|
||||||
switch (event->type) {
|
switch (event->type) {
|
||||||
case SAPP_EVENTTYPE_MOUSE_DOWN:
|
/* case SAPP_EVENTTYPE_MOUSE_DOWN:
|
||||||
handle_mouse_down(ud, event);
|
handle_mouse_down(ud, event);
|
||||||
break;
|
break;
|
||||||
case SAPP_EVENTTYPE_MOUSE_UP:
|
case SAPP_EVENTTYPE_MOUSE_UP:
|
||||||
@@ -478,7 +456,7 @@ static void event(const sapp_event* event, void* _userdata)
|
|||||||
break;
|
break;
|
||||||
case SAPP_EVENTTYPE_MOUSE_SCROLL:
|
case SAPP_EVENTTYPE_MOUSE_SCROLL:
|
||||||
handle_scroll_zoom(ud, event);
|
handle_scroll_zoom(ud, event);
|
||||||
break;
|
break; */
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -486,7 +464,7 @@ static void event(const sapp_event* event, void* _userdata)
|
|||||||
|
|
||||||
sapp_desc sokol_main(int argc, char* argv[])
|
sapp_desc sokol_main(int argc, char* argv[])
|
||||||
{
|
{
|
||||||
userdata_t* userdata = (userdata_t*) ALLOC(sizeof(userdata_t));
|
userdata_t* userdata = (userdata_t*) emmalloc_malloc(sizeof(userdata_t));
|
||||||
|
|
||||||
(void)argc;
|
(void)argc;
|
||||||
(void)argv;
|
(void)argv;
|
||||||
@@ -497,10 +475,10 @@ sapp_desc sokol_main(int argc, char* argv[])
|
|||||||
.cleanup_userdata_cb = cleanup,
|
.cleanup_userdata_cb = cleanup,
|
||||||
.event_userdata_cb = event,
|
.event_userdata_cb = event,
|
||||||
.window_title = "Sokol",
|
.window_title = "Sokol",
|
||||||
.logger.func = slog_func,
|
|
||||||
.allocator = {
|
.allocator = {
|
||||||
.alloc_fn = smemtrack_alloc,
|
.alloc_fn = _malloc,
|
||||||
.free_fn = smemtrack_free,
|
.free_fn = _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
|
|
||||||
36
src/pool.h
Normal file
36
src/pool.h
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
#include "api.h"
|
||||||
|
|
||||||
|
#define MAX_BUFFER_SIZE 1024 * 1024 * 1024 // 1GB
|
||||||
|
|
||||||
|
static void pool_buffer_grow(sg_buffer buffer, uint32_t stripe, uint32_t count, void* data)
|
||||||
|
{
|
||||||
|
size_t size = sg_query_buffer_size(buffer);
|
||||||
|
if(size == MAX_BUFFER_SIZE) return sg_update_buffer(buffer, &(sg_range) { data, MAX_BUFFER_SIZE });
|
||||||
|
if(size < stripe * count)
|
||||||
|
{
|
||||||
|
sg_buffer_desc desc = sg_query_buffer_desc(buffer);
|
||||||
|
while(desc.size < stripe * count) desc.size = fmaxf(MAX_BUFFER_SIZE, size * 2);
|
||||||
|
|
||||||
|
sg_uninit_buffer(buffer);
|
||||||
|
sg_init_buffer(buffer, &desc);
|
||||||
|
}
|
||||||
|
|
||||||
|
sg_update_buffer(buffer, &(sg_range) { data, stripe * count });
|
||||||
|
}
|
||||||
|
static void pool_view_grow(sg_view view, uint32_t stripe, uint32_t count, void* data)
|
||||||
|
{
|
||||||
|
sg_buffer buffer = sg_query_view_buffer(view);
|
||||||
|
|
||||||
|
size_t size = sg_query_buffer_size(buffer);
|
||||||
|
if(size == MAX_BUFFER_SIZE) return sg_update_buffer(buffer, &(sg_range) { data, MAX_BUFFER_SIZE });
|
||||||
|
if(size < stripe * count)
|
||||||
|
{
|
||||||
|
sg_buffer_desc desc = sg_query_buffer_desc(buffer);
|
||||||
|
while(desc.size < stripe * count) desc.size = fmaxf(MAX_BUFFER_SIZE, size * 2);
|
||||||
|
|
||||||
|
sg_uninit_buffer(buffer);
|
||||||
|
sg_init_buffer(buffer, &desc);
|
||||||
|
}
|
||||||
|
|
||||||
|
sg_update_buffer(buffer, &(sg_range) { data, stripe * count });
|
||||||
|
}
|
||||||
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
|
|
||||||
235
src/shaders/compute.wgsl
Normal file
235
src/shaders/compute.wgsl
Normal file
@@ -0,0 +1,235 @@
|
|||||||
|
struct Segment {
|
||||||
|
p0: vec2f,
|
||||||
|
p1: vec2f,
|
||||||
|
p2: vec2f,
|
||||||
|
p3: vec2f,
|
||||||
|
}
|
||||||
|
struct ShapeMeta {
|
||||||
|
start_segment: u32, //Offset in the segments buffer
|
||||||
|
segment_count: u32,
|
||||||
|
bbox_min: vec2f,
|
||||||
|
bbox_max: vec2f,
|
||||||
|
}
|
||||||
|
struct Circle {
|
||||||
|
center: vec2f,
|
||||||
|
radius: f32,
|
||||||
|
}
|
||||||
|
struct Tile {
|
||||||
|
world_min: vec2f,
|
||||||
|
world_max: vec2f,
|
||||||
|
offset: u32,
|
||||||
|
circle_count: u32,
|
||||||
|
count: u32,
|
||||||
|
};
|
||||||
|
|
||||||
|
@group(1) @binding(0) var<storage> segments: array<Segment>;
|
||||||
|
@group(1) @binding(1) var<storage> shapes: array<ShapeMeta>;
|
||||||
|
@group(1) @binding(2) var<storage> circles: array<Circle>;
|
||||||
|
@group(1) @binding(3) var<storage> tiles: array<Tile>;
|
||||||
|
@group(1) @binding(4) var<storage> indices: array<u32>;
|
||||||
|
@group(1) @binding(5) var sdf_buffer: texture_storage_2d<r16float, write>;
|
||||||
|
|
||||||
|
override TILE_SIZE: u32 = 256u;
|
||||||
|
|
||||||
|
// ---------- 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(workgroup_id) wg: vec3<u32>, // each workgroup is a tile
|
||||||
|
@builtin(local_invocation_id) local: vec3<u32>) // each local invocation is a pixel
|
||||||
|
{
|
||||||
|
let tile_idx = wg.x / 16u;
|
||||||
|
let tile = tiles[tile_idx];
|
||||||
|
|
||||||
|
let px = (wg.x % 16u) * 8u + local.x;
|
||||||
|
let py = wg.y * 8u + local.y;
|
||||||
|
|
||||||
|
if (px >= TILE_SIZE || py >= TILE_SIZE) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let uv = (vec2f(f32(px), f32(py)) + 0.5) / f32(TILE_SIZE);
|
||||||
|
let world = mix(tile.world_min, tile.world_max, uv);
|
||||||
|
|
||||||
|
var minDist: f32 = 1e20;
|
||||||
|
var sdf: f32 = 1e20;
|
||||||
|
var winding: i32 = 0;
|
||||||
|
|
||||||
|
for (var s = 0u; s < tile.count; s++) {
|
||||||
|
// Use a pre-culled shape range per tile to reduce the per-pixel processing time
|
||||||
|
let index = indices[tile.offset + s];
|
||||||
|
|
||||||
|
// If the index is lower than the circle count, it mean we are processing circles
|
||||||
|
if(index < tile.circle_count)
|
||||||
|
{
|
||||||
|
let c = circles[index];
|
||||||
|
sdf = min(sdf, length(world - c.center) - c.radius);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
let shape = shapes[index];
|
||||||
|
|
||||||
|
/*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;
|
||||||
|
}*/
|
||||||
|
|
||||||
|
// 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);
|
||||||
|
sdf = min(sdf, sign * minDist);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
textureStore(sdf_buffer, vec2(u32(world.x), u32(world.y)), vec4f(sdf, 0.0, 0.0, 1.0));
|
||||||
|
}
|
||||||
20
src/shaders/display.wgsl
Normal file
20
src/shaders/display.wgsl
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
struct Uniforms {
|
||||||
|
time: u32,
|
||||||
|
frame: u32,
|
||||||
|
mvp: mat4x4f,
|
||||||
|
}
|
||||||
|
|
||||||
|
@group(0) @binding(0) var<uniform> uniforms: Uniforms;
|
||||||
|
|
||||||
|
@group(1) @binding(0) var sdf : texture_2d<f32>;
|
||||||
|
@group(1) @binding(1) var sdf_sampler : sampler;
|
||||||
|
|
||||||
|
@vertex fn vs_main(@location(0) position: vec2f) -> @builtin(position) vec4f
|
||||||
|
{
|
||||||
|
return vec4f(position, 0.0, 1.0) * uniforms.mvp;
|
||||||
|
}
|
||||||
|
|
||||||
|
@fragment fn fs_main(@builtin(position) position: vec4f) -> @location(0) vec4f
|
||||||
|
{
|
||||||
|
return textureSample(sdf, sdf_sampler, position.xy);
|
||||||
|
}
|
||||||
@@ -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;
|
|
||||||
}
|
|
||||||
1267
src/shape.h
1267
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