quakeforge/libs/scene/test/test-components.c
Bill Currie 06ccc3023b [scene] Start work on a full-on ECS system
That does feel a little redundant, but I think the System in ECS is
referring to the systems that run on the components, while the other
system is the support code for the ECS. Anyway...

This is based heavily on the information provided by @skipjack in his
github blog about EnTT. Currently, entity recycling and sparse arrays
for component pools have been implemented, and adding components to an
entity has been tested.
2022-10-16 18:29:25 +09:00

133 lines
3 KiB
C

#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include "QF/simd/types.h"
#include "QF/mathlib.h"
#include "QF/scene/component.h"
enum test_components {
test_position,
test_scale,
test_rotation,
test_num_components
};
static void
create_position (void *data)
{
vec4f_t *pos = data;
*pos = (vec4f_t) { 0, 0, 0, 1 };
}
static void
create_scale (void *data)
{
vec_t *scale = data;
VectorSet (1, 1, 1, scale);
}
static void
create_rotation (void *data)
{
vec4f_t *rot = data;
*rot = (vec4f_t) { 0, 0, 0, 1 };
}
static const component_t test_components[] = {
[test_position] = {
.size = sizeof (vec4f_t),
.create = create_position,
.name = "position",
},
[test_scale] = {
.size = sizeof (vec3_t),
.create = create_scale,
.name = "scale",
},
[test_rotation] = {
.size = sizeof (vec4f_t),
.create = create_rotation,
.name = "rotation",
},
};
static int
check_ent_components (const uint32_t *ents, uint32_t count, uint32_t comp,
ecs_registry_t *reg)
{
ecs_pool_t *pool = &reg->comp_pools[comp];
const component_t *component = &reg->components[comp];
if (pool->count != count) {
printf ("%s pool has wrong object count: %d %d\n", component->name,
pool->count, count);
return 0;
}
uint32_t num_entities = 0;
for (uint32_t i = 0; i < reg->max_entities; i++) {
if (pool->sparse[i] == ~0u) {
continue;
}
if (pool->sparse[i] < pool->count) {
num_entities++;
continue;
}
printf ("invalid index in sparse array of %s: %d %d\n", component->name,
pool->sparse[i], pool->count);
return 0;
}
if (num_entities != count) {
printf ("%s sparse has wrong entity count: %d %d\n", component->name,
num_entities, count);
return 0;
}
for (uint32_t i = 0; i < count; i++) {
if (pool->sparse[Ent_Index (ents[i])] == ~0u) {
printf ("ent not in %s sparse: %x\n", component->name, ents[i]);
return 0;
}
if (pool->dense[pool->sparse[Ent_Index (ents[i])]] != ents[i]) {
printf ("indexed %s dense does have ent: %x %x\n", component->name,
pool->dense[pool->sparse[Ent_Index (ents[i])]], ents[i]);
return 0;
}
}
return 1;
}
int
main (void)
{
ecs_registry_t *reg = ECS_NewRegistry ();
ECS_RegisterComponents (reg, test_components, test_num_components);
uint32_t enta = ECS_NewEntity (reg);
uint32_t entb = ECS_NewEntity (reg);
uint32_t entc = ECS_NewEntity (reg);
Ent_AddComponent (enta, test_position, reg);
Ent_AddComponent (entb, test_position, reg);
Ent_AddComponent (entc, test_position, reg);
Ent_AddComponent (enta, test_rotation, reg);
Ent_AddComponent (entb, test_rotation, reg);
Ent_AddComponent (enta, test_scale, reg);
if (!check_ent_components ((uint32_t[]){enta, entb, entc}, 3,
test_position, reg)) {
return 1;
}
if (!check_ent_components ((uint32_t[]){enta, entb}, 2,
test_rotation, reg)) {
return 1;
}
if (!check_ent_components ((uint32_t[]){enta}, 1, test_scale, reg)) {
return 1;
}
ECS_DelRegistry (reg);
return 0;
}