Add a geometry pool, shape hierarchy, addittion and deletion.

This commit is contained in:
2026-04-30 17:55:46 +02:00
parent 9ce6e4accd
commit e71641c094
14 changed files with 2273 additions and 1341 deletions

144
src/interact.h Normal file
View File

@@ -0,0 +1,144 @@
#ifndef INTERACT_H
#define INTERACT_H
#include "api.h"
#include "types.h"
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 sc = cosf(s->rotation), ss = sinf(s->rotation);
for (uint32_t v = 0; v < s->num_verts; v++) {
float lx = s->verts[v].x * s->sx;
float ly = s->verts[v].y * s->sy;
float wx = s->cx + lx * sc - ly * ss;
float wy = s->cy + lx * ss + ly * sc;
if (first) { *min_x = *max_x = wx; *min_y = *max_y = wy; first = false; }
else {
if (wx < *min_x) *min_x = wx;
if (wx > *max_x) *max_x = wx;
if (wy < *min_y) *min_y = wy;
if (wy > *max_y) *max_y = wy;
}
}
}
}
static void update_shape_states(userdata_t *ud)
{
for (int i = 0; i < ud->shapes.count; i++) {
shape_t *s = (shape_t*) vec_get(&ud->shapes, i);
shape_set_state(s, s->hovered, s->selected);
}
}
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(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(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(s->group_id, gid, &ud->groups)) {
s->selected = !all_sel;
ud->interact.selected_count += s->selected ? 1 : -1;
}
}
}
static void rebuild_groups_from_shapes(vector_t *groups, vector_t *shapes)
{
// Save existing parent relationships so nested groups survive rebuild
int old_count = groups->count;
int *saved = NULL;
if (old_count > 0) {
saved = (int*) ALLOC((size_t)old_count * 2 * sizeof(int));
for (int i = 0; i < old_count; i++) {
group_t *g = (group_t*) vec_get(groups, i);
saved[i * 2] = g->id;
saved[i * 2 + 1] = g->parent_id;
}
}
groups->count = 0;
for (int i = 0; i < shapes->count; i++) {
shape_t *s = (shape_t*) vec_get(shapes, i);
if (s->group_id == 0) continue;
bool found = false;
for (int g = 0; g < groups->count; g++) {
if (((group_t*) vec_get(groups, g))->id == s->group_id) { found = true; break; }
}
if (!found) {
group_t grp = { .id = s->group_id, .parent_id = 0 };
*((group_t*) vec_push(groups)) = grp;
}
}
// Restore parent relationships for groups that still exist
for (int i = 0; i < old_count; i++) {
int gid = saved[i * 2];
int pid = saved[i * 2 + 1];
if (pid == 0) continue;
group_t *g = find_group(groups, gid);
if (g) {
// Only restore if parent group still exists
if (find_group(groups, pid))
g->parent_id = pid;
}
}
if (saved) FREE(saved);
}
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