summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile10
-rw-r--r--configure.lua1
-rw-r--r--world.cpp204
-rw-r--r--world.hpp178
4 files changed, 389 insertions, 4 deletions
diff --git a/Makefile b/Makefile
index 5ff97e2..3392608 100644
--- a/Makefile
+++ b/Makefile
@@ -62,8 +62,10 @@ ui.o: ui.cpp
g++ -std=c++20 $(opt_com) $(cflags) -c ui.cpp -o ui.o
video.o: video.cpp
g++ -std=c++20 $(opt_com) $(cflags) -c video.cpp -o video.o
-c2: app.o asset.o c2.o camera.o debugdraw.o editor.o maths.o model.o pipeline.o ui.o video.o libqstd.a
- g++ $(opt_lnk) $(lflags) -o c2 app.o asset.o c2.o camera.o debugdraw.o editor.o maths.o model.o pipeline.o ui.o video.o libqstd.a -lX11 -lm
+world.o: world.cpp
+ g++ -std=c++20 $(opt_com) $(cflags) -c world.cpp -o world.o
+c2: app.o asset.o c2.o camera.o debugdraw.o editor.o maths.o model.o pipeline.o ui.o video.o world.o libqstd.a
+ g++ $(opt_lnk) $(lflags) -o c2 app.o asset.o c2.o camera.o debugdraw.o editor.o maths.o model.o pipeline.o ui.o video.o world.o libqstd.a -lX11 -lm
c2: pack
@@ -129,10 +131,10 @@ pack: packer data/debug.csh data/mip_spec.csh data/sky.csh data/surface.csh data
data:
mkdir -p data
--include qstd/memory.d qstd/plat.d qstd/str.d qstd/pack.d cfg/cfgparse.d sc/sc.d sc/includer.d app.d asset.d c2.d camera.d debugdraw.d editor.d maths.d model.d pipeline.d ui.d video.d convtexture.d convmodel.d convmaterial.d packer.d
+-include qstd/memory.d qstd/plat.d qstd/str.d qstd/pack.d cfg/cfgparse.d sc/sc.d sc/includer.d app.d asset.d c2.d camera.d debugdraw.d editor.d maths.d model.d pipeline.d ui.d video.d world.d convtexture.d convmodel.d convmaterial.d packer.d
clean:
- rm -f qstd/memory.o qstd/plat.o qstd/str.o qstd/pack.o cfg/cfgparse.o sc/sc.o sc/includer.o app.o asset.o c2.o camera.o debugdraw.o editor.o maths.o model.o pipeline.o ui.o video.o convtexture.o convmodel.o convmaterial.o packer.o qstd/memory.d qstd/plat.d qstd/str.d qstd/pack.d cfg/cfgparse.d sc/sc.d sc/includer.d app.d asset.d c2.d camera.d debugdraw.d editor.d maths.d model.d pipeline.d ui.d video.d convtexture.d convmodel.d convmaterial.d packer.d data/debug.csh data/mip_spec.csh data/sky.csh data/surface.csh data/surface_depthonly.csh data/triangle.csh data/ui.csh data/monkey.mdl data/22.tex data/kita.tex data/brick_albedo.tex data/brick_ao.tex data/brick_normal.tex data/sky.tex data/bricks.mat data/plastic.mat
+ rm -f qstd/memory.o qstd/plat.o qstd/str.o qstd/pack.o cfg/cfgparse.o sc/sc.o sc/includer.o app.o asset.o c2.o camera.o debugdraw.o editor.o maths.o model.o pipeline.o ui.o video.o world.o convtexture.o convmodel.o convmaterial.o packer.o qstd/memory.d qstd/plat.d qstd/str.d qstd/pack.d cfg/cfgparse.d sc/sc.d sc/includer.d app.d asset.d c2.d camera.d debugdraw.d editor.d maths.d model.d pipeline.d ui.d video.d world.d convtexture.d convmodel.d convmaterial.d packer.d data/debug.csh data/mip_spec.csh data/sky.csh data/surface.csh data/surface_depthonly.csh data/triangle.csh data/ui.csh data/monkey.mdl data/22.tex data/kita.tex data/brick_albedo.tex data/brick_ao.tex data/brick_normal.tex data/sky.tex data/bricks.mat data/plastic.mat
rm -f shadercompiler
rmdir data
rm -f c2
diff --git a/configure.lua b/configure.lua
index c716c33..7e1d5e1 100644
--- a/configure.lua
+++ b/configure.lua
@@ -11,6 +11,7 @@ config = {
"pipeline",
"ui",
"video",
+ "world",
},
qstd = {
"memory",
diff --git a/world.cpp b/world.cpp
new file mode 100644
index 0000000..5cfd8bf
--- /dev/null
+++ b/world.cpp
@@ -0,0 +1,204 @@
+#include "world.hpp"
+extern "C" {
+#include "memory.h"
+#include "plat.h"
+}
+
+#include <string.h>
+
+static int component_sizes[max_components];
+
+void Pool::init(Arena* a, Component_Mask m) {
+ int i, coff;
+ next = 0;
+ size = 0;
+ mask = m;
+ count = 0;
+ for (i = 0, coff = 0; i < max_components; i++) {
+ if (m & ((Component_Mask)1 << i)) {
+ offsets[i] = coff;
+ coff += component_sizes[i];
+ }
+ }
+ size = coff;
+ data = arena_alloc(a, size * pool_cap);
+}
+
+void* Pool::add(Arena* a, Entity_Id eid) {
+ int idx;
+ if (next)
+ return next->add(a, eid);
+ if (count >= pool_cap) {
+ next = (Pool*)arena_alloc(a, sizeof *next);
+ next->init(a, mask);
+ return next->add(a, eid);
+ }
+ idx = count++;
+ entities[idx] = eid;
+ mapping[entity_index(eid)] = idx;
+ return &((char*)data)[idx * size];
+}
+
+void Pool::remove(Entity_Id eid) {
+ int eind = entity_index(eid);
+ int end = count - 1;
+ assert(eid == entities[mapping[eind]]);
+ memmove(
+ (char*)data + eind * size,
+ (char*)data + end * size,
+ size
+ );
+ entities[eind] = entities[count];
+ mapping[end] = eind;
+ count = end;
+}
+
+void* Pool::get(Entity_Id eid, int cid) {
+ int eind = entity_index(eid);
+ char* e = &((char*)data)[mapping[eind] * size];
+ assert(eid == entities[mapping[eind]]);
+ return &e[offsets[cid]];
+}
+
+void* Pool::get(Entity_Id eid) {
+ int eind = entity_index(eid);
+ void* e = &((char*)data)[mapping[eind] * size];
+ assert(eid == entities[mapping[eind]]);
+ return e;
+}
+
+int get_new_component_id(int size) {
+ static int id = 0;
+ int i = id++;
+ component_sizes[i] = size;
+ return i;
+}
+
+int entity_version(Entity_Id e) {
+ return e & 0xff;
+}
+
+int entity_index(Entity_Id e) {
+ return (e >> 8) & 0xffffff;
+}
+
+Entity_Id entity_id(int index, int version) {
+ return ((index & 0xffffff) << 8) | (version & 0xff);
+}
+
+void World::init(Arena* a) {
+ int i;
+ arena = a;
+ count = 0;
+ free_count = 0;
+ for (i = 0; i < max_entities; i++)
+ versions[i] = 1;
+ for (i = 0; i < max_pools; i++)
+ pools[i].mask = 0;
+}
+
+uint64_t World::hash_mask(Component_Mask m) {
+ uint64_t h = (uint64_t)m;
+ h = (h ^ (h >> 30)) * UINT64_C(0xbf58476d1ce4e5b9);
+ h = (h ^ (h >> 27)) * UINT64_C(0x94d049bb133111eb);
+ h = (h ^ (h >> 31));
+ return h;
+}
+
+Pool& World::get_pool(Component_Mask m) {
+ int i, idx;
+ idx = (int)(hash_mask(m) % max_pools);
+ for (i = 0; i < max_pools; i++) {
+ Pool& p = pools[idx];
+ if (!p.mask) {
+ p.init(arena, m);
+ return p;
+ } else if (p.mask == m)
+ return p;
+ idx++;
+ idx %= max_pools;
+ }
+ assert(0);
+ return pools[0];
+}
+
+Entity_Id World::create_entity() {
+ Entity_Id e;
+ int ind;
+ assert(count < max_entities);
+ if (free_count)
+ ind = entity_index(freelist[--free_count]);
+ else
+ ind = count++;
+ e = entity_id(ind, versions[ind]);
+ masks[ind] = 0;
+ entities[ind] = e;
+ return e;
+}
+
+void* World::add(Entity_Id eid, Component_Mask m) {
+ int eind = entity_index(eid);
+ int i;
+ assert(entity_version(eid) == versions[eind]);
+ Component_Mask om = masks[eind];
+ Component_Mask tm = om | m;
+ assert(om != tm);
+ Pool& p = get_pool(tm);
+ p.add(arena, eid);
+ if (om) {
+ Pool& op = get_pool(om);
+ for (i = 0; i < max_components; i++) {
+ if (om & ((Component_Mask)1 << i)) {
+ memcpy(
+ p.get(eid, i),
+ op.get(eid, i),
+ component_sizes[i]
+ );
+ }
+ }
+ op.remove(eid);
+ }
+ masks[eind] = tm;
+ return p.get(eid);
+}
+
+void* World::get(Entity_Id eid, int cid) {
+ int eind = entity_index(eid);
+ Pool& p = get_pool(masks[eind]);
+ assert(versions[eind] == entity_version(eid));
+ assert(p.entities[p.mapping[eind]] == eid);
+ return p.get(eid, cid);
+}
+
+void World::remove(Entity_Id eid, int cid) {
+ int eind = entity_index(eid), i;
+ Component_Mask om = masks[eind];
+ Component_Mask nm = om & ~((Component_Mask)1 << cid);
+ Pool& s = get_pool(om);
+ if (nm) {
+ Pool& d = get_pool(nm);
+ for (i = 0; i < max_components; i++) {
+ if (nm & ((uint64_t)1 << i)) {
+ memcpy(
+ d.get(eid, i),
+ s.get(eid, i),
+ component_sizes[i]
+ );
+ }
+ }
+ s.remove(eid);
+ }
+ s.remove(eid);
+ masks[eind] = nm;
+}
+
+void World::destroy(Entity_Id e) {
+ int eind = entity_index(e);
+ Component_Mask m = masks[eind];
+ Pool& p = get_pool(m);
+ p.remove(e);
+ assert(free_count < max_entities);
+ freelist[free_count++] = e;
+ versions[entity_index(e)]++;
+}
+
diff --git a/world.hpp b/world.hpp
new file mode 100644
index 0000000..267b58a
--- /dev/null
+++ b/world.hpp
@@ -0,0 +1,178 @@
+#ifndef world_hpp
+#define world_hpp
+
+struct Arena;
+
+#include <stdint.h>
+
+#include <new>
+#include <utility>
+
+using Component_Mask = uint64_t;
+using Entity_Id = uint32_t;
+
+#define max_entities 1024
+#define pool_cap 128
+#define max_components 64
+
+struct Pool {
+ Component_Mask mask;
+ Pool* next;
+ void* data;
+ Entity_Id entities[pool_cap];
+ int mapping[max_entities];
+ int offsets[max_components];
+ int size, count;
+
+ void init(Arena* a, Component_Mask m);
+ void* add(Arena* a, Entity_Id eid);
+ void* get(Entity_Id eid, int cid);
+ void* get(Entity_Id eid);
+ void remove(Entity_Id eid);
+};
+
+int entity_version(Entity_Id e);
+int entity_index(Entity_Id e);
+Entity_Id entity_id(int index, int version);
+int get_new_component_id(int size);
+
+struct World {
+ static constexpr int max_pools = 32;
+ Pool pools[max_pools];
+ Component_Mask masks[max_entities];
+ uint8_t versions[max_entities];
+ Entity_Id entities[max_entities];
+ Entity_Id freelist[max_entities];
+ Arena* arena;
+ int count, free_count;
+
+ void init(Arena* a);
+ uint64_t hash_mask(Component_Mask m);
+ Pool& get_pool(Component_Mask m);
+
+ template <typename T>
+ int get_component_id() {
+ static int id = get_new_component_id(sizeof(T));
+ return id;
+ }
+
+ Entity_Id create_entity();
+
+ template <typename... T>
+ Component_Mask get_mask() {
+ return (... | ((Component_Mask)1 << get_component_id<T>()));
+ }
+
+ template <typename... T>
+ std::tuple<T&...> add(Entity_Id e) {
+ Component_Mask m = get_mask<T...>();
+ add(e, m);
+ Pool& p = get_pool(masks[entity_index(e)]);
+ return { *(T*)p.get(e, get_component_id<T>())... };
+ }
+
+ template <typename T>
+ T& get(Entity_Id e) {
+ int id = get_component_id<T>();
+ return *(T*)get(e, id);
+ }
+
+ template <typename T>
+ void remove(Entity_Id e) {
+ int id = get_component_id<T>();
+ remove(e, id);
+ }
+
+ template <typename T>
+ bool has(Entity_Id e) {
+ int id = get_component_id<T>();
+ Component_Mask m = masks[entity_index(e)];
+ return (m & ((Component_Mask)1 << id)) != 0;
+ }
+
+ void* add(Entity_Id eid, Component_Mask m);
+ void* get(Entity_Id eid, int cid);
+ void remove(Entity_Id eid, int cid);
+ void destroy(Entity_Id e);
+
+ struct View {
+ World* w;
+ Pool* pools[max_pools];
+ int pool_count;
+
+ struct Iter {
+ View* v;
+ int ptr, ind;
+
+ bool equals(const Iter& other) {
+ return ptr == other.ptr && ind == other.ind;
+ }
+ bool operator==(const Iter& other) {
+ return equals(other);
+ }
+ bool operator!=(const Iter& other) {
+ return !equals(other);
+ }
+ Iter operator++() {
+ Pool* p = v->pools[ind];
+ ptr++;
+ if (ptr == p->count) {
+ ptr = 0;
+ ind++;
+ }
+ return *this;
+ }
+
+ template <typename C>
+ C& get() {
+ Pool* p = v->pools[ind];
+ return *(C*)(
+ (char*)p->data + ptr * p->size +
+ p->offsets[v->w->get_component_id<C>()]
+ );
+ }
+
+ Iter& operator*() {
+ return *this;
+ }
+
+ Entity_Id entity() {
+ Pool* p = v->pools[ind];
+ return p->entities[ptr];
+ }
+ };
+
+ Iter begin() {
+ Iter i;
+ i.v = this;
+ i.ind = 0;
+ i.ptr = 0;
+ return i;
+ }
+
+ Iter end() {
+ Iter i;
+ i.v = this;
+ i.ind = pool_count;
+ i.ptr = 0;
+ return i;
+ }
+ };
+
+ template <typename... T>
+ View view() {
+ int i;
+ auto m = get_mask<T...>();
+ View v;
+ v.w = this;
+ v.pool_count = 0;
+ for (i = 0; i < max_pools; i++) {
+ Pool& p = pools[i];
+ if (p.count && m == (p.mask & m))
+ v.pools[v.pool_count++] = &p;
+ }
+ return v;
+ }
+};
+
+#endif