You've already forked flecs_tests
Add a geometry pool, shape hierarchy, addittion and deletion.
This commit is contained in:
144
src/interact.h
Normal file
144
src/interact.h
Normal 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
|
||||
Reference in New Issue
Block a user