mirror of
https://git.code.sf.net/p/quake/quakeforge
synced 2025-02-24 12:42:32 +00:00
The main goal of this change was to make it easier to tell when a hierarchy has been deleted, but as a side benefit, it got rid of the use of PR_RESMAP. Also, it's easy to track the number of hierarchies. Unfortunately, it showed how brittle the component side of the ECS is (scene and canvas registries assumed their components were the first (no long the case), thus the sweeping changes). Centerprint doesn't work (but it hasn't for a while).
170 lines
4.4 KiB
C
170 lines
4.4 KiB
C
/*
|
|
ecs.h
|
|
|
|
Entity Component System
|
|
|
|
Copyright (C) 2022 Bill Currie <bill@taniwha.org>
|
|
|
|
Author: Bill Currie <bill@taniwha.org>
|
|
Date: 2022/10/07
|
|
|
|
This program is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU General Public License
|
|
as published by the Free Software Foundation; either version 2
|
|
of the License, or (at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
|
|
See the GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to:
|
|
|
|
Free Software Foundation, Inc.
|
|
59 Temple Place - Suite 330
|
|
Boston, MA 02111-1307, USA
|
|
|
|
*/
|
|
|
|
#ifndef __QF_ecs_h
|
|
#define __QF_ecs_h
|
|
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
|
|
#include "QF/darray.h"
|
|
#include "QF/qtypes.h"
|
|
|
|
#include "QF/ecs/component.h"
|
|
#include "QF/ecs/hierarchy.h"
|
|
|
|
/** \defgroup ecs Entity Component System
|
|
\ingroup utils
|
|
*/
|
|
///@{
|
|
|
|
#define ENT_GROW 1024
|
|
#define COMP_GROW 128
|
|
#define RANGE_GROW 32
|
|
#define ENT_IDBITS 20
|
|
#define nullent (~0u)
|
|
|
|
typedef struct ecs_pool_s {
|
|
uint32_t *sparse; // indexed by entity id, holds index to dense/data
|
|
uint32_t *dense; // holds entity id
|
|
void *data; // component data
|
|
uint32_t count; // number of components/dense entity ids
|
|
uint32_t max_count; // current capacity for components/entity ids
|
|
} ecs_pool_t;
|
|
|
|
typedef struct DARRAY_TYPE(component_t) componentset_t;
|
|
|
|
typedef struct ecs_range_s {
|
|
uint32_t start;
|
|
uint32_t end;
|
|
} ecs_range_t;
|
|
|
|
typedef struct ecs_subpool_s {
|
|
uint32_t *rangeids;
|
|
uint32_t *sorted;
|
|
uint32_t *ranges;
|
|
uint32_t next;
|
|
uint32_t available;
|
|
uint32_t num_ranges;
|
|
uint32_t max_ranges;
|
|
} ecs_subpool_t;
|
|
|
|
/// components that are available in every registry
|
|
enum {
|
|
ecs_name, ///< const char *
|
|
ecs_hierarchy, ///< hierarchy_t
|
|
|
|
ecs_comp_count
|
|
};
|
|
|
|
typedef struct ecs_registry_s {
|
|
const char *name;
|
|
ecs_pool_t *comp_pools;
|
|
uint32_t *entities;
|
|
ecs_subpool_t *subpools;
|
|
uint32_t next;
|
|
uint32_t available;
|
|
uint32_t num_entities;
|
|
uint32_t max_entities;
|
|
componentset_t components;
|
|
int locked;
|
|
} ecs_registry_t;
|
|
|
|
/** Tie an ECS system to a registry.
|
|
|
|
Keeps the registry using the system and the system's component base
|
|
together.
|
|
*/
|
|
typedef struct ecs_system_s {
|
|
ecs_registry_t *reg;
|
|
uint32_t base;
|
|
} ecs_system_t;
|
|
|
|
#include "QF/ecs/entity.h"
|
|
|
|
#define ECSINLINE GNU89INLINE inline
|
|
|
|
ecs_registry_t *ECS_NewRegistry (const char *name);
|
|
void ECS_DelRegistry (ecs_registry_t *registry);
|
|
uint32_t ECS_RegisterComponents (ecs_registry_t *registry,
|
|
const component_t *components,
|
|
uint32_t count);
|
|
void ECS_CreateComponentPools (ecs_registry_t *registry);
|
|
|
|
|
|
#ifndef __compar_d_fn_t_defined
|
|
#define __compar_d_fn_t_defined
|
|
typedef int (*__compar_d_fn_t)(const void *, const void *, void *);
|
|
#endif
|
|
void ECS_SortComponentPool (ecs_registry_t *registry, uint32_t component,
|
|
__compar_d_fn_t cmp, void *arg);
|
|
void ECS_SortComponentPoolRange (ecs_registry_t *registry, uint32_t component,
|
|
ecs_range_t range,
|
|
__compar_d_fn_t cmp, void *arg);
|
|
|
|
uint32_t ECS_NewEntity (ecs_registry_t *registry);
|
|
void ECS_DelEntity (ecs_registry_t *registry, uint32_t ent);
|
|
void ECS_RemoveEntities (ecs_registry_t *registry, uint32_t component);
|
|
void ECS_PrintEntity (ecs_registry_t *registry, uint32_t ent);
|
|
void ECS_PrintRegistry (ecs_registry_t *registry);
|
|
|
|
uint32_t ECS_NewSubpoolRange (ecs_registry_t *registry, uint32_t component);
|
|
void ECS_DelSubpoolRange (ecs_registry_t *registry, uint32_t component,
|
|
uint32_t id);
|
|
ECSINLINE ecs_range_t ECS_GetSubpoolRange (ecs_registry_t *registry,
|
|
uint32_t component, uint32_t id);
|
|
void ECS_MoveSubpoolLast (ecs_registry_t *registry, uint32_t component,
|
|
uint32_t id);
|
|
|
|
#undef ECSINLINE
|
|
#ifndef IMPLEMENT_ECS_Funcs
|
|
#define ECSINLINE GNU89INLINE inline
|
|
#else
|
|
#define ECSINLINE VISIBLE
|
|
#endif
|
|
|
|
ECSINLINE
|
|
ecs_range_t
|
|
ECS_GetSubpoolRange (ecs_registry_t *registry, uint32_t component, uint32_t id)
|
|
{
|
|
ecs_subpool_t *subpool = ®istry->subpools[component];
|
|
uint32_t ind = subpool->sorted[Ent_Index (id)];
|
|
ecs_range_t range = {
|
|
.start = ind ? subpool->ranges[ind - 1] : 0,
|
|
.end = subpool->ranges[ind],
|
|
};
|
|
return range;
|
|
}
|
|
|
|
#undef ECSINLINE
|
|
|
|
///@}
|
|
|
|
#endif//__QF_ecs_h
|