You've already forked flecs_tests
Add a geometry pool, shape hierarchy, addittion and deletion.
This commit is contained in:
184
src/shape.h
184
src/shape.h
@@ -7,9 +7,15 @@ typedef struct shape_vertex_t {
|
||||
float x, y;
|
||||
} shape_vertex_t;
|
||||
|
||||
typedef enum {
|
||||
SHAPE_CIRCLE,
|
||||
SHAPE_RECTANGLE,
|
||||
SHAPE_STAR,
|
||||
SHAPE_GENERIC,
|
||||
} shape_kind_t;
|
||||
|
||||
typedef struct shape_uniform_t {
|
||||
mat4 transform;
|
||||
float base_color[4];
|
||||
uint32_t state;
|
||||
uint8_t _pad[12];
|
||||
} shape_uniform_t;
|
||||
@@ -17,10 +23,8 @@ typedef struct shape_uniform_t {
|
||||
typedef struct shape_t {
|
||||
shape_vertex_t *verts;
|
||||
uint16_t *indices;
|
||||
uint32_t num_indices;
|
||||
uint32_t num_elements;
|
||||
uint32_t num_verts;
|
||||
sg_buffer vbuf;
|
||||
sg_buffer ibuf;
|
||||
shape_uniform_t uniform;
|
||||
bool hovered;
|
||||
bool selected;
|
||||
@@ -28,8 +32,119 @@ typedef struct shape_t {
|
||||
float cx, cy;
|
||||
float sx, sy;
|
||||
float rotation;
|
||||
int kind;
|
||||
|
||||
uint32_t vertex_base;
|
||||
uint32_t index_base;
|
||||
|
||||
int group_id;
|
||||
} shape_t;
|
||||
|
||||
// -- group entity (for nested groups) --
|
||||
|
||||
typedef struct {
|
||||
int id;
|
||||
int parent_id; // 0 = top-level group
|
||||
} group_t;
|
||||
|
||||
static group_t* find_group(vector_t *groups, int id) {
|
||||
for (int i = 0; i < groups->count; i++) {
|
||||
group_t *g = (group_t*) vec_get(groups, i);
|
||||
if (g->id == id) return g;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int get_topmost_group(vector_t *groups, int gid) {
|
||||
while (gid != 0) {
|
||||
group_t *g = find_group(groups, gid);
|
||||
if (!g || g->parent_id == 0) return gid;
|
||||
gid = g->parent_id;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool is_shape_in_group_hierarchy(int shape_gid, int target_gid, vector_t *groups) {
|
||||
int cur = shape_gid;
|
||||
while (cur != 0) {
|
||||
if (cur == target_gid) return true;
|
||||
group_t *g = find_group(groups, cur);
|
||||
if (!g) return false;
|
||||
cur = g->parent_id;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// -- shared geometry buffers (one vbuf + one ibuf for all shapes) --
|
||||
|
||||
static sg_buffer g_shape_vbuf = {0};
|
||||
static sg_buffer g_shape_ibuf = {0};
|
||||
static bool g_shape_pool_dirty;
|
||||
static uint32_t g_shape_vert_count;
|
||||
static uint32_t g_shape_idx_count;
|
||||
|
||||
static void shape_pool_rebuild(vector_t *shapes)
|
||||
{
|
||||
// count total vertices / indices (line strips: num_elements == num_verts + 1)
|
||||
uint32_t total_verts = 0, total_indices = 0;
|
||||
for (int i = 0; i < shapes->count; i++) {
|
||||
shape_t *s = (shape_t*) vec_get(shapes, i);
|
||||
total_verts += s->num_elements;
|
||||
total_indices += s->num_elements;
|
||||
}
|
||||
|
||||
if (g_shape_vbuf.id) { sg_destroy_buffer(g_shape_vbuf); g_shape_vbuf.id = 0; }
|
||||
if (g_shape_ibuf.id) { sg_destroy_buffer(g_shape_ibuf); g_shape_ibuf.id = 0; }
|
||||
g_shape_vert_count = 0;
|
||||
g_shape_idx_count = 0;
|
||||
|
||||
if (total_verts == 0) {
|
||||
g_shape_pool_dirty = false;
|
||||
return;
|
||||
}
|
||||
|
||||
shape_vertex_t *all_v = (shape_vertex_t*) ALLOC((size_t)total_verts * sizeof(shape_vertex_t));
|
||||
uint16_t *all_i = (uint16_t*) ALLOC((size_t)total_indices * sizeof(uint16_t));
|
||||
|
||||
uint32_t voff = 0, ioff = 0;
|
||||
for (int i = 0; i < shapes->count; i++) {
|
||||
shape_t *s = (shape_t*) vec_get(shapes, i);
|
||||
uint32_t n = s->num_elements;
|
||||
memcpy(&all_v[voff], s->verts, (size_t)n * sizeof(shape_vertex_t));
|
||||
for (uint32_t j = 0; j < n; j++)
|
||||
all_i[ioff + j] = (uint16_t)(voff + s->indices[j]);
|
||||
s->vertex_base = voff;
|
||||
s->index_base = ioff;
|
||||
voff += n;
|
||||
ioff += n;
|
||||
}
|
||||
|
||||
g_shape_vbuf = sg_make_buffer(&(sg_buffer_desc){
|
||||
.data = { all_v, (size_t)total_verts * sizeof(shape_vertex_t) },
|
||||
.label = "Shape verts (shared)",
|
||||
});
|
||||
g_shape_ibuf = sg_make_buffer(&(sg_buffer_desc){
|
||||
.data = { all_i, (size_t)total_indices * sizeof(uint16_t) },
|
||||
.usage = { .index_buffer = true },
|
||||
.label = "Shape indices (shared)",
|
||||
});
|
||||
|
||||
FREE(all_v);
|
||||
FREE(all_i);
|
||||
|
||||
g_shape_vert_count = total_verts;
|
||||
g_shape_idx_count = total_indices;
|
||||
g_shape_pool_dirty = false;
|
||||
}
|
||||
|
||||
static void shape_pool_shutdown(void)
|
||||
{
|
||||
if (g_shape_vbuf.id) { sg_destroy_buffer(g_shape_vbuf); g_shape_vbuf.id = 0; }
|
||||
if (g_shape_ibuf.id) { sg_destroy_buffer(g_shape_ibuf); g_shape_ibuf.id = 0; }
|
||||
g_shape_vert_count = 0;
|
||||
g_shape_idx_count = 0;
|
||||
}
|
||||
|
||||
#define SHAPE_HOVER_PX 6.0f
|
||||
|
||||
static int shape_calc_segments(float r)
|
||||
@@ -40,13 +155,13 @@ static int shape_calc_segments(float r)
|
||||
return n;
|
||||
}
|
||||
|
||||
static void shape_init_common(shape_t *s, const float color[4])
|
||||
static void shape_init_common(shape_t *s)
|
||||
{
|
||||
s->hovered = false;
|
||||
s->selected = false;
|
||||
memcpy(s->uniform.base_color, color, sizeof(float[4]));
|
||||
s->uniform.state = 0;
|
||||
memset(s->uniform._pad, 0, sizeof(s->uniform._pad));
|
||||
s->group_id = 0;
|
||||
}
|
||||
|
||||
static void shape_build_transform(shape_t *s)
|
||||
@@ -61,24 +176,13 @@ static void shape_build_transform(shape_t *s)
|
||||
|
||||
static void shape_make_buffers(shape_t *s)
|
||||
{
|
||||
uint32_t vcount = s->num_verts + 1;
|
||||
s->vbuf = sg_make_buffer(&(sg_buffer_desc) {
|
||||
.size = (size_t)vcount * sizeof(shape_vertex_t),
|
||||
.usage = { .stream_update = true },
|
||||
.label = "Shape vertices",
|
||||
});
|
||||
sg_update_buffer(s->vbuf, &(sg_range){s->verts, (size_t)vcount * sizeof(shape_vertex_t)});
|
||||
s->ibuf = sg_make_buffer(&(sg_buffer_desc) {
|
||||
.usage = { .index_buffer = true },
|
||||
.data = { s->indices, s->num_indices * sizeof(uint16_t) },
|
||||
.label = "Shape indices",
|
||||
});
|
||||
(void)s;
|
||||
g_shape_pool_dirty = true;
|
||||
}
|
||||
|
||||
static void shape_shutdown(shape_t *s)
|
||||
{
|
||||
sg_destroy_buffer(s->vbuf);
|
||||
sg_destroy_buffer(s->ibuf);
|
||||
g_shape_pool_dirty = true;
|
||||
FREE(s->verts);
|
||||
FREE(s->indices);
|
||||
}
|
||||
@@ -135,12 +239,13 @@ static bool shape_hit_test(shape_t *s, float wx, float wy, float world_tol)
|
||||
return false;
|
||||
}
|
||||
|
||||
static shape_t shape_circle(float x, float y, float r, const float color[4])
|
||||
static shape_t shape_circle(float x, float y, float r)
|
||||
{
|
||||
shape_t s;
|
||||
s.cx = x; s.cy = y;
|
||||
s.sx = r; s.sy = r;
|
||||
s.rotation = 0.0f;
|
||||
s.kind = SHAPE_CIRCLE;
|
||||
|
||||
int segs = shape_calc_segments(r);
|
||||
int count = segs + 1;
|
||||
@@ -153,22 +258,23 @@ static shape_t shape_circle(float x, float y, float r, const float color[4])
|
||||
}
|
||||
s.verts[segs] = s.verts[0];
|
||||
for (int i = 0; i <= segs; i++) s.indices[i] = (uint16_t)i;
|
||||
s.num_indices = (uint32_t)count;
|
||||
s.num_elements = (uint32_t)count;
|
||||
s.num_verts = (uint32_t)segs;
|
||||
|
||||
shape_init_common(&s, color);
|
||||
shape_init_common(&s);
|
||||
shape_build_transform(&s);
|
||||
shape_make_buffers(&s);
|
||||
return s;
|
||||
}
|
||||
|
||||
static shape_t shape_star(float x, float y, float outer_r, float inner_r,
|
||||
int points, const float color[4])
|
||||
int points)
|
||||
{
|
||||
shape_t s;
|
||||
s.cx = x; s.cy = y;
|
||||
s.sx = outer_r; s.sy = outer_r;
|
||||
s.rotation = 0.0f;
|
||||
s.kind = SHAPE_STAR;
|
||||
|
||||
int n = points * 2;
|
||||
int count = n + 1;
|
||||
@@ -183,10 +289,36 @@ static shape_t shape_star(float x, float y, float outer_r, float inner_r,
|
||||
}
|
||||
s.verts[n] = s.verts[0];
|
||||
for (int i = 0; i <= n; i++) s.indices[i] = (uint16_t)i;
|
||||
s.num_indices = (uint32_t)count;
|
||||
s.num_elements = (uint32_t)count;
|
||||
s.num_verts = (uint32_t)n;
|
||||
|
||||
shape_init_common(&s, color);
|
||||
shape_init_common(&s);
|
||||
shape_build_transform(&s);
|
||||
shape_make_buffers(&s);
|
||||
return s;
|
||||
}
|
||||
|
||||
static shape_t shape_rectangle(float x, float y, float w, float h)
|
||||
{
|
||||
shape_t s;
|
||||
s.cx = x; s.cy = y;
|
||||
s.sx = w * 0.5f; s.sy = h * 0.5f;
|
||||
s.rotation = 0.0f;
|
||||
s.kind = SHAPE_RECTANGLE;
|
||||
|
||||
s.num_verts = 4;
|
||||
s.num_elements = 5;
|
||||
s.verts = (shape_vertex_t*) ALLOC(5 * sizeof(shape_vertex_t));
|
||||
s.indices = (uint16_t*) ALLOC(5 * sizeof(uint16_t));
|
||||
|
||||
s.verts[0] = (shape_vertex_t){-1.0f, -1.0f};
|
||||
s.verts[1] = (shape_vertex_t){ 1.0f, -1.0f};
|
||||
s.verts[2] = (shape_vertex_t){ 1.0f, 1.0f};
|
||||
s.verts[3] = (shape_vertex_t){-1.0f, 1.0f};
|
||||
s.verts[4] = s.verts[0];
|
||||
for (int i = 0; i < 5; i++) s.indices[i] = (uint16_t)i;
|
||||
|
||||
shape_init_common(&s);
|
||||
shape_build_transform(&s);
|
||||
shape_make_buffers(&s);
|
||||
return s;
|
||||
|
||||
Reference in New Issue
Block a user