From 78647977f99c90f6f0ac5ee2a6c65e46be391c8a Mon Sep 17 00:00:00 2001 From: Mergul Date: Tue, 25 Sep 2018 11:31:09 +0200 Subject: [PATCH 001/217] -little change --- dub.json | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/dub.json b/dub.json index 03ad2af..882e501 100755 --- a/dub.json +++ b/dub.json @@ -22,7 +22,10 @@ }, { "name" : "dynlib", - "targetType" : "dynamicLibrary" + "targetType" : "dynamicLibrary", + "dflags-linux-ldc" : [ + "-defaultlib=phobos2-ldc" + ] }, { "name" : "sources", From ed589bbd71b9d0cea9695f298cf44a5c641fd297 Mon Sep 17 00:00:00 2001 From: Mergul Date: Sat, 29 Sep 2018 23:10:31 +0200 Subject: [PATCH 002/217] -added absen components list to system -added ECS uda attributes -added InputStruct version switch (gets update() input as structure of arrays) -initial (WIP) EntitiesData update() input structure compile time parsing --- dub.json | 3 + source/ecs/attributes.d | 4 + source/ecs/manager.d | 268 ++++++++++++++++++++++++++++------------ source/ecs/system.d | 1 + tests/tests.d | 41 +++++- 5 files changed, 238 insertions(+), 79 deletions(-) create mode 100644 source/ecs/attributes.d diff --git a/dub.json b/dub.json index bacb5fc..6705634 100755 --- a/dub.json +++ b/dub.json @@ -10,6 +10,9 @@ "dflags-posix-ldc": [ "-defaultlib=phobos2-ldc,druntime-ldc" ], + "versions": [ + "InputStruct" + ], "configurations" : [ { "name" : "library", diff --git a/source/ecs/attributes.d b/source/ecs/attributes.d new file mode 100644 index 0000000..67c09c1 --- /dev/null +++ b/source/ecs/attributes.d @@ -0,0 +1,4 @@ +module ecs.attributes; + +enum optional = "optional"; +enum absen = "absen"; \ No newline at end of file diff --git a/source/ecs/manager.d b/source/ecs/manager.d index 2ba41fa..df77253 100644 --- a/source/ecs/manager.d +++ b/source/ecs/manager.d @@ -61,92 +61,120 @@ class EntityManager System system; - static if (!(hasMember!(Sys, "system_id")) || !is(typeof(Sys.system_id) == ushort)) + version (InputStruct) { - static assert(0, "System should have \"__gshared ushort system_id"); - } - - static if (hasMember!(Sys, "update")) - { - alias types = Parameters!(Sys.update); - alias storages = ParameterStorageClassTuple!(Sys.update); - static string genCall()() + static if (!(hasMember!(Sys, "EntitiesData"))) { - string ret; + static assert(0, "System should gave \"EntitiesData\" struct for input components"); + } + + static string genCompList()() + { + string ret = "ushort comp;uint req;uint opt;uint absen;"; + static foreach (member; __traits(allMembers, Sys.EntitiesData)) { - uint i = 0; - uint opt = 0; - static foreach (param; (Parameters!(Sys.update))[1 .. $]) + static if (isFunction!(__traits(getMember, Sys.EntitiesData, member))) + static assert(0, "EntitiesData can't have any function!"); + else static if (isArray!(typeof(__traits(getMember, + Sys.EntitiesData, member)))) + static assert(0, "EntitiesData members should be arrays of elements!"); + else static if (is(typeof(__traits(getMember, + Sys.EntitiesData, member)) == Entity[])) + { + ret ~= "const string entities_name = \"" ~ member ~ "\";"; + } + else { - i++; - if (isPointer!param) { - ret ~= "if(opt_array" ~ opt.to!string ~ " !is null)opt_ptr" - ~ opt.to!string ~ " = &opt_array" ~ opt.to!string ~ "[i];"; - opt++; + bool has_att = false; + foreach (att; __traits(getAttributes, + __traits(getMember, Sys.EntitiesData, member))) + { + if (att == "optional") + { + ret ~= "opt++;"; + has_att = true; + break; + } + else if (att == "absen") + { + ret ~= "absen++;"; + has_att = true; + break; + } + } + if (!has_att) + ret ~= "req++;"; } } } - - /*foreach (i; 1 .. (Parameters!(Sys.update)).length) + + ret ~= "system.m_components = Mallocator.instance.makeArray!ushort(req);"; + ret ~= "system.m_optional_components = Mallocator.instance.makeArray!ushort(opt);"; + ret ~= "opt = 0;req = 0;absen = 0;"; + + static foreach (member; __traits(allMembers, Sys.EntitiesData)) { - ret ~= "*cast(types[" ~ i.to!string ~ "]*)(pointers[" ~ (i - 1) - .to!string ~ "]),"; - }*/ - uint i = 0; - uint req = 0; - uint opt = 0; - ret ~= "s.update(id_array[i],"; - static foreach (param; (Parameters!(Sys.update))[1 .. $]) - { - i++; - if (isPointer!param) + static if (isFunction!(__traits(getMember, Sys.EntitiesData, member))) + static assert(0, "EntitiesData can't have any function!"); + else static if (isArray!(typeof(__traits(getMember, + Sys.EntitiesData, member)))) + static assert(0, "EntitiesData members should be arrays of elements!"); + else static if (is(typeof(__traits(getMember, + Sys.EntitiesData, member)) == Entity[])) { - ret ~= "opt_ptr" ~ (opt++).to!string ~ ","; + //ret ~= "const string entities_name = \"" ~ member ~ "\";"; } else { - ret ~= "array" ~ (req++).to!string ~ "[i],"; - } - } - - - ret ~= ");"; - return ret; - } - - static string genArrays()() - { - string ret; - - uint i = 0; - uint req = 0; - uint opt = 0; - static foreach (param; (Parameters!(Sys.update))[1 .. $]) - { - i++; - if (isPointer!param) - { - ret ~= "PointerTarget!(types[" ~ i.to!string - ~ "])[] opt_array" ~ opt.to!string ~ " = null;"; - ret ~= "if(info.deltas[types[" ~ i.to!string ~ "].component_id] != 0)opt_array" - ~ opt.to!string ~ " - = (cast(types[" ~ i.to!string ~ "])(cast(void*)block + info.deltas[types[" - ~ i.to!string ~ "].component_id]))[0..block.entities_count];"; - ret ~= "types[" ~ i.to!string ~ "] opt_ptr" ~ opt.to!string ~ ";"; - opt++; - } - else - { - ret ~= "types[" ~ i.to!string ~ "][] array" ~ req.to!string ~ " = (cast(types[" - ~ i.to!string ~ "]*)(cast(void*)block + info.deltas[types[" - ~ i.to!string ~ "].component_id]))[0..block.entities_count];"; - req++; + { + bool has_att = false; + foreach (att; __traits(getAttributes, + __traits(getMember, Sys.EntitiesData, member))) + { + if (att == "optional") + { + ret ~= "{comp = components_map.get(\"" ~ (typeof(__traits(getMember, + Sys.EntitiesData, member))) + .stringof ~ "\", ushort.max);\n + if(comp == ushort.max)assert(0,\"Can't register system \\\"" ~ Sys.stringof + ~ "\\\" due to non existing component " ~ typeof(__traits(getMember, + Sys.EntitiesData, member)).stringof ~ ".\"); + system.m_optional_components[opt++] = comp;}"; + has_att = true; + break; + } + else if (att == "absen") + { + ret ~= "{comp = components_map.get(\"" ~ (typeof(__traits(getMember, + Sys.EntitiesData, member))) + .stringof ~ "\", ushort.max);\n + if(comp == ushort.max)assert(0,\"Can't register system \\\"" ~ Sys.stringof + ~ "\\\" due to non existing component " ~ typeof(__traits(getMember, + Sys.EntitiesData, member)).stringof + ~ ".\");system.m_absen_components[absen++] = comp;}"; + has_att = true; + break; + } + } + if (!has_att) + { + ret ~= "{comp = components_map.get(\"" ~ (typeof(__traits(getMember, + Sys.EntitiesData, member))) + .stringof ~ "\", ushort.max);\n + if(comp == ushort.max)assert(0,\"Can't register system \\\"" ~ Sys.stringof + ~ "\\\" due to non existing component " ~ typeof(__traits(getMember, + Sys.EntitiesData, member)).stringof ~ ".\"); + system.m_components[req++] = comp;}"; + } + } } } return ret; } - + } + else + { static string genCompList()() { string ret = "ushort comp;uint req;uint opt;"; @@ -186,6 +214,92 @@ class EntityManager } return ret; } + } + + static if (!(hasMember!(Sys, "system_id")) || !is(typeof(Sys.system_id) == ushort)) + { + static assert(0, "System should have \"__gshared ushort system_id"); + } + + static if (hasMember!(Sys, "update")) + { + alias types = Parameters!(Sys.update); + alias storages = ParameterStorageClassTuple!(Sys.update); + static string genCall()() + { + string ret; + { + uint i = 0; + uint opt = 0; + static foreach (param; (Parameters!(Sys.update))[1 .. $]) + { + i++; + if (isPointer!param) + { + ret ~= "if(opt_array" ~ opt.to!string ~ " !is null)opt_ptr" + ~ opt.to!string ~ " = &opt_array" ~ opt.to!string ~ "[i];"; + opt++; + } + } + } + + /*foreach (i; 1 .. (Parameters!(Sys.update)).length) + { + ret ~= "*cast(types[" ~ i.to!string ~ "]*)(pointers[" ~ (i - 1) + .to!string ~ "]),"; + }*/ + uint i = 0; + uint req = 0; + uint opt = 0; + ret ~= "s.update(id_array[i],"; + static foreach (param; (Parameters!(Sys.update))[1 .. $]) + { + i++; + if (isPointer!param) + { + ret ~= "opt_ptr" ~ (opt++).to!string ~ ","; + } + else + { + ret ~= "array" ~ (req++).to!string ~ "[i],"; + } + } + + ret ~= ");"; + return ret; + } + + static string genArrays()() + { + string ret; + + uint i = 0; + uint req = 0; + uint opt = 0; + static foreach (param; (Parameters!(Sys.update))[1 .. $]) + { + i++; + if (isPointer!param) + { + ret ~= "PointerTarget!(types[" ~ i.to!string + ~ "])[] opt_array" ~ opt.to!string ~ " = null;"; + ret ~= "if(info.deltas[types[" ~ i.to!string ~ "].component_id] != 0)opt_array" ~ opt.to!string + ~ " + = (cast(types[" ~ i.to!string ~ "])(cast(void*)block + info.deltas[types[" + ~ i.to!string ~ "].component_id]))[0..block.entities_count];"; + ret ~= "types[" ~ i.to!string ~ "] opt_ptr" ~ opt.to!string ~ ";"; + opt++; + } + else + { + ret ~= "types[" ~ i.to!string ~ "][] array" ~ req.to!string ~ " = (cast(types[" + ~ i.to!string ~ "]*)(cast(void*)block + info.deltas[types[" + ~ i.to!string ~ "].component_id]))[0..block.entities_count];"; + req++; + } + } + return ret; + } static void callUpdate(ref CallData data, void* entity) { @@ -255,7 +369,12 @@ class EntityManager system.m_priority = priority; //system.m_components = Mallocator.instance.makeArray!uint(types.length - 1); - static if (hasMember!(Sys, "update")) + + version (InputStruct) + { + mixin(genCompList()); + } + else static if (hasMember!(Sys, "update")) { mixin(genCompList()); } @@ -452,7 +571,6 @@ class EntityManager = components[comp].init_data; } - return temp; } @@ -505,7 +623,6 @@ class EntityManager current_delta += entites_in_block * components[id].size; } - foreach (uint i, ref system; systems) { if (system.m_update is null) @@ -644,7 +761,7 @@ class EntityManager EntitiesBlock* new_block = findBlockWithFreeSpace(new_info); void* start = new_block.dataBegin() + new_block.entities_count * EntityID.sizeof; - + Entity* new_entity = cast(Entity*) start; new_entity.id = entity.id; new_entity.updateID(); @@ -759,7 +876,7 @@ class EntityManager //removeEntityNoID(entity, block); void* start = new_block.dataBegin() + new_block.entities_count * EntityID.sizeof; - + Entity* new_entity = cast(Entity*) start; new_entity.id = entity.id; new_entity.updateID(); @@ -797,7 +914,6 @@ class EntityManager } } - new_block.entities_count++; removeEntityNoID(entity, block); } @@ -857,7 +973,6 @@ class EntityManager tmpl.entity_data.ptr + info.tmpl_deltas[comp], components[comp].size); } - if (!block.added_count) blocks_to_update.add(block); @@ -960,7 +1075,6 @@ class EntityManager } } - if (block.entities_count == 0) { if (info.first_block is block) diff --git a/source/ecs/system.d b/source/ecs/system.d index 83bcd7d..1276d86 100644 --- a/source/ecs/system.d +++ b/source/ecs/system.d @@ -39,6 +39,7 @@ package: void* m_system_pointer; ushort[] m_components; + ushort[] m_absen_components; ushort[] m_optional_components; //void function(ref EntityManager.CallData data, void* entity) update; diff --git a/tests/tests.d b/tests/tests.d index 5fc09f9..11852cb 100644 --- a/tests/tests.d +++ b/tests/tests.d @@ -4,6 +4,7 @@ import ecs.entity; import ecs.events; import ecs.manager; import ecs.system; +import ecs.attributes; import core.time; import std.stdio; @@ -124,11 +125,12 @@ int main() } - struct InputData + static struct EntitiesData { TestComp* test; TestComp2* test2; - @("optional") TestComp3* test3; + @optional TestComp3* test3; + @absen TestComp4* test4; } void update(ref Entity entity, ref TestComp test, ref TestComp2 test2)//, TestComp3* test3) //ref TestComp comp) @@ -153,6 +155,11 @@ int main() } + void update(ref EntitiesData data) + { + + } + void handleEvent(TestEvent event, ref TestComp test, ref TestComp2 test2, TestComp3* test3) { @@ -163,6 +170,11 @@ int main() { __gshared ushort system_id; + static struct EntitiesData + { + TestComp* test; + } + void initialize(ref Entity entity, ref TestComp comp) { @@ -175,6 +187,13 @@ int main() //writeln("High priority tekst! "); } + void update(ref EntitiesData data) //ref TestComp comp) + { + assert(cast(size_t)&data.test % TestComp.alignof == 0); + + //writeln("High priority tekst! "); + } + /*void handleEvent(Event event, ref TestComp comp) { @@ -185,6 +204,17 @@ int main() { __gshared ushort system_id; + static struct EntitiesData + { + Entity* entity; + TestComp3* test; + + /*void a() + { + + }*/ + } + void onEnable() { import std.stdio; @@ -211,6 +241,13 @@ int main() gEM.sendSelfEvent!(TestEvent)(entity.id, TestEvent()); } + void update(ref EntitiesData data) //ref TestComp comp) + { + //writeln("TestSystem2 update"); + data.test.gg += 14; + gEM.sendSelfEvent!(TestEvent)(data.entity.id, TestEvent()); + } + /*void handleEvent(Event event, ref TestComp comp) { From d5780a625209e1351a1828fbb4babb446667b1c9 Mon Sep 17 00:00:00 2001 From: Mergul Date: Sun, 30 Sep 2018 23:12:20 +0200 Subject: [PATCH 003/217] -working update() with EntitiesData structure input -added support for 'const' components input (read only, future usage) --- source/ecs/entity.d | 2 +- source/ecs/manager.d | 211 ++++++++++++++++++++++++++++++------------- tests/tests.d | 40 ++++---- 3 files changed, 167 insertions(+), 86 deletions(-) diff --git a/source/ecs/entity.d b/source/ecs/entity.d index 5e85211..d23bab6 100644 --- a/source/ecs/entity.d +++ b/source/ecs/entity.d @@ -17,7 +17,7 @@ struct Entity EntityManager.instance.id_manager.update(this); } - T* getComponent(T)() + T* getComponent(T)() const { EntityManager.EntitiesBlock* block = gEM.getMetaData(&this); EntityManager.EntityInfo* info = block.type_info; diff --git a/source/ecs/manager.d b/source/ecs/manager.d index df77253..5749319 100644 --- a/source/ecs/manager.d +++ b/source/ecs/manager.d @@ -61,6 +61,11 @@ class EntityManager System system; + static if (!(hasMember!(Sys, "system_id")) || !is(typeof(Sys.system_id) == ushort)) + { + static assert(0, "System should have \"__gshared ushort system_id"); + } + version (InputStruct) { static if (!(hasMember!(Sys, "EntitiesData"))) @@ -75,13 +80,13 @@ class EntityManager { static if (isFunction!(__traits(getMember, Sys.EntitiesData, member))) static assert(0, "EntitiesData can't have any function!"); - else static if (isArray!(typeof(__traits(getMember, - Sys.EntitiesData, member)))) + else static if (!(isArray!(typeof(__traits(getMember, + Sys.EntitiesData, member))))) static assert(0, "EntitiesData members should be arrays of elements!"); else static if (is(typeof(__traits(getMember, Sys.EntitiesData, member)) == Entity[])) { - ret ~= "const string entities_name = \"" ~ member ~ "\";"; + //ret ~= "const string entities_name = \"" ~ member ~ "\";"; } else { @@ -111,61 +116,51 @@ class EntityManager ret ~= "system.m_components = Mallocator.instance.makeArray!ushort(req);"; ret ~= "system.m_optional_components = Mallocator.instance.makeArray!ushort(opt);"; + ret ~= "system.m_absen_components = Mallocator.instance.makeArray!ushort(absen);"; ret ~= "opt = 0;req = 0;absen = 0;"; static foreach (member; __traits(allMembers, Sys.EntitiesData)) { - static if (isFunction!(__traits(getMember, Sys.EntitiesData, member))) - static assert(0, "EntitiesData can't have any function!"); - else static if (isArray!(typeof(__traits(getMember, - Sys.EntitiesData, member)))) - static assert(0, "EntitiesData members should be arrays of elements!"); - else static if (is(typeof(__traits(getMember, - Sys.EntitiesData, member)) == Entity[])) + static if (is(typeof(__traits(getMember, Sys.EntitiesData, member)) == Entity[]) + || is(typeof(__traits(getMember, Sys.EntitiesData, member)) == const(Entity)[])) { //ret ~= "const string entities_name = \"" ~ member ~ "\";"; } else { { + + ret ~= "{comp = components_map.get(Unqual!(ForeachType!(typeof( + Sys.EntitiesData." + ~ member ~ "))) + .stringof, ushort.max);\n + if(comp == ushort.max)assert(0,\"Can't register system \\\"" ~ Sys.stringof + ~ "\\\" due to non existing component \" ~ ForeachType!(typeof( + Sys.EntitiesData." + ~ member ~ ")) + .stringof + ~ \".\");"; + bool has_att = false; foreach (att; __traits(getAttributes, __traits(getMember, Sys.EntitiesData, member))) { if (att == "optional") { - ret ~= "{comp = components_map.get(\"" ~ (typeof(__traits(getMember, - Sys.EntitiesData, member))) - .stringof ~ "\", ushort.max);\n - if(comp == ushort.max)assert(0,\"Can't register system \\\"" ~ Sys.stringof - ~ "\\\" due to non existing component " ~ typeof(__traits(getMember, - Sys.EntitiesData, member)).stringof ~ ".\"); - system.m_optional_components[opt++] = comp;}"; + ret ~= "system.m_optional_components[opt++] = comp;}"; has_att = true; break; } else if (att == "absen") { - ret ~= "{comp = components_map.get(\"" ~ (typeof(__traits(getMember, - Sys.EntitiesData, member))) - .stringof ~ "\", ushort.max);\n - if(comp == ushort.max)assert(0,\"Can't register system \\\"" ~ Sys.stringof - ~ "\\\" due to non existing component " ~ typeof(__traits(getMember, - Sys.EntitiesData, member)).stringof - ~ ".\");system.m_absen_components[absen++] = comp;}"; + ret ~= "system.m_absen_components[absen++] = comp;}"; has_att = true; break; } } if (!has_att) { - ret ~= "{comp = components_map.get(\"" ~ (typeof(__traits(getMember, - Sys.EntitiesData, member))) - .stringof ~ "\", ushort.max);\n - if(comp == ushort.max)assert(0,\"Can't register system \\\"" ~ Sys.stringof - ~ "\\\" due to non existing component " ~ typeof(__traits(getMember, - Sys.EntitiesData, member)).stringof ~ ".\"); - system.m_components[req++] = comp;}"; + ret ~= "system.m_components[req++] = comp;}"; } } } @@ -216,11 +211,6 @@ class EntityManager } } - static if (!(hasMember!(Sys, "system_id")) || !is(typeof(Sys.system_id) == ushort)) - { - static assert(0, "System should have \"__gshared ushort system_id"); - } - static if (hasMember!(Sys, "update")) { alias types = Parameters!(Sys.update); @@ -243,11 +233,6 @@ class EntityManager } } - /*foreach (i; 1 .. (Parameters!(Sys.update)).length) - { - ret ~= "*cast(types[" ~ i.to!string ~ "]*)(pointers[" ~ (i - 1) - .to!string ~ "]),"; - }*/ uint i = 0; uint req = 0; uint opt = 0; @@ -301,39 +286,135 @@ class EntityManager return ret; } - static void callUpdate(ref CallData data, void* entity) + version (InputStruct) { - static if (hasMember!(Sys, "update")) + + static string genFillInputData()() { - Sys* s = cast(Sys*) data.system.m_system_pointer; - - void*[] pointers = (cast(void**) alloca(data.system.m_components.length * (void*) - .sizeof))[0 .. data.system.m_components.length]; - void*[] optional_pointers = (cast(void**) alloca( - data.system.m_optional_components.length * (void*).sizeof))[0 - .. data.system.m_optional_components.length]; - - EntitiesBlock* block = data.info.first_block; - while (block !is null) + string ret; + ushort comp; + uint req = 0; + uint opt = 0; + uint absen = 0; + foreach (member; __traits(allMembers, Sys.EntitiesData)) { - EntityInfo* info = block.type_info; - Entity[] id_array = (cast(Entity*) block.dataBegin())[0 - .. block.entities_count]; - mixin(genArrays()); - foreach (i; 0 .. block.entities_count) + if (is(typeof(__traits(getMember, Sys.EntitiesData, member)) == Entity[]) + || is(typeof(__traits(getMember, Sys.EntitiesData, member)) == const(Entity)[])) { - mixin(genCall()); - //data_pointer += EntityID.sizeof; //data.info.size; - /*foreach (ref pointer; pointers) + ret ~= "input_data." ~ member + ~ " = (cast(Entity*) block.dataBegin())[0 .. block.entities_count];"; + } + else + { + { + bool has_att = false; + foreach (att; __traits(getAttributes, + __traits(getMember, Sys.EntitiesData, member))) + { + if (att == "optional") + { + ret ~= "if(data.system.m_optional_components[" + ~ opt.to!string ~ "] < info.deltas.length && info.deltas[ data.system.m_optional_components[" + ~ opt.to!string ~ "]] != 0)input_data." ~ member ~ " = (cast(ForeachType!(typeof(Sys.EntitiesData." + ~ member ~ "))*)(cast(void*) block + info.deltas[ data.system.m_optional_components[" + ~ opt.to!string ~ "]]))[0 .. block.entities_count]; + else input_data." ~ member ~ " = null;"; + opt++; + has_att = true; + break; + } + else if (att == "absen") + { + absen++; + has_att = true; + break; + } + } + if (!has_att) + { + ret ~= "input_data." ~ member ~ " = (cast(ForeachType!(typeof(Sys.EntitiesData." + ~ member ~ "))*)(cast(void*) block + info.deltas[ data.system.m_components[" + ~ req.to!string ~ "]]))[0 .. block.entities_count];"; + req++; + } + } + } + } + return ret; + } + + static void callUpdate(ref CallData data, void* entity) + { + static if (hasMember!(Sys, "update")) + { + Sys* s = cast(Sys*) data.system.m_system_pointer; + + /*void*[] pointers = (cast(void**) alloca(data.system.m_components.length * (void*) + .sizeof))[0 .. data.system.m_components.length]; + void*[] optional_pointers = (cast(void**) alloca( + data.system.m_optional_components.length * (void*).sizeof))[0 + .. data.system.m_optional_components.length];*/ + + Sys.EntitiesData input_data; + + EntitiesBlock* block = data.info.first_block; + while (block !is null) + { + EntityInfo* info = block.type_info; + /*Entity[] id_array = (cast(Entity*) block.dataBegin())[0 + .. block.entities_count];*/ + //mixin(genArrays()); + + mixin(genFillInputData()); + + s.update(input_data); + /*foreach (i; 0 .. block.entities_count) + { + mixin(genCall()); + }*/ + + block = block.next_block; + } + + } + } + } + else + { + static void callUpdate(ref CallData data, void* entity) + { + static if (hasMember!(Sys, "update")) + { + Sys* s = cast(Sys*) data.system.m_system_pointer; + + void*[] pointers = (cast(void**) alloca(data.system.m_components.length * (void*) + .sizeof))[0 .. data.system.m_components.length]; + void*[] optional_pointers = (cast(void**) alloca( + data.system.m_optional_components.length * (void*).sizeof))[0 + .. data.system.m_optional_components.length]; + + EntitiesBlock* block = data.info.first_block; + while (block !is null) + { + EntityInfo* info = block.type_info; + Entity[] id_array = (cast(Entity*) block.dataBegin())[0 + .. block.entities_count]; + mixin(genArrays()); + foreach (i; 0 .. block.entities_count) + { + mixin(genCall()); + //data_pointer += EntityID.sizeof; //data.info.size; + /*foreach (ref pointer; pointers) pointer += size; foreach (ref pointer; optional_pointers) if (pointer != null) pointer += size;*/ + } + + block = block.next_block; } - block = block.next_block; } - } } @@ -918,7 +999,7 @@ class EntityManager removeEntityNoID(entity, block); } - void addComponents(Components...)(EntityID entity_id, Components comps) + void addComponents(Components...)(const EntityID entity_id, Components comps) { const uint num = Components.length; Entity* entity = id_manager.getEntityPointer(entity_id); @@ -1120,7 +1201,7 @@ class EntityManager *params: *pointer = pointer to any data of entity (i.e. component data pointer) */ - export EntitiesBlock* getMetaData(void* pointer) + export EntitiesBlock* getMetaData(const void* pointer) { return cast(EntitiesBlock*)(cast(size_t) pointer & (~cast(size_t)(page_size - 1))); } diff --git a/tests/tests.d b/tests/tests.d index 11852cb..3e9eee3 100644 --- a/tests/tests.d +++ b/tests/tests.d @@ -127,10 +127,10 @@ int main() static struct EntitiesData { - TestComp* test; - TestComp2* test2; - @optional TestComp3* test3; - @absen TestComp4* test4; + TestComp[] test; + TestComp2[] test2; + @optional TestComp3[] test3; + @absen TestComp4[] test4; } void update(ref Entity entity, ref TestComp test, ref TestComp2 test2)//, TestComp3* test3) //ref TestComp comp) @@ -139,25 +139,21 @@ int main() assert(cast(size_t)&test2 % TestComp2.alignof == 0); import std.stdio; - //writeln("Jakis tekst! ",test.b); test.a += 1000; test.b += 2000; - //writeln("Jakis tekst! ",test.b); test2.b += 2; test2.a = 8; - //writeln("Jakis tekst! ",test2.b); - //writeln("Low priority tekst! "); - /*if (test3) - { - test3.gg = 200; - test3.bg += 1; - }*/ - } void update(ref EntitiesData data) { - + foreach(i;0..data.test.length) + { + data.test[i].a += 1000; + data.test[i].b += 2000; + data.test2[i].b += 2; + data.test2[i].a = 8; + } } void handleEvent(TestEvent event, ref TestComp test, ref TestComp2 test2, TestComp3* test3) @@ -172,7 +168,7 @@ int main() static struct EntitiesData { - TestComp* test; + TestComp[] test; } void initialize(ref Entity entity, ref TestComp comp) @@ -206,8 +202,8 @@ int main() static struct EntitiesData { - Entity* entity; - TestComp3* test; + Entity[] entity; + TestComp3[] test; /*void a() { @@ -244,8 +240,12 @@ int main() void update(ref EntitiesData data) //ref TestComp comp) { //writeln("TestSystem2 update"); - data.test.gg += 14; - gEM.sendSelfEvent!(TestEvent)(data.entity.id, TestEvent()); + foreach(i;0..data.test.length) + { + data.test[i].gg += 14; + gEM.sendSelfEvent!(TestEvent)(data.entity[i].id, TestEvent()); + } + } /*void handleEvent(Event event, ref TestComp comp) From 0e13fafefd7738d3060eb625cf2323c2f8996370 Mon Sep 17 00:00:00 2001 From: Mergul Date: Mon, 1 Oct 2018 13:17:31 +0200 Subject: [PATCH 004/217] -removed 'InputStruct' version switch (now it's default behaviour) -checking if System struct has valid update(EntitiesData) prototype --- dub.json | 3 - source/ecs/manager.d | 504 +++++++++++++++---------------------------- tests/tests.d | 28 +-- 3 files changed, 172 insertions(+), 363 deletions(-) diff --git a/dub.json b/dub.json index 6705634..bacb5fc 100755 --- a/dub.json +++ b/dub.json @@ -10,9 +10,6 @@ "dflags-posix-ldc": [ "-defaultlib=phobos2-ldc,druntime-ldc" ], - "versions": [ - "InputStruct" - ], "configurations" : [ { "name" : "library", diff --git a/source/ecs/manager.d b/source/ecs/manager.d index 5749319..9dc7eff 100644 --- a/source/ecs/manager.d +++ b/source/ecs/manager.d @@ -66,27 +66,137 @@ class EntityManager static assert(0, "System should have \"__gshared ushort system_id"); } - version (InputStruct) + static if (!(hasMember!(Sys, "EntitiesData"))) { - static if (!(hasMember!(Sys, "EntitiesData"))) + static assert(0, "System should gave \"EntitiesData\" struct for input components"); + } + + static string genCompList()() + { + string ret = "ushort comp;uint req;uint opt;uint absen;"; + static foreach (member; __traits(allMembers, Sys.EntitiesData)) { - static assert(0, "System should gave \"EntitiesData\" struct for input components"); + static if (isFunction!(__traits(getMember, Sys.EntitiesData, member))) + static assert(0, "EntitiesData can't have any function!"); + else static if (!(isArray!(typeof(__traits(getMember, + Sys.EntitiesData, member))))) + static assert(0, "EntitiesData members should be arrays of elements!"); + else static if (is(typeof(__traits(getMember, Sys.EntitiesData, + member)) == Entity[])) + { + //ret ~= "const string entities_name = \"" ~ member ~ "\";"; + } + else + { + { + bool has_att = false; + foreach (att; __traits(getAttributes, + __traits(getMember, Sys.EntitiesData, member))) + { + if (att == "optional") + { + ret ~= "opt++;"; + has_att = true; + break; + } + else if (att == "absen") + { + ret ~= "absen++;"; + has_att = true; + break; + } + } + if (!has_att) + ret ~= "req++;"; + } + } } - static string genCompList()() + ret ~= "system.m_components = Mallocator.instance.makeArray!ushort(req);"; + ret ~= "system.m_optional_components = Mallocator.instance.makeArray!ushort(opt);"; + ret ~= "system.m_absen_components = Mallocator.instance.makeArray!ushort(absen);"; + ret ~= "opt = 0;req = 0;absen = 0;"; + + static foreach (member; __traits(allMembers, Sys.EntitiesData)) { - string ret = "ushort comp;uint req;uint opt;uint absen;"; - static foreach (member; __traits(allMembers, Sys.EntitiesData)) + static if (is(typeof(__traits(getMember, Sys.EntitiesData, + member)) == Entity[]) || is(typeof(__traits(getMember, + Sys.EntitiesData, member)) == const(Entity)[])) + { + //ret ~= "const string entities_name = \"" ~ member ~ "\";"; + } + else { - static if (isFunction!(__traits(getMember, Sys.EntitiesData, member))) - static assert(0, "EntitiesData can't have any function!"); - else static if (!(isArray!(typeof(__traits(getMember, - Sys.EntitiesData, member))))) - static assert(0, "EntitiesData members should be arrays of elements!"); - else static if (is(typeof(__traits(getMember, - Sys.EntitiesData, member)) == Entity[])) { - //ret ~= "const string entities_name = \"" ~ member ~ "\";"; + + ret ~= "{comp = components_map.get(Unqual!(ForeachType!(typeof( + Sys.EntitiesData." ~ member ~ "))) + .stringof, ushort.max);\n + if(comp == ushort.max)assert(0,\"Can't register system \\\"" + ~ Sys.stringof + ~ "\\\" due to non existing component \" ~ ForeachType!(typeof( + Sys.EntitiesData." + ~ member ~ ")) + .stringof + ~ \".\");"; + + bool has_att = false; + foreach (att; __traits(getAttributes, + __traits(getMember, Sys.EntitiesData, member))) + { + if (att == "optional") + { + ret ~= "system.m_optional_components[opt++] = comp;}"; + has_att = true; + break; + } + else if (att == "absen") + { + ret ~= "system.m_absen_components[absen++] = comp;}"; + has_att = true; + break; + } + } + if (!has_att) + { + ret ~= "system.m_components[req++] = comp;}"; + } + } + } + } + return ret; + } + + string genParamsChecking()() + { + string ret; + foreach (func; __traits(getOverloads, Sys, "update")) + { + if ((Parameters!(func)).length == 1) + ret ~= "\"" ~ (fullyQualifiedName!(Sys.EntitiesData)) ~ "\" == \"" ~ ( + fullyQualifiedName!((Parameters!(func))[0])) ~ "\" || "; + } + ret ~= "false"; + return ret; + } + + static if (hasMember!(Sys, "update") && (mixin(genParamsChecking()))) + { + static string genFillInputData()() + { + string ret; + ushort comp; + uint req = 0; + uint opt = 0; + uint absen = 0; + foreach (member; __traits(allMembers, Sys.EntitiesData)) + { + if (is(typeof(__traits(getMember, Sys.EntitiesData, + member)) == Entity[]) || is(typeof(__traits(getMember, + Sys.EntitiesData, member)) == const(Entity)[])) + { + ret ~= "input_data." ~ member + ~ " = (cast(Entity*) block.dataBegin())[0 .. block.entities_count];"; } else { @@ -97,325 +207,55 @@ class EntityManager { if (att == "optional") { - ret ~= "opt++;"; - has_att = true; - break; - } - else if (att == "absen") - { - ret ~= "absen++;"; - has_att = true; - break; - } - } - if (!has_att) - ret ~= "req++;"; - } - } - } - - ret ~= "system.m_components = Mallocator.instance.makeArray!ushort(req);"; - ret ~= "system.m_optional_components = Mallocator.instance.makeArray!ushort(opt);"; - ret ~= "system.m_absen_components = Mallocator.instance.makeArray!ushort(absen);"; - ret ~= "opt = 0;req = 0;absen = 0;"; - - static foreach (member; __traits(allMembers, Sys.EntitiesData)) - { - static if (is(typeof(__traits(getMember, Sys.EntitiesData, member)) == Entity[]) - || is(typeof(__traits(getMember, Sys.EntitiesData, member)) == const(Entity)[])) - { - //ret ~= "const string entities_name = \"" ~ member ~ "\";"; - } - else - { - { - - ret ~= "{comp = components_map.get(Unqual!(ForeachType!(typeof( - Sys.EntitiesData." - ~ member ~ "))) - .stringof, ushort.max);\n - if(comp == ushort.max)assert(0,\"Can't register system \\\"" ~ Sys.stringof - ~ "\\\" due to non existing component \" ~ ForeachType!(typeof( - Sys.EntitiesData." - ~ member ~ ")) - .stringof - ~ \".\");"; - - bool has_att = false; - foreach (att; __traits(getAttributes, - __traits(getMember, Sys.EntitiesData, member))) - { - if (att == "optional") - { - ret ~= "system.m_optional_components[opt++] = comp;}"; - has_att = true; - break; - } - else if (att == "absen") - { - ret ~= "system.m_absen_components[absen++] = comp;}"; - has_att = true; - break; - } - } - if (!has_att) - { - ret ~= "system.m_components[req++] = comp;}"; - } - } - } - } - return ret; - } - } - else - { - static string genCompList()() - { - string ret = "ushort comp;uint req;uint opt;"; - foreach (i; 1 .. (Parameters!(Sys.update)).length) - { - ret ~= " - static if(isPointer!(types[" ~ i.to!string - ~ "]))opt++; - else static if(storages[" ~ i.to!string ~ "] == STC.ref_)req++;\n - else static assert(0,\"Can't register system \\\"" ~ Sys.stringof - ~ "\\\". Unsupported parameter type \\\"\"~types[" - ~ i.to!string ~ "].stringof~\"\\\".\");"; - } - ret ~= "system.m_components = Mallocator.instance.makeArray!ushort(req);"; - ret ~= "system.m_optional_components = Mallocator.instance.makeArray!ushort(opt);"; - ret ~= "opt = 0;req = 0;"; - foreach (i; 1 .. (Parameters!(Sys.update)).length) - { - ret ~= " - static if(isPointer!(types[" ~ i.to!string ~ "])) - { - comp = components_map.get(PointerTarget!(types[" - ~ i.to!string ~ "]).stringof, ushort.max);\n - if(comp == ushort.max)assert(0,\"Can't register system \\\"" ~ Sys.stringof - ~ "\\\" due to non existing component \\\"\"~types[" ~ i.to!string ~ "].stringof~\"\\\".\"); - system.m_optional_components[opt++] = comp; - } - else static if(storages[" - ~ i.to!string ~ "] == STC.ref_) - { - comp = components_map.get(types[" ~ i.to!string ~ "].stringof, ushort.max);\n - if(comp == ushort.max)assert(0,\"Can't register system \\\"" - ~ Sys.stringof ~ "\\\" due to non existing component \\\"\"~types[" - ~ i.to!string ~ "].stringof~\"\\\".\"); - system.m_components[req++] = comp; - }"; - } - return ret; - } - } - - static if (hasMember!(Sys, "update")) - { - alias types = Parameters!(Sys.update); - alias storages = ParameterStorageClassTuple!(Sys.update); - static string genCall()() - { - string ret; - { - uint i = 0; - uint opt = 0; - static foreach (param; (Parameters!(Sys.update))[1 .. $]) - { - i++; - if (isPointer!param) - { - ret ~= "if(opt_array" ~ opt.to!string ~ " !is null)opt_ptr" - ~ opt.to!string ~ " = &opt_array" ~ opt.to!string ~ "[i];"; - opt++; - } - } - } - - uint i = 0; - uint req = 0; - uint opt = 0; - ret ~= "s.update(id_array[i],"; - static foreach (param; (Parameters!(Sys.update))[1 .. $]) - { - i++; - if (isPointer!param) - { - ret ~= "opt_ptr" ~ (opt++).to!string ~ ","; - } - else - { - ret ~= "array" ~ (req++).to!string ~ "[i],"; - } - } - - ret ~= ");"; - return ret; - } - - static string genArrays()() - { - string ret; - - uint i = 0; - uint req = 0; - uint opt = 0; - static foreach (param; (Parameters!(Sys.update))[1 .. $]) - { - i++; - if (isPointer!param) - { - ret ~= "PointerTarget!(types[" ~ i.to!string - ~ "])[] opt_array" ~ opt.to!string ~ " = null;"; - ret ~= "if(info.deltas[types[" ~ i.to!string ~ "].component_id] != 0)opt_array" ~ opt.to!string - ~ " - = (cast(types[" ~ i.to!string ~ "])(cast(void*)block + info.deltas[types[" - ~ i.to!string ~ "].component_id]))[0..block.entities_count];"; - ret ~= "types[" ~ i.to!string ~ "] opt_ptr" ~ opt.to!string ~ ";"; - opt++; - } - else - { - ret ~= "types[" ~ i.to!string ~ "][] array" ~ req.to!string ~ " = (cast(types[" - ~ i.to!string ~ "]*)(cast(void*)block + info.deltas[types[" - ~ i.to!string ~ "].component_id]))[0..block.entities_count];"; - req++; - } - } - return ret; - } - - version (InputStruct) - { - - static string genFillInputData()() - { - string ret; - ushort comp; - uint req = 0; - uint opt = 0; - uint absen = 0; - foreach (member; __traits(allMembers, Sys.EntitiesData)) - { - if (is(typeof(__traits(getMember, Sys.EntitiesData, member)) == Entity[]) - || is(typeof(__traits(getMember, Sys.EntitiesData, member)) == const(Entity)[])) - { - ret ~= "input_data." ~ member - ~ " = (cast(Entity*) block.dataBegin())[0 .. block.entities_count];"; - } - else - { - { - bool has_att = false; - foreach (att; __traits(getAttributes, - __traits(getMember, Sys.EntitiesData, member))) - { - if (att == "optional") - { - ret ~= "if(data.system.m_optional_components[" - ~ opt.to!string ~ "] < info.deltas.length && info.deltas[ data.system.m_optional_components[" - ~ opt.to!string ~ "]] != 0)input_data." ~ member ~ " = (cast(ForeachType!(typeof(Sys.EntitiesData." - ~ member ~ "))*)(cast(void*) block + info.deltas[ data.system.m_optional_components[" + ret ~= "if(data.system.m_optional_components[" ~ opt.to!string + ~ "] < info.deltas.length && info.deltas[ data.system.m_optional_components[" + ~ opt.to!string ~ "]] != 0)input_data." ~ member + ~ " = (cast(ForeachType!(typeof(Sys.EntitiesData." ~ member + ~ "))*)(cast(void*) block + info.deltas[ data.system.m_optional_components[" ~ opt.to!string ~ "]]))[0 .. block.entities_count]; - else input_data." ~ member ~ " = null;"; - opt++; - has_att = true; - break; - } - else if (att == "absen") - { - absen++; - has_att = true; - break; - } + else input_data." + ~ member ~ " = null;"; + opt++; + has_att = true; + break; } - if (!has_att) + else if (att == "absen") { - ret ~= "input_data." ~ member ~ " = (cast(ForeachType!(typeof(Sys.EntitiesData." - ~ member ~ "))*)(cast(void*) block + info.deltas[ data.system.m_components[" - ~ req.to!string ~ "]]))[0 .. block.entities_count];"; - req++; + absen++; + has_att = true; + break; } } - } - } - return ret; - } - - static void callUpdate(ref CallData data, void* entity) - { - static if (hasMember!(Sys, "update")) - { - Sys* s = cast(Sys*) data.system.m_system_pointer; - - /*void*[] pointers = (cast(void**) alloca(data.system.m_components.length * (void*) - .sizeof))[0 .. data.system.m_components.length]; - void*[] optional_pointers = (cast(void**) alloca( - data.system.m_optional_components.length * (void*).sizeof))[0 - .. data.system.m_optional_components.length];*/ - - Sys.EntitiesData input_data; - - EntitiesBlock* block = data.info.first_block; - while (block !is null) - { - EntityInfo* info = block.type_info; - /*Entity[] id_array = (cast(Entity*) block.dataBegin())[0 - .. block.entities_count];*/ - //mixin(genArrays()); - - mixin(genFillInputData()); - - s.update(input_data); - /*foreach (i; 0 .. block.entities_count) + if (!has_att) { - mixin(genCall()); - }*/ - - block = block.next_block; - } - - } - } - } - else - { - static void callUpdate(ref CallData data, void* entity) - { - static if (hasMember!(Sys, "update")) - { - Sys* s = cast(Sys*) data.system.m_system_pointer; - - void*[] pointers = (cast(void**) alloca(data.system.m_components.length * (void*) - .sizeof))[0 .. data.system.m_components.length]; - void*[] optional_pointers = (cast(void**) alloca( - data.system.m_optional_components.length * (void*).sizeof))[0 - .. data.system.m_optional_components.length]; - - EntitiesBlock* block = data.info.first_block; - while (block !is null) - { - EntityInfo* info = block.type_info; - Entity[] id_array = (cast(Entity*) block.dataBegin())[0 - .. block.entities_count]; - mixin(genArrays()); - foreach (i; 0 .. block.entities_count) - { - mixin(genCall()); - //data_pointer += EntityID.sizeof; //data.info.size; - /*foreach (ref pointer; pointers) - pointer += size; - foreach (ref pointer; optional_pointers) - if (pointer != null) - pointer += size;*/ + ret ~= "input_data." ~ member ~ " = (cast(ForeachType!(typeof(Sys.EntitiesData." ~ member + ~ "))*)(cast(void*) block + info.deltas[ data.system.m_components[" + ~ req.to!string ~ "]]))[0 .. block.entities_count];"; + req++; } - - block = block.next_block; } - } } + return ret; + } + + static void callUpdate(ref CallData data, void* entity) + { + Sys* s = cast(Sys*) data.system.m_system_pointer; + + Sys.EntitiesData input_data; + + EntitiesBlock* block = data.info.first_block; + while (block !is null) + { + EntityInfo* info = block.type_info; + + mixin(genFillInputData()); + + s.update(input_data); + + block = block.next_block; + } } system.m_update = &callUpdate; @@ -449,16 +289,7 @@ class EntityManager system.m_system_pointer = cast(void*) Mallocator.instance.make!Sys; system.m_priority = priority; - //system.m_components = Mallocator.instance.makeArray!uint(types.length - 1); - - version (InputStruct) - { - mixin(genCompList()); - } - else static if (hasMember!(Sys, "update")) - { - mixin(genCompList()); - } + mixin(genCompList()); ushort sys_id = systems_map.get(Sys.stringof, ushort.max); if (sys_id < systems.length) @@ -487,9 +318,12 @@ class EntityManager Sys.system_id = cast(ushort)(systems.length - 1); - foreach (info; &entities_infos.byValue) + if (system.m_update !is null) { - addEntityCaller(*info, cast(uint) systems.length - 1); + foreach (info; &entities_infos.byValue) + { + addEntityCaller(*info, cast(uint) systems.length - 1); + } } } diff --git a/tests/tests.d b/tests/tests.d index 3e9eee3..6947b29 100644 --- a/tests/tests.d +++ b/tests/tests.d @@ -176,18 +176,9 @@ int main() } - void update(ref Entity entity, ref TestComp test) //ref TestComp comp) + void update(ref EntitiesData data) { - assert(cast(size_t)&test % TestComp.alignof == 0); - - //writeln("High priority tekst! "); - } - - void update(ref EntitiesData data) //ref TestComp comp) - { - assert(cast(size_t)&data.test % TestComp.alignof == 0); - - //writeln("High priority tekst! "); + } /*void handleEvent(Event event, ref TestComp comp) @@ -204,11 +195,6 @@ int main() { Entity[] entity; TestComp3[] test; - - /*void a() - { - - }*/ } void onEnable() @@ -230,16 +216,8 @@ int main() } - void update(ref Entity entity, ref TestComp3 test) //ref TestComp comp) + void update(ref EntitiesData data) { - //writeln("TestSystem2 update"); - test.gg += 14; - gEM.sendSelfEvent!(TestEvent)(entity.id, TestEvent()); - } - - void update(ref EntitiesData data) //ref TestComp comp) - { - //writeln("TestSystem2 update"); foreach(i;0..data.test.length) { data.test[i].gg += 14; From 125c9e7d40f8780dc9d6e8ddb62cb9411320b0b5 Mon Sep 17 00:00:00 2001 From: Mergul Date: Mon, 1 Oct 2018 15:08:14 +0200 Subject: [PATCH 005/217] -support for 'length' parameter in EntitiesData (for convenience) --- source/ecs/manager.d | 23 +++++++++++++++++++---- source/ecs/system.d | 2 ++ tests/tests.d | 4 +++- 3 files changed, 24 insertions(+), 5 deletions(-) diff --git a/source/ecs/manager.d b/source/ecs/manager.d index 9dc7eff..11556cd 100644 --- a/source/ecs/manager.d +++ b/source/ecs/manager.d @@ -78,11 +78,17 @@ class EntityManager { static if (isFunction!(__traits(getMember, Sys.EntitiesData, member))) static assert(0, "EntitiesData can't have any function!"); + else static if(member == "length") + { + static assert(isIntegral!(typeof(__traits(getMember,Sys.EntitiesData, member))),"EntitiesData 'length' member must be integral type."); + static assert(typeof(__traits(getMember,Sys.EntitiesData, member)).sizeof > 1,"EntitiesData 'length' member can't be byte or ubyte."); + } else static if (!(isArray!(typeof(__traits(getMember, Sys.EntitiesData, member))))) static assert(0, "EntitiesData members should be arrays of elements!"); else static if (is(typeof(__traits(getMember, Sys.EntitiesData, - member)) == Entity[])) + member)) == Entity[]) || is(typeof(__traits(getMember, + Sys.EntitiesData, member)) == const(Entity)[])) { //ret ~= "const string entities_name = \"" ~ member ~ "\";"; } @@ -124,6 +130,10 @@ class EntityManager Sys.EntitiesData, member)) == const(Entity)[])) { //ret ~= "const string entities_name = \"" ~ member ~ "\";"; + } + else static if(member == "length") + { + } else { @@ -198,6 +208,11 @@ class EntityManager ret ~= "input_data." ~ member ~ " = (cast(Entity*) block.dataBegin())[0 .. block.entities_count];"; } + else if(member == "length") + { + ret ~= "input_data." ~ member + ~ " = block.entities_count;"; + } else { { @@ -306,8 +321,8 @@ class EntityManager } else { - string name = Mallocator.instance.makeArray(Sys.stringof); - systems_map.add(name, cast(ushort) systems.length); + system.name = Mallocator.instance.makeArray(Sys.stringof); + systems_map.add(system.name, cast(ushort) systems.length); systems.add(system); @@ -1240,7 +1255,7 @@ class EntityManager Vector!ubyte change_entities_list; HashMap!(ushort[], EntityInfo*) entities_infos; - HashMap!(string, ushort) systems_map; + HashMap!(const (char)[], ushort) systems_map; HashMap!(string, ushort) components_map; HashMap!(string, ushort) events_map; Vector!System systems; diff --git a/source/ecs/system.d b/source/ecs/system.d index 1276d86..b202d94 100644 --- a/source/ecs/system.d +++ b/source/ecs/system.d @@ -38,6 +38,8 @@ package: ///pointer to system implementation void* m_system_pointer; + const (char)[] name; + ushort[] m_components; ushort[] m_absen_components; ushort[] m_optional_components; diff --git a/tests/tests.d b/tests/tests.d index 6947b29..8cdc402 100644 --- a/tests/tests.d +++ b/tests/tests.d @@ -127,6 +127,7 @@ int main() static struct EntitiesData { + size_t length; TestComp[] test; TestComp2[] test2; @optional TestComp3[] test3; @@ -147,7 +148,7 @@ int main() void update(ref EntitiesData data) { - foreach(i;0..data.test.length) + foreach(i;0..data.length) { data.test[i].a += 1000; data.test[i].b += 2000; @@ -193,6 +194,7 @@ int main() static struct EntitiesData { + short length; Entity[] entity; TestComp3[] test; } From e4573f1ec7facdaeea1583a70dd424538356e291 Mon Sep 17 00:00:00 2001 From: Mergul Date: Mon, 1 Oct 2018 17:17:40 +0200 Subject: [PATCH 006/217] -better compile time code generation -support for AbsenComponents. Absen components can't exist in entity which are used by system. There are three possibilities to add absen component. Add '@absen' property to EntitiesData mebmer, create AbsenComponents enum with fields names corresponding to components names, or create AbsenComponents AliasSeq with strings expressions corresponding to components names. --- source/ecs/manager.d | 97 ++++++++++++++++++++++++++++++++------------ tests/tests.d | 25 +++++++++++- 2 files changed, 93 insertions(+), 29 deletions(-) diff --git a/source/ecs/manager.d b/source/ecs/manager.d index 11556cd..ffa53f6 100644 --- a/source/ecs/manager.d +++ b/source/ecs/manager.d @@ -73,7 +73,7 @@ class EntityManager static string genCompList()() { - string ret = "ushort comp;uint req;uint opt;uint absen;"; + static foreach (member; __traits(allMembers, Sys.EntitiesData)) { static if (isFunction!(__traits(getMember, Sys.EntitiesData, member))) @@ -86,11 +86,20 @@ class EntityManager else static if (!(isArray!(typeof(__traits(getMember, Sys.EntitiesData, member))))) static assert(0, "EntitiesData members should be arrays of elements!"); - else static if (is(typeof(__traits(getMember, Sys.EntitiesData, + } + + string ret;// = "ushort comp;uint req;uint opt;uint absen;"; + + uint req; + uint opt; + uint absen; + foreach (member; __traits(allMembers, Sys.EntitiesData)) + { + if (member == "length" || is(typeof(__traits(getMember, Sys.EntitiesData, member)) == Entity[]) || is(typeof(__traits(getMember, Sys.EntitiesData, member)) == const(Entity)[])) { - //ret ~= "const string entities_name = \"" ~ member ~ "\";"; + } else { @@ -101,44 +110,72 @@ class EntityManager { if (att == "optional") { - ret ~= "opt++;"; + //ret ~= "opt++;"; + opt++; has_att = true; break; } else if (att == "absen") { - ret ~= "absen++;"; + absen++; + //ret ~= "absen++;"; has_att = true; break; } } - if (!has_att) - ret ~= "req++;"; + if (!has_att)req++; + //ret ~= "req++;"; } } } - ret ~= "system.m_components = Mallocator.instance.makeArray!ushort(req);"; - ret ~= "system.m_optional_components = Mallocator.instance.makeArray!ushort(opt);"; - ret ~= "system.m_absen_components = Mallocator.instance.makeArray!ushort(absen);"; - ret ~= "opt = 0;req = 0;absen = 0;"; - - static foreach (member; __traits(allMembers, Sys.EntitiesData)) + static if(__traits(hasMember, Sys, "AbsenComponents")) { - static if (is(typeof(__traits(getMember, Sys.EntitiesData, + static if(is(Sys.AbsenComponents == enum)) + { + absen += (Fields!(Sys.AbsenComponents)).length;//static assert(0,"Enum AbsenComponents are not implemented yet."); + } + else static if(__traits(compiles,allSameType!(string,typeof(Sys.AbsenComponents))) && allSameType!(string,typeof(Sys.AbsenComponents)) && + isExpressions!(Sys.AbsenComponents)) + { + absen += Sys.AbsenComponents.length; + } + } + + if(req > 0)ret ~= "system.m_components = Mallocator.instance.makeArray!ushort("~req.to!string~");"; + if(opt > 0)ret ~= "system.m_optional_components = Mallocator.instance.makeArray!ushort("~opt.to!string~");"; + if(absen > 0)ret ~= "system.m_absen_components = Mallocator.instance.makeArray!ushort("~absen.to!string~");"; + ret ~= "ushort comp;";//uint opt = 0;uint req = 0;uint absen = 0;"; + + opt = 0; + req = 0; + absen = 0; + + static if(__traits(hasMember, Sys, "AbsenComponents")) + { + static if(is(Sys.AbsenComponents == enum)) + { + //static assert(0,"Enum AbsenComponents are not implemented yet."); + foreach(str;Fields!(Sys.AbsenComponents))ret ~= "system.m_absen_components["~(absen++).to!string~"] = components_map.get(\""~str.stringof~"\", ushort.max);"; + } + else static if(__traits(compiles,allSameType!(string,typeof(Sys.AbsenComponents))) && allSameType!(string,typeof(Sys.AbsenComponents)) && + isExpressions!(Sys.AbsenComponents)) + { + foreach(str;Sys.AbsenComponents)ret ~= "system.m_absen_components["~(absen++).to!string~"] = components_map.get(\""~str~"\", ushort.max);"; + } + } + + foreach (member; __traits(allMembers, Sys.EntitiesData)) + { + if (member == "length" || is(typeof(__traits(getMember, Sys.EntitiesData, member)) == Entity[]) || is(typeof(__traits(getMember, Sys.EntitiesData, member)) == const(Entity)[])) - { - //ret ~= "const string entities_name = \"" ~ member ~ "\";"; - } - else static if(member == "length") { } else { { - ret ~= "{comp = components_map.get(Unqual!(ForeachType!(typeof( Sys.EntitiesData." ~ member ~ "))) .stringof, ushort.max);\n @@ -156,20 +193,20 @@ class EntityManager { if (att == "optional") { - ret ~= "system.m_optional_components[opt++] = comp;}"; + ret ~= "system.m_optional_components["~(opt++).to!string~"] = comp;}"; has_att = true; break; } else if (att == "absen") { - ret ~= "system.m_absen_components[absen++] = comp;}"; + ret ~= "system.m_absen_components["~(absen++).to!string~"] = comp;}"; has_att = true; break; } } if (!has_att) { - ret ~= "system.m_components[req++] = comp;}"; + ret ~= "system.m_components["~(req++).to!string~"] = comp;}"; } } } @@ -586,6 +623,17 @@ class EntityManager ushort[] deltas = (cast(ushort*) alloca(num * ushort.sizeof))[0 .. num]; uint delta_id = 0; + if(system.m_absen_components) + { + foreach (id; system.m_absen_components) + { + foreach (id2; entity.components) + { + if(id == id2)return; + } + } + } + foreach (id; system.m_components) { deltas[delta_id] = ushort.max; @@ -618,11 +666,6 @@ class EntityManager break; } } - /*if (deltas[delta_id] == ushort.max) - { - deltas = null; - break; - }*/ delta_id++; } diff --git a/tests/tests.d b/tests/tests.d index 8cdc402..f2f0be0 100644 --- a/tests/tests.d +++ b/tests/tests.d @@ -131,7 +131,7 @@ int main() TestComp[] test; TestComp2[] test2; @optional TestComp3[] test3; - @absen TestComp4[] test4; + //@absen TestComp4[] test4; } void update(ref Entity entity, ref TestComp test, ref TestComp2 test2)//, TestComp3* test3) //ref TestComp comp) @@ -188,15 +188,28 @@ int main() }*/ } +import std.meta; + struct TestSystem2 { __gshared ushort system_id; + enum AbsenComponents0 + { + TestComp, + TestComp4 + } + + alias AbsenComponents = AliasSeq!("TestComp", "TestComp4"); + + string AbsenComponents2; + static struct EntitiesData { short length; Entity[] entity; TestComp3[] test; + //@absen TestComp[] testt; } void onEnable() @@ -225,7 +238,15 @@ int main() data.test[i].gg += 14; gEM.sendSelfEvent!(TestEvent)(data.entity[i].id, TestEvent()); } - + } + + void lateUpdate(ref EntitiesData data) + { + foreach(i;0..data.test.length) + { + data.test[i].gg -= 1; + gEM.sendSelfEvent!(TestEvent)(data.entity[i].id, TestEvent()); + } } /*void handleEvent(Event event, ref TestComp comp) From 288ad4c6cd81d26c17e3f0439637984d8c67b441 Mon Sep 17 00:00:00 2001 From: Mergul Date: Mon, 1 Oct 2018 17:29:43 +0200 Subject: [PATCH 007/217] -removed unused CallData.deltas member --- source/ecs/manager.d | 38 +++----------------------------------- 1 file changed, 3 insertions(+), 35 deletions(-) diff --git a/source/ecs/manager.d b/source/ecs/manager.d index ffa53f6..1d17aa6 100644 --- a/source/ecs/manager.d +++ b/source/ecs/manager.d @@ -618,10 +618,7 @@ class EntityManager export void addEntityCaller(ref EntityInfo entity, uint system_id) { System* system = &systems[system_id]; - CallData call_data = CallData(system_id, system, &entity, null); - uint num = cast(uint)(system.m_components.length + system.m_optional_components.length); - ushort[] deltas = (cast(ushort*) alloca(num * ushort.sizeof))[0 .. num]; - uint delta_id = 0; + CallData call_data = CallData(system_id, system, &entity); if(system.m_absen_components) { @@ -636,41 +633,14 @@ class EntityManager foreach (id; system.m_components) { - deltas[delta_id] = ushort.max; foreach (i2, id2; entity.components) { - if (id2 == id) - { - deltas[delta_id] = entity.deltas[id2]; - break; - } + if (id2 == id)goto is_; } - if (deltas[delta_id] == ushort.max) - { - deltas = null; - break; - } - delta_id++; - } - if (deltas is null) return; - - foreach (id; system.m_optional_components) - { - deltas[delta_id] = ushort.max; - foreach (i2, id2; entity.components) - { - if (id2 == id) - { - deltas[delta_id] = entity.deltas[id2]; - break; - } - } - delta_id++; + is_: } - call_data.deltas = Mallocator.instance.makeArray(deltas); //Mallocator.instance.makeArray!ushort(system.m_components.length); - uint index = 0; for (; index < entity.callers.length; index++) { @@ -1272,8 +1242,6 @@ class EntityManager System* system; ///poiner to Entity type info EntityManager.EntityInfo* info; - ///deltas for components - ushort[] deltas; //unused in linear-layout } alias SytemFuncType = void function(ref EntityManager.CallData data, void* entity); From 437c672478138e9de32c929968a0eae447c09dde Mon Sep 17 00:00:00 2001 From: Mergul Date: Mon, 1 Oct 2018 19:40:24 +0200 Subject: [PATCH 008/217] -documentation --- source/ecs/attributes.d | 2 + source/ecs/entity.d | 23 +++++++++++ source/ecs/id_manager.d | 23 ++++++++++- source/ecs/manager.d | 91 ++++++++++++++++++++++++++++++++++++++++- source/ecs/system.d | 19 +++++++++ 5 files changed, 154 insertions(+), 4 deletions(-) diff --git a/source/ecs/attributes.d b/source/ecs/attributes.d index 67c09c1..69667ec 100644 --- a/source/ecs/attributes.d +++ b/source/ecs/attributes.d @@ -1,4 +1,6 @@ module ecs.attributes; +///Used to mark optional components for system. enum optional = "optional"; +///Used to mark absen components for system. Enum 'AbsenComponents' should be used instead of it. enum absen = "absen"; \ No newline at end of file diff --git a/source/ecs/entity.d b/source/ecs/entity.d index d23bab6..854385a 100644 --- a/source/ecs/entity.d +++ b/source/ecs/entity.d @@ -2,21 +2,36 @@ module ecs.entity; import ecs.manager; +/************************************************************************************************************************ +*Entity ID structure. +*/ struct EntityID { + ///Index to entity in IDManager. uint id; + ///Counter required for reusing ID. uint counter; } +/************************************************************************************************************************ +*Structure of Entity. It's have only ID, but have full konwlege to get to components memory (If pointer to it is proper). +*/ struct Entity { + ///Entity ID. EntityID id; + /************************************************************************************************************************ + *Update pointer to it in IDManager + */ void updateID() { EntityManager.instance.id_manager.update(this); } + /************************************************************************************************************************ + *Get specified component. If component doesn't exist function retun null. + */ T* getComponent(T)() const { EntityManager.EntitiesBlock* block = gEM.getMetaData(&this); @@ -32,11 +47,19 @@ struct Entity } } +/************************************************************************************************************************ +*Entity template structure. +*/ export struct EntityTemplate { + ///Entity components data ubyte[] entity_data; + ///Pointer to entity type info. EntityManager.EntityInfo* info; + /************************************************************************************************************************ + *Get specified component. If component doesn't exist function return null. + */ T* getComponent(T)() { if(T.component_id >= info.tmpl_deltas.length)return null; diff --git a/source/ecs/id_manager.d b/source/ecs/id_manager.d index 86542e3..cd2fbb7 100644 --- a/source/ecs/id_manager.d +++ b/source/ecs/id_manager.d @@ -3,8 +3,14 @@ module ecs.id_manager; import ecs.entity; import ecs.vector; +/************************************************************************************************************************ +*IDManager is responsible for assignment and removing IDs. IDs are unique throughtout a whole duration of the program. +*/ struct IDManager { + /************************************************************************************************************************ + *Get new ID. + */ EntityID getNewID() { if (m_next_id >= m_ids_array.length) @@ -18,6 +24,9 @@ struct IDManager return id; } + /************************************************************************************************************************ + *Release ID. + */ void releaseID(EntityID id) { Data* data = &m_ids_array[id.id]; @@ -29,11 +38,17 @@ struct IDManager m_next_id = id.id; } + /************************************************************************************************************************ + *Update pointer to entity. The purpose of this function is to ensure that pointer to entity is always correct. + */ void update(ref Entity entity) { if(entity.id.counter == m_ids_array[entity.id.id].counter)m_ids_array[entity.id.id].entity = &entity; } + /************************************************************************************************************************ + *Returns pointer to entity. + */ export Entity* getEntityPointer(EntityID id) { Data* data = &m_ids_array[id.id]; @@ -43,20 +58,24 @@ struct IDManager return data.entity; } + /************************************************************************************************************************ + *Check if entity with specified ID exist. + */ export bool isExist(EntityID id) { Data* data = &m_ids_array[id.id]; return data.counter == id.counter; } - struct Data + private static struct Data { uint counter = 0; uint next_id = uint.max; Entity* entity = null; } - private uint m_next_id = 0; +private: + uint m_next_id; Vector!Data m_ids_array; } diff --git a/source/ecs/manager.d b/source/ecs/manager.d index 1d17aa6..95fd7b0 100644 --- a/source/ecs/manager.d +++ b/source/ecs/manager.d @@ -49,12 +49,23 @@ class EntityManager instance = null; } + /************************************************************************************************************************ + *Default constructor. + */ this() { //event_manager = EventManager(this); //event_manager.manager = this; } + /************************************************************************************************************************ + *Register new System into EntityManager. This funcion generate glue between EntityManager and System. + *Systems can be registered from external dynamic library, and can be registered after adding entities too. + *System mustn't be registered before components which system want to use, in this case functions call assertion. + * + *params: + *priority = system priority. Priority determines order of execution of systems updates. + */ void registerSystem(Sys)(int priority) { alias STC = ParameterStorageClass; @@ -392,6 +403,9 @@ class EntityManager return cast(Sys*) systems[Sys.system_id].m_system_pointer; } + /************************************************************************************************************************ + *Register component into EntityManager. + */ void registerComponent(Comp)() { ComponentInfo info; @@ -469,6 +483,9 @@ class EntityManager } } + /************************************************************************************************************************ + *Update systems. Should be called only between begin() and end(). + */ export void update() { foreach (info; &entities_infos.byValue) @@ -486,10 +503,10 @@ class EntityManager num = cast(ushort)((num + alignment - 1) & (-cast(int) alignment)); //num += alignment - (num & (alignment - 1)); } - static ushort alignedNum(ushort num, ushort alignment) + /*static ushort alignedNum(ushort num, ushort alignment) { return cast(ushort)((num + alignment - 1) & (-cast(int) alignment)); - } + }*/ extern (C) static int compareUShorts(const void* a, const void* b) { @@ -503,6 +520,12 @@ class EntityManager return 1; } + /************************************************************************************************************************ + *Allocate EntityTemplate with specifed components and returns pointer to it. + * + *params: + *components_ids = array of components allocated with template + */ export EntityTemplate* allocateTemplate(ushort[] components_ids) { @@ -541,6 +564,12 @@ class EntityManager return temp; } + /************************************************************************************************************************ + *Returns entity type info. + * + *params: + *ids = array of components + */ export EntityInfo* getEntityInfo(ushort[] ids) { EntityInfo* info = entities_infos.get(ids, null); @@ -651,11 +680,24 @@ class EntityManager entity.callers.add(call_data, index); } + /************************************************************************************************************************ + *Returns pointer to entity. + * + *params: + *id = ID of entity + */ export Entity* getEntity(EntityID id) { return cast(Entity*) id_manager.getEntityPointer(id); } + /************************************************************************************************************************ + *Remove components from entity by IDs. Components will be removed on end of frame. + * + *params: + *entity_id = ID of entity + *del_ids = array of components IDs + */ export void removeComponents(EntityID entity_id, ushort[] del_ids) { uint num = cast(uint) del_ids.length; @@ -725,6 +767,13 @@ class EntityManager removeEntityNoID(entity, block); } + /************************************************************************************************************************ + *Remove coponents from entity. + * + *params: + *Compoenents = components types to remove + *entity_id = ID of entity + */ void removeComponents(Components...)(EntityID entity_id) { const uint num = Components.length; @@ -861,6 +910,13 @@ class EntityManager removeEntityNoID(entity, block); } + /************************************************************************************************************************ + *Add components to entity. Components will be added on end of frame. + * + *params: + *entity_id = ID of entity to remove + *tmpl = pointer entity template allocated by EntityManager. + */ void addComponents(Components...)(const EntityID entity_id, Components comps) { const uint num = Components.length; @@ -895,12 +951,24 @@ class EntityManager //__addComponents(entity_id, new_ids, pointers); } + /************************************************************************************************************************ + *Free template memory. + * + *params: + *tmpl = pointer entity template allocated by EntityManager. + */ export void freeTemplate(EntityTemplate* template_) { Mallocator.instance.dispose(template_.entity_data); Mallocator.instance.dispose(template_); } + /************************************************************************************************************************ + *Add entity to system. + * + *params: + *tmpl = pointer entity template allocated by EntityManager. + */ export ref Entity addEntity(EntityTemplate* tmpl) { EntitiesBlock* block = findBlockWithFreeSpace(tmpl.info); @@ -969,6 +1037,12 @@ class EntityManager return block; } + /************************************************************************************************************************ + *Remove entity by ID. Entity will be removed on frame end. + * + *params: + *id = id of entity to remove + */ export void removeEntity(EntityID id) { entities_to_remove.add(id); @@ -1125,6 +1199,9 @@ class EntityManager entities_to_remove.clear(); } + /************************************************************************************************************************ + *Begin of update process. Should be called before any update is called. + */ export void begin() { updateBlocks(); @@ -1137,6 +1214,9 @@ class EntityManager } } + /************************************************************************************************************************ + *End of update process. Should be called after every update function. + */ export void end() { foreach (ref system; instance.systems) @@ -1151,11 +1231,18 @@ class EntityManager //clearEvents(); } + /************************************************************************************************************************ + *Component info; + */ struct ComponentInfo { + ///Component size ushort size; + ///Component data alignment ushort alignment; + ///Initialization data ubyte[] init_data; + ///Pointer to component destroy callback void function(void* pointer) destroy_callback; } diff --git a/source/ecs/system.d b/source/ecs/system.d index b202d94..38722e4 100644 --- a/source/ecs/system.d +++ b/source/ecs/system.d @@ -3,13 +3,22 @@ module ecs.system; import ecs.entity; import ecs.manager; +/************************************************************************************************************************ +*System contain data required to proper glue EntityManager with Systems. +*/ struct System { + /************************************************************************************************************************ + *Check if system is enabled. + */ export bool enabled() { return m_enabled; } + /************************************************************************************************************************ + *Enable system. If actually it is enabled function do nothing. + */ export void enable() { if (!m_enabled && m_enable) @@ -17,6 +26,9 @@ struct System m_enabled = true; } + /************************************************************************************************************************ + *Disable system. If actually it is disabled function do nothing. + */ export void disable() { if (m_enabled && m_disable) @@ -24,6 +36,9 @@ struct System m_enabled = false; } + /************************************************************************************************************************ + *Get system priority. + */ export int priority() { return m_priority; @@ -38,10 +53,14 @@ package: ///pointer to system implementation void* m_system_pointer; + ///system name const (char)[] name; + ///required components ushort[] m_components; + ///absen components ushort[] m_absen_components; + ///optional components ushort[] m_optional_components; //void function(ref EntityManager.CallData data, void* entity) update; From 2004909642e07c3d7c4a9f8d675566723a733b7e Mon Sep 17 00:00:00 2001 From: Mergul Date: Mon, 1 Oct 2018 22:11:27 +0200 Subject: [PATCH 009/217] -sorting components ids in systems -changed callUpdate() prototype --- source/ecs/manager.d | 10 +++++++--- source/ecs/system.d | 7 +++++-- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/source/ecs/manager.d b/source/ecs/manager.d index 95fd7b0..c315979 100644 --- a/source/ecs/manager.d +++ b/source/ecs/manager.d @@ -302,7 +302,7 @@ class EntityManager return ret; } - static void callUpdate(ref CallData data, void* entity) + static void callUpdate(ref CallData data) { Sys* s = cast(Sys*) data.system.m_system_pointer; @@ -354,6 +354,10 @@ class EntityManager mixin(genCompList()); + if(system.m_components)qsort(system.m_components.ptr, system.m_components.length, ushort.sizeof, &compareUShorts); + if(system.m_optional_components)qsort(system.m_optional_components.ptr, system.m_optional_components.length, ushort.sizeof, &compareUShorts); + if(system.m_absen_components)qsort(system.m_absen_components.ptr, system.m_absen_components.length, ushort.sizeof, &compareUShorts); + ushort sys_id = systems_map.get(Sys.stringof, ushort.max); if (sys_id < systems.length) { @@ -493,7 +497,7 @@ class EntityManager foreach (data; info.callers) { if (data.system.enabled) - (cast(SytemFuncType) data.system.m_update)(data, null); //caller(call_data,null); + (cast(SytemFuncType) data.system.m_update)(data); //caller(call_data,null); } } } @@ -1331,7 +1335,7 @@ class EntityManager EntityManager.EntityInfo* info; } - alias SytemFuncType = void function(ref EntityManager.CallData data, void* entity); + alias SytemFuncType = void function(ref EntityManager.CallData data); //alias sendSelfEvent = instance.event_manager.sendSelfEvent; diff --git a/source/ecs/system.d b/source/ecs/system.d index 38722e4..421321d 100644 --- a/source/ecs/system.d +++ b/source/ecs/system.d @@ -63,8 +63,8 @@ package: ///optional components ushort[] m_optional_components; - //void function(ref EntityManager.CallData data, void* entity) update; - void* m_update; ///workaroud for DMD bug with upper line + void function(ref EntityManager.CallData data) m_update; + //void* m_update; ///workaroud for DMD bug with upper line void function(void* system_pointer) m_enable; void function(void* system_pointer) m_disable; @@ -74,4 +74,7 @@ package: void function(void* system_pointer) m_begin; void function(void* system_pointer) m_end; + + void function(ref EntityManager.CallData data) m_initialize; + void function(ref EntityManager.CallData data) m_deinitilize; } From fddfc78ec1e61d0ccc053985ddadbb34fb70f8ec Mon Sep 17 00:00:00 2001 From: Mergul Date: Tue, 2 Oct 2018 15:36:00 +0200 Subject: [PATCH 010/217] -removed system components sorting due to fact that it's make an issue -workaround for DMD phobos issues --- source/ecs/attributes.d | 4 +-- source/ecs/manager.d | 58 ++++++++++++++++++++--------------------- source/ecs/system.d | 14 +++++----- tests/tests.d | 10 +++---- 4 files changed, 44 insertions(+), 42 deletions(-) diff --git a/source/ecs/attributes.d b/source/ecs/attributes.d index 69667ec..4068a06 100644 --- a/source/ecs/attributes.d +++ b/source/ecs/attributes.d @@ -2,5 +2,5 @@ module ecs.attributes; ///Used to mark optional components for system. enum optional = "optional"; -///Used to mark absen components for system. Enum 'AbsenComponents' should be used instead of it. -enum absen = "absen"; \ No newline at end of file +///Used to mark absent components for system. Enum 'AbsentComponents' should be used instead of it. +enum absent = "absent"; \ No newline at end of file diff --git a/source/ecs/manager.d b/source/ecs/manager.d index c315979..95a31d6 100644 --- a/source/ecs/manager.d +++ b/source/ecs/manager.d @@ -99,11 +99,11 @@ class EntityManager static assert(0, "EntitiesData members should be arrays of elements!"); } - string ret;// = "ushort comp;uint req;uint opt;uint absen;"; + string ret;// = "ushort comp;uint req;uint opt;uint absent;"; uint req; uint opt; - uint absen; + uint absent; foreach (member; __traits(allMembers, Sys.EntitiesData)) { if (member == "length" || is(typeof(__traits(getMember, Sys.EntitiesData, @@ -126,9 +126,9 @@ class EntityManager has_att = true; break; } - else if (att == "absen") + else if (att == "absent") { - absen++; + absent++; //ret ~= "absen++;"; has_att = true; break; @@ -140,39 +140,39 @@ class EntityManager } } - static if(__traits(hasMember, Sys, "AbsenComponents")) + static if(__traits(hasMember, Sys, "AbsentComponents")) { - static if(is(Sys.AbsenComponents == enum)) + static if(is(Sys.AbsentComponents == enum)) { - absen += (Fields!(Sys.AbsenComponents)).length;//static assert(0,"Enum AbsenComponents are not implemented yet."); + absent += (Fields!(Sys.AbsentComponents)).length;//static assert(0,"Enum AbsentComponents are not implemented yet."); } - else static if(__traits(compiles,allSameType!(string,typeof(Sys.AbsenComponents))) && allSameType!(string,typeof(Sys.AbsenComponents)) && - isExpressions!(Sys.AbsenComponents)) + else static if(__traits(compiles,allSameType!(string,typeof(Sys.AbsentComponents))) && allSameType!(string,typeof(Sys.AbsentComponents)) && + isExpressions!(Sys.AbsentComponents)) { - absen += Sys.AbsenComponents.length; + absent += Sys.AbsentComponents.length; } } if(req > 0)ret ~= "system.m_components = Mallocator.instance.makeArray!ushort("~req.to!string~");"; if(opt > 0)ret ~= "system.m_optional_components = Mallocator.instance.makeArray!ushort("~opt.to!string~");"; - if(absen > 0)ret ~= "system.m_absen_components = Mallocator.instance.makeArray!ushort("~absen.to!string~");"; - ret ~= "ushort comp;";//uint opt = 0;uint req = 0;uint absen = 0;"; + if(absent > 0)ret ~= "system.m_absent_components = Mallocator.instance.makeArray!ushort("~absent.to!string~");"; + ret ~= "ushort comp;";//uint opt = 0;uint req = 0;uint absent = 0;"; opt = 0; req = 0; - absen = 0; + absent = 0; - static if(__traits(hasMember, Sys, "AbsenComponents")) + static if(__traits(hasMember, Sys, "AbsentComponents")) { - static if(is(Sys.AbsenComponents == enum)) + static if(is(Sys.AbsentComponents == enum)) { - //static assert(0,"Enum AbsenComponents are not implemented yet."); - foreach(str;Fields!(Sys.AbsenComponents))ret ~= "system.m_absen_components["~(absen++).to!string~"] = components_map.get(\""~str.stringof~"\", ushort.max);"; + //static assert(0,"Enum AbsentComponents are not implemented yet."); + foreach(str;Fields!(Sys.AbsentComponents))ret ~= "system.m_absent_components["~(absent++).to!string~"] = components_map.get(\""~str.stringof~"\", ushort.max);"; } - else static if(__traits(compiles,allSameType!(string,typeof(Sys.AbsenComponents))) && allSameType!(string,typeof(Sys.AbsenComponents)) && - isExpressions!(Sys.AbsenComponents)) + else static if(__traits(compiles,allSameType!(string,typeof(Sys.AbsentComponents))) && allSameType!(string,typeof(Sys.AbsentComponents)) && + isExpressions!(Sys.AbsentComponents)) { - foreach(str;Sys.AbsenComponents)ret ~= "system.m_absen_components["~(absen++).to!string~"] = components_map.get(\""~str~"\", ushort.max);"; + foreach(str;Sys.AbsentComponents)ret ~= "system.m_absent_components["~(absent++).to!string~"] = components_map.get(\""~str~"\", ushort.max);"; } } @@ -208,9 +208,9 @@ class EntityManager has_att = true; break; } - else if (att == "absen") + else if (att == "absent") { - ret ~= "system.m_absen_components["~(absen++).to!string~"] = comp;}"; + ret ~= "system.m_absent_components["~(absent++).to!string~"] = comp;}"; has_att = true; break; } @@ -246,7 +246,7 @@ class EntityManager ushort comp; uint req = 0; uint opt = 0; - uint absen = 0; + uint absent = 0; foreach (member; __traits(allMembers, Sys.EntitiesData)) { if (is(typeof(__traits(getMember, Sys.EntitiesData, @@ -282,9 +282,9 @@ class EntityManager has_att = true; break; } - else if (att == "absen") + else if (att == "absent") { - absen++; + absent++; has_att = true; break; } @@ -354,9 +354,9 @@ class EntityManager mixin(genCompList()); - if(system.m_components)qsort(system.m_components.ptr, system.m_components.length, ushort.sizeof, &compareUShorts); + /*if(system.m_components)qsort(system.m_components.ptr, system.m_components.length, ushort.sizeof, &compareUShorts); if(system.m_optional_components)qsort(system.m_optional_components.ptr, system.m_optional_components.length, ushort.sizeof, &compareUShorts); - if(system.m_absen_components)qsort(system.m_absen_components.ptr, system.m_absen_components.length, ushort.sizeof, &compareUShorts); + if(system.m_absent_components)qsort(system.m_absent_components.ptr, system.m_absent_components.length, ushort.sizeof, &compareUShorts);*/ ushort sys_id = systems_map.get(Sys.stringof, ushort.max); if (sys_id < systems.length) @@ -653,9 +653,9 @@ class EntityManager System* system = &systems[system_id]; CallData call_data = CallData(system_id, system, &entity); - if(system.m_absen_components) + if(system.m_absent_components) { - foreach (id; system.m_absen_components) + foreach (id; system.m_absent_components) { foreach (id2; entity.components) { diff --git a/source/ecs/system.d b/source/ecs/system.d index 421321d..b13c60a 100644 --- a/source/ecs/system.d +++ b/source/ecs/system.d @@ -58,13 +58,13 @@ package: ///required components ushort[] m_components; - ///absen components - ushort[] m_absen_components; + ///absent components + ushort[] m_absent_components; ///optional components ushort[] m_optional_components; - void function(ref EntityManager.CallData data) m_update; - //void* m_update; ///workaroud for DMD bug with upper line + //void function(ref EntityManager.CallData data) m_update; + void* m_update; ///workaroud for DMD bug with upper line void function(void* system_pointer) m_enable; void function(void* system_pointer) m_disable; @@ -75,6 +75,8 @@ package: void function(void* system_pointer) m_begin; void function(void* system_pointer) m_end; - void function(ref EntityManager.CallData data) m_initialize; - void function(ref EntityManager.CallData data) m_deinitilize; + //void function(ref EntityManager.CallData data) m_initialize; + //void function(ref EntityManager.CallData data) m_deinitilize; + void* m_initialize; + void* m_deinitilize; } diff --git a/tests/tests.d b/tests/tests.d index f2f0be0..86c48fb 100644 --- a/tests/tests.d +++ b/tests/tests.d @@ -131,7 +131,7 @@ int main() TestComp[] test; TestComp2[] test2; @optional TestComp3[] test3; - //@absen TestComp4[] test4; + //@absent TestComp4[] test4; } void update(ref Entity entity, ref TestComp test, ref TestComp2 test2)//, TestComp3* test3) //ref TestComp comp) @@ -194,22 +194,22 @@ import std.meta; { __gshared ushort system_id; - enum AbsenComponents0 + enum AbsentComponents0 { TestComp, TestComp4 } - alias AbsenComponents = AliasSeq!("TestComp", "TestComp4"); + alias AbsentComponents = AliasSeq!("TestComp", "TestComp4"); - string AbsenComponents2; + string AbsentComponents2; static struct EntitiesData { short length; Entity[] entity; TestComp3[] test; - //@absen TestComp[] testt; + //@absent TestComp[] testt; } void onEnable() From 3a767babc0605cb58eeee73d6432dcf36e819bdb Mon Sep 17 00:00:00 2001 From: Mergul Date: Wed, 10 Oct 2018 18:35:20 +0200 Subject: [PATCH 011/217] -call update by Systems instead of EntityTypes (version UpdateBySystems) -memory packing (every block in EntityType except last one are always full) --- dub.json | 3 + source/ecs/manager.d | 313 +++++++++++++++++++++++++++++++------------ tests/tests.d | 8 +- 3 files changed, 232 insertions(+), 92 deletions(-) diff --git a/dub.json b/dub.json index bacb5fc..c4303f2 100755 --- a/dub.json +++ b/dub.json @@ -10,6 +10,9 @@ "dflags-posix-ldc": [ "-defaultlib=phobos2-ldc,druntime-ldc" ], + "versions": [ + "UpdateBySystems" + ], "configurations" : [ { "name" : "library", diff --git a/source/ecs/manager.d b/source/ecs/manager.d index 95a31d6..168b6a1 100644 --- a/source/ecs/manager.d +++ b/source/ecs/manager.d @@ -89,28 +89,30 @@ class EntityManager { static if (isFunction!(__traits(getMember, Sys.EntitiesData, member))) static assert(0, "EntitiesData can't have any function!"); - else static if(member == "length") + else static if (member == "length") { - static assert(isIntegral!(typeof(__traits(getMember,Sys.EntitiesData, member))),"EntitiesData 'length' member must be integral type."); - static assert(typeof(__traits(getMember,Sys.EntitiesData, member)).sizeof > 1,"EntitiesData 'length' member can't be byte or ubyte."); + static assert(isIntegral!(typeof(__traits(getMember, Sys.EntitiesData, + member))), "EntitiesData 'length' member must be integral type."); + static assert(typeof(__traits(getMember, Sys.EntitiesData, member)) + .sizeof > 1, "EntitiesData 'length' member can't be byte or ubyte."); } else static if (!(isArray!(typeof(__traits(getMember, Sys.EntitiesData, member))))) static assert(0, "EntitiesData members should be arrays of elements!"); } - string ret;// = "ushort comp;uint req;uint opt;uint absent;"; - + string ret; // = "ushort comp;uint req;uint opt;uint absent;"; + uint req; uint opt; uint absent; foreach (member; __traits(allMembers, Sys.EntitiesData)) { - if (member == "length" || is(typeof(__traits(getMember, Sys.EntitiesData, - member)) == Entity[]) || is(typeof(__traits(getMember, + if (member == "length" || is(typeof(__traits(getMember, + Sys.EntitiesData, member)) == Entity[]) || is(typeof(__traits(getMember, Sys.EntitiesData, member)) == const(Entity)[])) { - + } else { @@ -134,52 +136,66 @@ class EntityManager break; } } - if (!has_att)req++; - //ret ~= "req++;"; + if (!has_att) + req++; + //ret ~= "req++;"; } } } - static if(__traits(hasMember, Sys, "AbsentComponents")) + static if (__traits(hasMember, Sys, "AbsentComponents")) { - static if(is(Sys.AbsentComponents == enum)) + static if (is(Sys.AbsentComponents == enum)) { - absent += (Fields!(Sys.AbsentComponents)).length;//static assert(0,"Enum AbsentComponents are not implemented yet."); + absent += (Fields!(Sys.AbsentComponents)).length; //static assert(0,"Enum AbsentComponents are not implemented yet."); } - else static if(__traits(compiles,allSameType!(string,typeof(Sys.AbsentComponents))) && allSameType!(string,typeof(Sys.AbsentComponents)) && - isExpressions!(Sys.AbsentComponents)) + else static if (__traits(compiles, allSameType!(string, typeof(Sys.AbsentComponents))) + && allSameType!(string, typeof(Sys.AbsentComponents)) + && isExpressions!(Sys.AbsentComponents)) { absent += Sys.AbsentComponents.length; } } - if(req > 0)ret ~= "system.m_components = Mallocator.instance.makeArray!ushort("~req.to!string~");"; - if(opt > 0)ret ~= "system.m_optional_components = Mallocator.instance.makeArray!ushort("~opt.to!string~");"; - if(absent > 0)ret ~= "system.m_absent_components = Mallocator.instance.makeArray!ushort("~absent.to!string~");"; - ret ~= "ushort comp;";//uint opt = 0;uint req = 0;uint absent = 0;"; + if (req > 0) + ret ~= "system.m_components = Mallocator.instance.makeArray!ushort(" + ~ req.to!string ~ ");"; + if (opt > 0) + ret ~= "system.m_optional_components = Mallocator.instance.makeArray!ushort(" + ~ opt.to!string ~ ");"; + if (absent > 0) + ret ~= "system.m_absent_components = Mallocator.instance.makeArray!ushort(" + ~ absent.to!string ~ ");"; + ret ~= "ushort comp;"; //uint opt = 0;uint req = 0;uint absent = 0;"; opt = 0; req = 0; absent = 0; - static if(__traits(hasMember, Sys, "AbsentComponents")) + static if (__traits(hasMember, Sys, "AbsentComponents")) { - static if(is(Sys.AbsentComponents == enum)) + static if (is(Sys.AbsentComponents == enum)) { //static assert(0,"Enum AbsentComponents are not implemented yet."); - foreach(str;Fields!(Sys.AbsentComponents))ret ~= "system.m_absent_components["~(absent++).to!string~"] = components_map.get(\""~str.stringof~"\", ushort.max);"; + foreach (str; Fields!(Sys.AbsentComponents)) + ret ~= "system.m_absent_components[" ~ (absent++) + .to!string ~ "] = components_map.get(\"" + ~ str.stringof ~ "\", ushort.max);"; } - else static if(__traits(compiles,allSameType!(string,typeof(Sys.AbsentComponents))) && allSameType!(string,typeof(Sys.AbsentComponents)) && - isExpressions!(Sys.AbsentComponents)) + else static if (__traits(compiles, allSameType!(string, typeof(Sys.AbsentComponents))) + && allSameType!(string, typeof(Sys.AbsentComponents)) + && isExpressions!(Sys.AbsentComponents)) { - foreach(str;Sys.AbsentComponents)ret ~= "system.m_absent_components["~(absent++).to!string~"] = components_map.get(\""~str~"\", ushort.max);"; + foreach (str; Sys.AbsentComponents) + ret ~= "system.m_absent_components[" ~ (absent++) + .to!string ~ "] = components_map.get(\"" ~ str ~ "\", ushort.max);"; } } foreach (member; __traits(allMembers, Sys.EntitiesData)) { - if (member == "length" || is(typeof(__traits(getMember, Sys.EntitiesData, - member)) == Entity[]) || is(typeof(__traits(getMember, + if (member == "length" || is(typeof(__traits(getMember, + Sys.EntitiesData, member)) == Entity[]) || is(typeof(__traits(getMember, Sys.EntitiesData, member)) == const(Entity)[])) { @@ -204,20 +220,22 @@ class EntityManager { if (att == "optional") { - ret ~= "system.m_optional_components["~(opt++).to!string~"] = comp;}"; + ret ~= "system.m_optional_components[" ~ (opt++) + .to!string ~ "] = comp;}"; has_att = true; break; } else if (att == "absent") { - ret ~= "system.m_absent_components["~(absent++).to!string~"] = comp;}"; + ret ~= "system.m_absent_components[" ~ (absent++) + .to!string ~ "] = comp;}"; has_att = true; break; } } if (!has_att) { - ret ~= "system.m_components["~(req++).to!string~"] = comp;}"; + ret ~= "system.m_components[" ~ (req++).to!string ~ "] = comp;}"; } } } @@ -256,10 +274,9 @@ class EntityManager ret ~= "input_data." ~ member ~ " = (cast(Entity*) block.dataBegin())[0 .. block.entities_count];"; } - else if(member == "length") + else if (member == "length") { - ret ~= "input_data." ~ member - ~ " = block.entities_count;"; + ret ~= "input_data." ~ member ~ " = block.entities_count;"; } else { @@ -392,6 +409,28 @@ class EntityManager addEntityCaller(*info, cast(uint) systems.length - 1); } } + + version (UpdateBySystems) + { + bool added = false; + foreach (i, ref caller; system_callers) + { + if (systems[caller.system_id].priority > priority) + { + SystemCaller* sys_caller = Mallocator.instance.make!SystemCaller; + sys_caller.system_id = Sys.system_id; + system_callers.add(sys_caller, i); + added = true; + break; + } + } + if (!added) + { + SystemCaller* sys_caller = Mallocator.instance.make!SystemCaller; + sys_caller.system_id = Sys.system_id; + system_callers.add(sys_caller); + } + } } updateEntityCallers(); @@ -492,12 +531,34 @@ class EntityManager */ export void update() { - foreach (info; &entities_infos.byValue) + version (UpdateBySystems) { - foreach (data; info.callers) + foreach (caller; system_callers) { - if (data.system.enabled) - (cast(SytemFuncType) data.system.m_update)(data); //caller(call_data,null); + System* sys = &systems[caller.system_id]; + if (sys.enabled) + { + if (sys.m_begin) + sys.m_begin(sys.m_system_pointer); + foreach (info; caller.infos) + { + CallData data = CallData(caller.system_id, sys, info); + (cast(SytemFuncType) data.system.m_update)(data); + } + if (sys.m_end) + sys.m_end(sys.m_system_pointer); + } + } + } + else + { + foreach (info; &entities_infos.byValue) + { + foreach (data; info.callers) + { + if (data.system.enabled) + (cast(SytemFuncType) data.system.m_update)(data); //caller(call_data,null); + } } } } @@ -630,6 +691,16 @@ class EntityManager addEntityCaller(*info, i); } + version (UpdateBySystems) + { + foreach (uint i, ref system; systems) + { + if (system.m_update is null) + continue; + addSystemCaller(*info, i); + } + } + updateEntityCallers(); entities_infos.add(info.components, info); @@ -648,18 +719,19 @@ class EntityManager } } - export void addEntityCaller(ref EntityInfo entity, uint system_id) + export void addSystemCaller(ref EntityInfo entity, uint system_id) { System* system = &systems[system_id]; - CallData call_data = CallData(system_id, system, &entity); + //CallData call_data = CallData(system_id, system, &entity); - if(system.m_absent_components) + if (system.m_absent_components) { foreach (id; system.m_absent_components) { foreach (id2; entity.components) { - if(id == id2)return; + if (id == id2) + return; } } } @@ -668,10 +740,56 @@ class EntityManager { foreach (i2, id2; entity.components) { - if (id2 == id)goto is_; + if (id2 == id) + goto is_; } return; - is_: + is_: + } + + uint index = 0; + for (; index < system_callers.length; index++) + { + if (system_callers[index].system_id == system_id) + break; + } + + system_callers[index].infos.add(&entity); + /*for (; index < entity.callers.length; index++) + { + CallData* caller = &entity.callers[index]; + if (caller.system.priority >= call_data.system.priority) + break; + } + entity.callers.add(call_data, index);*/ + } + + export void addEntityCaller(ref EntityInfo entity, uint system_id) + { + System* system = &systems[system_id]; + CallData call_data = CallData(system_id, system, &entity); + + if (system.m_absent_components) + { + foreach (id; system.m_absent_components) + { + foreach (id2; entity.components) + { + if (id == id2) + return; + } + } + } + + foreach (id; system.m_components) + { + foreach (i2, id2; entity.components) + { + if (id2 == id) + goto is_; + } + return; + is_: } uint index = 0; @@ -1002,7 +1120,7 @@ class EntityManager private EntitiesBlock* findBlockWithFreeSpace(EntityInfo* info) { EntitiesBlock* previous_block; - EntitiesBlock* block = info.first_with_free_space; + EntitiesBlock* block = info.last_block; while (1) { @@ -1021,7 +1139,7 @@ class EntityManager block.prev_block = previous_block; block.id = cast(ushort)(previous_block.id + 1); } - info.first_with_free_space = block; + info.last_block = block; break; // new block certainly has free space } // check if there is enought space @@ -1034,7 +1152,6 @@ class EntityManager continue; } - info.first_with_free_space = block; break; // block exists and bounds check passed } @@ -1071,11 +1188,7 @@ class EntityManager void* data_begin = block.dataBegin(); EntityInfo* info = block.type_info; - block.entities_count--; - - //set "first_with_free_space" if should it be - if (info.first_with_free_space.id > block.id) - info.first_with_free_space = block; + info.last_block.entities_count--; static if (EntityID.sizeof == 8) uint pos = cast(uint)((cast(void*) entity - data_begin) >> 3); @@ -1096,43 +1209,36 @@ class EntityManager } } + if(block !is info.last_block || pos != block.entities_count) + { + foreach (comp; info.components) + { + void* src = cast(void*) info.last_block + info.deltas[comp]; + void* dst = cast(void*) block + info.deltas[comp]; + uint size = components[comp].size; + memcpy(dst + pos * size, src + info.last_block.entities_count * size, size); + } + + block = info.last_block; + entity.id = *cast(EntityID*)(block.dataBegin() + block.entities_count * EntityID.sizeof); + + entity.updateID(); + } + + block = info.last_block; if (block.entities_count == 0) { + info.last_block = block.prev_block; if (info.first_block is block) { - info.first_block = block.next_block; - } - if (info.first_with_free_space is block) - { - info.first_with_free_space = block.next_block; //info.first_block; + info.first_block = null; } if (block.prev_block) { - block.prev_block.next_block = block.next_block; - } - if (block.next_block) - { - block.next_block.prev_block = block.prev_block; - } + block.prev_block.next_block = null; + } allocator.freeBlock(block); - return; } - - if (pos == block.entities_count) - return; - - foreach (comp; info.components) - { - void* ptr = cast(void*) block + info.deltas[comp]; - uint size = components[comp].size; - memcpy(ptr + pos * size, ptr + block.entities_count * size, size); - } - - entity.id = *cast(EntityID*)(data_begin + block.entities_count * EntityID.sizeof); - - //update pointer for moved entity ID - //entity = cast(Entity*) dst; - entity.updateID(); } /************************************************************************************************************************ @@ -1211,10 +1317,18 @@ class EntityManager updateBlocks(); removeEntities(); changeEntites(); - foreach (ref system; instance.systems) + + version (UpdateBySystems) { - if (system.m_begin) - system.m_begin(system.m_system_pointer); + + } + else + { + foreach (ref system; instance.systems) + { + if (system.m_begin) + system.m_begin(system.m_system_pointer); + } } } @@ -1223,11 +1337,19 @@ class EntityManager */ export void end() { - foreach (ref system; instance.systems) + version (UpdateBySystems) { - if (system.m_end) - system.m_end(system.m_system_pointer); + } + else + { + foreach (ref system; instance.systems) + { + if (system.m_end) + system.m_end(system.m_system_pointer); + } + } + updateBlocks(); removeEntities(); changeEntites(); @@ -1262,6 +1384,12 @@ class EntityManager */ struct EntityInfo { + ///Returns number of blocks + uint blocksCount() + { + return last_block.id; + } + ///entity components ushort[] components; @@ -1279,8 +1407,8 @@ class EntityManager ///pointer to first block/page EntitiesBlock* first_block; - ///a hint for allocations - EntitiesBlock* first_with_free_space; // a hint for allocations, should have empty space in it but doesn't have to + ///pointer to last block + EntitiesBlock* last_block; ///array of CallData. Contain data for System calls. Vector!(CallData) callers; } @@ -1335,6 +1463,15 @@ class EntityManager EntityManager.EntityInfo* info; } + struct SystemCaller + { + uint system_id; + System* system; + Vector!(EntityInfo*) infos; + } + + Vector!(SystemCaller*) system_callers; + alias SytemFuncType = void function(ref EntityManager.CallData data); //alias sendSelfEvent = instance.event_manager.sendSelfEvent; @@ -1357,7 +1494,7 @@ class EntityManager Vector!ubyte change_entities_list; HashMap!(ushort[], EntityInfo*) entities_infos; - HashMap!(const (char)[], ushort) systems_map; + HashMap!(const(char)[], ushort) systems_map; HashMap!(string, ushort) components_map; HashMap!(string, ushort) events_map; Vector!System systems; diff --git a/tests/tests.d b/tests/tests.d index 86c48fb..79a76a6 100644 --- a/tests/tests.d +++ b/tests/tests.d @@ -324,14 +324,14 @@ import std.meta; //foreach(i; 0..1_000_000)gEM.removeEntity(gEM.addEntity(tmpl).id); - EntityID[1000] idss; + EntityID[5000] idss; - foreach (i; 0 .. 1_000) + foreach (i; 0 .. 200) { gEM.begin(); - foreach (j; 0 .. 1_000) + foreach (j; 0 .. 5_000) idss[j] = gEM.addEntity(tmpl).id; - foreach (j; 0 .. 1_000) + foreach (j; 0 .. 5_000) gEM.removeEntity(idss[j]); gEM.end(); } From 5dd24b6462741a935b07a8cabad932fd18101847 Mon Sep 17 00:00:00 2001 From: Mergul Date: Sun, 14 Oct 2018 16:59:46 +0200 Subject: [PATCH 012/217] -Systems, Components and Events now must have proper mixin. Mixins are located in ecs.core module. (i.e. mixin ECS.Component) -Multithreading support: *multithreaded update - updateMT(), function generates jobs to execute *added dispatch callback function to dispatch generated jobs (setJobDispachFunc) *added getID callback for get thread ID by EntityManager -added Job structure. Job has one function "execute()". -calling partial info update (required to multithreading) -multithreaded removeEntity, addCompoenents, removeComponents. Every thread has own data and remove/change lists. -multithreaded addEntity (WIP) -fixed issue with duplicating components -simpler and faster "findBlockWithFreeSpace" function -CallDataAllocator, allocator for CallDatas (used for Jobs) -fixed some bugs/issues --- source/ecs/core.d | 29 +++ source/ecs/manager.d | 548 ++++++++++++++++++++++++++++++++++--------- source/ecs/package.d | 1 + source/ecs/system.d | 20 +- source/ecs/vector.d | 4 +- tests/tests.d | 52 ++-- 6 files changed, 519 insertions(+), 135 deletions(-) create mode 100644 source/ecs/core.d diff --git a/source/ecs/core.d b/source/ecs/core.d new file mode 100644 index 0000000..6b27d26 --- /dev/null +++ b/source/ecs/core.d @@ -0,0 +1,29 @@ +module ecs.core; + +public import ecs.manager; + +static struct ECS +{ + mixin template System(uint jobs_count = 32) + { + __gshared ushort system_id; + EntityManager.Job[] _ecs_jobs; + + void __ecsInitialize() + { + import std.experimental.allocator.mallocator; + import std.experimental.allocator; + _ecs_jobs = Mallocator.instance.makeArray!(EntityManager.Job)(jobs_count); + } + } + + mixin template Component() + { + __gshared ushort component_id; + } + + mixin template Event() + { + __gshared ushort event_id; + } +} \ No newline at end of file diff --git a/source/ecs/manager.d b/source/ecs/manager.d index 168b6a1..ec99df1 100644 --- a/source/ecs/manager.d +++ b/source/ecs/manager.d @@ -8,6 +8,7 @@ import std.traits; import core.stdc.stdlib; import core.stdc.string; +import core.atomic; import ecs.entity; import ecs.block_allocator; @@ -22,11 +23,10 @@ alias SerializeVector = ecs.vector.Vector!ubyte; class EntityManager { - - export static void initialize() + export static void initialize(uint threads_count) { if (instance is null) - instance = Mallocator.instance.make!EntityManager; + instance = Mallocator.instance.make!EntityManager(threads_count); } export static void destroy() @@ -42,7 +42,7 @@ class EntityManager foreach (ref system; instance.systems) { if (system.m_destroy) - system.m_destroy(system.m_system_pointer); + (cast(void function(void*))system.m_destroy)(system.m_system_pointer); } Mallocator.instance.dispose(instance); @@ -52,8 +52,10 @@ class EntityManager /************************************************************************************************************************ *Default constructor. */ - this() + this(uint threads_count) { + if(threads_count == 0)threads_count = 0; + threads = Mallocator.instance.makeArray!ThreadData(threads_count); //event_manager = EventManager(this); //event_manager.manager = this; } @@ -272,11 +274,11 @@ class EntityManager Sys.EntitiesData, member)) == const(Entity)[])) { ret ~= "input_data." ~ member - ~ " = (cast(Entity*) block.dataBegin())[0 .. block.entities_count];"; + ~ " = (cast(Entity*) block.dataBegin())[offset .. entities_count];"; } else if (member == "length") { - ret ~= "input_data." ~ member ~ " = block.entities_count;"; + ret ~= "input_data." ~ member ~ " = cast(typeof(input_data.length))(entities_count - offset);"; } else { @@ -292,7 +294,7 @@ class EntityManager ~ opt.to!string ~ "]] != 0)input_data." ~ member ~ " = (cast(ForeachType!(typeof(Sys.EntitiesData." ~ member ~ "))*)(cast(void*) block + info.deltas[ data.system.m_optional_components[" - ~ opt.to!string ~ "]]))[0 .. block.entities_count]; + ~ opt.to!string ~ "]]))[offset .. entities_count]; else input_data." ~ member ~ " = null;"; opt++; @@ -310,7 +312,7 @@ class EntityManager { ret ~= "input_data." ~ member ~ " = (cast(ForeachType!(typeof(Sys.EntitiesData." ~ member ~ "))*)(cast(void*) block + info.deltas[ data.system.m_components[" - ~ req.to!string ~ "]]))[0 .. block.entities_count];"; + ~ req.to!string ~ "]]))[offset .. entities_count];"; req++; } } @@ -319,22 +321,47 @@ class EntityManager return ret; } + //pragma(msg,genFillInputData); + static void callUpdate(ref CallData data) { Sys* s = cast(Sys*) data.system.m_system_pointer; Sys.EntitiesData input_data; + EntityInfo* info = data.info; //block.type_info; - EntitiesBlock* block = data.info.first_block; - while (block !is null) + EntitiesBlock* block; + if (data.first_block) + block = data.first_block; + else + block = info.first_block; + + uint offset = data.begin; + uint entities_count; + uint blocks; + if (data.blocks) + blocks = data.blocks; + else + blocks = uint.max; + + while (block !is null && blocks > 0) { - EntityInfo* info = block.type_info; + if (blocks == 1) + { + if (data.end) + entities_count = data.end; + else entities_count = block.entities_count; + } + else + entities_count = block.entities_count; mixin(genFillInputData()); s.update(input_data); block = block.next_block; + offset = 0; + blocks--; } } @@ -368,6 +395,8 @@ class EntityManager system.m_system_pointer = cast(void*) Mallocator.instance.make!Sys; system.m_priority = priority; + (cast(Sys*) system.m_system_pointer).__ecsInitialize(); + system.jobs = (cast(Sys*) system.m_system_pointer)._ecs_jobs; mixin(genCompList()); @@ -383,7 +412,7 @@ class EntityManager /*if (systems[sys_id].m_destroy) systems[sys_id].m_destroy(systems[sys_id].m_system_pointer);*/ if (system.m_create) - system.m_create(system.m_system_pointer); + (cast(void function(void*))system.m_create)(system.m_system_pointer); systems[sys_id] = system; Sys.system_id = sys_id; @@ -396,7 +425,7 @@ class EntityManager systems.add(system); if (system.m_create) - system.m_create(system.m_system_pointer); + (cast(void function(void*))system.m_create)(system.m_system_pointer); systems[$ - 1].enable(); @@ -538,15 +567,16 @@ class EntityManager System* sys = &systems[caller.system_id]; if (sys.enabled) { - if (sys.m_begin) - sys.m_begin(sys.m_system_pointer); + //if (sys.m_begin) + // sys.m_begin(sys.m_system_pointer); foreach (info; caller.infos) { CallData data = CallData(caller.system_id, sys, info); - (cast(SytemFuncType) data.system.m_update)(data); + data.update(); + //(cast(SytemFuncType) data.system.m_update)(data); } - if (sys.m_end) - sys.m_end(sys.m_system_pointer); + //if (sys.m_end) + // sys.m_end(sys.m_system_pointer); } } } @@ -557,22 +587,158 @@ class EntityManager foreach (data; info.callers) { if (data.system.enabled) - (cast(SytemFuncType) data.system.m_update)(data); //caller(call_data,null); + data.update(); + //(cast(SytemFuncType) data.system.m_update)(data); //caller(call_data,null); } } } } + void updateMT() + { + assert(m_dispatch_jobs, + "Can't update with multithreading without JobDispatch function. Please use setJobDispatchFunc()."); + Vector!CallData tmp_datas; + tmp_datas.reserve(8); + + foreach (caller; system_callers) + { + System* sys = &systems[caller.system_id]; + if (sys.enabled) + { + uint entities_count = 0; + foreach (info; caller.infos) + { + uint blocks_count = info.blocksCount(); + if(blocks_count == 0)continue; + if (blocks_count > 1) + entities_count += (blocks_count - 1) * info.max_entities; + entities_count += info.last_block.entities_count; + } + + if (!entities_count) + continue; + + uint jobs_count = cast(uint) sys.jobs.length; + uint entities_per_job = entities_count / jobs_count + 1; + + if (entities_per_job <= 4) + { + jobs_count = entities_count / 4; + if(jobs_count == 0)jobs_count = 1; + entities_per_job = entities_count / jobs_count + 1; + } + + uint job_id = 0; + entities_count = 0; + + void nextJob() + { + CallData[] callers = m_call_data_allocator.getCallData(cast(uint)tmp_datas.length); + callers[0..$] = tmp_datas[0..$]; + tmp_datas.clear(); + sys.jobs[job_id].callers = callers; + job_id++; + } + + foreach (info; caller.infos) + { + uint blocks_count = info.blocksCount(); + EntitiesBlock* first_block = info.first_block; + uint first_elem = 0; + begin: + if (first_block is null || blocks_count == 0) + continue; + + if ((blocks_count - 1) * info.max_entities + entities_count + + info.last_block.entities_count - first_elem >= entities_per_job) + { + int reamaining_entities = (entities_per_job - entities_count - (first_block.entities_count - first_elem)); + if(reamaining_entities >= 0) + { + int full_blocks_count = reamaining_entities / info.max_entities; + EntitiesBlock* block = first_block; + foreach (i; 0 .. full_blocks_count + 1) + block = block.next_block; + + if ( + full_blocks_count * info.max_entities + + entities_count + (first_block.entities_count - first_elem) >= entities_per_job) + { + CallData data = CallData(caller.system_id, sys, info, first_block, + cast(ushort) (full_blocks_count + 1), cast(ushort) first_elem, 0); + tmp_datas.add(data); + first_elem = 0; + blocks_count -= full_blocks_count + 1; + first_block = block; + } + else + { + entities_count += full_blocks_count * info.max_entities + (first_block.entities_count - first_elem);// - first_elem; + uint last_elem = entities_per_job - entities_count;// + first_elem - 1; + CallData data = CallData(caller.system_id, sys, info, first_block, + cast(ushort)(full_blocks_count + 2), + cast(ushort) first_elem, cast(ushort) last_elem); + tmp_datas.add(data); + first_elem = last_elem; + blocks_count -= full_blocks_count + 1; + assert(first_elem <= block.entities_count); + first_block = block; + } + } + else + { + uint last_elem = entities_per_job - entities_count; + CallData data = CallData(caller.system_id, sys, info, first_block, + 1, cast(ushort) first_elem, cast(ushort)(first_elem + last_elem)); + tmp_datas.add(data); + first_elem += last_elem; + assert(first_elem <= first_block.entities_count); + } + nextJob(); + entities_count = 0; + goto begin; + } + else + { + CallData data = CallData(caller.system_id, sys, info, + first_block, cast(ushort) blocks_count, cast(ushort) first_elem); + tmp_datas.add(data); + entities_count += (blocks_count - 1) + * info.max_entities + info.last_block.entities_count - first_elem; + } + } + nextJob(); + + m_dispatch_jobs(sys.jobs[0..job_id]); + } + } + } + + struct Job + { + CallData[] callers; + + void execute() + { + EntityManager.instance.getThreadID(); + foreach (ref caller; callers) + { + caller.update(); + } + } + } + + void setJobDispachFunc(void delegate(Job[]) func) + { + m_dispatch_jobs = func; + } + static void alignNum(ref ushort num, ushort alignment) { num = cast(ushort)((num + alignment - 1) & (-cast(int) alignment)); //num += alignment - (num & (alignment - 1)); } - /*static ushort alignedNum(ushort num, ushort alignment) - { - return cast(ushort)((num + alignment - 1) & (-cast(int) alignment)); - }*/ - extern (C) static int compareUShorts(const void* a, const void* b) { ushort _a = *cast(ushort*) a; @@ -754,7 +920,7 @@ class EntityManager break; } - system_callers[index].infos.add(&entity); + if(index < system_callers.length)system_callers[index].infos.add(&entity); /*for (; index < entity.callers.length; index++) { CallData* caller = &entity.callers[index]; @@ -822,11 +988,12 @@ class EntityManager */ export void removeComponents(EntityID entity_id, ushort[] del_ids) { + ThreadData* data = &threads[thread_id]; uint num = cast(uint) del_ids.length; - change_entities_list.add(0); - change_entities_list.add((cast(ubyte*)&entity_id)[0 .. 8]); - change_entities_list.add((cast(ubyte*)&num)[0 .. 4]); - change_entities_list.add(cast(ubyte[]) del_ids); + data.change_entities_list.add(0); + data.change_entities_list.add((cast(ubyte*)&entity_id)[0 .. 8]); + data.change_entities_list.add((cast(ubyte*)&num)[0 .. 4]); + data.change_entities_list.add(cast(ubyte[]) del_ids); } private void __removeComponents(EntityID entity_id, ushort[] del_ids) @@ -961,34 +1128,42 @@ class EntityManager uint j = 0; uint k = 0; - foreach (ref id; ids) + uint len = 0; + //foreach (ref id; ids) + for(;len= new_ids.length) { - id = info.components[j++]; - continue; + if(j >= info.components.length)break; + *id = info.components[j++]; + //continue; } - if (j >= info.components.length) + else if (j >= info.components.length) { - id = new_ids[k++]; - continue; + *id = new_ids[k++]; + //continue; } - debug if (new_ids[k] == info.components[j]) - assert(0, "Trying to add already existing component!"); - if (new_ids[k] < info.components[j]) + else if(new_ids[k] == info.components[j]) { - id = new_ids[k++]; + *id = info.components[j++]; + k++; + } + /*debug if (new_ids[k] == info.components[j]) + assert(0, "Trying to add already existing component!");*/ + else if (new_ids[k] < info.components[j]) + { + *id = new_ids[k++]; } else - id = info.components[j++]; + *id = info.components[j++]; } + if(len == info.components.length)return; - EntityInfo* new_info = getEntityInfo(ids); + EntityInfo* new_info = getEntityInfo(ids[0..len]); EntitiesBlock* new_block = findBlockWithFreeSpace(new_info); - //removeEntityNoID(entity, block); - void* start = new_block.dataBegin() + new_block.entities_count * EntityID.sizeof; Entity* new_entity = cast(Entity*) start; @@ -1001,10 +1176,10 @@ class EntityManager uint ind = cast(uint)((cast(void*) entity - block.dataBegin()) >> 3); else uint ind = cast(uint)((cast(void*) entity - block.dataBegin()) / EntityID.sizeof()); - foreach (ref id; ids) + foreach (ref id; ids[0..len]) { void* dst = cast(void*) new_block + new_info.deltas[id] + ( - new_block.entities_count + new_block.added_count) * components[id].size; + new_block.entities_count /*+ new_block.added_count*/) * components[id].size; uint size = components[id].size; if (k >= new_ids.length) { @@ -1060,14 +1235,14 @@ class EntityManager { pointers[i] = ∁ }*/ - - change_entities_list.add(1); - change_entities_list.add((cast(ubyte*)&entity_id)[0 .. 8]); - change_entities_list.add((cast(ubyte*)&num)[0 .. 4]); - change_entities_list.add(cast(ubyte[]) new_ids); + ThreadData* data = &threads[thread_id]; + data.change_entities_list.add(1); + data.change_entities_list.add((cast(ubyte*)&entity_id)[0 .. 8]); + data.change_entities_list.add((cast(ubyte*)&num)[0 .. 4]); + data.change_entities_list.add(cast(ubyte[]) new_ids); static foreach (i, comp; comps) { - change_entities_list.add((cast(ubyte*)&comp)[0 .. comp.sizeof]); + data.change_entities_list.add((cast(ubyte*)&comp)[0 .. comp.sizeof]); } //__addComponents(entity_id, new_ids, pointers); @@ -1093,9 +1268,30 @@ class EntityManager */ export ref Entity addEntity(EntityTemplate* tmpl) { - EntitiesBlock* block = findBlockWithFreeSpace(tmpl.info); - uint id = (block.entities_count + block.added_count); EntityInfo* info = tmpl.info; + EntitiesBlock* last_block = info.last_block; + ushort index = 0; + if(last_block)/*index = */ + { + //index = last_block.added_count; + index = last_block.added_count.atomicOp!"+="(1); + } + EntitiesBlock* block = findBlockWithFreeSpace(tmpl.info,index); + if(block != last_block) + { + //index = block.added_count; + /*if(last_block) + { + //last_block.added_count.atomicOp!"-="(1); + last_block.added_count = cast(ushort)(info.max_entities - last_block.entities_count); + }*/ + index = block.added_count.atomicOp!"+="(1); + } + + //index--; + //index = cast(ushort)(block.added_count - 1); + uint id = (block.entities_count + index - 1);//block.added_count); + //EntityInfo* info = tmpl.info; void* data_begin = block.dataBegin(); void* start = data_begin + EntityID.sizeof * id; @@ -1106,23 +1302,45 @@ class EntityManager tmpl.entity_data.ptr + info.tmpl_deltas[comp], components[comp].size); } - if (!block.added_count) + //if (!block.added_count) + //if(block.added_count == 1) + if(index == 1) blocks_to_update.add(block); Entity* entity = cast(Entity*) start; entity.id = id_manager.getNewID(); entity.updateID(); - block.added_count++; + //block.added_count++; + //import core.atomic; + //block.entities_count++; return *entity; } - private EntitiesBlock* findBlockWithFreeSpace(EntityInfo* info) + private EntitiesBlock* findBlockWithFreeSpace(EntityInfo* info, uint new_index = 1) { - EntitiesBlock* previous_block; + //EntitiesBlock* previous_block; EntitiesBlock* block = info.last_block; - while (1) + if(block is null) + { + block = cast(EntitiesBlock*) allocator.getBlock(); //AlignedMallocator.instance.alignedAllocate(page_size, page_size); + *block = EntitiesBlock(info); + block.id = 0; + info.first_block = block; + info.last_block = block; + } + else if(block.entities_count + new_index/*block.added_count*/ > info.max_entities) + { + EntitiesBlock* new_block = cast(EntitiesBlock*) allocator.getBlock(); //AlignedMallocator.instance.alignedAllocate(page_size, page_size); + *new_block = EntitiesBlock(info); + new_block.prev_block = block; + block.next_block = new_block; + new_block.id = cast(ushort)(block.id + 1); + block = new_block; + info.last_block = block; + }//*/ + /*while (1) { if (block is null) { @@ -1143,8 +1361,6 @@ class EntityManager break; // new block certainly has free space } // check if there is enought space - /*if (block.dataDelta() + ( - block.entities_count + block.added_count + 1) * info.size > page_size)*/ if (block.entities_count + block.added_count >= block.type_info.max_entities) { previous_block = block; @@ -1153,7 +1369,7 @@ class EntityManager } break; // block exists and bounds check passed - } + }//*/ return block; } @@ -1166,7 +1382,7 @@ class EntityManager */ export void removeEntity(EntityID id) { - entities_to_remove.add(id); + threads[thread_id].entities_to_remove.add(id); } private void __removeEntity(EntityID id) @@ -1209,7 +1425,7 @@ class EntityManager } } - if(block !is info.last_block || pos != block.entities_count) + if (block !is info.last_block || pos != block.entities_count) { foreach (comp; info.components) { @@ -1236,7 +1452,8 @@ class EntityManager if (block.prev_block) { block.prev_block.next_block = null; - } + block.prev_block.added_count = 0; + } allocator.freeBlock(block); } } @@ -1254,40 +1471,43 @@ class EntityManager private void changeEntites() { - uint index = 0; - uint len = cast(uint) change_entities_list.length; - while (index < len) + foreach(ref thread;threads) { - if (!change_entities_list[index++]) + uint index = 0; + uint len = cast(uint) thread.change_entities_list.length; + while (index < len) { - EntityID id = *cast(EntityID*)&change_entities_list[index]; - index += EntityID.sizeof; - uint num = *cast(uint*)&change_entities_list[index]; - index += uint.sizeof; - ushort[] ids = (cast(ushort*) alloca(num * ushort.sizeof))[0 .. num]; - ids[0 .. $] = (cast(ushort*)&change_entities_list[index])[0 .. num]; - index += ushort.sizeof * num; - __removeComponents(id, ids); - } - else - { - EntityID id = *cast(EntityID*)&change_entities_list[index]; - index += EntityID.sizeof; - uint num = *cast(uint*)&change_entities_list[index]; - index += uint.sizeof; - ushort[] ids = (cast(ushort*) alloca(num * ushort.sizeof))[0 .. num]; - ids[0 .. $] = (cast(ushort*)&change_entities_list[index])[0 .. num]; - index += ushort.sizeof * num; - void*[] pointers = (cast(void**) alloca(num * (void*).sizeof))[0 .. num]; - foreach (i; 0 .. num) + if (!thread.change_entities_list[index++]) { - pointers[i] = &change_entities_list[index]; - index += components[ids[i]].size; + EntityID id = *cast(EntityID*)&thread.change_entities_list[index]; + index += EntityID.sizeof; + uint num = *cast(uint*)&thread.change_entities_list[index]; + index += uint.sizeof; + ushort[] ids = (cast(ushort*) alloca(num * ushort.sizeof))[0 .. num]; + ids[0 .. $] = (cast(ushort*)&thread.change_entities_list[index])[0 .. num]; + index += ushort.sizeof * num; + __removeComponents(id, ids); + } + else + { + EntityID id = *cast(EntityID*)&thread.change_entities_list[index]; + index += EntityID.sizeof; + uint num = *cast(uint*)&thread.change_entities_list[index]; + index += uint.sizeof; + ushort[] ids = (cast(ushort*) alloca(num * ushort.sizeof))[0 .. num]; + ids[0 .. $] = (cast(ushort*)&thread.change_entities_list[index])[0 .. num]; + index += ushort.sizeof * num; + void*[] pointers = (cast(void**) alloca(num * (void*).sizeof))[0 .. num]; + foreach (i; 0 .. num) + { + pointers[i] = &thread.change_entities_list[index]; + index += components[ids[i]].size; + } + __addComponents(id, ids, pointers); } - __addComponents(id, ids, pointers); } + thread.change_entities_list.clear(); } - change_entities_list.clear(); } private void updateBlocks() @@ -1295,18 +1515,26 @@ class EntityManager foreach (block; blocks_to_update) { block.entities_count += block.added_count; - block.added_count = 0; + if(block.entities_count > block.type_info.max_entities) + { + block.entities_count = block.type_info.max_entities; + } + //block.added_count = 0; + block.added_count.atomicStore(cast(ushort)0); } blocks_to_update.clear(); } private void removeEntities() { - foreach (id; entities_to_remove) + foreach(i,ref thread;threads) { - __removeEntity(id); + foreach (id; thread.entities_to_remove) + { + __removeEntity(id); + } + thread.entities_to_remove.clear(); } - entities_to_remove.clear(); } /************************************************************************************************************************ @@ -1317,19 +1545,20 @@ class EntityManager updateBlocks(); removeEntities(); changeEntites(); + m_call_data_allocator.clear(); - version (UpdateBySystems) + /*version (UpdateBySystems) { } else + {*/ + foreach (ref system; instance.systems) { - foreach (ref system; instance.systems) - { - if (system.m_begin) - system.m_begin(system.m_system_pointer); - } + if (system.m_begin) + (cast(void function(void*))system.m_begin)(system.m_system_pointer); } + //} } /************************************************************************************************************************ @@ -1337,18 +1566,18 @@ class EntityManager */ export void end() { - version (UpdateBySystems) + /*version (UpdateBySystems) { } else + {*/ + foreach (ref system; instance.systems) { - foreach (ref system; instance.systems) - { - if (system.m_end) - system.m_end(system.m_system_pointer); - } + if (system.m_end) + (cast(void function(void*))system.m_end)(system.m_system_pointer); } + //} updateBlocks(); removeEntities(); @@ -1357,6 +1586,12 @@ class EntityManager //clearEvents(); } + private void getThreadID() + { + if(m_thread_id_func)thread_id = m_thread_id_func(); + else thread_id = 0; + } + /************************************************************************************************************************ *Component info; */ @@ -1387,7 +1622,9 @@ class EntityManager ///Returns number of blocks uint blocksCount() { - return last_block.id; + if(last_block) + return last_block.id + 1; + else return 0; } ///entity components @@ -1438,7 +1675,8 @@ class EntityManager ///number of entities in block ushort entities_count = 0; ///number of new entities in block - ushort added_count = 0; + shared ushort added_count = 0; + //ushort added_count = 0; ///block id ushort id = 0; ///maximum number of entities in block @@ -1452,15 +1690,32 @@ class EntityManager /************************************************************************************************************************ *Structure with data used to calling System calls. + * + *first_block, begin, end, blocks parameters are used + *to call partial info update */ struct CallData { + void update() + { + (cast(SytemFuncType) system.m_update)(this); + } + ///system ID. Used to update system pointer after system reload. uint system_id; ///pointer to used system System* system; ///poiner to Entity type info EntityManager.EntityInfo* info; + + ///pointer to first block into process (if 0 then first block will be used) + EntitiesBlock* first_block; + ///number of blocks to update (if 0 then update all) + ushort blocks; + ///index of first element in first block + ushort begin; + ///index of last element in last block + ushort end; } struct SystemCaller @@ -1470,6 +1725,16 @@ class EntityManager Vector!(EntityInfo*) infos; } + struct ThreadData + { + Vector!EntityID entities_to_remove; + Vector!ubyte change_entities_list; + } + + static uint thread_id; + + ThreadData[] threads; + Vector!(SystemCaller*) system_callers; alias SytemFuncType = void function(ref EntityManager.CallData data); @@ -1489,9 +1754,12 @@ class EntityManager //EventManager event_manager; mixin EventManagerCode; - Vector!EntityID entities_to_remove; + //Vector!EntityID entities_to_remove; Vector!(EntitiesBlock*) blocks_to_update; - Vector!ubyte change_entities_list; + //Vector!ubyte change_entities_list; + + void delegate(Job[] jobs) m_dispatch_jobs; + uint delegate() m_thread_id_func; HashMap!(ushort[], EntityInfo*) entities_infos; HashMap!(const(char)[], ushort) systems_map; @@ -1500,6 +1768,60 @@ class EntityManager Vector!System systems; Vector!ComponentInfo components; Vector!EventInfo events; + + CallDataAllocator m_call_data_allocator; + struct CallDataAllocator + { + struct Block + { + CallData[256] data; + uint allocated = 0; + } + + Vector!(Block*) blocks; + uint id; + + void clear() + { + if(blocks.length > 0) + foreach (block; blocks[0 .. id + 1]) + { + block.allocated = 0; + } + id = 0; + //blocks.clear(); + } + + CallData[] getCallData(uint num) + { + if (blocks.length == 0) + { + Block* new_block = Mallocator.instance.make!Block; + blocks.add(new_block); + } + /*else if(blocks[$-1].allocated + num >= 256) + { + blocks.add(Block()); + }*/ + + Block* block = blocks[id]; + if (block.allocated + num >= 256) + { + id++; + if (id == blocks.length) + { + Block* new_block = Mallocator.instance.make!Block; + blocks.add(new_block); + } + block = blocks[id]; + } + + CallData[] ret = block.data[block.allocated .. block.allocated + num]; + block.allocated += num; + return ret; + } + } + __gshared EntityManager instance = null; } diff --git a/source/ecs/package.d b/source/ecs/package.d index e043ec9..fb40799 100644 --- a/source/ecs/package.d +++ b/source/ecs/package.d @@ -3,5 +3,6 @@ module ecs; public import ecs.manager; public import ecs.entity; public import ecs.system; +public import ecs.core; import ecs.id_manager; import ecs.events; \ No newline at end of file diff --git a/source/ecs/system.d b/source/ecs/system.d index b13c60a..2ac96fb 100644 --- a/source/ecs/system.d +++ b/source/ecs/system.d @@ -8,6 +8,7 @@ import ecs.manager; */ struct System { + /************************************************************************************************************************ *Check if system is enabled. */ @@ -22,7 +23,7 @@ struct System export void enable() { if (!m_enabled && m_enable) - m_enable(m_system_pointer); + (cast(void function(void*))m_enable)(m_system_pointer); m_enabled = true; } @@ -32,7 +33,7 @@ struct System export void disable() { if (m_enabled && m_disable) - m_disable(m_system_pointer); + (cast(void function(void*))m_disable)(m_system_pointer); m_enabled = false; } @@ -63,17 +64,28 @@ package: ///optional components ushort[] m_optional_components; + EntityManager.Job[] jobs; + //void function(ref EntityManager.CallData data) m_update; void* m_update; ///workaroud for DMD bug with upper line - void function(void* system_pointer) m_enable; + /*void function(void* system_pointer) m_enable; void function(void* system_pointer) m_disable; void function(void* system_pointer) m_create; void function(void* system_pointer) m_destroy; void function(void* system_pointer) m_begin; - void function(void* system_pointer) m_end; + void function(void* system_pointer) m_end;*/ + + void* m_enable; + void* m_disable; + + void* m_create; + void* m_destroy; + + void* m_begin; + void* m_end; //void function(ref EntityManager.CallData data) m_initialize; //void function(ref EntityManager.CallData data) m_deinitilize; diff --git a/source/ecs/vector.d b/source/ecs/vector.d index ef6a238..d67552f 100644 --- a/source/ecs/vector.d +++ b/source/ecs/vector.d @@ -49,9 +49,9 @@ public: export void removeAll() { if (array !is null) { - foreach (ref el; array[0 .. used]) { + /*foreach (ref el; array[0 .. used]) { destroy(el); - } + }*/ freeData(cast(void[]) array); gVectorsDestroyed++; } diff --git a/tests/tests.d b/tests/tests.d index 79a76a6..c9fb25a 100644 --- a/tests/tests.d +++ b/tests/tests.d @@ -5,6 +5,7 @@ import ecs.events; import ecs.manager; import ecs.system; import ecs.attributes; +import ecs.core; import core.time; import std.stdio; @@ -14,19 +15,19 @@ int main() struct TestEvent { - __gshared ushort event_id; + mixin ECS.Event;//__gshared ushort event_id; int a; } struct TestEvent2 { - __gshared ushort event_id; + mixin ECS.Event;//__gshared ushort event_id; float a; } static struct TestComp { - __gshared ushort component_id; + mixin ECS.Component;//__gshared ushort component_id; int a = 1; ulong b = 2; @@ -43,7 +44,7 @@ int main() static struct TestComp2 { - __gshared ushort component_id; + mixin ECS.Component;//__gshared ushort component_id; int b = 3; int a = 4; @@ -60,7 +61,7 @@ int main() static struct TestComp3 { - __gshared ushort component_id; + mixin ECS.Component;//__gshared ushort component_id; uint gg = 5; //good game uint bg = 6; //bad game @@ -77,7 +78,7 @@ int main() static struct TestComp4 { - __gshared ushort component_id; + mixin ECS.Component;//__gshared ushort component_id; uint gg = 7; //good game uint bg = 8; //bad game ulong a = 9; @@ -98,7 +99,7 @@ int main() struct TestSystem { - __gshared ushort system_id; + mixin ECS.System!16;//__gshared ushort system_id; void onCreate() { @@ -146,7 +147,7 @@ int main() test2.a = 8; } - void update(ref EntitiesData data) + void update(EntitiesData data) { foreach(i;0..data.length) { @@ -165,7 +166,7 @@ int main() struct TestSystemWithHighPriority { - __gshared ushort system_id; + mixin ECS.System!16;//__gshared ushort system_id; static struct EntitiesData { @@ -177,7 +178,7 @@ int main() } - void update(ref EntitiesData data) + void update(EntitiesData data) { } @@ -192,7 +193,7 @@ import std.meta; struct TestSystem2 { - __gshared ushort system_id; + mixin ECS.System!16;//__gshared ushort system_id; enum AbsentComponents0 { @@ -255,6 +256,15 @@ import std.meta; }*/ } + void dispatch(EntityManager.Job[] jobs) + { + foreach(job;jobs) + { + //writeln(job); + job.execute(); + } + } + void writeEntityComponents(Entity* entity) { write(entity.id); @@ -270,7 +280,8 @@ import std.meta; //writeln((cast(uint*) pp)[0 .. 14], " ", pp); } - EntityManager.initialize(); + EntityManager.initialize(1); + gEM.setJobDispachFunc(&dispatch); assert(gEM !is null); MonoTime time = MonoTime.currTime; @@ -358,40 +369,49 @@ import std.meta; //assert(*(cast(EntityID*)(cast(void*)tmpl.info.first_block+24)) == EntityID(1,1)); //assert(*(cast(EntityID*)(cast(void*)tmpl.info.first_block+48)) == EntityID(1,1)); + Entity entity2; + foreach (i; 0 .. 500_000) { - gEM.addEntity(tmpl); + entity2 = gEM.addEntity(tmpl); gEM.addEntity(tmpl2); } time = MonoTime.currTime; gEM.begin(); + //gEM.updateMT(); gEM.update(); gEM.end(); dur = (MonoTime.currTime - time).total!"usecs"; writeln("Update: ", dur, " usecs"); + writeEntityComponents(gEM.getEntity(entity2.id)); + time = MonoTime.currTime; gEM.begin(); - gEM.update(); + gEM.updateMT(); + //gEM.update(); gEM.end(); dur = (MonoTime.currTime - time).total!"usecs"; writeln("Update: ", dur, " usecs"); + writeEntityComponents(gEM.getEntity(entity2.id)); + time = MonoTime.currTime; gEM.begin(); - gEM.update(); + gEM.updateMT(); + //gEM.update(); gEM.end(); dur = (MonoTime.currTime - time).total!"usecs"; writeln("Update: ", dur, " usecs"); - writeEntityComponents(gEM.getEntity(entity.id)); + writeEntityComponents(gEM.getEntity(entity2.id)); entity = gEM.addEntity(tmpl); From 6e2c00f608d72cce68ffd5cbb592292240b19286 Mon Sep 17 00:00:00 2001 From: Mergul Date: Sun, 14 Oct 2018 18:36:31 +0200 Subject: [PATCH 013/217] -formatted with dfmt -cleaned up code --- source/ecs/manager.d | 195 ++++++++++++++++++------------------------- 1 file changed, 79 insertions(+), 116 deletions(-) diff --git a/source/ecs/manager.d b/source/ecs/manager.d index ec99df1..c7d3925 100644 --- a/source/ecs/manager.d +++ b/source/ecs/manager.d @@ -42,7 +42,7 @@ class EntityManager foreach (ref system; instance.systems) { if (system.m_destroy) - (cast(void function(void*))system.m_destroy)(system.m_system_pointer); + (cast(void function(void*)) system.m_destroy)(system.m_system_pointer); } Mallocator.instance.dispose(instance); @@ -54,7 +54,8 @@ class EntityManager */ this(uint threads_count) { - if(threads_count == 0)threads_count = 0; + if (threads_count == 0) + threads_count = 0; threads = Mallocator.instance.makeArray!ThreadData(threads_count); //event_manager = EventManager(this); //event_manager.manager = this; @@ -278,7 +279,8 @@ class EntityManager } else if (member == "length") { - ret ~= "input_data." ~ member ~ " = cast(typeof(input_data.length))(entities_count - offset);"; + ret ~= "input_data." ~ member + ~ " = cast(typeof(input_data.length))(entities_count - offset);"; } else { @@ -350,7 +352,8 @@ class EntityManager { if (data.end) entities_count = data.end; - else entities_count = block.entities_count; + else + entities_count = block.entities_count; } else entities_count = block.entities_count; @@ -412,7 +415,7 @@ class EntityManager /*if (systems[sys_id].m_destroy) systems[sys_id].m_destroy(systems[sys_id].m_system_pointer);*/ if (system.m_create) - (cast(void function(void*))system.m_create)(system.m_system_pointer); + (cast(void function(void*)) system.m_create)(system.m_system_pointer); systems[sys_id] = system; Sys.system_id = sys_id; @@ -425,7 +428,7 @@ class EntityManager systems.add(system); if (system.m_create) - (cast(void function(void*))system.m_create)(system.m_system_pointer); + (cast(void function(void*)) system.m_create)(system.m_system_pointer); systems[$ - 1].enable(); @@ -610,12 +613,13 @@ class EntityManager foreach (info; caller.infos) { uint blocks_count = info.blocksCount(); - if(blocks_count == 0)continue; + if (blocks_count == 0) + continue; if (blocks_count > 1) entities_count += (blocks_count - 1) * info.max_entities; entities_count += info.last_block.entities_count; } - + if (!entities_count) continue; @@ -625,7 +629,8 @@ class EntityManager if (entities_per_job <= 4) { jobs_count = entities_count / 4; - if(jobs_count == 0)jobs_count = 1; + if (jobs_count == 0) + jobs_count = 1; entities_per_job = entities_count / jobs_count + 1; } @@ -634,8 +639,9 @@ class EntityManager void nextJob() { - CallData[] callers = m_call_data_allocator.getCallData(cast(uint)tmp_datas.length); - callers[0..$] = tmp_datas[0..$]; + CallData[] callers = m_call_data_allocator.getCallData( + cast(uint) tmp_datas.length); + callers[0 .. $] = tmp_datas[0 .. $]; tmp_datas.clear(); sys.jobs[job_id].callers = callers; job_id++; @@ -653,20 +659,21 @@ class EntityManager if ((blocks_count - 1) * info.max_entities + entities_count + info.last_block.entities_count - first_elem >= entities_per_job) { - int reamaining_entities = (entities_per_job - entities_count - (first_block.entities_count - first_elem)); - if(reamaining_entities >= 0) + int reamaining_entities = (entities_per_job - entities_count - ( + first_block.entities_count - first_elem)); + if (reamaining_entities >= 0) { int full_blocks_count = reamaining_entities / info.max_entities; EntitiesBlock* block = first_block; foreach (i; 0 .. full_blocks_count + 1) block = block.next_block; - if ( - full_blocks_count * info.max_entities - + entities_count + (first_block.entities_count - first_elem) >= entities_per_job) + if (full_blocks_count * info.max_entities + entities_count + ( + first_block.entities_count - first_elem) >= entities_per_job) { CallData data = CallData(caller.system_id, sys, info, first_block, - cast(ushort) (full_blocks_count + 1), cast(ushort) first_elem, 0); + cast(ushort)(full_blocks_count + 1), + cast(ushort) first_elem, 0); tmp_datas.add(data); first_elem = 0; blocks_count -= full_blocks_count + 1; @@ -674,10 +681,11 @@ class EntityManager } else { - entities_count += full_blocks_count * info.max_entities + (first_block.entities_count - first_elem);// - first_elem; - uint last_elem = entities_per_job - entities_count;// + first_elem - 1; - CallData data = CallData(caller.system_id, sys, info, first_block, - cast(ushort)(full_blocks_count + 2), + entities_count += full_blocks_count * info.max_entities + ( + first_block.entities_count - first_elem); // - first_elem; + uint last_elem = entities_per_job - entities_count; // + first_elem - 1; + CallData data = CallData(caller.system_id, sys, info, + first_block, cast(ushort)(full_blocks_count + 2), cast(ushort) first_elem, cast(ushort) last_elem); tmp_datas.add(data); first_elem = last_elem; @@ -689,8 +697,8 @@ class EntityManager else { uint last_elem = entities_per_job - entities_count; - CallData data = CallData(caller.system_id, sys, info, first_block, - 1, cast(ushort) first_elem, cast(ushort)(first_elem + last_elem)); + CallData data = CallData(caller.system_id, sys, info, first_block, 1, + cast(ushort) first_elem, cast(ushort)(first_elem + last_elem)); tmp_datas.add(data); first_elem += last_elem; assert(first_elem <= first_block.entities_count); @@ -704,13 +712,13 @@ class EntityManager CallData data = CallData(caller.system_id, sys, info, first_block, cast(ushort) blocks_count, cast(ushort) first_elem); tmp_datas.add(data); - entities_count += (blocks_count - 1) - * info.max_entities + info.last_block.entities_count - first_elem; + entities_count += (blocks_count - 1) * info.max_entities + + info.last_block.entities_count - first_elem; } } nextJob(); - m_dispatch_jobs(sys.jobs[0..job_id]); + m_dispatch_jobs(sys.jobs[0 .. job_id]); } } } @@ -920,7 +928,8 @@ class EntityManager break; } - if(index < system_callers.length)system_callers[index].infos.add(&entity); + if (index < system_callers.length) + system_callers[index].infos.add(&entity); /*for (; index < entity.callers.length; index++) { CallData* caller = &entity.callers[index]; @@ -1130,12 +1139,13 @@ class EntityManager uint k = 0; uint len = 0; //foreach (ref id; ids) - for(;len= new_ids.length) { - if(j >= info.components.length)break; + if (j >= info.components.length) + break; *id = info.components[j++]; //continue; } @@ -1144,7 +1154,7 @@ class EntityManager *id = new_ids[k++]; //continue; } - else if(new_ids[k] == info.components[j]) + else if (new_ids[k] == info.components[j]) { *id = info.components[j++]; k++; @@ -1158,9 +1168,10 @@ class EntityManager else *id = info.components[j++]; } - if(len == info.components.length)return; + if (len == info.components.length) + return; - EntityInfo* new_info = getEntityInfo(ids[0..len]); + EntityInfo* new_info = getEntityInfo(ids[0 .. len]); EntitiesBlock* new_block = findBlockWithFreeSpace(new_info); @@ -1176,10 +1187,10 @@ class EntityManager uint ind = cast(uint)((cast(void*) entity - block.dataBegin()) >> 3); else uint ind = cast(uint)((cast(void*) entity - block.dataBegin()) / EntityID.sizeof()); - foreach (ref id; ids[0..len]) + foreach (ref id; ids[0 .. len]) { void* dst = cast(void*) new_block + new_info.deltas[id] + ( - new_block.entities_count /*+ new_block.added_count*/) * components[id].size; + new_block.entities_count /*+ new_block.added_count*/ ) * components[id].size; uint size = components[id].size; if (k >= new_ids.length) { @@ -1270,59 +1281,41 @@ class EntityManager { EntityInfo* info = tmpl.info; EntitiesBlock* last_block = info.last_block; + ushort index = 0; - if(last_block)/*index = */ - { - //index = last_block.added_count; - index = last_block.added_count.atomicOp!"+="(1); - } - EntitiesBlock* block = findBlockWithFreeSpace(tmpl.info,index); - if(block != last_block) - { - //index = block.added_count; - /*if(last_block) - { - //last_block.added_count.atomicOp!"-="(1); - last_block.added_count = cast(ushort)(info.max_entities - last_block.entities_count); - }*/ - index = block.added_count.atomicOp!"+="(1); - } - - //index--; - //index = cast(ushort)(block.added_count - 1); - uint id = (block.entities_count + index - 1);//block.added_count); - //EntityInfo* info = tmpl.info; + if (last_block)index = last_block.added_count.atomicOp!"+="(1); + EntitiesBlock* block = findBlockWithFreeSpace(tmpl.info, index); + if (block != last_block)index = block.added_count.atomicOp!"+="(1); + uint id = (block.entities_count + index - 1); //block.added_count); + void* data_begin = block.dataBegin(); void* start = data_begin + EntityID.sizeof * id; - //memcpy(data_begin + EntityID.sizeof * id, tmpl.entity_data.ptr, EntityID.sizeof); + foreach (i, comp; info.components) { memcpy(cast(void*) block + info.deltas[comp] + components[comp].size * id, tmpl.entity_data.ptr + info.tmpl_deltas[comp], components[comp].size); } - //if (!block.added_count) - //if(block.added_count == 1) - if(index == 1) + if (index == 1) blocks_to_update.add(block); Entity* entity = cast(Entity*) start; entity.id = id_manager.getNewID(); entity.updateID(); - //block.added_count++; - //import core.atomic; - - //block.entities_count++; + return *entity; } + /************************************************************************************************************************ + *Return block with free space for selected EntityInfo. + */ private EntitiesBlock* findBlockWithFreeSpace(EntityInfo* info, uint new_index = 1) { - //EntitiesBlock* previous_block; EntitiesBlock* block = info.last_block; - if(block is null) + if (block is null) { block = cast(EntitiesBlock*) allocator.getBlock(); //AlignedMallocator.instance.alignedAllocate(page_size, page_size); *block = EntitiesBlock(info); @@ -1330,7 +1323,7 @@ class EntityManager info.first_block = block; info.last_block = block; } - else if(block.entities_count + new_index/*block.added_count*/ > info.max_entities) + else if (block.entities_count + new_index /*block.added_count*/ > info.max_entities) { EntitiesBlock* new_block = cast(EntitiesBlock*) allocator.getBlock(); //AlignedMallocator.instance.alignedAllocate(page_size, page_size); *new_block = EntitiesBlock(info); @@ -1339,38 +1332,7 @@ class EntityManager new_block.id = cast(ushort)(block.id + 1); block = new_block; info.last_block = block; - }//*/ - /*while (1) - { - if (block is null) - { - block = cast(EntitiesBlock*) allocator.getBlock(); //AlignedMallocator.instance.alignedAllocate(page_size, page_size); - *block = EntitiesBlock(info); - if (previous_block is null) - { - info.first_block = block; - block.id = 0; - } - else - { - previous_block.next_block = block; - block.prev_block = previous_block; - block.id = cast(ushort)(previous_block.id + 1); - } - info.last_block = block; - break; // new block certainly has free space - } - // check if there is enought space - if (block.entities_count + block.added_count >= block.type_info.max_entities) - { - previous_block = block; - block = block.next_block; - continue; - } - - break; // block exists and bounds check passed - }//*/ - + } return block; } @@ -1413,12 +1375,10 @@ class EntityManager if (call_destructors) { - //void* data = data_begin + pos * info.size; foreach (comp; info.components) { if (components[comp].destroy_callback) { - //components[comp].destroy_callback(data + info.deltas[comp]); components[comp].destroy_callback(cast( void*) block + info.deltas[comp] + pos * components[comp].size); } @@ -1471,7 +1431,7 @@ class EntityManager private void changeEntites() { - foreach(ref thread;threads) + foreach (ref thread; threads) { uint index = 0; uint len = cast(uint) thread.change_entities_list.length; @@ -1515,19 +1475,19 @@ class EntityManager foreach (block; blocks_to_update) { block.entities_count += block.added_count; - if(block.entities_count > block.type_info.max_entities) + if (block.entities_count > block.type_info.max_entities) { block.entities_count = block.type_info.max_entities; } //block.added_count = 0; - block.added_count.atomicStore(cast(ushort)0); + block.added_count.atomicStore(cast(ushort) 0); } blocks_to_update.clear(); } private void removeEntities() { - foreach(i,ref thread;threads) + foreach (i, ref thread; threads) { foreach (id; thread.entities_to_remove) { @@ -1556,7 +1516,7 @@ class EntityManager foreach (ref system; instance.systems) { if (system.m_begin) - (cast(void function(void*))system.m_begin)(system.m_system_pointer); + (cast(void function(void*)) system.m_begin)(system.m_system_pointer); } //} } @@ -1575,7 +1535,7 @@ class EntityManager foreach (ref system; instance.systems) { if (system.m_end) - (cast(void function(void*))system.m_end)(system.m_system_pointer); + (cast(void function(void*)) system.m_end)(system.m_system_pointer); } //} @@ -1588,8 +1548,10 @@ class EntityManager private void getThreadID() { - if(m_thread_id_func)thread_id = m_thread_id_func(); - else thread_id = 0; + if (m_thread_id_func) + thread_id = m_thread_id_func(); + else + thread_id = 0; } /************************************************************************************************************************ @@ -1622,9 +1584,10 @@ class EntityManager ///Returns number of blocks uint blocksCount() { - if(last_block) - return last_block.id + 1; - else return 0; + if (last_block) + return last_block.id + 1; + else + return 0; } ///entity components @@ -1783,11 +1746,11 @@ class EntityManager void clear() { - if(blocks.length > 0) - foreach (block; blocks[0 .. id + 1]) - { - block.allocated = 0; - } + if (blocks.length > 0) + foreach (block; blocks[0 .. id + 1]) + { + block.allocated = 0; + } id = 0; //blocks.clear(); } From 2824bdb55bd96d6a309a084de5e7ce1b23dc3b77 Mon Sep 17 00:00:00 2001 From: Mergul Date: Mon, 15 Oct 2018 22:25:28 +0200 Subject: [PATCH 014/217] -multithreaded addEntity(). Works good, but: *IDManager has mutex (no multithreaded support) *allocating blocks has mutex (probably it's possible to do diffrent mutex for diffrent EntityInfo) -addEntity() if slightly better optimized --- source/ecs/manager.d | 98 ++++++++++++++++++++++++++++++++++++-------- 1 file changed, 80 insertions(+), 18 deletions(-) diff --git a/source/ecs/manager.d b/source/ecs/manager.d index c7d3925..2249a20 100644 --- a/source/ecs/manager.d +++ b/source/ecs/manager.d @@ -9,6 +9,7 @@ import std.traits; import core.stdc.stdlib; import core.stdc.string; import core.atomic; +import core.sync.mutex; import ecs.entity; import ecs.block_allocator; @@ -57,6 +58,9 @@ class EntityManager if (threads_count == 0) threads_count = 0; threads = Mallocator.instance.makeArray!ThreadData(threads_count); + + add_mutex = Mallocator.instance.make!Mutex; + entity_block_alloc_mutex = Mallocator.instance.make!Mutex; //event_manager = EventManager(this); //event_manager.manager = this; } @@ -1280,15 +1284,18 @@ class EntityManager export ref Entity addEntity(EntityTemplate* tmpl) { EntityInfo* info = tmpl.info; - EntitiesBlock* last_block = info.last_block; ushort index = 0; - if (last_block)index = last_block.added_count.atomicOp!"+="(1); - EntitiesBlock* block = findBlockWithFreeSpace(tmpl.info, index); - if (block != last_block)index = block.added_count.atomicOp!"+="(1); + EntitiesBlock* block; + do + { + block = findBlockWithFreeSpaceMT(info); + index = block.added_count.atomicOp!"+="(1); + } + while (block.entities_count + index > info.max_entities); uint id = (block.entities_count + index - 1); //block.added_count); - + void* data_begin = block.dataBegin(); void* start = data_begin + EntityID.sizeof * id; @@ -1299,10 +1306,12 @@ class EntityManager } if (index == 1) - blocks_to_update.add(block); + threads[thread_id].blocks_to_update.add(block); Entity* entity = cast(Entity*) start; + add_mutex.lock_nothrow(); entity.id = id_manager.getNewID(); + add_mutex.unlock_nothrow(); entity.updateID(); return *entity; @@ -1311,21 +1320,65 @@ class EntityManager /************************************************************************************************************************ *Return block with free space for selected EntityInfo. */ - private EntitiesBlock* findBlockWithFreeSpace(EntityInfo* info, uint new_index = 1) + private EntitiesBlock* findBlockWithFreeSpace(EntityInfo* info) { EntitiesBlock* block = info.last_block; if (block is null) { - block = cast(EntitiesBlock*) allocator.getBlock(); //AlignedMallocator.instance.alignedAllocate(page_size, page_size); + block = cast(EntitiesBlock*) allocator.getBlock(); *block = EntitiesBlock(info); block.id = 0; info.first_block = block; info.last_block = block; } - else if (block.entities_count + new_index /*block.added_count*/ > info.max_entities) + else if (block.entities_count >= info.max_entities) { - EntitiesBlock* new_block = cast(EntitiesBlock*) allocator.getBlock(); //AlignedMallocator.instance.alignedAllocate(page_size, page_size); + EntitiesBlock* new_block = cast(EntitiesBlock*) allocator.getBlock(); + *new_block = EntitiesBlock(info); + new_block.prev_block = block; + block.next_block = new_block; + new_block.id = cast(ushort)(block.id + 1); + block = new_block; + info.last_block = block; + } + return block; + } + + /************************************************************************************************************************ + *Return block with free space for selected EntityInfo. Additional this function is multithread safe. + */ + private EntitiesBlock* findBlockWithFreeSpaceMT(EntityInfo* info) + { + EntitiesBlock* block = info.last_block; + + if (block is null) + { + entity_block_alloc_mutex.lock_nothrow(); + scope (exit) + entity_block_alloc_mutex.unlock_nothrow(); + + if (info.last_block != null) + return info.last_block; + + block = cast(EntitiesBlock*) allocator.getBlock(); + *block = EntitiesBlock(info); + block.id = 0; + info.first_block = block; + info.last_block = block; + } + else if (block.entities_count + block.added_count > info.max_entities) + { + EntitiesBlock* last_block = info.last_block; + + entity_block_alloc_mutex.lock_nothrow(); + scope (exit) + entity_block_alloc_mutex.unlock_nothrow(); + + if (info.last_block !is last_block) + return info.last_block; + + EntitiesBlock* new_block = cast(EntitiesBlock*) allocator.getBlock(); *new_block = EntitiesBlock(info); new_block.prev_block = block; block.next_block = new_block; @@ -1472,17 +1525,20 @@ class EntityManager private void updateBlocks() { - foreach (block; blocks_to_update) + foreach (ref thread; threads) { - block.entities_count += block.added_count; - if (block.entities_count > block.type_info.max_entities) + foreach (block; thread.blocks_to_update) { - block.entities_count = block.type_info.max_entities; + block.entities_count += block.added_count; + if (block.entities_count > block.type_info.max_entities) + { + block.entities_count = block.type_info.max_entities; + } + //block.added_count = 0; + block.added_count.atomicStore(cast(ushort) 0); } - //block.added_count = 0; - block.added_count.atomicStore(cast(ushort) 0); + thread.blocks_to_update.clear(); } - blocks_to_update.clear(); } private void removeEntities() @@ -1611,6 +1667,8 @@ class EntityManager EntitiesBlock* last_block; ///array of CallData. Contain data for System calls. Vector!(CallData) callers; + + ///Mutex used to managing block new alloction } /************************************************************************************************************************ @@ -1692,6 +1750,7 @@ class EntityManager { Vector!EntityID entities_to_remove; Vector!ubyte change_entities_list; + Vector!(EntitiesBlock*) blocks_to_update; } static uint thread_id; @@ -1718,7 +1777,7 @@ class EntityManager mixin EventManagerCode; //Vector!EntityID entities_to_remove; - Vector!(EntitiesBlock*) blocks_to_update; + //Vector!(EntitiesBlock*) blocks_to_update; //Vector!ubyte change_entities_list; void delegate(Job[] jobs) m_dispatch_jobs; @@ -1732,6 +1791,9 @@ class EntityManager Vector!ComponentInfo components; Vector!EventInfo events; + Mutex add_mutex; + Mutex entity_block_alloc_mutex; + CallDataAllocator m_call_data_allocator; struct CallDataAllocator { From 430ce8074c4232bcd9a0ed4aae0b5e9308c70d79 Mon Sep 17 00:00:00 2001 From: Mergul Date: Sat, 20 Oct 2018 11:42:29 +0200 Subject: [PATCH 015/217] -multithreading jobs dependencies: *system has arrays of read only and modified components *new attribute "readonly" usable for variables which should be visible as read only. Const can be used instead for enable checks by compiler. *JobGroup was added. JobGroup contain array of jobs and array of dependencies (JobGroups) *new function generateDependencies() generate exclusion between systems, and then generate dependencies for SystemCallers and JobGroups -fixed issue with jobs generating (empty blocks with only newly added entities was used, and led to crash) -fixed small typo mistake --- source/ecs/attributes.d | 4 +- source/ecs/manager.d | 256 ++++++++++++++++++++++++++++++++++++---- source/ecs/system.d | 4 + tests/tests.d | 10 +- 4 files changed, 246 insertions(+), 28 deletions(-) diff --git a/source/ecs/attributes.d b/source/ecs/attributes.d index 4068a06..6b45dae 100644 --- a/source/ecs/attributes.d +++ b/source/ecs/attributes.d @@ -3,4 +3,6 @@ module ecs.attributes; ///Used to mark optional components for system. enum optional = "optional"; ///Used to mark absent components for system. Enum 'AbsentComponents' should be used instead of it. -enum absent = "absent"; \ No newline at end of file +enum absent = "absent"; +///Used to mark readonly components for system. "const" can be used insted. +enum readonly = "readonly"; \ No newline at end of file diff --git a/source/ecs/manager.d b/source/ecs/manager.d index 2249a20..9132a39 100644 --- a/source/ecs/manager.d +++ b/source/ecs/manager.d @@ -108,11 +108,13 @@ class EntityManager static assert(0, "EntitiesData members should be arrays of elements!"); } - string ret; // = "ushort comp;uint req;uint opt;uint absent;"; + string ret; uint req; uint opt; uint absent; + uint read_only; + uint modified; foreach (member; __traits(allMembers, Sys.EntitiesData)) { if (member == "length" || is(typeof(__traits(getMember, @@ -125,27 +127,41 @@ class EntityManager { { bool has_att = false; + bool is_read_only = false; + int attribs = 0; + if (is(CopyConstness!(ForeachType!(typeof(mixin("Sys.EntitiesData." ~ member))), + int) == const(int))) + { + is_read_only = true; + } foreach (att; __traits(getAttributes, __traits(getMember, Sys.EntitiesData, member))) { if (att == "optional") { - //ret ~= "opt++;"; opt++; - has_att = true; - break; + attribs++; + //break; } else if (att == "absent") { absent++; - //ret ~= "absen++;"; - has_att = true; - break; + attribs++; + //break; + } + if (att == "readonly") + { + is_read_only = true; } } - if (!has_att) + assert(attribs <= 1, + "EntitiesData member can't have both \"@optional\" and \"@absent\"."); + if (!attribs) req++; - //ret ~= "req++;"; + if (is_read_only) + read_only++; + else + modified++; } } } @@ -173,11 +189,19 @@ class EntityManager if (absent > 0) ret ~= "system.m_absent_components = Mallocator.instance.makeArray!ushort(" ~ absent.to!string ~ ");"; + if (read_only > 0) + ret ~= "system.m_read_only_components = Mallocator.instance.makeArray!ushort(" + ~ read_only.to!string ~ ");"; + if (modified > 0) + ret ~= "system.m_modified_components = Mallocator.instance.makeArray!ushort(" + ~ modified.to!string ~ ");"; ret ~= "ushort comp;"; //uint opt = 0;uint req = 0;uint absent = 0;"; opt = 0; req = 0; absent = 0; + read_only = 0; + modified = 0; static if (__traits(hasMember, Sys, "AbsentComponents")) { @@ -221,29 +245,46 @@ class EntityManager .stringof ~ \".\");"; + bool is_read_only = false; bool has_att = false; + if (is(CopyConstness!(ForeachType!(typeof(mixin("Sys.EntitiesData." ~ member))), + int) == const(int))) + { + is_read_only = true; + } foreach (att; __traits(getAttributes, __traits(getMember, Sys.EntitiesData, member))) { if (att == "optional") { ret ~= "system.m_optional_components[" ~ (opt++) - .to!string ~ "] = comp;}"; + .to!string ~ "] = comp;"; has_att = true; - break; + //break; } else if (att == "absent") { ret ~= "system.m_absent_components[" ~ (absent++) - .to!string ~ "] = comp;}"; + .to!string ~ "] = comp;"; has_att = true; - break; + //break; + } + if (att == "readonly") + { + is_read_only = true; } } if (!has_att) { - ret ~= "system.m_components[" ~ (req++).to!string ~ "] = comp;}"; + ret ~= "system.m_components[" ~ (req++).to!string ~ "] = comp;"; } + if (is_read_only) + ret ~= "system.m_read_only_components[" ~ (read_only++) + .to!string ~ "] = comp;"; + else + ret ~= "system.m_modified_components[" ~ (modified++) + .to!string ~ "] = comp;"; + ret ~= "}"; } } } @@ -362,6 +403,8 @@ class EntityManager else entities_count = block.entities_count; + assert(entities_count <= block.entities_count && offset <= block.entities_count); + mixin(genFillInputData()); s.update(input_data); @@ -616,7 +659,7 @@ class EntityManager uint entities_count = 0; foreach (info; caller.infos) { - uint blocks_count = info.blocksCount(); + uint blocks_count = info.nonEmptyBlocksCount(); if (blocks_count == 0) continue; if (blocks_count > 1) @@ -653,7 +696,7 @@ class EntityManager foreach (info; caller.infos) { - uint blocks_count = info.blocksCount(); + uint blocks_count = info.nonEmptyBlocksCount(); EntitiesBlock* first_block = info.first_block; uint first_elem = 0; begin: @@ -722,7 +765,8 @@ class EntityManager } nextJob(); - m_dispatch_jobs(sys.jobs[0 .. job_id]); + caller.job_group.jobs = sys.jobs[0 .. job_id]; + m_dispatch_jobs(caller.job_group);//sys.jobs[0 .. job_id]); } } } @@ -741,7 +785,15 @@ class EntityManager } } - void setJobDispachFunc(void delegate(Job[]) func) + struct JobGroup + { + Job[] jobs; + JobGroup*[] dependencies; + uint id; + //uint max_jobs; + } + + void setJobDispachFunc(void delegate(JobGroup) func) { m_dispatch_jobs = func; } @@ -1357,7 +1409,7 @@ class EntityManager entity_block_alloc_mutex.lock_nothrow(); scope (exit) entity_block_alloc_mutex.unlock_nothrow(); - + if (info.last_block != null) return info.last_block; @@ -1482,7 +1534,7 @@ class EntityManager return cast(EntitiesBlock*)(cast(size_t) pointer & (~cast(size_t)(page_size - 1))); } - private void changeEntites() + private void changeEntities() { foreach (ref thread; threads) { @@ -1560,7 +1612,7 @@ class EntityManager { updateBlocks(); removeEntities(); - changeEntites(); + changeEntities(); m_call_data_allocator.clear(); /*version (UpdateBySystems) @@ -1597,7 +1649,7 @@ class EntityManager updateBlocks(); removeEntities(); - changeEntites(); + changeEntities(); //clearEvents(); } @@ -1610,6 +1662,146 @@ class EntityManager thread_id = 0; } + /*private */ + void generateDependencies() + { + foreach (caller; system_callers) + { + caller.system = &systems[caller.system_id]; + if(caller.exclusion)Mallocator.instance.dispose(caller.exclusion); + if(caller.dependencies)Mallocator.instance.dispose(caller.dependencies); + } + uint index = 0; + SystemCaller*[] exclusion; + exclusion = (cast(SystemCaller**) alloca((SystemCaller*).sizeof * system_callers.length))[0 + .. system_callers.length]; + foreach (caller; system_callers) + { + index = 0; + out_for: foreach (caller2; system_callers) + { + if (/*caller.system.priority != caller2.system.priority ||*/ caller is caller2) + continue; + foreach (cmp; caller.system.m_read_only_components) + { + foreach (cmp2; caller2.system.m_modified_components) + { + if (cmp == cmp2) + { + exclusion[index++] = caller2; + continue out_for; + } + } + } + foreach (cmp; caller.system.m_modified_components) + { + foreach (cmp2; caller2.system.m_read_only_components) + { + if (cmp == cmp2) + { + exclusion[index++] = caller2; + continue out_for; + } + } + foreach (cmp2; caller2.system.m_modified_components) + { + if (cmp == cmp2) + { + exclusion[index++] = caller2; + continue out_for; + } + } + } + } + + + if(index > 0)caller.exclusion = Mallocator.instance.makeArray(exclusion[0..index]); + else caller.exclusion = null; + + /*import std.stdio; + write("Exclusive systems for system ", caller.system.name, ": "); + foreach (ex; exclusion[0 .. index]) + write(ex.system.name, " "); + writeln();*/ + } + + extern (C) static int compareSystems(const void* a, const void* b) + { + SystemCaller* _a = *cast(SystemCaller**) a; + SystemCaller* _b = *cast(SystemCaller**) b; + if (_a.system.priority < _b.system.priority) + return -1; + else if (_a.system.priority == _b.system.priority) + { + if (_a.exclusion.length < _b.exclusion.length) + return -1; + else if (_a.exclusion.length == _b.exclusion.length) + return 0; + else + return 1; + } + else + return 1; + } + + qsort(system_callers.array.ptr, system_callers.length, (SystemCaller*) + .sizeof, &compareSystems); + + /*static struct CallerData + { + uint id; + //bool + }*/ + + /*caller_data = (cast(SystemCaller**) alloca((SystemCaller*).sizeof * system_callers.length))[0 + .. system_callers.length];*/ + + foreach(uint i,caller;system_callers)caller.job_group.id = i; + + int priority = int.min; + uint beg = 0; + index = 0; + foreach(uint i,caller;system_callers) + { + /* + if(priority == int.min)priority = caller.system.priority; + if(priority != caller.system.priority) + { + foreach(caller2;system_callers[beg..i]) + { + + } + priority = caller.system.priority; + beg = i; + }*/ + index = 0; + foreach(ex;caller.exclusion) + { + if(ex.job_group.id > caller.job_group.id)continue; + + exclusion[index++] = ex; + } + + if(index > 0) + { + caller.dependencies = Mallocator.instance.makeArray(exclusion[0..index]); + caller.job_group.dependencies = Mallocator.instance.makeArray!(JobGroup*)(index); + + foreach(j,dep;caller.dependencies) + { + caller.job_group.dependencies[j] = &dep.job_group; + } + } + else caller.dependencies = null; + + /*import std.stdio; + write("Dependencies for system ", caller.system.name, ": "); + foreach (ex; caller.dependencies) + write(ex.system.name, " "); + writeln();*/ + } + } + /************************************************************************************************************************ *Component info; */ @@ -1646,6 +1838,21 @@ class EntityManager return 0; } + ///Returns number of non empty blocks + uint nonEmptyBlocksCount() + { + EntitiesBlock* block = last_block; + while (1) + { + if (block is null) + return 0; + if (block.entities_count == 0) + block = block.prev_block; + else + return block.id + 1; + } + } + ///entity components ushort[] components; @@ -1744,6 +1951,9 @@ class EntityManager uint system_id; System* system; Vector!(EntityInfo*) infos; + SystemCaller*[] dependencies; + SystemCaller*[] exclusion; + JobGroup job_group; } struct ThreadData @@ -1780,7 +1990,7 @@ class EntityManager //Vector!(EntitiesBlock*) blocks_to_update; //Vector!ubyte change_entities_list; - void delegate(Job[] jobs) m_dispatch_jobs; + void delegate(JobGroup jobs) m_dispatch_jobs; uint delegate() m_thread_id_func; HashMap!(ushort[], EntityInfo*) entities_infos; diff --git a/source/ecs/system.d b/source/ecs/system.d index 2ac96fb..28e2e23 100644 --- a/source/ecs/system.d +++ b/source/ecs/system.d @@ -66,6 +66,10 @@ package: EntityManager.Job[] jobs; + System*[] m_dependencies; + ushort[] m_read_only_components; + ushort[] m_modified_components; + //void function(ref EntityManager.CallData data) m_update; void* m_update; ///workaroud for DMD bug with upper line diff --git a/tests/tests.d b/tests/tests.d index c9fb25a..ee27305 100644 --- a/tests/tests.d +++ b/tests/tests.d @@ -131,7 +131,7 @@ int main() size_t length; TestComp[] test; TestComp2[] test2; - @optional TestComp3[] test3; + @readonly @optional const(TestComp3)[] test3; //@absent TestComp4[] test4; } @@ -208,7 +208,7 @@ import std.meta; static struct EntitiesData { short length; - Entity[] entity; + const (Entity)[] entity; TestComp3[] test; //@absent TestComp[] testt; } @@ -256,9 +256,9 @@ import std.meta; }*/ } - void dispatch(EntityManager.Job[] jobs) + void dispatch(EntityManager.JobGroup jobs) { - foreach(job;jobs) + foreach(job;jobs.jobs) { //writeln(job); job.execute(); @@ -366,6 +366,8 @@ import std.meta; gEM.registerSystem!TestSystem2(0); + gEM.generateDependencies(); + //assert(*(cast(EntityID*)(cast(void*)tmpl.info.first_block+24)) == EntityID(1,1)); //assert(*(cast(EntityID*)(cast(void*)tmpl.info.first_block+48)) == EntityID(1,1)); From d3f7593afc071752f47b214c2c3e18ad3a042383 Mon Sep 17 00:00:00 2001 From: Mergul Date: Thu, 25 Oct 2018 11:46:08 +0200 Subject: [PATCH 016/217] -BlockAllocator is no longer template -Multithreaded IDManager.getNewID() *use implementation with free IDs stack (instead of classic pool) -support for multiple UpdatePasses. Passes are added by name, and must be called between begin() end() functions. -removed mutex from addEntity() -commit() function added. Used to commit all changes made while update() call. Called automatically by begin() end() functions. --- source/ecs/block_allocator.d | 5 +- source/ecs/events.d | 6 +- source/ecs/id_manager.d | 169 +++++++++++++-- source/ecs/manager.d | 397 ++++++++++++++++++++--------------- source/ecs/system.d | 4 +- tests/tests.d | 14 +- 6 files changed, 406 insertions(+), 189 deletions(-) diff --git a/source/ecs/block_allocator.d b/source/ecs/block_allocator.d index 30afcc8..29b1fb3 100644 --- a/source/ecs/block_allocator.d +++ b/source/ecs/block_allocator.d @@ -5,8 +5,11 @@ import ecs.manager; import std.experimental.allocator; import std.experimental.allocator.mallocator : AlignedMallocator, Mallocator; -struct BlockAllocator(uint block_size, uint blocks_in_allocation) +struct BlockAllocator//(uint block_size, uint blocks_in_allocation) { + private uint block_size; + private uint blocks_in_allocation; + void* next_block = null; void* getBlock() diff --git a/source/ecs/events.d b/source/ecs/events.d index 3a09bc8..20c8c0e 100644 --- a/source/ecs/events.d +++ b/source/ecs/events.d @@ -17,10 +17,10 @@ mixin template EventManagerCode() //@disable this(); - this(EntityManager m) + /*this(EntityManager m) { manager = m; - } + }*/ void sendSelfEvent(Ev)(EntityID id, Ev event) { @@ -120,6 +120,6 @@ mixin template EventManagerCode() EventList current_events; EventList process_events; - BlockAllocator!(events_block_size, events_blocks_in_allocation) allocator; + BlockAllocator/*!(events_block_size, events_blocks_in_allocation)*/ allocator; EntityManager manager; } diff --git a/source/ecs/id_manager.d b/source/ecs/id_manager.d index cd2fbb7..1e8ebad 100644 --- a/source/ecs/id_manager.d +++ b/source/ecs/id_manager.d @@ -1,8 +1,15 @@ module ecs.id_manager; +import std.experimental.allocator; +import std.experimental.allocator.mallocator : AlignedMallocator, Mallocator; + import ecs.entity; import ecs.vector; +import core.atomic; +import core.stdc.string : memcpy; +import core.sync.mutex; + /************************************************************************************************************************ *IDManager is responsible for assignment and removing IDs. IDs are unique throughtout a whole duration of the program. */ @@ -11,17 +18,62 @@ struct IDManager /************************************************************************************************************************ *Get new ID. */ - EntityID getNewID() + pragma(inline, false) EntityID getNewID() { - if (m_next_id >= m_ids_array.length) - m_ids_array.add(Data()); + //uint current = m_next_id; + //uint next;// = m_ids_array[m_next_id].next_id; +begin: + //if (current == uint.max)//> m_last_id) + int current = m_stack_top.atomicOp!"-="(1) + 1; + if(current < 0) + { + uint add_id = m_last_id.atomicOp!"+="(1) - 1; + + if (add_id >= m_ids_array.length) + { + uint local_id = add_id - cast(uint) m_ids_array.length; + uint block_id = local_id >> 16; + if (block_id >= m_blocks_count) + { + add_mutex.lock(); + if(block_id >= m_blocks_count) + { + m_blocks[m_blocks_count].alloc(); + m_blocks_count++; + } + add_mutex.unlock(); + } + } + + EntityID id; + id.id = add_id; + id.counter = 0; + return id; + } + + + //current += 1; + uint index = m_free_stack[current]; EntityID id; - id.id = m_next_id; - id.counter = /*++*/m_ids_array[m_next_id].counter; - m_next_id = m_ids_array[m_next_id].next_id; - if (m_next_id == uint.max) - m_next_id = cast(uint) m_ids_array.length; + id.id = index; + id.counter = m_ids_array[index].counter; + //current = m_ids_array[index].next_id; return id; + + /*next = m_ids_array[current].next_id; + if(cas(&m_next_id,current,next)) + { + EntityID id; + id.id = current; + id.counter = m_ids_array[current].counter; + m_next_id = m_ids_array[current].next_id; + return id; + } + else + { + current = next; + goto begin; + }*/ } /************************************************************************************************************************ @@ -33,9 +85,12 @@ struct IDManager if (data.counter != id.counter) return; data.counter++; - data.next_id = m_next_id; + //data.next_id = m_next_id; data.entity = null; - m_next_id = id.id; + ///m_next_id = id.id; + + m_stack_top.atomicOp!"+="(1); + m_free_stack[m_stack_top] = id.id; } /************************************************************************************************************************ @@ -43,7 +98,15 @@ struct IDManager */ void update(ref Entity entity) { - if(entity.id.counter == m_ids_array[entity.id.id].counter)m_ids_array[entity.id.id].entity = &entity; + if (entity.id.id >= cast(uint) m_ids_array.length) + { + uint local_id = entity.id.id - cast(uint) m_ids_array.length; + uint block_id = local_id >> 16; + local_id -= block_id << 16; + m_blocks[block_id].data[local_id].entity = &entity; + } + else //if (entity.id.counter == m_ids_array[entity.id.id].counter) + m_ids_array[entity.id.id].entity = &entity; } /************************************************************************************************************************ @@ -51,6 +114,19 @@ struct IDManager */ export Entity* getEntityPointer(EntityID id) { + if (id.id >= m_ids_array.length) + { + uint local_id = id.id - cast(uint) m_ids_array.length; + uint block_id = local_id >> 16; + assert(block_id < m_blocks_count); + if (block_id >= m_blocks_count) + return null; + local_id -= block_id << 16; + if (m_blocks[block_id].data[local_id].counter != id.counter) + return null; + return m_blocks[block_id].data[local_id].entity; + } + Data* data = &m_ids_array[id.id]; if (data.counter != id.counter) return null; @@ -67,16 +143,81 @@ struct IDManager return data.counter == id.counter; } + void initialize() + { + m_ids_array = Mallocator.instance.makeArray!Data(65536); + m_free_stack = Mallocator.instance.makeArray!uint(65536); + m_blocks = Mallocator.instance.makeArray!Block(64); + m_blocks_count = 1; + m_blocks[0].alloc(); + + add_mutex = Mallocator.instance.make!Mutex(); + } + + void optimize() + { + if(m_stack_top < -1)m_stack_top = -1; + if(m_last_id > m_ids_array.length) + { + uint begin = cast(uint)m_ids_array.length; + Data[] new_array = Mallocator.instance.makeArray!Data(begin + (m_blocks_count << 16)); + memcpy(new_array.ptr, m_ids_array.ptr, m_ids_array.length * Data.sizeof); + Mallocator.instance.dispose(m_ids_array); + m_ids_array = new_array; + + uint[] new_stack = Mallocator.instance.makeArray!uint(m_ids_array.length); + memcpy(new_stack.ptr,m_free_stack.ptr,m_free_stack.length * uint.sizeof); + Mallocator.instance.dispose(m_free_stack); + m_free_stack = new_stack; + + foreach(block;m_blocks[0..m_blocks_count-1]) + { + memcpy(cast(void*)m_ids_array.ptr + begin * Data.sizeof, block.data.ptr, 65536 * Data.sizeof); + begin += 65536; + } + memcpy(cast(void*)m_ids_array.ptr + begin * Data.sizeof, m_blocks[m_blocks_count-1].data.ptr, (m_last_id - begin) * Data.sizeof); + foreach(block;m_blocks[1..m_blocks_count])block.free(); + m_blocks_count = 1; + } + } + + private static struct Block + { + void alloc() + { + assert(data is null); + data = Mallocator.instance.makeArray!Data(65536); + } + + void free() + { + assert(data !is null); + Mallocator.instance.dispose(data); + } + + Data[] data; //65536 + } + private static struct Data { uint counter = 0; - uint next_id = uint.max; + //uint next_id = uint.max; Entity* entity = null; } private: - uint m_next_id; - Vector!Data m_ids_array; + Mutex add_mutex; + //shared uint m_next_id = 0; + + //shared uint m_last_id = 0; + Data[] m_ids_array = null; + uint m_blocks_count = 0; + Block[] m_blocks; + //shared int m_stack_top = -1; + uint[] m_free_stack = null; + + align(64) shared uint m_last_id = 0; + align(64) shared int m_stack_top = -1; } unittest diff --git a/source/ecs/manager.d b/source/ecs/manager.d index 9132a39..ffea30a 100644 --- a/source/ecs/manager.d +++ b/source/ecs/manager.d @@ -59,10 +59,30 @@ class EntityManager threads_count = 0; threads = Mallocator.instance.makeArray!ThreadData(threads_count); - add_mutex = Mallocator.instance.make!Mutex; + id_manager.initialize(); + + allocator = BlockAllocator(page_size,pages_in_block); + + //add_mutex = Mallocator.instance.make!Mutex; entity_block_alloc_mutex = Mallocator.instance.make!Mutex; //event_manager = EventManager(this); //event_manager.manager = this; + + UpdatePass* pass = Mallocator.instance.make!UpdatePass; + pass.name = Mallocator.instance.makeArray("update"); + passes.add(pass); + + passes_map.add(cast(string)pass.name, cast(ushort)(passes.length - 1)); + } + + /************************************************************************************************************************ + *Same as "void registerSystem(Sys)(int priority, int pass = 0)" but use pass name instead of id. + */ + void registerSystem(Sys)(int priority, const (char)[] pass_name) + { + ushort pass = passes_map.get(pass_name, ushort.max); + assert(pass != ushort.max); + registerSystem!(Sys)(priority, pass); } /************************************************************************************************************************ @@ -73,11 +93,14 @@ class EntityManager *params: *priority = system priority. Priority determines order of execution of systems updates. */ - void registerSystem(Sys)(int priority) + void registerSystem(Sys)(int priority, ushort pass = 0) { alias STC = ParameterStorageClass; + assert(pass < passes.length); + System system; + system.m_pass = pass; static if (!(hasMember!(Sys, "system_id")) || !is(typeof(Sys.system_id) == ushort)) { @@ -450,10 +473,6 @@ class EntityManager mixin(genCompList()); - /*if(system.m_components)qsort(system.m_components.ptr, system.m_components.length, ushort.sizeof, &compareUShorts); - if(system.m_optional_components)qsort(system.m_optional_components.ptr, system.m_optional_components.length, ushort.sizeof, &compareUShorts); - if(system.m_absent_components)qsort(system.m_absent_components.ptr, system.m_absent_components.length, ushort.sizeof, &compareUShorts);*/ - ushort sys_id = systems_map.get(Sys.stringof, ushort.max); if (sys_id < systems.length) { @@ -492,13 +511,13 @@ class EntityManager version (UpdateBySystems) { bool added = false; - foreach (i, ref caller; system_callers) + foreach (i, ref caller; passes[pass].system_callers) { if (systems[caller.system_id].priority > priority) { SystemCaller* sys_caller = Mallocator.instance.make!SystemCaller; sys_caller.system_id = Sys.system_id; - system_callers.add(sys_caller, i); + passes[pass].system_callers.add(sys_caller, i); added = true; break; } @@ -507,7 +526,7 @@ class EntityManager { SystemCaller* sys_caller = Mallocator.instance.make!SystemCaller; sys_caller.system_id = Sys.system_id; - system_callers.add(sys_caller); + passes[pass].system_callers.add(sys_caller); } } } @@ -525,6 +544,15 @@ class EntityManager return cast(Sys*) systems[Sys.system_id].m_system_pointer; } + ushort registerPass(const (char)[] name) + { + UpdatePass* pass = Mallocator.instance.make!UpdatePass; + pass.name = Mallocator.instance.makeArray(name); + passes.add(pass); + passes_map.add(name,cast(ushort)(passes.length - 1)); + return cast(ushort)(passes.length - 1); + } + /************************************************************************************************************************ *Register component into EntityManager. */ @@ -564,7 +592,7 @@ class EntityManager { components.add(info); Comp.component_id = cast(ushort)(components.length - 1); - string name = Mallocator.instance.makeArray(Comp.stringof); + const (char)[] name = Mallocator.instance.makeArray(Comp.stringof); components_map.add(name, cast(ushort)(components.length - 1)); } } @@ -605,14 +633,25 @@ class EntityManager } } + /************************************************************************************************************************ + *Same as "void update(int pass = 0)" but use pass name instead of id. + */ + void update(const (char)[] pass_name) + { + ushort pass = passes_map.get(pass_name, ushort.max); + assert(pass != ushort.max); + update(pass); + } + /************************************************************************************************************************ *Update systems. Should be called only between begin() and end(). */ - export void update() + export void update(ushort pass = 0) { + assert(pass < passes.length); version (UpdateBySystems) { - foreach (caller; system_callers) + foreach (caller; passes[pass].system_callers) { System* sys = &systems[caller.system_id]; if (sys.enabled) @@ -644,14 +683,25 @@ class EntityManager } } - void updateMT() + /************************************************************************************************************************ + *Same as "void updateMT(int pass = 0)" but use pass name instead of id. + */ + void updateMT(const (char)[] pass_name) { + ushort pass = passes_map.get(pass_name, ushort.max); + assert(pass != ushort.max); + updateMT(pass); + } + + void updateMT(ushort pass = 0) + { + assert(pass < passes.length); assert(m_dispatch_jobs, "Can't update with multithreading without JobDispatch function. Please use setJobDispatchFunc()."); Vector!CallData tmp_datas; tmp_datas.reserve(8); - foreach (caller; system_callers) + foreach (caller; passes[pass].system_callers) { System* sys = &systems[caller.system_id]; if (sys.enabled) @@ -766,7 +816,7 @@ class EntityManager nextJob(); caller.job_group.jobs = sys.jobs[0 .. job_id]; - m_dispatch_jobs(caller.job_group);//sys.jobs[0 .. job_id]); + m_dispatch_jobs(caller.job_group); //sys.jobs[0 .. job_id]); } } } @@ -978,14 +1028,14 @@ class EntityManager } uint index = 0; - for (; index < system_callers.length; index++) + for (; index < passes[system.m_pass].system_callers.length; index++) { - if (system_callers[index].system_id == system_id) + if (passes[system.m_pass].system_callers[index].system_id == system_id) break; } - if (index < system_callers.length) - system_callers[index].infos.add(&entity); + if (index < passes[system.m_pass].system_callers.length) + passes[system.m_pass].system_callers[index].infos.add(&entity); /*for (; index < entity.callers.length; index++) { CallData* caller = &entity.callers[index]; @@ -1137,10 +1187,6 @@ class EntityManager del_ids[i] = comp.component_id; } - /*change_entities_list.add(0); - change_entities_list.add((cast(ubyte*)&entity_id)[0..8]); - change_entities_list.add((cast(ubyte*)&num)[0..4]); - change_entities_list.add(cast(ubyte[])del_ids);*/ removeComponents(entity_id, del_ids); } @@ -1361,9 +1407,9 @@ class EntityManager threads[thread_id].blocks_to_update.add(block); Entity* entity = cast(Entity*) start; - add_mutex.lock_nothrow(); + //add_mutex.lock_nothrow(); entity.id = id_manager.getNewID(); - add_mutex.unlock_nothrow(); + //add_mutex.unlock_nothrow(); entity.updateID(); return *entity; @@ -1605,28 +1651,28 @@ class EntityManager } } + export void commit() + { + id_manager.optimize(); + updateBlocks(); + removeEntities(); + changeEntities(); + } + /************************************************************************************************************************ *Begin of update process. Should be called before any update is called. */ export void begin() { - updateBlocks(); - removeEntities(); - changeEntities(); + + commit(); m_call_data_allocator.clear(); - /*version (UpdateBySystems) - { - - } - else - {*/ foreach (ref system; instance.systems) { if (system.m_begin) (cast(void function(void*)) system.m_begin)(system.m_system_pointer); } - //} } /************************************************************************************************************************ @@ -1634,22 +1680,14 @@ class EntityManager */ export void end() { - /*version (UpdateBySystems) - { - - } - else - {*/ + foreach (ref system; instance.systems) { if (system.m_end) (cast(void function(void*)) system.m_end)(system.m_system_pointer); } - //} - updateBlocks(); - removeEntities(); - changeEntities(); + commit(); //clearEvents(); } @@ -1665,140 +1703,149 @@ class EntityManager /*private */ void generateDependencies() { - foreach (caller; system_callers) + foreach(pass_id,pass;passes) { - caller.system = &systems[caller.system_id]; - if(caller.exclusion)Mallocator.instance.dispose(caller.exclusion); - if(caller.dependencies)Mallocator.instance.dispose(caller.dependencies); - } - uint index = 0; - SystemCaller*[] exclusion; - exclusion = (cast(SystemCaller**) alloca((SystemCaller*).sizeof * system_callers.length))[0 - .. system_callers.length]; - foreach (caller; system_callers) - { - index = 0; - out_for: foreach (caller2; system_callers) + foreach (caller; pass.system_callers) { - if (/*caller.system.priority != caller2.system.priority ||*/ caller is caller2) - continue; - foreach (cmp; caller.system.m_read_only_components) - { - foreach (cmp2; caller2.system.m_modified_components) - { - if (cmp == cmp2) - { - exclusion[index++] = caller2; - continue out_for; - } - } - } - foreach (cmp; caller.system.m_modified_components) - { - foreach (cmp2; caller2.system.m_read_only_components) - { - if (cmp == cmp2) - { - exclusion[index++] = caller2; - continue out_for; - } - } - foreach (cmp2; caller2.system.m_modified_components) - { - if (cmp == cmp2) - { - exclusion[index++] = caller2; - continue out_for; - } - } - } + caller.system = &systems[caller.system_id]; + if (caller.exclusion) + Mallocator.instance.dispose(caller.exclusion); + if (caller.dependencies) + Mallocator.instance.dispose(caller.dependencies); } - - - if(index > 0)caller.exclusion = Mallocator.instance.makeArray(exclusion[0..index]); - else caller.exclusion = null; - - /*import std.stdio; - write("Exclusive systems for system ", caller.system.name, ": "); - foreach (ex; exclusion[0 .. index]) - write(ex.system.name, " "); - writeln();*/ - } - - extern (C) static int compareSystems(const void* a, const void* b) - { - SystemCaller* _a = *cast(SystemCaller**) a; - SystemCaller* _b = *cast(SystemCaller**) b; - if (_a.system.priority < _b.system.priority) - return -1; - else if (_a.system.priority == _b.system.priority) + uint index = 0; + SystemCaller*[] exclusion; + exclusion = (cast(SystemCaller**) alloca((SystemCaller*).sizeof * pass.system_callers.length))[0 + .. pass.system_callers.length]; + foreach (caller; pass.system_callers) { - if (_a.exclusion.length < _b.exclusion.length) + index = 0; + out_for: foreach (caller2; pass.system_callers) + { + if ( /*caller.system.priority != caller2.system.priority ||*/ caller is caller2) + continue; + foreach (cmp; caller.system.m_read_only_components) + { + foreach (cmp2; caller2.system.m_modified_components) + { + if (cmp == cmp2) + { + exclusion[index++] = caller2; + continue out_for; + } + } + } + foreach (cmp; caller.system.m_modified_components) + { + foreach (cmp2; caller2.system.m_read_only_components) + { + if (cmp == cmp2) + { + exclusion[index++] = caller2; + continue out_for; + } + } + foreach (cmp2; caller2.system.m_modified_components) + { + if (cmp == cmp2) + { + exclusion[index++] = caller2; + continue out_for; + } + } + } + } + + if (index > 0) + caller.exclusion = Mallocator.instance.makeArray(exclusion[0 .. index]); + else + caller.exclusion = null; + + /*import std.stdio; + write("Exclusive systems for system ", caller.system.name, ": "); + foreach (ex; exclusion[0 .. index]) + write(ex.system.name, " "); + writeln();*/ + } + + extern (C) static int compareSystems(const void* a, const void* b) + { + SystemCaller* _a = *cast(SystemCaller**) a; + SystemCaller* _b = *cast(SystemCaller**) b; + if (_a.system.priority < _b.system.priority) return -1; - else if (_a.exclusion.length == _b.exclusion.length) - return 0; + else if (_a.system.priority == _b.system.priority) + { + if (_a.exclusion.length < _b.exclusion.length) + return -1; + else if (_a.exclusion.length == _b.exclusion.length) + return 0; + else + return 1; + } else return 1; } - else - return 1; - } - qsort(system_callers.array.ptr, system_callers.length, (SystemCaller*) - .sizeof, &compareSystems); + qsort(pass.system_callers.array.ptr, pass.system_callers.length, (SystemCaller*) + .sizeof, &compareSystems); - /*static struct CallerData - { - uint id; - //bool - }*/ - - /*caller_data = (cast(SystemCaller**) alloca((SystemCaller*).sizeof * system_callers.length))[0 - .. system_callers.length];*/ - - foreach(uint i,caller;system_callers)caller.job_group.id = i; - - int priority = int.min; - uint beg = 0; - index = 0; - foreach(uint i,caller;system_callers) - { - /* - if(priority == int.min)priority = caller.system.priority; - if(priority != caller.system.priority) + /*static struct CallerData { - foreach(caller2;system_callers[beg..i]) - { - - } - priority = caller.system.priority; - beg = i; + uint id; + //bool }*/ + + /*caller_data = (cast(SystemCaller**) alloca((SystemCaller*).sizeof * pass.system_callers.length))[0 + .. pass.system_callers.length];*/ + + foreach (uint i, caller; pass.system_callers) + caller.job_group.id = i; + + int priority = int.min; + uint beg = 0; index = 0; - foreach(ex;caller.exclusion) + foreach (uint i, caller; pass.system_callers) { - if(ex.job_group.id > caller.job_group.id)continue; - - exclusion[index++] = ex; - } - - if(index > 0) - { - caller.dependencies = Mallocator.instance.makeArray(exclusion[0..index]); - caller.job_group.dependencies = Mallocator.instance.makeArray!(JobGroup*)(index); - - foreach(j,dep;caller.dependencies) + /* + if(priority == int.min)priority = caller.system.priority; + if(priority != caller.system.priority) { - caller.job_group.dependencies[j] = &dep.job_group; - } - } - else caller.dependencies = null; + foreach(caller2;pass.system_callers[beg..i]) + { + + } + priority = caller.system.priority; + beg = i; + }*/ + index = 0; + foreach (ex; caller.exclusion) + { + if (ex.job_group.id > caller.job_group.id) + continue; - /*import std.stdio; - write("Dependencies for system ", caller.system.name, ": "); - foreach (ex; caller.dependencies) - write(ex.system.name, " "); - writeln();*/ + exclusion[index++] = ex; + } + + if (index > 0) + { + caller.dependencies = Mallocator.instance.makeArray(exclusion[0 .. index]); + caller.job_group.dependencies = Mallocator.instance.makeArray!(JobGroup*)(index); + + foreach (j, dep; caller.dependencies) + { + caller.job_group.dependencies[j] = &dep.job_group; + } + } + else + caller.dependencies = null; + + /*import std.stdio; + write("Dependencies for system ", caller.system.name, ": "); + foreach (ex; caller.dependencies) + write(ex.system.name, " "); + writeln();*/ + } } } @@ -1963,11 +2010,24 @@ class EntityManager Vector!(EntitiesBlock*) blocks_to_update; } + struct UpdatePass + { + ~this() + { + assert(name); + if(name)Mallocator.instance.dispose(name); + } + char[] name; + Vector!(SystemCaller*) system_callers; + } + static uint thread_id; ThreadData[] threads; - Vector!(SystemCaller*) system_callers; + Vector!(UpdatePass*) passes; + + //Vector!(SystemCaller*) system_callers; alias SytemFuncType = void function(ref EntityManager.CallData data); @@ -1981,7 +2041,7 @@ class EntityManager enum pages_in_block = 128; IDManager id_manager; - BlockAllocator!(page_size, pages_in_block) allocator; + BlockAllocator/*!(page_size, pages_in_block)*/ allocator; //EventManager event_manager; mixin EventManagerCode; @@ -1995,13 +2055,14 @@ class EntityManager HashMap!(ushort[], EntityInfo*) entities_infos; HashMap!(const(char)[], ushort) systems_map; - HashMap!(string, ushort) components_map; - HashMap!(string, ushort) events_map; + HashMap!(const(char)[], ushort) components_map; + HashMap!(const(char)[], ushort) events_map; + HashMap!(const(char)[], ushort) passes_map; Vector!System systems; Vector!ComponentInfo components; Vector!EventInfo events; - Mutex add_mutex; + //Mutex add_mutex; Mutex entity_block_alloc_mutex; CallDataAllocator m_call_data_allocator; diff --git a/source/ecs/system.d b/source/ecs/system.d index 28e2e23..84d9862 100644 --- a/source/ecs/system.d +++ b/source/ecs/system.d @@ -53,6 +53,8 @@ package: int m_priority; ///pointer to system implementation void* m_system_pointer; + ///system pass index + int m_pass; ///system name const (char)[] name; @@ -66,7 +68,7 @@ package: EntityManager.Job[] jobs; - System*[] m_dependencies; + //System*[] m_dependencies; ushort[] m_read_only_components; ushort[] m_modified_components; diff --git a/tests/tests.d b/tests/tests.d index ee27305..22753eb 100644 --- a/tests/tests.d +++ b/tests/tests.d @@ -175,7 +175,7 @@ int main() void initialize(ref Entity entity, ref TestComp comp) { - + int o = 1; } void update(EntitiesData data) @@ -284,6 +284,8 @@ import std.meta; gEM.setJobDispachFunc(&dispatch); assert(gEM !is null); + gEM.registerPass("fixed"); + MonoTime time = MonoTime.currTime; gEM.registerComponent!TestComp2; @@ -299,7 +301,7 @@ import std.meta; time = MonoTime.currTime; - gEM.registerSystem!TestSystemWithHighPriority(100); + gEM.registerSystem!TestSystemWithHighPriority(100,"fixed"); gEM.registerSystem!TestSystem(0); //gEM.registerSystem!TestSystemWithHighPriority(100); //gEM.registerSystem!TestSystem2(0); @@ -346,6 +348,7 @@ import std.meta; gEM.removeEntity(idss[j]); gEM.end(); } + gEM.commit(); dur = (MonoTime.currTime - time).total!"usecs"; writeln("Entities adding: ", dur, " usecs"); @@ -373,12 +376,18 @@ import std.meta; Entity entity2; + time = MonoTime.currTime; + foreach (i; 0 .. 500_000) { entity2 = gEM.addEntity(tmpl); gEM.addEntity(tmpl2); } + gEM.commit(); + dur = (MonoTime.currTime - time).total!"usecs"; + writeln("Entities adding2: ", dur, " usecs"); + time = MonoTime.currTime; gEM.begin(); @@ -441,6 +450,7 @@ import std.meta; gEM.begin(); gEM.update(); + gEM.update("fixed"); gEM.end(); writeEntityComponents(gEM.getEntity(entity.id)); From f666dfd1d5e332a82790c07c1a078bca997a0357 Mon Sep 17 00:00:00 2001 From: Mergul Date: Fri, 26 Oct 2018 17:43:51 +0200 Subject: [PATCH 017/217] -onBegin() return type was changed from void to bool -disabling system execution in onBegin() funciton --- source/ecs/manager.d | 67 +++++++++++++++++++++++++------------------- source/ecs/system.d | 3 ++ tests/tests.d | 3 +- 3 files changed, 43 insertions(+), 30 deletions(-) diff --git a/source/ecs/manager.d b/source/ecs/manager.d index ffea30a..cee24f2 100644 --- a/source/ecs/manager.d +++ b/source/ecs/manager.d @@ -61,7 +61,7 @@ class EntityManager id_manager.initialize(); - allocator = BlockAllocator(page_size,pages_in_block); + allocator = BlockAllocator(page_size, pages_in_block); //add_mutex = Mallocator.instance.make!Mutex; entity_block_alloc_mutex = Mallocator.instance.make!Mutex; @@ -72,13 +72,13 @@ class EntityManager pass.name = Mallocator.instance.makeArray("update"); passes.add(pass); - passes_map.add(cast(string)pass.name, cast(ushort)(passes.length - 1)); + passes_map.add(cast(string) pass.name, cast(ushort)(passes.length - 1)); } /************************************************************************************************************************ *Same as "void registerSystem(Sys)(int priority, int pass = 0)" but use pass name instead of id. */ - void registerSystem(Sys)(int priority, const (char)[] pass_name) + void registerSystem(Sys)(int priority, const(char)[] pass_name) { ushort pass = passes_map.get(pass_name, ushort.max); assert(pass != ushort.max); @@ -441,29 +441,35 @@ class EntityManager system.m_update = &callUpdate; } - static string catchFunc()(string member, string func) + static string catchFunc(RetType = void)(string member, string func) { - string ret = "static if (hasMember!(Sys, \"" ~ func ~ "\")) + //dfmt off + static if(is(RetType == void))string ret_str = ""; + else string ret_str = "return "; + string ret = "static if (hasMember!(Sys, \"" ~ func ~ "\") && + Parameters!(Sys."~func~").length == 0 && + is(ReturnType!(Sys."~func~") == "~RetType.stringof~")) { - static void call" ~ func + static "~RetType.stringof~" call" ~ func ~ "(void* system_pointer) { Sys* s = cast(Sys*) system_pointer; - s." ~ func ~ "(); + "~ret_str~"s." ~ func ~ "(); } system." ~ member ~ " = &call" ~ func ~ "; }"; return ret; + //dfmt on } mixin(catchFunc("m_enable", "onEnable")); mixin(catchFunc("m_disable", "onDisable")); mixin(catchFunc("m_create", "onCreate")); mixin(catchFunc("m_destroy", "onDestroy")); - mixin(catchFunc("m_begin", "onBegin")); + mixin(catchFunc!(bool)("m_begin", "onBegin")); mixin(catchFunc("m_end", "onEnd")); system.m_system_pointer = cast(void*) Mallocator.instance.make!Sys; @@ -544,12 +550,12 @@ class EntityManager return cast(Sys*) systems[Sys.system_id].m_system_pointer; } - ushort registerPass(const (char)[] name) + ushort registerPass(const(char)[] name) { UpdatePass* pass = Mallocator.instance.make!UpdatePass; pass.name = Mallocator.instance.makeArray(name); passes.add(pass); - passes_map.add(name,cast(ushort)(passes.length - 1)); + passes_map.add(name, cast(ushort)(passes.length - 1)); return cast(ushort)(passes.length - 1); } @@ -592,7 +598,7 @@ class EntityManager { components.add(info); Comp.component_id = cast(ushort)(components.length - 1); - const (char)[] name = Mallocator.instance.makeArray(Comp.stringof); + const(char)[] name = Mallocator.instance.makeArray(Comp.stringof); components_map.add(name, cast(ushort)(components.length - 1)); } } @@ -636,7 +642,7 @@ class EntityManager /************************************************************************************************************************ *Same as "void update(int pass = 0)" but use pass name instead of id. */ - void update(const (char)[] pass_name) + void update(const(char)[] pass_name) { ushort pass = passes_map.get(pass_name, ushort.max); assert(pass != ushort.max); @@ -654,7 +660,7 @@ class EntityManager foreach (caller; passes[pass].system_callers) { System* sys = &systems[caller.system_id]; - if (sys.enabled) + if (sys.enabled && sys.execute) { //if (sys.m_begin) // sys.m_begin(sys.m_system_pointer); @@ -686,7 +692,7 @@ class EntityManager /************************************************************************************************************************ *Same as "void updateMT(int pass = 0)" but use pass name instead of id. */ - void updateMT(const (char)[] pass_name) + void updateMT(const(char)[] pass_name) { ushort pass = passes_map.get(pass_name, ushort.max); assert(pass != ushort.max); @@ -704,7 +710,7 @@ class EntityManager foreach (caller; passes[pass].system_callers) { System* sys = &systems[caller.system_id]; - if (sys.enabled) + if (sys.enabled && sys.execute) { uint entities_count = 0; foreach (info; caller.infos) @@ -1668,10 +1674,10 @@ class EntityManager commit(); m_call_data_allocator.clear(); - foreach (ref system; instance.systems) + foreach (ref system; systems) { - if (system.m_begin) - (cast(void function(void*)) system.m_begin)(system.m_system_pointer); + if (system.enabled && system.m_begin) + system.execute = (cast(bool function(void*)) system.m_begin)(system.m_system_pointer); } } @@ -1680,10 +1686,10 @@ class EntityManager */ export void end() { - - foreach (ref system; instance.systems) + + foreach (ref system; systems) { - if (system.m_end) + if (system.enabled && system.m_end) (cast(void function(void*)) system.m_end)(system.m_system_pointer); } @@ -1703,7 +1709,7 @@ class EntityManager /*private */ void generateDependencies() { - foreach(pass_id,pass;passes) + foreach (pass_id, pass; passes) { foreach (caller; pass.system_callers) { @@ -1715,8 +1721,8 @@ class EntityManager } uint index = 0; SystemCaller*[] exclusion; - exclusion = (cast(SystemCaller**) alloca((SystemCaller*).sizeof * pass.system_callers.length))[0 - .. pass.system_callers.length]; + exclusion = (cast(SystemCaller**) alloca((SystemCaller*) + .sizeof * pass.system_callers.length))[0 .. pass.system_callers.length]; foreach (caller; pass.system_callers) { index = 0; @@ -1787,8 +1793,8 @@ class EntityManager return 1; } - qsort(pass.system_callers.array.ptr, pass.system_callers.length, (SystemCaller*) - .sizeof, &compareSystems); + qsort(pass.system_callers.array.ptr, pass.system_callers.length, + (SystemCaller*).sizeof, &compareSystems); /*static struct CallerData { @@ -1830,7 +1836,8 @@ class EntityManager if (index > 0) { caller.dependencies = Mallocator.instance.makeArray(exclusion[0 .. index]); - caller.job_group.dependencies = Mallocator.instance.makeArray!(JobGroup*)(index); + caller.job_group.dependencies = Mallocator.instance.makeArray!( + JobGroup*)(index); foreach (j, dep; caller.dependencies) { @@ -2015,8 +2022,10 @@ class EntityManager ~this() { assert(name); - if(name)Mallocator.instance.dispose(name); + if (name) + Mallocator.instance.dispose(name); } + char[] name; Vector!(SystemCaller*) system_callers; } @@ -2041,7 +2050,7 @@ class EntityManager enum pages_in_block = 128; IDManager id_manager; - BlockAllocator/*!(page_size, pages_in_block)*/ allocator; + BlockAllocator /*!(page_size, pages_in_block)*/ allocator; //EventManager event_manager; mixin EventManagerCode; diff --git a/source/ecs/system.d b/source/ecs/system.d index 84d9862..2787c68 100644 --- a/source/ecs/system.d +++ b/source/ecs/system.d @@ -47,6 +47,9 @@ struct System package: + ///should system be executed in current update? + bool execute = true; + ///should system update and catch events? bool m_enabled = false; ///system priority diff --git a/tests/tests.d b/tests/tests.d index 22753eb..a217b91 100644 --- a/tests/tests.d +++ b/tests/tests.d @@ -111,9 +111,10 @@ int main() writeln("On Test System destroy."); } - void onBegin() + bool onBegin() { //writeln("On Test System begin."); + return true; } void onEnd() From 16a5696840b634bbd871a2e341442b341aeac99b Mon Sep 17 00:00:00 2001 From: Mergul Date: Sat, 27 Oct 2018 17:34:27 +0200 Subject: [PATCH 018/217] -removed UpdateBySystems version switch (it's now default behaviour) -beginRegister() and endRegister() was added (every register functions must be called between this calls, update calls can't be called there) -SystemCallers and Systems dependecies is rebuild always in endRegister(); -beginRegister() clear all SystemCallers and Systems dependencies -possibility to get System ID and execution state -JobGroup has now pointer to it's parent (SystemCaller) -SystemCaller clean up destructor --- dub.json | 3 - source/ecs/manager.d | 279 ++++++++++++++++++------------------------- source/ecs/system.d | 20 +++- tests/tests.d | 6 +- 4 files changed, 143 insertions(+), 165 deletions(-) diff --git a/dub.json b/dub.json index c4303f2..bacb5fc 100755 --- a/dub.json +++ b/dub.json @@ -10,9 +10,6 @@ "dflags-posix-ldc": [ "-defaultlib=phobos2-ldc,druntime-ldc" ], - "versions": [ - "UpdateBySystems" - ], "configurations" : [ { "name" : "library", diff --git a/source/ecs/manager.d b/source/ecs/manager.d index cee24f2..fdc2862 100644 --- a/source/ecs/manager.d +++ b/source/ecs/manager.d @@ -20,6 +20,8 @@ import ecs.vector; import ecs.events; alias gEM = EntityManager.instance; +alias gEntityManager = EntityManager.instance; +alias gEventManager = EntityManager.instance; alias SerializeVector = ecs.vector.Vector!ubyte; class EntityManager @@ -50,6 +52,67 @@ class EntityManager instance = null; } + /************************************************************************************************************************ + *Begin registering process. Every register function should be called between beginRegister() and endRegister(). + */ + void beginRegister() + { + assert(!register_state,"beginRegister() can't be called twice before endRegister();"); + register_state = true; + + foreach(pass;passes) + { + foreach(caller;pass.system_callers) + { + Mallocator.instance.dispose(caller); + } + pass.system_callers.clear(); + } + } + + /************************************************************************************************************************ + *End registering process. Every register function should be called between beginRegister() and endRegister(). + */ + void endRegister() + { + assert(register_state,"beginRegister() should be called before endRegister();"); + register_state = false; + + foreach(ref system;systems) + { + if (system.m_update is null) + continue; + + bool added = false; + foreach (i, caller; passes[system.m_pass].system_callers) + { + if (systems[caller.system_id].priority > system.priority) + { + SystemCaller* sys_caller = Mallocator.instance.make!SystemCaller; + sys_caller.system_id = system.id; + sys_caller.job_group.caller = sys_caller; + passes[system.m_pass].system_callers.add(sys_caller, i); + added = true; + break; + } + } + if (!added) + { + SystemCaller* sys_caller = Mallocator.instance.make!SystemCaller; + sys_caller.system_id = system.id; + sys_caller.job_group.caller = sys_caller; + passes[system.m_pass].system_callers.add(sys_caller); + } + + foreach(info;&entities_infos.byValue) + { + addSystemCaller(*info,system.id); + } + } + + generateDependencies(); + } + /************************************************************************************************************************ *Default constructor. */ @@ -81,7 +144,7 @@ class EntityManager void registerSystem(Sys)(int priority, const(char)[] pass_name) { ushort pass = passes_map.get(pass_name, ushort.max); - assert(pass != ushort.max); + assert(pass != ushort.max,"Update pass (Name "~pass_name~") doesn't exist."); registerSystem!(Sys)(priority, pass); } @@ -97,14 +160,15 @@ class EntityManager { alias STC = ParameterStorageClass; - assert(pass < passes.length); + assert(register_state,"asda"); + assert(pass < passes.length,"Update pass (ID "~pass.to!string~") doesn't exist."); System system; system.m_pass = pass; static if (!(hasMember!(Sys, "system_id")) || !is(typeof(Sys.system_id) == ushort)) { - static assert(0, "System should have \"__gshared ushort system_id"); + static assert(0, "Add \"mixin ECS.System;\" in top of system structure;");//"System should have \"__gshared ushort system_id"); } static if (!(hasMember!(Sys, "EntitiesData"))) @@ -489,55 +553,24 @@ class EntityManager if (system.m_create) (cast(void function(void*)) system.m_create)(system.m_system_pointer); + system.m_id = sys_id; systems[sys_id] = system; - Sys.system_id = sys_id; } else { system.name = Mallocator.instance.makeArray(Sys.stringof); systems_map.add(system.name, cast(ushort) systems.length); + system.m_id = cast(ushort)(systems.length); + systems.add(system); if (system.m_create) (cast(void function(void*)) system.m_create)(system.m_system_pointer); systems[$ - 1].enable(); - - Sys.system_id = cast(ushort)(systems.length - 1); - - if (system.m_update !is null) - { - foreach (info; &entities_infos.byValue) - { - addEntityCaller(*info, cast(uint) systems.length - 1); - } - } - - version (UpdateBySystems) - { - bool added = false; - foreach (i, ref caller; passes[pass].system_callers) - { - if (systems[caller.system_id].priority > priority) - { - SystemCaller* sys_caller = Mallocator.instance.make!SystemCaller; - sys_caller.system_id = Sys.system_id; - passes[pass].system_callers.add(sys_caller, i); - added = true; - break; - } - } - if (!added) - { - SystemCaller* sys_caller = Mallocator.instance.make!SystemCaller; - sys_caller.system_id = Sys.system_id; - passes[pass].system_callers.add(sys_caller); - } - } } - - updateEntityCallers(); + Sys.system_id = system.id; } System* getSystem(ushort id) @@ -568,7 +601,7 @@ class EntityManager static if (!(hasMember!(Comp, "component_id")) || !is(typeof(Comp.component_id) == ushort)) { - static assert(0, "Component should have \"__gshared ushort component_id"); + static assert(0, "Add \"mixin ECS.Component;\" in top of component structure;");//"Component should have \"__gshared ushort component_id"); } static if (hasMember!(Comp, "onDestroy") && isFunction!(Comp.onDestroy) @@ -609,7 +642,7 @@ class EntityManager static if (!(hasMember!(Ev, "event_id")) || !is(typeof(Ev.event_id) == ushort)) { - static assert(0, "Event should have \"__gshared ushort event_id"); + static assert(0, "Add \"mixin ECS.Event;\" in top of event structure;");//"Event should have \"__gshared ushort event_id"); } static if (hasMember!(Ev, "onDestroy") && isFunction!(Ev.onDestroy) @@ -654,36 +687,17 @@ class EntityManager */ export void update(ushort pass = 0) { + assert(!register_state); assert(pass < passes.length); - version (UpdateBySystems) + foreach (caller; passes[pass].system_callers) { - foreach (caller; passes[pass].system_callers) + System* sys = &systems[caller.system_id]; + if (sys.enabled && sys.execute) { - System* sys = &systems[caller.system_id]; - if (sys.enabled && sys.execute) + foreach (info; caller.infos) { - //if (sys.m_begin) - // sys.m_begin(sys.m_system_pointer); - foreach (info; caller.infos) - { - CallData data = CallData(caller.system_id, sys, info); - data.update(); - //(cast(SytemFuncType) data.system.m_update)(data); - } - //if (sys.m_end) - // sys.m_end(sys.m_system_pointer); - } - } - } - else - { - foreach (info; &entities_infos.byValue) - { - foreach (data; info.callers) - { - if (data.system.enabled) - data.update(); - //(cast(SytemFuncType) data.system.m_update)(data); //caller(call_data,null); + CallData data = CallData(caller.system_id, sys, info); + data.update(); } } } @@ -701,6 +715,7 @@ class EntityManager void updateMT(ushort pass = 0) { + assert(!register_state); assert(pass < passes.length); assert(m_dispatch_jobs, "Can't update with multithreading without JobDispatch function. Please use setJobDispatchFunc()."); @@ -827,28 +842,6 @@ class EntityManager } } - struct Job - { - CallData[] callers; - - void execute() - { - EntityManager.instance.getThreadID(); - foreach (ref caller; callers) - { - caller.update(); - } - } - } - - struct JobGroup - { - Job[] jobs; - JobGroup*[] dependencies; - uint id; - //uint max_jobs; - } - void setJobDispachFunc(void delegate(JobGroup) func) { m_dispatch_jobs = func; @@ -974,41 +967,17 @@ class EntityManager { if (system.m_update is null) continue; - addEntityCaller(*info, i); + addSystemCaller(*info, i); } - version (UpdateBySystems) - { - foreach (uint i, ref system; systems) - { - if (system.m_update is null) - continue; - addSystemCaller(*info, i); - } - } - - updateEntityCallers(); - entities_infos.add(info.components, info); } return info; } - export void updateEntityCallers() - { - foreach (entity; &entities_infos.byValue) - { - foreach (ref caller; entity.callers) - { - caller.system = &systems[caller.system_id]; - } - } - } - export void addSystemCaller(ref EntityInfo entity, uint system_id) { System* system = &systems[system_id]; - //CallData call_data = CallData(system_id, system, &entity); if (system.m_absent_components) { @@ -1042,51 +1011,6 @@ class EntityManager if (index < passes[system.m_pass].system_callers.length) passes[system.m_pass].system_callers[index].infos.add(&entity); - /*for (; index < entity.callers.length; index++) - { - CallData* caller = &entity.callers[index]; - if (caller.system.priority >= call_data.system.priority) - break; - } - entity.callers.add(call_data, index);*/ - } - - export void addEntityCaller(ref EntityInfo entity, uint system_id) - { - System* system = &systems[system_id]; - CallData call_data = CallData(system_id, system, &entity); - - if (system.m_absent_components) - { - foreach (id; system.m_absent_components) - { - foreach (id2; entity.components) - { - if (id == id2) - return; - } - } - } - - foreach (id; system.m_components) - { - foreach (i2, id2; entity.components) - { - if (id2 == id) - goto is_; - } - return; - is_: - } - - uint index = 0; - for (; index < entity.callers.length; index++) - { - CallData* caller = &entity.callers[index]; - if (caller.system.priority >= call_data.system.priority) - break; - } - entity.callers.add(call_data, index); } /************************************************************************************************************************ @@ -1677,7 +1601,7 @@ class EntityManager foreach (ref system; systems) { if (system.enabled && system.m_begin) - system.execute = (cast(bool function(void*)) system.m_begin)(system.m_system_pointer); + system.m_execute = (cast(bool function(void*)) system.m_begin)(system.m_system_pointer); } } @@ -1927,7 +1851,7 @@ class EntityManager ///pointer to last block EntitiesBlock* last_block; ///array of CallData. Contain data for System calls. - Vector!(CallData) callers; + //Vector!(CallData) callers; ///Mutex used to managing block new alloction } @@ -2000,8 +1924,41 @@ class EntityManager ushort end; } + struct Job + { + CallData[] callers; + + void execute() + { + EntityManager.instance.getThreadID(); + foreach (ref caller; callers) + { + caller.update(); + } + } + } + + struct JobGroup + { + Job[] jobs; + JobGroup*[] dependencies; + uint id; + SystemCaller* caller; + //uint max_jobs; + } + struct SystemCaller { + ~this() + { + if(dependencies) + { + Mallocator.instance.dispose(dependencies); + Mallocator.instance.dispose(exclusion); + } + if(job_group.dependencies)Mallocator.instance.dispose(job_group.dependencies); + } + uint system_id; System* system; Vector!(EntityInfo*) infos; @@ -2036,6 +1993,8 @@ class EntityManager Vector!(UpdatePass*) passes; + bool register_state = false; + //Vector!(SystemCaller*) system_callers; alias SytemFuncType = void function(ref EntityManager.CallData data); diff --git a/source/ecs/system.d b/source/ecs/system.d index 2787c68..787c56c 100644 --- a/source/ecs/system.d +++ b/source/ecs/system.d @@ -45,10 +45,28 @@ struct System return m_priority; } + /************************************************************************************************************************ + *Get system priority. + */ + export bool execute() + { + return m_execute; + } + + /************************************************************************************************************************ + *Get system priority. + */ + export ushort id() + { + return m_id; + } + package: ///should system be executed in current update? - bool execute = true; + bool m_execute = true; + ///system id + ushort m_id; ///should system update and catch events? bool m_enabled = false; diff --git a/tests/tests.d b/tests/tests.d index a217b91..5366d53 100644 --- a/tests/tests.d +++ b/tests/tests.d @@ -285,6 +285,7 @@ import std.meta; gEM.setJobDispachFunc(&dispatch); assert(gEM !is null); + gEM.beginRegister(); gEM.registerPass("fixed"); MonoTime time = MonoTime.currTime; @@ -306,6 +307,7 @@ import std.meta; gEM.registerSystem!TestSystem(0); //gEM.registerSystem!TestSystemWithHighPriority(100); //gEM.registerSystem!TestSystem2(0); + gEM.endRegister(); dur = (MonoTime.currTime - time).total!"usecs"; writeln("Systems register: ", dur, " usecs"); @@ -368,9 +370,11 @@ import std.meta; //foreach(j; 0..1_000)gEM.addEntity(tmpl); + gEM.beginRegister(); gEM.registerSystem!TestSystem2(0); + gEM.endRegister(); - gEM.generateDependencies(); + //gEM.generateDependencies(); //assert(*(cast(EntityID*)(cast(void*)tmpl.info.first_block+24)) == EntityID(1,1)); //assert(*(cast(EntityID*)(cast(void*)tmpl.info.first_block+48)) == EntityID(1,1)); From 3bc5ff2423a5da3ab7e2c220c2a89d9c330f5438 Mon Sep 17 00:00:00 2001 From: Mergul Date: Fri, 2 Nov 2018 15:39:46 +0100 Subject: [PATCH 019/217] -changes in gitignore -changed "absent" to "excluded" everywhere -added Events support: *systems are scanned by handleEvent() function *generate system callers for events *event sending have (untested) multithreaded support *EventInput structure in System has input components for event --- .gitignore | 22 +- dub.json | 3 + source/ecs/attributes.d | 4 +- source/ecs/core.d | 2 + source/ecs/events.d | 158 ++++++++++++-- source/ecs/manager.d | 345 +++++++++++++++++++++++++----- source/ecs/system.d | 12 +- tests/tests.d | 453 +++++++++++++++++++++------------------- 8 files changed, 689 insertions(+), 310 deletions(-) diff --git a/.gitignore b/.gitignore index f203f51..de4c133 100644 --- a/.gitignore +++ b/.gitignore @@ -1,17 +1,5 @@ -dub.userprefs -dub.selections.json -.dub -/.vscode -LOC -perf.data -perf.data.old -*.o -*.a -*.obj -*.exe -*.lib -*.so -*.def -*.lib -*.dll -*.exp \ No newline at end of file +* +!source +!tests +!dub.json +!.gitignore \ No newline at end of file diff --git a/dub.json b/dub.json index bacb5fc..52988fd 100755 --- a/dub.json +++ b/dub.json @@ -10,6 +10,9 @@ "dflags-posix-ldc": [ "-defaultlib=phobos2-ldc,druntime-ldc" ], + "dflagss": [ + "-betterC" + ], "configurations" : [ { "name" : "library", diff --git a/source/ecs/attributes.d b/source/ecs/attributes.d index 6b45dae..3a5ec95 100644 --- a/source/ecs/attributes.d +++ b/source/ecs/attributes.d @@ -2,7 +2,7 @@ module ecs.attributes; ///Used to mark optional components for system. enum optional = "optional"; -///Used to mark absent components for system. Enum 'AbsentComponents' should be used instead of it. -enum absent = "absent"; +///Used to mark components excluded from update for system. Enum 'ExcludedComponents' should be used instead of it. +enum excluded = "excluded"; ///Used to mark readonly components for system. "const" can be used insted. enum readonly = "readonly"; \ No newline at end of file diff --git a/source/ecs/core.d b/source/ecs/core.d index 6b27d26..3095dbb 100644 --- a/source/ecs/core.d +++ b/source/ecs/core.d @@ -1,6 +1,7 @@ module ecs.core; public import ecs.manager; +public import ecs.entity; static struct ECS { @@ -25,5 +26,6 @@ static struct ECS mixin template Event() { __gshared ushort event_id; + EntityID entity_id; } } \ No newline at end of file diff --git a/source/ecs/events.d b/source/ecs/events.d index 20c8c0e..ef81b6c 100644 --- a/source/ecs/events.d +++ b/source/ecs/events.d @@ -4,15 +4,19 @@ import ecs.manager; import ecs.block_allocator; import ecs.entity; +import std.experimental.allocator; +import std.experimental.allocator.mallocator : AlignedMallocator, Mallocator; import std.algorithm.comparison : max; -/* -struct Event + +/*struct Event { - uint type; + uint id; + }*/ -mixin template EventManagerCode() +//mixin template EventManagerCode() +struct EventManager { //@disable this(); @@ -22,7 +26,7 @@ mixin template EventManagerCode() manager = m; }*/ - void sendSelfEvent(Ev)(EntityID id, Ev event) + /*void sendSelfEvent(Ev)(EntityID id, Ev event) { ushort size = cast(ushort)(Ev.sizeof); // + EntityID.sizeof + ushort.sizeof); ushort alignment = cast(ushort)(Ev.alignof); @@ -53,8 +57,6 @@ mixin template EventManagerCode() aligned_index = index; alignNum(aligned_index, alignment); - /*if(alignment > EntityID.sizeof + uint.sizeof)aligned_index = alignment; - else aligned_index = uint.sizeof * 4;*/ } EventBlock* block = list.current_block; @@ -66,22 +68,101 @@ mixin template EventManagerCode() *cast(EntityID*)&block.data[index + 2] = id; *cast(Ev*)&block.data[aligned_index] = event; block.index = cast(ushort)(aligned_index + Ev.sizeof); + }*/ + + void initialize(EntityManager m) + { + allocator = BlockAllocator(events_block_size, events_blocks_in_allocation); + manager = m; + } + + void sendEvent(Ev)(EntityID id, Ev event, uint thread_id = 0) + { + uint block_id = current_index+thread_id; + + EventData* data = &events[Ev.event_id]; + EventBlock* block = data.blocks[block_id]; + EntityManager.EventInfo* info = &gEM.events[Ev.event_id]; + event.entity_id = id; + + if(block is null) + { + block = cast(EventBlock*) allocator.getBlock(); + *block = EventBlock(); + data.first_blocks[block_id] = block; + data.blocks[block_id] = block; + } + + if(block.count >= data.max_events) + { + EventBlock* new_block = cast(EventBlock*) allocator.getBlock(); + *new_block = EventBlock(); + block.next = new_block; + block = new_block; + data.blocks[block_id] = block; + } + + /*void* start = cast(void*)block + data.data_offset + block.count * info.size; + Ev* event_ptr = cast(Ev*)start; + *event_ptr = event;*/ + Ev* event_array = cast(Ev*)(cast(void*)block + data.data_offset); + event_array[block.count] = event; + block.count++; + } + + void swapCurrent() + { + uint threads_count = cast(uint)manager.threads.length; + if(current_index == 0)current_index = threads_count; + else current_index = 0; + + foreach(ref event;events) + { + foreach(ref first_block; event.first_blocks[current_index .. current_index + threads_count]) + { + EventBlock* block = first_block; + while(block) + { + EventBlock* to_dispose = block; + block = block.next; + allocator.freeBlock(to_dispose); + } + first_block = null; + } + foreach(ref block; event.blocks[current_index .. current_index + threads_count]) + { + block = null; + } + } } void clearEvents() { - EventList tmp = current_events; + uint threads_count = cast(uint)manager.threads.length; + foreach(ref event;events) + { + foreach(ref first_block; event.first_blocks) + { + EventBlock* block = first_block; + while(block) + { + EventBlock* to_dispose = block; + block = block.next; + allocator.freeBlock(to_dispose); + } + first_block = null; + } + foreach(ref block; event.blocks) + { + block = null; + } + } + /*EventList tmp = current_events; current_events = process_events; process_events = tmp; EventBlock* block = process_events.first_block; - /*if(block) - { - import std.stdio; - writeln(block.data); - }*/ - while (block) { EventBlock* free = block; @@ -89,7 +170,30 @@ mixin template EventManagerCode() allocator.freeBlock(free); } process_events.first_block = null; - process_events.current_block = null; + process_events.current_block = null;*/ + } + + void allocateData(uint threads_count) + { + if(events) + { + foreach(ref event;events) + { + Mallocator.instance.dispose(event.blocks); + Mallocator.instance.dispose(event.first_blocks); + } + Mallocator.instance.dispose(events); + } + events = Mallocator.instance.makeArray!EventData(gEM.events.length); + foreach(i,ref event;events) + { + event.blocks = Mallocator.instance.makeArray!(EventBlock*)(threads_count*2); + event.first_blocks = Mallocator.instance.makeArray!(EventBlock*)(threads_count*2); + event.data_offset = EventBlock.sizeof;//gEM.events[i]. + gEM.alignNum(event.data_offset, gEM.events[i].alignment); + + event.max_events = cast(ushort)((events_block_size - event.data_offset) / gEM.events[i].size); + } } ///Single page size. Must be power of two. @@ -99,7 +203,7 @@ mixin template EventManagerCode() struct EventBlock { - union + /*union { struct { @@ -108,17 +212,31 @@ mixin template EventManagerCode() } ubyte[events_block_size] data; - } + }*/ + EventBlock* next; + ushort count = 0; } - struct EventList + /*struct EventList { EventBlock* first_block; EventBlock* current_block; + }*/ + + struct EventData + { + ushort data_offset; + ushort max_events; + EventBlock*[] blocks; + EventBlock*[] first_blocks; + + //EventBlock*[] current_blocks; } - EventList current_events; - EventList process_events; + /*EventList current_events; + EventList process_events;*/ + uint current_index = 0; + EventData[] events; BlockAllocator/*!(events_block_size, events_blocks_in_allocation)*/ allocator; EntityManager manager; diff --git a/source/ecs/manager.d b/source/ecs/manager.d index fdc2862..1215c5b 100644 --- a/source/ecs/manager.d +++ b/source/ecs/manager.d @@ -57,12 +57,12 @@ class EntityManager */ void beginRegister() { - assert(!register_state,"beginRegister() can't be called twice before endRegister();"); + assert(!register_state, "beginRegister() can't be called twice before endRegister();"); register_state = true; - foreach(pass;passes) + foreach (pass; passes) { - foreach(caller;pass.system_callers) + foreach (caller; pass.system_callers) { Mallocator.instance.dispose(caller); } @@ -75,13 +75,13 @@ class EntityManager */ void endRegister() { - assert(register_state,"beginRegister() should be called before endRegister();"); + assert(register_state, "beginRegister() should be called before endRegister();"); register_state = false; - foreach(ref system;systems) + foreach (ref system; systems) { if (system.m_update is null) - continue; + continue; bool added = false; foreach (i, caller; passes[system.m_pass].system_callers) @@ -103,10 +103,45 @@ class EntityManager sys_caller.job_group.caller = sys_caller; passes[system.m_pass].system_callers.add(sys_caller); } - - foreach(info;&entities_infos.byValue) + + foreach (info; &entities_infos.byValue) { - addSystemCaller(*info,system.id); + addSystemCaller(*info, system.id); + } + } + + event_manager.allocateData(cast(uint) threads.length); + + foreach(ref info;events) + { + Mallocator.instance.dispose(info.callers); + } + + ushort[] event_callers = (cast(ushort*)alloca(ushort.sizeof * events.length))[0..events.length]; + foreach(ref caller; event_callers)caller = 0; + + foreach(ref system;systems) + { + foreach(caller;system.m_event_callers) + { + event_callers[caller.id]++; + } + } + + foreach(i,ref info; events) + { + info.callers = Mallocator.instance.makeArray!(EventCaller)(event_callers[i]); + } + + foreach(ref caller; event_callers)caller = 0; + + foreach(ref system;systems) + { + foreach(caller;system.m_event_callers) + { + events[caller.id].callers[event_callers[caller.id]].callback = caller.callback; + events[caller.id].callers[event_callers[caller.id]].system = &system; + event_callers[caller.id]++; } } @@ -119,10 +154,11 @@ class EntityManager this(uint threads_count) { if (threads_count == 0) - threads_count = 0; + threads_count = 1; threads = Mallocator.instance.makeArray!ThreadData(threads_count); id_manager.initialize(); + event_manager.initialize(this); allocator = BlockAllocator(page_size, pages_in_block); @@ -144,7 +180,7 @@ class EntityManager void registerSystem(Sys)(int priority, const(char)[] pass_name) { ushort pass = passes_map.get(pass_name, ushort.max); - assert(pass != ushort.max,"Update pass (Name "~pass_name~") doesn't exist."); + assert(pass != ushort.max, "Update pass (Name " ~ pass_name ~ ") doesn't exist."); registerSystem!(Sys)(priority, pass); } @@ -158,17 +194,18 @@ class EntityManager */ void registerSystem(Sys)(int priority, ushort pass = 0) { - alias STC = ParameterStorageClass; + //alias STC = ParameterStorageClass; - assert(register_state,"asda"); - assert(pass < passes.length,"Update pass (ID "~pass.to!string~") doesn't exist."); + assert(register_state, + "registerSystem must be called between beginRegister() and endRegister()."); + assert(pass < passes.length, "Update pass (ID " ~ pass.to!string ~ ") doesn't exist."); System system; system.m_pass = pass; static if (!(hasMember!(Sys, "system_id")) || !is(typeof(Sys.system_id) == ushort)) { - static assert(0, "Add \"mixin ECS.System;\" in top of system structure;");//"System should have \"__gshared ushort system_id"); + static assert(0, "Add \"mixin ECS.System;\" in top of system structure;"); //"System should have \"__gshared ushort system_id"); } static if (!(hasMember!(Sys, "EntitiesData"))) @@ -176,6 +213,126 @@ class EntityManager static assert(0, "System should gave \"EntitiesData\" struct for input components"); } + //dfmt off + static if(hasMember!(Sys,"EventInput")) + { + static string genEventCompList()() + { + string ret = "Sys.EventInput input;\n"; + string type; + //bool has = true; + foreach (member; __traits(allMembers, Sys.EventInput)) + { + if(mixin("fullyQualifiedName!(ConstOf!(PointerTarget!(typeof(Sys.EventInput."~member~")))) == \"const(ecs.entity.Entity)\"")) + { + ret ~= "input." ~ member ~ " = cast(Entity*) data.block.dataBegin() + data.id;\n"; + continue; + } + + bool has = false; + bool optional = false; + foreach(member2; __traits(allMembers, Sys.EntitiesData)) + { + static if(mixin("isBasicType!(typeof(Sys.EntitiesData."~member2~"))")){} + else static if(mixin("fullyQualifiedName!(ConstOf!(PointerTarget!(typeof(Sys.EventInput."~member~")))) == fullyQualifiedName!(ConstOf!(ForeachType!(typeof(Sys.EntitiesData."~member2~"))))")) + { + has = true; + if(mixin("hasUDA!(Sys.EntitiesData."~member2~",\"optional\")"))optional = true; + break; + } + } + if(!has)assert(0); + + if(optional)ret ~= "input." ~ member ~ " = null;\n"; + else ret ~= "input." ~ member ~ " = cast(typeof(Sys.EventInput." ~ member + ~ "))(cast(void*) data.block + info.deltas[typeof(Sys.EventInput." + ~ member ~ ").component_id] + data.id * typeof(Sys.EventInput." ~ member + ~ ").sizeof);\n"; + } + return ret; + } + + //pragma(msg,genEventCompList()); + //pragma(msg,genEventCompList()); + + static string checkHandler()(string member) + { + string ret; + ret ~= "(Parameters!(Sys."~member~")).length == 2 && "; + ret ~= "((is(Parameters!(Sys."~member~")[0] == Sys.EventInput) && hasStaticMember!(Parameters!(Sys."~member~")[1],\"event_id\")) ||"; + ret ~= " (is(Parameters!(Sys."~member~")[1] == Sys.EventInput) && hasStaticMember!(Parameters!(Sys."~member~")[0],\"event_id\")))"; + return ret; + } + + /*static struct Handler + { + ushort id; + void* callback; + }*/ + + static string catchEventHanlders()() + { + int event_handlers = 0; + string ret; + string event_param; + + static if(__traits(hasMember, Sys, "handleEvent")) + { + foreach(func; __traits(getOverloads, Sys, "handleEvent")) + { + event_handlers++;//pragma(msg,"kupa"); + } + + //ret ~= "Handler[] handlers = (cast(Handler*)alloca("~event_handlers.to!string~" * (Handler).sizeof))[0 .. "~event_handlers.to!string~"];\n"; + ret ~= "system.m_event_callers = Mallocator.instance.makeArray!(System.EventCaller)("~event_handlers.to!string~");"; + event_handlers = 0; + + foreach(j,func; __traits(getOverloads, Sys, "handleEvent")) + { + event_param = "Parameters!(__traits(getOverloads, Sys, \"handleEvent\")["~j.to!string~"])[1]"; + ret ~= "static void callHandler"~event_handlers.to!string~"(ref EventCallData data)\n{\n"; + ret ~= "Sys* s = cast(Sys*) data.system_pointer; + EntityInfo* info = data.block.type_info;"; + ret ~= genEventCompList(); + ret ~= "s.handleEvent(input, *cast("~event_param~"*)data.event);"; + ret ~= "}\n"; + ret ~= "system.m_event_callers["~event_handlers.to!string~"].callback = cast(void*)&callHandler"~event_handlers.to!string~";"; + ret ~= "system.m_event_callers["~event_handlers.to!string~"].id = "~event_param~".event_id;"; + event_handlers++; + } + + /*ret ~= "ushort max_id = 0;"; + ret ~= "foreach(handler;handlers) + { + if(handler.id > max_id)max_id = handler.id; + }"; + ret ~= "system.m_event_callback = Mallocator.instance.makeArray!(System.EventHandler)(max_id);"; + ret ~= "foreach(handler;handlers) + { + system.m_event_callback[handler.id] = handler.callback; + }";*/ + } + + /*static if(__traits(hasMember, Sys, "handleEvent"))//foreach(member; __traits(allMembers,Sys)) + { + + //static foreach() + static if (member == "handleEvent" && mixin("isFunction!(Sys."~member~")")) + { + static if(mixin(checkHandler(member))) + { + event_handlers++; + } + } + }*/ + return ret; + } + + //pragma(msg,catchEventHanlders()); + mixin(catchEventHanlders()); + } + //dfmt on + static string genCompList()() { @@ -199,7 +356,7 @@ class EntityManager uint req; uint opt; - uint absent; + uint excluded; uint read_only; uint modified; foreach (member; __traits(allMembers, Sys.EntitiesData)) @@ -230,9 +387,9 @@ class EntityManager attribs++; //break; } - else if (att == "absent") + else if (att == "excluded") { - absent++; + excluded++; attribs++; //break; } @@ -242,7 +399,7 @@ class EntityManager } } assert(attribs <= 1, - "EntitiesData member can't have both \"@optional\" and \"@absent\"."); + "EntitiesData member can't have both \"@optional\" and \"@excluded\"."); if (!attribs) req++; if (is_read_only) @@ -253,17 +410,17 @@ class EntityManager } } - static if (__traits(hasMember, Sys, "AbsentComponents")) + static if (__traits(hasMember, Sys, "ExcludedComponents")) { - static if (is(Sys.AbsentComponents == enum)) + static if (is(Sys.ExcludedComponents == enum)) { - absent += (Fields!(Sys.AbsentComponents)).length; //static assert(0,"Enum AbsentComponents are not implemented yet."); + excluded += (Fields!(Sys.ExcludedComponents)).length; //static assert(0,"Enum ExcludedComponents are not implemented yet."); } - else static if (__traits(compiles, allSameType!(string, typeof(Sys.AbsentComponents))) - && allSameType!(string, typeof(Sys.AbsentComponents)) - && isExpressions!(Sys.AbsentComponents)) + else static if (__traits(compiles, allSameType!(string, typeof(Sys.ExcludedComponents))) + && allSameType!(string, typeof(Sys.ExcludedComponents)) + && isExpressions!(Sys.ExcludedComponents)) { - absent += Sys.AbsentComponents.length; + excluded += Sys.ExcludedComponents.length; } } @@ -273,39 +430,39 @@ class EntityManager if (opt > 0) ret ~= "system.m_optional_components = Mallocator.instance.makeArray!ushort(" ~ opt.to!string ~ ");"; - if (absent > 0) - ret ~= "system.m_absent_components = Mallocator.instance.makeArray!ushort(" - ~ absent.to!string ~ ");"; + if (excluded > 0) + ret ~= "system.m_excluded_components = Mallocator.instance.makeArray!ushort(" + ~ excluded.to!string ~ ");"; if (read_only > 0) ret ~= "system.m_read_only_components = Mallocator.instance.makeArray!ushort(" ~ read_only.to!string ~ ");"; if (modified > 0) ret ~= "system.m_modified_components = Mallocator.instance.makeArray!ushort(" ~ modified.to!string ~ ");"; - ret ~= "ushort comp;"; //uint opt = 0;uint req = 0;uint absent = 0;"; + ret ~= "ushort comp;"; //uint opt = 0;uint req = 0;uint excluded = 0;"; opt = 0; req = 0; - absent = 0; + excluded = 0; read_only = 0; modified = 0; - static if (__traits(hasMember, Sys, "AbsentComponents")) + static if (__traits(hasMember, Sys, "ExcludedComponents")) { - static if (is(Sys.AbsentComponents == enum)) + static if (is(Sys.ExcludedComponents == enum)) { - //static assert(0,"Enum AbsentComponents are not implemented yet."); - foreach (str; Fields!(Sys.AbsentComponents)) - ret ~= "system.m_absent_components[" ~ (absent++) + //static assert(0,"Enum ExcludedComponents are not implemented yet."); + foreach (str; Fields!(Sys.ExcludedComponents)) + ret ~= "system.m_excluded_components[" ~ (excluded++) .to!string ~ "] = components_map.get(\"" ~ str.stringof ~ "\", ushort.max);"; } - else static if (__traits(compiles, allSameType!(string, typeof(Sys.AbsentComponents))) - && allSameType!(string, typeof(Sys.AbsentComponents)) - && isExpressions!(Sys.AbsentComponents)) + else static if (__traits(compiles, allSameType!(string, typeof(Sys.ExcludedComponents))) + && allSameType!(string, typeof(Sys.ExcludedComponents)) + && isExpressions!(Sys.ExcludedComponents)) { - foreach (str; Sys.AbsentComponents) - ret ~= "system.m_absent_components[" ~ (absent++) + foreach (str; Sys.ExcludedComponents) + ret ~= "system.m_excluded_components[" ~ (excluded++) .to!string ~ "] = components_map.get(\"" ~ str ~ "\", ushort.max);"; } } @@ -349,9 +506,9 @@ class EntityManager has_att = true; //break; } - else if (att == "absent") + else if (att == "excluded") { - ret ~= "system.m_absent_components[" ~ (absent++) + ret ~= "system.m_excluded_components[" ~ (excluded++) .to!string ~ "] = comp;"; has_att = true; //break; @@ -399,7 +556,7 @@ class EntityManager ushort comp; uint req = 0; uint opt = 0; - uint absent = 0; + uint excluded = 0; foreach (member; __traits(allMembers, Sys.EntitiesData)) { if (is(typeof(__traits(getMember, Sys.EntitiesData, @@ -435,9 +592,9 @@ class EntityManager has_att = true; break; } - else if (att == "absent") + else if (att == "excluded") { - absent++; + excluded++; has_att = true; break; } @@ -601,7 +758,7 @@ class EntityManager static if (!(hasMember!(Comp, "component_id")) || !is(typeof(Comp.component_id) == ushort)) { - static assert(0, "Add \"mixin ECS.Component;\" in top of component structure;");//"Component should have \"__gshared ushort component_id"); + static assert(0, "Add \"mixin ECS.Component;\" in top of component structure;"); //"Component should have \"__gshared ushort component_id"); } static if (hasMember!(Comp, "onDestroy") && isFunction!(Comp.onDestroy) @@ -642,7 +799,7 @@ class EntityManager static if (!(hasMember!(Ev, "event_id")) || !is(typeof(Ev.event_id) == ushort)) { - static assert(0, "Add \"mixin ECS.Event;\" in top of event structure;");//"Event should have \"__gshared ushort event_id"); + static assert(0, "Add \"mixin ECS.Event;\" in top of event structure;"); //"Event should have \"__gshared ushort event_id"); } static if (hasMember!(Ev, "onDestroy") && isFunction!(Ev.onDestroy) @@ -979,9 +1136,9 @@ class EntityManager { System* system = &systems[system_id]; - if (system.m_absent_components) + if (system.m_excluded_components) { - foreach (id; system.m_absent_components) + foreach (id; system.m_excluded_components) { foreach (id2; entity.components) { @@ -1581,12 +1738,66 @@ class EntityManager } } + void updateEvents() + { + bool empty = true; + //uint index = event_manager. + while(1) + { + event_manager.swapCurrent(); + //event_manager.clearEvents(); + uint current_index; + if(event_manager.current_index == 0)current_index = cast(uint)threads.length; + else current_index = 0; + foreach(i,event;event_manager.events) + { + foreach(first_block;event.first_blocks[current_index .. current_index + threads.length]) + { + EventManager.EventBlock* block = first_block; + if(block)empty = false; + while(block) + { + EventCallData call_data; + void* event_pointer = cast(void*)block + event.data_offset; + call_data.event = event_pointer; + foreach(j;0..block.count) + { + //void* event_pointer = cast(void*)block + event.data_offset; + EntityID entity_id = *cast(EntityID*)event_pointer; + Entity* entity = id_manager.getEntityPointer(entity_id); + call_data.block = getMetaData(entity); + + static if (EntityID.sizeof == 8) + call_data.id = cast(ushort)((cast(void*)entity - call_data.block.dataBegin()) >> 3); + else + call_data.id = cast(ushort)((cast(void*)entity - call_data.block.dataBegin()) / EntityID.sizeof); + + foreach(caller; events[i].callers) + { + call_data.system_pointer = caller.system.m_system_pointer; + (cast(void function(ref EventCallData))caller.callback)(call_data); + } + event_pointer += events[i].size; + } + block = block.next; + } + } + } + if(empty)break; + empty = true; + //event_manager.clearEvents(); + } + //event_manager.swapCurrent(); + } + export void commit() { + updateEvents(); id_manager.optimize(); updateBlocks(); removeEntities(); changeEntities(); + event_manager.clearEvents(); } /************************************************************************************************************************ @@ -1601,7 +1812,8 @@ class EntityManager foreach (ref system; systems) { if (system.enabled && system.m_begin) - system.m_execute = (cast(bool function(void*)) system.m_begin)(system.m_system_pointer); + system.m_execute = (cast(bool function(void*)) system.m_begin)( + system.m_system_pointer); } } @@ -1619,7 +1831,7 @@ class EntityManager commit(); - //clearEvents(); + //event_manager.clearEvents(); } private void getThreadID() @@ -1630,6 +1842,11 @@ class EntityManager thread_id = 0; } + void sendEvent(Ev)(EntityID id, Ev event) + { + event_manager.sendEvent(id, event, thread_id); + } + /*private */ void generateDependencies() { @@ -1795,10 +2012,25 @@ class EntityManager void function(void* pointer) destroy_callback; } + struct EventCaller + { + System* system; + void* callback; + } + + struct EventCallData + { + EntitiesBlock* block; + void* system_pointer; + void* event; + ushort id; + } + struct EventInfo { ushort size; ushort alignment; + EventCaller[] callers; void function(void* pointer) destroy_callback; } @@ -1951,12 +2183,13 @@ class EntityManager { ~this() { - if(dependencies) + if (dependencies) { Mallocator.instance.dispose(dependencies); Mallocator.instance.dispose(exclusion); } - if(job_group.dependencies)Mallocator.instance.dispose(job_group.dependencies); + if (job_group.dependencies) + Mallocator.instance.dispose(job_group.dependencies); } uint system_id; @@ -2011,8 +2244,8 @@ class EntityManager IDManager id_manager; BlockAllocator /*!(page_size, pages_in_block)*/ allocator; - //EventManager event_manager; - mixin EventManagerCode; + EventManager event_manager; + //mixin EventManagerCode; //Vector!EntityID entities_to_remove; //Vector!(EntitiesBlock*) blocks_to_update; diff --git a/source/ecs/system.d b/source/ecs/system.d index 787c56c..9c61591 100644 --- a/source/ecs/system.d +++ b/source/ecs/system.d @@ -61,6 +61,12 @@ struct System return m_id; } + struct EventCaller + { + ushort id; + void* callback; + } + package: ///should system be executed in current update? @@ -82,8 +88,8 @@ package: ///required components ushort[] m_components; - ///absent components - ushort[] m_absent_components; + ///excluded components + ushort[] m_excluded_components; ///optional components ushort[] m_optional_components; @@ -93,6 +99,8 @@ package: ushort[] m_read_only_components; ushort[] m_modified_components; + EventCaller[] m_event_callers; + //void function(ref EntityManager.CallData data) m_update; void* m_update; ///workaroud for DMD bug with upper line diff --git a/tests/tests.d b/tests/tests.d index 5366d53..7f9f72b 100644 --- a/tests/tests.d +++ b/tests/tests.d @@ -10,253 +10,280 @@ import ecs.core; import core.time; import std.stdio; -int main() +struct TestEvent { + mixin ECS.Event;//__gshared ushort event_id; + int a; +} - struct TestEvent +struct TestEvent2 +{ + mixin ECS.Event;//__gshared ushort event_id; + float a; +} + +static struct TestComp +{ + mixin ECS.Component;//__gshared ushort component_id; + int a = 1; + ulong b = 2; + + static void serializeComponent(SerializeVector output) { - mixin ECS.Event;//__gshared ushort event_id; - int a; + } - struct TestEvent2 + static void deserializeComponent(ubyte[] data) { - mixin ECS.Event;//__gshared ushort event_id; - float a; + + } +} + +static struct TestComp2 +{ + mixin ECS.Component;//__gshared ushort component_id; + int b = 3; + int a = 4; + + static void serializeComponent(ref TestComp comp, SerializeVector output) + { + } - static struct TestComp + static void deserializeComponent(ref TestComp comp, ubyte[] data) { - mixin ECS.Component;//__gshared ushort component_id; - int a = 1; - ulong b = 2; - static void serializeComponent(SerializeVector output) + } +} + +static struct TestComp3 +{ + mixin ECS.Component;//__gshared ushort component_id; + uint gg = 5; //good game + uint bg = 6; //bad game + + void serializeComponent(SerializeVector output) + { + + } + + void deserializeComponent(ubyte[] data) + { + + } +} + +static struct TestComp4 +{ + mixin ECS.Component;//__gshared ushort component_id; + uint gg = 7; //good game + uint bg = 8; //bad game + ulong a = 9; + ulong b = 10; + ulong c = 11; + ulong g = 12; + + static void serializeComponent(ref TestComp comp, SerializeVector output) + { + + } + + static void deserializeComponent(ref TestComp comp, ubyte[] data) + { + + } +} + +struct TestSystem +{ + mixin ECS.System!16;//__gshared ushort system_id; + + void onCreate() + { + writeln("On Test System create."); + } + + void onDestroy() + { + writeln("On Test System destroy."); + } + + bool onBegin() + { + //writeln("On Test System begin."); + return true; + } + + void onEnd() + { + //writeln("On Test System end."); + } + + void initialize(ref Entity entity, ref TestComp comp) + { + + } + + static struct EntitiesData + { + size_t length; + TestComp[] test; + TestComp2[] test2; + @readonly @optional const(TestComp3)[] test3; + //@excluded TestComp4[] test4; + } + + void update(ref Entity entity, ref TestComp test, ref TestComp2 test2)//, TestComp3* test3) //ref TestComp comp) + { + assert(cast(size_t)&test % TestComp.alignof == 0); + assert(cast(size_t)&test2 % TestComp2.alignof == 0); + import std.stdio; + + test.a += 1000; + test.b += 2000; + test2.b += 2; + test2.a = 8; + } + + void update(EntitiesData data) + { + foreach(i;0..data.length) { - - } - - static void deserializeComponent(ubyte[] data) - { - + data.test[i].a += 1000; + data.test[i].b += 2000; + data.test2[i].b += 2; + data.test2[i].a = 8; } } - static struct TestComp2 + void handleEvent(TestEvent event, ref TestComp test, ref TestComp2 test2, TestComp3* test3) { - mixin ECS.Component;//__gshared ushort component_id; - int b = 3; - int a = 4; - static void serializeComponent(ref TestComp comp, SerializeVector output) - { + } +} - } +struct TestSystemWithHighPriority +{ + mixin ECS.System!16;//__gshared ushort system_id; - static void deserializeComponent(ref TestComp comp, ubyte[] data) - { - - } + static struct EntitiesData + { + TestComp[] test; } - static struct TestComp3 + void initialize(ref Entity entity, ref TestComp comp) { - mixin ECS.Component;//__gshared ushort component_id; - uint gg = 5; //good game - uint bg = 6; //bad game - - void serializeComponent(SerializeVector output) - { - - } - - void deserializeComponent(ubyte[] data) - { - - } + int o = 1; } - static struct TestComp4 + void update(EntitiesData data) { - mixin ECS.Component;//__gshared ushort component_id; - uint gg = 7; //good game - uint bg = 8; //bad game - ulong a = 9; - ulong b = 10; - ulong c = 11; - ulong g = 12; - - static void serializeComponent(ref TestComp comp, SerializeVector output) - { - - } - - static void deserializeComponent(ref TestComp comp, ubyte[] data) - { - - } + } - struct TestSystem + /*void handleEvent(Event event, ref TestComp comp) { - mixin ECS.System!16;//__gshared ushort system_id; - void onCreate() - { - writeln("On Test System create."); - } - - void onDestroy() - { - writeln("On Test System destroy."); - } - - bool onBegin() - { - //writeln("On Test System begin."); - return true; - } - - void onEnd() - { - //writeln("On Test System end."); - } - - void initialize(ref Entity entity, ref TestComp comp) - { - - } - - static struct EntitiesData - { - size_t length; - TestComp[] test; - TestComp2[] test2; - @readonly @optional const(TestComp3)[] test3; - //@absent TestComp4[] test4; - } - - void update(ref Entity entity, ref TestComp test, ref TestComp2 test2)//, TestComp3* test3) //ref TestComp comp) - { - assert(cast(size_t)&test % TestComp.alignof == 0); - assert(cast(size_t)&test2 % TestComp2.alignof == 0); - import std.stdio; - - test.a += 1000; - test.b += 2000; - test2.b += 2; - test2.a = 8; - } - - void update(EntitiesData data) - { - foreach(i;0..data.length) - { - data.test[i].a += 1000; - data.test[i].b += 2000; - data.test2[i].b += 2; - data.test2[i].a = 8; - } - } - - void handleEvent(TestEvent event, ref TestComp test, ref TestComp2 test2, TestComp3* test3) - { - - } - } - - struct TestSystemWithHighPriority - { - mixin ECS.System!16;//__gshared ushort system_id; - - static struct EntitiesData - { - TestComp[] test; - } - - void initialize(ref Entity entity, ref TestComp comp) - { - int o = 1; - } - - void update(EntitiesData data) - { - - } - - /*void handleEvent(Event event, ref TestComp comp) - { - - }*/ - } + }*/ +} import std.meta; - struct TestSystem2 +struct TestSystem2 +{ + mixin ECS.System!16;//__gshared ushort system_id; + + /*enum ExcludedComponents0 { - mixin ECS.System!16;//__gshared ushort system_id; - - enum AbsentComponents0 - { - TestComp, - TestComp4 - } - - alias AbsentComponents = AliasSeq!("TestComp", "TestComp4"); - - string AbsentComponents2; - - static struct EntitiesData - { - short length; - const (Entity)[] entity; - TestComp3[] test; - //@absent TestComp[] testt; - } - - void onEnable() - { - import std.stdio; - - writeln("TestSystem2 enabled"); - } - - void onDisable() - { - import std.stdio; - - writeln("TestSystem2 disabled"); - } - - void initialize(ref Entity entity, ref TestComp comp) - { - - } - - void update(ref EntitiesData data) - { - foreach(i;0..data.test.length) - { - data.test[i].gg += 14; - gEM.sendSelfEvent!(TestEvent)(data.entity[i].id, TestEvent()); - } - } - - void lateUpdate(ref EntitiesData data) - { - foreach(i;0..data.test.length) - { - data.test[i].gg -= 1; - gEM.sendSelfEvent!(TestEvent)(data.entity[i].id, TestEvent()); - } - } - - /*void handleEvent(Event event, ref TestComp comp) - { - - }*/ + TestComp, + TestComp4 } + alias ExcludedComponents = AliasSeq!("TestComp", "TestComp4"); + + string ExcludedComponents2;*/ + + static struct EntitiesData + { + short length; + const (Entity)[] entity; + TestComp3[] test; + //@excluded TestComp[] testt; + } + + static struct EventInput + { + Entity* entity; + TestComp3* test; + //TestComp* tt; + } + + void handleEvent(EventInput input, ref TestEvent event) + { + input.test.bg = event.a; + TestEvent2 event2; + event2.a = event.a + 8; + gEM.sendEvent(input.entity.id, event2); + } + + void handleEvent(EventInput input, ref TestEvent2 event) + { + input.test.gg = cast(uint)event.a; + } + + void onEnable() + { + import std.stdio; + + writeln("TestSystem2 enabled"); + } + + void onDisable() + { + import std.stdio; + + writeln("TestSystem2 disabled"); + } + + void initialize(ref Entity entity, ref TestComp comp) + { + + } + + void update(EntitiesData data) + { + foreach(i;0..data.test.length) + { + data.test[i].gg += 14; + TestEvent event; + event.a = data.test[i].gg + 4; + gEM.sendEvent(data.entity[i].id, event);//*/ + /*TestEvent2 event2; + event2.a = data.test[i].gg + 8; + gEM.sendEvent(data.entity[i].id, event2);//*/ + //gEM.sendEvent!(TestEvent)(data.entity[i].id, event); + //gEM.sendSelfEvent!(TestEvent)(data.entity[i].id, TestEvent()); + } + } + + void lateUpdate(ref EntitiesData data) + { + foreach(i;0..data.test.length) + { + data.test[i].gg -= 1; + //gEM.sendSelfEvent!(TestEvent)(data.entity[i].id, TestEvent()); + } + } + + /*void handleEvent(Event event, ref TestComp comp) + { + + }*/ +} + +int main() +{ + void dispatch(EntityManager.JobGroup jobs) { foreach(job;jobs.jobs) From 60f720151e38aa9721ba47675a9afb280843313c Mon Sep 17 00:00:00 2001 From: Mergul Date: Fri, 2 Nov 2018 15:47:50 +0100 Subject: [PATCH 020/217] -changed .gitignore -imports temporarly removed from repo --- .gitignore | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index de4c133..34d64bd 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,8 @@ * -!source -!tests +!*/ +!source/** +!tests/** + +!README.md !dub.json !.gitignore \ No newline at end of file From fef55bd790a922f349f7f037143dc0ea4cdb7ba0 Mon Sep 17 00:00:00 2001 From: Mergul Date: Fri, 2 Nov 2018 15:52:35 +0100 Subject: [PATCH 021/217] -removed imports (temporarly) --- import/ecs/ecs.di | 112 ----------- import/ecs/entity.di | 30 --- import/ecs/entity_allocator.di | 11 -- import/ecs/events.di | 9 - import/ecs/hash_map.di | 328 --------------------------------- import/ecs/id_manager.di | 20 -- import/ecs/manager.di | 287 ----------------------------- import/ecs/package.di | 7 - import/ecs/string_intern.di | 31 ---- import/ecs/system.di | 26 --- import/ecs/traits.di | 20 -- import/ecs/vector.di | 274 --------------------------- 12 files changed, 1155 deletions(-) delete mode 100644 import/ecs/ecs.di delete mode 100644 import/ecs/entity.di delete mode 100644 import/ecs/entity_allocator.di delete mode 100644 import/ecs/events.di delete mode 100644 import/ecs/hash_map.di delete mode 100644 import/ecs/id_manager.di delete mode 100644 import/ecs/manager.di delete mode 100644 import/ecs/package.di delete mode 100644 import/ecs/string_intern.di delete mode 100644 import/ecs/system.di delete mode 100644 import/ecs/traits.di delete mode 100644 import/ecs/vector.di diff --git a/import/ecs/ecs.di b/import/ecs/ecs.di deleted file mode 100644 index 13041de..0000000 --- a/import/ecs/ecs.di +++ /dev/null @@ -1,112 +0,0 @@ -// D import file generated from 'source\ecs\ecs.d' -module ecs.ecs; -import std.stdio; -version (Design) -{ - alias SytemFuncType = void function(ref SystemCallData data, void* componentsStart); - struct HasComponentsStore - { - ulong[4] bits; - bool has(HasComponentsStore components); - bool notIn(HasComponentsStore components); - int length(); - } - struct ComponentInfo - { - int size; - int aligment; - SerializeJSON funsSerJ; - SerializeBiN funcSerB; - } - struct System - { - HasComponentsStore requiredComponents; - HasComponentsStore absenComponents; - HasComponentsStore maybeComponents; - bool enabled; - int priority; - SytemFuncType func; - } - struct SystemCallData - { - System* system; - int[] componentsDt; - } - struct EntityTypeData - { - HasComponentsStore components; - int[] deltas; - int totalSize; - int totalAligment = 8; - SystemCallData[] systems; - } - struct EntitiesBlock - { - EntityTypeData* typeData; - Entity* freeEntitySlot; - EntitiesBlock* nextBlock; - } - struct EntityID - { - ulong id = (ulong).max; - static immutable notUsedValue = EntityID((ulong).max); - } - struct Entity - { - EntityID entityID = EntityID.notUsedValue; - union - { - string name; - Entity* nextFreeSlot; - } - uint group; - EntityID entityID; - } - struct Template - { - HasComponentsStore hasComp; - Entity* entity; - } - struct Manager - { - EntityAllocator entityArrayAllcoator; - ComponentInfo[] components; - System[] systems; - HashMap!(HasComponentsStore, EntitiesBlock*) entitiesDatas; - HashMapTwoWays!(string, Entity*) nameMap; - HashMapTwoWays!(EntityID, Entity*) idMap; - EntitiesBlock* getEntitiesBlock(HasComponentsStore hasComponents); - EntitiesBlock* addNewBlock(HasComponentsStore hasComponents, EntitiesBlock* firstBlock); - void alignNum(ref int num, int aligment); - EntityTypeData* newEntityTypeData(HasComponentsStore hasComponents); - void addEntity(Template* templ); - void addSystem(Func)(int priority) - { - HasComponentsStore requiredComponents; - HasComponentsStore absenComponents; - HasComponentsStore maybeComponents; - void systemCaller(ref SystemCallData data, void* componentsStart); - System* system = new System(&systemCaller, entTypeData); - systems ~= system; - foreach (ref entTypeData; entitiesDatas) - { - if (!entTypeData.hasComp.has(requiredComponents) || !entTypeData.hasComp.notIn(absenComponents)) - { - continue; - } - entTypeData.systems ~= system; - } - } - } - void someSystem(CompA a, CompB b, CompC* c); - void main(); - class System - { - void start(); - void end(); - void update(ref ObjRend a); - void useEvent(EventData evvv, ref ObjRend a); - } - alias SerializeVector = ubyte[]; - __gshared EntityManager gEntityManager; -} diff --git a/import/ecs/entity.di b/import/ecs/entity.di deleted file mode 100644 index db6208b..0000000 --- a/import/ecs/entity.di +++ /dev/null @@ -1,30 +0,0 @@ -// D import file generated from 'source\ecs\entity.d' -module ecs.entity; -import ecs.manager; -struct EntityID -{ - uint id; - uint counter; -} -struct Entity -{ - EntityID id; - void updateID(); - T* getComponent(T)() - { - EntityManager.EntitiesBlock* block = gEM.getMetaData(&this); - EntityManager.EntityInfo* info = block.type_data; - if (T.component_id >= info.deltas.length || info.deltas[T.component_id] == 0) - return null; - return cast(T*)(cast(void*)&this + info.deltas[T.component_id]); - } -} -export struct EntityTemplate -{ - ubyte[] entity_data; - EntityManager.EntityInfo* info; - T* getComponent(T)() - { - return cast(T*)(entity_data.ptr + info.deltas[T.component_id]); - } -} diff --git a/import/ecs/entity_allocator.di b/import/ecs/entity_allocator.di deleted file mode 100644 index 66472fd..0000000 --- a/import/ecs/entity_allocator.di +++ /dev/null @@ -1,11 +0,0 @@ -// D import file generated from 'source\ecs\entity_allocator.d' -module ecs.entity_allocator; -import ecs.manager; -import std.experimental.allocator; -import std.experimental.allocator.mallocator : AlignedMallocator, Mallocator; -struct EntityAllocator -{ - void* next_block; - void* getBlock(); - private void allocBlock(); -} diff --git a/import/ecs/events.di b/import/ecs/events.di deleted file mode 100644 index 73085c6..0000000 --- a/import/ecs/events.di +++ /dev/null @@ -1,9 +0,0 @@ -// D import file generated from 'source\ecs\events.d' -module ecs.events; -struct Event -{ - uint type; -} -class EventManager -{ -} diff --git a/import/ecs/hash_map.di b/import/ecs/hash_map.di deleted file mode 100644 index d621ad8..0000000 --- a/import/ecs/hash_map.di +++ /dev/null @@ -1,328 +0,0 @@ -// D import file generated from 'source\ecs\hash_map.d' -module ecs.hash_map; -import std.traits; -import ecs.vector; -import ecs.traits; -enum doNotInline = "version(DigitalMars)pragma(inline,false);version(LDC)pragma(LDC_never_inline);"; -private enum HASH_EMPTY = 0; -private enum HASH_DELETED = 1; -private enum HASH_FILLED_MARK = ulong(1) << 8 * (ulong).sizeof - 1; -export ulong defaultHashFunc(T)(auto ref T t) -{ - static if (isIntegral!T) - { - return hashInt(t); - } - else - { - return hashInt(t.hashOf); - } -} -export nothrow @nogc @safe ulong hashInt(ulong x); -struct HashMap(KeyPar, ValuePar, alias hashFunc = defaultHashFunc) -{ - alias Key = KeyPar; - alias Value = ValuePar; - enum rehashFactor = 0.75; - enum size_t getIndexEmptyValue = size_t.max; - static struct KeyVal - { - Key key; - Value value; - } - static struct Bucket - { - ulong hash; - KeyVal keyValue; - } - Vector!Bucket elements; - size_t length; - size_t markerdDeleted; - export void clear() - { - elements.clear(); - length = 0; - markerdDeleted = 0; - } - export void reset() - { - elements.reset(); - length = 0; - markerdDeleted = 0; - } - export bool isIn(ref Key el) - { - return getIndex(el) != getIndexEmptyValue; - } - export bool isIn(Key el) - { - return getIndex(el) != getIndexEmptyValue; - } - export Value* getPtr()(auto ref Key k) - { - size_t index = getIndex(k); - if (index == getIndexEmptyValue) - { - return null; - } - else - { - return &elements[index].keyValue.value; - } - } - export ref Value get()(auto ref Key k) - { - size_t index = getIndex(k); - assert(index != getIndexEmptyValue); - return elements[index].keyValue.value; - } - deprecated("Use get with second parameter.") export auto ref Value getDefault()(auto ref Key k, auto ref Value defaultValue) - { - return get(k, defaultValue); - } - export auto ref Value get()(auto ref Key k, auto ref Value defaultValue) - { - size_t index = getIndex(k); - if (index == getIndexEmptyValue) - { - return defaultValue; - } - else - { - return elements[index].keyValue.value; - } - } - export ref Value getInsertDefault()(auto ref Key k, auto ref Value defaultValue) - { - size_t index = getIndex(k); - if (index == getIndexEmptyValue) - { - add(k, defaultValue); - } - index = getIndex(k); - assert(index != getIndexEmptyValue); - return elements[index].keyValue.value; - } - export bool tryRemove(Key el) - { - size_t index = getIndex(el); - if (index == getIndexEmptyValue) - { - return false; - } - length--; - elements[index].hash = HASH_DELETED; - markerdDeleted++; - return true; - } - export void remove(Key el) - { - bool ok = tryRemove(el); - assert(ok); - } - export ref Value opIndex()(auto ref Key key) - { - return get(key); - } - export void opIndexAssign()(auto ref Value value, auto ref Key key) - { - add(key, value); - } - export void add()(auto ref Key key, auto ref Value value) - { - size_t index = getIndex(key); - if (index != getIndexEmptyValue) - { - elements[index].keyValue.value = value; - return ; - } - if (getLoadFactor(length + 1) > rehashFactor || getLoadFactor(length + markerdDeleted) > rehashFactor) - { - rehash(); - } - length++; - immutable ulong hash = hashFunc(key) | HASH_FILLED_MARK; - immutable size_t rotateMask = elements.length - 1; - index = hash & rotateMask; - while (true) - { - Bucket* gr = &elements[index]; - if ((gr.hash & HASH_FILLED_MARK) == 0) - { - if (gr.hash == HASH_DELETED) - { - markerdDeleted--; - } - gr.hash = hash; - gr.keyValue.key = key; - gr.keyValue.value = value; - return ; - } - index++; - index = index & rotateMask; - } - } - export size_t getIndex(Key el) - { - return getIndex(el); - } - export size_t getIndex(ref Key el) - { - mixin(doNotInline); - immutable size_t groupsLength = elements.length; - if (groupsLength == 0) - { - return getIndexEmptyValue; - } - immutable ulong hash = hashFunc(el) | HASH_FILLED_MARK; - immutable size_t rotateMask = groupsLength - 1; - size_t index = hash & rotateMask; - while (true) - { - Bucket* gr = &elements[index]; - if (gr.hash == hash && (gr.keyValue.key == el)) - { - return index; - } - if (gr.hash == HASH_EMPTY) - { - return getIndexEmptyValue; - } - index++; - index = index & rotateMask; - } - } - export float getLoadFactor(size_t forElementsNum) - { - if (elements.length == 0) - { - return 1; - } - return cast(float)forElementsNum / elements.length; - } - export void rehash() - { - mixin(doNotInline); - Vector!KeyVal allElements; - allElements.reserve(elements.length); - foreach (ref Bucket el; elements) - { - if ((el.hash & HASH_FILLED_MARK) == 0) - { - el.hash = HASH_EMPTY; - continue; - } - el.hash = HASH_EMPTY; - allElements ~= el.keyValue; - } - if (getLoadFactor(length + 1) > rehashFactor) - { - elements.length = (elements.length ? elements.length : 4) << 1; - } - foreach (i, ref el; allElements) - { - add(el.key, el.value); - } - length = allElements.length; - markerdDeleted = 0; - } - export int opApply(DG)(scope DG dg) - { - int result; - foreach (ref Bucket gr; elements) - { - if ((gr.hash & HASH_FILLED_MARK) == 0) - { - continue; - } - static if (isForeachDelegateWithTypes!(DG, Key)) - { - result = dg(gr.keyValue.key); - } - else - { - static if (isForeachDelegateWithTypes!(DG, Value)) - { - result = dg(gr.keyValue.value); - } - else - { - static if (isForeachDelegateWithTypes!(DG, Key, Value)) - { - result = dg(gr.keyValue.key, gr.keyValue.value); - } - else - { - static assert(0); - } - } - } - if (result) - break; - } - return result; - } - export int byKey(scope int delegate(Key k) dg) - { - int result; - foreach (ref Key k; this) - { - result = dg(k); - if (result) - break; - } - return result; - } - export int byValue(scope int delegate(ref Value k) dg) - { - int result; - foreach (ref Value v; this) - { - result = dg(v); - if (result) - break; - } - return result; - } - export int byKeyValue(scope int delegate(ref Key k, ref Value v) dg) - { - int result; - foreach (ref Key k, ref Value v; this) - { - result = dg(k, v); - if (result) - break; - } - return result; - } - import std.format : FormatSpec, formatValue; - export void toString(scope void delegate(const(char)[]) sink, FormatSpec!char fmt) - { - formatValue(sink, '[', fmt); - foreach (ref k, ref v; &byKeyValue) - { - formatValue(sink, k, fmt); - formatValue(sink, ':', fmt); - formatValue(sink, v, fmt); - formatValue(sink, ", ", fmt); - } - formatValue(sink, ']', fmt); - } -} -static void dumpHashMapToJson(T)(ref T map, string path = "HashMapDump.json") -{ - Vector!char data; - import std.file; - import mutils.serializer.json; - JSONSerializer.instance.serialize!(Load.no)(map, data); - std.file.write(path, data[]); -} -static void printHashMap(T)(ref T map) -{ - import std.stdio; - writeln(T.stringof, " dump:\x0a"); - foreach (k, v; &map.byKeyValue) - { - writefln("%20s : %20s", k, v); - } -} diff --git a/import/ecs/id_manager.di b/import/ecs/id_manager.di deleted file mode 100644 index 55a00ef..0000000 --- a/import/ecs/id_manager.di +++ /dev/null @@ -1,20 +0,0 @@ -// D import file generated from 'source\ecs\id_manager.d' -module ecs.id_manager; -import ecs.entity; -import ecs.vector; -struct IDManager -{ - EntityID getNewID(); - void releaseID(EntityID id); - void update(ref Entity entity); - Entity* getEntityPointer(EntityID id); - bool isExist(EntityID id); - struct Data - { - uint counter = 0; - uint next_id = (uint).max; - Entity* entity = null; - } - private uint m_next_id = 0; - Vector!Data m_ids_array; -} diff --git a/import/ecs/manager.di b/import/ecs/manager.di deleted file mode 100644 index 801bc1d..0000000 --- a/import/ecs/manager.di +++ /dev/null @@ -1,287 +0,0 @@ -// D import file generated from 'source\ecs\manager.d' -module ecs.manager; -import std.algorithm : max; -import std.conv : to; -import std.experimental.allocator; -import std.experimental.allocator.mallocator : AlignedMallocator, Mallocator; -import std.traits; -import core.stdc.stdlib; -import core.stdc.string; -import ecs.entity; -import ecs.entity_allocator; -import ecs.hash_map; -import ecs.id_manager; -import ecs.system; -import ecs.vector; -alias gEM = EntityManager.instance; -alias SerializeVector = ecs.vector.Vector!ubyte; -class EntityManager -{ - export static void initialize(); - export static void destroy(); - export void registerSystem(Sys)(int priority) - { - alias types = Parameters!(Sys.update); - alias storages = ParameterStorageClassTuple!(Sys.update); - alias STC = ParameterStorageClass; - System system; - static string genCall()() - { - string ret = "s.update(*cast(Entity*)data_pointer,"; - uint i = 0; - uint req = 0; - uint opt = 0; - static foreach (param; Parameters!(Sys.update)[1..$]) - { - i++; - if (isPointer!param) - { - ret ~= "cast(types[" ~ i.to!string ~ "])(optional_pointers[" ~ opt++.to!string ~ "]),"; - } - else - { - ret ~= "*cast(types[" ~ i.to!string ~ "]*)(pointers[" ~ req++.to!string ~ "]),"; - } - } - ret ~= ");"; - return ret; - } - static string genCompList()() - { - string ret = "ushort comp;uint req;uint opt;"; - foreach (i; 1 .. (Parameters!(Sys.update)).length) - { - ret ~= "\x0a static if(isPointer!(types[" ~ i.to!string ~ "]))opt++;\x0a else static if(storages[" ~ i.to!string ~ "] == STC.ref_)req++;\x0a\x0a else static assert(0,\"Can't register system \\\"" ~ Sys.stringof ~ "\\\". Unsupported parameter type \\\"\"~types[" ~ i.to!string ~ "].stringof~\"\\\".\");"; - } - ret ~= "system.m_components = Mallocator.instance.makeArray!ushort(req);"; - ret ~= "system.m_optional_components = Mallocator.instance.makeArray!ushort(opt);"; - ret ~= "opt = 0;req = 0;"; - foreach (i; 1 .. (Parameters!(Sys.update)).length) - { - ret ~= "\x0a static if(isPointer!(types[" ~ i.to!string ~ "]))\x0a {\x0a comp = components_map.get(PointerTarget!(types[" ~ i.to!string ~ "]).stringof, ushort.max);\x0a\x0a if(comp == ushort.max)assert(0,\"Can't register system \\\"" ~ Sys.stringof ~ "\\\" due to non existing component \\\"\"~types[" ~ i.to!string ~ "].stringof~\"\\\".\");\x0a system.m_optional_components[opt++] = comp;\x0a }\x0a else static if(storages[" ~ i.to!string ~ "] == STC.ref_)\x0a {\x0a comp = components_map.get(types[" ~ i.to!string ~ "].stringof, ushort.max);\x0a\x0a if(comp == ushort.max)assert(0,\"Can't register system \\\"" ~ Sys.stringof ~ "\\\" due to non existing component \\\"\"~types[" ~ i.to!string ~ "].stringof~\"\\\".\");\x0a system.m_components[req++] = comp;\x0a }"; - } - return ret; - } - static string catchFunc()(string member, string func) - { - string ret = "static if (hasMember!(Sys, \"" ~ func ~ "\"))\x0a {\x0a static void call" ~ func ~ "(void* system_pointer)\x0a {\x0a\x0a Sys* s = cast(Sys*) system_pointer;\x0a s." ~ func ~ "();\x0a }\x0a\x0a system." ~ member ~ " = &call" ~ func ~ ";\x0a }"; - return ret; - } - static if (hasMember!(Sys, "update")) - { - static void callUpdate(ref CallData data, void* entity) - { - static if (hasMember!(Sys, "update")) - { - Sys* s = cast(Sys*) data.system.m_system_pointer; - - void*[] pointers = (cast(void**) alloca(data.system.m_components.length * (void*) - .sizeof))[0 .. data.system.m_components.length]; - void*[] optional_pointers = (cast(void**) alloca( - data.system.m_optional_components.length * (void*).sizeof))[0 - .. data.system.m_optional_components.length]; - - EntitiesBlock* block = data.info.first_block; - while (block !is null) - { - uint size = block.type_data.size; - void* data_pointer = block.dataBegin(); - foreach (i, ref pointer; pointers) - { - pointer = data_pointer + data.deltas[i]; - } - foreach (i, ref pointer; optional_pointers) - { - uint ind = cast(uint)(i + pointers.length); - if (data.deltas[ind] != uint.max) - pointer = data_pointer + data.deltas[ind]; - else - pointer = null; - } - foreach (i; 0 .. block.entities_count) - { - mixin(genCall()); - data_pointer += size; //data.info.size; - foreach (ref pointer; pointers) - pointer += size; - foreach (ref pointer; optional_pointers) - if (pointer != null) - pointer += size; - } - block = block.next_block; - } - - } - } - system.m_update = &callUpdate; - } - - mixin(catchFunc("m_enable", "onEnable")); - mixin(catchFunc("m_disable", "onDisable")); - mixin(catchFunc("m_create", "onCreate")); - mixin(catchFunc("m_destroy", "onDestroy")); - mixin(catchFunc("m_begin", "onBegin")); - mixin(catchFunc("m_end", "onEnd")); - system.m_system_pointer = cast(void*)Mallocator.instance.make!Sys; - system.m_priority = priority; - mixin(genCompList()); - ushort sys_id = systems_map.get(Sys.stringof, (ushort).max); - if (sys_id < systems.length) - { - system.enable(); - systems[sys_id] = system; - } - else - { - systems_map.add(Sys.stringof, cast(ushort)systems.length); - systems.add(system); - if (system.m_create) - system.m_create(system.m_system_pointer); - systems[$ - 1].enable(); - foreach (info; &entities_infos.byValue) - { - addEntityCaller(*info, cast(uint)systems.length - 1); - } - } - updateEntityCallers(); - } - void registerComponent(Comp)() - { - ComponentInfo info; - static if (!hasMember!(Comp, "component_id") || !is(typeof(Comp.component_id) == ushort)) - { - static assert(0, "Component should have \"__gshared ushort component_id"); - } - - static if (hasMember!(Comp, "onDestroy") && isFunction!(Comp.onDestroy) && is(ReturnType!(Comp.onDestroy) == void) && (Parameters!(Comp.onDestroy).length == 0)) - { - static void callDestroy(void* pointer) - { - (cast(Comp*) pointer).onDestroy(); - } - info.destroy_callback = &callDestroy; - } - - info.size = Comp.sizeof; - info.aligment = Comp.alignof; - info.init_data = Mallocator.instance.makeArray!ubyte(Comp.sizeof); - *cast(Comp*)info.init_data.ptr = Comp.init; - ushort comp_id = components_map.get(Comp.stringof, (ushort).max); - if (comp_id < components.length) - { - Comp.component_id = comp_id; - } - else - { - components.add(info); - Comp.component_id = cast(ushort)(components.length - 1); - components_map.add(Comp.stringof, cast(ushort)(components.length - 1)); - } - } - export void update(); - static void alignNum(ref ushort num, ushort aligment); - extern (C) static int compareUShorts(const void* a, const void* b); - export EntityTemplate* allocateTemplate(ushort[] components_ids); - export EntityInfo* getEntityInfo(ushort[] ids); - export void updateEntityCallers(); - export void addEntityCaller(ref EntityInfo entity, uint system_id); - export Entity* getEntity(EntityID id); - export void removeComponents(EntityID entity_id, ushort[] del_ids); - private void __removeComponents(EntityID entity_id, ushort[] del_ids); - void removeComponents(Components...)(EntityID entity_id) - { - const uint num = Components.length; - ushort[num] del_ids; - static foreach (i, comp; Components) - { - del_ids[i] = comp.component_id; - } - removeComponents(entity_id, del_ids); - } - private void __addComponents(EntityID entity_id, ushort[] new_ids, void*[] data_pointers); - void addComponents(Components...)(EntityID entity_id, Components comps) - { - const uint num = Components.length; - Entity* entity = id_manager.getEntityPointer(entity_id); - EntitiesBlock* block = getMetaData(entity); - EntityInfo* info = block.type_data; - ushort[] ids = (cast(ushort*)alloca((ushort).sizeof * (info.components.length + num)))[0..info.components.length + num]; - ushort[num] new_ids; - static foreach (i, comp; Components) - { - new_ids[i] = comp.component_id; - } - change_entities_list.add(1); - change_entities_list.add((cast(ubyte*)&entity_id)[0..8]); - change_entities_list.add((cast(ubyte*)&num)[0..4]); - change_entities_list.add(cast(ubyte[])new_ids); - static foreach (i, comp; comps) - { - change_entities_list.add((cast(ubyte*)&comp)[0..comp.sizeof]); - } - } - export void freeTemplate(EntityTemplate* template_); - export ref Entity addEntity(EntityTemplate* tmpl); - private EntitiesBlock* findBlockWithFreeSpace(EntityInfo* info); - export void removeEntity(EntityID id); - private void __removeEntity(EntityID id); - private void removeEntityNoID(Entity* entity, EntitiesBlock* block, bool call_destructors = false); - export EntitiesBlock* getMetaData(void* pointer); - private void changeEntites(); - private void updateBlocks(); - private void removeEntities(); - export void begin(); - export void end(); - struct ComponentInfo - { - ushort size; - ushort aligment; - ubyte[] init_data; - void function(void* pointer) destroy_callback; - } - struct EntityInfo - { - ushort[] components; - ushort[] deltas; - ushort alignment; - ushort size; - EntitiesBlock* first_block; - EntitiesBlock* first_with_free_space; - Vector!CallData callers; - } - struct EntitiesBlock - { - uint dataDelta(); - void* dataBegin(); - EntityInfo* type_data; - ushort entities_count; - ushort added_count; - uint id; - EntitiesBlock* next_block; - } - struct CallData - { - uint system_id; - System* system; - EntityManager.EntityInfo* info; - ushort[] deltas; - } - alias SytemFuncType = void function(ref EntityManager.CallData data, void* entity); - enum page_size = 4096; - enum pages_in_block = 128; - IDManager id_manager; - EntityAllocator allocator; - Vector!EntityID entities_to_remove; - Vector!(EntitiesBlock*) blocks_to_update; - Vector!ubyte change_entities_list; - HashMap!(ushort[], EntityInfo*) entities_infos; - HashMap!(string, ushort) systems_map; - HashMap!(string, ushort) components_map; - Vector!System systems; - Vector!ComponentInfo components; - __gshared EntityManager instance; -} -version (Windows) -{ - extern (Windows) bool DllMain(void* hInstance, uint ulReason, void*); -} diff --git a/import/ecs/package.di b/import/ecs/package.di deleted file mode 100644 index 41d9943..0000000 --- a/import/ecs/package.di +++ /dev/null @@ -1,7 +0,0 @@ -// D import file generated from 'source\ecs\package.d' -module ecs; -public import ecs.manager; -public import ecs.entity; -public import ecs.system; -import ecs.id_manager; -import ecs.events; diff --git a/import/ecs/string_intern.di b/import/ecs/string_intern.di deleted file mode 100644 index 665bfc5..0000000 --- a/import/ecs/string_intern.di +++ /dev/null @@ -1,31 +0,0 @@ -// D import file generated from 'source\ecs\string_intern.d' -module ecs.string_intern; -import ecs.hash_map; -import ecs.traits : isForeachDelegateWithI; -import std.experimental.allocator; -import std.experimental.allocator.mallocator; -import std.traits : Parameters; -private static __gshared HashMap!(const(char)[], StringIntern) gStringInterns; -struct StringIntern -{ - private const(char)* strPtr; - this(const(char)[] fromStr) - { - opAssign(fromStr); - } - void reset(); - size_t length(); - const(char)[] str(); - const(char)[] cstr(); - bool opEquals()(auto ref const StringIntern s) - { - return strPtr == s.strPtr; - } - bool opEquals()(auto ref const(char[]) s) - { - return str() == s; - } - void opAssign(const(char)[] fromStr); - const(char)[] opSlice(); - private const(char)[] allocStr(const(char)[] fromStr); -} diff --git a/import/ecs/system.di b/import/ecs/system.di deleted file mode 100644 index fd28e8a..0000000 --- a/import/ecs/system.di +++ /dev/null @@ -1,26 +0,0 @@ -// D import file generated from 'source\ecs\system.d' -module ecs.system; -import ecs.entity; -import ecs.manager; -struct System -{ - export bool enabled(); - export void enable(); - export void disable(); - export int priority(); - package - { - bool m_enabled = false; - int m_priority; - void* m_system_pointer; - ushort[] m_components; - ushort[] m_optional_components; - void* m_update; - void function(void* system_pointer) m_enable; - void function(void* system_pointer) m_disable; - void function(void* system_pointer) m_create; - void function(void* system_pointer) m_destroy; - void function(void* system_pointer) m_begin; - void function(void* system_pointer) m_end; - } -} diff --git a/import/ecs/traits.di b/import/ecs/traits.di deleted file mode 100644 index 7eef028..0000000 --- a/import/ecs/traits.di +++ /dev/null @@ -1,20 +0,0 @@ -// D import file generated from 'source\ecs\traits.d' -module ecs.traits; -import std.traits; -bool isForeachDelegateWithI(DG)() -{ - return is(DG == delegate) && is(ReturnType!DG == int) && (Parameters!DG.length == 2) && isIntegral!(Parameters!DG[0]); -} -bool isForeachDelegateWithoutI(DG)() -{ - return is(DG == delegate) && is(ReturnType!DG == int) && (Parameters!DG.length == 1); -} -bool isForeachDelegateWithTypes(DG, Types...)() -{ - return is(DG == delegate) && is(ReturnType!DG == int) && is(Parameters!DG == Types); -} -auto assumeNoGC(T)(T t) if (isFunctionPointer!T || isDelegate!T) -{ - enum attrs = functionAttributes!T | FunctionAttribute.nogc; - return cast(SetFunctionAttributes!(T, functionLinkage!T, attrs))t; -} diff --git a/import/ecs/vector.di b/import/ecs/vector.di deleted file mode 100644 index cb0917e..0000000 --- a/import/ecs/vector.di +++ /dev/null @@ -1,274 +0,0 @@ -// D import file generated from 'source\ecs\vector.d' -module ecs.vector; -import core.bitop; -import core.stdc.stdlib : free, malloc; -import core.stdc.string : memcpy, memset; -import std.algorithm : swap; -import std.conv : emplace; -import std.traits : hasMember, isCopyable, TemplateOf, Unqual; -export pure nothrow @nogc @safe size_t nextPow2(size_t num); -__gshared size_t gVectorsCreated = 0; -__gshared size_t gVectorsDestroyed = 0; -struct Vector(T) -{ - T[] array; - size_t used; - public - { - export this()(T t) - { - add(t); - } - export this(X)(X[] t) if (is(Unqual!X == Unqual!T)) - { - add(t); - } - static if (isCopyable!T) - { - export this(this) - { - T[] tmp = array[0..used]; - array = null; - used = 0; - add(tmp); - } - } - else - { - @disable this(this); - } - export ~this() - { - clear(); - } - export void clear() - { - removeAll(); - } - export void removeAll() - { - if (array !is null) - { - foreach (ref el; array[0..used]) - { - destroy(el); - } - freeData(cast(void[])array); - gVectorsDestroyed++; - } - array = null; - used = 0; - } - export bool empty() - { - return used == 0; - } - export size_t length() - { - return used; - } - export void length(size_t newLength) - { - if (newLength > used) - { - reserve(newLength); - foreach (ref el; array[used..newLength]) - { - emplace(&el); - } - } - else - { - foreach (ref el; array[newLength..used]) - { - destroy(el); - } - } - used = newLength; - } - export void reset() - { - used = 0; - } - export void reserve(size_t numElements) - { - if (numElements > array.length) - { - extend(numElements); - } - } - export size_t capacity() - { - return array.length - used; - } - export void extend(size_t newNumOfElements) - { - auto oldArray = manualExtend(array, newNumOfElements); - if (oldArray !is null) - { - freeData(oldArray); - } - } - export @nogc void freeData(void[] data) - { - memset(data.ptr, 15, data.length); - free(data.ptr); - } - export static void[] manualExtend(ref T[] array, size_t newNumOfElements = 0) - { - if (newNumOfElements == 0) - newNumOfElements = 2; - if (array.length == 0) - gVectorsCreated++; - T[] oldArray = array; - size_t oldSize = oldArray.length * T.sizeof; - size_t newSize = newNumOfElements * T.sizeof; - T* memory = cast(T*)malloc(newSize); - memcpy(cast(void*)memory, cast(void*)oldArray.ptr, oldSize); - array = memory[0..newNumOfElements]; - return cast(void[])oldArray; - } - export Vector!T copy()() - { - Vector!T duplicate; - duplicate.reserve(used); - duplicate ~= array[0..used]; - return duplicate; - } - export bool canAddWithoutRealloc(uint elemNum = 1) - { - return used + elemNum <= array.length; - } - export void add()(T t) - { - if (used >= array.length) - { - extend(nextPow2(used + 1)); - } - emplace(&array[used], t); - used++; - } - export void add()(T t, size_t pos) - { - assert(pos <= used); - if (used >= array.length) - { - extend(array.length * 2); - } - foreach_reverse (size_t i; pos .. used) - { - array[i + 1] = array[i]; - } - emplace(&array[pos], t); - used++; - } - export void add(X)(X[] t) if (is(Unqual!X == Unqual!T)) - { - if (used + t.length > array.length) - { - extend(nextPow2(used + t.length)); - } - foreach (i; 0 .. t.length) - { - emplace(&array[used + i], t[i]); - } - used += t.length; - } - export void remove(size_t elemNum) - { - destroy(array[elemNum]); - swap(array[elemNum], array[used - 1]); - used--; - } - export void removeStable()(size_t elemNum) - { - used--; - foreach (i; 0 .. used) - { - array[i] = array[i + 1]; - } - } - export bool tryRemoveElement()(T elem) - { - foreach (i, ref el; array[0..used]) - { - if (el == elem) - { - remove(i); - return true; - } - } - return false; - } - export void removeElement()(T elem) - { - bool ok = tryRemoveElement(elem); - assert(ok, "There is no such an element in vector"); - } - export ref T opIndex(size_t elemNum) - { - assert(elemNum < used, "Range violation [index]"); - return array.ptr[elemNum]; - } - export auto opSlice() - { - return array.ptr[0..used]; - } - export T[] opSlice(size_t x, size_t y) - { - assert(y <= used); - return array.ptr[x..y]; - } - export size_t opDollar() - { - return used; - } - export void opAssign(X)(X[] slice) - { - reset(); - this ~= slice; - } - export void opOpAssign(string op)(T obj) - { - static assert(op == "~"); - add(obj); - } - export void opOpAssign(string op, X)(X[] obj) - { - static assert(op == "~"); - add(obj); - } - export void opIndexAssign()(T obj, size_t elemNum) - { - assert(elemNum < used, "Range viloation"); - array[elemNum] = obj; - } - export void opSliceAssign()(T[] obj, size_t a, size_t b) - { - assert(b <= used && (a <= b), "Range viloation"); - array.ptr[a..b] = obj; - } - export const bool opEquals()(auto ref const Vector!T r) - { - return used == r.used && (array.ptr[0..used] == r.array.ptr[0..r.used]); - } - export const nothrow @trusted size_t toHash() - { - return hashOf(cast(Unqual!T[])array.ptr[0..used]); - } - import std.format : FormatSpec, formatValue; - export void toString(scope void delegate(const(char)[]) sink, FormatSpec!char fmt) - { - static if (__traits(compiles, formatValue(sink, array[0..used], fmt))) - { - formatValue(sink, array[0..used], fmt); - } - - } - } -} -private pure nothrow @nogc @safe T[n] s(T, size_t n)(auto ref T[n] array) -{ - return array; -} -enum string checkVectorAllocations = "\x0a//assert(gVectorsCreated==gVectorsDestroyed);\x0agVectorsCreated=gVectorsDestroyed=0;\x0ascope(exit){if(gVectorsCreated!=gVectorsDestroyed){\x09\x0a\x09import std.stdio : writefln;\x0a\x09writefln(\"created==destroyed %s==%s\", gVectorsCreated, gVectorsDestroyed);\x0a\x09assert(gVectorsCreated==gVectorsDestroyed, \"Vector memory leak\");\x0a}}\x0a"; From 204ce9dc79584b4208e187f5a073ac994118488c Mon Sep 17 00:00:00 2001 From: Mergul Date: Fri, 2 Nov 2018 16:36:38 +0100 Subject: [PATCH 022/217] -almost every funtion is marked as @nogc and nothrow (only problem with HashMap) --- source/ecs/block_allocator.d | 6 +-- source/ecs/core.d | 2 +- source/ecs/entity.d | 4 +- source/ecs/events.d | 10 ++--- source/ecs/hash_map.d | 2 +- source/ecs/id_manager.d | 22 +++++----- source/ecs/manager.d | 81 ++++++++++++++++++------------------ source/ecs/string_intern.d | 1 + source/ecs/system.d | 16 +++---- tests/tests.d | 2 +- 10 files changed, 74 insertions(+), 72 deletions(-) diff --git a/source/ecs/block_allocator.d b/source/ecs/block_allocator.d index 29b1fb3..d2272dd 100644 --- a/source/ecs/block_allocator.d +++ b/source/ecs/block_allocator.d @@ -12,7 +12,7 @@ struct BlockAllocator//(uint block_size, uint blocks_in_allocation) void* next_block = null; - void* getBlock() + void* getBlock() nothrow @nogc { if (next_block is null) allocBlock(); @@ -21,13 +21,13 @@ struct BlockAllocator//(uint block_size, uint blocks_in_allocation) return ret; } - void freeBlock(void* block) + void freeBlock(void* block) nothrow @nogc { *cast(void**)block = next_block; next_block = block; } - private void allocBlock() + private void allocBlock() nothrow @nogc { next_block = cast(void*) AlignedMallocator.instance.alignedAllocate( block_size * blocks_in_allocation, block_size); diff --git a/source/ecs/core.d b/source/ecs/core.d index 3095dbb..8f34fc0 100644 --- a/source/ecs/core.d +++ b/source/ecs/core.d @@ -10,7 +10,7 @@ static struct ECS __gshared ushort system_id; EntityManager.Job[] _ecs_jobs; - void __ecsInitialize() + void __ecsInitialize() nothrow @nogc { import std.experimental.allocator.mallocator; import std.experimental.allocator; diff --git a/source/ecs/entity.d b/source/ecs/entity.d index 854385a..3757d80 100644 --- a/source/ecs/entity.d +++ b/source/ecs/entity.d @@ -24,7 +24,7 @@ struct Entity /************************************************************************************************************************ *Update pointer to it in IDManager */ - void updateID() + void updateID() nothrow @nogc { EntityManager.instance.id_manager.update(this); } @@ -60,7 +60,7 @@ export struct EntityTemplate /************************************************************************************************************************ *Get specified component. If component doesn't exist function return null. */ - T* getComponent(T)() + T* getComponent(T)() nothrow @nogc { if(T.component_id >= info.tmpl_deltas.length)return null; return cast(T*)(entity_data.ptr + info.tmpl_deltas[T.component_id]); diff --git a/source/ecs/events.d b/source/ecs/events.d index ef81b6c..a6f6d36 100644 --- a/source/ecs/events.d +++ b/source/ecs/events.d @@ -70,13 +70,13 @@ struct EventManager block.index = cast(ushort)(aligned_index + Ev.sizeof); }*/ - void initialize(EntityManager m) + void initialize(EntityManager m) nothrow @nogc { allocator = BlockAllocator(events_block_size, events_blocks_in_allocation); manager = m; } - void sendEvent(Ev)(EntityID id, Ev event, uint thread_id = 0) + void sendEvent(Ev)(EntityID id, Ev event, uint thread_id = 0) nothrow @nogc { uint block_id = current_index+thread_id; @@ -110,7 +110,7 @@ struct EventManager block.count++; } - void swapCurrent() + void swapCurrent() nothrow @nogc { uint threads_count = cast(uint)manager.threads.length; if(current_index == 0)current_index = threads_count; @@ -136,7 +136,7 @@ struct EventManager } } - void clearEvents() + void clearEvents() nothrow @nogc { uint threads_count = cast(uint)manager.threads.length; foreach(ref event;events) @@ -173,7 +173,7 @@ struct EventManager process_events.current_block = null;*/ } - void allocateData(uint threads_count) + void allocateData(uint threads_count) nothrow @nogc { if(events) { diff --git a/source/ecs/hash_map.d b/source/ecs/hash_map.d index 2a62201..da317d2 100755 --- a/source/ecs/hash_map.d +++ b/source/ecs/hash_map.d @@ -11,7 +11,7 @@ private enum HASH_EMPTY = 0; private enum HASH_DELETED = 0x1; private enum HASH_FILLED_MARK = ulong(1) << 8 * ulong.sizeof - 1; -export ulong defaultHashFunc(T)(auto ref T t) { +export ulong defaultHashFunc(T)(auto ref T t) nothrow @nogc { static if (isIntegral!(T)) { return hashInt(t); } else { diff --git a/source/ecs/id_manager.d b/source/ecs/id_manager.d index 1e8ebad..07566d3 100644 --- a/source/ecs/id_manager.d +++ b/source/ecs/id_manager.d @@ -18,7 +18,7 @@ struct IDManager /************************************************************************************************************************ *Get new ID. */ - pragma(inline, false) EntityID getNewID() + pragma(inline, false) EntityID getNewID() nothrow @nogc { //uint current = m_next_id; //uint next;// = m_ids_array[m_next_id].next_id; @@ -35,13 +35,13 @@ begin: uint block_id = local_id >> 16; if (block_id >= m_blocks_count) { - add_mutex.lock(); + add_mutex.lock_nothrow(); if(block_id >= m_blocks_count) { m_blocks[m_blocks_count].alloc(); m_blocks_count++; } - add_mutex.unlock(); + add_mutex.unlock_nothrow(); } } @@ -79,7 +79,7 @@ begin: /************************************************************************************************************************ *Release ID. */ - void releaseID(EntityID id) + void releaseID(EntityID id) nothrow @nogc { Data* data = &m_ids_array[id.id]; if (data.counter != id.counter) @@ -96,7 +96,7 @@ begin: /************************************************************************************************************************ *Update pointer to entity. The purpose of this function is to ensure that pointer to entity is always correct. */ - void update(ref Entity entity) + void update(ref Entity entity) nothrow @nogc { if (entity.id.id >= cast(uint) m_ids_array.length) { @@ -112,7 +112,7 @@ begin: /************************************************************************************************************************ *Returns pointer to entity. */ - export Entity* getEntityPointer(EntityID id) + export Entity* getEntityPointer(EntityID id) nothrow @nogc { if (id.id >= m_ids_array.length) { @@ -137,13 +137,13 @@ begin: /************************************************************************************************************************ *Check if entity with specified ID exist. */ - export bool isExist(EntityID id) + export bool isExist(EntityID id) nothrow @nogc { Data* data = &m_ids_array[id.id]; return data.counter == id.counter; } - void initialize() + void initialize() nothrow @nogc { m_ids_array = Mallocator.instance.makeArray!Data(65536); m_free_stack = Mallocator.instance.makeArray!uint(65536); @@ -154,7 +154,7 @@ begin: add_mutex = Mallocator.instance.make!Mutex(); } - void optimize() + void optimize() nothrow @nogc { if(m_stack_top < -1)m_stack_top = -1; if(m_last_id > m_ids_array.length) @@ -183,13 +183,13 @@ begin: private static struct Block { - void alloc() + void alloc() nothrow @nogc { assert(data is null); data = Mallocator.instance.makeArray!Data(65536); } - void free() + void free() nothrow @nogc { assert(data !is null); Mallocator.instance.dispose(data); diff --git a/source/ecs/manager.d b/source/ecs/manager.d index 1215c5b..b8932f3 100644 --- a/source/ecs/manager.d +++ b/source/ecs/manager.d @@ -55,7 +55,7 @@ class EntityManager /************************************************************************************************************************ *Begin registering process. Every register function should be called between beginRegister() and endRegister(). */ - void beginRegister() + void beginRegister() nothrow @nogc { assert(!register_state, "beginRegister() can't be called twice before endRegister();"); register_state = true; @@ -730,12 +730,12 @@ class EntityManager Sys.system_id = system.id; } - System* getSystem(ushort id) + System* getSystem(ushort id) nothrow @nogc { return &systems[id]; } - Sys* getSystem(Sys)() + Sys* getSystem(Sys)() nothrow @nogc { return cast(Sys*) systems[Sys.system_id].m_system_pointer; } @@ -765,9 +765,10 @@ class EntityManager && is(ReturnType!(Comp.onDestroy) == void) && Parameters!(Comp.onDestroy).length == 0) { - static void callDestroy(void* pointer) + static void callDestroy(void* pointer) nothrow @nogc + { - (cast(Comp*) pointer).onDestroy(); + (cast(void delegate() nothrow @nogc)&(cast(Comp*) pointer).onDestroy)(); } info.destroy_callback = &callDestroy; @@ -832,7 +833,7 @@ class EntityManager /************************************************************************************************************************ *Same as "void update(int pass = 0)" but use pass name instead of id. */ - void update(const(char)[] pass_name) + void update(const(char)[] pass_name) nothrow @nogc { ushort pass = passes_map.get(pass_name, ushort.max); assert(pass != ushort.max); @@ -842,7 +843,7 @@ class EntityManager /************************************************************************************************************************ *Update systems. Should be called only between begin() and end(). */ - export void update(ushort pass = 0) + export void update(ushort pass = 0) nothrow @nogc { assert(!register_state); assert(pass < passes.length); @@ -863,14 +864,14 @@ class EntityManager /************************************************************************************************************************ *Same as "void updateMT(int pass = 0)" but use pass name instead of id. */ - void updateMT(const(char)[] pass_name) + void updateMT(const(char)[] pass_name) nothrow @nogc { ushort pass = passes_map.get(pass_name, ushort.max); assert(pass != ushort.max); updateMT(pass); } - void updateMT(ushort pass = 0) + void updateMT(ushort pass = 0) nothrow @nogc { assert(!register_state); assert(pass < passes.length); @@ -994,22 +995,22 @@ class EntityManager nextJob(); caller.job_group.jobs = sys.jobs[0 .. job_id]; - m_dispatch_jobs(caller.job_group); //sys.jobs[0 .. job_id]); + (cast(void delegate(JobGroup) nothrow @nogc)m_dispatch_jobs)(caller.job_group); //sys.jobs[0 .. job_id]); } } } - void setJobDispachFunc(void delegate(JobGroup) func) + void setJobDispachFunc(void delegate(JobGroup) func) nothrow @nogc { m_dispatch_jobs = func; } - static void alignNum(ref ushort num, ushort alignment) + static void alignNum(ref ushort num, ushort alignment) nothrow @nogc { num = cast(ushort)((num + alignment - 1) & (-cast(int) alignment)); //num += alignment - (num & (alignment - 1)); } - extern (C) static int compareUShorts(const void* a, const void* b) + extern (C) static int compareUShorts(const void* a, const void* b) nothrow @nogc { ushort _a = *cast(ushort*) a; ushort _b = *cast(ushort*) b; @@ -1132,7 +1133,7 @@ class EntityManager return info; } - export void addSystemCaller(ref EntityInfo entity, uint system_id) + export void addSystemCaller(ref EntityInfo entity, uint system_id) nothrow @nogc { System* system = &systems[system_id]; @@ -1176,7 +1177,7 @@ class EntityManager *params: *id = ID of entity */ - export Entity* getEntity(EntityID id) + export Entity* getEntity(EntityID id) nothrow @nogc { return cast(Entity*) id_manager.getEntityPointer(id); } @@ -1188,7 +1189,7 @@ class EntityManager *entity_id = ID of entity *del_ids = array of components IDs */ - export void removeComponents(EntityID entity_id, ushort[] del_ids) + export void removeComponents(EntityID entity_id, ushort[] del_ids) nothrow @nogc { ThreadData* data = &threads[thread_id]; uint num = cast(uint) del_ids.length; @@ -1414,7 +1415,7 @@ class EntityManager *entity_id = ID of entity to remove *tmpl = pointer entity template allocated by EntityManager. */ - void addComponents(Components...)(const EntityID entity_id, Components comps) + void addComponents(Components...)(const EntityID entity_id, Components comps) nothrow @nogc { const uint num = Components.length; Entity* entity = id_manager.getEntityPointer(entity_id); @@ -1505,7 +1506,7 @@ class EntityManager /************************************************************************************************************************ *Return block with free space for selected EntityInfo. */ - private EntitiesBlock* findBlockWithFreeSpace(EntityInfo* info) + private EntitiesBlock* findBlockWithFreeSpace(EntityInfo* info) nothrow @nogc { EntitiesBlock* block = info.last_block; @@ -1585,7 +1586,7 @@ class EntityManager threads[thread_id].entities_to_remove.add(id); } - private void __removeEntity(EntityID id) + private void __removeEntity(EntityID id) nothrow @nogc { //get entity and block meta data pointers Entity* entity = id_manager.getEntityPointer(id); @@ -1598,7 +1599,7 @@ class EntityManager } private void removeEntityNoID(Entity* entity, EntitiesBlock* block, - bool call_destructors = false) + bool call_destructors = false) nothrow @nogc { //pos is Entity number in block void* data_begin = block.dataBegin(); @@ -1662,7 +1663,7 @@ class EntityManager *params: *pointer = pointer to any data of entity (i.e. component data pointer) */ - export EntitiesBlock* getMetaData(const void* pointer) + export EntitiesBlock* getMetaData(const void* pointer) nothrow @nogc { return cast(EntitiesBlock*)(cast(size_t) pointer & (~cast(size_t)(page_size - 1))); } @@ -1726,7 +1727,7 @@ class EntityManager } } - private void removeEntities() + private void removeEntities() nothrow @nogc { foreach (i, ref thread; threads) { @@ -1738,7 +1739,7 @@ class EntityManager } } - void updateEvents() + void updateEvents() nothrow @nogc { bool empty = true; //uint index = event_manager. @@ -1775,7 +1776,7 @@ class EntityManager foreach(caller; events[i].callers) { call_data.system_pointer = caller.system.m_system_pointer; - (cast(void function(ref EventCallData))caller.callback)(call_data); + (cast(void function(ref EventCallData) nothrow @nogc)caller.callback)(call_data); } event_pointer += events[i].size; } @@ -1834,21 +1835,21 @@ class EntityManager //event_manager.clearEvents(); } - private void getThreadID() + private void getThreadID() nothrow @nogc { if (m_thread_id_func) - thread_id = m_thread_id_func(); + thread_id = (cast(uint delegate() nothrow @nogc)m_thread_id_func)(); else thread_id = 0; } - void sendEvent(Ev)(EntityID id, Ev event) + void sendEvent(Ev)(EntityID id, Ev event) nothrow @nogc { event_manager.sendEvent(id, event, thread_id); } /*private */ - void generateDependencies() + void generateDependencies() nothrow @nogc { foreach (pass_id, pass; passes) { @@ -2009,7 +2010,7 @@ class EntityManager ///Initialization data ubyte[] init_data; ///Pointer to component destroy callback - void function(void* pointer) destroy_callback; + void function(void* pointer) nothrow @nogc destroy_callback; } struct EventCaller @@ -2040,7 +2041,7 @@ class EntityManager struct EntityInfo { ///Returns number of blocks - uint blocksCount() + uint blocksCount() nothrow @nogc { if (last_block) return last_block.id + 1; @@ -2049,7 +2050,7 @@ class EntityManager } ///Returns number of non empty blocks - uint nonEmptyBlocksCount() + uint nonEmptyBlocksCount() nothrow @nogc { EntitiesBlock* block = last_block; while (1) @@ -2094,7 +2095,7 @@ class EntityManager struct EntitiesBlock { ///return distance (in bytes) from begin of block to data - uint dataDelta() + uint dataDelta() nothrow @nogc { ushort dif = EntitiesBlock.sizeof; alignNum(dif, type_info.alignment); @@ -2102,7 +2103,7 @@ class EntityManager } ///return pointer to first element in block - export void* dataBegin() + export void* dataBegin() nothrow @nogc { ushort dif = EntitiesBlock.sizeof; return cast(void*)&this + dif; @@ -2134,7 +2135,7 @@ class EntityManager */ struct CallData { - void update() + void update() nothrow @nogc { (cast(SytemFuncType) system.m_update)(this); } @@ -2160,7 +2161,7 @@ class EntityManager { CallData[] callers; - void execute() + void execute() nothrow @nogc { EntityManager.instance.getThreadID(); foreach (ref caller; callers) @@ -2181,7 +2182,7 @@ class EntityManager struct SystemCaller { - ~this() + ~this() nothrow @nogc { if (dependencies) { @@ -2209,7 +2210,7 @@ class EntityManager struct UpdatePass { - ~this() + ~this() nothrow @nogc { assert(name); if (name) @@ -2230,7 +2231,7 @@ class EntityManager //Vector!(SystemCaller*) system_callers; - alias SytemFuncType = void function(ref EntityManager.CallData data); + alias SytemFuncType = void function(ref EntityManager.CallData data) nothrow @nogc; //alias sendSelfEvent = instance.event_manager.sendSelfEvent; @@ -2278,7 +2279,7 @@ class EntityManager Vector!(Block*) blocks; uint id; - void clear() + void clear() nothrow @nogc { if (blocks.length > 0) foreach (block; blocks[0 .. id + 1]) @@ -2289,7 +2290,7 @@ class EntityManager //blocks.clear(); } - CallData[] getCallData(uint num) + CallData[] getCallData(uint num) nothrow @nogc { if (blocks.length == 0) { diff --git a/source/ecs/string_intern.d b/source/ecs/string_intern.d index 49dc21b..ed7820e 100644 --- a/source/ecs/string_intern.d +++ b/source/ecs/string_intern.d @@ -9,6 +9,7 @@ import std.traits : Parameters; private __gshared static HashMap!(const(char)[], StringIntern) gStringInterns; struct StringIntern { + private const(char)* strPtr; this(const(char)[] fromStr) { diff --git a/source/ecs/system.d b/source/ecs/system.d index 9c61591..d21e75a 100644 --- a/source/ecs/system.d +++ b/source/ecs/system.d @@ -12,7 +12,7 @@ struct System /************************************************************************************************************************ *Check if system is enabled. */ - export bool enabled() + export bool enabled() nothrow @nogc { return m_enabled; } @@ -20,27 +20,27 @@ struct System /************************************************************************************************************************ *Enable system. If actually it is enabled function do nothing. */ - export void enable() + export void enable() nothrow @nogc { if (!m_enabled && m_enable) - (cast(void function(void*))m_enable)(m_system_pointer); + (cast(void function(void*) nothrow @nogc)m_enable)(m_system_pointer); m_enabled = true; } /************************************************************************************************************************ *Disable system. If actually it is disabled function do nothing. */ - export void disable() + export void disable() nothrow @nogc { if (m_enabled && m_disable) - (cast(void function(void*))m_disable)(m_system_pointer); + (cast(void function(void*) nothrow @nogc)m_disable)(m_system_pointer); m_enabled = false; } /************************************************************************************************************************ *Get system priority. */ - export int priority() + export int priority() nothrow @nogc { return m_priority; } @@ -48,7 +48,7 @@ struct System /************************************************************************************************************************ *Get system priority. */ - export bool execute() + export bool execute() nothrow @nogc { return m_execute; } @@ -56,7 +56,7 @@ struct System /************************************************************************************************************************ *Get system priority. */ - export ushort id() + export ushort id() nothrow @nogc { return m_id; } diff --git a/tests/tests.d b/tests/tests.d index 7f9f72b..1d48f4b 100644 --- a/tests/tests.d +++ b/tests/tests.d @@ -284,7 +284,7 @@ struct TestSystem2 int main() { - void dispatch(EntityManager.JobGroup jobs) + void dispatch(EntityManager.JobGroup jobs) nothrow @nogc { foreach(job;jobs.jobs) { From dec0582398c3df57f27c717dd7958d00bea12e33 Mon Sep 17 00:00:00 2001 From: Mergul Date: Wed, 7 Nov 2018 19:53:33 +0100 Subject: [PATCH 023/217] -removed some unittest and unused code --- source/ecs/hash_map.d | 106 +--------------------------- source/ecs/manager.d | 43 ------------ source/ecs/vector.d | 160 +----------------------------------------- 3 files changed, 3 insertions(+), 306 deletions(-) diff --git a/source/ecs/hash_map.d b/source/ecs/hash_map.d index da317d2..4f25394 100755 --- a/source/ecs/hash_map.d +++ b/source/ecs/hash_map.d @@ -15,7 +15,7 @@ export ulong defaultHashFunc(T)(auto ref T t) nothrow @nogc { static if (isIntegral!(T)) { return hashInt(t); } else { - return hashInt(t.hashOf); // hashOf is not giving proper distribution between H1 and H2 hash parts + return 0;//hashInt(t.hashOf); // hashOf is not giving proper distribution between H1 and H2 hash parts } } @@ -291,106 +291,4 @@ struct HashMap(KeyPar, ValuePar, alias hashFunc = defaultHashFunc) { } return result; } - - import std.format : FormatSpec, formatValue; - - /** - * Preety print - */ - export void toString(scope void delegate(const(char)[]) sink, FormatSpec!char fmt) { - formatValue(sink, '[', fmt); - foreach (ref k, ref v; &byKeyValue) { - formatValue(sink, k, fmt); - formatValue(sink, ':', fmt); - formatValue(sink, v, fmt); - formatValue(sink, ", ", fmt); - } - formatValue(sink, ']', fmt); - } - -} - -static void dumpHashMapToJson(T)(ref T map, string path = "HashMapDump.json") { - Vector!char data; - import std.file; - import mutils.serializer.json; - - JSONSerializer.instance.serialize!(Load.no)(map, data); - std.file.write(path, data[]); -} - -static void printHashMap(T)(ref T map) { - import std.stdio; - - writeln(T.stringof, " dump:\n"); - foreach (k, v; &map.byKeyValue) { - writefln("%20s : %20s", k, v); - } -} - -unittest { - HashMap!(int, int) map; - - assert(map.isIn(123) == false); - assert(map.markerdDeleted == 0); - map.add(123, 1); - map.add(123, 1); - assert(map.isIn(123) == true); - assert(map.isIn(122) == false); - assert(map.length == 1); - map.remove(123); - assert(map.markerdDeleted == 1); - assert(map.isIn(123) == false); - assert(map.length == 0); - assert(map.tryRemove(500) == false); - map.add(123, 1); - assert(map.markerdDeleted == 0); - assert(map.tryRemove(123) == true); - - foreach (i; 1 .. 130) { - map.add(i, 1); - } - - foreach (i; 1 .. 130) { - assert(map.isIn(i)); - } - - foreach (i; 130 .. 500) { - assert(!map.isIn(i)); - } - - foreach (int el; map) { - assert(map.isIn(el)); - } -} - -unittest { - HashMap!(int, int) map; - map.add(1, 10); - assert(map.get(1) == 10); - assert(map.get(2, 20) == 20); - assert(!map.isIn(2)); - assert(map.getInsertDefault(2, 20) == 20); - assert(map.get(2) == 20); - map[5] = 50; - assert(map[5] == 50); - foreach (k; &map.byKey) { - } - foreach (k, v; &map.byKeyValue) { - } - foreach (v; &map.byValue) { - } -} - -unittest { - HashMap!(Vector!char, int) map; - Vector!char vecA; - - vecA ~= "AAA"; - map.add(vecA, 10); - assert(map[vecA] == 10); - map.add(vecA, 20); - assert(map[vecA] == 20); - //assert(vecA=="AAA"); - //assert(map["AAA"]==10);// TODO hashMap Vector!char and string -} +} \ No newline at end of file diff --git a/source/ecs/manager.d b/source/ecs/manager.d index b8932f3..d603b30 100644 --- a/source/ecs/manager.d +++ b/source/ecs/manager.d @@ -1720,7 +1720,6 @@ class EntityManager { block.entities_count = block.type_info.max_entities; } - //block.added_count = 0; block.added_count.atomicStore(cast(ushort) 0); } thread.blocks_to_update.clear(); @@ -1742,11 +1741,9 @@ class EntityManager void updateEvents() nothrow @nogc { bool empty = true; - //uint index = event_manager. while(1) { event_manager.swapCurrent(); - //event_manager.clearEvents(); uint current_index; if(event_manager.current_index == 0)current_index = cast(uint)threads.length; else current_index = 0; @@ -1763,7 +1760,6 @@ class EntityManager call_data.event = event_pointer; foreach(j;0..block.count) { - //void* event_pointer = cast(void*)block + event.data_offset; EntityID entity_id = *cast(EntityID*)event_pointer; Entity* entity = id_manager.getEntityPointer(entity_id); call_data.block = getMetaData(entity); @@ -1786,9 +1782,7 @@ class EntityManager } if(empty)break; empty = true; - //event_manager.clearEvents(); } - //event_manager.swapCurrent(); } export void commit() @@ -1831,8 +1825,6 @@ class EntityManager } commit(); - - //event_manager.clearEvents(); } private void getThreadID() nothrow @nogc @@ -1938,15 +1930,6 @@ class EntityManager qsort(pass.system_callers.array.ptr, pass.system_callers.length, (SystemCaller*).sizeof, &compareSystems); - /*static struct CallerData - { - uint id; - //bool - }*/ - - /*caller_data = (cast(SystemCaller**) alloca((SystemCaller*).sizeof * pass.system_callers.length))[0 - .. pass.system_callers.length];*/ - foreach (uint i, caller; pass.system_callers) caller.job_group.id = i; @@ -1955,17 +1938,6 @@ class EntityManager index = 0; foreach (uint i, caller; pass.system_callers) { - /* - if(priority == int.min)priority = caller.system.priority; - if(priority != caller.system.priority) - { - foreach(caller2;pass.system_callers[beg..i]) - { - - } - priority = caller.system.priority; - beg = i; - }*/ index = 0; foreach (ex; caller.exclusion) { @@ -2083,10 +2055,6 @@ class EntityManager EntitiesBlock* first_block; ///pointer to last block EntitiesBlock* last_block; - ///array of CallData. Contain data for System calls. - //Vector!(CallData) callers; - - ///Mutex used to managing block new alloction } /************************************************************************************************************************ @@ -2229,14 +2197,8 @@ class EntityManager bool register_state = false; - //Vector!(SystemCaller*) system_callers; - alias SytemFuncType = void function(ref EntityManager.CallData data) nothrow @nogc; - //alias sendSelfEvent = instance.event_manager.sendSelfEvent; - - //alias event_manager this; - ///Single page size. Must be power of two. enum page_size = 32768; //4096; ///Number of pages in block. @@ -2246,11 +2208,6 @@ class EntityManager BlockAllocator /*!(page_size, pages_in_block)*/ allocator; EventManager event_manager; - //mixin EventManagerCode; - - //Vector!EntityID entities_to_remove; - //Vector!(EntitiesBlock*) blocks_to_update; - //Vector!ubyte change_entities_list; void delegate(JobGroup jobs) m_dispatch_jobs; uint delegate() m_thread_id_func; diff --git a/source/ecs/vector.d b/source/ecs/vector.d index d67552f..a17aaf8 100644 --- a/source/ecs/vector.d +++ b/source/ecs/vector.d @@ -239,162 +239,4 @@ public: export bool opEquals()(auto ref const Vector!(T) r) const { return used == r.used && array.ptr[0 .. used] == r.array.ptr[0 .. r.used]; } - - export size_t toHash() const nothrow @trusted { - return hashOf(cast(Unqual!(T)[]) array.ptr[0 .. used]); - } - - import std.format : FormatSpec, formatValue; - - /** - * Preety print - */ - export void toString(scope void delegate(const(char)[]) sink, FormatSpec!char fmt) { - static if (__traits(compiles, formatValue(sink, array[0 .. used], fmt))) { - formatValue(sink, array[0 .. used], fmt); - } - } - -} - -// Helper to avoid GC -private T[n] s(T, size_t n)(auto ref T[n] array) pure nothrow @nogc @safe { - return array; -} - -@nogc nothrow unittest { - Vector!int vec; - assert(vec.empty); - vec.add(0); - vec.add(1); - vec.add(2); - vec.add(3); - vec.add(4); - vec.add(5); - assert(vec.length == 6); - assert(vec[3] == 3); - assert(vec[5] == 5); - assert(vec[] == [0, 1, 2, 3, 4, 5].s); - assert(!vec.empty); - vec.remove(3); - assert(vec.length == 5); - assert(vec[] == [0, 1, 2, 5, 4].s); //unstable remove -} - -@nogc nothrow unittest { - Vector!int vec; - assert(vec.empty); - vec ~= [0, 1, 2, 3, 4, 5].s; - assert(vec[] == [0, 1, 2, 3, 4, 5].s); - assert(vec.length == 6); - vec ~= 6; - assert(vec[] == [0, 1, 2, 3, 4, 5, 6].s); - -} - -@nogc nothrow unittest { - Vector!int vec; - vec ~= [0, 1, 2, 3, 4, 5].s; - vec[3] = 33; - assert(vec[3] == 33); -} - -@nogc nothrow unittest { - Vector!char vec; - vec ~= "abcd"; - assert(vec[] == cast(char[]) "abcd"); -} - -@nogc nothrow unittest { - Vector!int vec; - vec ~= [0, 1, 2, 3, 4, 5].s; - vec.length = 2; - assert(vec[] == [0, 1].s); -} -/////////////////////////////////////////// - -enum string checkVectorAllocations = ` -//assert(gVectorsCreated==gVectorsDestroyed); -gVectorsCreated=gVectorsDestroyed=0; -scope(exit){if(gVectorsCreated!=gVectorsDestroyed){ - import std.stdio : writefln; - writefln("created==destroyed %s==%s", gVectorsCreated, gVectorsDestroyed); - assert(gVectorsCreated==gVectorsDestroyed, "Vector memory leak"); -}} -`; - -unittest { - mixin(checkVectorAllocations); - Vector!int vecA = Vector!int([0, 1, 2, 3, 4, 5].s); - assert(vecA[] == [0, 1, 2, 3, 4, 5].s); - Vector!int vecB; - vecB = vecA; - assert(vecB[] == [0, 1, 2, 3, 4, 5].s); - assert(vecB.array.ptr != vecA.array.ptr); - assert(vecB.used == vecA.used); - Vector!int vecC = vecA; - assert(vecC[] == [0, 1, 2, 3, 4, 5].s); - assert(vecC.array.ptr != vecA.array.ptr); - assert(vecC.used == vecA.used); - Vector!int vecD = vecA.init; -} - -unittest { - static int numInit = 0; - static int numDestroy = 0; - scope (exit) { - assert(numInit == numDestroy); - } - static struct CheckDestructor { - int num = 1; - - this(this) { - numInit++; - } - - this(int n) { - num = n; - numInit++; - - } - - ~this() { - numDestroy++; - } - } - - CheckDestructor[2] arr = [CheckDestructor(1), CheckDestructor(1)]; - Vector!CheckDestructor vec; - vec ~= CheckDestructor(1); - vec ~= arr; - vec.remove(1); -} - -unittest { - assert(gVectorsCreated == gVectorsDestroyed); - gVectorsCreated = 0; - gVectorsDestroyed = 0; - scope (exit) { - assert(gVectorsCreated == gVectorsDestroyed); - } - string strA = "aaa bbb"; - string strB = "ccc"; - Vector!(Vector!char) vecA = Vector!(Vector!char)(Vector!char(cast(char[]) strA)); - assert(vecA[0] == Vector!char(cast(char[]) strA)); - Vector!(Vector!char) vecB; - vecB = vecA; - assert(vecB[0] == Vector!char(cast(char[]) strA)); - assert(vecA.array.ptr != vecB.array.ptr); - assert(vecB.used == vecA.used); - assert(vecB[0].array.ptr != vecA[0].array.ptr); - assert(vecB[0].used == vecA[0].used); -} - -unittest { - static struct Test { - int num; - @disable this(this); - } - - Vector!Test test; -} +} \ No newline at end of file From b18440e9bcf438e983dec732725f85d50418b227 Mon Sep 17 00:00:00 2001 From: Mergul Date: Wed, 16 Jan 2019 13:51:28 +0100 Subject: [PATCH 024/217] -fixed problems with new DMD --- source/ecs/manager.d | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/source/ecs/manager.d b/source/ecs/manager.d index d603b30..aa8c20a 100644 --- a/source/ecs/manager.d +++ b/source/ecs/manager.d @@ -1121,11 +1121,11 @@ class EntityManager current_delta += entites_in_block * components[id].size; } - foreach (uint i, ref system; systems) + foreach (i, ref system; systems) { if (system.m_update is null) continue; - addSystemCaller(*info, i); + addSystemCaller(*info, cast(uint)i); } entities_infos.add(info.components, info); @@ -1930,13 +1930,13 @@ class EntityManager qsort(pass.system_callers.array.ptr, pass.system_callers.length, (SystemCaller*).sizeof, &compareSystems); - foreach (uint i, caller; pass.system_callers) - caller.job_group.id = i; + foreach (i, caller; pass.system_callers) + caller.job_group.id = cast(uint)i; int priority = int.min; uint beg = 0; index = 0; - foreach (uint i, caller; pass.system_callers) + foreach (i, caller; pass.system_callers) { index = 0; foreach (ex; caller.exclusion) From a82ca1e659a9f8a7ccab86a29384fcf9ca2c9a3d Mon Sep 17 00:00:00 2001 From: Mergul Date: Thu, 21 Mar 2019 13:19:03 +0100 Subject: [PATCH 025/217] -some documentation changes -added Component onCreate callback which is called after allocating entity from template --- .gitignore | 1 - source/ecs/entity.d | 3 ++ source/ecs/manager.d | 65 +++++++++++++++++++++++++++++++++----------- source/ecs/system.d | 10 +++++++ 4 files changed, 62 insertions(+), 17 deletions(-) diff --git a/.gitignore b/.gitignore index 34d64bd..3a4254f 100644 --- a/.gitignore +++ b/.gitignore @@ -2,7 +2,6 @@ !*/ !source/** !tests/** - !README.md !dub.json !.gitignore \ No newline at end of file diff --git a/source/ecs/entity.d b/source/ecs/entity.d index 3757d80..931dfa0 100644 --- a/source/ecs/entity.d +++ b/source/ecs/entity.d @@ -1,3 +1,6 @@ +/************************************************************************************************************************ +*Entity module. +*/ module ecs.entity; import ecs.manager; diff --git a/source/ecs/manager.d b/source/ecs/manager.d index aa8c20a..87491ea 100644 --- a/source/ecs/manager.d +++ b/source/ecs/manager.d @@ -1,3 +1,6 @@ +/************************************************************************************************************************ +*Most important module. +*/ module ecs.manager; import std.algorithm : max; @@ -24,6 +27,9 @@ alias gEntityManager = EntityManager.instance; alias gEventManager = EntityManager.instance; alias SerializeVector = ecs.vector.Vector!ubyte; +/************************************************************************************************************************ +*Entity manager is responsible for everything. +*/ class EntityManager { export static void initialize(uint threads_count) @@ -189,8 +195,9 @@ class EntityManager *Systems can be registered from external dynamic library, and can be registered after adding entities too. *System mustn't be registered before components which system want to use, in this case functions call assertion. * - *params: - *priority = system priority. Priority determines order of execution of systems updates. + *Params: + *priority = system priority. Priority determines order of execution of systems updates + *pass = index of UpdatePass which sholud call system update */ void registerSystem(Sys)(int priority, ushort pass = 0) { @@ -730,11 +737,17 @@ class EntityManager Sys.system_id = system.id; } + /************************************************************************************************************************ + *Return system ECS api by id + */ System* getSystem(ushort id) nothrow @nogc { return &systems[id]; } + /************************************************************************************************************************ + *Return pointer to system registered in manager + */ Sys* getSystem(Sys)() nothrow @nogc { return cast(Sys*) systems[Sys.system_id].m_system_pointer; @@ -766,7 +779,6 @@ class EntityManager && Parameters!(Comp.onDestroy).length == 0) { static void callDestroy(void* pointer) nothrow @nogc - { (cast(void delegate() nothrow @nogc)&(cast(Comp*) pointer).onDestroy)(); } @@ -774,6 +786,18 @@ class EntityManager info.destroy_callback = &callDestroy; } + static if (hasMember!(Comp, "onCreate") && isFunction!(Comp.onCreate) + && is(ReturnType!(Comp.onCreate) == void) + && Parameters!(Comp.onCreate).length == 0) + { + static void callCreate(void* pointer) nothrow @nogc + { + (cast(void delegate() nothrow @nogc)&(cast(Comp*) pointer).onCreate)(); + } + + info.create_callback = &callCreate; + } + info.size = Comp.sizeof; info.alignment = Comp.alignof; //8; info.init_data = Mallocator.instance.makeArray!ubyte(Comp.sizeof); @@ -1025,7 +1049,7 @@ class EntityManager /************************************************************************************************************************ *Allocate EntityTemplate with specifed components and returns pointer to it. * - *params: + *Params: *components_ids = array of components allocated with template */ export EntityTemplate* allocateTemplate(ushort[] components_ids) @@ -1069,7 +1093,7 @@ class EntityManager /************************************************************************************************************************ *Returns entity type info. * - *params: + *Params: *ids = array of components */ export EntityInfo* getEntityInfo(ushort[] ids) @@ -1174,7 +1198,7 @@ class EntityManager /************************************************************************************************************************ *Returns pointer to entity. * - *params: + *Params: *id = ID of entity */ export Entity* getEntity(EntityID id) nothrow @nogc @@ -1185,7 +1209,7 @@ class EntityManager /************************************************************************************************************************ *Remove components from entity by IDs. Components will be removed on end of frame. * - *params: + *Params: *entity_id = ID of entity *del_ids = array of components IDs */ @@ -1262,8 +1286,8 @@ class EntityManager /************************************************************************************************************************ *Remove coponents from entity. * - *params: - *Compoenents = components types to remove + *Params: + *Components = components types to remove *entity_id = ID of entity */ void removeComponents(Components...)(EntityID entity_id) @@ -1411,9 +1435,9 @@ class EntityManager /************************************************************************************************************************ *Add components to entity. Components will be added on end of frame. * - *params: + *Params: *entity_id = ID of entity to remove - *tmpl = pointer entity template allocated by EntityManager. + *comps = components to add */ void addComponents(Components...)(const EntityID entity_id, Components comps) nothrow @nogc { @@ -1452,8 +1476,8 @@ class EntityManager /************************************************************************************************************************ *Free template memory. * - *params: - *tmpl = pointer entity template allocated by EntityManager. + *Params: + *template_ = pointer entity template allocated by EntityManager. */ export void freeTemplate(EntityTemplate* template_) { @@ -1464,7 +1488,7 @@ class EntityManager /************************************************************************************************************************ *Add entity to system. * - *params: + *Params: *tmpl = pointer entity template allocated by EntityManager. */ export ref Entity addEntity(EntityTemplate* tmpl) @@ -1489,6 +1513,13 @@ class EntityManager { memcpy(cast(void*) block + info.deltas[comp] + components[comp].size * id, tmpl.entity_data.ptr + info.tmpl_deltas[comp], components[comp].size); + + if (components[comp].create_callback) + { + components[comp].create_callback(cast( + void*) block + info.deltas[comp] + id * components[comp].size); + } + } if (index == 1) @@ -1578,7 +1609,7 @@ class EntityManager /************************************************************************************************************************ *Remove entity by ID. Entity will be removed on frame end. * - *params: + *Params: *id = id of entity to remove */ export void removeEntity(EntityID id) @@ -1660,7 +1691,7 @@ class EntityManager /************************************************************************************************************************ *functions return MetaData of page. * - *params: + *Params: *pointer = pointer to any data of entity (i.e. component data pointer) */ export EntitiesBlock* getMetaData(const void* pointer) nothrow @nogc @@ -1983,6 +2014,8 @@ class EntityManager ubyte[] init_data; ///Pointer to component destroy callback void function(void* pointer) nothrow @nogc destroy_callback; + ///Pointer to component create callback + void function(void* pointer) nothrow @nogc create_callback; } struct EventCaller diff --git a/source/ecs/system.d b/source/ecs/system.d index d21e75a..ba2168e 100644 --- a/source/ecs/system.d +++ b/source/ecs/system.d @@ -1,3 +1,6 @@ +/************************************************************************************************************************ +*System module. +*/ module ecs.system; import ecs.entity; @@ -5,6 +8,13 @@ import ecs.manager; /************************************************************************************************************************ *System contain data required to proper glue EntityManager with Systems. +*System callbacks: +*
-void onEnable() +*
-void onDisable(); +*
-bool onBegin(); +*
-void onEnd(); +*
-void onCreate() +*
-void onDestroy(); */ struct System { From 6bbc8b5152be26200b4d702a4eb4e57e3e4d9610 Mon Sep 17 00:00:00 2001 From: Mergul Date: Sat, 23 Mar 2019 19:48:24 +0000 Subject: [PATCH 026/217] -git now should ignore .dub/dub.json -added onAdd/onRemove to test -added onAdd/onRemove callbacks for system -generating onAdd/onRemove listeners --- .gitignore | 2 +- source/ecs/manager.d | 94 +++++++++++++++++++++++++++++++++++++++++++- source/ecs/system.d | 6 +++ tests/tests.d | 16 ++++++++ 4 files changed, 116 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index 3a4254f..280be93 100644 --- a/.gitignore +++ b/.gitignore @@ -3,5 +3,5 @@ !source/** !tests/** !README.md -!dub.json +!./dub.json !.gitignore \ No newline at end of file diff --git a/source/ecs/manager.d b/source/ecs/manager.d index 87491ea..8ca576c 100644 --- a/source/ecs/manager.d +++ b/source/ecs/manager.d @@ -84,6 +84,12 @@ class EntityManager assert(register_state, "beginRegister() should be called before endRegister();"); register_state = false; + foreach(ref info; &entities_infos.byValue) + { + if(info.systems)Mallocator.instance.dispose(info.systems); + info.systems = Mallocator.instance.makeArray!bool(systems.length); + } + foreach (ref system; systems) { if (system.m_update is null) @@ -151,6 +157,11 @@ class EntityManager } } + foreach(info; &entities_infos.byValue) + { + generateListeners(info); + } + generateDependencies(); } @@ -681,7 +692,6 @@ class EntityManager static "~RetType.stringof~" call" ~ func ~ "(void* system_pointer) { - Sys* s = cast(Sys*) system_pointer; "~ret_str~"s." ~ func ~ "(); } @@ -693,6 +703,32 @@ class EntityManager //dfmt on } + static string catchEntityFunc(RetType = void)(string member, string func) + { + //dfmt off + + static if(is(RetType == void))string ret_str = ""; + else string ret_str = "return "; + string ret = "static if (hasMember!(Sys, \"" ~ func ~ "\") && + Parameters!(Sys."~func~").length == 1 && + is(Parameters!(Sys."~func~")[0] == Sys.EntitiesData) && + is(ReturnType!(Sys."~func~") == "~RetType.stringof~")) + { + static "~RetType.stringof~" call" ~ func + ~ "(void* system_pointer) + { + Sys* s = cast(Sys*) system_pointer; + Sys.EntitiesData data; + "~ret_str~"s." ~ func ~ "(data); + } + + system." + ~ member ~ " = &call" ~ func ~ "; + }"; + return ret; + //dfmt on + } + mixin(catchFunc("m_enable", "onEnable")); mixin(catchFunc("m_disable", "onDisable")); mixin(catchFunc("m_create", "onCreate")); @@ -700,6 +736,9 @@ class EntityManager mixin(catchFunc!(bool)("m_begin", "onBegin")); mixin(catchFunc("m_end", "onEnd")); + mixin(catchEntityFunc("m_entity_added","onAdd")); + mixin(catchEntityFunc("m_entity_removed","onRemove")); + system.m_system_pointer = cast(void*) Mallocator.instance.make!Sys; system.m_priority = priority; (cast(Sys*) system.m_system_pointer).__ecsInitialize(); @@ -1145,6 +1184,8 @@ class EntityManager current_delta += entites_in_block * components[id].size; } + info.systems = Mallocator.instance.makeArray!bool(systems.length); + foreach (i, ref system; systems) { if (system.m_update is null) @@ -1153,10 +1194,52 @@ class EntityManager } entities_infos.add(info.components, info); + + generateListeners(info); } return info; } + void generateListeners(EntityInfo* info) + { + if(info.add_listeners) + { + Mallocator.instance.dispose(info.add_listeners); + info.add_listeners = null; + } + if(info.remove_listeners) + { + Mallocator.instance.dispose(info.remove_listeners); + info.remove_listeners = null; + } + + ushort[] tmp_add = (cast(ushort*)alloca(systems.length*ushort.sizeof))[0..systems.length]; + ushort[] tmp_rem = (cast(ushort*)alloca(systems.length*ushort.sizeof))[0..systems.length]; + int add_len = 0; + int rem_len = 0; + foreach(i;0..systems.length) + { + if(info.systems[i]) + { + System* system = &systems[i]; + if(system.m_entity_added)tmp_add[add_len++] = cast(ushort)i; + if(system.m_entity_removed)tmp_rem[rem_len++] = cast(ushort)i; + } + } + + if(add_len) + { + info.add_listeners = Mallocator.instance.makeArray!ushort(add_len); + memcpy(info.add_listeners.ptr,tmp_add.ptr,add_len*ushort.sizeof); + } + + if(rem_len) + { + info.remove_listeners = Mallocator.instance.makeArray!ushort(rem_len); + memcpy(info.remove_listeners.ptr,tmp_add.ptr,rem_len*ushort.sizeof); + } + } + export void addSystemCaller(ref EntityInfo entity, uint system_id) nothrow @nogc { System* system = &systems[system_id]; @@ -1193,6 +1276,8 @@ class EntityManager if (index < passes[system.m_pass].system_callers.length) passes[system.m_pass].system_callers[index].infos.add(&entity); + + entity.systems[system_id] = true; } /************************************************************************************************************************ @@ -2084,6 +2169,13 @@ class EntityManager ///max number of entities in block ushort max_entities; + ///array of systems which will update this entity + bool[] systems; + ///systems which are listening for added entities + ushort[] add_listeners; + ///systems which are listening for removed entities + ushort[] remove_listeners; + ///pointer to first block/page EntitiesBlock* first_block; ///pointer to last block diff --git a/source/ecs/system.d b/source/ecs/system.d index ba2168e..747f85c 100644 --- a/source/ecs/system.d +++ b/source/ecs/system.d @@ -9,12 +9,15 @@ import ecs.manager; /************************************************************************************************************************ *System contain data required to proper glue EntityManager with Systems. *System callbacks: +*
-void update(EntitesData); *
-void onEnable() *
-void onDisable(); *
-bool onBegin(); *
-void onEnd(); *
-void onCreate() *
-void onDestroy(); +*
-void onAdd(EntitesData); +*
-void onRemove(EntitiesData); */ struct System { @@ -132,6 +135,9 @@ package: void* m_begin; void* m_end; + void* m_entity_added; + void* m_entity_removed; + //void function(ref EntityManager.CallData data) m_initialize; //void function(ref EntityManager.CallData data) m_deinitilize; void* m_initialize; diff --git a/tests/tests.d b/tests/tests.d index 1d48f4b..dade72a 100644 --- a/tests/tests.d +++ b/tests/tests.d @@ -108,6 +108,21 @@ struct TestSystem writeln("On Test System destroy."); } + void onAdd(EntitiesData data) + { + writeln("Entity added ID: ",data.entites[0].id); + } + + /*void onAdd() + { + + }*/ + + void onRemove(EntitiesData data) + { + writeln("Entity destroyed ID: ",data.entites[0].id); + } + bool onBegin() { //writeln("On Test System begin."); @@ -127,6 +142,7 @@ struct TestSystem static struct EntitiesData { size_t length; + const(Entity)[] entites; TestComp[] test; TestComp2[] test2; @readonly @optional const(TestComp3)[] test3; From 3aad89fc566ebe0b90aef5f8b1bc57d2bd886cb4 Mon Sep 17 00:00:00 2001 From: Mergul Date: Sat, 23 Mar 2019 20:18:26 +0000 Subject: [PATCH 027/217] -fillInputData created as local function in register process -call onAdd (WIP) --- source/ecs/manager.d | 129 ++++++++++++++++++++++++++----------------- tests/tests.d | 4 +- 2 files changed, 79 insertions(+), 54 deletions(-) diff --git a/source/ecs/manager.d b/source/ecs/manager.d index 8ca576c..4bb3af1 100644 --- a/source/ecs/manager.d +++ b/source/ecs/manager.d @@ -566,78 +566,85 @@ class EntityManager return ret; } - static if (hasMember!(Sys, "update") && (mixin(genParamsChecking()))) + static string genFillInputData()() { - static string genFillInputData()() + string ret; + ushort comp; + uint req = 0; + uint opt = 0; + uint excluded = 0; + foreach (member; __traits(allMembers, Sys.EntitiesData)) { - string ret; - ushort comp; - uint req = 0; - uint opt = 0; - uint excluded = 0; - foreach (member; __traits(allMembers, Sys.EntitiesData)) + if (is(typeof(__traits(getMember, Sys.EntitiesData, + member)) == Entity[]) || is(typeof(__traits(getMember, + Sys.EntitiesData, member)) == const(Entity)[])) + { + ret ~= "input_data." ~ member + ~ " = (cast(Entity*) block.dataBegin())[offset .. entities_count];"; + } + else if (member == "length") + { + ret ~= "input_data." ~ member + ~ " = cast(typeof(input_data.length))(entities_count - offset);"; + } + else { - if (is(typeof(__traits(getMember, Sys.EntitiesData, - member)) == Entity[]) || is(typeof(__traits(getMember, - Sys.EntitiesData, member)) == const(Entity)[])) - { - ret ~= "input_data." ~ member - ~ " = (cast(Entity*) block.dataBegin())[offset .. entities_count];"; - } - else if (member == "length") - { - ret ~= "input_data." ~ member - ~ " = cast(typeof(input_data.length))(entities_count - offset);"; - } - else { + bool has_att = false; + foreach (att; __traits(getAttributes, + __traits(getMember, Sys.EntitiesData, member))) { - bool has_att = false; - foreach (att; __traits(getAttributes, - __traits(getMember, Sys.EntitiesData, member))) + if (att == "optional") { - if (att == "optional") - { - ret ~= "if(data.system.m_optional_components[" ~ opt.to!string - ~ "] < info.deltas.length && info.deltas[ data.system.m_optional_components[" - ~ opt.to!string ~ "]] != 0)input_data." ~ member - ~ " = (cast(ForeachType!(typeof(Sys.EntitiesData." ~ member - ~ "))*)(cast(void*) block + info.deltas[ data.system.m_optional_components[" - ~ opt.to!string ~ "]]))[offset .. entities_count]; - else input_data." - ~ member ~ " = null;"; - opt++; - has_att = true; - break; - } - else if (att == "excluded") - { - excluded++; - has_att = true; - break; - } + ret ~= "if(system.m_optional_components[" ~ opt.to!string + ~ "] < info.deltas.length && info.deltas[ system.m_optional_components[" + ~ opt.to!string ~ "]] != 0)input_data." ~ member + ~ " = (cast(ForeachType!(typeof(Sys.EntitiesData." ~ member + ~ "))*)(cast(void*) block + info.deltas[ system.m_optional_components[" + ~ opt.to!string ~ "]]))[offset .. entities_count]; + else input_data." + ~ member ~ " = null;"; + opt++; + has_att = true; + break; } - if (!has_att) + else if (att == "excluded") { - ret ~= "input_data." ~ member ~ " = (cast(ForeachType!(typeof(Sys.EntitiesData." ~ member - ~ "))*)(cast(void*) block + info.deltas[ data.system.m_components[" - ~ req.to!string ~ "]]))[offset .. entities_count];"; - req++; + excluded++; + has_att = true; + break; } } + if (!has_att) + { + ret ~= "input_data." ~ member ~ " = (cast(ForeachType!(typeof(Sys.EntitiesData." ~ member + ~ "))*)(cast(void*) block + info.deltas[ system.m_components[" + ~ req.to!string ~ "]]))[offset .. entities_count];"; + req++; + } } } - return ret; } + return ret; + } - //pragma(msg,genFillInputData); + //pragma(msg,genFillInputData); + static void fillInputData(ref Sys.EntitiesData input_data, EntityInfo* info, EntitiesBlock* block, + uint offset, uint entities_count, System* system) + { + mixin(genFillInputData()); + } + + static if (hasMember!(Sys, "update") && (mixin(genParamsChecking()))) + { static void callUpdate(ref CallData data) { Sys* s = cast(Sys*) data.system.m_system_pointer; Sys.EntitiesData input_data; EntityInfo* info = data.info; //block.type_info; + System* system = data.system; EntitiesBlock* block; if (data.first_block) @@ -667,7 +674,8 @@ class EntityManager assert(entities_count <= block.entities_count && offset <= block.entities_count); - mixin(genFillInputData()); + fillInputData(input_data, info, block, offset, entities_count, system); + //mixin(genFillInputData()); s.update(input_data); @@ -1825,12 +1833,29 @@ class EntityManager } } + private void callAddEntityListeners(EntityInfo* info, EntitiesBlock* block, int entity_index) + { + foreach(listener;info.add_listeners) + { + System* system = &systems[listener]; + (cast(void function (System*)) system.m_entity_added)(system); + } + } + private void updateBlocks() { foreach (ref thread; threads) { foreach (block; thread.blocks_to_update) { + EntityInfo* info = block.type_info; + if(info.add_listeners) + { + foreach(i;block.entities_count..block.entities_count+block.added_count) + { + callAddEntityListeners(info,block,i); + } + } block.entities_count += block.added_count; if (block.entities_count > block.type_info.max_entities) { diff --git a/tests/tests.d b/tests/tests.d index dade72a..3681ada 100644 --- a/tests/tests.d +++ b/tests/tests.d @@ -110,7 +110,7 @@ struct TestSystem void onAdd(EntitiesData data) { - writeln("Entity added ID: ",data.entites[0].id); + //writeln("Entity added ID: ");//,data.entites[0].id); } /*void onAdd() @@ -120,7 +120,7 @@ struct TestSystem void onRemove(EntitiesData data) { - writeln("Entity destroyed ID: ",data.entites[0].id); + //writeln("Entity destroyed ID: ",data.entites[0].id); } bool onBegin() From 1841c9c24446721202f787effcfdcbcbdaf4b813 Mon Sep 17 00:00:00 2001 From: Mergul Date: Sat, 23 Mar 2019 20:34:50 +0000 Subject: [PATCH 028/217] -working onAdd listener when new Entity is added to EntityManager --- source/ecs/manager.d | 31 +++++++++++++++++++++---------- tests/tests.d | 12 ++++-------- 2 files changed, 25 insertions(+), 18 deletions(-) diff --git a/source/ecs/manager.d b/source/ecs/manager.d index 4bb3af1..a1e694a 100644 --- a/source/ecs/manager.d +++ b/source/ecs/manager.d @@ -723,11 +723,12 @@ class EntityManager is(ReturnType!(Sys."~func~") == "~RetType.stringof~")) { static "~RetType.stringof~" call" ~ func - ~ "(void* system_pointer) + ~ "(ref ListenerCallData data) { - Sys* s = cast(Sys*) system_pointer; - Sys.EntitiesData data; - "~ret_str~"s." ~ func ~ "(data); + Sys* s = cast(Sys*) data.system.m_system_pointer; + Sys.EntitiesData input_data; + fillInputData(input_data, data.block.type_info, data.block, data.begin, data.end, data.system); + "~ret_str~"s." ~ func ~ "(input_data); } system." @@ -1833,12 +1834,17 @@ class EntityManager } } - private void callAddEntityListeners(EntityInfo* info, EntitiesBlock* block, int entity_index) + private void callAddEntityListeners(EntityInfo* info, EntitiesBlock* block, int begin, int end) { foreach(listener;info.add_listeners) { System* system = &systems[listener]; - (cast(void function (System*)) system.m_entity_added)(system); + ListenerCallData data; + data.system = system; + data.block = block; + data.begin = begin; + data.end = end; + (cast(void function (ref ListenerCallData)) system.m_entity_added)(data); } } @@ -1851,10 +1857,7 @@ class EntityManager EntityInfo* info = block.type_info; if(info.add_listeners) { - foreach(i;block.entities_count..block.entities_count+block.added_count) - { - callAddEntityListeners(info,block,i); - } + callAddEntityListeners(info,block,block.entities_count,block.entities_count+block.added_count); } block.entities_count += block.added_count; if (block.entities_count > block.type_info.max_entities) @@ -2275,6 +2278,14 @@ class EntityManager ushort end; } + struct ListenerCallData + { + System* system; + EntitiesBlock* block; + uint begin; + uint end; + } + struct Job { CallData[] callers; diff --git a/tests/tests.d b/tests/tests.d index 3681ada..2bb14af 100644 --- a/tests/tests.d +++ b/tests/tests.d @@ -110,18 +110,14 @@ struct TestSystem void onAdd(EntitiesData data) { - //writeln("Entity added ID: ");//,data.entites[0].id); + //foreach(i;0..data.length) + //writeln("Entity added ID: ",data.entites[i].id.id); } - /*void onAdd() - { - - }*/ - - void onRemove(EntitiesData data) + /*void onRemove(EntitiesData data) { //writeln("Entity destroyed ID: ",data.entites[0].id); - } + }*/ bool onBegin() { From e4be23ee96c2bfe792507abcb234fefac6bd9785 Mon Sep 17 00:00:00 2001 From: Mergul Date: Sat, 23 Mar 2019 21:47:39 +0000 Subject: [PATCH 029/217] -onRemove() called when entity is removed from EntityManager --- source/ecs/manager.d | 31 +++++++++++++++++++++++++++++-- tests/tests.d | 4 ++-- 2 files changed, 31 insertions(+), 4 deletions(-) diff --git a/source/ecs/manager.d b/source/ecs/manager.d index a1e694a..b7f0ecf 100644 --- a/source/ecs/manager.d +++ b/source/ecs/manager.d @@ -1718,6 +1718,19 @@ class EntityManager if (entity is null) return; //return if entity doesn't exist EntitiesBlock* block = getMetaData(entity); + + EntityInfo* info = block.type_info; + if(info.remove_listeners) + { + void* data_begin = block.dataBegin(); + static if (EntityID.sizeof == 8) + uint pos = cast(uint)((cast(void*) entity - data_begin) >> 3); + else + uint pos = cast(uint)((cast(void*) entity - data_begin) / EntityID.sizeof()); + + callRemoveEntityListeners(info,block,pos,pos+1); + } + id_manager.releaseID(id); //release id from manager removeEntityNoID(entity, block, true); @@ -1834,7 +1847,7 @@ class EntityManager } } - private void callAddEntityListeners(EntityInfo* info, EntitiesBlock* block, int begin, int end) + private void callAddEntityListeners(EntityInfo* info, EntitiesBlock* block, int begin, int end) @nogc nothrow { foreach(listener;info.add_listeners) { @@ -1844,7 +1857,21 @@ class EntityManager data.block = block; data.begin = begin; data.end = end; - (cast(void function (ref ListenerCallData)) system.m_entity_added)(data); + (cast(void function (ref ListenerCallData) nothrow @nogc) system.m_entity_added)(data); + } + } + + private void callRemoveEntityListeners(EntityInfo* info, EntitiesBlock* block, int begin, int end) @nogc nothrow + { + foreach(listener;info.add_listeners) + { + System* system = &systems[listener]; + ListenerCallData data; + data.system = system; + data.block = block; + data.begin = begin; + data.end = end; + (cast(void function (ref ListenerCallData) nothrow @nogc) system.m_entity_removed)(data); } } diff --git a/tests/tests.d b/tests/tests.d index 2bb14af..8d7f751 100644 --- a/tests/tests.d +++ b/tests/tests.d @@ -114,10 +114,10 @@ struct TestSystem //writeln("Entity added ID: ",data.entites[i].id.id); } - /*void onRemove(EntitiesData data) + void onRemove(EntitiesData data) { //writeln("Entity destroyed ID: ",data.entites[0].id); - }*/ + } bool onBegin() { From 4ac80d702589a678a02bb33f99e759da96b8636f Mon Sep 17 00:00:00 2001 From: Mergul Date: Sun, 24 Mar 2019 14:42:21 +0000 Subject: [PATCH 030/217] -onAdd/onRemove called when components are changed --- source/ecs/manager.d | 85 +++++++++++++++++++++++++++++++++++++------- tests/tests.d | 60 ++++++++++++++++++++++++++++++- 2 files changed, 131 insertions(+), 14 deletions(-) diff --git a/source/ecs/manager.d b/source/ecs/manager.d index b7f0ecf..7c10e5e 100644 --- a/source/ecs/manager.d +++ b/source/ecs/manager.d @@ -1284,9 +1284,12 @@ class EntityManager } if (index < passes[system.m_pass].system_callers.length) + { passes[system.m_pass].system_callers[index].infos.add(&entity); - entity.systems[system_id] = true; + entity.systems[system_id] = true; + } + } /************************************************************************************************************************ @@ -1365,6 +1368,18 @@ class EntityManager uint ind = cast(uint)((cast(void*) entity - block.dataBegin()) >> 3); else uint ind = cast(uint)((cast(void*) entity - block.dataBegin()) / EntityID.sizeof()); + + if(info.remove_listeners) + { + foreach(listener;info.remove_listeners) + { + if(!new_info.systems[listener]) + { + callRemoveEntityListener(&systems[listener],info,block,ind,ind+1); + } + } + } + foreach (comp; new_info.components) { uint comp_size = components[comp].size; @@ -1372,6 +1387,17 @@ class EntityManager cast(void*) block + info.deltas[comp] + ind * comp_size, comp_size); } + if(new_info.add_listeners) + { + foreach(listener;new_info.add_listeners) + { + if(!info.systems[listener]) + { + callAddEntityListener(&systems[listener],new_info,new_block,new_block.entities_count,new_block.entities_count+1); + } + } + } + new_block.entities_count++; removeEntityNoID(entity, block); @@ -1495,6 +1521,18 @@ class EntityManager uint ind = cast(uint)((cast(void*) entity - block.dataBegin()) >> 3); else uint ind = cast(uint)((cast(void*) entity - block.dataBegin()) / EntityID.sizeof()); + + if(info.remove_listeners) + { + foreach(listener;info.remove_listeners) + { + if(!new_info.systems[listener]) + { + callRemoveEntityListener(&systems[listener],info,block,ind,ind+1); + } + } + } + foreach (ref id; ids[0 .. len]) { void* dst = cast(void*) new_block + new_info.deltas[id] + ( @@ -1522,6 +1560,17 @@ class EntityManager } } + if(new_info.add_listeners) + { + foreach(listener;new_info.add_listeners) + { + if(!info.systems[listener]) + { + callAddEntityListener(&systems[listener],new_info,new_block,new_block.entities_count,new_block.entities_count+1); + } + } + } + new_block.entities_count++; removeEntityNoID(entity, block); } @@ -1852,29 +1901,39 @@ class EntityManager foreach(listener;info.add_listeners) { System* system = &systems[listener]; - ListenerCallData data; - data.system = system; - data.block = block; - data.begin = begin; - data.end = end; - (cast(void function (ref ListenerCallData) nothrow @nogc) system.m_entity_added)(data); + callAddEntityListener(system,info,block,begin,end); } } + private void callAddEntityListener(System* system, EntityInfo* info, EntitiesBlock* block, int begin, int end) @nogc nothrow + { + ListenerCallData data; + data.system = system; + data.block = block; + data.begin = begin; + data.end = end; + (cast(void function (ref ListenerCallData) nothrow @nogc) system.m_entity_added)(data); + } + private void callRemoveEntityListeners(EntityInfo* info, EntitiesBlock* block, int begin, int end) @nogc nothrow { foreach(listener;info.add_listeners) { System* system = &systems[listener]; - ListenerCallData data; - data.system = system; - data.block = block; - data.begin = begin; - data.end = end; - (cast(void function (ref ListenerCallData) nothrow @nogc) system.m_entity_removed)(data); + callRemoveEntityListener(system,info,block,begin,end); } } + private void callRemoveEntityListener(System* system, EntityInfo* info, EntitiesBlock* block, int begin, int end) @nogc nothrow + { + ListenerCallData data; + data.system = system; + data.block = block; + data.begin = begin; + data.end = end; + (cast(void function (ref ListenerCallData) nothrow @nogc) system.m_entity_removed)(data); + } + private void updateBlocks() { foreach (ref thread; threads) diff --git a/tests/tests.d b/tests/tests.d index 8d7f751..9e74e6e 100644 --- a/tests/tests.d +++ b/tests/tests.d @@ -94,6 +94,63 @@ static struct TestComp4 } } +struct ChangeTestSystem +{ + mixin ECS.System!16;//__gshared ushort system_id; + + void onCreate() + { + writeln("On Change Test System create."); + } + + void onDestroy() + { + writeln("On Change Test System destroy."); + } + + void onAdd(EntitiesData data) + { + foreach(i;0..data.length) + writeln("Entity added ID: ",data.entites[i].id.id); + } + + void onRemove(EntitiesData data) + { + writeln("Entity removed ID: ",data.entites[0].id); + } + + bool onBegin() + { + //writeln("On Test System begin."); + return true; + } + + void onEnd() + { + //writeln("On Test System end."); + } + + void initialize(ref Entity entity, ref TestComp comp) + { + + } + + static struct EntitiesData + { + size_t length; + const(Entity)[] entites; + TestComp4[] test4; + } + + void update(EntitiesData data) + { + foreach(i;0..data.length) + { + + } + } +} + struct TestSystem { mixin ECS.System!16;//__gshared ushort system_id; @@ -344,6 +401,7 @@ int main() gEM.registerSystem!TestSystemWithHighPriority(100,"fixed"); gEM.registerSystem!TestSystem(0); + gEM.registerSystem!ChangeTestSystem(0); //gEM.registerSystem!TestSystemWithHighPriority(100); //gEM.registerSystem!TestSystem2(0); gEM.endRegister(); @@ -491,6 +549,7 @@ int main() gEM.removeComponents!(TestComp)(entity.id); gEM.addComponents(entity.id, TestComp()); + gEM.removeComponents!(TestComp4)(entity.id); gEM.begin(); gEM.update(); @@ -498,7 +557,6 @@ int main() gEM.end(); writeEntityComponents(gEM.getEntity(entity.id)); - //import std.stdio; //writeln((cast(uint*)tmpl.info.first_block)[0..48]); gEM.freeTemplate(tmpl); From c64d621f0ed1668accd53935ae2e7cb2c4747176 Mon Sep 17 00:00:00 2001 From: Mergul Date: Tue, 26 Mar 2019 13:13:32 +0000 Subject: [PATCH 031/217] -fixed critical bug with onAdd callback --- source/ecs/manager.d | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/source/ecs/manager.d b/source/ecs/manager.d index 7c10e5e..0c6d0aa 100644 --- a/source/ecs/manager.d +++ b/source/ecs/manager.d @@ -1941,16 +1941,19 @@ class EntityManager foreach (block; thread.blocks_to_update) { EntityInfo* info = block.type_info; - if(info.add_listeners) - { - callAddEntityListeners(info,block,block.entities_count,block.entities_count+block.added_count); - } + ushort entities_count = block.entities_count; block.entities_count += block.added_count; if (block.entities_count > block.type_info.max_entities) { block.entities_count = block.type_info.max_entities; } block.added_count.atomicStore(cast(ushort) 0); + + if(info.add_listeners) + { + callAddEntityListeners(info,block,entities_count,block.entities_count); + } + } thread.blocks_to_update.clear(); } From 280d7b8ec4b0ad4287c3be184527b02160f0e978 Mon Sep 17 00:00:00 2001 From: Mergul Date: Thu, 28 Mar 2019 12:19:30 +0100 Subject: [PATCH 032/217] -onAdd/onRemove order is determined by system priority -fixed many bug with onAdd/onRemove -onAdd/onRemove now works even when system haven't update callback --- source/ecs/manager.d | 97 ++++++++++++++++++++++++++++++++++++++++---- tests/tests.d | 62 +++++++++++++++++++++++++++- 2 files changed, 148 insertions(+), 11 deletions(-) diff --git a/source/ecs/manager.d b/source/ecs/manager.d index 0c6d0aa..cd3c00f 100644 --- a/source/ecs/manager.d +++ b/source/ecs/manager.d @@ -93,7 +93,16 @@ class EntityManager foreach (ref system; systems) { if (system.m_update is null) + { + if(system.m_entity_added || system.m_entity_removed) + { + foreach (info; &entities_infos.byValue) + { + connectListenerToEntityInfo(*info,system.id); + } + } continue; + } bool added = false; foreach (i, caller; passes[system.m_pass].system_callers) @@ -119,6 +128,7 @@ class EntityManager foreach (info; &entities_infos.byValue) { addSystemCaller(*info, system.id); + //info.systems[system.id] = true; } } @@ -1197,8 +1207,12 @@ class EntityManager foreach (i, ref system; systems) { + //if(system.m_entity_added || system.m_entity_removed)info.systems[system.id] = true; if (system.m_update is null) + { + if(system.m_entity_added || system.m_entity_removed)connectListenerToEntityInfo(*info,cast(uint)i); continue; + } addSystemCaller(*info, cast(uint)i); } @@ -1221,18 +1235,53 @@ class EntityManager Mallocator.instance.dispose(info.remove_listeners); info.remove_listeners = null; } - + //allocate local data ushort[] tmp_add = (cast(ushort*)alloca(systems.length*ushort.sizeof))[0..systems.length]; ushort[] tmp_rem = (cast(ushort*)alloca(systems.length*ushort.sizeof))[0..systems.length]; int add_len = 0; int rem_len = 0; + //assign listeners to lists foreach(i;0..systems.length) { if(info.systems[i]) { System* system = &systems[i]; - if(system.m_entity_added)tmp_add[add_len++] = cast(ushort)i; - if(system.m_entity_removed)tmp_rem[rem_len++] = cast(ushort)i; + //onAddEntity listener + if(system.m_entity_added) + { + //find listener position by priority + int j; + for(j=0;j systems[tmp_add[j]].priority)break; + } + add_len++; + //move elements after new listener + for(int k=add_len;k>j;k--) + { + tmp_add[k] = tmp_add[k-1]; + } + //assign listener + tmp_add[j] = cast(ushort)i; + } + //onRemoveEntity listener + if(system.m_entity_removed) + { + //find listener position by priority + int j; + for(j=0;j systems[tmp_rem[j]].priority)break; + } + rem_len++; + //move elements after new listener + for(int k=rem_len;k>j;k--) + { + tmp_rem[k] = tmp_rem[k-1]; + } + //assign listener + tmp_rem[j] = cast(ushort)i; + } } } @@ -1245,11 +1294,11 @@ class EntityManager if(rem_len) { info.remove_listeners = Mallocator.instance.makeArray!ushort(rem_len); - memcpy(info.remove_listeners.ptr,tmp_add.ptr,rem_len*ushort.sizeof); + memcpy(info.remove_listeners.ptr,tmp_rem.ptr,rem_len*ushort.sizeof); } } - export void addSystemCaller(ref EntityInfo entity, uint system_id) nothrow @nogc + export void connectListenerToEntityInfo(ref EntityInfo entity, uint system_id) nothrow @nogc { System* system = &systems[system_id]; @@ -1276,6 +1325,38 @@ class EntityManager is_: } + entity.systems[system_id] = true; + } + + export void addSystemCaller(ref EntityInfo info, uint system_id) nothrow @nogc + { + System* system = &systems[system_id]; + + if (system.m_excluded_components) + { + foreach (id; system.m_excluded_components) + { + foreach (id2; info.components) + { + if (id == id2) + return; + } + } + } + + foreach (id; system.m_components) + { + foreach (i2, id2; info.components) + { + if (id2 == id) + goto is_; + } + return; + is_: + } + + info.systems[system_id] = true; + uint index = 0; for (; index < passes[system.m_pass].system_callers.length; index++) { @@ -1285,9 +1366,7 @@ class EntityManager if (index < passes[system.m_pass].system_callers.length) { - passes[system.m_pass].system_callers[index].infos.add(&entity); - - entity.systems[system_id] = true; + passes[system.m_pass].system_callers[index].infos.add(&info); } } @@ -1917,7 +1996,7 @@ class EntityManager private void callRemoveEntityListeners(EntityInfo* info, EntitiesBlock* block, int begin, int end) @nogc nothrow { - foreach(listener;info.add_listeners) + foreach(listener;info.remove_listeners) { System* system = &systems[listener]; callRemoveEntityListener(system,info,block,begin,end); diff --git a/tests/tests.d b/tests/tests.d index 9e74e6e..4fa8515 100644 --- a/tests/tests.d +++ b/tests/tests.d @@ -170,11 +170,11 @@ struct TestSystem //foreach(i;0..data.length) //writeln("Entity added ID: ",data.entites[i].id.id); } - +/* void onRemove(EntitiesData data) { //writeln("Entity destroyed ID: ",data.entites[0].id); - } + }*/ bool onBegin() { @@ -256,6 +256,57 @@ struct TestSystemWithHighPriority }*/ } +struct Sys1 +{ + mixin ECS.System; + + struct EntitiesData + { + TestComp[] comp; + } + + void onAdd(EntitiesData data) + { + + } +} + +struct Sys2 +{ + mixin ECS.System; + + struct EntitiesData + { + TestComp[] comp; + } + + void onAdd(EntitiesData data) + { + + } +} + +struct Sys3 +{ + mixin ECS.System; + + struct EntitiesData + { + TestComp[] comp; + } + + void onAdd(EntitiesData data) + { + + } + + void update(EntitiesData data) + { + + } +} + + import std.meta; struct TestSystem2 @@ -402,6 +453,9 @@ int main() gEM.registerSystem!TestSystemWithHighPriority(100,"fixed"); gEM.registerSystem!TestSystem(0); gEM.registerSystem!ChangeTestSystem(0); + gEM.registerSystem!Sys1(10); + gEM.registerSystem!Sys2(-100); + gEM.registerSystem!Sys3(-2); //gEM.registerSystem!TestSystemWithHighPriority(100); //gEM.registerSystem!TestSystem2(0); gEM.endRegister(); @@ -429,6 +483,10 @@ int main() { entity = gEM.addEntity(tmpl); writeEntityComponents(gEM.getEntity(entity.id)); + EntityManager.EntitiesBlock* block = EntityManager.instance.getMetaData(gEM.getEntity(entity.id)); + EntityManager.EntityInfo* info = block.type_info; + writeln(info.add_listeners); + //if(info)assert(0); } time = MonoTime.currTime; From d118adc028215edcbc1bb73875a0c1efc3de97d6 Mon Sep 17 00:00:00 2001 From: Mergul Date: Thu, 28 Mar 2019 17:57:28 +0100 Subject: [PATCH 033/217] -code foramtted with dfmt --- source/ecs/manager.d | 224 ++++++++++++++++++++++++------------------- source/ecs/system.d | 10 +- 2 files changed, 128 insertions(+), 106 deletions(-) diff --git a/source/ecs/manager.d b/source/ecs/manager.d index cd3c00f..d04a516 100644 --- a/source/ecs/manager.d +++ b/source/ecs/manager.d @@ -84,9 +84,10 @@ class EntityManager assert(register_state, "beginRegister() should be called before endRegister();"); register_state = false; - foreach(ref info; &entities_infos.byValue) + foreach (ref info; &entities_infos.byValue) { - if(info.systems)Mallocator.instance.dispose(info.systems); + if (info.systems) + Mallocator.instance.dispose(info.systems); info.systems = Mallocator.instance.makeArray!bool(systems.length); } @@ -94,11 +95,11 @@ class EntityManager { if (system.m_update is null) { - if(system.m_entity_added || system.m_entity_removed) + if (system.m_entity_added || system.m_entity_removed) { foreach (info; &entities_infos.byValue) { - connectListenerToEntityInfo(*info,system.id); + connectListenerToEntityInfo(*info, system.id); } } continue; @@ -134,32 +135,35 @@ class EntityManager event_manager.allocateData(cast(uint) threads.length); - foreach(ref info;events) + foreach (ref info; events) { Mallocator.instance.dispose(info.callers); } - ushort[] event_callers = (cast(ushort*)alloca(ushort.sizeof * events.length))[0..events.length]; - foreach(ref caller; event_callers)caller = 0; + ushort[] event_callers = (cast(ushort*) alloca(ushort.sizeof * events.length))[0 + .. events.length]; + foreach (ref caller; event_callers) + caller = 0; - foreach(ref system;systems) + foreach (ref system; systems) { - foreach(caller;system.m_event_callers) + foreach (caller; system.m_event_callers) { event_callers[caller.id]++; } } - foreach(i,ref info; events) + foreach (i, ref info; events) { info.callers = Mallocator.instance.makeArray!(EventCaller)(event_callers[i]); } - foreach(ref caller; event_callers)caller = 0; + foreach (ref caller; event_callers) + caller = 0; - foreach(ref system;systems) + foreach (ref system; systems) { - foreach(caller;system.m_event_callers) + foreach (caller; system.m_event_callers) { events[caller.id].callers[event_callers[caller.id]].callback = caller.callback; events[caller.id].callers[event_callers[caller.id]].system = &system; @@ -167,7 +171,7 @@ class EntityManager } } - foreach(info; &entities_infos.byValue) + foreach (info; &entities_infos.byValue) { generateListeners(info); } @@ -554,8 +558,8 @@ class EntityManager ret ~= "system.m_read_only_components[" ~ (read_only++) .to!string ~ "] = comp;"; else - ret ~= "system.m_modified_components[" ~ (modified++) - .to!string ~ "] = comp;"; + ret ~= "system.m_modified_components[" ~ (modified++) + .to!string ~ "] = comp;"; ret ~= "}"; } } @@ -640,8 +644,8 @@ class EntityManager //pragma(msg,genFillInputData); - static void fillInputData(ref Sys.EntitiesData input_data, EntityInfo* info, EntitiesBlock* block, - uint offset, uint entities_count, System* system) + static void fillInputData(ref Sys.EntitiesData input_data, EntityInfo* info, + EntitiesBlock* block, uint offset, uint entities_count, System* system) { mixin(genFillInputData()); } @@ -755,8 +759,8 @@ class EntityManager mixin(catchFunc!(bool)("m_begin", "onBegin")); mixin(catchFunc("m_end", "onEnd")); - mixin(catchEntityFunc("m_entity_added","onAdd")); - mixin(catchEntityFunc("m_entity_removed","onRemove")); + mixin(catchEntityFunc("m_entity_added", "onAdd")); + mixin(catchEntityFunc("m_entity_removed", "onRemove")); system.m_system_pointer = cast(void*) Mallocator.instance.make!Sys; system.m_priority = priority; @@ -845,8 +849,7 @@ class EntityManager } static if (hasMember!(Comp, "onCreate") && isFunction!(Comp.onCreate) - && is(ReturnType!(Comp.onCreate) == void) - && Parameters!(Comp.onCreate).length == 0) + && is(ReturnType!(Comp.onCreate) == void) && Parameters!(Comp.onCreate).length == 0) { static void callCreate(void* pointer) nothrow @nogc { @@ -1077,7 +1080,7 @@ class EntityManager nextJob(); caller.job_group.jobs = sys.jobs[0 .. job_id]; - (cast(void delegate(JobGroup) nothrow @nogc)m_dispatch_jobs)(caller.job_group); //sys.jobs[0 .. job_id]); + (cast(void delegate(JobGroup) nothrow @nogc) m_dispatch_jobs)(caller.job_group); //sys.jobs[0 .. job_id]); } } } @@ -1210,10 +1213,11 @@ class EntityManager //if(system.m_entity_added || system.m_entity_removed)info.systems[system.id] = true; if (system.m_update is null) { - if(system.m_entity_added || system.m_entity_removed)connectListenerToEntityInfo(*info,cast(uint)i); + if (system.m_entity_added || system.m_entity_removed) + connectListenerToEntityInfo(*info, cast(uint) i); continue; } - addSystemCaller(*info, cast(uint)i); + addSystemCaller(*info, cast(uint) i); } entities_infos.add(info.components, info); @@ -1225,76 +1229,80 @@ class EntityManager void generateListeners(EntityInfo* info) { - if(info.add_listeners) + if (info.add_listeners) { Mallocator.instance.dispose(info.add_listeners); info.add_listeners = null; } - if(info.remove_listeners) + if (info.remove_listeners) { Mallocator.instance.dispose(info.remove_listeners); info.remove_listeners = null; } //allocate local data - ushort[] tmp_add = (cast(ushort*)alloca(systems.length*ushort.sizeof))[0..systems.length]; - ushort[] tmp_rem = (cast(ushort*)alloca(systems.length*ushort.sizeof))[0..systems.length]; + ushort[] tmp_add = (cast(ushort*) alloca(systems.length * ushort.sizeof))[0 + .. systems.length]; + ushort[] tmp_rem = (cast(ushort*) alloca(systems.length * ushort.sizeof))[0 + .. systems.length]; int add_len = 0; int rem_len = 0; //assign listeners to lists - foreach(i;0..systems.length) + foreach (i; 0 .. systems.length) { - if(info.systems[i]) + if (info.systems[i]) { System* system = &systems[i]; //onAddEntity listener - if(system.m_entity_added) + if (system.m_entity_added) { //find listener position by priority int j; - for(j=0;j systems[tmp_add[j]].priority)break; + if (systems[i].priority > systems[tmp_add[j]].priority) + break; } add_len++; //move elements after new listener - for(int k=add_len;k>j;k--) + for (int k = add_len; k > j; k--) { - tmp_add[k] = tmp_add[k-1]; + tmp_add[k] = tmp_add[k - 1]; } //assign listener - tmp_add[j] = cast(ushort)i; + tmp_add[j] = cast(ushort) i; } //onRemoveEntity listener - if(system.m_entity_removed) + if (system.m_entity_removed) { //find listener position by priority int j; - for(j=0;j systems[tmp_rem[j]].priority)break; + if (systems[i].priority > systems[tmp_rem[j]].priority) + break; } rem_len++; //move elements after new listener - for(int k=rem_len;k>j;k--) + for (int k = rem_len; k > j; k--) { - tmp_rem[k] = tmp_rem[k-1]; + tmp_rem[k] = tmp_rem[k - 1]; } //assign listener - tmp_rem[j] = cast(ushort)i; + tmp_rem[j] = cast(ushort) i; } } } - - if(add_len) + + if (add_len) { info.add_listeners = Mallocator.instance.makeArray!ushort(add_len); - memcpy(info.add_listeners.ptr,tmp_add.ptr,add_len*ushort.sizeof); + memcpy(info.add_listeners.ptr, tmp_add.ptr, add_len * ushort.sizeof); } - if(rem_len) + if (rem_len) { info.remove_listeners = Mallocator.instance.makeArray!ushort(rem_len); - memcpy(info.remove_listeners.ptr,tmp_rem.ptr,rem_len*ushort.sizeof); + memcpy(info.remove_listeners.ptr, tmp_rem.ptr, rem_len * ushort.sizeof); } } @@ -1368,7 +1376,7 @@ class EntityManager { passes[system.m_pass].system_callers[index].infos.add(&info); } - + } /************************************************************************************************************************ @@ -1448,13 +1456,13 @@ class EntityManager else uint ind = cast(uint)((cast(void*) entity - block.dataBegin()) / EntityID.sizeof()); - if(info.remove_listeners) + if (info.remove_listeners) { - foreach(listener;info.remove_listeners) + foreach (listener; info.remove_listeners) { - if(!new_info.systems[listener]) + if (!new_info.systems[listener]) { - callRemoveEntityListener(&systems[listener],info,block,ind,ind+1); + callRemoveEntityListener(&systems[listener], info, block, ind, ind + 1); } } } @@ -1466,13 +1474,14 @@ class EntityManager cast(void*) block + info.deltas[comp] + ind * comp_size, comp_size); } - if(new_info.add_listeners) + if (new_info.add_listeners) { - foreach(listener;new_info.add_listeners) + foreach (listener; new_info.add_listeners) { - if(!info.systems[listener]) + if (!info.systems[listener]) { - callAddEntityListener(&systems[listener],new_info,new_block,new_block.entities_count,new_block.entities_count+1); + callAddEntityListener(&systems[listener], new_info, new_block, + new_block.entities_count, new_block.entities_count + 1); } } } @@ -1601,13 +1610,13 @@ class EntityManager else uint ind = cast(uint)((cast(void*) entity - block.dataBegin()) / EntityID.sizeof()); - if(info.remove_listeners) + if (info.remove_listeners) { - foreach(listener;info.remove_listeners) + foreach (listener; info.remove_listeners) { - if(!new_info.systems[listener]) + if (!new_info.systems[listener]) { - callRemoveEntityListener(&systems[listener],info,block,ind,ind+1); + callRemoveEntityListener(&systems[listener], info, block, ind, ind + 1); } } } @@ -1639,13 +1648,14 @@ class EntityManager } } - if(new_info.add_listeners) + if (new_info.add_listeners) { - foreach(listener;new_info.add_listeners) + foreach (listener; new_info.add_listeners) { - if(!info.systems[listener]) + if (!info.systems[listener]) { - callAddEntityListener(&systems[listener],new_info,new_block,new_block.entities_count,new_block.entities_count+1); + callAddEntityListener(&systems[listener], new_info, new_block, + new_block.entities_count, new_block.entities_count + 1); } } } @@ -1738,8 +1748,8 @@ class EntityManager if (components[comp].create_callback) { - components[comp].create_callback(cast( - void*) block + info.deltas[comp] + id * components[comp].size); + components[comp].create_callback( + cast(void*) block + info.deltas[comp] + id * components[comp].size); } } @@ -1846,9 +1856,9 @@ class EntityManager if (entity is null) return; //return if entity doesn't exist EntitiesBlock* block = getMetaData(entity); - + EntityInfo* info = block.type_info; - if(info.remove_listeners) + if (info.remove_listeners) { void* data_begin = block.dataBegin(); static if (EntityID.sizeof == 8) @@ -1856,7 +1866,7 @@ class EntityManager else uint pos = cast(uint)((cast(void*) entity - data_begin) / EntityID.sizeof()); - callRemoveEntityListeners(info,block,pos,pos+1); + callRemoveEntityListeners(info, block, pos, pos + 1); } id_manager.releaseID(id); //release id from manager @@ -1977,40 +1987,43 @@ class EntityManager private void callAddEntityListeners(EntityInfo* info, EntitiesBlock* block, int begin, int end) @nogc nothrow { - foreach(listener;info.add_listeners) + foreach (listener; info.add_listeners) { System* system = &systems[listener]; - callAddEntityListener(system,info,block,begin,end); + callAddEntityListener(system, info, block, begin, end); } } - private void callAddEntityListener(System* system, EntityInfo* info, EntitiesBlock* block, int begin, int end) @nogc nothrow + private void callAddEntityListener(System* system, EntityInfo* info, + EntitiesBlock* block, int begin, int end) @nogc nothrow { ListenerCallData data; data.system = system; data.block = block; data.begin = begin; data.end = end; - (cast(void function (ref ListenerCallData) nothrow @nogc) system.m_entity_added)(data); + (cast(void function(ref ListenerCallData) nothrow @nogc) system.m_entity_added)(data); } - private void callRemoveEntityListeners(EntityInfo* info, EntitiesBlock* block, int begin, int end) @nogc nothrow + private void callRemoveEntityListeners(EntityInfo* info, EntitiesBlock* block, int begin, + int end) @nogc nothrow { - foreach(listener;info.remove_listeners) + foreach (listener; info.remove_listeners) { System* system = &systems[listener]; - callRemoveEntityListener(system,info,block,begin,end); + callRemoveEntityListener(system, info, block, begin, end); } } - private void callRemoveEntityListener(System* system, EntityInfo* info, EntitiesBlock* block, int begin, int end) @nogc nothrow + private void callRemoveEntityListener(System* system, EntityInfo* info, + EntitiesBlock* block, int begin, int end) @nogc nothrow { ListenerCallData data; data.system = system; data.block = block; data.begin = begin; data.end = end; - (cast(void function (ref ListenerCallData) nothrow @nogc) system.m_entity_removed)(data); + (cast(void function(ref ListenerCallData) nothrow @nogc) system.m_entity_removed)(data); } private void updateBlocks() @@ -2028,11 +2041,11 @@ class EntityManager } block.added_count.atomicStore(cast(ushort) 0); - if(info.add_listeners) + if (info.add_listeners) { - callAddEntityListeners(info,block,entities_count,block.entities_count); + callAddEntityListeners(info, block, entities_count, block.entities_count); } - + } thread.blocks_to_update.clear(); } @@ -2053,38 +2066,46 @@ class EntityManager void updateEvents() nothrow @nogc { bool empty = true; - while(1) + while (1) { event_manager.swapCurrent(); uint current_index; - if(event_manager.current_index == 0)current_index = cast(uint)threads.length; - else current_index = 0; - foreach(i,event;event_manager.events) + if (event_manager.current_index == 0) + current_index = cast(uint) threads.length; + else + current_index = 0; + foreach (i, event; event_manager.events) { - foreach(first_block;event.first_blocks[current_index .. current_index + threads.length]) + foreach (first_block; event.first_blocks[current_index + .. current_index + threads.length]) { EventManager.EventBlock* block = first_block; - if(block)empty = false; - while(block) + if (block) + empty = false; + while (block) { EventCallData call_data; - void* event_pointer = cast(void*)block + event.data_offset; + void* event_pointer = cast(void*) block + event.data_offset; call_data.event = event_pointer; - foreach(j;0..block.count) + foreach (j; 0 .. block.count) { - EntityID entity_id = *cast(EntityID*)event_pointer; + EntityID entity_id = *cast(EntityID*) event_pointer; Entity* entity = id_manager.getEntityPointer(entity_id); call_data.block = getMetaData(entity); static if (EntityID.sizeof == 8) - call_data.id = cast(ushort)((cast(void*)entity - call_data.block.dataBegin()) >> 3); + call_data.id = cast(ushort)( + (cast(void*) entity - call_data.block.dataBegin()) >> 3); else - call_data.id = cast(ushort)((cast(void*)entity - call_data.block.dataBegin()) / EntityID.sizeof); - - foreach(caller; events[i].callers) + call_data.id = cast(ushort)( + (cast(void*) entity - call_data.block.dataBegin()) / EntityID + .sizeof); + + foreach (caller; events[i].callers) { call_data.system_pointer = caller.system.m_system_pointer; - (cast(void function(ref EventCallData) nothrow @nogc)caller.callback)(call_data); + (cast(void function(ref EventCallData) nothrow @nogc) caller + .callback)(call_data); } event_pointer += events[i].size; } @@ -2092,14 +2113,15 @@ class EntityManager } } } - if(empty)break; + if (empty) + break; empty = true; } } export void commit() { - updateEvents(); + updateEvents(); id_manager.optimize(); updateBlocks(); removeEntities(); @@ -2142,7 +2164,7 @@ class EntityManager private void getThreadID() nothrow @nogc { if (m_thread_id_func) - thread_id = (cast(uint delegate() nothrow @nogc)m_thread_id_func)(); + thread_id = (cast(uint delegate() nothrow @nogc) m_thread_id_func)(); else thread_id = 0; } @@ -2243,7 +2265,7 @@ class EntityManager (SystemCaller*).sizeof, &compareSystems); foreach (i, caller; pass.system_callers) - caller.job_group.id = cast(uint)i; + caller.job_group.id = cast(uint) i; int priority = int.min; uint beg = 0; diff --git a/source/ecs/system.d b/source/ecs/system.d index 747f85c..9b377cf 100644 --- a/source/ecs/system.d +++ b/source/ecs/system.d @@ -36,7 +36,7 @@ struct System export void enable() nothrow @nogc { if (!m_enabled && m_enable) - (cast(void function(void*) nothrow @nogc)m_enable)(m_system_pointer); + (cast(void function(void*) nothrow @nogc) m_enable)(m_system_pointer); m_enabled = true; } @@ -46,7 +46,7 @@ struct System export void disable() nothrow @nogc { if (m_enabled && m_disable) - (cast(void function(void*) nothrow @nogc)m_disable)(m_system_pointer); + (cast(void function(void*) nothrow @nogc) m_disable)(m_system_pointer); m_enabled = false; } @@ -97,7 +97,7 @@ package: int m_pass; ///system name - const (char)[] name; + const(char)[] name; ///required components ushort[] m_components; @@ -140,6 +140,6 @@ package: //void function(ref EntityManager.CallData data) m_initialize; //void function(ref EntityManager.CallData data) m_deinitilize; - void* m_initialize; - void* m_deinitilize; + void* m_initialize; + void* m_deinitilize; } From 7a33e4f94f7d9665f4af11abe6731ed84f0670f5 Mon Sep 17 00:00:00 2001 From: Mergul Date: Thu, 28 Mar 2019 18:01:43 +0100 Subject: [PATCH 034/217] -renamed callbacks: *onAdd -> onAddEntity *onRemove -> onRemoveEntity *update -> onUpdate --- source/ecs/manager.d | 24 ++++++++++++------------ source/ecs/system.d | 10 +++++----- tests/tests.d | 26 +++++++++++++------------- 3 files changed, 30 insertions(+), 30 deletions(-) diff --git a/source/ecs/manager.d b/source/ecs/manager.d index d04a516..a5443ce 100644 --- a/source/ecs/manager.d +++ b/source/ecs/manager.d @@ -95,7 +95,7 @@ class EntityManager { if (system.m_update is null) { - if (system.m_entity_added || system.m_entity_removed) + if (system.m_add_entity || system.m_remove_entity) { foreach (info; &entities_infos.byValue) { @@ -570,7 +570,7 @@ class EntityManager string genParamsChecking()() { string ret; - foreach (func; __traits(getOverloads, Sys, "update")) + foreach (func; __traits(getOverloads, Sys, "onUpdate")) { if ((Parameters!(func)).length == 1) ret ~= "\"" ~ (fullyQualifiedName!(Sys.EntitiesData)) ~ "\" == \"" ~ ( @@ -650,7 +650,7 @@ class EntityManager mixin(genFillInputData()); } - static if (hasMember!(Sys, "update") && (mixin(genParamsChecking()))) + static if (hasMember!(Sys, "onUpdate") && (mixin(genParamsChecking()))) { static void callUpdate(ref CallData data) { @@ -691,7 +691,7 @@ class EntityManager fillInputData(input_data, info, block, offset, entities_count, system); //mixin(genFillInputData()); - s.update(input_data); + s.onUpdate(input_data); block = block.next_block; offset = 0; @@ -759,8 +759,8 @@ class EntityManager mixin(catchFunc!(bool)("m_begin", "onBegin")); mixin(catchFunc("m_end", "onEnd")); - mixin(catchEntityFunc("m_entity_added", "onAdd")); - mixin(catchEntityFunc("m_entity_removed", "onRemove")); + mixin(catchEntityFunc("m_add_entity", "onAddEntity")); + mixin(catchEntityFunc("m_remove_entity", "onRemoveEntity")); system.m_system_pointer = cast(void*) Mallocator.instance.make!Sys; system.m_priority = priority; @@ -1210,10 +1210,10 @@ class EntityManager foreach (i, ref system; systems) { - //if(system.m_entity_added || system.m_entity_removed)info.systems[system.id] = true; + //if(system.m_add_entity || system.m_remove_entity)info.systems[system.id] = true; if (system.m_update is null) { - if (system.m_entity_added || system.m_entity_removed) + if (system.m_add_entity || system.m_remove_entity) connectListenerToEntityInfo(*info, cast(uint) i); continue; } @@ -1253,7 +1253,7 @@ class EntityManager { System* system = &systems[i]; //onAddEntity listener - if (system.m_entity_added) + if (system.m_add_entity) { //find listener position by priority int j; @@ -1272,7 +1272,7 @@ class EntityManager tmp_add[j] = cast(ushort) i; } //onRemoveEntity listener - if (system.m_entity_removed) + if (system.m_remove_entity) { //find listener position by priority int j; @@ -2002,7 +2002,7 @@ class EntityManager data.block = block; data.begin = begin; data.end = end; - (cast(void function(ref ListenerCallData) nothrow @nogc) system.m_entity_added)(data); + (cast(void function(ref ListenerCallData) nothrow @nogc) system.m_add_entity)(data); } private void callRemoveEntityListeners(EntityInfo* info, EntitiesBlock* block, int begin, @@ -2023,7 +2023,7 @@ class EntityManager data.block = block; data.begin = begin; data.end = end; - (cast(void function(ref ListenerCallData) nothrow @nogc) system.m_entity_removed)(data); + (cast(void function(ref ListenerCallData) nothrow @nogc) system.m_remove_entity)(data); } private void updateBlocks() diff --git a/source/ecs/system.d b/source/ecs/system.d index 9b377cf..d3d2b31 100644 --- a/source/ecs/system.d +++ b/source/ecs/system.d @@ -9,15 +9,15 @@ import ecs.manager; /************************************************************************************************************************ *System contain data required to proper glue EntityManager with Systems. *System callbacks: -*
-void update(EntitesData); +*
-void onUpdate(EntitesData); *
-void onEnable() *
-void onDisable(); *
-bool onBegin(); *
-void onEnd(); *
-void onCreate() *
-void onDestroy(); -*
-void onAdd(EntitesData); -*
-void onRemove(EntitiesData); +*
-void onAddEntity(EntitesData); +*
-void onRemoveEntity(EntitiesData); */ struct System { @@ -135,8 +135,8 @@ package: void* m_begin; void* m_end; - void* m_entity_added; - void* m_entity_removed; + void* m_add_entity; + void* m_remove_entity; //void function(ref EntityManager.CallData data) m_initialize; //void function(ref EntityManager.CallData data) m_deinitilize; diff --git a/tests/tests.d b/tests/tests.d index 4fa8515..1206732 100644 --- a/tests/tests.d +++ b/tests/tests.d @@ -108,13 +108,13 @@ struct ChangeTestSystem writeln("On Change Test System destroy."); } - void onAdd(EntitiesData data) + void onAddEntity(EntitiesData data) { foreach(i;0..data.length) writeln("Entity added ID: ",data.entites[i].id.id); } - void onRemove(EntitiesData data) + void onRemoveEntity(EntitiesData data) { writeln("Entity removed ID: ",data.entites[0].id); } @@ -142,7 +142,7 @@ struct ChangeTestSystem TestComp4[] test4; } - void update(EntitiesData data) + void onUpdate(EntitiesData data) { foreach(i;0..data.length) { @@ -165,13 +165,13 @@ struct TestSystem writeln("On Test System destroy."); } - void onAdd(EntitiesData data) + void onAddEntity(EntitiesData data) { //foreach(i;0..data.length) //writeln("Entity added ID: ",data.entites[i].id.id); } /* - void onRemove(EntitiesData data) + void onRemoveEntity(EntitiesData data) { //writeln("Entity destroyed ID: ",data.entites[0].id); }*/ @@ -202,7 +202,7 @@ struct TestSystem //@excluded TestComp4[] test4; } - void update(ref Entity entity, ref TestComp test, ref TestComp2 test2)//, TestComp3* test3) //ref TestComp comp) + void onUpdate(ref Entity entity, ref TestComp test, ref TestComp2 test2)//, TestComp3* test3) //ref TestComp comp) { assert(cast(size_t)&test % TestComp.alignof == 0); assert(cast(size_t)&test2 % TestComp2.alignof == 0); @@ -214,7 +214,7 @@ struct TestSystem test2.a = 8; } - void update(EntitiesData data) + void onUpdate(EntitiesData data) { foreach(i;0..data.length) { @@ -245,7 +245,7 @@ struct TestSystemWithHighPriority int o = 1; } - void update(EntitiesData data) + void onUpdate(EntitiesData data) { } @@ -265,7 +265,7 @@ struct Sys1 TestComp[] comp; } - void onAdd(EntitiesData data) + void onAddEntity(EntitiesData data) { } @@ -280,7 +280,7 @@ struct Sys2 TestComp[] comp; } - void onAdd(EntitiesData data) + void onAddEntity(EntitiesData data) { } @@ -295,12 +295,12 @@ struct Sys3 TestComp[] comp; } - void onAdd(EntitiesData data) + void onAddEntity(EntitiesData data) { } - void update(EntitiesData data) + void onUpdate(EntitiesData data) { } @@ -370,7 +370,7 @@ struct TestSystem2 } - void update(EntitiesData data) + void onUpdate(EntitiesData data) { foreach(i;0..data.test.length) { From 0608fe6e89d3ff8387317724796fdf7b26409693 Mon Sep 17 00:00:00 2001 From: Mergul Date: Thu, 28 Mar 2019 20:25:08 +0100 Subject: [PATCH 035/217] -added new listener callback: onChangeEntity. Callback is called when entity optional components are changed. There is no info about which components are changed (added/removed), but should be in the future).This is probably slowest callback. --- source/ecs/manager.d | 102 ++++++++++++++++++++++++++++++++++++-- source/ecs/system.d | 1 + tests/tests.d | 114 ++++++++++++++++++++++++++++--------------- 3 files changed, 175 insertions(+), 42 deletions(-) diff --git a/source/ecs/manager.d b/source/ecs/manager.d index a5443ce..0e45551 100644 --- a/source/ecs/manager.d +++ b/source/ecs/manager.d @@ -95,7 +95,7 @@ class EntityManager { if (system.m_update is null) { - if (system.m_add_entity || system.m_remove_entity) + if (system.m_add_entity || system.m_remove_entity || system.m_change_entity) { foreach (info; &entities_infos.byValue) { @@ -761,6 +761,7 @@ class EntityManager mixin(catchEntityFunc("m_add_entity", "onAddEntity")); mixin(catchEntityFunc("m_remove_entity", "onRemoveEntity")); + mixin(catchEntityFunc("m_change_entity", "onChangeEntity")); system.m_system_pointer = cast(void*) Mallocator.instance.make!Sys; system.m_priority = priority; @@ -1210,10 +1211,9 @@ class EntityManager foreach (i, ref system; systems) { - //if(system.m_add_entity || system.m_remove_entity)info.systems[system.id] = true; if (system.m_update is null) { - if (system.m_add_entity || system.m_remove_entity) + if (system.m_add_entity || system.m_remove_entity || system.m_change_entity) connectListenerToEntityInfo(*info, cast(uint) i); continue; } @@ -1239,13 +1239,21 @@ class EntityManager Mallocator.instance.dispose(info.remove_listeners); info.remove_listeners = null; } + if (info.change_listeners) + { + Mallocator.instance.dispose(info.change_listeners); + info.change_listeners = null; + } //allocate local data ushort[] tmp_add = (cast(ushort*) alloca(systems.length * ushort.sizeof))[0 .. systems.length]; ushort[] tmp_rem = (cast(ushort*) alloca(systems.length * ushort.sizeof))[0 .. systems.length]; + ushort[] tmp_ch = (cast(ushort*) alloca(systems.length * ushort.sizeof))[0 .. systems + .length]; int add_len = 0; int rem_len = 0; + int ch_len = 0; //assign listeners to lists foreach (i; 0 .. systems.length) { @@ -1290,6 +1298,25 @@ class EntityManager //assign listener tmp_rem[j] = cast(ushort) i; } + //onChangeEntity listener + if (system.m_change_entity) + { + //find listener position by priority + int j; + for (j = 0; j < ch_len; j++) + { + if (systems[i].priority > systems[tmp_ch[j]].priority) + break; + } + ch_len++; + //move elements after new listener + for (int k = ch_len; k > j; k--) + { + tmp_ch[k] = tmp_ch[k - 1]; + } + //assign listener + tmp_ch[j] = cast(ushort) i; + } } } @@ -1304,6 +1331,12 @@ class EntityManager info.remove_listeners = Mallocator.instance.makeArray!ushort(rem_len); memcpy(info.remove_listeners.ptr, tmp_rem.ptr, rem_len * ushort.sizeof); } + + if (ch_len) + { + info.change_listeners = Mallocator.instance.makeArray!ushort(ch_len); + memcpy(info.change_listeners.ptr, tmp_ch.ptr, ch_len * ushort.sizeof); + } } export void connectListenerToEntityInfo(ref EntityInfo entity, uint system_id) nothrow @nogc @@ -1486,6 +1519,18 @@ class EntityManager } } + if (new_info.change_listeners) + { + foreach (listener; new_info.change_listeners) + { + if (info.systems[listener]) + { + callChangeEntityListener(&systems[listener], new_info, new_block, + new_block.entities_count, new_block.entities_count + 1, del_ids); + } + } + } + new_block.entities_count++; removeEntityNoID(entity, block); @@ -1660,6 +1705,18 @@ class EntityManager } } + if (new_info.change_listeners) + { + foreach (listener; new_info.change_listeners) + { + if (info.systems[listener]) + { + callChangeEntityListener(&systems[listener], new_info, new_block, + new_block.entities_count, new_block.entities_count + 1, new_ids); + } + } + } + new_block.entities_count++; removeEntityNoID(entity, block); } @@ -2026,6 +2083,43 @@ class EntityManager (cast(void function(ref ListenerCallData) nothrow @nogc) system.m_remove_entity)(data); } + private void callChangeEntityListener(System* system, EntityInfo* info, + EntitiesBlock* block, int begin, int end, ushort[] ch_ids) @nogc nothrow + { + int i = 0; + int j = 0; + bool is_ = false; + while (1) + { + if (ch_ids[i] == system.m_optional_components[j]) + { + is_ = true; + break; + } + else if (ch_ids[i] > system.m_optional_components[j]) + { + j++; + if (j >= system.m_optional_components.length) + break; + } + else + { + i++; + if (i >= ch_ids.length) + break; + } + } + if (!is_) + return; + + ListenerCallData data; + data.system = system; + data.block = block; + data.begin = begin; + data.end = end; + (cast(void function(ref ListenerCallData) nothrow @nogc) system.m_change_entity)(data); + } + private void updateBlocks() { foreach (ref thread; threads) @@ -2393,6 +2487,8 @@ class EntityManager ushort[] add_listeners; ///systems which are listening for removed entities ushort[] remove_listeners; + ///systems which are listening for changed entities (changed in term of contained components) + ushort[] change_listeners; ///pointer to first block/page EntitiesBlock* first_block; diff --git a/source/ecs/system.d b/source/ecs/system.d index d3d2b31..765c380 100644 --- a/source/ecs/system.d +++ b/source/ecs/system.d @@ -137,6 +137,7 @@ package: void* m_add_entity; void* m_remove_entity; + void* m_change_entity; //void function(ref EntityManager.CallData data) m_initialize; //void function(ref EntityManager.CallData data) m_deinitilize; diff --git a/tests/tests.d b/tests/tests.d index 1206732..50c31b6 100644 --- a/tests/tests.d +++ b/tests/tests.d @@ -12,19 +12,19 @@ import std.stdio; struct TestEvent { - mixin ECS.Event;//__gshared ushort event_id; + mixin ECS.Event; //__gshared ushort event_id; int a; } struct TestEvent2 { - mixin ECS.Event;//__gshared ushort event_id; + mixin ECS.Event; //__gshared ushort event_id; float a; } static struct TestComp { - mixin ECS.Component;//__gshared ushort component_id; + mixin ECS.Component; //__gshared ushort component_id; int a = 1; ulong b = 2; @@ -41,7 +41,7 @@ static struct TestComp static struct TestComp2 { - mixin ECS.Component;//__gshared ushort component_id; + mixin ECS.Component; //__gshared ushort component_id; int b = 3; int a = 4; @@ -58,7 +58,7 @@ static struct TestComp2 static struct TestComp3 { - mixin ECS.Component;//__gshared ushort component_id; + mixin ECS.Component; //__gshared ushort component_id; uint gg = 5; //good game uint bg = 6; //bad game @@ -75,7 +75,28 @@ static struct TestComp3 static struct TestComp4 { - mixin ECS.Component;//__gshared ushort component_id; + mixin ECS.Component; //__gshared ushort component_id; + uint gg = 7; //good game + uint bg = 8; //bad game + ulong a = 9; + ulong b = 10; + ulong c = 11; + ulong g = 12; + + static void serializeComponent(ref TestComp comp, SerializeVector output) + { + + } + + static void deserializeComponent(ref TestComp comp, ubyte[] data) + { + + } +} + +static struct TestComp5 +{ + mixin ECS.Component; //__gshared ushort component_id; uint gg = 7; //good game uint bg = 8; //bad game ulong a = 9; @@ -96,7 +117,7 @@ static struct TestComp4 struct ChangeTestSystem { - mixin ECS.System!16;//__gshared ushort system_id; + mixin ECS.System!16; //__gshared ushort system_id; void onCreate() { @@ -110,13 +131,18 @@ struct ChangeTestSystem void onAddEntity(EntitiesData data) { - foreach(i;0..data.length) - writeln("Entity added ID: ",data.entites[i].id.id); + foreach (i; 0 .. data.length) + writeln("Entity added! ID: ", data.entites[i].id.id); } void onRemoveEntity(EntitiesData data) { - writeln("Entity removed ID: ",data.entites[0].id); + writeln("Entity removed! ID: ", data.entites[0].id); + } + + void onChangeEntity(EntitiesData data) + { + writeln("Entity changed! ID: ", data.entites[0].id); } bool onBegin() @@ -140,20 +166,21 @@ struct ChangeTestSystem size_t length; const(Entity)[] entites; TestComp4[] test4; + @optional TestComp5[] test5; } void onUpdate(EntitiesData data) { - foreach(i;0..data.length) + foreach (i; 0 .. data.length) { - + } } } struct TestSystem { - mixin ECS.System!16;//__gshared ushort system_id; + mixin ECS.System!16; //__gshared ushort system_id; void onCreate() { @@ -170,7 +197,7 @@ struct TestSystem //foreach(i;0..data.length) //writeln("Entity added ID: ",data.entites[i].id.id); } -/* + /* void onRemoveEntity(EntitiesData data) { //writeln("Entity destroyed ID: ",data.entites[0].id); @@ -202,7 +229,7 @@ struct TestSystem //@excluded TestComp4[] test4; } - void onUpdate(ref Entity entity, ref TestComp test, ref TestComp2 test2)//, TestComp3* test3) //ref TestComp comp) + void onUpdate(ref Entity entity, ref TestComp test, ref TestComp2 test2) //, TestComp3* test3) //ref TestComp comp) { assert(cast(size_t)&test % TestComp.alignof == 0); assert(cast(size_t)&test2 % TestComp2.alignof == 0); @@ -216,7 +243,7 @@ struct TestSystem void onUpdate(EntitiesData data) { - foreach(i;0..data.length) + foreach (i; 0 .. data.length) { data.test[i].a += 1000; data.test[i].b += 2000; @@ -233,7 +260,7 @@ struct TestSystem struct TestSystemWithHighPriority { - mixin ECS.System!16;//__gshared ushort system_id; + mixin ECS.System!16; //__gshared ushort system_id; static struct EntitiesData { @@ -247,7 +274,7 @@ struct TestSystemWithHighPriority void onUpdate(EntitiesData data) { - + } /*void handleEvent(Event event, ref TestComp comp) @@ -282,7 +309,7 @@ struct Sys2 void onAddEntity(EntitiesData data) { - + } } @@ -297,7 +324,7 @@ struct Sys3 void onAddEntity(EntitiesData data) { - + } void onUpdate(EntitiesData data) @@ -306,12 +333,11 @@ struct Sys3 } } - import std.meta; struct TestSystem2 { - mixin ECS.System!16;//__gshared ushort system_id; + mixin ECS.System!16; //__gshared ushort system_id; /*enum ExcludedComponents0 { @@ -326,7 +352,7 @@ struct TestSystem2 static struct EntitiesData { short length; - const (Entity)[] entity; + const(Entity)[] entity; TestComp3[] test; //@excluded TestComp[] testt; } @@ -348,7 +374,7 @@ struct TestSystem2 void handleEvent(EventInput input, ref TestEvent2 event) { - input.test.gg = cast(uint)event.a; + input.test.gg = cast(uint) event.a; } void onEnable() @@ -372,12 +398,12 @@ struct TestSystem2 void onUpdate(EntitiesData data) { - foreach(i;0..data.test.length) + foreach (i; 0 .. data.test.length) { data.test[i].gg += 14; TestEvent event; event.a = data.test[i].gg + 4; - gEM.sendEvent(data.entity[i].id, event);//*/ + gEM.sendEvent(data.entity[i].id, event); //*/ /*TestEvent2 event2; event2.a = data.test[i].gg + 8; gEM.sendEvent(data.entity[i].id, event2);//*/ @@ -385,10 +411,10 @@ struct TestSystem2 //gEM.sendSelfEvent!(TestEvent)(data.entity[i].id, TestEvent()); } } - + void lateUpdate(ref EntitiesData data) { - foreach(i;0..data.test.length) + foreach (i; 0 .. data.test.length) { data.test[i].gg -= 1; //gEM.sendSelfEvent!(TestEvent)(data.entity[i].id, TestEvent()); @@ -406,7 +432,7 @@ int main() void dispatch(EntityManager.JobGroup jobs) nothrow @nogc { - foreach(job;jobs.jobs) + foreach (job; jobs.jobs) { //writeln(job); job.execute(); @@ -417,13 +443,17 @@ int main() { write(entity.id); TestComp* test_comp = entity.getComponent!TestComp; - if(test_comp)write(*test_comp); + if (test_comp) + write(*test_comp); TestComp2* test_comp2 = entity.getComponent!TestComp2; - if(test_comp2)write(*test_comp2); + if (test_comp2) + write(*test_comp2); TestComp3* test_comp3 = entity.getComponent!TestComp3; - if(test_comp3)write(*test_comp3); + if (test_comp3) + write(*test_comp3); TestComp4* test_comp4 = entity.getComponent!TestComp4; - if(test_comp4)write(*test_comp4); + if (test_comp4) + write(*test_comp4); writeln(); //writeln((cast(uint*) pp)[0 .. 14], " ", pp); } @@ -441,6 +471,7 @@ int main() gEM.registerComponent!TestComp4; gEM.registerComponent!TestComp; gEM.registerComponent!TestComp3; + gEM.registerComponent!TestComp5; gEM.registerEvent!TestEvent; gEM.registerEvent!TestEvent2; @@ -450,7 +481,7 @@ int main() time = MonoTime.currTime; - gEM.registerSystem!TestSystemWithHighPriority(100,"fixed"); + gEM.registerSystem!TestSystemWithHighPriority(100, "fixed"); gEM.registerSystem!TestSystem(0); gEM.registerSystem!ChangeTestSystem(0); gEM.registerSystem!Sys1(10); @@ -483,12 +514,13 @@ int main() { entity = gEM.addEntity(tmpl); writeEntityComponents(gEM.getEntity(entity.id)); - EntityManager.EntitiesBlock* block = EntityManager.instance.getMetaData(gEM.getEntity(entity.id)); + EntityManager.EntitiesBlock* block = EntityManager.instance.getMetaData( + gEM.getEntity(entity.id)); EntityManager.EntityInfo* info = block.type_info; writeln(info.add_listeners); //if(info)assert(0); - } - + } + time = MonoTime.currTime; //foreach(i; 0..1_000_000)gEM.addEntity(tmpl); @@ -607,13 +639,17 @@ int main() gEM.removeComponents!(TestComp)(entity.id); gEM.addComponents(entity.id, TestComp()); - gEM.removeComponents!(TestComp4)(entity.id); + gEM.addComponents(entity.id, TestComp5()); gEM.begin(); gEM.update(); gEM.update("fixed"); gEM.end(); + gEM.removeComponents!(TestComp4)(entity.id); + + gEM.commit(); + writeEntityComponents(gEM.getEntity(entity.id)); //import std.stdio; //writeln((cast(uint*)tmpl.info.first_block)[0..48]); @@ -621,4 +657,4 @@ int main() EntityManager.destroy(); return 0; -} \ No newline at end of file +} From 201681e4ca5e4580022852a5729f1ca65f3810ae Mon Sep 17 00:00:00 2001 From: Mergul Date: Thu, 4 Apr 2019 17:54:39 +0200 Subject: [PATCH 036/217] -fixed small issue, now Template.getComponent should return null if component doesn't exist in template --- source/ecs/entity.d | 2 +- source/ecs/manager.d | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/source/ecs/entity.d b/source/ecs/entity.d index 931dfa0..09a5996 100644 --- a/source/ecs/entity.d +++ b/source/ecs/entity.d @@ -65,7 +65,7 @@ export struct EntityTemplate */ T* getComponent(T)() nothrow @nogc { - if(T.component_id >= info.tmpl_deltas.length)return null; + if(T.component_id >= info.tmpl_deltas.length || info.tmpl_deltas[T.component_id] == ushort.max)return null; return cast(T*)(entity_data.ptr + info.tmpl_deltas[T.component_id]); } } diff --git a/source/ecs/manager.d b/source/ecs/manager.d index 0e45551..ddcbba5 100644 --- a/source/ecs/manager.d +++ b/source/ecs/manager.d @@ -1171,7 +1171,7 @@ class EntityManager info.size = EntityID.sizeof; info.alignment = EntityID.alignof; - info.tmpl_deltas = Mallocator.instance.makeArray!ushort(ids[$ - 1] + 1); + info.tmpl_deltas = Mallocator.instance.makeArray!ushort(ids[$ - 1] + 1,ushort.max); uint components_size = EntityID.sizeof; foreach (i, id; ids) From 77f67004ddd1a13485955c82d712a3513d51f678 Mon Sep 17 00:00:00 2001 From: Mergul Date: Sat, 6 Apr 2019 14:15:02 +0000 Subject: [PATCH 037/217] -removed string_intern -removed unused traits --- source/ecs/string_intern.d | 138 ------------------------------------- source/ecs/traits.d | 30 +------- 2 files changed, 2 insertions(+), 166 deletions(-) delete mode 100644 source/ecs/string_intern.d diff --git a/source/ecs/string_intern.d b/source/ecs/string_intern.d deleted file mode 100644 index ed7820e..0000000 --- a/source/ecs/string_intern.d +++ /dev/null @@ -1,138 +0,0 @@ -module ecs.string_intern; - -import ecs.hash_map; -import ecs.traits : isForeachDelegateWithI; -import std.experimental.allocator; -import std.experimental.allocator.mallocator; -import std.traits : Parameters; - -private __gshared static HashMap!(const(char)[], StringIntern) gStringInterns; - -struct StringIntern { - - private const(char)* strPtr; - - this(const(char)[] fromStr) { - opAssign(fromStr); - } - - void reset() { - strPtr=null; - } - - size_t length() { - if (strPtr is null) { - return 0; - } - return *cast(size_t*)(strPtr - 8); - } - - const(char)[] str() { - if (strPtr is null) { - return null; - } - return strPtr[0 .. length]; - } - - const(char)[] cstr() { - if (strPtr is null) { - return "\0"; - } - return strPtr[0 .. length + 1]; - } - - bool opEquals()(auto ref const StringIntern s) { - return strPtr == s.strPtr; - } - - bool opEquals()(auto ref const(char[]) s) { - return str() == s; - } - - void opAssign(const(char)[] fromStr) { - if (fromStr.length == 0) { - return; - } - StringIntern defaultValue; - StringIntern internedStr = gStringInterns.get(fromStr, defaultValue); - - if (internedStr.length == 0) { - internedStr.strPtr = allocStr(fromStr).ptr; - gStringInterns.add(internedStr.str, internedStr); - } - - strPtr = internedStr.strPtr; - } - - const(char)[] opSlice() { - if (strPtr is null) { - return null; - } - return strPtr[0 .. length]; - } - - private const(char)[] allocStr(const(char)[] fromStr) { - char[] data = Mallocator.instance.makeArray!(char)(fromStr.length + size_t.sizeof + 1); - size_t* len = cast(size_t*) data.ptr; - *len = fromStr.length; - data[size_t.sizeof .. $ - 1] = fromStr; - data[$ - 1] = '\0'; - return data[size_t.sizeof .. $ - 1]; - } -} - -unittest { - static assert(StringIntern.sizeof == size_t.sizeof); - const(char)[] chA = ['a', 'a']; - char[] chB = ['o', 't', 'h', 'e', 'r']; - const(char)[] chC = ['o', 't', 'h', 'e', 'r']; - string chD = "other"; - - StringIntern strA; - StringIntern strB = StringIntern(""); - StringIntern strC = StringIntern("a"); - StringIntern strD = "a"; - StringIntern strE = "aa"; - StringIntern strF = chA; - StringIntern strG = chB; - - assert(strA == strB); - assert(strA != strC); - assert(strC == strD); - assert(strD != strE); - assert(strE == strF); - - assert(strD.length == 1); - assert(strE.length == 2); - assert(strG.length == 5); - - strA = "other"; - assert(strA == "other"); - assert(strA == chB); - assert(strA == chC); - assert(strA == chD); - assert(strA.str.ptr[strA.str.length] == '\0'); - assert(strA.cstr[$ - 1] == '\0'); - - foreach (char c; strA) { - } - foreach (int i, char c; strA) { - } - foreach (ubyte i, char c; strA) { - } - foreach (c; strA) { - } -} - -unittest { - import ecs.hash_map : HashMap; - - HashMap!(StringIntern, StringIntern) map; - - map.add(StringIntern("aaa"), StringIntern("bbb")); - map.add(StringIntern("aaa"), StringIntern("bbb")); - - assert(map.length == 1); - assert(map.get(StringIntern("aaa")) == StringIntern("bbb")); - -} diff --git a/source/ecs/traits.d b/source/ecs/traits.d index cb5da91..3289221 100644 --- a/source/ecs/traits.d +++ b/source/ecs/traits.d @@ -1,28 +1,7 @@ -module ecs.traits; +module ecs.traits; import std.traits; -bool isForeachDelegateWithI(DG)() { - return is(DG == delegate) && is(ReturnType!DG == int) - && Parameters!DG.length == 2 && isIntegral!(Parameters!(DG)[0]); -} - -unittest { - assert(isForeachDelegateWithI!(int delegate(int, double))); - assert(isForeachDelegateWithI!(int delegate(int, double) @nogc nothrow)); - assert(!isForeachDelegateWithI!(int delegate(double, double))); -} - -bool isForeachDelegateWithoutI(DG)() { - return is(DG == delegate) && is(ReturnType!DG == int) && Parameters!DG.length == 1; -} - -unittest { - assert(isForeachDelegateWithoutI!(int delegate(int))); - assert(isForeachDelegateWithoutI!(int delegate(size_t) @nogc nothrow)); - assert(!isForeachDelegateWithoutI!(void delegate(int))); -} - bool isForeachDelegateWithTypes(DG, Types...)() { return is(DG == delegate) && is(ReturnType!DG == int) && is(Parameters!DG == Types); } @@ -31,9 +10,4 @@ unittest { assert(isForeachDelegateWithTypes!(int delegate(int, int), int, int)); assert(isForeachDelegateWithTypes!(int delegate(ref int, ref int), int, int)); assert(!isForeachDelegateWithTypes!(int delegate(double), int, int)); -} - -auto assumeNoGC(T)(T t) if (isFunctionPointer!T || isDelegate!T) { - enum attrs = functionAttributes!T | FunctionAttribute.nogc; - return cast(SetFunctionAttributes!(T, functionLinkage!T, attrs)) t; -} +} \ No newline at end of file From 7e7658af3bd91254ccb81a8e668c4b57a34d7a25 Mon Sep 17 00:00:00 2001 From: Mergul Date: Sat, 6 Apr 2019 14:24:31 +0000 Subject: [PATCH 038/217] -added first mmcommando commit --- source/ecs/manager.d | 45 ++++++++++++++++++++++++++++++++++++++++---- source/ecs/traits.d | 32 ++++++++++++++++++++++++++++--- 2 files changed, 70 insertions(+), 7 deletions(-) diff --git a/source/ecs/manager.d b/source/ecs/manager.d index ddcbba5..26ffb5a 100644 --- a/source/ecs/manager.d +++ b/source/ecs/manager.d @@ -21,6 +21,7 @@ import ecs.id_manager; import ecs.system; import ecs.vector; import ecs.events; +import ecs.traits; alias gEM = EntityManager.instance; alias gEntityManager = EntityManager.instance; @@ -248,7 +249,7 @@ class EntityManager //dfmt off static if(hasMember!(Sys,"EventInput")) { - static string genEventCompList()() + /*static string genEventCompList()() { string ret = "Sys.EventInput input;\n"; string type; @@ -282,11 +283,45 @@ class EntityManager ~ ").sizeof);\n"; } return ret; - } + }*/ //pragma(msg,genEventCompList()); //pragma(msg,genEventCompList()); + static void genEventCompList(Sys)(ref EventCallData data, EntityInfo* info, ref Sys.EventInput input) + { + alias EventFields=Fields!(Sys.EventInput); + foreach (eventFieldNum, ref eventField; input.tupleof) + { + alias EventFieldType = Unqual!(typeof(*eventField)); + enum bool isEntity = is( EventFieldType == ecs.entity.Entity ); + + static if(isEntity) + { + eventField=cast(Entity*) data.block.dataBegin() + data.id; + continue; + } + else + { + enum long indexInEntitiesData=getIndexOfTypeInEntitiesData!(Sys.EntitiesData, EventFieldType); + static assert(indexInEntitiesData != -1);// Type present in EventInput has to be present in EntitiesData + + enum bool isOptional = hasUDA!(Sys.EntitiesData.tupleof[indexInEntitiesData], "optional"); + static if(isOptional) + { + eventField=null; + } + else + { + eventField = cast(EventFieldType*)(cast(void*) data.block + + info.deltas[EventFieldType.component_id] + + data.id * EventFieldType.sizeof); + } + } + + } + } + static string checkHandler()(string member) { string ret; @@ -325,7 +360,9 @@ class EntityManager ret ~= "static void callHandler"~event_handlers.to!string~"(ref EventCallData data)\n{\n"; ret ~= "Sys* s = cast(Sys*) data.system_pointer; EntityInfo* info = data.block.type_info;"; - ret ~= genEventCompList(); + //ret ~= genEventCompList(); + ret ~= "Sys.EventInput input;\n"; + ret ~= "genEventCompList!(Sys)(data, info, input);"; ret ~= "s.handleEvent(input, *cast("~event_param~"*)data.event);"; ret ~= "}\n"; ret ~= "system.m_event_callers["~event_handlers.to!string~"].callback = cast(void*)&callHandler"~event_handlers.to!string~";"; @@ -1171,7 +1208,7 @@ class EntityManager info.size = EntityID.sizeof; info.alignment = EntityID.alignof; - info.tmpl_deltas = Mallocator.instance.makeArray!ushort(ids[$ - 1] + 1,ushort.max); + info.tmpl_deltas = Mallocator.instance.makeArray!ushort(ids[$ - 1] + 1, ushort.max); uint components_size = EntityID.sizeof; foreach (i, id; ids) diff --git a/source/ecs/traits.d b/source/ecs/traits.d index 3289221..b270b06 100644 --- a/source/ecs/traits.d +++ b/source/ecs/traits.d @@ -2,12 +2,38 @@ module ecs.traits; import std.traits; -bool isForeachDelegateWithTypes(DG, Types...)() { +bool isForeachDelegateWithTypes(DG, Types...)() +{ return is(DG == delegate) && is(ReturnType!DG == int) && is(Parameters!DG == Types); } -unittest { +unittest +{ assert(isForeachDelegateWithTypes!(int delegate(int, int), int, int)); assert(isForeachDelegateWithTypes!(int delegate(ref int, ref int), int, int)); assert(!isForeachDelegateWithTypes!(int delegate(double), int, int)); -} \ No newline at end of file +} + +/************************************************************************************************************************ +* Returns index of Component/Entity array in System's EntitiesData struct +*/ +static long getIndexOfTypeInEntitiesData(EntitiesData, Type)() +{ + alias EntitiesDataFields = Fields!(EntitiesData); + long index = -1; + foreach (fieldNum, FieldType; Fields!(EntitiesData)) + { + + static if (!isBasicType!(FieldType)) // Not basic type + { + // FieldType should be something like: 'const(SomeComponent)[]' + enum bool entitiesMatches = is(Type == Unqual!(ForeachType!(FieldType))); + static if (entitiesMatches) + { + index = fieldNum; + break; + } + } + } + return index; +} From dbdbdb35e1ca87edb87686fe3ee79fe695b68bed Mon Sep 17 00:00:00 2001 From: Mergul Date: Sat, 6 Apr 2019 14:36:50 +0000 Subject: [PATCH 039/217] -added assert message --- source/ecs/manager.d | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/ecs/manager.d b/source/ecs/manager.d index 26ffb5a..92f4aaf 100644 --- a/source/ecs/manager.d +++ b/source/ecs/manager.d @@ -304,7 +304,7 @@ class EntityManager else { enum long indexInEntitiesData=getIndexOfTypeInEntitiesData!(Sys.EntitiesData, EventFieldType); - static assert(indexInEntitiesData != -1);// Type present in EventInput has to be present in EntitiesData + static assert(indexInEntitiesData != -1, "Component present in EventInput has to be present in EntitiesData!");// Type present in EventInput has to be present in EntitiesData enum bool isOptional = hasUDA!(Sys.EntitiesData.tupleof[indexInEntitiesData], "optional"); static if(isOptional) From be5de2ae9cd8e39ae8cbdf00de064bb087aaaa9a Mon Sep 17 00:00:00 2001 From: Mergul Date: Sat, 6 Apr 2019 14:47:33 +0000 Subject: [PATCH 040/217] -added second mmcommando commit -removed some stupid feature --- source/ecs/manager.d | 99 ++++++++++++++------------------------------ 1 file changed, 31 insertions(+), 68 deletions(-) diff --git a/source/ecs/manager.d b/source/ecs/manager.d index 92f4aaf..36acd5e 100644 --- a/source/ecs/manager.d +++ b/source/ecs/manager.d @@ -249,47 +249,13 @@ class EntityManager //dfmt off static if(hasMember!(Sys,"EventInput")) { - /*static string genEventCompList()() - { - string ret = "Sys.EventInput input;\n"; - string type; - //bool has = true; - foreach (member; __traits(allMembers, Sys.EventInput)) - { - if(mixin("fullyQualifiedName!(ConstOf!(PointerTarget!(typeof(Sys.EventInput."~member~")))) == \"const(ecs.entity.Entity)\"")) - { - ret ~= "input." ~ member ~ " = cast(Entity*) data.block.dataBegin() + data.id;\n"; - continue; - } + /* static void genEventCompList(Sys)(ref EventCallData data, EntityInfo* info, ref Sys.EventInput input) + {*/ + static void callEventHandler(Type)(ref EventCallData data){ + Sys.EventInput input; + Sys* dataSystem = cast(Sys*) data.system_pointer; + EntityInfo* info = data.block.type_info; - bool has = false; - bool optional = false; - foreach(member2; __traits(allMembers, Sys.EntitiesData)) - { - static if(mixin("isBasicType!(typeof(Sys.EntitiesData."~member2~"))")){} - else static if(mixin("fullyQualifiedName!(ConstOf!(PointerTarget!(typeof(Sys.EventInput."~member~")))) == fullyQualifiedName!(ConstOf!(ForeachType!(typeof(Sys.EntitiesData."~member2~"))))")) - { - has = true; - if(mixin("hasUDA!(Sys.EntitiesData."~member2~",\"optional\")"))optional = true; - break; - } - } - if(!has)assert(0); - - if(optional)ret ~= "input." ~ member ~ " = null;\n"; - else ret ~= "input." ~ member ~ " = cast(typeof(Sys.EventInput." ~ member - ~ "))(cast(void*) data.block + info.deltas[typeof(Sys.EventInput." - ~ member ~ ").component_id] + data.id * typeof(Sys.EventInput." ~ member - ~ ").sizeof);\n"; - } - return ret; - }*/ - - //pragma(msg,genEventCompList()); - //pragma(msg,genEventCompList()); - - static void genEventCompList(Sys)(ref EventCallData data, EntityInfo* info, ref Sys.EventInput input) - { alias EventFields=Fields!(Sys.EventInput); foreach (eventFieldNum, ref eventField; input.tupleof) { @@ -320,16 +286,34 @@ class EntityManager } } + dataSystem.handleEvent(input, *cast(Type*)data.event); } - static string checkHandler()(string member) + static void setEventCallers(Sys)(System system){ + enum allEventHandlers=__traits(getOverloads, Sys, "handleEvent").length; + system.m_event_callers = Mallocator.instance.makeArray!(System.EventCaller)(allEventHandlers); + + foreach(j, func; __traits(getOverloads, Sys, "handleEvent")) + { + alias EventParamType=Parameters!( __traits(getOverloads, Sys, "handleEvent")[j] )[1]; + system.m_event_callers[j].callback = cast(void*)&callEventHandler!(EventParamType); + system.m_event_callers[j].id = EventParamType.event_id; + } + } + + static if(__traits(hasMember, Sys, "handleEvent")) + { + setEventCallers!(Sys)(system); + } + + /*static string checkHandler()(string member) { string ret; ret ~= "(Parameters!(Sys."~member~")).length == 2 && "; ret ~= "((is(Parameters!(Sys."~member~")[0] == Sys.EventInput) && hasStaticMember!(Parameters!(Sys."~member~")[1],\"event_id\")) ||"; ret ~= " (is(Parameters!(Sys."~member~")[1] == Sys.EventInput) && hasStaticMember!(Parameters!(Sys."~member~")[0],\"event_id\")))"; return ret; - } + }*/ /*static struct Handler { @@ -337,7 +321,7 @@ class EntityManager void* callback; }*/ - static string catchEventHanlders()() + /*static string catchEventHanlders()() { int event_handlers = 0; string ret; @@ -369,36 +353,15 @@ class EntityManager ret ~= "system.m_event_callers["~event_handlers.to!string~"].id = "~event_param~".event_id;"; event_handlers++; } - - /*ret ~= "ushort max_id = 0;"; - ret ~= "foreach(handler;handlers) - { - if(handler.id > max_id)max_id = handler.id; - }"; - ret ~= "system.m_event_callback = Mallocator.instance.makeArray!(System.EventHandler)(max_id);"; - ret ~= "foreach(handler;handlers) - { - system.m_event_callback[handler.id] = handler.callback; - }";*/ } - - /*static if(__traits(hasMember, Sys, "handleEvent"))//foreach(member; __traits(allMembers,Sys)) - { - - //static foreach() - static if (member == "handleEvent" && mixin("isFunction!(Sys."~member~")")) - { - static if(mixin(checkHandler(member))) - { - event_handlers++; - } - } - }*/ + return ret; } //pragma(msg,catchEventHanlders()); - mixin(catchEventHanlders()); + mixin(catchEventHanlders());*/ + + } //dfmt on From e7d3d08febb9bd241b3e9888d12bf7fa4512b0f7 Mon Sep 17 00:00:00 2001 From: Mergul Date: Sat, 6 Apr 2019 15:02:07 +0000 Subject: [PATCH 041/217] -fixed mmcomando commit bug --- source/ecs/manager.d | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/ecs/manager.d b/source/ecs/manager.d index 36acd5e..56e887c 100644 --- a/source/ecs/manager.d +++ b/source/ecs/manager.d @@ -289,7 +289,7 @@ class EntityManager dataSystem.handleEvent(input, *cast(Type*)data.event); } - static void setEventCallers(Sys)(System system){ + static void setEventCallers(Sys)(ref System system){ enum allEventHandlers=__traits(getOverloads, Sys, "handleEvent").length; system.m_event_callers = Mallocator.instance.makeArray!(System.EventCaller)(allEventHandlers); From bf8fac84cf9697aa06f758ed504fa9988f5356a1 Mon Sep 17 00:00:00 2001 From: Mergul Date: Sat, 6 Apr 2019 15:03:29 +0000 Subject: [PATCH 042/217] -removed comments --- source/ecs/manager.d | 127 +++++++++++++------------------------------ 1 file changed, 37 insertions(+), 90 deletions(-) diff --git a/source/ecs/manager.d b/source/ecs/manager.d index 56e887c..eb49475 100644 --- a/source/ecs/manager.d +++ b/source/ecs/manager.d @@ -246,124 +246,71 @@ class EntityManager static assert(0, "System should gave \"EntitiesData\" struct for input components"); } - //dfmt off - static if(hasMember!(Sys,"EventInput")) + static if (hasMember!(Sys, "EventInput")) { - /* static void genEventCompList(Sys)(ref EventCallData data, EntityInfo* info, ref Sys.EventInput input) - {*/ - static void callEventHandler(Type)(ref EventCallData data){ - Sys.EventInput input; + static void callEventHandler(Type)(ref EventCallData data) + { + Sys.EventInput input; Sys* dataSystem = cast(Sys*) data.system_pointer; EntityInfo* info = data.block.type_info; - alias EventFields=Fields!(Sys.EventInput); + alias EventFields = Fields!(Sys.EventInput); foreach (eventFieldNum, ref eventField; input.tupleof) - { + { alias EventFieldType = Unqual!(typeof(*eventField)); - enum bool isEntity = is( EventFieldType == ecs.entity.Entity ); - - static if(isEntity) + enum bool isEntity = is(EventFieldType == ecs.entity.Entity); + + static if (isEntity) { - eventField=cast(Entity*) data.block.dataBegin() + data.id; + eventField = cast(Entity*) data.block.dataBegin() + data.id; continue; } else - { - enum long indexInEntitiesData=getIndexOfTypeInEntitiesData!(Sys.EntitiesData, EventFieldType); - static assert(indexInEntitiesData != -1, "Component present in EventInput has to be present in EntitiesData!");// Type present in EventInput has to be present in EntitiesData + { + enum long indexInEntitiesData = getIndexOfTypeInEntitiesData!(Sys.EntitiesData, + EventFieldType); + static assert(indexInEntitiesData != -1, + "Component present in EventInput has to be present in EntitiesData!"); // Type present in EventInput has to be present in EntitiesData - enum bool isOptional = hasUDA!(Sys.EntitiesData.tupleof[indexInEntitiesData], "optional"); - static if(isOptional) + enum bool isOptional = hasUDA!(Sys.EntitiesData.tupleof[indexInEntitiesData], + "optional"); + static if (isOptional) { - eventField=null; + eventField = null; } - else + else { - eventField = cast(EventFieldType*)(cast(void*) data.block - + info.deltas[EventFieldType.component_id] - + data.id * EventFieldType.sizeof); + eventField = cast(EventFieldType*)(cast(void*) data.block + + info.deltas[EventFieldType.component_id] + + data.id * EventFieldType.sizeof); } } - + } - dataSystem.handleEvent(input, *cast(Type*)data.event); + dataSystem.handleEvent(input, *cast(Type*) data.event); } - static void setEventCallers(Sys)(ref System system){ - enum allEventHandlers=__traits(getOverloads, Sys, "handleEvent").length; - system.m_event_callers = Mallocator.instance.makeArray!(System.EventCaller)(allEventHandlers); - - foreach(j, func; __traits(getOverloads, Sys, "handleEvent")) + static void setEventCallers(Sys)(ref System system) + { + enum allEventHandlers = __traits(getOverloads, Sys, "handleEvent").length; + system.m_event_callers = Mallocator.instance.makeArray!( + System.EventCaller)(allEventHandlers); + + foreach (j, func; __traits(getOverloads, Sys, "handleEvent")) { - alias EventParamType=Parameters!( __traits(getOverloads, Sys, "handleEvent")[j] )[1]; - system.m_event_callers[j].callback = cast(void*)&callEventHandler!(EventParamType); + alias EventParamType = Parameters!(__traits(getOverloads, + Sys, "handleEvent")[j])[1]; + system.m_event_callers[j].callback = cast( + void*)&callEventHandler!(EventParamType); system.m_event_callers[j].id = EventParamType.event_id; } } - static if(__traits(hasMember, Sys, "handleEvent")) + static if (__traits(hasMember, Sys, "handleEvent")) { setEventCallers!(Sys)(system); } - - /*static string checkHandler()(string member) - { - string ret; - ret ~= "(Parameters!(Sys."~member~")).length == 2 && "; - ret ~= "((is(Parameters!(Sys."~member~")[0] == Sys.EventInput) && hasStaticMember!(Parameters!(Sys."~member~")[1],\"event_id\")) ||"; - ret ~= " (is(Parameters!(Sys."~member~")[1] == Sys.EventInput) && hasStaticMember!(Parameters!(Sys."~member~")[0],\"event_id\")))"; - return ret; - }*/ - - /*static struct Handler - { - ushort id; - void* callback; - }*/ - - /*static string catchEventHanlders()() - { - int event_handlers = 0; - string ret; - string event_param; - - static if(__traits(hasMember, Sys, "handleEvent")) - { - foreach(func; __traits(getOverloads, Sys, "handleEvent")) - { - event_handlers++;//pragma(msg,"kupa"); - } - - //ret ~= "Handler[] handlers = (cast(Handler*)alloca("~event_handlers.to!string~" * (Handler).sizeof))[0 .. "~event_handlers.to!string~"];\n"; - ret ~= "system.m_event_callers = Mallocator.instance.makeArray!(System.EventCaller)("~event_handlers.to!string~");"; - event_handlers = 0; - - foreach(j,func; __traits(getOverloads, Sys, "handleEvent")) - { - event_param = "Parameters!(__traits(getOverloads, Sys, \"handleEvent\")["~j.to!string~"])[1]"; - ret ~= "static void callHandler"~event_handlers.to!string~"(ref EventCallData data)\n{\n"; - ret ~= "Sys* s = cast(Sys*) data.system_pointer; - EntityInfo* info = data.block.type_info;"; - //ret ~= genEventCompList(); - ret ~= "Sys.EventInput input;\n"; - ret ~= "genEventCompList!(Sys)(data, info, input);"; - ret ~= "s.handleEvent(input, *cast("~event_param~"*)data.event);"; - ret ~= "}\n"; - ret ~= "system.m_event_callers["~event_handlers.to!string~"].callback = cast(void*)&callHandler"~event_handlers.to!string~";"; - ret ~= "system.m_event_callers["~event_handlers.to!string~"].id = "~event_param~".event_id;"; - event_handlers++; - } - } - - return ret; - } - - //pragma(msg,catchEventHanlders()); - mixin(catchEventHanlders());*/ - - } - //dfmt on static string genCompList()() { From fd6e6c035516148065b1156d2fe51c6041958b41 Mon Sep 17 00:00:00 2001 From: Mergul Date: Sat, 6 Apr 2019 15:11:44 +0000 Subject: [PATCH 043/217] -changed naming style to match whole project --- source/ecs/manager.d | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/source/ecs/manager.d b/source/ecs/manager.d index eb49475..0d77132 100644 --- a/source/ecs/manager.d +++ b/source/ecs/manager.d @@ -251,50 +251,50 @@ class EntityManager static void callEventHandler(Type)(ref EventCallData data) { Sys.EventInput input; - Sys* dataSystem = cast(Sys*) data.system_pointer; + Sys* data_system = cast(Sys*) data.system_pointer; EntityInfo* info = data.block.type_info; alias EventFields = Fields!(Sys.EventInput); - foreach (eventFieldNum, ref eventField; input.tupleof) + foreach (ref event_field; input.tupleof) { - alias EventFieldType = Unqual!(typeof(*eventField)); - enum bool isEntity = is(EventFieldType == ecs.entity.Entity); + alias EventFieldType = Unqual!(typeof(*event_field)); + enum bool is_entity = is(EventFieldType == ecs.entity.Entity); - static if (isEntity) + static if (is_entity) { - eventField = cast(Entity*) data.block.dataBegin() + data.id; + event_field = cast(Entity*) data.block.dataBegin() + data.id; continue; } else { - enum long indexInEntitiesData = getIndexOfTypeInEntitiesData!(Sys.EntitiesData, + enum long index_in_entities_data = getIndexOfTypeInEntitiesData!(Sys.EntitiesData, EventFieldType); - static assert(indexInEntitiesData != -1, + static assert(index_in_entities_data != -1, "Component present in EventInput has to be present in EntitiesData!"); // Type present in EventInput has to be present in EntitiesData - enum bool isOptional = hasUDA!(Sys.EntitiesData.tupleof[indexInEntitiesData], + enum bool is_optional = hasUDA!(Sys.EntitiesData.tupleof[index_in_entities_data], "optional"); - static if (isOptional) + static if (is_optional) { - eventField = null; + event_field = null; } else { - eventField = cast(EventFieldType*)(cast(void*) data.block + event_field = cast(EventFieldType*)(cast(void*) data.block + info.deltas[EventFieldType.component_id] + data.id * EventFieldType.sizeof); } } } - dataSystem.handleEvent(input, *cast(Type*) data.event); + data_system.handleEvent(input, *cast(Type*) data.event); } static void setEventCallers(Sys)(ref System system) { - enum allEventHandlers = __traits(getOverloads, Sys, "handleEvent").length; + enum event_handlers_num = __traits(getOverloads, Sys, "handleEvent").length; system.m_event_callers = Mallocator.instance.makeArray!( - System.EventCaller)(allEventHandlers); + System.EventCaller)(event_handlers_num); foreach (j, func; __traits(getOverloads, Sys, "handleEvent")) { From f39d5ab403c3b32bf0784dd5010d16ddc2d52b2e Mon Sep 17 00:00:00 2001 From: Mergul Date: Sat, 6 Apr 2019 15:30:49 +0000 Subject: [PATCH 044/217] -removed next mixin genParamsChecking() --- source/ecs/manager.d | 29 +++++++++++++++-------------- tests/tests.d | 2 +- 2 files changed, 16 insertions(+), 15 deletions(-) diff --git a/source/ecs/manager.d b/source/ecs/manager.d index 0d77132..2a34d27 100644 --- a/source/ecs/manager.d +++ b/source/ecs/manager.d @@ -514,19 +514,6 @@ class EntityManager return ret; } - string genParamsChecking()() - { - string ret; - foreach (func; __traits(getOverloads, Sys, "onUpdate")) - { - if ((Parameters!(func)).length == 1) - ret ~= "\"" ~ (fullyQualifiedName!(Sys.EntitiesData)) ~ "\" == \"" ~ ( - fullyQualifiedName!((Parameters!(func))[0])) ~ "\" || "; - } - ret ~= "false"; - return ret; - } - static string genFillInputData()() { string ret; @@ -596,8 +583,22 @@ class EntityManager { mixin(genFillInputData()); } + + bool checkOnUpdateParams()() + { + bool ret = false; + foreach (func; __traits(getOverloads, Sys, "onUpdate")) + { + if ((Parameters!(func)).length == 1 && is(Parameters!(func)[0] == Sys.EntitiesData)) + { + ret = true; + break; + } + } + return ret; + } - static if (hasMember!(Sys, "onUpdate") && (mixin(genParamsChecking()))) + static if (hasMember!(Sys, "onUpdate") && checkOnUpdateParams()) { static void callUpdate(ref CallData data) { diff --git a/tests/tests.d b/tests/tests.d index 50c31b6..60fed07 100644 --- a/tests/tests.d +++ b/tests/tests.d @@ -329,7 +329,7 @@ struct Sys3 void onUpdate(EntitiesData data) { - + } } From eaf2d1581cde31441a1c77f662245e5fc32bd6e6 Mon Sep 17 00:00:00 2001 From: Mergul Date: Sat, 6 Apr 2019 16:28:59 +0000 Subject: [PATCH 045/217] -removed next two mixins: *catchFunc *catchEntityFunc --- source/ecs/manager.d | 91 ++++++++++++++++++++------------------------ tests/tests.d | 7 +++- 2 files changed, 48 insertions(+), 50 deletions(-) diff --git a/source/ecs/manager.d b/source/ecs/manager.d index 2a34d27..5719f6e 100644 --- a/source/ecs/manager.d +++ b/source/ecs/manager.d @@ -637,8 +637,7 @@ class EntityManager assert(entities_count <= block.entities_count && offset <= block.entities_count); fillInputData(input_data, info, block, offset, entities_count, system); - //mixin(genFillInputData()); - + s.onUpdate(input_data); block = block.next_block; @@ -650,66 +649,60 @@ class EntityManager system.m_update = &callUpdate; } - static string catchFunc(RetType = void)(string member, string func) + static void catchFunction(string func_name, RetType = void)(void** member) { - //dfmt off - static if(is(RetType == void))string ret_str = ""; - else string ret_str = "return "; - string ret = "static if (hasMember!(Sys, \"" ~ func ~ "\") && - Parameters!(Sys."~func~").length == 0 && - is(ReturnType!(Sys."~func~") == "~RetType.stringof~")) + static if(hasMember!(Sys,func_name)) { - static "~RetType.stringof~" call" ~ func - ~ "(void* system_pointer) + foreach (func; __traits(getOverloads, Sys, func_name)) { - Sys* s = cast(Sys*) system_pointer; - "~ret_str~"s." ~ func ~ "(); + static if ((Parameters!(func)).length == 0 && is(ReturnType!(func) == RetType)) + { + static RetType callFunc(void* system_pointer) + { + Sys* s = cast(Sys*) system_pointer; + static if(is(RetTyp == void))mixin("s."~func_name~"()"); + else return mixin("s."~func_name~"()"); + } + *member = cast(void*)&callFunc; + break; + } } - - system." - ~ member ~ " = &call" ~ func ~ "; - }"; - return ret; - //dfmt on + } } - static string catchEntityFunc(RetType = void)(string member, string func) + static void catchEntityFunction(string func_name, RetType = void)(void** member) { - //dfmt off - - static if(is(RetType == void))string ret_str = ""; - else string ret_str = "return "; - string ret = "static if (hasMember!(Sys, \"" ~ func ~ "\") && - Parameters!(Sys."~func~").length == 1 && - is(Parameters!(Sys."~func~")[0] == Sys.EntitiesData) && - is(ReturnType!(Sys."~func~") == "~RetType.stringof~")) + static if(hasMember!(Sys,func_name)) { - static "~RetType.stringof~" call" ~ func - ~ "(ref ListenerCallData data) + foreach (func; __traits(getOverloads, Sys, func_name)) { - Sys* s = cast(Sys*) data.system.m_system_pointer; - Sys.EntitiesData input_data; - fillInputData(input_data, data.block.type_info, data.block, data.begin, data.end, data.system); - "~ret_str~"s." ~ func ~ "(input_data); + static if ((Parameters!(func)).length == 1 && is(Parameters!(func)[0] == Sys.EntitiesData) && is(ReturnType!(func) == RetType)) + { + static RetType callFunc(ref ListenerCallData data) + { + Sys* s = cast(Sys*) data.system.m_system_pointer; + Sys.EntitiesData input_data; + fillInputData(input_data, data.block.type_info, data.block, data.begin, data.end, data.system); + static if(is(RetTyp == void))mixin("s."~func_name~"(input_data)"); + else return mixin("s."~func_name~"(input_data)"); + } + *member = cast(void*)&callFunc; + break; + } } - - system." - ~ member ~ " = &call" ~ func ~ "; - }"; - return ret; - //dfmt on + } } - mixin(catchFunc("m_enable", "onEnable")); - mixin(catchFunc("m_disable", "onDisable")); - mixin(catchFunc("m_create", "onCreate")); - mixin(catchFunc("m_destroy", "onDestroy")); - mixin(catchFunc!(bool)("m_begin", "onBegin")); - mixin(catchFunc("m_end", "onEnd")); + catchFunction!("onEnable")(&system.m_enable); + catchFunction!("onDisable")(&system.m_disable); + catchFunction!("onCreate")(&system.m_create); + catchFunction!("onDestroy")(&system.m_destroy); + catchFunction!("onBegin",bool)(&system.m_begin); + catchFunction!("onEnd")(&system.m_end); - mixin(catchEntityFunc("m_add_entity", "onAddEntity")); - mixin(catchEntityFunc("m_remove_entity", "onRemoveEntity")); - mixin(catchEntityFunc("m_change_entity", "onChangeEntity")); + catchEntityFunction!("onAddEntity")(&system.m_add_entity); + catchEntityFunction!("onRemoveEntity")(&system.m_remove_entity); + catchEntityFunction!("onChangeEntity")(&system.m_change_entity); system.m_system_pointer = cast(void*) Mallocator.instance.make!Sys; system.m_priority = priority; diff --git a/tests/tests.d b/tests/tests.d index 60fed07..bf6fd53 100644 --- a/tests/tests.d +++ b/tests/tests.d @@ -124,6 +124,11 @@ struct ChangeTestSystem writeln("On Change Test System create."); } + void onCreate(int i) + { + writeln("On Change Test System create."); + } + void onDestroy() { writeln("On Change Test System destroy."); @@ -329,7 +334,7 @@ struct Sys3 void onUpdate(EntitiesData data) { - + } } From 71c7df2ab3ce72461e99d58212b7c3b03e75c52b Mon Sep 17 00:00:00 2001 From: Mergul Date: Sat, 6 Apr 2019 17:51:42 +0000 Subject: [PATCH 046/217] -added third mmcomando commit --- source/ecs/manager.d | 194 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 192 insertions(+), 2 deletions(-) diff --git a/source/ecs/manager.d b/source/ecs/manager.d index 5719f6e..496b6ef 100644 --- a/source/ecs/manager.d +++ b/source/ecs/manager.d @@ -312,7 +312,7 @@ class EntityManager } } - static string genCompList()() + /*static string genCompList()() { static foreach (member; __traits(allMembers, Sys.EntitiesData)) @@ -512,6 +512,195 @@ class EntityManager } } return ret; + }*/ + + static struct ComponentsIndices + { + string[] readonly; + string[] excluded; + string[] optional; + string[] mutable; + string[] req; + + } + + static void allocateSystemComponents(ComponentsIndices componentsInfo)(ref System system) + { + size_t req = componentsInfo.req.length; + size_t opt = componentsInfo.optional.length; + size_t excluded = componentsInfo.excluded.length; + size_t read_only = componentsInfo.readonly.length; + size_t modified = componentsInfo.mutable.length; + + if (req > 0) + system.m_components = Mallocator.instance.makeArray!ushort(req); + if (opt > 0) + system.m_optional_components = Mallocator.instance.makeArray!ushort(opt); + if (excluded > 0) + system.m_excluded_components = Mallocator.instance.makeArray!ushort(excluded); + if (read_only > 0) + system.m_read_only_components = Mallocator.instance.makeArray!ushort(read_only); + if (modified > 0) + system.m_modified_components = Mallocator.instance.makeArray!ushort(modified); + + } + + bool checkExcludedComponentsSomething(Sys)() + { + return __traits(compiles, allSameType!(string, typeof(Sys.ExcludedComponents))) && allSameType!(string, + typeof(Sys.ExcludedComponents)) && isExpressions!(Sys.ExcludedComponents); + } + + static ComponentsIndices getComponentsInfo() + { + ComponentsIndices componentsInfo; + + foreach (member; __traits(allMembers, Sys.EntitiesData)) + { + alias MemberType = typeof(__traits(getMember, Sys.EntitiesData, member)); + if (member == "length" || is(MemberType == Entity[]) || is(MemberType == const(Entity)[])) + { + continue; + } + string name; + static if (isArray!MemberType) + { // Workaround. This code is never called with: not an array type, but compiler prints an error + name = Unqual!(ForeachType!MemberType).stringof; + } + + bool isOptional; + bool isExcluded; + bool isReadOnly; + + // isMutable!( ForeachType!(MemberType) ); + if (is(CopyConstness!(ForeachType!(MemberType), int) == const(int))) + { + isReadOnly = true; + } + + foreach (att; __traits(getAttributes, __traits(getMember, Sys.EntitiesData, member))) + { + if (att == "optional") + { + isOptional = true; + } + else if (att == "excluded") + { + isExcluded = true; + } + if (att == "readonly") + { + isReadOnly = true; + } + } + if (isReadOnly) + { + componentsInfo.readonly ~= name; + } + else + { + componentsInfo.mutable ~= name; + } + if (isExcluded) + { + componentsInfo.excluded ~= name; + } + if (isOptional) + { + componentsInfo.optional ~= name; + } + if (isReadOnly) + { + componentsInfo.readonly ~= name; + } + if (isExcluded == false && isOptional == false) + { //is Req + componentsInfo.req ~= name; + } + + assert(!(isOptional && isExcluded), + "EntitiesData member can't have both \"@optional\" and \"@excluded\"."); + + } + + static if (__traits(hasMember, Sys, "ExcludedComponents")) + { + static if (is(Sys.ExcludedComponents == enum)) + { + foreach (str; Fields!(Sys.ExcludedComponents)) + { + ComponentInfo info; + info.isExcluded = true; + info.name = str.stringof; + } + } + else static if (checkExcludedComponentsSomething!Sys) + { + foreach (str; Sys.ExcludedComponents) + { + ComponentInfo info; + info.isExcluded = true; + info.name = str; + + } + + } + } + return componentsInfo; + } + + static void genCompList()(ref System system, ref HashMap!(const(char)[], ushort) components_map) + { + + foreach (member; __traits(allMembers, Sys.EntitiesData)) + { + alias MemberType=typeof(__traits(getMember, Sys.EntitiesData, member)); + + static if (isFunction!(__traits(getMember, Sys.EntitiesData, member))) + static assert(0, "EntitiesData can't have any function!"); + else static if (member == "length") + { + static assert(isIntegral!(MemberType), "EntitiesData 'length' member must be integral type."); + static assert(MemberType.sizeof > 1, "EntitiesData 'length' member can't be byte or ubyte."); + } + else static if (!(isArray!(MemberType))) + static assert(0, "EntitiesData members should be arrays of elements!"); + } + + enum ComponentsIndices componentsInfo = getComponentsInfo(); + allocateSystemComponents!(componentsInfo)(system); + + foreach (iii, name; componentsInfo.req) + { + ushort comp = components_map.get(cast(char[]) name, ushort.max); + assert(comp != ushort.max, "Can not register system: component not present"); + system.m_components[iii] = comp; + } + foreach (iii, name; componentsInfo.excluded) + { + ushort comp = components_map.get(cast(char[]) name, ushort.max); + assert(comp != ushort.max, "Can not register system: component not present"); + system.m_excluded_components[iii] = comp; + } + foreach (iii, name; componentsInfo.optional) + { + ushort comp = components_map.get(cast(char[]) name, ushort.max); + assert(comp != ushort.max, "Can not register system: component not present"); + system.m_optional_components[iii] = comp; + } + foreach (iii, name; componentsInfo.readonly) + { + ushort comp = components_map.get(cast(char[]) name, ushort.max); + assert(comp != ushort.max, "Can not register system: component not present"); + system.m_read_only_components[iii] = comp; + } + foreach (iii, name; componentsInfo.mutable) + { + ushort comp = components_map.get(cast(char[]) name, ushort.max); + assert(comp != ushort.max, "Can not register system: component not present"); + system.m_modified_components[iii] = comp; + } + } static string genFillInputData()() @@ -709,7 +898,8 @@ class EntityManager (cast(Sys*) system.m_system_pointer).__ecsInitialize(); system.jobs = (cast(Sys*) system.m_system_pointer)._ecs_jobs; - mixin(genCompList()); + //mixin(genCompList()); + genCompList(system, components_map); ushort sys_id = systems_map.get(Sys.stringof, ushort.max); if (sys_id < systems.length) From b0760228b12c3350b1957b0318b297cec6865e09 Mon Sep 17 00:00:00 2001 From: Mergul Date: Sat, 6 Apr 2019 18:03:14 +0000 Subject: [PATCH 047/217] -changed assertion infos --- source/ecs/manager.d | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/source/ecs/manager.d b/source/ecs/manager.d index 496b6ef..6aa36ee 100644 --- a/source/ecs/manager.d +++ b/source/ecs/manager.d @@ -673,31 +673,31 @@ class EntityManager foreach (iii, name; componentsInfo.req) { ushort comp = components_map.get(cast(char[]) name, ushort.max); - assert(comp != ushort.max, "Can not register system: component not present"); + assert(comp != ushort.max, "Can't register system \""~Sys.stringof~"\" due to non existing component \""~name~"\"."); system.m_components[iii] = comp; } foreach (iii, name; componentsInfo.excluded) { ushort comp = components_map.get(cast(char[]) name, ushort.max); - assert(comp != ushort.max, "Can not register system: component not present"); + assert(comp != ushort.max, "Can't register system \""~Sys.stringof~"\" due to non existing component \""~name~"\"."); system.m_excluded_components[iii] = comp; } foreach (iii, name; componentsInfo.optional) { ushort comp = components_map.get(cast(char[]) name, ushort.max); - assert(comp != ushort.max, "Can not register system: component not present"); + assert(comp != ushort.max, "Can't register system \""~Sys.stringof~"\" due to non existing component \""~name~"\"."); system.m_optional_components[iii] = comp; } foreach (iii, name; componentsInfo.readonly) { ushort comp = components_map.get(cast(char[]) name, ushort.max); - assert(comp != ushort.max, "Can not register system: component not present"); + assert(comp != ushort.max, "Can't register system \""~Sys.stringof~"\" due to non existing component \""~name~"\"."); system.m_read_only_components[iii] = comp; } foreach (iii, name; componentsInfo.mutable) { ushort comp = components_map.get(cast(char[]) name, ushort.max); - assert(comp != ushort.max, "Can not register system: component not present"); + assert(comp != ushort.max, "Can't register system \""~Sys.stringof~"\" due to non existing component \""~name~"\"."); system.m_modified_components[iii] = comp; } From 63d58392256758bbaab83d2a13b82db509bf78de Mon Sep 17 00:00:00 2001 From: Mergul Date: Sat, 6 Apr 2019 18:07:08 +0000 Subject: [PATCH 048/217] -changed naming style to match whole project --- source/ecs/manager.d | 72 ++++++++++++++++++++++---------------------- 1 file changed, 36 insertions(+), 36 deletions(-) diff --git a/source/ecs/manager.d b/source/ecs/manager.d index 6aa36ee..76a3684 100644 --- a/source/ecs/manager.d +++ b/source/ecs/manager.d @@ -524,13 +524,13 @@ class EntityManager } - static void allocateSystemComponents(ComponentsIndices componentsInfo)(ref System system) + static void allocateSystemComponents(ComponentsIndices components_info)(ref System system) { - size_t req = componentsInfo.req.length; - size_t opt = componentsInfo.optional.length; - size_t excluded = componentsInfo.excluded.length; - size_t read_only = componentsInfo.readonly.length; - size_t modified = componentsInfo.mutable.length; + size_t req = components_info.req.length; + size_t opt = components_info.optional.length; + size_t excluded = components_info.excluded.length; + size_t read_only = components_info.readonly.length; + size_t modified = components_info.mutable.length; if (req > 0) system.m_components = Mallocator.instance.makeArray!ushort(req); @@ -553,7 +553,7 @@ class EntityManager static ComponentsIndices getComponentsInfo() { - ComponentsIndices componentsInfo; + ComponentsIndices components_info; foreach (member; __traits(allMembers, Sys.EntitiesData)) { @@ -568,57 +568,57 @@ class EntityManager name = Unqual!(ForeachType!MemberType).stringof; } - bool isOptional; - bool isExcluded; - bool isReadOnly; + bool is_optional; + bool is_excluded; + bool is_read_only; // isMutable!( ForeachType!(MemberType) ); if (is(CopyConstness!(ForeachType!(MemberType), int) == const(int))) { - isReadOnly = true; + is_read_only = true; } foreach (att; __traits(getAttributes, __traits(getMember, Sys.EntitiesData, member))) { if (att == "optional") { - isOptional = true; + is_optional = true; } else if (att == "excluded") { - isExcluded = true; + is_excluded = true; } if (att == "readonly") { - isReadOnly = true; + is_read_only = true; } } - if (isReadOnly) + if (is_read_only) { - componentsInfo.readonly ~= name; + components_info.readonly ~= name; } else { - componentsInfo.mutable ~= name; + components_info.mutable ~= name; } - if (isExcluded) + if (is_excluded) { - componentsInfo.excluded ~= name; + components_info.excluded ~= name; } - if (isOptional) + if (is_optional) { - componentsInfo.optional ~= name; + components_info.optional ~= name; } - if (isReadOnly) + if (is_read_only) { - componentsInfo.readonly ~= name; + components_info.readonly ~= name; } - if (isExcluded == false && isOptional == false) + if (is_excluded == false && is_optional == false) { //is Req - componentsInfo.req ~= name; + components_info.req ~= name; } - assert(!(isOptional && isExcluded), + assert(!(is_optional && is_excluded), "EntitiesData member can't have both \"@optional\" and \"@excluded\"."); } @@ -630,7 +630,7 @@ class EntityManager foreach (str; Fields!(Sys.ExcludedComponents)) { ComponentInfo info; - info.isExcluded = true; + info.is_excluded = true; info.name = str.stringof; } } @@ -639,14 +639,14 @@ class EntityManager foreach (str; Sys.ExcludedComponents) { ComponentInfo info; - info.isExcluded = true; + info.is_excluded = true; info.name = str; } } } - return componentsInfo; + return components_info; } static void genCompList()(ref System system, ref HashMap!(const(char)[], ushort) components_map) @@ -667,34 +667,34 @@ class EntityManager static assert(0, "EntitiesData members should be arrays of elements!"); } - enum ComponentsIndices componentsInfo = getComponentsInfo(); - allocateSystemComponents!(componentsInfo)(system); + enum ComponentsIndices components_info = getComponentsInfo(); + allocateSystemComponents!(components_info)(system); - foreach (iii, name; componentsInfo.req) + foreach (iii, name; components_info.req) { ushort comp = components_map.get(cast(char[]) name, ushort.max); assert(comp != ushort.max, "Can't register system \""~Sys.stringof~"\" due to non existing component \""~name~"\"."); system.m_components[iii] = comp; } - foreach (iii, name; componentsInfo.excluded) + foreach (iii, name; components_info.excluded) { ushort comp = components_map.get(cast(char[]) name, ushort.max); assert(comp != ushort.max, "Can't register system \""~Sys.stringof~"\" due to non existing component \""~name~"\"."); system.m_excluded_components[iii] = comp; } - foreach (iii, name; componentsInfo.optional) + foreach (iii, name; components_info.optional) { ushort comp = components_map.get(cast(char[]) name, ushort.max); assert(comp != ushort.max, "Can't register system \""~Sys.stringof~"\" due to non existing component \""~name~"\"."); system.m_optional_components[iii] = comp; } - foreach (iii, name; componentsInfo.readonly) + foreach (iii, name; components_info.readonly) { ushort comp = components_map.get(cast(char[]) name, ushort.max); assert(comp != ushort.max, "Can't register system \""~Sys.stringof~"\" due to non existing component \""~name~"\"."); system.m_read_only_components[iii] = comp; } - foreach (iii, name; componentsInfo.mutable) + foreach (iii, name; components_info.mutable) { ushort comp = components_map.get(cast(char[]) name, ushort.max); assert(comp != ushort.max, "Can't register system \""~Sys.stringof~"\" due to non existing component \""~name~"\"."); From a93529dad1eeb4f7c32b242fd698902b6d68deac Mon Sep 17 00:00:00 2001 From: Mergul Date: Sat, 6 Apr 2019 18:09:25 +0000 Subject: [PATCH 049/217] -removed commented code --- source/ecs/manager.d | 203 ------------------------------------------- 1 file changed, 203 deletions(-) diff --git a/source/ecs/manager.d b/source/ecs/manager.d index 76a3684..49f4c2a 100644 --- a/source/ecs/manager.d +++ b/source/ecs/manager.d @@ -312,208 +312,6 @@ class EntityManager } } - /*static string genCompList()() - { - - static foreach (member; __traits(allMembers, Sys.EntitiesData)) - { - static if (isFunction!(__traits(getMember, Sys.EntitiesData, member))) - static assert(0, "EntitiesData can't have any function!"); - else static if (member == "length") - { - static assert(isIntegral!(typeof(__traits(getMember, Sys.EntitiesData, - member))), "EntitiesData 'length' member must be integral type."); - static assert(typeof(__traits(getMember, Sys.EntitiesData, member)) - .sizeof > 1, "EntitiesData 'length' member can't be byte or ubyte."); - } - else static if (!(isArray!(typeof(__traits(getMember, - Sys.EntitiesData, member))))) - static assert(0, "EntitiesData members should be arrays of elements!"); - } - - string ret; - - uint req; - uint opt; - uint excluded; - uint read_only; - uint modified; - foreach (member; __traits(allMembers, Sys.EntitiesData)) - { - if (member == "length" || is(typeof(__traits(getMember, - Sys.EntitiesData, member)) == Entity[]) || is(typeof(__traits(getMember, - Sys.EntitiesData, member)) == const(Entity)[])) - { - - } - else - { - { - bool has_att = false; - bool is_read_only = false; - int attribs = 0; - if (is(CopyConstness!(ForeachType!(typeof(mixin("Sys.EntitiesData." ~ member))), - int) == const(int))) - { - is_read_only = true; - } - foreach (att; __traits(getAttributes, - __traits(getMember, Sys.EntitiesData, member))) - { - if (att == "optional") - { - opt++; - attribs++; - //break; - } - else if (att == "excluded") - { - excluded++; - attribs++; - //break; - } - if (att == "readonly") - { - is_read_only = true; - } - } - assert(attribs <= 1, - "EntitiesData member can't have both \"@optional\" and \"@excluded\"."); - if (!attribs) - req++; - if (is_read_only) - read_only++; - else - modified++; - } - } - } - - static if (__traits(hasMember, Sys, "ExcludedComponents")) - { - static if (is(Sys.ExcludedComponents == enum)) - { - excluded += (Fields!(Sys.ExcludedComponents)).length; //static assert(0,"Enum ExcludedComponents are not implemented yet."); - } - else static if (__traits(compiles, allSameType!(string, typeof(Sys.ExcludedComponents))) - && allSameType!(string, typeof(Sys.ExcludedComponents)) - && isExpressions!(Sys.ExcludedComponents)) - { - excluded += Sys.ExcludedComponents.length; - } - } - - if (req > 0) - ret ~= "system.m_components = Mallocator.instance.makeArray!ushort(" - ~ req.to!string ~ ");"; - if (opt > 0) - ret ~= "system.m_optional_components = Mallocator.instance.makeArray!ushort(" - ~ opt.to!string ~ ");"; - if (excluded > 0) - ret ~= "system.m_excluded_components = Mallocator.instance.makeArray!ushort(" - ~ excluded.to!string ~ ");"; - if (read_only > 0) - ret ~= "system.m_read_only_components = Mallocator.instance.makeArray!ushort(" - ~ read_only.to!string ~ ");"; - if (modified > 0) - ret ~= "system.m_modified_components = Mallocator.instance.makeArray!ushort(" - ~ modified.to!string ~ ");"; - ret ~= "ushort comp;"; //uint opt = 0;uint req = 0;uint excluded = 0;"; - - opt = 0; - req = 0; - excluded = 0; - read_only = 0; - modified = 0; - - static if (__traits(hasMember, Sys, "ExcludedComponents")) - { - static if (is(Sys.ExcludedComponents == enum)) - { - //static assert(0,"Enum ExcludedComponents are not implemented yet."); - foreach (str; Fields!(Sys.ExcludedComponents)) - ret ~= "system.m_excluded_components[" ~ (excluded++) - .to!string ~ "] = components_map.get(\"" - ~ str.stringof ~ "\", ushort.max);"; - } - else static if (__traits(compiles, allSameType!(string, typeof(Sys.ExcludedComponents))) - && allSameType!(string, typeof(Sys.ExcludedComponents)) - && isExpressions!(Sys.ExcludedComponents)) - { - foreach (str; Sys.ExcludedComponents) - ret ~= "system.m_excluded_components[" ~ (excluded++) - .to!string ~ "] = components_map.get(\"" ~ str ~ "\", ushort.max);"; - } - } - - foreach (member; __traits(allMembers, Sys.EntitiesData)) - { - if (member == "length" || is(typeof(__traits(getMember, - Sys.EntitiesData, member)) == Entity[]) || is(typeof(__traits(getMember, - Sys.EntitiesData, member)) == const(Entity)[])) - { - - } - else - { - { - ret ~= "{comp = components_map.get(Unqual!(ForeachType!(typeof( - Sys.EntitiesData." ~ member ~ "))) - .stringof, ushort.max);\n - if(comp == ushort.max)assert(0,\"Can't register system \\\"" - ~ Sys.stringof - ~ "\\\" due to non existing component \" ~ ForeachType!(typeof( - Sys.EntitiesData." - ~ member ~ ")) - .stringof - ~ \".\");"; - - bool is_read_only = false; - bool has_att = false; - if (is(CopyConstness!(ForeachType!(typeof(mixin("Sys.EntitiesData." ~ member))), - int) == const(int))) - { - is_read_only = true; - } - foreach (att; __traits(getAttributes, - __traits(getMember, Sys.EntitiesData, member))) - { - if (att == "optional") - { - ret ~= "system.m_optional_components[" ~ (opt++) - .to!string ~ "] = comp;"; - has_att = true; - //break; - } - else if (att == "excluded") - { - ret ~= "system.m_excluded_components[" ~ (excluded++) - .to!string ~ "] = comp;"; - has_att = true; - //break; - } - if (att == "readonly") - { - is_read_only = true; - } - } - if (!has_att) - { - ret ~= "system.m_components[" ~ (req++).to!string ~ "] = comp;"; - } - if (is_read_only) - ret ~= "system.m_read_only_components[" ~ (read_only++) - .to!string ~ "] = comp;"; - else - ret ~= "system.m_modified_components[" ~ (modified++) - .to!string ~ "] = comp;"; - ret ~= "}"; - } - } - } - return ret; - }*/ - static struct ComponentsIndices { string[] readonly; @@ -572,7 +370,6 @@ class EntityManager bool is_excluded; bool is_read_only; - // isMutable!( ForeachType!(MemberType) ); if (is(CopyConstness!(ForeachType!(MemberType), int) == const(int))) { is_read_only = true; From a5eade669ecdc2a00b86a0b98eb77d3b45dbb215 Mon Sep 17 00:00:00 2001 From: Mergul Date: Sat, 6 Apr 2019 18:41:48 +0000 Subject: [PATCH 050/217] -removed mixin genFillInputData --- source/ecs/manager.d | 160 ++++++++++++++++++------------------------- 1 file changed, 68 insertions(+), 92 deletions(-) diff --git a/source/ecs/manager.d b/source/ecs/manager.d index 49f4c2a..133b964 100644 --- a/source/ecs/manager.d +++ b/source/ecs/manager.d @@ -312,14 +312,19 @@ class EntityManager } } + static struct CompInfo + { + string name; + string type; + } + static struct ComponentsIndices { - string[] readonly; - string[] excluded; - string[] optional; - string[] mutable; - string[] req; - + CompInfo[] readonly; + CompInfo[] excluded; + CompInfo[] optional; + CompInfo[] mutable; + CompInfo[] req; } static void allocateSystemComponents(ComponentsIndices components_info)(ref System system) @@ -392,27 +397,27 @@ class EntityManager } if (is_read_only) { - components_info.readonly ~= name; + components_info.readonly ~= CompInfo(member,name); } else { - components_info.mutable ~= name; + components_info.mutable ~= CompInfo(member,name); } if (is_excluded) { - components_info.excluded ~= name; + components_info.excluded ~= CompInfo(member,name); } if (is_optional) { - components_info.optional ~= name; + components_info.optional ~= CompInfo(member,name); } if (is_read_only) { - components_info.readonly ~= name; + components_info.readonly ~= CompInfo(member,name); } if (is_excluded == false && is_optional == false) { //is Req - components_info.req ~= name; + components_info.req ~= CompInfo(member,name); } assert(!(is_optional && is_excluded), @@ -467,107 +472,78 @@ class EntityManager enum ComponentsIndices components_info = getComponentsInfo(); allocateSystemComponents!(components_info)(system); - foreach (iii, name; components_info.req) + foreach (iii, comp_info; components_info.req) { - ushort comp = components_map.get(cast(char[]) name, ushort.max); - assert(comp != ushort.max, "Can't register system \""~Sys.stringof~"\" due to non existing component \""~name~"\"."); + ushort comp = components_map.get(cast(char[]) comp_info.type, ushort.max); + assert(comp != ushort.max, "Can't register system \""~Sys.stringof~"\" due to non existing component \""~comp_info.type~"\"."); system.m_components[iii] = comp; } - foreach (iii, name; components_info.excluded) + foreach (iii, comp_info; components_info.excluded) { - ushort comp = components_map.get(cast(char[]) name, ushort.max); - assert(comp != ushort.max, "Can't register system \""~Sys.stringof~"\" due to non existing component \""~name~"\"."); + ushort comp = components_map.get(cast(char[]) comp_info.type, ushort.max); + assert(comp != ushort.max, "Can't register system \""~Sys.stringof~"\" due to non existing component \""~comp_info.type~"\"."); system.m_excluded_components[iii] = comp; } - foreach (iii, name; components_info.optional) + foreach (iii, comp_info; components_info.optional) { - ushort comp = components_map.get(cast(char[]) name, ushort.max); - assert(comp != ushort.max, "Can't register system \""~Sys.stringof~"\" due to non existing component \""~name~"\"."); + ushort comp = components_map.get(cast(char[]) comp_info.type, ushort.max); + assert(comp != ushort.max, "Can't register system \""~Sys.stringof~"\" due to non existing component \""~comp_info.type~"\"."); system.m_optional_components[iii] = comp; } - foreach (iii, name; components_info.readonly) + foreach (iii, comp_info; components_info.readonly) { - ushort comp = components_map.get(cast(char[]) name, ushort.max); - assert(comp != ushort.max, "Can't register system \""~Sys.stringof~"\" due to non existing component \""~name~"\"."); + ushort comp = components_map.get(cast(char[]) comp_info.type, ushort.max); + assert(comp != ushort.max, "Can't register system \""~Sys.stringof~"\" due to non existing component \""~comp_info.type~"\"."); system.m_read_only_components[iii] = comp; } - foreach (iii, name; components_info.mutable) + foreach (iii, comp_info; components_info.mutable) { - ushort comp = components_map.get(cast(char[]) name, ushort.max); - assert(comp != ushort.max, "Can't register system \""~Sys.stringof~"\" due to non existing component \""~name~"\"."); + ushort comp = components_map.get(cast(char[]) comp_info.type, ushort.max); + assert(comp != ushort.max, "Can't register system \""~Sys.stringof~"\" due to non existing component \""~comp_info.type~"\"."); system.m_modified_components[iii] = comp; } } - static string genFillInputData()() - { - string ret; - ushort comp; - uint req = 0; - uint opt = 0; - uint excluded = 0; - foreach (member; __traits(allMembers, Sys.EntitiesData)) - { - if (is(typeof(__traits(getMember, Sys.EntitiesData, - member)) == Entity[]) || is(typeof(__traits(getMember, - Sys.EntitiesData, member)) == const(Entity)[])) - { - ret ~= "input_data." ~ member - ~ " = (cast(Entity*) block.dataBegin())[offset .. entities_count];"; - } - else if (member == "length") - { - ret ~= "input_data." ~ member - ~ " = cast(typeof(input_data.length))(entities_count - offset);"; - } - else - { - { - bool has_att = false; - foreach (att; __traits(getAttributes, - __traits(getMember, Sys.EntitiesData, member))) - { - if (att == "optional") - { - ret ~= "if(system.m_optional_components[" ~ opt.to!string - ~ "] < info.deltas.length && info.deltas[ system.m_optional_components[" - ~ opt.to!string ~ "]] != 0)input_data." ~ member - ~ " = (cast(ForeachType!(typeof(Sys.EntitiesData." ~ member - ~ "))*)(cast(void*) block + info.deltas[ system.m_optional_components[" - ~ opt.to!string ~ "]]))[offset .. entities_count]; - else input_data." - ~ member ~ " = null;"; - opt++; - has_att = true; - break; - } - else if (att == "excluded") - { - excluded++; - has_att = true; - break; - } - } - if (!has_att) - { - ret ~= "input_data." ~ member ~ " = (cast(ForeachType!(typeof(Sys.EntitiesData." ~ member - ~ "))*)(cast(void*) block + info.deltas[ system.m_components[" - ~ req.to!string ~ "]]))[offset .. entities_count];"; - req++; - } - } - } - } - return ret; - } - - //pragma(msg,genFillInputData); - static void fillInputData(ref Sys.EntitiesData input_data, EntityInfo* info, EntitiesBlock* block, uint offset, uint entities_count, System* system) { - mixin(genFillInputData()); + enum ComponentsIndices components_info = getComponentsInfo(); + static foreach (member; __traits(allMembers, Sys.EntitiesData)) + { + static if (is(typeof(__traits(getMember, Sys.EntitiesData, + member)) == Entity[]) || is(typeof(__traits(getMember, + Sys.EntitiesData, member)) == const(Entity)[])) + { + __traits(getMember, input_data, member) = (cast(Entity*) block.dataBegin())[offset .. entities_count]; + } + else static if (member == "length") + { + __traits(getMember, input_data, member) = cast(typeof(input_data.length))(entities_count - offset); + } + else + { + + } + } + + static foreach (iii, comp_info; components_info.req) + { + __traits(getMember, input_data, comp_info.name) = + (cast(ForeachType!(typeof(__traits(getMember, + Sys.EntitiesData, comp_info.name)))*)(cast(void*) block + info.deltas[ system.m_components[iii]]))[offset .. entities_count]; + } + + static foreach (iii, comp_info; components_info.optional) + { + if(system.m_optional_components[iii] < info.deltas.length && info.deltas[system.m_optional_components[iii]] != 0) + { + __traits(getMember, input_data, comp_info.name) = + (cast(ForeachType!(typeof(__traits(getMember, + Sys.EntitiesData, comp_info.name)))*)(cast(void*) block + info.deltas[ system.m_optional_components[iii]]))[offset .. entities_count]; + + } + } } bool checkOnUpdateParams()() From 8b24ecf7d15c2836c0f069fc57eb404d7ca65738 Mon Sep 17 00:00:00 2001 From: Mergul Date: Sat, 6 Apr 2019 19:22:25 +0000 Subject: [PATCH 051/217] -some changes in registerSystem --- source/ecs/manager.d | 32 +++++++++++++++----------------- 1 file changed, 15 insertions(+), 17 deletions(-) diff --git a/source/ecs/manager.d b/source/ecs/manager.d index 133b964..20aff6b 100644 --- a/source/ecs/manager.d +++ b/source/ecs/manager.d @@ -325,6 +325,7 @@ class EntityManager CompInfo[] optional; CompInfo[] mutable; CompInfo[] req; + string entites_array; } static void allocateSystemComponents(ComponentsIndices components_info)(ref System system) @@ -363,8 +364,10 @@ class EntityManager alias MemberType = typeof(__traits(getMember, Sys.EntitiesData, member)); if (member == "length" || is(MemberType == Entity[]) || is(MemberType == const(Entity)[])) { + if(is(MemberType == Entity[]) || is(MemberType == const(Entity)[]))components_info.entites_array = member; continue; } + string name; static if (isArray!MemberType) { // Workaround. This code is never called with: not an array type, but compiler prints an error @@ -451,6 +454,8 @@ class EntityManager return components_info; } + enum ComponentsIndices components_info = getComponentsInfo(); + static void genCompList()(ref System system, ref HashMap!(const(char)[], ushort) components_map) { @@ -469,7 +474,7 @@ class EntityManager static assert(0, "EntitiesData members should be arrays of elements!"); } - enum ComponentsIndices components_info = getComponentsInfo(); + //enum ComponentsIndices components_info = getComponentsInfo(); allocateSystemComponents!(components_info)(system); foreach (iii, comp_info; components_info.req) @@ -508,23 +513,16 @@ class EntityManager static void fillInputData(ref Sys.EntitiesData input_data, EntityInfo* info, EntitiesBlock* block, uint offset, uint entities_count, System* system) { - enum ComponentsIndices components_info = getComponentsInfo(); - static foreach (member; __traits(allMembers, Sys.EntitiesData)) + //enum ComponentsIndices components_info = getComponentsInfo(); + + static if(components_info.entites_array) { - static if (is(typeof(__traits(getMember, Sys.EntitiesData, - member)) == Entity[]) || is(typeof(__traits(getMember, - Sys.EntitiesData, member)) == const(Entity)[])) - { - __traits(getMember, input_data, member) = (cast(Entity*) block.dataBegin())[offset .. entities_count]; - } - else static if (member == "length") - { - __traits(getMember, input_data, member) = cast(typeof(input_data.length))(entities_count - offset); - } - else - { - - } + __traits(getMember, input_data, components_info.entites_array) = (cast(Entity*) block.dataBegin())[offset .. entities_count]; + } + + static if(hasMember!(Sys.EntitiesData,"length")) + { + input_data.length = cast(typeof(input_data.length))(entities_count - offset); } static foreach (iii, comp_info; components_info.req) From fe158e1b60650737bb1071ab4e057b6dab396c2c Mon Sep 17 00:00:00 2001 From: Mergul Date: Sat, 6 Apr 2019 19:24:58 +0000 Subject: [PATCH 052/217] -removed commited code --- source/ecs/manager.d | 1 - 1 file changed, 1 deletion(-) diff --git a/source/ecs/manager.d b/source/ecs/manager.d index 20aff6b..6925aa9 100644 --- a/source/ecs/manager.d +++ b/source/ecs/manager.d @@ -669,7 +669,6 @@ class EntityManager (cast(Sys*) system.m_system_pointer).__ecsInitialize(); system.jobs = (cast(Sys*) system.m_system_pointer)._ecs_jobs; - //mixin(genCompList()); genCompList(system, components_map); ushort sys_id = systems_map.get(Sys.stringof, ushort.max); From 9220a28f7ca2f73df7202f026517a62abf4bee03 Mon Sep 17 00:00:00 2001 From: Mergul Date: Sat, 6 Apr 2019 20:27:28 +0000 Subject: [PATCH 053/217] -fixed issue with ExcludedComponents as enum or alias -removed way to add excluded component by adding attribiute @excluded (it's very stupid way) --- source/ecs/attributes.d | 4 ++-- source/ecs/manager.d | 39 +++++++++++++++++---------------------- tests/tests.d | 8 ++++---- 3 files changed, 23 insertions(+), 28 deletions(-) diff --git a/source/ecs/attributes.d b/source/ecs/attributes.d index 3a5ec95..cb49933 100644 --- a/source/ecs/attributes.d +++ b/source/ecs/attributes.d @@ -2,7 +2,7 @@ module ecs.attributes; ///Used to mark optional components for system. enum optional = "optional"; -///Used to mark components excluded from update for system. Enum 'ExcludedComponents' should be used instead of it. -enum excluded = "excluded"; +//Used to mark components excluded from update for system. Enum 'ExcludedComponents' should be used instead of it. +//enum excluded = "excluded"; ///Used to mark readonly components for system. "const" can be used insted. enum readonly = "readonly"; \ No newline at end of file diff --git a/source/ecs/manager.d b/source/ecs/manager.d index 6925aa9..42799aa 100644 --- a/source/ecs/manager.d +++ b/source/ecs/manager.d @@ -349,16 +349,16 @@ class EntityManager } - bool checkExcludedComponentsSomething(Sys)() - { - return __traits(compiles, allSameType!(string, typeof(Sys.ExcludedComponents))) && allSameType!(string, - typeof(Sys.ExcludedComponents)) && isExpressions!(Sys.ExcludedComponents); - } - static ComponentsIndices getComponentsInfo() { ComponentsIndices components_info; + bool checkExcludedComponentsSomething(Sys)() + { + return __traits(compiles, allSameType!(string, typeof(Sys.ExcludedComponents))) && allSameType!(string, + typeof(Sys.ExcludedComponents)) && isExpressions!(Sys.ExcludedComponents); + } + foreach (member; __traits(allMembers, Sys.EntitiesData)) { alias MemberType = typeof(__traits(getMember, Sys.EntitiesData, member)); @@ -375,7 +375,7 @@ class EntityManager } bool is_optional; - bool is_excluded; + //bool is_excluded; bool is_read_only; if (is(CopyConstness!(ForeachType!(MemberType), int) == const(int))) @@ -389,10 +389,10 @@ class EntityManager { is_optional = true; } - else if (att == "excluded") + /*else if (att == "excluded") { is_excluded = true; - } + }*/ if (att == "readonly") { is_read_only = true; @@ -406,10 +406,10 @@ class EntityManager { components_info.mutable ~= CompInfo(member,name); } - if (is_excluded) + /*if (is_excluded) { components_info.excluded ~= CompInfo(member,name); - } + }*/ if (is_optional) { components_info.optional ~= CompInfo(member,name); @@ -418,13 +418,13 @@ class EntityManager { components_info.readonly ~= CompInfo(member,name); } - if (is_excluded == false && is_optional == false) + if (/*is_excluded == false &&*/ is_optional == false) { //is Req components_info.req ~= CompInfo(member,name); } - assert(!(is_optional && is_excluded), - "EntitiesData member can't have both \"@optional\" and \"@excluded\"."); + /*assert(!(is_optional && is_excluded), + "EntitiesData member can't have both \"@optional\" and \"@excluded\".");*/ } @@ -432,21 +432,16 @@ class EntityManager { static if (is(Sys.ExcludedComponents == enum)) { - foreach (str; Fields!(Sys.ExcludedComponents)) + foreach (str; __traits(allMembers, Sys.ExcludedComponents)) { - ComponentInfo info; - info.is_excluded = true; - info.name = str.stringof; + components_info.excluded ~= CompInfo(str,str); } } else static if (checkExcludedComponentsSomething!Sys) { foreach (str; Sys.ExcludedComponents) { - ComponentInfo info; - info.is_excluded = true; - info.name = str; - + components_info.excluded ~= CompInfo(str,str); } } diff --git a/tests/tests.d b/tests/tests.d index bf6fd53..db85ba7 100644 --- a/tests/tests.d +++ b/tests/tests.d @@ -344,14 +344,14 @@ struct TestSystem2 { mixin ECS.System!16; //__gshared ushort system_id; - /*enum ExcludedComponents0 + /*enum ExcludedComponents { TestComp, TestComp4 - } - - alias ExcludedComponents = AliasSeq!("TestComp", "TestComp4"); + }*/ + //alias ExcludedComponents = AliasSeq!("TestComp", "TestComp4"); +/* string ExcludedComponents2;*/ static struct EntitiesData From cb257a2360993cede1f1133cead0fb75fa3b3580 Mon Sep 17 00:00:00 2001 From: Mergul Date: Wed, 15 May 2019 08:47:30 +0000 Subject: [PATCH 054/217] -added export attribute --- dub.json | 3 ++- source/ecs/events.d | 2 +- source/ecs/manager.d | 45 ++++++++++++++++++++++---------------------- source/ecs/vector.d | 4 ++-- 4 files changed, 28 insertions(+), 26 deletions(-) diff --git a/dub.json b/dub.json index 52988fd..8b90068 100755 --- a/dub.json +++ b/dub.json @@ -8,7 +8,8 @@ "license": "BSD", "sourcePaths" : ["source\/"], "dflags-posix-ldc": [ - "-defaultlib=phobos2-ldc,druntime-ldc" + "-defaultlib=phobos2-ldc,druntime-ldc", + "-fvisibility=hidden" ], "dflagss": [ "-betterC" diff --git a/source/ecs/events.d b/source/ecs/events.d index a6f6d36..ca9bade 100644 --- a/source/ecs/events.d +++ b/source/ecs/events.d @@ -76,7 +76,7 @@ struct EventManager manager = m; } - void sendEvent(Ev)(EntityID id, Ev event, uint thread_id = 0) nothrow @nogc + export void sendEvent(Ev)(EntityID id, Ev event, uint thread_id = 0) nothrow @nogc { uint block_id = current_index+thread_id; diff --git a/source/ecs/manager.d b/source/ecs/manager.d index 42799aa..784ec4f 100644 --- a/source/ecs/manager.d +++ b/source/ecs/manager.d @@ -23,15 +23,15 @@ import ecs.vector; import ecs.events; import ecs.traits; -alias gEM = EntityManager.instance; -alias gEntityManager = EntityManager.instance; -alias gEventManager = EntityManager.instance; +export alias gEM = EntityManager.instance; +export alias gEntityManager = EntityManager.instance; +export alias gEventManager = EntityManager.instance; alias SerializeVector = ecs.vector.Vector!ubyte; /************************************************************************************************************************ *Entity manager is responsible for everything. */ -class EntityManager +export class EntityManager { export static void initialize(uint threads_count) { @@ -62,7 +62,7 @@ class EntityManager /************************************************************************************************************************ *Begin registering process. Every register function should be called between beginRegister() and endRegister(). */ - void beginRegister() nothrow @nogc + export void beginRegister() nothrow @nogc { assert(!register_state, "beginRegister() can't be called twice before endRegister();"); register_state = true; @@ -80,7 +80,7 @@ class EntityManager /************************************************************************************************************************ *End registering process. Every register function should be called between beginRegister() and endRegister(). */ - void endRegister() + export void endRegister() { assert(register_state, "beginRegister() should be called before endRegister();"); register_state = false; @@ -699,7 +699,7 @@ class EntityManager /************************************************************************************************************************ *Return system ECS api by id */ - System* getSystem(ushort id) nothrow @nogc + export System* getSystem(ushort id) nothrow @nogc { return &systems[id]; } @@ -712,7 +712,7 @@ class EntityManager return cast(Sys*) systems[Sys.system_id].m_system_pointer; } - ushort registerPass(const(char)[] name) + export ushort registerPass(const(char)[] name) { UpdatePass* pass = Mallocator.instance.make!UpdatePass; pass.name = Mallocator.instance.makeArray(name); @@ -815,7 +815,7 @@ class EntityManager /************************************************************************************************************************ *Same as "void update(int pass = 0)" but use pass name instead of id. */ - void update(const(char)[] pass_name) nothrow @nogc + export void update(const(char)[] pass_name) nothrow @nogc { ushort pass = passes_map.get(pass_name, ushort.max); assert(pass != ushort.max); @@ -846,14 +846,14 @@ class EntityManager /************************************************************************************************************************ *Same as "void updateMT(int pass = 0)" but use pass name instead of id. */ - void updateMT(const(char)[] pass_name) nothrow @nogc + export void updateMT(const(char)[] pass_name) nothrow @nogc { ushort pass = passes_map.get(pass_name, ushort.max); assert(pass != ushort.max); updateMT(pass); } - void updateMT(ushort pass = 0) nothrow @nogc + export void updateMT(ushort pass = 0) nothrow @nogc { assert(!register_state); assert(pass < passes.length); @@ -982,7 +982,7 @@ class EntityManager } } - void setJobDispachFunc(void delegate(JobGroup) func) nothrow @nogc + export void setJobDispachFunc(void delegate(JobGroup) func) nothrow @nogc { m_dispatch_jobs = func; } @@ -1123,7 +1123,7 @@ class EntityManager return info; } - void generateListeners(EntityInfo* info) + private void generateListeners(EntityInfo* info) { if (info.add_listeners) { @@ -2053,7 +2053,7 @@ class EntityManager } } - void updateEvents() nothrow @nogc + private void updateEvents() nothrow @nogc { bool empty = true; while (1) @@ -2164,8 +2164,7 @@ class EntityManager event_manager.sendEvent(id, event, thread_id); } - /*private */ - void generateDependencies() nothrow @nogc + private void generateDependencies() nothrow @nogc { foreach (pass_id, pass; passes) { @@ -2398,7 +2397,7 @@ class EntityManager struct EntitiesBlock { ///return distance (in bytes) from begin of block to data - uint dataDelta() nothrow @nogc + export uint dataDelta() nothrow @nogc { ushort dif = EntitiesBlock.sizeof; alignNum(dif, type_info.alignment); @@ -2438,7 +2437,7 @@ class EntityManager */ struct CallData { - void update() nothrow @nogc + export void update() nothrow @nogc { (cast(SytemFuncType) system.m_update)(this); } @@ -2472,7 +2471,7 @@ class EntityManager { CallData[] callers; - void execute() nothrow @nogc + export void execute() nothrow @nogc { EntityManager.instance.getThreadID(); foreach (ref caller; callers) @@ -2519,15 +2518,17 @@ class EntityManager Vector!(EntitiesBlock*) blocks_to_update; } - struct UpdatePass + export struct UpdatePass { - ~this() nothrow @nogc + export ~this() nothrow @nogc { assert(name); if (name) Mallocator.instance.dispose(name); } + export size_t __xtoHash(); + char[] name; Vector!(SystemCaller*) system_callers; } @@ -2620,7 +2621,7 @@ class EntityManager } } - __gshared EntityManager instance = null; + export __gshared EntityManager instance = null; } /* diff --git a/source/ecs/vector.d b/source/ecs/vector.d index a17aaf8..47cd761 100644 --- a/source/ecs/vector.d +++ b/source/ecs/vector.d @@ -11,8 +11,8 @@ export @nogc @safe nothrow pure size_t nextPow2(size_t num) { return 1 << bsr(num) + 1; } -__gshared size_t gVectorsCreated = 0; -__gshared size_t gVectorsDestroyed = 0; +export __gshared size_t gVectorsCreated = 0; +export __gshared size_t gVectorsDestroyed = 0; struct Vector(T) { T[] array; From 1396d0bf853d6fbf3c3fa5e3f49bba5631d30dd0 Mon Sep 17 00:00:00 2001 From: Mergul Date: Sun, 2 Jun 2019 11:05:38 +0200 Subject: [PATCH 055/217] -removed -fvisibility=hidden (switch works only with betterC) --- dub.json | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/dub.json b/dub.json index 8b90068..52988fd 100755 --- a/dub.json +++ b/dub.json @@ -8,8 +8,7 @@ "license": "BSD", "sourcePaths" : ["source\/"], "dflags-posix-ldc": [ - "-defaultlib=phobos2-ldc,druntime-ldc", - "-fvisibility=hidden" + "-defaultlib=phobos2-ldc,druntime-ldc" ], "dflagss": [ "-betterC" From 9f125078edf7dbe40b14c813ebc9696ec282a89f Mon Sep 17 00:00:00 2001 From: Mergul Date: Mon, 17 Jun 2019 18:04:54 +0000 Subject: [PATCH 056/217] -dmd bug workaround --- source/ecs/entity.d | 1 + source/ecs/manager.d | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/source/ecs/entity.d b/source/ecs/entity.d index 09a5996..8fbc6e4 100644 --- a/source/ecs/entity.d +++ b/source/ecs/entity.d @@ -3,6 +3,7 @@ */ module ecs.entity; +import ecs.system; import ecs.manager; /************************************************************************************************************************ diff --git a/source/ecs/manager.d b/source/ecs/manager.d index 784ec4f..3505abd 100644 --- a/source/ecs/manager.d +++ b/source/ecs/manager.d @@ -14,11 +14,11 @@ import core.stdc.string; import core.atomic; import core.sync.mutex; +import ecs.system; import ecs.entity; import ecs.block_allocator; import ecs.hash_map; import ecs.id_manager; -import ecs.system; import ecs.vector; import ecs.events; import ecs.traits; From 17fc7bc004c11138d3a2bd5338ebcdf6aa7889f1 Mon Sep 17 00:00:00 2001 From: Mergul Date: Mon, 17 Jun 2019 18:25:36 +0000 Subject: [PATCH 057/217] -removed __xtoHash() method --- source/ecs/manager.d | 2 -- 1 file changed, 2 deletions(-) diff --git a/source/ecs/manager.d b/source/ecs/manager.d index 3505abd..1197767 100644 --- a/source/ecs/manager.d +++ b/source/ecs/manager.d @@ -2527,8 +2527,6 @@ export class EntityManager Mallocator.instance.dispose(name); } - export size_t __xtoHash(); - char[] name; Vector!(SystemCaller*) system_callers; } From 9824b587fb392124e2f2108dd9946077d0f4e055 Mon Sep 17 00:00:00 2001 From: Mergul Date: Tue, 18 Jun 2019 13:57:31 +0200 Subject: [PATCH 058/217] -fixed stack-overflow error --- dub.json | 3 ++- source/ecs/manager.d | 23 ++++++++++++----------- tests/tests.d | 27 ++++++++++++++++++++++++--- 3 files changed, 38 insertions(+), 15 deletions(-) diff --git a/dub.json b/dub.json index 52988fd..d5e4a87 100755 --- a/dub.json +++ b/dub.json @@ -8,7 +8,8 @@ "license": "BSD", "sourcePaths" : ["source\/"], "dflags-posix-ldc": [ - "-defaultlib=phobos2-ldc,druntime-ldc" + "-defaultlib=phobos2-ldc,druntime-ldc", + "-fsanitize=address" ], "dflagss": [ "-betterC" diff --git a/source/ecs/manager.d b/source/ecs/manager.d index 784ec4f..12dfa7c 100644 --- a/source/ecs/manager.d +++ b/source/ecs/manager.d @@ -1331,8 +1331,8 @@ export class EntityManager ThreadData* data = &threads[thread_id]; uint num = cast(uint) del_ids.length; data.change_entities_list.add(0); - data.change_entities_list.add((cast(ubyte*)&entity_id)[0 .. 8]); - data.change_entities_list.add((cast(ubyte*)&num)[0 .. 4]); + data.change_entities_list.add((cast(ubyte*)&entity_id)[0 .. EntityID.sizeof]); + data.change_entities_list.add((cast(ubyte*)&num)[0 .. uint.sizeof]); data.change_entities_list.add(cast(ubyte[]) del_ids); } @@ -1646,9 +1646,9 @@ export class EntityManager pointers[i] = ∁ }*/ ThreadData* data = &threads[thread_id]; - data.change_entities_list.add(1); - data.change_entities_list.add((cast(ubyte*)&entity_id)[0 .. 8]); - data.change_entities_list.add((cast(ubyte*)&num)[0 .. 4]); + data.change_entities_list.add(cast(ubyte)1u); + data.change_entities_list.add((cast(ubyte*)&entity_id)[0 .. EntityID.sizeof]); + data.change_entities_list.add((cast(ubyte*)&num)[0 .. uint.sizeof]); data.change_entities_list.add(cast(ubyte[]) new_ids); static foreach (i, comp; comps) { @@ -1903,6 +1903,7 @@ export class EntityManager { uint index = 0; uint len = cast(uint) thread.change_entities_list.length; + void*[32] pointers;// = (cast(void**) alloca(num * (void*).sizeof))[0 .. num]; while (index < len) { if (!thread.change_entities_list[index++]) @@ -1911,8 +1912,8 @@ export class EntityManager index += EntityID.sizeof; uint num = *cast(uint*)&thread.change_entities_list[index]; index += uint.sizeof; - ushort[] ids = (cast(ushort*) alloca(num * ushort.sizeof))[0 .. num]; - ids[0 .. $] = (cast(ushort*)&thread.change_entities_list[index])[0 .. num]; + ushort[] ids;// = (cast(ushort*) alloca(num * ushort.sizeof))[0 .. num]; + ids = (cast(ushort*)&thread.change_entities_list[index])[0 .. num]; index += ushort.sizeof * num; __removeComponents(id, ids); } @@ -1922,16 +1923,16 @@ export class EntityManager index += EntityID.sizeof; uint num = *cast(uint*)&thread.change_entities_list[index]; index += uint.sizeof; - ushort[] ids = (cast(ushort*) alloca(num * ushort.sizeof))[0 .. num]; - ids[0 .. $] = (cast(ushort*)&thread.change_entities_list[index])[0 .. num]; + ushort[] ids;// = (cast(ushort*) alloca(num * ushort.sizeof))[0 .. num]; + ids = (cast(ushort*)&thread.change_entities_list[index])[0 .. num]; index += ushort.sizeof * num; - void*[] pointers = (cast(void**) alloca(num * (void*).sizeof))[0 .. num]; + //void*[] pointers = (cast(void**) alloca(num * (void*).sizeof))[0 .. num]; foreach (i; 0 .. num) { pointers[i] = &thread.change_entities_list[index]; index += components[ids[i]].size; } - __addComponents(id, ids, pointers); + __addComponents(id, ids, pointers[0..num]); } } thread.change_entities_list.clear(); diff --git a/tests/tests.d b/tests/tests.d index db85ba7..4f68da4 100644 --- a/tests/tests.d +++ b/tests/tests.d @@ -1,5 +1,8 @@ module tests.tests; +import std.experimental.allocator; +import std.experimental.allocator.mallocator; + import ecs.entity; import ecs.events; import ecs.manager; @@ -136,8 +139,10 @@ struct ChangeTestSystem void onAddEntity(EntitiesData data) { + //printf("Entity added! ID: "); foreach (i; 0 .. data.length) - writeln("Entity added! ID: ", data.entites[i].id.id); + printf("Entity added! ID: %u\n",data.entites[i].id.id); + //writeln("Entity added! ID: ", data.entites[i].id.id); } void onRemoveEntity(EntitiesData data) @@ -532,7 +537,7 @@ int main() //foreach(i; 0..1_000_000)gEM.removeEntity(gEM.addEntity(tmpl).id); - EntityID[5000] idss; + EntityID[] idss = Mallocator.instance.makeArray!EntityID(5000);//[5000] foreach (i; 0 .. 200) { @@ -575,10 +580,12 @@ int main() time = MonoTime.currTime; + EntityID[] entities = Mallocator.instance.makeArray!EntityID(1_000_000); foreach (i; 0 .. 500_000) { entity2 = gEM.addEntity(tmpl); - gEM.addEntity(tmpl2); + entities[i*2] = entity2.id; + entities[i*2+1] = gEM.addEntity(tmpl2).id; } gEM.commit(); @@ -587,6 +594,20 @@ int main() time = MonoTime.currTime; + foreach (i; 0 .. 1_000_000) + { + EntityManager.instance.addComponents(entities[i],TestComp5()); + //if((i & 0x00FFFF) == 0)gEM.commit(); + } + + gEM.commit(); + dur = (MonoTime.currTime - time).total!"usecs"; + writeln("Components adding: ", dur, " usecs"); + + Mallocator.instance.dispose(entities); + + time = MonoTime.currTime; + gEM.begin(); //gEM.updateMT(); gEM.update(); From 235bbb49f27eb79262121319cd00558a47768db6 Mon Sep 17 00:00:00 2001 From: Mergul Date: Tue, 18 Jun 2019 16:45:38 +0200 Subject: [PATCH 059/217] -block allocator now track allocated blocks and is able to free memory -jobs data is now allocated in System struct -written memory cleanup (AddressSanitizer don't show any leak) --- source/ecs/block_allocator.d | 32 +++++++++ source/ecs/core.d | 10 ++- source/ecs/events.d | 48 +++++++++++--- source/ecs/id_manager.d | 23 ++++++- source/ecs/manager.d | 122 +++++++++++++++++++++++++++++------ source/ecs/system.d | 2 +- tests/tests.d | 18 ++++-- 7 files changed, 214 insertions(+), 41 deletions(-) diff --git a/source/ecs/block_allocator.d b/source/ecs/block_allocator.d index d2272dd..2894f61 100644 --- a/source/ecs/block_allocator.d +++ b/source/ecs/block_allocator.d @@ -10,7 +10,15 @@ struct BlockAllocator//(uint block_size, uint blocks_in_allocation) private uint block_size; private uint blocks_in_allocation; + struct BlockPointers + { + void*[32] blocks; + uint numberof = 0; + BlockPointers* next_pointers = null; + } + void* next_block = null; + BlockPointers* pointers = null; void* getBlock() nothrow @nogc { @@ -31,6 +39,16 @@ struct BlockAllocator//(uint block_size, uint blocks_in_allocation) { next_block = cast(void*) AlignedMallocator.instance.alignedAllocate( block_size * blocks_in_allocation, block_size); + + if(pointers is null)pointers = Mallocator.instance.make!BlockPointers; + if(pointers.numberof >= 32) + { + BlockPointers* new_pointers = Mallocator.instance.make!BlockPointers; + new_pointers.next_pointers = pointers; + pointers = new_pointers; + } + pointers.blocks[pointers.numberof++] = next_block; + foreach (i; 0 .. blocks_in_allocation - 1) { void** pointer = cast(void**)(next_block + i * block_size); @@ -40,4 +58,18 @@ struct BlockAllocator//(uint block_size, uint blocks_in_allocation) next_block + (blocks_in_allocation - 1) * block_size); *pointer = null; } + + void freeMemory() nothrow @nogc + { + while(pointers) + { + foreach(i;0..pointers.numberof) + { + AlignedMallocator.instance.dispose(pointers.blocks[i]); + } + BlockPointers* next_pointers = pointers.next_pointers; + Mallocator.instance.dispose(pointers); + pointers = next_pointers; + } + } } diff --git a/source/ecs/core.d b/source/ecs/core.d index 8f34fc0..64dceba 100644 --- a/source/ecs/core.d +++ b/source/ecs/core.d @@ -8,7 +8,8 @@ static struct ECS mixin template System(uint jobs_count = 32) { __gshared ushort system_id; - EntityManager.Job[] _ecs_jobs; + uint __ecs_jobs_count = jobs_count; + /*EntityManager.Job[] _ecs_jobs; void __ecsInitialize() nothrow @nogc { @@ -16,6 +17,13 @@ static struct ECS import std.experimental.allocator; _ecs_jobs = Mallocator.instance.makeArray!(EntityManager.Job)(jobs_count); } + + void __ecsDeinitialize() nothrow @nogc + { + import std.experimental.allocator.mallocator; + import std.experimental.allocator; + Mallocator.instance.dispose(_ecs_jobs); + }*/ } mixin template Component() diff --git a/source/ecs/events.d b/source/ecs/events.d index ca9bade..47d9415 100644 --- a/source/ecs/events.d +++ b/source/ecs/events.d @@ -175,15 +175,7 @@ struct EventManager void allocateData(uint threads_count) nothrow @nogc { - if(events) - { - foreach(ref event;events) - { - Mallocator.instance.dispose(event.blocks); - Mallocator.instance.dispose(event.first_blocks); - } - Mallocator.instance.dispose(events); - } + disposeData(); events = Mallocator.instance.makeArray!EventData(gEM.events.length); foreach(i,ref event;events) { @@ -196,8 +188,44 @@ struct EventManager } } + private void disposeData() nothrow @nogc + { + if(events) + { + foreach(ref event;events) + { + foreach(first_block; event.first_blocks) + { + EventBlock* block = first_block; + EventBlock* next_block; + if(block)next_block = first_block.next; + while(block) + { + Mallocator.instance.dispose(block); + block = next_block; + if(block)next_block = block.next; + } + } + + Mallocator.instance.dispose(event.blocks); + Mallocator.instance.dispose(event.first_blocks); + } + Mallocator.instance.dispose(events); + } + allocator.freeMemory(); + } + + ~this() nothrow @nogc + { + disposeData(); + /*foreach(i,ref event;events) + { + EventBlock* block = event.first_blocks; + }*/ + } + ///Single page size. Must be power of two. - enum events_block_size = 1 << 12; + enum events_block_size = 1 << 14; ///Number of pages in block. enum events_blocks_in_allocation = 128; diff --git a/source/ecs/id_manager.d b/source/ecs/id_manager.d index 07566d3..3ee7f1c 100644 --- a/source/ecs/id_manager.d +++ b/source/ecs/id_manager.d @@ -154,6 +154,24 @@ begin: add_mutex = Mallocator.instance.make!Mutex(); } + void deinitialize() @trusted @nogc + { + if(m_ids_array)Mallocator.instance.dispose(m_ids_array); + if(m_free_stack)Mallocator.instance.dispose(m_free_stack); + if(m_blocks) + { + foreach(ref block;m_blocks) + { + if(block.data)block.free(); + } + Mallocator.instance.dispose(m_blocks); + } + if(add_mutex) + { + Mallocator.instance.dispose(cast(void*)add_mutex); //workaround for compiler bug + } + } + void optimize() nothrow @nogc { if(m_stack_top < -1)m_stack_top = -1; @@ -176,7 +194,7 @@ begin: begin += 65536; } memcpy(cast(void*)m_ids_array.ptr + begin * Data.sizeof, m_blocks[m_blocks_count-1].data.ptr, (m_last_id - begin) * Data.sizeof); - foreach(block;m_blocks[1..m_blocks_count])block.free(); + foreach(ref block;m_blocks[1..m_blocks_count])block.free(); m_blocks_count = 1; } } @@ -193,9 +211,10 @@ begin: { assert(data !is null); Mallocator.instance.dispose(data); + data = null; } - Data[] data; //65536 + Data[] data = null; //65536 } private static struct Data diff --git a/source/ecs/manager.d b/source/ecs/manager.d index 12dfa7c..0a7017d 100644 --- a/source/ecs/manager.d +++ b/source/ecs/manager.d @@ -36,7 +36,17 @@ export class EntityManager export static void initialize(uint threads_count) { if (instance is null) + { instance = Mallocator.instance.make!EntityManager(threads_count); + + with(instance) + { + UpdatePass* pass = Mallocator.instance.make!UpdatePass; + pass.name = Mallocator.instance.makeArray("update"); + passes.add(pass); + passes_map.add(cast(string) pass.name, cast(ushort)(passes.length - 1)); + } + } } export static void destroy() @@ -44,19 +54,58 @@ export class EntityManager if (instance is null) return; - foreach (ref system; instance.systems) + with(instance) { - system.disable(); - } + foreach (ref system; systems) + { + system.disable(); + if (system.m_destroy) + (cast(void function(void*)) system.m_destroy)(system.m_system_pointer); - foreach (ref system; instance.systems) - { - if (system.m_destroy) - (cast(void function(void*)) system.m_destroy)(system.m_system_pointer); + if(system.jobs)Mallocator.instance.dispose(system.jobs); + if(system.m_read_only_components)Mallocator.instance.dispose(system.m_read_only_components); + if(system.m_modified_components)Mallocator.instance.dispose(system.m_modified_components); + if(system.m_components)Mallocator.instance.dispose(system.m_components); + if(system.m_excluded_components)Mallocator.instance.dispose(system.m_excluded_components); + if(system.m_optional_components)Mallocator.instance.dispose(system.m_optional_components); + if(system.name)Mallocator.instance.dispose(system.name); + if(system.m_event_callers)Mallocator.instance.dispose(system.m_event_callers); + + if(system.m_system_pointer)Mallocator.instance.dispose(system.m_system_pointer); + } + + foreach(EntityInfo* info;&entities_infos.byValue) + { + //if(info.components)Mallocator.instance.dispose(info.components); + + Mallocator.instance.dispose(info); + } + + foreach(UpdatePass* pass; passes) + { + Mallocator.instance.dispose(pass); + } + passes.clear(); + + foreach(ComponentInfo info; components) + { + if(info.init_data)Mallocator.instance.dispose(info.init_data); + } + + foreach(EventInfo info; events) + { + if(info.callers)Mallocator.instance.dispose(info.callers); + } + + foreach(name; &components_map.byKey) + { + if(name)Mallocator.instance.dispose(name); + } } Mallocator.instance.dispose(instance); instance = null; + } /************************************************************************************************************************ @@ -198,12 +247,16 @@ export class EntityManager entity_block_alloc_mutex = Mallocator.instance.make!Mutex; //event_manager = EventManager(this); //event_manager.manager = this; + } - UpdatePass* pass = Mallocator.instance.make!UpdatePass; - pass.name = Mallocator.instance.makeArray("update"); - passes.add(pass); + ~this() + { + id_manager.deinitialize(); - passes_map.add(cast(string) pass.name, cast(ushort)(passes.length - 1)); + if(threads)Mallocator.instance.dispose(threads); + if(entity_block_alloc_mutex)Mallocator.instance.dispose(entity_block_alloc_mutex); + + allocator.freeMemory(); } /************************************************************************************************************************ @@ -451,7 +504,7 @@ export class EntityManager enum ComponentsIndices components_info = getComponentsInfo(); - static void genCompList()(ref System system, ref HashMap!(const(char)[], ushort) components_map) + static void genCompList()(ref System system, ref HashMap!(char[], ushort) components_map) { foreach (member; __traits(allMembers, Sys.EntitiesData)) @@ -661,12 +714,13 @@ export class EntityManager system.m_system_pointer = cast(void*) Mallocator.instance.make!Sys; system.m_priority = priority; - (cast(Sys*) system.m_system_pointer).__ecsInitialize(); - system.jobs = (cast(Sys*) system.m_system_pointer)._ecs_jobs; + //(cast(Sys*) system.m_system_pointer).__ecsInitialize(); + //system.jobs = (cast(Sys*) system.m_system_pointer)._ecs_jobs; + system.jobs = Mallocator.instance.makeArray!(Job)((cast(Sys*) system.m_system_pointer).__ecs_jobs_count); genCompList(system, components_map); - ushort sys_id = systems_map.get(Sys.stringof, ushort.max); + ushort sys_id = systems_map.get(cast(char[])Sys.stringof, ushort.max); if (sys_id < systems.length) { system.enable(); @@ -761,7 +815,7 @@ export class EntityManager info.init_data = Mallocator.instance.makeArray!ubyte(Comp.sizeof); *cast(Comp*) info.init_data.ptr = Comp.init; // = Comp(); - ushort comp_id = components_map.get(Comp.stringof, ushort.max); + ushort comp_id = components_map.get(cast(char[])Comp.stringof, ushort.max); if (comp_id < components.length) { Comp.component_id = comp_id; @@ -771,7 +825,7 @@ export class EntityManager { components.add(info); Comp.component_id = cast(ushort)(components.length - 1); - const(char)[] name = Mallocator.instance.makeArray(Comp.stringof); + char[] name = Mallocator.instance.makeArray(Comp.stringof); components_map.add(name, cast(ushort)(components.length - 1)); } } @@ -2362,6 +2416,17 @@ export class EntityManager } } + ~this() + { + if(components)Mallocator.instance.dispose(components); + if(deltas)Mallocator.instance.dispose(deltas); + if(tmpl_deltas)Mallocator.instance.dispose(tmpl_deltas); + if(systems)Mallocator.instance.dispose(systems); + if(add_listeners)Mallocator.instance.dispose(add_listeners); + if(remove_listeners)Mallocator.instance.dispose(remove_listeners); + if(change_listeners)Mallocator.instance.dispose(change_listeners); + } + ///entity components ushort[] components; @@ -2498,6 +2563,9 @@ export class EntityManager if (dependencies) { Mallocator.instance.dispose(dependencies); + } + if(exclusion) + { Mallocator.instance.dispose(exclusion); } if (job_group.dependencies) @@ -2526,10 +2594,13 @@ export class EntityManager assert(name); if (name) Mallocator.instance.dispose(name); + foreach(caller; system_callers) + { + Mallocator.instance.dispose(caller); + } + system_callers.clear(); } - export size_t __xtoHash(); - char[] name; Vector!(SystemCaller*) system_callers; } @@ -2558,8 +2629,8 @@ export class EntityManager uint delegate() m_thread_id_func; HashMap!(ushort[], EntityInfo*) entities_infos; - HashMap!(const(char)[], ushort) systems_map; - HashMap!(const(char)[], ushort) components_map; + HashMap!(char[], ushort) systems_map; + HashMap!(char[], ushort) components_map; HashMap!(const(char)[], ushort) events_map; HashMap!(const(char)[], ushort) passes_map; Vector!System systems; @@ -2578,6 +2649,15 @@ export class EntityManager uint allocated = 0; } + ~this() + { + foreach(block;blocks) + { + Mallocator.instance.dispose(block); + } + blocks.clear(); + } + Vector!(Block*) blocks; uint id; diff --git a/source/ecs/system.d b/source/ecs/system.d index 765c380..e033147 100644 --- a/source/ecs/system.d +++ b/source/ecs/system.d @@ -97,7 +97,7 @@ package: int m_pass; ///system name - const(char)[] name; + char[] name; ///required components ushort[] m_components; diff --git a/tests/tests.d b/tests/tests.d index 4f68da4..03fcc97 100644 --- a/tests/tests.d +++ b/tests/tests.d @@ -141,18 +141,20 @@ struct ChangeTestSystem { //printf("Entity added! ID: "); foreach (i; 0 .. data.length) - printf("Entity added! ID: %u\n",data.entites[i].id.id); - //writeln("Entity added! ID: ", data.entites[i].id.id); + printf("Entity added! ID: %u\n",data.entites[i].id); + //writeln("Entity added! ID: ", data.entites[i].id); } void onRemoveEntity(EntitiesData data) { - writeln("Entity removed! ID: ", data.entites[0].id); + //writeln("Entity removed! ID: ", data.entites[0].id); + printf("Entity removed! ID: %u\n",data.entites[0].id); } void onChangeEntity(EntitiesData data) { - writeln("Entity changed! ID: ", data.entites[0].id); + //writeln("Entity changed! ID: ", data.entites[0].id); + printf("Entity changed! ID: %u\n",data.entites[0].id); } bool onBegin() @@ -538,6 +540,7 @@ int main() //foreach(i; 0..1_000_000)gEM.removeEntity(gEM.addEntity(tmpl).id); EntityID[] idss = Mallocator.instance.makeArray!EntityID(5000);//[5000] + scope(exit)Mallocator.instance.dispose(idss); foreach (i; 0 .. 200) { @@ -568,7 +571,7 @@ int main() //foreach(j; 0..1_000)gEM.addEntity(tmpl); gEM.beginRegister(); - gEM.registerSystem!TestSystem2(0); + //gEM.registerSystem!TestSystem2(0); gEM.endRegister(); //gEM.generateDependencies(); @@ -674,13 +677,16 @@ int main() gEM.removeComponents!(TestComp4)(entity.id); - gEM.commit(); + gEM.commit();//*/ writeEntityComponents(gEM.getEntity(entity.id)); //import std.stdio; //writeln((cast(uint*)tmpl.info.first_block)[0..48]); gEM.freeTemplate(tmpl); + gEM.freeTemplate(tmpl2); EntityManager.destroy(); + + return 0; } From b04ab77e0c5aa6dd630116103e22eba478c17cd6 Mon Sep 17 00:00:00 2001 From: Mergul Date: Tue, 18 Jun 2019 17:49:51 +0200 Subject: [PATCH 060/217] -added components change caching (no HashMap searching during components adding or removing) --- dub.json | 3 +- source/ecs/manager.d | 126 ++++++++++++++++++++++++++++++++++++++----- tests/tests.d | 14 ++++- 3 files changed, 128 insertions(+), 15 deletions(-) diff --git a/dub.json b/dub.json index d5e4a87..52988fd 100755 --- a/dub.json +++ b/dub.json @@ -8,8 +8,7 @@ "license": "BSD", "sourcePaths" : ["source\/"], "dflags-posix-ldc": [ - "-defaultlib=phobos2-ldc,druntime-ldc", - "-fsanitize=address" + "-defaultlib=phobos2-ldc,druntime-ldc" ], "dflagss": [ "-betterC" diff --git a/source/ecs/manager.d b/source/ecs/manager.d index 0a7017d..140d8f2 100644 --- a/source/ecs/manager.d +++ b/source/ecs/manager.d @@ -1403,7 +1403,9 @@ export class EntityManager ushort[] ids = (cast(ushort*) alloca(ushort.sizeof * (info.components.length)))[0 .. info.components.length]; - uint j = 0; + EntityInfo* new_info = info; + + /*uint j = 0; uint k = 0; foreach (id; info.components) { @@ -1416,15 +1418,23 @@ export class EntityManager else if (del_ids[k] == info.components[j]) { k++; + new_info = new_info.getNewInfoAdd(del_ids[k]); } else ids[j++] = id; } if (j == info.components.length) - return; + return;*/ - EntityInfo* new_info = getEntityInfo(ids[0 .. j]); + foreach(id;del_ids) + { + new_info = new_info.getNewInfoRemove(id); + } + + if(new_info == info)return; + + //EntityInfo* new_info = getEntityInfo(ids[0 .. j]); EntitiesBlock* new_block = findBlockWithFreeSpace(new_info); @@ -1513,8 +1523,8 @@ export class EntityManager return; EntitiesBlock* block = getMetaData(entity); EntityInfo* info = block.type_info; - ushort[] ids = (cast(ushort*) alloca(ushort.sizeof * (info.components.length + num)))[0 - .. info.components.length + num]; + /*ushort[] ids = (cast(ushort*) alloca(ushort.sizeof * (info.components.length + num)))[0 + .. info.components.length + num];*/ /*ushort[num] new_ids; static foreach (i, comp; Components) @@ -1552,7 +1562,9 @@ export class EntityManager } } - uint j = 0; + EntityInfo* new_info = info; + + /* uint j = 0; uint k = 0; uint len = 0; //foreach (ref id; ids) @@ -1569,6 +1581,7 @@ export class EntityManager else if (j >= info.components.length) { *id = new_ids[k++]; + new_info = new_info.getNewInfoAdd(*id); //continue; } else if (new_ids[k] == info.components[j]) @@ -1577,18 +1590,26 @@ export class EntityManager k++; } /*debug if (new_ids[k] == info.components[j]) - assert(0, "Trying to add already existing component!");*/ + assert(0, "Trying to add already existing component!");//* else if (new_ids[k] < info.components[j]) { *id = new_ids[k++]; + new_info = new_info.getNewInfoAdd(*id); } else *id = info.components[j++]; } if (len == info.components.length) - return; + return;*/ - EntityInfo* new_info = getEntityInfo(ids[0 .. len]); + foreach(id;new_ids) + { + new_info = new_info.getNewInfoAdd(id); + } + + if(new_info == info)return; + + //EntityInfo* new_info = getEntityInfo(ids[0 .. len]); EntitiesBlock* new_block = findBlockWithFreeSpace(new_info); @@ -1598,8 +1619,8 @@ export class EntityManager new_entity.id = entity.id; new_entity.updateID(); - j = 0; - k = 0; + uint j = 0; + uint k = 0; static if (EntityID.sizeof == 8) uint ind = cast(uint)((cast(void*) entity - block.dataBegin()) >> 3); else @@ -1616,7 +1637,7 @@ export class EntityManager } } - foreach (ref id; ids[0 .. len]) + foreach (ref id; new_info.components)//ids[0 .. len]) { void* dst = cast(void*) new_block + new_info.deltas[id] + ( new_block.entities_count /*+ new_block.added_count*/ ) * components[id].size; @@ -2416,6 +2437,82 @@ export class EntityManager } } + EntityInfo* getNewInfoAdd(ushort id) + { + if(comp_add_info.length < id) + { + EntityInfo*[] new_infos = Mallocator.instance.makeArray!(EntityInfo*)(instance.components.length); + if(comp_add_info !is null) + { + new_infos[0 .. comp_add_info.length] = comp_add_info[0 .. $]; + Mallocator.instance.dispose(comp_add_info); + } + comp_add_info = new_infos; + } + if(comp_add_info[id])return comp_add_info[id]; + + ushort[] ids = (cast(ushort*) alloca(ushort.sizeof * (components.length + 1)))[0 + .. components.length + 1]; + uint len = 0; + + foreach(comp; components) + { + if(id > comp) + { + ids[len++] = comp; + } + else if(id == comp)return &this; + else + { + ids[len++] = id; + ids[len++] = comp; + } + } + if(id > components[$ - 1])ids[len++] = id; + + assert(len == components.length + 1); + + EntityInfo* new_info = instance.getEntityInfo(ids[0 .. len]); + + comp_add_info[id] = new_info; + return new_info; + } + + EntityInfo* getNewInfoRemove(ushort id) + { + if(comp_rem_info.length < id) + { + EntityInfo*[] new_infos = Mallocator.instance.makeArray!(EntityInfo*)(instance.components.length); + if(comp_rem_info !is null) + { + new_infos[0 .. comp_rem_info.length] = comp_rem_info[0 .. $]; + Mallocator.instance.dispose(comp_rem_info); + } + comp_rem_info = new_infos; + } + if(comp_rem_info[id])return comp_rem_info[id]; + + ushort[] ids = (cast(ushort*) alloca(ushort.sizeof * (components.length - 1)))[0 + .. components.length - 1]; + uint len = 0; + + foreach(comp; components) + { + if(id != comp) + { + ids[len++] = comp; + } + } + if(len == components.length)return &this; + + assert(len == components.length - 1); + + EntityInfo* new_info = instance.getEntityInfo(ids[0 .. len]); + + comp_rem_info[id] = new_info; + return new_info; + } + ~this() { if(components)Mallocator.instance.dispose(components); @@ -2435,6 +2532,11 @@ export class EntityManager ///deltas in memory for components in EntityTemplate ushort[] tmpl_deltas; + ///cached new infos after adding component + EntityInfo*[] comp_add_info; + ///cached new infos after removing component + EntityInfo*[] comp_rem_info; + ///alignment of whole entity ushort alignment; //unused in linear-layout ///size of entity (with alignment respect) diff --git a/tests/tests.d b/tests/tests.d index 03fcc97..edd8b16 100644 --- a/tests/tests.d +++ b/tests/tests.d @@ -600,13 +600,25 @@ int main() foreach (i; 0 .. 1_000_000) { EntityManager.instance.addComponents(entities[i],TestComp5()); - //if((i & 0x00FFFF) == 0)gEM.commit(); + if((i & 0x00FFFF) == 0)gEM.commit(); } gEM.commit(); dur = (MonoTime.currTime - time).total!"usecs"; writeln("Components adding: ", dur, " usecs"); + time = MonoTime.currTime; + + foreach (i; 0 .. 1_000_000) + { + EntityManager.instance.removeComponents!TestComp5(entities[i]); + //if((i & 0x00FFFF) == 0)gEM.commit(); + } + + gEM.commit(); + dur = (MonoTime.currTime - time).total!"usecs"; + writeln("Components removing: ", dur, " usecs"); + Mallocator.instance.dispose(entities); time = MonoTime.currTime; From 01ff3962b5a2aac760aef7aa03288795c8be1e12 Mon Sep 17 00:00:00 2001 From: Mergul Date: Tue, 18 Jun 2019 20:12:18 +0200 Subject: [PATCH 061/217] -added SimpleVector (vector with only ubyte data) -components adding and removing now use SimpleVector (optimalization) --- source/ecs/manager.d | 6 ++-- source/ecs/simple_vector.d | 66 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 70 insertions(+), 2 deletions(-) create mode 100644 source/ecs/simple_vector.d diff --git a/source/ecs/manager.d b/source/ecs/manager.d index 140d8f2..f2df314 100644 --- a/source/ecs/manager.d +++ b/source/ecs/manager.d @@ -20,6 +20,7 @@ import ecs.hash_map; import ecs.id_manager; import ecs.system; import ecs.vector; +import ecs.simple_vector; import ecs.events; import ecs.traits; @@ -1387,7 +1388,7 @@ export class EntityManager data.change_entities_list.add(0); data.change_entities_list.add((cast(ubyte*)&entity_id)[0 .. EntityID.sizeof]); data.change_entities_list.add((cast(ubyte*)&num)[0 .. uint.sizeof]); - data.change_entities_list.add(cast(ubyte[]) del_ids); + data.change_entities_list.add((cast(ubyte*)del_ids.ptr)[0 .. num * 2]); } private void __removeComponents(EntityID entity_id, ushort[] del_ids) @@ -2685,7 +2686,8 @@ export class EntityManager struct ThreadData { Vector!EntityID entities_to_remove; - Vector!ubyte change_entities_list; + //Vector!ubyte change_entities_list; + SimpleVector change_entities_list; Vector!(EntitiesBlock*) blocks_to_update; } diff --git a/source/ecs/simple_vector.d b/source/ecs/simple_vector.d new file mode 100644 index 0000000..1751040 --- /dev/null +++ b/source/ecs/simple_vector.d @@ -0,0 +1,66 @@ +module ecs.simple_vector; + +import std.experimental.allocator; +import std.experimental.allocator.mallocator; + +import core.stdc.string; + +struct SimpleVector +{ + + @disable this(this); + + void add(ubyte el) nothrow @nogc + { + while(used >= data.length) + { + if(data is null)data = Mallocator.instance.makeArray!ubyte(1024); + else Mallocator.instance.expandArray(data,data.length); + } + data[used++] = el; + } + + void add(ubyte[] el) nothrow @nogc + { + while(used + el.length >= data.length) + { + if(data is null)data = Mallocator.instance.makeArray!ubyte(1024); + else Mallocator.instance.expandArray(data,data.length); + } + memcpy(data.ptr + used, el.ptr, el.length); + used += el.length; + } + + size_t length() nothrow @nogc + { + return used; + } + + export ref ubyte opIndex(size_t pos) nothrow @nogc + { + return data[pos]; + } + + export ubyte[] opSlice() nothrow @nogc + { + return data[0 .. used]; + } + + export ubyte[] opSlice(size_t x, size_t y) nothrow @nogc + { + return data[x .. y]; + } + + export size_t opDollar() nothrow @nogc + { + return used; + } + + void clear() nothrow @nogc + { + used = 0; + } + + ubyte[] data = null; + size_t used = 0; +} \ No newline at end of file From f27e4c30ad156d6476258e60e023e56002a29851 Mon Sep 17 00:00:00 2001 From: Mergul Date: Thu, 27 Jun 2019 16:53:51 +0000 Subject: [PATCH 062/217] -updated copyright --- dub.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dub.json b/dub.json index 52988fd..bebf2ff 100755 --- a/dub.json +++ b/dub.json @@ -4,7 +4,7 @@ "Michał Masiukiewicz", "Dawid Masiukiewicz" ], "description": "Dynamic Entity Component System", - "copyright": "Copyright © 2017-2018, Michał Masiukiewicz, Dawid Masiukiewicz", + "copyright": "Copyright © 2018-2019, Michał Masiukiewicz, Dawid Masiukiewicz", "license": "BSD", "sourcePaths" : ["source\/"], "dflags-posix-ldc": [ From dfdb56d5017f333a73a1ce040a0143138cb69077 Mon Sep 17 00:00:00 2001 From: Mergul Date: Sat, 10 Aug 2019 15:35:36 +0000 Subject: [PATCH 063/217] -system name getter -added error checking for event handling in registerSystem -now only valid handleEvent() functions are taken by system during register --- source/ecs/manager.d | 41 ++++++++++++++++++++++++++--------------- source/ecs/system.d | 10 +++++++++- tests/tests.d | 9 ++++++++- 3 files changed, 43 insertions(+), 17 deletions(-) diff --git a/source/ecs/manager.d b/source/ecs/manager.d index 19d7cd1..3318d9e 100644 --- a/source/ecs/manager.d +++ b/source/ecs/manager.d @@ -69,7 +69,7 @@ export class EntityManager if(system.m_components)Mallocator.instance.dispose(system.m_components); if(system.m_excluded_components)Mallocator.instance.dispose(system.m_excluded_components); if(system.m_optional_components)Mallocator.instance.dispose(system.m_optional_components); - if(system.name)Mallocator.instance.dispose(system.name); + if(system.m_name)Mallocator.instance.dispose(system.m_name); if(system.m_event_callers)Mallocator.instance.dispose(system.m_event_callers); if(system.m_system_pointer)Mallocator.instance.dispose(system.m_system_pointer); @@ -344,20 +344,31 @@ export class EntityManager data_system.handleEvent(input, *cast(Type*) data.event); } - static void setEventCallers(Sys)(ref System system) + void setEventCallers(Sys)(ref System system) { enum event_handlers_num = __traits(getOverloads, Sys, "handleEvent").length; - system.m_event_callers = Mallocator.instance.makeArray!( - System.EventCaller)(event_handlers_num); + System.EventCaller[] callers = (cast(System.EventCaller*)alloca(event_handlers_num * System.EventCaller.sizeof))[0..event_handlers_num]; + int i = 0; foreach (j, func; __traits(getOverloads, Sys, "handleEvent")) { - alias EventParamType = Parameters!(__traits(getOverloads, - Sys, "handleEvent")[j])[1]; - system.m_event_callers[j].callback = cast( - void*)&callEventHandler!(EventParamType); - system.m_event_callers[j].id = EventParamType.event_id; + alias Params = Parameters!(__traits(getOverloads, + Sys, "handleEvent")[j]); + static if(Params.length == 2 && is(Params[0] == __traits(getMember, Sys, "EventInput"))) + { + alias EventParamType = Params[1]; + enum EventName = Unqual!(EventParamType).stringof; + ushort evt = events_map.get(cast(char[]) EventName, ushort.max); + assert(evt != ushort.max, "Can't register system \""~Sys.stringof~"\" due to non existing event \""~EventName~"\"."); + + callers[i].callback = cast( + void*)&callEventHandler!(EventParamType); + callers[i].id = EventParamType.event_id; + i++; + } } + + system.m_event_callers = Mallocator.instance.makeArray(callers[0..i]); } static if (__traits(hasMember, Sys, "handleEvent")) @@ -736,8 +747,8 @@ export class EntityManager } else { - system.name = Mallocator.instance.makeArray(Sys.stringof); - systems_map.add(system.name, cast(ushort) systems.length); + system.m_name = Mallocator.instance.makeArray(Sys.stringof); + systems_map.add(system.m_name, cast(ushort) systems.length); system.m_id = cast(ushort)(systems.length); @@ -2302,9 +2313,9 @@ export class EntityManager caller.exclusion = null; /*import std.stdio; - write("Exclusive systems for system ", caller.system.name, ": "); + write("Exclusive systems for system ", caller.system.m_name, ": "); foreach (ex; exclusion[0 .. index]) - write(ex.system.name, " "); + write(ex.system.m_name, " "); writeln();*/ } @@ -2362,9 +2373,9 @@ export class EntityManager caller.dependencies = null; /*import std.stdio; - write("Dependencies for system ", caller.system.name, ": "); + write("Dependencies for system ", caller.system.m_name, ": "); foreach (ex; caller.dependencies) - write(ex.system.name, " "); + write(ex.system.m_name, " "); writeln();*/ } } diff --git a/source/ecs/system.d b/source/ecs/system.d index e033147..b4ad780 100644 --- a/source/ecs/system.d +++ b/source/ecs/system.d @@ -74,6 +74,14 @@ struct System return m_id; } + /************************************************************************************************************************ + *Get system name. + */ + export const (char)[] name() nothrow @nogc + { + return cast(const (char)[])m_name; + } + struct EventCaller { ushort id; @@ -97,7 +105,7 @@ package: int m_pass; ///system name - char[] name; + char[] m_name; ///required components ushort[] m_components; diff --git a/tests/tests.d b/tests/tests.d index edd8b16..3cf3697 100644 --- a/tests/tests.d +++ b/tests/tests.d @@ -376,6 +376,11 @@ struct TestSystem2 //TestComp* tt; } + void handleEvent(EventInput input) + { + + } + void handleEvent(EventInput input, ref TestEvent event) { input.test.bg = event.a; @@ -571,9 +576,11 @@ int main() //foreach(j; 0..1_000)gEM.addEntity(tmpl); gEM.beginRegister(); - //gEM.registerSystem!TestSystem2(0); + gEM.registerSystem!TestSystem2(0); gEM.endRegister(); + System* sys = EntityManager.instance.getSystem(TestSystem2.system_id); + //gEM.generateDependencies(); //assert(*(cast(EntityID*)(cast(void*)tmpl.info.first_block+24)) == EntityID(1,1)); From 8318d2efb49a5b476fee2e535fa246f4b8fd690e Mon Sep 17 00:00:00 2001 From: Mergul Date: Sat, 10 Aug 2019 15:44:01 +0000 Subject: [PATCH 064/217] -added support for optional components in event handling --- source/ecs/manager.d | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/source/ecs/manager.d b/source/ecs/manager.d index 3318d9e..b5636b3 100644 --- a/source/ecs/manager.d +++ b/source/ecs/manager.d @@ -330,7 +330,10 @@ export class EntityManager "optional"); static if (is_optional) { - event_field = null; + if(info.deltas[EventFieldType.component_id] != 0)event_field = cast(EventFieldType*)(cast(void*) data.block + + info.deltas[EventFieldType.component_id] + + data.id * EventFieldType.sizeof); + else event_field = null; } else { From 1be08eb5345a0b63d24f9221ce9e16f557cbf6d4 Mon Sep 17 00:00:00 2001 From: Mergul Date: Sat, 10 Aug 2019 16:20:50 +0000 Subject: [PATCH 065/217] -added pure annotation for some functions -addEntity now returns pointer instead of reference (it's has more sense) -added function addEntityCopy(EntityID) which adds copy of entity with it's whole data --- source/ecs/manager.d | 106 +++++++++++++++++++++++++++++-------------- tests/tests.d | 43 +++++++++--------- 2 files changed, 94 insertions(+), 55 deletions(-) diff --git a/source/ecs/manager.d b/source/ecs/manager.d index b5636b3..6d01d6d 100644 --- a/source/ecs/manager.d +++ b/source/ecs/manager.d @@ -1056,7 +1056,7 @@ export class EntityManager m_dispatch_jobs = func; } - static void alignNum(ref ushort num, ushort alignment) nothrow @nogc + static void alignNum(ref ushort num, ushort alignment) nothrow @nogc pure { num = cast(ushort)((num + alignment - 1) & (-cast(int) alignment)); //num += alignment - (num & (alignment - 1)); } @@ -1459,10 +1459,7 @@ export class EntityManager new_entity.id = entity.id; new_entity.updateID(); - static if (EntityID.sizeof == 8) - uint ind = cast(uint)((cast(void*) entity - block.dataBegin()) >> 3); - else - uint ind = cast(uint)((cast(void*) entity - block.dataBegin()) / EntityID.sizeof()); + uint ind = block.entityIndex(entity); if (info.remove_listeners) { @@ -1636,10 +1633,7 @@ export class EntityManager uint j = 0; uint k = 0; - static if (EntityID.sizeof == 8) - uint ind = cast(uint)((cast(void*) entity - block.dataBegin()) >> 3); - else - uint ind = cast(uint)((cast(void*) entity - block.dataBegin()) / EntityID.sizeof()); + uint ind = block.entityIndex(entity); if (info.remove_listeners) { @@ -1761,12 +1755,66 @@ export class EntityManager } /************************************************************************************************************************ - *Add entity to system. + *Add copy of entity to system and returns pointer to it. Added copy has same data as copied entity. Returen pointer is + *valid only before one from commit(), begin() or end() will be called. To save entity to further use you should save ID + *instead of pointer. * *Params: *tmpl = pointer entity template allocated by EntityManager. */ - export ref Entity addEntity(EntityTemplate* tmpl) + export Entity* addEntityCopy(EntityID id) + { + Entity* entity = getEntity(id); + EntitiesBlock* block = getMetaData(entity); + EntityInfo* info = block.type_info; + + ushort index = block.entityIndex(entity); + + ushort new_index = 0; + EntitiesBlock* new_block; + do + { + new_block = findBlockWithFreeSpaceMT(info); + new_index = new_block.added_count.atomicOp!"+="(1); + } + while (new_block.entities_count + new_index > info.max_entities); + + ushort new_id = cast(ushort)(new_block.entities_count + new_index - 1); + const void* data_begin = new_block.dataBegin(); + const void* start = data_begin + EntityID.sizeof * new_id; + + foreach (i, comp; info.components) + { + memcpy(cast(void*) new_block + info.deltas[comp] + components[comp].size * new_id, + cast(void*) block + info.deltas[comp] + components[comp].size * index, components[comp].size); + + if (components[comp].create_callback) + { + components[comp].create_callback( + cast(void*) block + info.deltas[comp] + new_id * components[comp].size); + } + } + + if (new_index == 1) + threads[thread_id].blocks_to_update.add(new_block); + + Entity* new_entity = cast(Entity*) start; + //add_mutex.lock_nothrow(); + new_entity.id = id_manager.getNewID(); + //add_mutex.unlock_nothrow(); + new_entity.updateID(); + + return new_entity; + } + + /************************************************************************************************************************ + *Add entity to system. Returen pointer is valid only before one from commit(), begin() or end() will be called. To save entity to further + *use you should save ID instead of pointer. + * + *Params: + *tmpl = pointer entity template allocated by EntityManager. + */ + export Entity* addEntity(EntityTemplate* tmpl) { EntityInfo* info = tmpl.info; @@ -1806,7 +1854,7 @@ export class EntityManager //add_mutex.unlock_nothrow(); entity.updateID(); - return *entity; + return entity; } /************************************************************************************************************************ @@ -1903,11 +1951,7 @@ export class EntityManager EntityInfo* info = block.type_info; if (info.remove_listeners) { - void* data_begin = block.dataBegin(); - static if (EntityID.sizeof == 8) - uint pos = cast(uint)((cast(void*) entity - data_begin) >> 3); - else - uint pos = cast(uint)((cast(void*) entity - data_begin) / EntityID.sizeof()); + uint pos = block.entityIndex(entity); callRemoveEntityListeners(info, block, pos, pos + 1); } @@ -1920,16 +1964,11 @@ export class EntityManager private void removeEntityNoID(Entity* entity, EntitiesBlock* block, bool call_destructors = false) nothrow @nogc { - //pos is Entity number in block - void* data_begin = block.dataBegin(); EntityInfo* info = block.type_info; info.last_block.entities_count--; - static if (EntityID.sizeof == 8) - uint pos = cast(uint)((cast(void*) entity - data_begin) >> 3); - else - uint pos = cast(uint)((cast(void*) entity - data_begin) / EntityID.sizeof()); + uint pos = block.entityIndex(entity); if (call_destructors) { @@ -2173,14 +2212,7 @@ export class EntityManager EntityID entity_id = *cast(EntityID*) event_pointer; Entity* entity = id_manager.getEntityPointer(entity_id); call_data.block = getMetaData(entity); - - static if (EntityID.sizeof == 8) - call_data.id = cast(ushort)( - (cast(void*) entity - call_data.block.dataBegin()) >> 3); - else - call_data.id = cast(ushort)( - (cast(void*) entity - call_data.block.dataBegin()) / EntityID - .sizeof); + call_data.id = call_data.block.entityIndex(entity); foreach (caller; events[i].callers) { @@ -2580,7 +2612,7 @@ export class EntityManager struct EntitiesBlock { ///return distance (in bytes) from begin of block to data - export uint dataDelta() nothrow @nogc + export uint dataDelta() nothrow @nogc pure { ushort dif = EntitiesBlock.sizeof; alignNum(dif, type_info.alignment); @@ -2588,12 +2620,20 @@ export class EntityManager } ///return pointer to first element in block - export void* dataBegin() nothrow @nogc + export void* dataBegin() nothrow @nogc pure { ushort dif = EntitiesBlock.sizeof; return cast(void*)&this + dif; } + export ushort entityIndex(Entity* entity) nothrow @nogc pure + { + static if (EntityID.sizeof == 8) + return cast(ushort)((cast(void*) entity - dataBegin()) >> 3); + else + return cast(ushort)((cast(void*) entity - dataBegin()) / EntityID.sizeof()); + } + ///pointer to Entity type info EntityInfo* type_info = null; ///number of entities in block diff --git a/tests/tests.d b/tests/tests.d index 3cf3697..1b7e47b 100644 --- a/tests/tests.d +++ b/tests/tests.d @@ -526,13 +526,13 @@ int main() dur = (MonoTime.currTime - time).total!"usecs"; writeln("Template allocating: ", dur, " usecs"); - Entity entity; + EntityID entity; { - entity = gEM.addEntity(tmpl); - writeEntityComponents(gEM.getEntity(entity.id)); + entity = gEM.addEntity(tmpl).id; + writeEntityComponents(gEM.getEntity(entity)); EntityManager.EntitiesBlock* block = EntityManager.instance.getMetaData( - gEM.getEntity(entity.id)); + gEM.getEntity(entity)); EntityManager.EntityInfo* info = block.type_info; writeln(info.add_listeners); //if(info)assert(0); @@ -586,15 +586,15 @@ int main() //assert(*(cast(EntityID*)(cast(void*)tmpl.info.first_block+24)) == EntityID(1,1)); //assert(*(cast(EntityID*)(cast(void*)tmpl.info.first_block+48)) == EntityID(1,1)); - Entity entity2; + EntityID entity2; time = MonoTime.currTime; EntityID[] entities = Mallocator.instance.makeArray!EntityID(1_000_000); foreach (i; 0 .. 500_000) { - entity2 = gEM.addEntity(tmpl); - entities[i*2] = entity2.id; + entity2 = gEM.addEntity(tmpl).id; + entities[i*2] = entity2; entities[i*2+1] = gEM.addEntity(tmpl2).id; } @@ -638,7 +638,7 @@ int main() dur = (MonoTime.currTime - time).total!"usecs"; writeln("Update: ", dur, " usecs"); - writeEntityComponents(gEM.getEntity(entity2.id)); + writeEntityComponents(gEM.getEntity(entity2)); time = MonoTime.currTime; @@ -650,7 +650,7 @@ int main() dur = (MonoTime.currTime - time).total!"usecs"; writeln("Update: ", dur, " usecs"); - writeEntityComponents(gEM.getEntity(entity2.id)); + writeEntityComponents(gEM.getEntity(entity2)); time = MonoTime.currTime; @@ -662,9 +662,9 @@ int main() dur = (MonoTime.currTime - time).total!"usecs"; writeln("Update: ", dur, " usecs"); - writeEntityComponents(gEM.getEntity(entity2.id)); + writeEntityComponents(gEM.getEntity(entity2)); - entity = gEM.addEntity(tmpl); + entity = gEM.addEntity(tmpl).id; gEM.begin(); gEM.update(); @@ -672,40 +672,39 @@ int main() //Entity* pp;// = gEM.getEntity(entity.id); //writeln((cast(uint*) pp)[0 .. 14], " ", pp); - writeEntityComponents(gEM.getEntity(entity.id)); + writeEntityComponents(gEM.getEntity(entity)); gEM.addEntity(tmpl); + gEM.addEntityCopy(entity); - gEM.addComponents(entity.id, TestComp4()); - gEM.addComponents(entity.id, TestComp3()); + gEM.addComponents(entity, TestComp4()); + gEM.addComponents(entity, TestComp3()); gEM.begin(); gEM.update(); gEM.end(); - writeEntityComponents(gEM.getEntity(entity.id)); + writeEntityComponents(gEM.getEntity(entity)); - gEM.removeComponents!(TestComp)(entity.id); - gEM.addComponents(entity.id, TestComp()); - gEM.addComponents(entity.id, TestComp5()); + gEM.removeComponents!(TestComp)(entity); + gEM.addComponents(entity, TestComp()); + gEM.addComponents(entity, TestComp5()); gEM.begin(); gEM.update(); gEM.update("fixed"); gEM.end(); - gEM.removeComponents!(TestComp4)(entity.id); + gEM.removeComponents!(TestComp4)(entity); gEM.commit();//*/ - writeEntityComponents(gEM.getEntity(entity.id)); + writeEntityComponents(gEM.getEntity(entity)); //import std.stdio; //writeln((cast(uint*)tmpl.info.first_block)[0..48]); gEM.freeTemplate(tmpl); gEM.freeTemplate(tmpl2); EntityManager.destroy(); - - return 0; } From 9402e917f239fbb18fb01dfc9b6a4a7210f6707d Mon Sep 17 00:00:00 2001 From: Mergul Date: Sat, 10 Aug 2019 16:32:57 +0000 Subject: [PATCH 066/217] -added function to create EntityTemplate form Entity --- source/ecs/manager.d | 39 +++++++++++++++++++++++++++++++++++++++ tests/tests.d | 10 +++++++++- 2 files changed, 48 insertions(+), 1 deletion(-) diff --git a/source/ecs/manager.d b/source/ecs/manager.d index 6d01d6d..4523e4e 100644 --- a/source/ecs/manager.d +++ b/source/ecs/manager.d @@ -1073,6 +1073,45 @@ export class EntityManager return 1; } + /************************************************************************************************************************ + *Allocate EntityTemplate with all components from entity witch it's data and returns pointer to it. + * + *Params: + *id = ID of entity from which should be created template + *fill_default = if true, components will be filled with default data, instead entity data will be taken + */ + export EntityTemplate* allocateTemplate(EntityID entity_id, bool fill_default = false) + { + Entity* entity = getEntity(entity_id); + EntitiesBlock* block = getMetaData(entity); + EntityInfo* info = block.type_info; + + EntityTemplate* temp = Mallocator.instance.make!EntityTemplate; + temp.entity_data = Mallocator.instance.makeArray!ubyte(info.size); + temp.info = info; + + if(fill_default) + { + //fill components with default data + foreach (comp; info.components) + { + temp.entity_data[info.tmpl_deltas[comp] .. info.tmpl_deltas[comp] + components[comp].size] + = components[comp].init_data; + } + } + else + { + ushort index = block.entityIndex(entity); + foreach (comp; info.components) + { + memcpy(cast(void*) temp.entity_data + info.tmpl_deltas[comp], + cast(void*) block + info.deltas[comp] + components[comp].size * index, components[comp].size); + } + } + + return temp; + } + /************************************************************************************************************************ *Allocate EntityTemplate with specifed components and returns pointer to it. * diff --git a/tests/tests.d b/tests/tests.d index 1b7e47b..4c41220 100644 --- a/tests/tests.d +++ b/tests/tests.d @@ -674,8 +674,14 @@ int main() //writeln((cast(uint*) pp)[0 .. 14], " ", pp); writeEntityComponents(gEM.getEntity(entity)); + writeln("Entity, its copy, and template, and default filled tempalte"); gEM.addEntity(tmpl); - gEM.addEntityCopy(entity); + writeEntityComponents(gEM.getEntity(entity)); + writeEntityComponents(gEM.addEntityCopy(entity)); + EntityTemplate* copy_tempalte = gEM.allocateTemplate(entity); + writeEntityComponents(gEM.addEntity(copy_tempalte)); + EntityTemplate* copy_default_tempalte = gEM.allocateTemplate(entity,true); + writeEntityComponents(gEM.addEntity(copy_default_tempalte)); gEM.addComponents(entity, TestComp4()); gEM.addComponents(entity, TestComp3()); @@ -704,6 +710,8 @@ int main() //writeln((cast(uint*)tmpl.info.first_block)[0..48]); gEM.freeTemplate(tmpl); gEM.freeTemplate(tmpl2); + gEM.freeTemplate(copy_tempalte); + gEM.freeTemplate(copy_default_tempalte); EntityManager.destroy(); return 0; From beab56033c34b783df8e761abd9f69763b96c4e1 Mon Sep 17 00:00:00 2001 From: Mergul Date: Tue, 13 Aug 2019 11:13:26 +0000 Subject: [PATCH 067/217] -events are simplified to handleEvent(Entity*,Event) (use entity.getComponent to get entity components) --- source/ecs/manager.d | 25 +++++++++++++++++++------ tests/tests.d | 16 +++++++++------- 2 files changed, 28 insertions(+), 13 deletions(-) diff --git a/source/ecs/manager.d b/source/ecs/manager.d index 4523e4e..4c30c10 100644 --- a/source/ecs/manager.d +++ b/source/ecs/manager.d @@ -304,9 +304,9 @@ export class EntityManager { static void callEventHandler(Type)(ref EventCallData data) { - Sys.EventInput input; + //Sys.EventInput input; Sys* data_system = cast(Sys*) data.system_pointer; - EntityInfo* info = data.block.type_info; + /*EntityInfo* info = data.block.type_info; alias EventFields = Fields!(Sys.EventInput); foreach (ref event_field; input.tupleof) @@ -343,8 +343,9 @@ export class EntityManager } } - } - data_system.handleEvent(input, *cast(Type*) data.event); + }//*/ + Type* event = cast(Type*) data.event; + data_system.handleEvent(/*input, */gEM.getEntity(event.entity_id), *event); } void setEventCallers(Sys)(ref System system) @@ -357,7 +358,19 @@ export class EntityManager { alias Params = Parameters!(__traits(getOverloads, Sys, "handleEvent")[j]); - static if(Params.length == 2 && is(Params[0] == __traits(getMember, Sys, "EventInput"))) + /*static if(Params.length == 2 && is(Params[0] == __traits(getMember, Sys, "EventInput"))) + { + alias EventParamType = Params[1]; + enum EventName = Unqual!(EventParamType).stringof; + ushort evt = events_map.get(cast(char[]) EventName, ushort.max); + assert(evt != ushort.max, "Can't register system \""~Sys.stringof~"\" due to non existing event \""~EventName~"\"."); + + callers[i].callback = cast( + void*)&callEventHandler!(EventParamType); + callers[i].id = EventParamType.event_id; + i++; + }*/ + static if(Params.length == 2 && is(Params[0] == Entity*)) { alias EventParamType = Params[1]; enum EventName = Unqual!(EventParamType).stringof; @@ -389,9 +402,9 @@ export class EntityManager static struct ComponentsIndices { CompInfo[] readonly; + CompInfo[] mutable; CompInfo[] excluded; CompInfo[] optional; - CompInfo[] mutable; CompInfo[] req; string entites_array; } diff --git a/tests/tests.d b/tests/tests.d index 4c41220..30810e2 100644 --- a/tests/tests.d +++ b/tests/tests.d @@ -376,22 +376,24 @@ struct TestSystem2 //TestComp* tt; } - void handleEvent(EventInput input) + /*void handleEvent(EventInput input) { - } + }*/ - void handleEvent(EventInput input, ref TestEvent event) + void handleEvent(/*EventInput input, */Entity* entity, ref TestEvent event) { - input.test.bg = event.a; + TestComp3* test = entity.getComponent!TestComp3; + test.bg = event.a; TestEvent2 event2; event2.a = event.a + 8; - gEM.sendEvent(input.entity.id, event2); + gEM.sendEvent(entity.id, event2); } - void handleEvent(EventInput input, ref TestEvent2 event) + void handleEvent(/*EventInput input, */Entity* entity, ref TestEvent2 event) { - input.test.gg = cast(uint) event.a; + TestComp3* test = entity.getComponent!TestComp3; + test.gg = cast(uint) event.a; } void onEnable() From ebec25633ef09b79cdb11ceddb062d9aa7af59d8 Mon Sep 17 00:00:00 2001 From: Mergul Date: Tue, 13 Aug 2019 11:58:01 +0000 Subject: [PATCH 068/217] -now event handler system does not have to has EventInput structure --- source/ecs/manager.d | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/ecs/manager.d b/source/ecs/manager.d index 4c30c10..e7bbb8a 100644 --- a/source/ecs/manager.d +++ b/source/ecs/manager.d @@ -300,7 +300,7 @@ export class EntityManager static assert(0, "System should gave \"EntitiesData\" struct for input components"); } - static if (hasMember!(Sys, "EventInput")) + static if (hasMember!(Sys, "handleEvent")) { static void callEventHandler(Type)(ref EventCallData data) { From 49a60d33c5348d825fd95a883111d25aec8d1c3f Mon Sep 17 00:00:00 2001 From: Mergul Date: Wed, 14 Aug 2019 11:00:21 +0200 Subject: [PATCH 069/217] -fixed events thread safety --- source/ecs/events.d | 16 ++++++++++++++++ source/ecs/manager.d | 1 + 2 files changed, 17 insertions(+) diff --git a/source/ecs/events.d b/source/ecs/events.d index 47d9415..b2bd8cc 100644 --- a/source/ecs/events.d +++ b/source/ecs/events.d @@ -8,6 +8,7 @@ import std.experimental.allocator; import std.experimental.allocator.mallocator : AlignedMallocator, Mallocator; import std.algorithm.comparison : max; +import core.sync.mutex; /*struct Event { @@ -73,9 +74,15 @@ struct EventManager void initialize(EntityManager m) nothrow @nogc { allocator = BlockAllocator(events_block_size, events_blocks_in_allocation); + event_block_alloc_mutex = Mallocator.instance.make!Mutex; manager = m; } + void destroy() + { + Mallocator.instance.dispose(event_block_alloc_mutex); + } + export void sendEvent(Ev)(EntityID id, Ev event, uint thread_id = 0) nothrow @nogc { uint block_id = current_index+thread_id; @@ -87,6 +94,10 @@ struct EventManager if(block is null) { + event_block_alloc_mutex.lock_nothrow(); + scope (exit) + event_block_alloc_mutex.unlock_nothrow(); + block = cast(EventBlock*) allocator.getBlock(); *block = EventBlock(); data.first_blocks[block_id] = block; @@ -95,6 +106,10 @@ struct EventManager if(block.count >= data.max_events) { + event_block_alloc_mutex.lock_nothrow(); + scope (exit) + event_block_alloc_mutex.unlock_nothrow(); + EventBlock* new_block = cast(EventBlock*) allocator.getBlock(); *new_block = EventBlock(); block.next = new_block; @@ -265,6 +280,7 @@ struct EventManager EventList process_events;*/ uint current_index = 0; EventData[] events; + Mutex event_block_alloc_mutex; BlockAllocator/*!(events_block_size, events_blocks_in_allocation)*/ allocator; EntityManager manager; diff --git a/source/ecs/manager.d b/source/ecs/manager.d index 19d7cd1..a96a699 100644 --- a/source/ecs/manager.d +++ b/source/ecs/manager.d @@ -253,6 +253,7 @@ export class EntityManager ~this() { id_manager.deinitialize(); + event_manager.destroy(); if(threads)Mallocator.instance.dispose(threads); if(entity_block_alloc_mutex)Mallocator.instance.dispose(entity_block_alloc_mutex); From 41f1c6474bfcc520c4de68dcdc96756d7760518b Mon Sep 17 00:00:00 2001 From: Mergul Date: Thu, 10 Oct 2019 20:56:44 +0200 Subject: [PATCH 070/217] -fully working betterC for windows *replaced array[..] = array[ .. ] sclice copy with mempcy *added own std library (allocator, alloca, Mutex) *changed tamplates for collecting components for systems -fixed issue with multiple optional components registering for system --- dub.json | 32 +++ source/ecs/block_allocator.d | 15 +- source/ecs/core.d | 15 - source/ecs/ecs.d | 339 ---------------------- source/ecs/events.d | 139 ++------- source/ecs/hash_map.d | 7 +- source/ecs/id_manager.d | 48 ++-- source/ecs/manager.d | 530 ++++++++++++++++------------------- source/ecs/simple_vector.d | 14 +- source/ecs/std.d | 227 +++++++++++++++ source/ecs/system.d | 12 +- source/ecs/vector.d | 11 +- source/win_dll.d | 5 +- tests/tests.d | 196 ++++++++----- 14 files changed, 722 insertions(+), 868 deletions(-) delete mode 100644 source/ecs/ecs.d create mode 100644 source/ecs/std.d diff --git a/dub.json b/dub.json index bebf2ff..4f1f32c 100755 --- a/dub.json +++ b/dub.json @@ -40,6 +40,38 @@ "-Hdimport/", "-op" ] + }, + { + "name" : "library-betterC", + "targetType" : "library", + "excludedSourceFiles":[ + "source\/win_dll.d" + ], + "dflags": [ + "-betterC", + "-defaultlib=" + ] + }, + { + "name" : "dynlib-betterC", + "targetType" : "dynamicLibrary", + "dflags": [ + "-betterC", + "-defaultlib=", + "--fvisibility=hidden" + ] + }, + { + "name" : "tests-betterC", + "targetType" : "executable", + "sourcePaths" : ["source\/","tests\/"], + "excludedSourceFiles":[ + "source\/win_dll.d" + ], + "dflags": [ + "-betterC", + "-defaultlib=" + ] } ] } \ No newline at end of file diff --git a/source/ecs/block_allocator.d b/source/ecs/block_allocator.d index 2894f61..abb7856 100644 --- a/source/ecs/block_allocator.d +++ b/source/ecs/block_allocator.d @@ -1,9 +1,10 @@ module ecs.block_allocator; import ecs.manager; - +import ecs.std; +/* import std.experimental.allocator; -import std.experimental.allocator.mallocator : AlignedMallocator, Mallocator; +import std.experimental.allocator.mallocator : AlignedMallocator, Mallocator;*/ struct BlockAllocator//(uint block_size, uint blocks_in_allocation) { @@ -37,13 +38,13 @@ struct BlockAllocator//(uint block_size, uint blocks_in_allocation) private void allocBlock() nothrow @nogc { - next_block = cast(void*) AlignedMallocator.instance.alignedAllocate( + next_block = cast(void*) Mallocator.alignAlloc( block_size * blocks_in_allocation, block_size); - if(pointers is null)pointers = Mallocator.instance.make!BlockPointers; + if(pointers is null)pointers = Mallocator.make!BlockPointers; if(pointers.numberof >= 32) { - BlockPointers* new_pointers = Mallocator.instance.make!BlockPointers; + BlockPointers* new_pointers = Mallocator.make!BlockPointers; new_pointers.next_pointers = pointers; pointers = new_pointers; } @@ -65,10 +66,10 @@ struct BlockAllocator//(uint block_size, uint blocks_in_allocation) { foreach(i;0..pointers.numberof) { - AlignedMallocator.instance.dispose(pointers.blocks[i]); + Mallocator.alignDispose(pointers.blocks[i]); } BlockPointers* next_pointers = pointers.next_pointers; - Mallocator.instance.dispose(pointers); + Mallocator.dispose(pointers); pointers = next_pointers; } } diff --git a/source/ecs/core.d b/source/ecs/core.d index 64dceba..431f57b 100644 --- a/source/ecs/core.d +++ b/source/ecs/core.d @@ -9,21 +9,6 @@ static struct ECS { __gshared ushort system_id; uint __ecs_jobs_count = jobs_count; - /*EntityManager.Job[] _ecs_jobs; - - void __ecsInitialize() nothrow @nogc - { - import std.experimental.allocator.mallocator; - import std.experimental.allocator; - _ecs_jobs = Mallocator.instance.makeArray!(EntityManager.Job)(jobs_count); - } - - void __ecsDeinitialize() nothrow @nogc - { - import std.experimental.allocator.mallocator; - import std.experimental.allocator; - Mallocator.instance.dispose(_ecs_jobs); - }*/ } mixin template Component() diff --git a/source/ecs/ecs.d b/source/ecs/ecs.d deleted file mode 100644 index 60d0f6a..0000000 --- a/source/ecs/ecs.d +++ /dev/null @@ -1,339 +0,0 @@ -module ecs.ecs; - -import std.stdio; - -version(Design): - -alias SytemFuncType = void function(ref SystemCallData data, void* componentsStart); - -struct HasComponentsStore -{ - ulong[4] bits; //256 components - - bool has(HasComponentsStore components) - { - return true; - } - - bool notIn(HasComponentsStore components) - { - return true; - } - - int length() - { - assert(0); - } -} - -// Informacje o kompnencie -struct ComponentInfo -{ - int size; - int aligment; - SerializeJSON funsSerJ; - SerializeBiN funcSerB; -} - -struct System -{ - HasComponentsStore requiredComponents; - HasComponentsStore absenComponents; - HasComponentsStore maybeComponents; - bool enabled; - int priority; - SytemFuncType func; -} -// Informacje o systemie dla konkretnego entitiesa -struct SystemCallData -{ - System* system; - int[] componentsDt; -} - -// Informacje o entitiesie danego typu -struct EntityTypeData -{ - HasComponentsStore components; - int[] deltas; - int totalSize; - int totalAligment = 8; - SystemCallData[] systems; -} - -struct EntitiesBlock -{ - EntityTypeData* typeData; - Entity* freeEntitySlot; - EntitiesBlock* nextBlock; -} - -struct EntityID -{ - ulong id = ulong.max; - static immutable notUsedValue = EntityID(ulong.max); -} - -// Dane konkretnego Entitiesa -struct Entity -{ - EntityID entityID = EntityID.notUsedValue; - union - { - string name; - Entity* nextFreeSlot; - } - - //string eventOnDestroy; - uint group; - EntityID entityID; - //ubyte[XX] thereIsComponentsMemory; -} - -struct Template -{ - HasComponentsStore hasComp; - Entity* entity; -} - -struct Manager -{ - EntityAllocator entityArrayAllcoator; - - ComponentInfo[] components; - System[] systems; - HashMap!(HasComponentsStore, EntitiesBlock*) entitiesDatas; - HashMapTwoWays!(string, Entity*) nameMap; - HashMapTwoWays!(EntityID, Entity*) idMap; - - EntitiesBlock* getEntitiesBlock(HasComponentsStore hasComponents) - { - EntitiesBlock* block = entitiesDatas.get(hasComponents, null); - if (block is null) - { - // If such component combination was never present, add it - block = addNewBlock(hasComponents, block); - return block; - } - // Iterate over list of components until free slot is found or lists ends - do - { - if (block.freeEntitySlot !is null) - { - return block; - } - if (block.nextBlock is null) - { - block = addNewBlock(hasComponents); - return block; - } - block = block.nextBlock; - } - while (block.nextBlock !is null); - - } - - EntitiesBlock* addNewBlock(HasComponentsStore hasComponents, EntitiesBlock* firstBlock) - { - // Get last block so order of blocks is preserved, and first blocks are filled first - EntitiesBlock* lastBlock = firstBlock; - if (lastBlock !is null) - { - while (lastBlock.nextBlock !is null) - { - lastBlock = lastBlock.nextBlock; - } - } - assert(lastBlock is null || lastBlock.nextBlock is null); - - ubyte[] memory = new ubyte[](4096); - EntitiesBlock* block = cast(EntitiesBlock*) memory.ptr; - if (lastBlock is null) - { - EntityTypeData* entityTypeData = newEntityTypeData(hasComponents); - block.typeData = entityTypeData; - block.nextBlock = null; - entitiesDatas.add(hasComponents, block); - } - else - { - lastBlock.nextBlock = block; - block.typeData = lastBlock.typeData; - block.nextBlock = null; - } - } - - void alignNum(ref int num, int aligment) - { - int reminder = num % aligment; - if (reminder != 0) - { - num += aligment - reminder; - } - } - - EntityTypeData* newEntityTypeData(HasComponentsStore hasComponents) - { - EntityTypeData* typeData = new EntityTypeData(); - typeData.components = hasComponents; - ComponentInfo[] components = getComponentsInfo(hasComponents); - typeData.deltas.length = hasComponents.length; - - foreach (i, comp; components) - { - typeData.deltas[i] = typeData.totalSize; - typeData.totalAligment.max(comp.aligment); - typeData.totalSize += comp.size; - alignNum(typeData.totalSize, comp.aligment); - } - alignNum(typeData.totalSize, typeData.totalAligment); - - foreach (sys; systems) - { - if (!typeData.hasComp.has(sys.requiredComponents) - || !typeData.hasComp.notIn(sys.absenComponents)) - { - continue; - } - entTypeData.systems ~= sys; - } - - return typeData; - } - - void addEntity(Template* templ) - { - EntitiesBlock* block = getEntitiesBlock(templ.hasComp); - Entity* newEntity = block.freeEntitySlot; - block.freeEntitySlot = newEntity.nextFreeSlot; - // from to size - memcpy(temp.entity, newEntity, block.typeData.totalSize); - } - - void addSystem(Func)(int priority) - { - HasComponentsStore requiredComponents; - HasComponentsStore absenComponents; - HasComponentsStore maybeComponents; - - void systemCaller(ref SystemCallData data, void * componentsStart) - { - Func(cast(FUnc.par1Type)(componentsStart + data.componentsDt[0]), - cast(FUnc.par1Type)(componentsStart + data.componentsDt[1])/*...*/); - } - System* system = new System(&systemCaller, entTypeData); - systems ~= system; - - foreach (ref entTypeData; entitiesDatas) - { - if (!entTypeData.hasComp.has(requiredComponents) - || !entTypeData.hasComp.notIn(absenComponents)) - { - continue; - } - entTypeData.systems ~= system; - } - } -} - -void someSystem(CompA a, CompB b, CompC* c) -{ -} - -void main() -{ - writeln("Edit source/app.d to start your project."); -} - -class System -{ - - void start() - { - - } - - void end() - { - - } - - void update(ref ObjRend a) - { - - } - - void useEvent(EventData evvv, ref ObjRend a) - { - - } -} - -alias SerializeVector = ubyte[]; - -__gshared EntityManager gEntityManager; - -unittest -{ - struct ComponentA - { - __gshared static int component_id; - int a; - ulong b; - - static void serializeComponent(ref ComponentA comp, SerializeVector output) - { - - } - - static void deerializeComponent(ref ComponentA comp, ubyte[] data) - { - - } - - } - - gEM.addComponet!ComponentA(); - assert(ComponentA.component_id == 0); - ComponentData* ccc = &gEM.componnets[ComponentA.component_id]; - assert(ccc.totalAligment == 8); - assert(ccc.totalSize == 8); - - HasComponentsStore hasComponents; - hasComponents.addComponet(ComponentA.component_id); - EntityTempalte* tmpl = gEM.allocateTemplate(hasComponents); - - ComponentA* comp = tmpl.getComponent!ComponentA(ComponentA.component_id); - comp.a = 111; - comp.b = 222; - - gEM.addEntity(tmpl); - - struct SystemAdd - { - void update(ref ComponentA a) - { - a.a+=1000; - b.b+=2000; - - } - - void handleEvent(EventData evvv, ref ComponentA a) - { - } - } - - int priority=10; - gEM.registerSystem!(SystemAdd)(priority); - gEM.updateStepAll(); - foreach(EntityID id; gEM.IterateByAllEntiteis){ - assert(id.getComponent(ComponentA.component_id)); - ComponentA* ccc=id.getComponent(ComponentA.component_id); - assert(ccc.a==1111); - assert(ccc.b==2222); - } - - - -} - diff --git a/source/ecs/events.d b/source/ecs/events.d index b2bd8cc..b7fa8ed 100644 --- a/source/ecs/events.d +++ b/source/ecs/events.d @@ -3,12 +3,13 @@ module ecs.events; import ecs.manager; import ecs.block_allocator; import ecs.entity; - +import ecs.std; +/* import std.experimental.allocator; -import std.experimental.allocator.mallocator : AlignedMallocator, Mallocator; +import std.experimental.allocator.mallocator : AlignedMallocator, Mallocator;*/ import std.algorithm.comparison : max; -import core.sync.mutex; +//import core.sync.mutex; /*struct Event { @@ -20,67 +21,22 @@ import core.sync.mutex; struct EventManager { - //@disable this(); - - /*this(EntityManager m) - { - manager = m; - }*/ - - /*void sendSelfEvent(Ev)(EntityID id, Ev event) - { - ushort size = cast(ushort)(Ev.sizeof); // + EntityID.sizeof + ushort.sizeof); - ushort alignment = cast(ushort)(Ev.alignof); - - EventList* list = &process_events; - - if (list.current_block is null) - { - list.current_block = cast(EventBlock*) allocator.getBlock(); - list.first_block = list.current_block; - list.current_block.index = cast(ushort)((void*).sizeof + ushort.sizeof); - } - - ushort index = cast(ushort)( - list.current_block.index + ushort.sizeof + EntityID.sizeof + ushort.sizeof); - - ushort aligned_index = index; //cast(ushort)(list.current_block.index); - alignNum(aligned_index, alignment); - - if (aligned_index + Ev.sizeof > events_block_size) - { - list.current_block.next = cast(EventBlock*) allocator.getBlock(); - list.current_block = list.current_block.next; - list.current_block.index = cast(ushort)((void*).sizeof + ushort.sizeof); - - index = cast(ushort)((void*) - .sizeof + ushort.sizeof + ushort.sizeof + EntityID.sizeof + ushort.sizeof); // + EntityID.sizeof + ushort.sizeof; - - aligned_index = index; - alignNum(aligned_index, alignment); - } - - EventBlock* block = list.current_block; - - ushort align_ = cast(ushort)(aligned_index - index); - *cast(ushort*)&block.data[block.index] = align_; - index = cast(ushort)(aligned_index - (EntityID.sizeof + ushort.sizeof)); - *cast(ushort*)&block.data[index] = Ev.event_id; - *cast(EntityID*)&block.data[index + 2] = id; - *cast(Ev*)&block.data[aligned_index] = event; - block.index = cast(ushort)(aligned_index + Ev.sizeof); - }*/ - - void initialize(EntityManager m) nothrow @nogc + void initialize(EntityManager* m) nothrow @nogc { allocator = BlockAllocator(events_block_size, events_blocks_in_allocation); - event_block_alloc_mutex = Mallocator.instance.make!Mutex; + event_block_alloc_mutex = Mallocator.make!Mutex; + event_block_alloc_mutex.initialize(); manager = m; } - void destroy() + void destroy() nothrow @nogc { - Mallocator.instance.dispose(event_block_alloc_mutex); + if(event_block_alloc_mutex) + { + event_block_alloc_mutex.destroy(); + Mallocator.dispose(event_block_alloc_mutex); + event_block_alloc_mutex = null; + } } export void sendEvent(Ev)(EntityID id, Ev event, uint thread_id = 0) nothrow @nogc @@ -94,9 +50,9 @@ struct EventManager if(block is null) { - event_block_alloc_mutex.lock_nothrow(); + event_block_alloc_mutex.lock(); scope (exit) - event_block_alloc_mutex.unlock_nothrow(); + event_block_alloc_mutex.unlock(); block = cast(EventBlock*) allocator.getBlock(); *block = EventBlock(); @@ -106,9 +62,9 @@ struct EventManager if(block.count >= data.max_events) { - event_block_alloc_mutex.lock_nothrow(); + event_block_alloc_mutex.lock(); scope (exit) - event_block_alloc_mutex.unlock_nothrow(); + event_block_alloc_mutex.unlock(); EventBlock* new_block = cast(EventBlock*) allocator.getBlock(); *new_block = EventBlock(); @@ -117,9 +73,6 @@ struct EventManager data.blocks[block_id] = block; } - /*void* start = cast(void*)block + data.data_offset + block.count * info.size; - Ev* event_ptr = cast(Ev*)start; - *event_ptr = event;*/ Ev* event_array = cast(Ev*)(cast(void*)block + data.data_offset); event_array[block.count] = event; block.count++; @@ -172,30 +125,16 @@ struct EventManager block = null; } } - /*EventList tmp = current_events; - current_events = process_events; - process_events = tmp; - - EventBlock* block = process_events.first_block; - - while (block) - { - EventBlock* free = block; - block = block.next; - allocator.freeBlock(free); - } - process_events.first_block = null; - process_events.current_block = null;*/ } void allocateData(uint threads_count) nothrow @nogc { disposeData(); - events = Mallocator.instance.makeArray!EventData(gEM.events.length); + events = Mallocator.makeArray!EventData(gEM.events.length); foreach(i,ref event;events) { - event.blocks = Mallocator.instance.makeArray!(EventBlock*)(threads_count*2); - event.first_blocks = Mallocator.instance.makeArray!(EventBlock*)(threads_count*2); + event.blocks = Mallocator.makeArray!(EventBlock*)(threads_count*2); + event.first_blocks = Mallocator.makeArray!(EventBlock*)(threads_count*2); event.data_offset = EventBlock.sizeof;//gEM.events[i]. gEM.alignNum(event.data_offset, gEM.events[i].alignment); @@ -216,16 +155,16 @@ struct EventManager if(block)next_block = first_block.next; while(block) { - Mallocator.instance.dispose(block); + Mallocator.dispose(block); block = next_block; if(block)next_block = block.next; } } - Mallocator.instance.dispose(event.blocks); - Mallocator.instance.dispose(event.first_blocks); + Mallocator.dispose(event.blocks); + Mallocator.dispose(event.first_blocks); } - Mallocator.instance.dispose(events); + Mallocator.dispose(events); } allocator.freeMemory(); } @@ -233,10 +172,6 @@ struct EventManager ~this() nothrow @nogc { disposeData(); - /*foreach(i,ref event;events) - { - EventBlock* block = event.first_blocks; - }*/ } ///Single page size. Must be power of two. @@ -246,26 +181,10 @@ struct EventManager struct EventBlock { - /*union - { - struct - { - EventBlock* next; - ushort index = 2; - } - - ubyte[events_block_size] data; - }*/ EventBlock* next; ushort count = 0; } - /*struct EventList - { - EventBlock* first_block; - EventBlock* current_block; - }*/ - struct EventData { ushort data_offset; @@ -276,12 +195,10 @@ struct EventManager //EventBlock*[] current_blocks; } - /*EventList current_events; - EventList process_events;*/ uint current_index = 0; EventData[] events; - Mutex event_block_alloc_mutex; + Mutex* event_block_alloc_mutex; - BlockAllocator/*!(events_block_size, events_blocks_in_allocation)*/ allocator; - EntityManager manager; + BlockAllocator allocator; + EntityManager* manager; } diff --git a/source/ecs/hash_map.d b/source/ecs/hash_map.d index 4f25394..f6d1642 100755 --- a/source/ecs/hash_map.d +++ b/source/ecs/hash_map.d @@ -30,6 +30,7 @@ export ulong hashInt(ulong x) nothrow @nogc @safe { struct HashMap(KeyPar, ValuePar, alias hashFunc = defaultHashFunc) { alias Key = KeyPar; alias Value = ValuePar; + nothrow: enum rehashFactor = 0.75; enum size_t getIndexEmptyValue = size_t.max; @@ -262,7 +263,7 @@ struct HashMap(KeyPar, ValuePar, alias hashFunc = defaultHashFunc) { return result; } - export int byKey(scope int delegate(Key k) dg) { + export int byKey(scope int delegate(Key k) nothrow dg) { int result; foreach (ref Key k; this) { result = dg(k); @@ -272,7 +273,7 @@ struct HashMap(KeyPar, ValuePar, alias hashFunc = defaultHashFunc) { return result; } - export int byValue(scope int delegate(ref Value k) dg) { + export int byValue(scope int delegate(ref Value k) nothrow dg) { int result; foreach (ref Value v; this) { result = dg(v); @@ -282,7 +283,7 @@ struct HashMap(KeyPar, ValuePar, alias hashFunc = defaultHashFunc) { return result; } - export int byKeyValue(scope int delegate(ref Key k, ref Value v) dg) { + export int byKeyValue(scope int delegate(ref Key k, ref Value v) nothrow dg) { int result; foreach (ref Key k, ref Value v; this) { result = dg(k, v); diff --git a/source/ecs/id_manager.d b/source/ecs/id_manager.d index 3ee7f1c..8821918 100644 --- a/source/ecs/id_manager.d +++ b/source/ecs/id_manager.d @@ -1,14 +1,15 @@ module ecs.id_manager; - +/* import std.experimental.allocator; -import std.experimental.allocator.mallocator : AlignedMallocator, Mallocator; +import std.experimental.allocator.mallocator : AlignedMallocator, Mallocator;*/ import ecs.entity; import ecs.vector; +import ecs.std; import core.atomic; import core.stdc.string : memcpy; -import core.sync.mutex; +//import core.sync.mutex; /************************************************************************************************************************ *IDManager is responsible for assignment and removing IDs. IDs are unique throughtout a whole duration of the program. @@ -35,13 +36,13 @@ begin: uint block_id = local_id >> 16; if (block_id >= m_blocks_count) { - add_mutex.lock_nothrow(); + add_mutex.lock(); if(block_id >= m_blocks_count) { m_blocks[m_blocks_count].alloc(); m_blocks_count++; } - add_mutex.unlock_nothrow(); + add_mutex.unlock(); } } @@ -145,30 +146,34 @@ begin: void initialize() nothrow @nogc { - m_ids_array = Mallocator.instance.makeArray!Data(65536); - m_free_stack = Mallocator.instance.makeArray!uint(65536); - m_blocks = Mallocator.instance.makeArray!Block(64); + m_ids_array = Mallocator.makeArray!Data(65536); + m_free_stack = Mallocator.makeArray!uint(65536); + m_blocks = Mallocator.makeArray!Block(64); + foreach(ref block;m_blocks)block = Block(); m_blocks_count = 1; m_blocks[0].alloc(); - add_mutex = Mallocator.instance.make!Mutex(); + add_mutex = Mallocator.make!Mutex(); + add_mutex.initialize(); } - void deinitialize() @trusted @nogc + void deinitialize() @trusted @nogc nothrow { - if(m_ids_array)Mallocator.instance.dispose(m_ids_array); - if(m_free_stack)Mallocator.instance.dispose(m_free_stack); + if(m_ids_array)Mallocator.dispose(m_ids_array); + if(m_free_stack)Mallocator.dispose(m_free_stack); if(m_blocks) { foreach(ref block;m_blocks) { if(block.data)block.free(); } - Mallocator.instance.dispose(m_blocks); + Mallocator.dispose(m_blocks); } if(add_mutex) { - Mallocator.instance.dispose(cast(void*)add_mutex); //workaround for compiler bug + add_mutex.destroy(); + Mallocator.dispose(add_mutex);//cast(void*)add_mutex); //workaround for compiler bug + add_mutex = null; } } @@ -178,14 +183,14 @@ begin: if(m_last_id > m_ids_array.length) { uint begin = cast(uint)m_ids_array.length; - Data[] new_array = Mallocator.instance.makeArray!Data(begin + (m_blocks_count << 16)); + Data[] new_array = Mallocator.makeArray!Data(begin + (m_blocks_count << 16)); memcpy(new_array.ptr, m_ids_array.ptr, m_ids_array.length * Data.sizeof); - Mallocator.instance.dispose(m_ids_array); + Mallocator.dispose(m_ids_array); m_ids_array = new_array; - uint[] new_stack = Mallocator.instance.makeArray!uint(m_ids_array.length); + uint[] new_stack = Mallocator.makeArray!uint(m_ids_array.length); memcpy(new_stack.ptr,m_free_stack.ptr,m_free_stack.length * uint.sizeof); - Mallocator.instance.dispose(m_free_stack); + Mallocator.dispose(m_free_stack); m_free_stack = new_stack; foreach(block;m_blocks[0..m_blocks_count-1]) @@ -204,13 +209,13 @@ begin: void alloc() nothrow @nogc { assert(data is null); - data = Mallocator.instance.makeArray!Data(65536); + data = Mallocator.makeArray!Data(65536); } void free() nothrow @nogc { assert(data !is null); - Mallocator.instance.dispose(data); + Mallocator.dispose(data); data = null; } @@ -225,7 +230,7 @@ begin: } private: - Mutex add_mutex; + Mutex* add_mutex; //shared uint m_next_id = 0; //shared uint m_last_id = 0; @@ -261,5 +266,4 @@ unittest assert(id3 == EntityID(2, 1)); assert(manager.isExist(id3)); assert(!manager.isExist(EntityID(0, 1))); - } diff --git a/source/ecs/manager.d b/source/ecs/manager.d index d75fa00..e3d37f3 100644 --- a/source/ecs/manager.d +++ b/source/ecs/manager.d @@ -5,14 +5,14 @@ module ecs.manager; import std.algorithm : max; import std.conv : to; -import std.experimental.allocator; -import std.experimental.allocator.mallocator : AlignedMallocator, Mallocator; +//import std.experimental.allocator; +//import std.experimental.allocator.mallocator : AlignedMallocator, Mallocator; import std.traits; -import core.stdc.stdlib; +import core.stdc.stdlib : qsort; import core.stdc.string; import core.atomic; -import core.sync.mutex; +//import core.sync.mutex; import ecs.system; import ecs.entity; @@ -23,6 +23,7 @@ import ecs.vector; import ecs.simple_vector; import ecs.events; import ecs.traits; +import ecs.std; export alias gEM = EntityManager.instance; export alias gEntityManager = EntityManager.instance; @@ -32,18 +33,21 @@ alias SerializeVector = ecs.vector.Vector!ubyte; /************************************************************************************************************************ *Entity manager is responsible for everything. */ -export class EntityManager +export struct EntityManager { export static void initialize(uint threads_count) { if (instance is null) { - instance = Mallocator.instance.make!EntityManager(threads_count); + //instance = Mallocator.make!EntityManager(threads_count); + instance = Mallocator.make!EntityManager(threads_count); with(instance) { - UpdatePass* pass = Mallocator.instance.make!UpdatePass; - pass.name = Mallocator.instance.makeArray("update"); + UpdatePass* pass = Mallocator.make!UpdatePass; + pass.name = Mallocator.makeArray(cast(char[])"update"); + //pass.name = Mallocator.makeArray!char("update".length); + //pass.name[0..$] = "update"; passes.add(pass); passes_map.add(cast(string) pass.name, cast(ushort)(passes.length - 1)); } @@ -63,50 +67,49 @@ export class EntityManager if (system.m_destroy) (cast(void function(void*)) system.m_destroy)(system.m_system_pointer); - if(system.jobs)Mallocator.instance.dispose(system.jobs); - if(system.m_read_only_components)Mallocator.instance.dispose(system.m_read_only_components); - if(system.m_modified_components)Mallocator.instance.dispose(system.m_modified_components); - if(system.m_components)Mallocator.instance.dispose(system.m_components); - if(system.m_excluded_components)Mallocator.instance.dispose(system.m_excluded_components); - if(system.m_optional_components)Mallocator.instance.dispose(system.m_optional_components); - if(system.m_name)Mallocator.instance.dispose(system.m_name); - if(system.m_event_callers)Mallocator.instance.dispose(system.m_event_callers); + if(system.jobs)Mallocator.dispose(system.jobs); + if(system.m_read_only_components)Mallocator.dispose(system.m_read_only_components); + if(system.m_modified_components)Mallocator.dispose(system.m_modified_components); + if(system.m_components)Mallocator.dispose(system.m_components); + if(system.m_excluded_components)Mallocator.dispose(system.m_excluded_components); + if(system.m_optional_components)Mallocator.dispose(system.m_optional_components); + if(system.m_name)Mallocator.dispose(system.m_name); + if(system.m_event_callers)Mallocator.dispose(system.m_event_callers); - if(system.m_system_pointer)Mallocator.instance.dispose(system.m_system_pointer); + if(system.m_system_pointer)Mallocator.dispose(system.m_system_pointer); } foreach(EntityInfo* info;&entities_infos.byValue) { - //if(info.components)Mallocator.instance.dispose(info.components); + //if(info.components)Mallocator.dispose(info.components); - Mallocator.instance.dispose(info); - } + Mallocator.dispose(info); + }//*/ foreach(UpdatePass* pass; passes) { - Mallocator.instance.dispose(pass); + Mallocator.dispose(pass); } passes.clear(); foreach(ComponentInfo info; components) { - if(info.init_data)Mallocator.instance.dispose(info.init_data); + if(info.init_data)Mallocator.dispose(info.init_data); } foreach(EventInfo info; events) { - if(info.callers)Mallocator.instance.dispose(info.callers); + if(info.callers)Mallocator.dispose(info.callers); } foreach(name; &components_map.byKey) { - if(name)Mallocator.instance.dispose(name); + if(name)Mallocator.dispose(name); } } - Mallocator.instance.dispose(instance); + Mallocator.dispose(instance); instance = null; - } /************************************************************************************************************************ @@ -121,7 +124,7 @@ export class EntityManager { foreach (caller; pass.system_callers) { - Mallocator.instance.dispose(caller); + Mallocator.dispose(caller); } pass.system_callers.clear(); } @@ -138,8 +141,8 @@ export class EntityManager foreach (ref info; &entities_infos.byValue) { if (info.systems) - Mallocator.instance.dispose(info.systems); - info.systems = Mallocator.instance.makeArray!bool(systems.length); + Mallocator.dispose(info.systems); + info.systems = Mallocator.makeArray!bool(systems.length); } foreach (ref system; systems) @@ -161,7 +164,7 @@ export class EntityManager { if (systems[caller.system_id].priority > system.priority) { - SystemCaller* sys_caller = Mallocator.instance.make!SystemCaller; + SystemCaller* sys_caller = Mallocator.make!SystemCaller; sys_caller.system_id = system.id; sys_caller.job_group.caller = sys_caller; passes[system.m_pass].system_callers.add(sys_caller, i); @@ -171,7 +174,7 @@ export class EntityManager } if (!added) { - SystemCaller* sys_caller = Mallocator.instance.make!SystemCaller; + SystemCaller* sys_caller = Mallocator.make!SystemCaller; sys_caller.system_id = system.id; sys_caller.job_group.caller = sys_caller; passes[system.m_pass].system_callers.add(sys_caller); @@ -188,7 +191,7 @@ export class EntityManager foreach (ref info; events) { - Mallocator.instance.dispose(info.callers); + Mallocator.dispose(info.callers); } ushort[] event_callers = (cast(ushort*) alloca(ushort.sizeof * events.length))[0 @@ -206,7 +209,7 @@ export class EntityManager foreach (i, ref info; events) { - info.callers = Mallocator.instance.makeArray!(EventCaller)(event_callers[i]); + info.callers = Mallocator.makeArray!(EventCaller)(event_callers[i]); } foreach (ref caller; event_callers) @@ -222,7 +225,7 @@ export class EntityManager } } - foreach (info; &entities_infos.byValue) + foreach(EntityInfo* info;&entities_infos.byValue) { generateListeners(info); } @@ -233,30 +236,37 @@ export class EntityManager /************************************************************************************************************************ *Default constructor. */ - this(uint threads_count) + this(uint threads_count) nothrow @nogc { if (threads_count == 0) threads_count = 1; - threads = Mallocator.instance.makeArray!ThreadData(threads_count); + threads = Mallocator.makeArray!ThreadData(threads_count); + //foreach(ref thread;threads)thread = ThreadData().init; id_manager.initialize(); - event_manager.initialize(this); + event_manager.initialize(&this); allocator = BlockAllocator(page_size, pages_in_block); - //add_mutex = Mallocator.instance.make!Mutex; - entity_block_alloc_mutex = Mallocator.instance.make!Mutex; + //add_mutex = Mallocator.make!Mutex; + entity_block_alloc_mutex = Mallocator.make!Mutex; + entity_block_alloc_mutex.initialize(); //event_manager = EventManager(this); //event_manager.manager = this; } - ~this() + ~this() nothrow @nogc { id_manager.deinitialize(); event_manager.destroy(); - if(threads)Mallocator.instance.dispose(threads); - if(entity_block_alloc_mutex)Mallocator.instance.dispose(entity_block_alloc_mutex); + if(threads)Mallocator.dispose(threads); + if(entity_block_alloc_mutex) + { + entity_block_alloc_mutex.destroy(); + Mallocator.dispose(entity_block_alloc_mutex); + entity_block_alloc_mutex = null; + } allocator.freeMemory(); } @@ -267,7 +277,7 @@ export class EntityManager void registerSystem(Sys)(int priority, const(char)[] pass_name) { ushort pass = passes_map.get(pass_name, ushort.max); - assert(pass != ushort.max, "Update pass (Name " ~ pass_name ~ ") doesn't exist."); + assert(pass != ushort.max);//, "Update pass (Name " ~ pass_name ~ ") doesn't exist."); registerSystem!(Sys)(priority, pass); } @@ -286,19 +296,19 @@ export class EntityManager assert(register_state, "registerSystem must be called between beginRegister() and endRegister()."); - assert(pass < passes.length, "Update pass (ID " ~ pass.to!string ~ ") doesn't exist."); + assert(pass < passes.length);//, "Update pass (ID " ~ pass.to!string ~ ") doesn't exist."); System system; system.m_pass = pass; static if (!(hasMember!(Sys, "system_id")) || !is(typeof(Sys.system_id) == ushort)) { - static assert(0, "Add \"mixin ECS.System;\" in top of system structure;"); //"System should have \"__gshared ushort system_id"); + static assert(0);//, "Add \"mixin ECS.System;\" in top of system structure;"); //"System should have \"__gshared ushort system_id"); } static if (!(hasMember!(Sys, "EntitiesData"))) { - static assert(0, "System should gave \"EntitiesData\" struct for input components"); + static assert(0);//, "System should gave \"EntitiesData\" struct for input components"); } static if (hasMember!(Sys, "handleEvent")) @@ -346,7 +356,7 @@ export class EntityManager }//*/ Type* event = cast(Type*) data.event; - data_system.handleEvent(/*input, */gEM.getEntity(event.entity_id), *event); + data_system.handleEvent(gEM.getEntity(event.entity_id), *event); } void setEventCallers(Sys)(ref System system) @@ -359,18 +369,6 @@ export class EntityManager { alias Params = Parameters!(__traits(getOverloads, Sys, "handleEvent")[j]); - /*static if(Params.length == 2 && is(Params[0] == __traits(getMember, Sys, "EventInput"))) - { - alias EventParamType = Params[1]; - enum EventName = Unqual!(EventParamType).stringof; - ushort evt = events_map.get(cast(char[]) EventName, ushort.max); - assert(evt != ushort.max, "Can't register system \""~Sys.stringof~"\" due to non existing event \""~EventName~"\"."); - - callers[i].callback = cast( - void*)&callEventHandler!(EventParamType); - callers[i].id = EventParamType.event_id; - i++; - }*/ static if(Params.length == 2 && is(Params[0] == Entity*)) { alias EventParamType = Params[1]; @@ -385,12 +383,12 @@ export class EntityManager } } - system.m_event_callers = Mallocator.instance.makeArray(callers[0..i]); + system.m_event_callers = Mallocator.makeArray(callers[0..i]); } static if (__traits(hasMember, Sys, "handleEvent")) { - setEventCallers!(Sys)(system); + //setEventCallers!(Sys)(system); } } @@ -402,11 +400,69 @@ export class EntityManager static struct ComponentsIndices { - CompInfo[] readonly; - CompInfo[] mutable; - CompInfo[] excluded; - CompInfo[] optional; - CompInfo[] req; + + CompInfo[] readonly() + { + return m_readonly[0 .. m_readonly_counter]; + } + + CompInfo[] mutable() + { + return m_mutable[0 .. m_mutable_counter]; + } + + CompInfo[] excluded() + { + return m_excluded[0 .. m_excluded_counter]; + } + + CompInfo[] optional() + { + return m_optional[0 .. m_optional_counter]; + } + + CompInfo[] req() + { + return m_req[0 .. m_req_counter]; + } + + void addReadonly(CompInfo info) + { + m_readonly[m_readonly_counter++] = info; + } + + void addMutable(CompInfo info) + { + m_mutable[m_mutable_counter++] = info; + } + + void addExcluded(CompInfo info) + { + m_excluded[m_excluded_counter++] = info; + } + + void addOptional(CompInfo info) + { + m_optional[m_optional_counter++] = info; + } + + void addReq(CompInfo info) + { + m_req[m_req_counter++] = info; + } + + CompInfo[32] m_readonly; + CompInfo[32] m_mutable; + CompInfo[32] m_excluded; + CompInfo[32] m_optional; + CompInfo[32] m_req; + + uint m_readonly_counter; + uint m_mutable_counter; + uint m_excluded_counter; + uint m_optional_counter; + uint m_req_counter; + string entites_array; } @@ -419,22 +475,25 @@ export class EntityManager size_t modified = components_info.mutable.length; if (req > 0) - system.m_components = Mallocator.instance.makeArray!ushort(req); + system.m_components = Mallocator.makeArray!ushort(req); if (opt > 0) - system.m_optional_components = Mallocator.instance.makeArray!ushort(opt); + system.m_optional_components = Mallocator.makeArray!ushort(opt); if (excluded > 0) - system.m_excluded_components = Mallocator.instance.makeArray!ushort(excluded); + system.m_excluded_components = Mallocator.makeArray!ushort(excluded); if (read_only > 0) - system.m_read_only_components = Mallocator.instance.makeArray!ushort(read_only); + system.m_read_only_components = Mallocator.makeArray!ushort(read_only); if (modified > 0) - system.m_modified_components = Mallocator.instance.makeArray!ushort(modified); + system.m_modified_components = Mallocator.makeArray!ushort(modified); } - static ComponentsIndices getComponentsInfo() + static ComponentsIndices getComponentsInfo()() { ComponentsIndices components_info; + //import core.stdc.stdlib; + //uint[] aaa = (cast(uint*)malloc(400))[0..100]; + bool checkExcludedComponentsSomething(Sys)() { return __traits(compiles, allSameType!(string, typeof(Sys.ExcludedComponents))) && allSameType!(string, @@ -457,7 +516,6 @@ export class EntityManager } bool is_optional; - //bool is_excluded; bool is_read_only; if (is(CopyConstness!(ForeachType!(MemberType), int) == const(int))) @@ -471,10 +529,6 @@ export class EntityManager { is_optional = true; } - /*else if (att == "excluded") - { - is_excluded = true; - }*/ if (att == "readonly") { is_read_only = true; @@ -482,32 +536,32 @@ export class EntityManager } if (is_read_only) { - components_info.readonly ~= CompInfo(member,name); + components_info.addReadonly(CompInfo(member,name)); + //components_info.readonly ~= CompInfo(member,name); } else { - components_info.mutable ~= CompInfo(member,name); + components_info.addMutable(CompInfo(member,name)); + //components_info.mutable ~= CompInfo(member,name); } - /*if (is_excluded) - { - components_info.excluded ~= CompInfo(member,name); - }*/ if (is_optional) { - components_info.optional ~= CompInfo(member,name); + components_info.addOptional(CompInfo(member,name)); + //components_info.optional ~= CompInfo(member,name); } - if (is_read_only) + else { - components_info.readonly ~= CompInfo(member,name); + components_info.addReq(CompInfo(member,name)); + //components_info.req ~= CompInfo(member,name); } - if (/*is_excluded == false &&*/ is_optional == false) + /*if (is_read_only) + { + //components_info.readonly ~= CompInfo(member,name); + } + if (is_optional == false) { //is Req - components_info.req ~= CompInfo(member,name); - } - - /*assert(!(is_optional && is_excluded), - "EntitiesData member can't have both \"@optional\" and \"@excluded\".");*/ - + //components_info.req ~= CompInfo(member,name); + }*/ } static if (__traits(hasMember, Sys, "ExcludedComponents")) @@ -516,18 +570,21 @@ export class EntityManager { foreach (str; __traits(allMembers, Sys.ExcludedComponents)) { - components_info.excluded ~= CompInfo(str,str); + components_info.addExcluded(CompInfo(str,str)); + //components_info.excluded ~= CompInfo(str,str); } } else static if (checkExcludedComponentsSomething!Sys) { foreach (str; Sys.ExcludedComponents) { - components_info.excluded ~= CompInfo(str,str); + components_info.addExcluded(CompInfo(str,str)); + //components_info.excluded ~= CompInfo(str,str); } } } + return components_info; } @@ -557,31 +614,31 @@ export class EntityManager foreach (iii, comp_info; components_info.req) { ushort comp = components_map.get(cast(char[]) comp_info.type, ushort.max); - assert(comp != ushort.max, "Can't register system \""~Sys.stringof~"\" due to non existing component \""~comp_info.type~"\"."); + assert(comp != ushort.max);//, "Can't register system \""~Sys.stringof~"\" due to non existing component \""~comp_info.type~"\"."); system.m_components[iii] = comp; } foreach (iii, comp_info; components_info.excluded) { ushort comp = components_map.get(cast(char[]) comp_info.type, ushort.max); - assert(comp != ushort.max, "Can't register system \""~Sys.stringof~"\" due to non existing component \""~comp_info.type~"\"."); + assert(comp != ushort.max);//, "Can't register system \""~Sys.stringof~"\" due to non existing component \""~comp_info.type~"\"."); system.m_excluded_components[iii] = comp; } foreach (iii, comp_info; components_info.optional) { ushort comp = components_map.get(cast(char[]) comp_info.type, ushort.max); - assert(comp != ushort.max, "Can't register system \""~Sys.stringof~"\" due to non existing component \""~comp_info.type~"\"."); + assert(comp != ushort.max);//, "Can't register system \""~Sys.stringof~"\" due to non existing component \""~comp_info.type~"\"."); system.m_optional_components[iii] = comp; } foreach (iii, comp_info; components_info.readonly) { ushort comp = components_map.get(cast(char[]) comp_info.type, ushort.max); - assert(comp != ushort.max, "Can't register system \""~Sys.stringof~"\" due to non existing component \""~comp_info.type~"\"."); + assert(comp != ushort.max);//, "Can't register system \""~Sys.stringof~"\" due to non existing component \""~comp_info.type~"\"."); system.m_read_only_components[iii] = comp; } foreach (iii, comp_info; components_info.mutable) { ushort comp = components_map.get(cast(char[]) comp_info.type, ushort.max); - assert(comp != ushort.max, "Can't register system \""~Sys.stringof~"\" due to non existing component \""~comp_info.type~"\"."); + assert(comp != ushort.max);//, "Can't register system \""~Sys.stringof~"\" due to non existing component \""~comp_info.type~"\"."); system.m_modified_components[iii] = comp; } @@ -741,11 +798,11 @@ export class EntityManager catchEntityFunction!("onRemoveEntity")(&system.m_remove_entity); catchEntityFunction!("onChangeEntity")(&system.m_change_entity); - system.m_system_pointer = cast(void*) Mallocator.instance.make!Sys; + system.m_system_pointer = cast(void*) Mallocator.make!Sys; system.m_priority = priority; //(cast(Sys*) system.m_system_pointer).__ecsInitialize(); //system.jobs = (cast(Sys*) system.m_system_pointer)._ecs_jobs; - system.jobs = Mallocator.instance.makeArray!(Job)((cast(Sys*) system.m_system_pointer).__ecs_jobs_count); + system.jobs = Mallocator.makeArray!(Job)((cast(Sys*) system.m_system_pointer).__ecs_jobs_count); genCompList(system, components_map); @@ -754,8 +811,6 @@ export class EntityManager { system.enable(); - /*if (systems[sys_id].m_destroy) - systems[sys_id].m_destroy(systems[sys_id].m_system_pointer);*/ if (system.m_create) (cast(void function(void*)) system.m_create)(system.m_system_pointer); @@ -764,7 +819,7 @@ export class EntityManager } else { - system.m_name = Mallocator.instance.makeArray(Sys.stringof); + system.m_name = Mallocator.makeArray(cast(char[])Sys.stringof); systems_map.add(system.m_name, cast(ushort) systems.length); system.m_id = cast(ushort)(systems.length); @@ -797,8 +852,10 @@ export class EntityManager export ushort registerPass(const(char)[] name) { - UpdatePass* pass = Mallocator.instance.make!UpdatePass; - pass.name = Mallocator.instance.makeArray(name); + UpdatePass* pass = Mallocator.make!UpdatePass; + pass.name = Mallocator.makeArray(cast(char[])name); + /*pass.name = Mallocator.makeArray!char(name.length); + pass.name[0..$] = name[0..$];*/ passes.add(pass); passes_map.add(name, cast(ushort)(passes.length - 1)); return cast(ushort)(passes.length - 1); @@ -841,7 +898,7 @@ export class EntityManager info.size = Comp.sizeof; info.alignment = Comp.alignof; //8; - info.init_data = Mallocator.instance.makeArray!ubyte(Comp.sizeof); + info.init_data = Mallocator.makeArray!ubyte(Comp.sizeof); *cast(Comp*) info.init_data.ptr = Comp.init; // = Comp(); ushort comp_id = components_map.get(cast(char[])Comp.stringof, ushort.max); @@ -854,7 +911,9 @@ export class EntityManager { components.add(info); Comp.component_id = cast(ushort)(components.length - 1); - char[] name = Mallocator.instance.makeArray(Comp.stringof); + char[] name = Mallocator.makeArray(cast(char[])Comp.stringof); + /*char[] name = Mallocator.makeArray!char(Comp.stringof.length); + name[0..$] = Comp.stringof;*/ components_map.add(name, cast(ushort)(components.length - 1)); } } @@ -982,7 +1041,8 @@ export class EntityManager { CallData[] callers = m_call_data_allocator.getCallData( cast(uint) tmp_datas.length); - callers[0 .. $] = tmp_datas[0 .. $]; + //callers[0 .. $] = tmp_datas[0 .. $]; + memcpy(callers.ptr, &tmp_datas[0], CallData.sizeof * tmp_datas.length); tmp_datas.clear(); sys.jobs[job_id].callers = callers; job_id++; @@ -1100,8 +1160,8 @@ export class EntityManager EntitiesBlock* block = getMetaData(entity); EntityInfo* info = block.type_info; - EntityTemplate* temp = Mallocator.instance.make!EntityTemplate; - temp.entity_data = Mallocator.instance.makeArray!ubyte(info.size); + EntityTemplate* temp = Mallocator.make!EntityTemplate; + temp.entity_data = Mallocator.makeArray!ubyte(info.size); temp.info = info; if(fill_default) @@ -1109,8 +1169,9 @@ export class EntityManager //fill components with default data foreach (comp; info.components) { - temp.entity_data[info.tmpl_deltas[comp] .. info.tmpl_deltas[comp] + components[comp].size] - = components[comp].init_data; + memcpy(temp.entity_data.ptr + info.tmpl_deltas[comp], components[comp].init_data.ptr, components[comp].size); + /*temp.entity_data[info.tmpl_deltas[comp] .. info.tmpl_deltas[comp] + components[comp].size] + = components[comp].init_data;*/ } } else @@ -1137,7 +1198,8 @@ export class EntityManager ushort[] ids = (cast(ushort*) alloca(ushort.sizeof * components_ids.length))[0 .. components_ids.length]; - ids[0 .. $] = components_ids[]; + memcpy(ids.ptr, components_ids.ptr, ushort.sizeof * components_ids.length); + //ids[0 .. $] = components_ids[]; qsort(ids.ptr, ids.length, ushort.sizeof, &compareUShorts); { uint j = 1; @@ -1156,15 +1218,16 @@ export class EntityManager EntityInfo* info = getEntityInfo(ids); - EntityTemplate* temp = Mallocator.instance.make!EntityTemplate; - temp.entity_data = Mallocator.instance.makeArray!ubyte(info.size); + EntityTemplate* temp = Mallocator.make!EntityTemplate; + temp.entity_data = Mallocator.makeArray!ubyte(info.size); temp.info = info; //fill components with default data foreach (comp; info.components) { - temp.entity_data[info.tmpl_deltas[comp] .. info.tmpl_deltas[comp] + components[comp].size] - = components[comp].init_data; + memcpy(temp.entity_data.ptr + info.tmpl_deltas[comp], components[comp].init_data.ptr, components[comp].size); + /*temp.entity_data[info.tmpl_deltas[comp] .. info.tmpl_deltas[comp] + components[comp].size] + = components[comp].init_data;*/ } return temp; @@ -1181,15 +1244,17 @@ export class EntityManager EntityInfo* info = entities_infos.get(ids, null); if (info is null) { - info = Mallocator.instance.make!EntityInfo; + info = Mallocator.make!EntityInfo; - info.components = Mallocator.instance.makeArray(ids); - info.deltas = Mallocator.instance.makeArray!ushort(ids[$ - 1] + 1); + info.components = Mallocator.makeArray(ids); + /*info.components = Mallocator.makeArray!ushort(ids.length); + info.components[0 .. $] = ids[0 .. $];*/ + info.deltas = Mallocator.makeArray!ushort(ids[$ - 1] + 1); info.size = EntityID.sizeof; info.alignment = EntityID.alignof; - info.tmpl_deltas = Mallocator.instance.makeArray!ushort(ids[$ - 1] + 1, ushort.max); + info.tmpl_deltas = Mallocator.makeArray!ushort(ids[$ - 1] + 1, ushort.max); uint components_size = EntityID.sizeof; foreach (i, id; ids) @@ -1202,18 +1267,11 @@ export class EntityManager } alignNum(info.size, info.alignment); - /**/ - uint block_memory = cast(uint)( page_size - EntitiesBlock.sizeof - (info.size - components_size)); //uint entity_comps_size = EntityID.sizeof; uint mem_begin = EntitiesBlock.sizeof; - /*foreach (id; ids) - { - entity_comps_size += components[id].size; - }*/ - uint entites_in_block = block_memory / info.size; //entity_comps_size; info.max_entities = cast(ushort) entites_in_block; ushort current_delta = cast(ushort)(mem_begin + entites_in_block * EntityID.sizeof); @@ -1225,7 +1283,7 @@ export class EntityManager current_delta += entites_in_block * components[id].size; } - info.systems = Mallocator.instance.makeArray!bool(systems.length); + info.systems = Mallocator.makeArray!bool(systems.length); foreach (i, ref system; systems) { @@ -1245,21 +1303,21 @@ export class EntityManager return info; } - private void generateListeners(EntityInfo* info) + private void generateListeners(EntityInfo* info) nothrow { if (info.add_listeners) { - Mallocator.instance.dispose(info.add_listeners); + Mallocator.dispose(info.add_listeners); info.add_listeners = null; } if (info.remove_listeners) { - Mallocator.instance.dispose(info.remove_listeners); + Mallocator.dispose(info.remove_listeners); info.remove_listeners = null; } if (info.change_listeners) { - Mallocator.instance.dispose(info.change_listeners); + Mallocator.dispose(info.change_listeners); info.change_listeners = null; } //allocate local data @@ -1340,19 +1398,19 @@ export class EntityManager if (add_len) { - info.add_listeners = Mallocator.instance.makeArray!ushort(add_len); + info.add_listeners = Mallocator.makeArray!ushort(add_len); memcpy(info.add_listeners.ptr, tmp_add.ptr, add_len * ushort.sizeof); } if (rem_len) { - info.remove_listeners = Mallocator.instance.makeArray!ushort(rem_len); + info.remove_listeners = Mallocator.makeArray!ushort(rem_len); memcpy(info.remove_listeners.ptr, tmp_rem.ptr, rem_len * ushort.sizeof); } if (ch_len) { - info.change_listeners = Mallocator.instance.makeArray!ushort(ch_len); + info.change_listeners = Mallocator.makeArray!ushort(ch_len); memcpy(info.change_listeners.ptr, tmp_ch.ptr, ch_len * ushort.sizeof); } } @@ -1473,28 +1531,6 @@ export class EntityManager EntityInfo* new_info = info; - /*uint j = 0; - uint k = 0; - foreach (id; info.components) - { - while (k < del_ids.length && del_ids[k] < id) - k++; - if (k >= del_ids.length) - { - ids[j++] = id; - } - else if (del_ids[k] == info.components[j]) - { - k++; - new_info = new_info.getNewInfoAdd(del_ids[k]); - } - else - ids[j++] = id; - } - - if (j == info.components.length) - return;*/ - foreach(id;del_ids) { new_info = new_info.getNewInfoRemove(id); @@ -1588,21 +1624,6 @@ export class EntityManager return; EntitiesBlock* block = getMetaData(entity); EntityInfo* info = block.type_info; - /*ushort[] ids = (cast(ushort*) alloca(ushort.sizeof * (info.components.length + num)))[0 - .. info.components.length + num];*/ - /*ushort[num] new_ids; - - static foreach (i, comp; Components) - { - new_ids[i] = comp.component_id; - }*/ - - /*void*[num] pointers; - - static foreach (i, comp; comps) - { - pointers[i] = ∁ - }*/ foreach (int i; 0 .. num) { @@ -1629,44 +1650,6 @@ export class EntityManager EntityInfo* new_info = info; - /* uint j = 0; - uint k = 0; - uint len = 0; - //foreach (ref id; ids) - for (; len < ids.length; len++) - { - ushort* id = &ids[len]; - if (k >= new_ids.length) - { - if (j >= info.components.length) - break; - *id = info.components[j++]; - //continue; - } - else if (j >= info.components.length) - { - *id = new_ids[k++]; - new_info = new_info.getNewInfoAdd(*id); - //continue; - } - else if (new_ids[k] == info.components[j]) - { - *id = info.components[j++]; - k++; - } - /*debug if (new_ids[k] == info.components[j]) - assert(0, "Trying to add already existing component!");//* - else if (new_ids[k] < info.components[j]) - { - *id = new_ids[k++]; - new_info = new_info.getNewInfoAdd(*id); - } - else - *id = info.components[j++]; - } - if (len == info.components.length) - return;*/ - foreach(id;new_ids) { new_info = new_info.getNewInfoAdd(id); @@ -1702,7 +1685,7 @@ export class EntityManager foreach (ref id; new_info.components)//ids[0 .. len]) { void* dst = cast(void*) new_block + new_info.deltas[id] + ( - new_block.entities_count /*+ new_block.added_count*/ ) * components[id].size; + new_block.entities_count ) * components[id].size; uint size = components[id].size; if (k >= new_ids.length) { @@ -1776,12 +1759,6 @@ export class EntityManager new_ids[i] = comp.component_id; } - /*void*[num] pointers; - - static foreach (i, comp; comps) - { - pointers[i] = ∁ - }*/ ThreadData* data = &threads[thread_id]; data.change_entities_list.add(cast(ubyte)1u); data.change_entities_list.add((cast(ubyte*)&entity_id)[0 .. EntityID.sizeof]); @@ -1803,8 +1780,8 @@ export class EntityManager */ export void freeTemplate(EntityTemplate* template_) { - Mallocator.instance.dispose(template_.entity_data); - Mallocator.instance.dispose(template_); + Mallocator.dispose(template_.entity_data); + Mallocator.dispose(template_); } /************************************************************************************************************************ @@ -1947,9 +1924,9 @@ export class EntityManager if (block is null) { - entity_block_alloc_mutex.lock_nothrow(); + entity_block_alloc_mutex.lock(); scope (exit) - entity_block_alloc_mutex.unlock_nothrow(); + entity_block_alloc_mutex.unlock(); if (info.last_block != null) return info.last_block; @@ -1964,9 +1941,9 @@ export class EntityManager { EntitiesBlock* last_block = info.last_block; - entity_block_alloc_mutex.lock_nothrow(); + entity_block_alloc_mutex.lock(); scope (exit) - entity_block_alloc_mutex.unlock_nothrow(); + entity_block_alloc_mutex.unlock(); if (info.last_block !is last_block) return info.last_block; @@ -2348,9 +2325,9 @@ export class EntityManager { caller.system = &systems[caller.system_id]; if (caller.exclusion) - Mallocator.instance.dispose(caller.exclusion); + Mallocator.dispose(caller.exclusion); if (caller.dependencies) - Mallocator.instance.dispose(caller.dependencies); + Mallocator.dispose(caller.dependencies); } uint index = 0; SystemCaller*[] exclusion; @@ -2361,7 +2338,7 @@ export class EntityManager index = 0; out_for: foreach (caller2; pass.system_callers) { - if ( /*caller.system.priority != caller2.system.priority ||*/ caller is caller2) + if ( caller is caller2) continue; foreach (cmp; caller.system.m_read_only_components) { @@ -2396,15 +2373,13 @@ export class EntityManager } if (index > 0) - caller.exclusion = Mallocator.instance.makeArray(exclusion[0 .. index]); + { + caller.exclusion = Mallocator.makeArray(exclusion[0 .. index]); + /*caller.exclusion = Mallocator.makeArray!(SystemCaller*)(index); + caller.exclusion[0..$] = exclusion[0 .. index];*/ + } else caller.exclusion = null; - - /*import std.stdio; - write("Exclusive systems for system ", caller.system.m_name, ": "); - foreach (ex; exclusion[0 .. index]) - write(ex.system.m_name, " "); - writeln();*/ } extern (C) static int compareSystems(const void* a, const void* b) @@ -2448,8 +2423,10 @@ export class EntityManager if (index > 0) { - caller.dependencies = Mallocator.instance.makeArray(exclusion[0 .. index]); - caller.job_group.dependencies = Mallocator.instance.makeArray!( + caller.dependencies = Mallocator.makeArray(exclusion[0 .. index]); + /*caller.dependencies = Mallocator.makeArray!(SystemCaller*)(index); + caller.dependencies[0..$] = exclusion[0 .. index];*/ + caller.job_group.dependencies = Mallocator.makeArray!( JobGroup*)(index); foreach (j, dep; caller.dependencies) @@ -2459,12 +2436,6 @@ export class EntityManager } else caller.dependencies = null; - - /*import std.stdio; - write("Dependencies for system ", caller.system.m_name, ": "); - foreach (ex; caller.dependencies) - write(ex.system.m_name, " "); - writeln();*/ } } } @@ -2474,6 +2445,7 @@ export class EntityManager */ struct ComponentInfo { + nothrow ~this(){} ///Component size ushort size; ///Component data alignment @@ -2482,8 +2454,10 @@ export class EntityManager ubyte[] init_data; ///Pointer to component destroy callback void function(void* pointer) nothrow @nogc destroy_callback; + //void* destroy_callback; ///Pointer to component create callback void function(void* pointer) nothrow @nogc create_callback; + //void* create_callback; } struct EventCaller @@ -2541,11 +2515,12 @@ export class EntityManager { if(comp_add_info.length < id) { - EntityInfo*[] new_infos = Mallocator.instance.makeArray!(EntityInfo*)(instance.components.length); + EntityInfo*[] new_infos = Mallocator.makeArray!(EntityInfo*)(instance.components.length); if(comp_add_info !is null) { - new_infos[0 .. comp_add_info.length] = comp_add_info[0 .. $]; - Mallocator.instance.dispose(comp_add_info); + //new_infos[0 .. comp_add_info.length] = comp_add_info[0 .. $]; + memcpy(new_infos.ptr, comp_add_info.ptr, (EntityInfo*).sizeof * comp_add_info.length); + Mallocator.dispose(comp_add_info); } comp_add_info = new_infos; } @@ -2582,11 +2557,12 @@ export class EntityManager { if(comp_rem_info.length < id) { - EntityInfo*[] new_infos = Mallocator.instance.makeArray!(EntityInfo*)(instance.components.length); + EntityInfo*[] new_infos = Mallocator.makeArray!(EntityInfo*)(instance.components.length); if(comp_rem_info !is null) { - new_infos[0 .. comp_rem_info.length] = comp_rem_info[0 .. $]; - Mallocator.instance.dispose(comp_rem_info); + //new_infos[0 .. comp_rem_info.length] = comp_rem_info[0 .. $]; + memcpy(new_infos.ptr, comp_rem_info.ptr, (EntityInfo*).sizeof * comp_rem_info.length); + Mallocator.dispose(comp_rem_info); } comp_rem_info = new_infos; } @@ -2613,15 +2589,15 @@ export class EntityManager return new_info; } - ~this() + ~this() @nogc nothrow { - if(components)Mallocator.instance.dispose(components); - if(deltas)Mallocator.instance.dispose(deltas); - if(tmpl_deltas)Mallocator.instance.dispose(tmpl_deltas); - if(systems)Mallocator.instance.dispose(systems); - if(add_listeners)Mallocator.instance.dispose(add_listeners); - if(remove_listeners)Mallocator.instance.dispose(remove_listeners); - if(change_listeners)Mallocator.instance.dispose(change_listeners); + if(components)Mallocator.dispose(components); + if(deltas)Mallocator.dispose(deltas); + if(tmpl_deltas)Mallocator.dispose(tmpl_deltas); + if(systems)Mallocator.dispose(systems); + if(add_listeners)Mallocator.dispose(add_listeners); + if(remove_listeners)Mallocator.dispose(remove_listeners); + if(change_listeners)Mallocator.dispose(change_listeners); } ///entity components @@ -2772,14 +2748,14 @@ export class EntityManager { if (dependencies) { - Mallocator.instance.dispose(dependencies); + Mallocator.dispose(dependencies); } if(exclusion) { - Mallocator.instance.dispose(exclusion); + Mallocator.dispose(exclusion); } if (job_group.dependencies) - Mallocator.instance.dispose(job_group.dependencies); + Mallocator.dispose(job_group.dependencies); } uint system_id; @@ -2804,10 +2780,10 @@ export class EntityManager { assert(name); if (name) - Mallocator.instance.dispose(name); + Mallocator.dispose(name); foreach(caller; system_callers) { - Mallocator.instance.dispose(caller); + Mallocator.dispose(caller); } system_callers.clear(); } @@ -2832,7 +2808,7 @@ export class EntityManager enum pages_in_block = 128; IDManager id_manager; - BlockAllocator /*!(page_size, pages_in_block)*/ allocator; + BlockAllocator allocator; EventManager event_manager; @@ -2849,7 +2825,7 @@ export class EntityManager Vector!EventInfo events; //Mutex add_mutex; - Mutex entity_block_alloc_mutex; + Mutex* entity_block_alloc_mutex; CallDataAllocator m_call_data_allocator; struct CallDataAllocator @@ -2860,11 +2836,11 @@ export class EntityManager uint allocated = 0; } - ~this() + ~this() nothrow @nogc { foreach(block;blocks) { - Mallocator.instance.dispose(block); + Mallocator.dispose(block); } blocks.clear(); } @@ -2887,13 +2863,9 @@ export class EntityManager { if (blocks.length == 0) { - Block* new_block = Mallocator.instance.make!Block; + Block* new_block = Mallocator.make!Block; blocks.add(new_block); } - /*else if(blocks[$-1].allocated + num >= 256) - { - blocks.add(Block()); - }*/ Block* block = blocks[id]; if (block.allocated + num >= 256) @@ -2901,7 +2873,7 @@ export class EntityManager id++; if (id == blocks.length) { - Block* new_block = Mallocator.instance.make!Block; + Block* new_block = Mallocator.make!Block; blocks.add(new_block); } block = blocks[id]; @@ -2913,15 +2885,5 @@ export class EntityManager } } - export __gshared EntityManager instance = null; + export __gshared EntityManager* instance = null; } - -/* -static ulong defaultHashFunc(T)(auto ref T t) -{ - ulong ret = 0; - foreach(id;t) - { - ret = ret - } -}*/ diff --git a/source/ecs/simple_vector.d b/source/ecs/simple_vector.d index 1751040..7d9cd7a 100644 --- a/source/ecs/simple_vector.d +++ b/source/ecs/simple_vector.d @@ -1,7 +1,9 @@ module ecs.simple_vector; - +/* import std.experimental.allocator; -import std.experimental.allocator.mallocator; +import std.experimental.allocator.mallocator;*/ + +import ecs.std; import core.stdc.string; @@ -14,8 +16,8 @@ struct SimpleVector { while(used >= data.length) { - if(data is null)data = Mallocator.instance.makeArray!ubyte(1024); - else Mallocator.instance.expandArray(data,data.length); + if(data is null)data = Mallocator.makeArray!ubyte(1024); + else data = Mallocator.expandArray(data,data.length); } data[used++] = el; } @@ -24,8 +26,8 @@ struct SimpleVector { while(used + el.length >= data.length) { - if(data is null)data = Mallocator.instance.makeArray!ubyte(1024); - else Mallocator.instance.expandArray(data,data.length); + if(data is null)data = Mallocator.makeArray!ubyte(1024); + else data = Mallocator.expandArray(data,data.length); } memcpy(data.ptr + used, el.ptr, el.length); used += el.length; diff --git a/source/ecs/std.d b/source/ecs/std.d new file mode 100644 index 0000000..8dfbccf --- /dev/null +++ b/source/ecs/std.d @@ -0,0 +1,227 @@ +module ecs.std; + +import core.stdc.stdlib : malloc, free, realloc; +import core.stdc.string : memcpy; +import std.traits; +import core.time; + +version (Windows) +{ + import core.sys.windows.windows; + extern(Windows) void* _aligned_malloc(size_t size,size_t alignment) @nogc nothrow @system; + extern(Windows) void _aligned_free(void* ptr) @nogc nothrow @system; + + version(LDC) + { + /*extern(Windows) void* __alloca(size_t size) @nogc nothrow @system; + alias alloca = __alloca;*/ + + private const uint max_alloca = 10000; + private char[max_alloca] alloca_array; + private uint alloca_pos = 0; + void* alloca(size_t length) @nogc nothrow + { + if(alloca_pos + length > max_alloca)alloca_pos = 0; + void* ret = &alloca_array[alloca_pos]; + alloca_pos += length; + return ret; + } + + extern(Windows) void ___chkstk_ms() @nogc nothrow @system; + + extern(Windows) void __chkstk() + { + ___chkstk_ms(); + } + } + else + { + private const uint max_alloca = 10000; + private char[max_alloca] alloca_array; + private uint alloca_pos = 0; + void* alloca(size_t length) @nogc nothrow + { + if(alloca_pos + length > max_alloca)alloca_pos = 0; + void* ret = &alloca_array[alloca_pos]; + alloca_pos += length; + return ret; + } + } +} +else version (Posix) +{ + import core.sys.posix.pthread; + import core.sys.posix.stdlib; + public import core.stdc.stdlib : alloca; +} + +static struct Mallocator +{ + static T[] makeArray(T)(size_t length) nothrow @nogc + { + T[] ret = (cast(T*)malloc(T.sizeof * length))[0 .. length]; + + /*static if(__traits(isPOD, T)) + { + static immutable T init = T.init; + + foreach(i;0..ret.length) + { + memcpy(&ret[i], &init, T.sizeof); + } + } + else + {*/ + static import std.conv; + foreach(i;0..ret.length) + { + std.conv.emplace(&ret[i]); + } + // } + + //static if(is(T == struct))std.conv.emplace(ret); + //static import std.conv; + //emplace + /*foreach(i;0..ret.length) + { + memcpy(ret); + }*/ + return ret; + } + + static T[] makeArray(T)(size_t length, T initializer) nothrow @nogc + { + T[] ret = (cast(T*)malloc(T.sizeof * length))[0 .. length]; + foreach(ref v; ret)v = initializer; + return ret; + //return (cast(T*)ret)[0 .. length]; + } + + static T[] expandArray(T)(T[] array, size_t length) nothrow @nogc + { + size_t new_length = array.length + length; + return (cast(T*)realloc(array.ptr, T.sizeof * new_length))[0 .. new_length]; + } + + static T[] makeArray(T)(T[] array) nothrow @nogc + { + T[] ret = (cast(T*)malloc(T.sizeof * array.length))[0 .. array.length];//Mallocator.makeArray!(T)(array.length); + foreach(i, ref v;ret)v = array[i]; + //ret[0 .. $] = array; + return ret; + } + + static T* make(T, Args...)(Args args) + { + T* ret = cast(T*)malloc(T.sizeof); + //*ret = T.init; + //static immutable T init = T(); + //memcpy(ret, &init, T.sizeof); + //static if(__traits(hasMember, T, "__ctor"))ret.__ctor(args); + static import std.conv; + static if(__traits(isPOD, T)) + { + static immutable T init = T.init; + memcpy(ret, &init, T.sizeof); + } + else static if(is(T == struct))std.conv.emplace(ret, args); + //else std.conv.emplace(ret, args); + return ret; + } + + static void* alignAlloc(size_t length, size_t alignment) nothrow @nogc + { + + void* ret; + version(Posix)ret = aligned_alloc(alignment, length); + else version(Windows)ret = _aligned_malloc(length, alignment); + else static assert(0, "Unimplemented platform!"); + //posix_memalign(&ret, alignment, length); + return ret; + } + + static void dispose(T)(T object) nothrow @nogc + { + static if(__traits(hasMember, T, "__dtor"))object.__dtor(); + free(cast(void*)object); + } + + static void alignDispose(T)(T object) + { + static if(__traits(hasMember, T, "__dtor"))object.__dtor(); + version(Posix)aligned_free(cast(void*)object); + else version(Windows)_aligned_free(cast(void*)object); + else static assert(0, "Unimplemented platform!"); + + } +} + +struct Mutex +{ + + version (Windows) + { + void initialize() nothrow @nogc + { + InitializeCriticalSection(cast(CRITICAL_SECTION*) &m_handle); + } + + void destroy() nothrow @nogc + { + DeleteCriticalSection(&m_handle); + } + + void lock() nothrow @nogc + { + EnterCriticalSection(&m_handle); + } + + void unlock() nothrow @nogc + { + LeaveCriticalSection(&m_handle); + } + + int tryLock() nothrow @nogc + { + return TryEnterCriticalSection(&m_handle) != 0; + } + + CRITICAL_SECTION m_handle; + } + else version (Posix) + { + void initialize() nothrow @nogc + { + pthread_mutexattr_t attr = void; + + pthread_mutexattr_init(&attr); + + pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); + pthread_mutex_init(cast(pthread_mutex_t*) &m_handle, &attr); + + pthread_mutexattr_destroy(&attr); + } + + void destroy() nothrow @nogc + { + pthread_mutex_destroy(&m_handle); + } + + void lock() nothrow @nogc + { + pthread_mutex_lock(&m_handle); + } + + void unlock() nothrow @nogc + { + pthread_mutex_unlock(&m_handle); + } + + int tryLock() nothrow @nogc + { + return pthread_mutex_trylock(&m_handle) == 0; + } + + private pthread_mutex_t m_handle; + } +} \ No newline at end of file diff --git a/source/ecs/system.d b/source/ecs/system.d index b4ad780..30e9389 100644 --- a/source/ecs/system.d +++ b/source/ecs/system.d @@ -125,14 +125,14 @@ package: //void function(ref EntityManager.CallData data) m_update; void* m_update; ///workaroud for DMD bug with upper line - /*void function(void* system_pointer) m_enable; - void function(void* system_pointer) m_disable; + //void function(void* system_pointer) m_enable; + //void function(void* system_pointer) m_disable; - void function(void* system_pointer) m_create; - void function(void* system_pointer) m_destroy; + //void function(void* system_pointer) m_create; + //void function(void* system_pointer) m_destroy; - void function(void* system_pointer) m_begin; - void function(void* system_pointer) m_end;*/ + //void function(void* system_pointer) m_begin; + //void function(void* system_pointer) m_end; void* m_enable; void* m_disable; diff --git a/source/ecs/vector.d b/source/ecs/vector.d index 47cd761..7c029d0 100644 --- a/source/ecs/vector.d +++ b/source/ecs/vector.d @@ -3,7 +3,7 @@ module ecs.vector; import core.bitop; import core.stdc.stdlib : free, malloc; import core.stdc.string : memcpy, memset; -import std.algorithm : swap; +//import std.algorithm : swap; import std.conv : emplace; import std.traits : hasMember, isCopyable, TemplateOf, Unqual; @@ -28,7 +28,7 @@ public: } - static if (isCopyable!T) { + /*static if (isCopyable!T) { export this(this) { T[] tmp = array[0 .. used]; array = null; @@ -37,7 +37,9 @@ public: } } else { @disable this(this); - } + }*/ + + @disable this(this); export ~this() { clear(); @@ -167,7 +169,8 @@ public: export void remove(size_t elemNum) { destroy(array[elemNum]); - swap(array[elemNum], array[used - 1]); + //swap(array[elemNum], array[used - 1]); + array[elemNum] = array[used - 1]; used--; } diff --git a/source/win_dll.d b/source/win_dll.d index c417b45..1ff8ce4 100644 --- a/source/win_dll.d +++ b/source/win_dll.d @@ -7,7 +7,7 @@ import core.sys.windows.windows; extern(Windows) bool DllMain(void* hInstance, uint ulReason, void*) { - switch (ulReason) + /*switch (ulReason) { default: assert(0); case DLL_PROCESS_ATTACH: @@ -26,5 +26,6 @@ extern(Windows) bool DllMain(void* hInstance, uint ulReason, void*) dll_thread_detach( true, true ); break; } - return true; + return true;*/ + return 0; } \ No newline at end of file diff --git a/tests/tests.d b/tests/tests.d index 30810e2..5b36007 100644 --- a/tests/tests.d +++ b/tests/tests.d @@ -1,7 +1,7 @@ module tests.tests; - +/* import std.experimental.allocator; -import std.experimental.allocator.mallocator; +import std.experimental.allocator.mallocator;*/ import ecs.entity; import ecs.events; @@ -13,6 +13,21 @@ import ecs.core; import core.time; import std.stdio; +version(Windows) +{ + import core.sys.windows.windows; + struct Time + { + static long getUSecTime() + { + LARGE_INTEGER time, freq; + QueryPerformanceFrequency(&freq); + QueryPerformanceCounter(&time); + return time.QuadPart / (freq.QuadPart / 1000_000); + } + } +} + struct TestEvent { mixin ECS.Event; //__gshared ushort event_id; @@ -124,17 +139,20 @@ struct ChangeTestSystem void onCreate() { - writeln("On Change Test System create."); + //writeln("On Change Test System create."); + printf("On Change Test System create."); } void onCreate(int i) { - writeln("On Change Test System create."); + //writeln("On Change Test System create."); + printf("On Change Test System create."); } void onDestroy() { - writeln("On Change Test System destroy."); + //writeln("On Change Test System destroy."); + printf("On Change Test System destroy."); } void onAddEntity(EntitiesData data) @@ -142,30 +160,30 @@ struct ChangeTestSystem //printf("Entity added! ID: "); foreach (i; 0 .. data.length) printf("Entity added! ID: %u\n",data.entites[i].id); - //writeln("Entity added! ID: ", data.entites[i].id); + ////writeln("Entity added! ID: ", data.entites[i].id); } void onRemoveEntity(EntitiesData data) { - //writeln("Entity removed! ID: ", data.entites[0].id); + ////writeln("Entity removed! ID: ", data.entites[0].id); printf("Entity removed! ID: %u\n",data.entites[0].id); } void onChangeEntity(EntitiesData data) { - //writeln("Entity changed! ID: ", data.entites[0].id); + ////writeln("Entity changed! ID: ", data.entites[0].id); printf("Entity changed! ID: %u\n",data.entites[0].id); } bool onBegin() { - //writeln("On Test System begin."); + ////writeln("On Test System begin."); return true; } void onEnd() { - //writeln("On Test System end."); + ////writeln("On Test System end."); } void initialize(ref Entity entity, ref TestComp comp) @@ -196,34 +214,36 @@ struct TestSystem void onCreate() { - writeln("On Test System create."); + //writeln("On Test System create."); + printf("On Change Test System create."); } void onDestroy() { - writeln("On Test System destroy."); + //writeln("On Test System destroy."); + printf("On Change Test System destroy."); } void onAddEntity(EntitiesData data) { //foreach(i;0..data.length) - //writeln("Entity added ID: ",data.entites[i].id.id); + ////writeln("Entity added ID: ",data.entites[i].id.id); } /* void onRemoveEntity(EntitiesData data) { - //writeln("Entity destroyed ID: ",data.entites[0].id); + ////writeln("Entity destroyed ID: ",data.entites[0].id); }*/ bool onBegin() { - //writeln("On Test System begin."); + ////writeln("On Test System begin."); return true; } void onEnd() { - //writeln("On Test System end."); + ////writeln("On Test System end."); } void initialize(ref Entity entity, ref TestComp comp) @@ -400,14 +420,16 @@ struct TestSystem2 { import std.stdio; - writeln("TestSystem2 enabled"); + //writeln("TestSystem2 enabled"); + printf("TestSystem2 enabled"); } void onDisable() { import std.stdio; - writeln("TestSystem2 disabled"); + //writeln("TestSystem2 disabled"); + printf("TestSystem2 disabled"); } void initialize(ref Entity entity, ref TestComp comp) @@ -446,35 +468,38 @@ struct TestSystem2 }*/ } -int main() +extern(C) int main() { void dispatch(EntityManager.JobGroup jobs) nothrow @nogc { foreach (job; jobs.jobs) { - //writeln(job); + ////writeln(job); job.execute(); } } void writeEntityComponents(Entity* entity) { - write(entity.id); + + printf("EntityID(%u, %u)",entity.id.id,entity.id.counter); + //write(entity.id); TestComp* test_comp = entity.getComponent!TestComp; if (test_comp) - write(*test_comp); + printf("TestComp(%u, %u)",test_comp.a,test_comp.b);//write(*test_comp); TestComp2* test_comp2 = entity.getComponent!TestComp2; if (test_comp2) - write(*test_comp2); + printf("TestComp2(%u, %u)",test_comp2.a,test_comp2.b);//write(*test_comp2); TestComp3* test_comp3 = entity.getComponent!TestComp3; if (test_comp3) - write(*test_comp3); + printf("TestComp3(%u, %u)",test_comp3.gg,test_comp3.bg);//write(*test_comp3); TestComp4* test_comp4 = entity.getComponent!TestComp4; if (test_comp4) - write(*test_comp4); - writeln(); - //writeln((cast(uint*) pp)[0 .. 14], " ", pp); + printf("TestComp4(%u, %u, %u, %u, %u, %u)",test_comp4.gg,test_comp4.bg,test_comp4.a,test_comp4.b,test_comp4.c,test_comp4.g);//write(*test_comp4); + printf("\n"); + //writeln(); + ////writeln((cast(uint*) pp)[0 .. 14], " ", pp); } EntityManager.initialize(1); @@ -484,7 +509,8 @@ int main() gEM.beginRegister(); gEM.registerPass("fixed"); - MonoTime time = MonoTime.currTime; + //MonoTime time = MonoTime.currTime; + long time = Time.getUSecTime(); gEM.registerComponent!TestComp2; gEM.registerComponent!TestComp4; @@ -495,10 +521,13 @@ int main() gEM.registerEvent!TestEvent; gEM.registerEvent!TestEvent2; - ulong dur = (MonoTime.currTime - time).total!"usecs"; - writeln("Components register: ", dur, " usecs"); + /*ulong dur = (MonoTime.currTime - time).total!"usecs"; + //writeln("Components register: ", dur, " usecs"); - time = MonoTime.currTime; + time = MonoTime.currTime;*/ + + printf("Components register: %f usecs\n",cast(float)(Time.getUSecTime() - time)); + time = Time.getUSecTime(); gEM.registerSystem!TestSystemWithHighPriority(100, "fixed"); gEM.registerSystem!TestSystem(0); @@ -507,13 +536,15 @@ int main() gEM.registerSystem!Sys2(-100); gEM.registerSystem!Sys3(-2); //gEM.registerSystem!TestSystemWithHighPriority(100); - //gEM.registerSystem!TestSystem2(0); + //gEM.registerSystem!TestSystem2(0);*/ gEM.endRegister(); - dur = (MonoTime.currTime - time).total!"usecs"; - writeln("Systems register: ", dur, " usecs"); + /*dur = (MonoTime.currTime - time).total!"usecs"; + //writeln("Systems register: ", dur, " usecs"); - time = MonoTime.currTime; + time = MonoTime.currTime;*/ + printf("Systems register: %f usecs\n",cast(float)(Time.getUSecTime() - time)); + time = Time.getUSecTime(); //ushort[3] ids = [TestComp2.component_id, TestComp.component_id, TestComp4.component_id]; ushort[2] ids = [TestComp2.component_id, TestComp.component_id]; @@ -522,11 +553,13 @@ int main() //ushort[3] ids2 = [TestComp3.component_id, TestComp.component_id, TestComp4.component_id]; ushort[2] ids2 = [TestComp3.component_id, TestComp.component_id]; EntityTemplate* tmpl2 = gEM.allocateTemplate(ids2); - //writeln(tmpl.info.components[]); + ////writeln(tmpl.info.components[]); //*cast(EntityID*) tmpl.entity_data.ptr = EntityID(1, 1); - dur = (MonoTime.currTime - time).total!"usecs"; - writeln("Template allocating: ", dur, " usecs"); + //dur = (MonoTime.currTime - time).total!"usecs"; + //writeln("Template allocating: ", dur, " usecs"); + printf("Template allocating: %f usecs\n",cast(float)(Time.getUSecTime() - time)); + time = Time.getUSecTime(); EntityID entity; @@ -536,18 +569,21 @@ int main() EntityManager.EntitiesBlock* block = EntityManager.instance.getMetaData( gEM.getEntity(entity)); EntityManager.EntityInfo* info = block.type_info; - writeln(info.add_listeners); + //writeln(info.add_listeners); //if(info)assert(0); } - time = MonoTime.currTime; + //time = MonoTime.currTime; + time = Time.getUSecTime(); //foreach(i; 0..1_000_000)gEM.addEntity(tmpl); //foreach(i; 0..1_000_000)gEM.removeEntity(gEM.addEntity(tmpl).id); - EntityID[] idss = Mallocator.instance.makeArray!EntityID(5000);//[5000] - scope(exit)Mallocator.instance.dispose(idss); + import ecs.std; + + EntityID[] idss = Mallocator.makeArray!EntityID(5000);//[5000] + //scope(exit)Mallocator.dispose(idss); foreach (i; 0 .. 200) { @@ -560,8 +596,10 @@ int main() } gEM.commit(); - dur = (MonoTime.currTime - time).total!"usecs"; - writeln("Entities adding: ", dur, " usecs"); + //dur = (MonoTime.currTime - time).total!"usecs"; + //writeln("Entities adding: ", dur, " usecs"); + printf("Entities adding: %f usecs\n",cast(float)(Time.getUSecTime() - time)); + time = Time.getUSecTime(); uint blocks = 0; foreach (info; &gEM.entities_infos.byValue) @@ -573,7 +611,8 @@ int main() blocks++; } } - writeln("Entities blocks: ", blocks); + //writeln("Entities blocks: ", blocks); + printf("Entities blocks: %u\n",blocks); //foreach(j; 0..1_000)gEM.addEntity(tmpl); @@ -590,9 +629,10 @@ int main() EntityID entity2; - time = MonoTime.currTime; + //time = MonoTime.currTime; + time = Time.getUSecTime(); - EntityID[] entities = Mallocator.instance.makeArray!EntityID(1_000_000); + EntityID[] entities = Mallocator.makeArray!EntityID(1_000_000); foreach (i; 0 .. 500_000) { entity2 = gEM.addEntity(tmpl).id; @@ -601,10 +641,12 @@ int main() } gEM.commit(); - dur = (MonoTime.currTime - time).total!"usecs"; - writeln("Entities adding2: ", dur, " usecs"); + //dur = (MonoTime.currTime - time).total!"usecs"; + //writeln("Entities adding2: ", dur, " usecs"); - time = MonoTime.currTime; + //time = MonoTime.currTime; + printf("Entities adding2: %f usecs\n",cast(float)(Time.getUSecTime() - time)); + time = Time.getUSecTime(); foreach (i; 0 .. 1_000_000) { @@ -613,10 +655,12 @@ int main() } gEM.commit(); - dur = (MonoTime.currTime - time).total!"usecs"; - writeln("Components adding: ", dur, " usecs"); + //dur = (MonoTime.currTime - time).total!"usecs"; + //writeln("Components adding: ", dur, " usecs"); - time = MonoTime.currTime; + //time = MonoTime.currTime; + printf("Components adding: %f usecs\n",cast(float)(Time.getUSecTime() - time)); + time = Time.getUSecTime(); foreach (i; 0 .. 1_000_000) { @@ -625,44 +669,52 @@ int main() } gEM.commit(); - dur = (MonoTime.currTime - time).total!"usecs"; - writeln("Components removing: ", dur, " usecs"); + //dur = (MonoTime.currTime - time).total!"usecs"; + //writeln("Components removing: ", dur, " usecs"); + printf("Components removing: %f usecs\n",cast(float)(Time.getUSecTime() - time)); + time = Time.getUSecTime(); - Mallocator.instance.dispose(entities); + Mallocator.dispose(entities); - time = MonoTime.currTime; + //time = MonoTime.currTime; + time = Time.getUSecTime(); gEM.begin(); //gEM.updateMT(); gEM.update(); gEM.end(); - dur = (MonoTime.currTime - time).total!"usecs"; - writeln("Update: ", dur, " usecs"); + //dur = (MonoTime.currTime - time).total!"usecs"; + //writeln("Update: ", dur, " usecs"); + printf("Update: %f usecs\n",cast(float)(Time.getUSecTime() - time)); writeEntityComponents(gEM.getEntity(entity2)); - time = MonoTime.currTime; + //time = MonoTime.currTime; + time = Time.getUSecTime(); gEM.begin(); gEM.updateMT(); //gEM.update(); gEM.end(); - dur = (MonoTime.currTime - time).total!"usecs"; - writeln("Update: ", dur, " usecs"); + //dur = (MonoTime.currTime - time).total!"usecs"; + //writeln("Update: ", dur, " usecs"); + printf("Update: %f usecs\n",cast(float)(Time.getUSecTime() - time)); writeEntityComponents(gEM.getEntity(entity2)); - time = MonoTime.currTime; + //time = MonoTime.currTime; + time = Time.getUSecTime(); gEM.begin(); gEM.updateMT(); //gEM.update(); gEM.end(); - dur = (MonoTime.currTime - time).total!"usecs"; - writeln("Update: ", dur, " usecs"); + //dur = (MonoTime.currTime - time).total!"usecs"; + //writeln("Update: ", dur, " usecs"); + printf("Update: %f usecs\n",cast(float)(Time.getUSecTime() - time)); writeEntityComponents(gEM.getEntity(entity2)); @@ -673,10 +725,10 @@ int main() gEM.end(); //Entity* pp;// = gEM.getEntity(entity.id); - //writeln((cast(uint*) pp)[0 .. 14], " ", pp); + ////writeln((cast(uint*) pp)[0 .. 14], " ", pp); writeEntityComponents(gEM.getEntity(entity)); - writeln("Entity, its copy, and template, and default filled tempalte"); + //writeln("Entity, its copy, and template, and default filled tempalte"); gEM.addEntity(tmpl); writeEntityComponents(gEM.getEntity(entity)); writeEntityComponents(gEM.addEntityCopy(entity)); @@ -705,16 +757,22 @@ int main() gEM.removeComponents!(TestComp4)(entity); - gEM.commit();//*/ + gEM.commit(); + + printf("pre end\n"); writeEntityComponents(gEM.getEntity(entity)); //import std.stdio; - //writeln((cast(uint*)tmpl.info.first_block)[0..48]); + ////writeln((cast(uint*)tmpl.info.first_block)[0..48]); gEM.freeTemplate(tmpl); gEM.freeTemplate(tmpl2); gEM.freeTemplate(copy_tempalte); gEM.freeTemplate(copy_default_tempalte); EntityManager.destroy(); + Mallocator.dispose(idss); + + printf("end\n");//*/ + return 0; } From 9c5ceacacb9913a1bfdc4fdfb7dd57e78af0a44a Mon Sep 17 00:00:00 2001 From: Mergul Date: Thu, 10 Oct 2019 22:14:18 +0200 Subject: [PATCH 071/217] -some cleanup --- source/ecs/block_allocator.d | 5 +---- source/ecs/events.d | 15 ++------------- source/ecs/id_manager.d | 6 +----- source/ecs/manager.d | 18 ++++++------------ source/ecs/package.d | 10 ++++++---- source/ecs/simple_vector.d | 3 --- source/ecs/std.d | 2 +- 7 files changed, 17 insertions(+), 42 deletions(-) diff --git a/source/ecs/block_allocator.d b/source/ecs/block_allocator.d index abb7856..edd2275 100644 --- a/source/ecs/block_allocator.d +++ b/source/ecs/block_allocator.d @@ -2,11 +2,8 @@ module ecs.block_allocator; import ecs.manager; import ecs.std; -/* -import std.experimental.allocator; -import std.experimental.allocator.mallocator : AlignedMallocator, Mallocator;*/ -struct BlockAllocator//(uint block_size, uint blocks_in_allocation) +struct BlockAllocator { private uint block_size; private uint blocks_in_allocation; diff --git a/source/ecs/events.d b/source/ecs/events.d index b7fa8ed..6aa773f 100644 --- a/source/ecs/events.d +++ b/source/ecs/events.d @@ -1,23 +1,12 @@ module ecs.events; -import ecs.manager; import ecs.block_allocator; import ecs.entity; +import ecs.manager; import ecs.std; -/* -import std.experimental.allocator; -import std.experimental.allocator.mallocator : AlignedMallocator, Mallocator;*/ + import std.algorithm.comparison : max; -//import core.sync.mutex; - -/*struct Event -{ - uint id; - -}*/ - -//mixin template EventManagerCode() struct EventManager { diff --git a/source/ecs/id_manager.d b/source/ecs/id_manager.d index 8821918..1804390 100644 --- a/source/ecs/id_manager.d +++ b/source/ecs/id_manager.d @@ -1,15 +1,11 @@ module ecs.id_manager; -/* -import std.experimental.allocator; -import std.experimental.allocator.mallocator : AlignedMallocator, Mallocator;*/ import ecs.entity; -import ecs.vector; import ecs.std; +import ecs.vector; import core.atomic; import core.stdc.string : memcpy; -//import core.sync.mutex; /************************************************************************************************************************ *IDManager is responsible for assignment and removing IDs. IDs are unique throughtout a whole duration of the program. diff --git a/source/ecs/manager.d b/source/ecs/manager.d index e3d37f3..6868474 100644 --- a/source/ecs/manager.d +++ b/source/ecs/manager.d @@ -5,25 +5,22 @@ module ecs.manager; import std.algorithm : max; import std.conv : to; -//import std.experimental.allocator; -//import std.experimental.allocator.mallocator : AlignedMallocator, Mallocator; import std.traits; +import core.atomic; import core.stdc.stdlib : qsort; import core.stdc.string; -import core.atomic; -//import core.sync.mutex; -import ecs.system; -import ecs.entity; +import ecs.system;//not ordered as forward reference bug workaround import ecs.block_allocator; +import ecs.entity; +import ecs.events; import ecs.hash_map; import ecs.id_manager; -import ecs.vector; import ecs.simple_vector; -import ecs.events; -import ecs.traits; import ecs.std; +import ecs.traits; +import ecs.vector; export alias gEM = EntityManager.instance; export alias gEntityManager = EntityManager.instance; @@ -491,9 +488,6 @@ export struct EntityManager { ComponentsIndices components_info; - //import core.stdc.stdlib; - //uint[] aaa = (cast(uint*)malloc(400))[0..100]; - bool checkExcludedComponentsSomething(Sys)() { return __traits(compiles, allSameType!(string, typeof(Sys.ExcludedComponents))) && allSameType!(string, diff --git a/source/ecs/package.d b/source/ecs/package.d index fb40799..eda440d 100644 --- a/source/ecs/package.d +++ b/source/ecs/package.d @@ -1,8 +1,10 @@ module ecs; -public import ecs.manager; -public import ecs.entity; -public import ecs.system; public import ecs.core; +public import ecs.entity; +public import ecs.manager; +public import ecs.system; + +import ecs.events; import ecs.id_manager; -import ecs.events; \ No newline at end of file +import ecs.std; \ No newline at end of file diff --git a/source/ecs/simple_vector.d b/source/ecs/simple_vector.d index 7d9cd7a..6310d69 100644 --- a/source/ecs/simple_vector.d +++ b/source/ecs/simple_vector.d @@ -1,7 +1,4 @@ module ecs.simple_vector; -/* -import std.experimental.allocator; -import std.experimental.allocator.mallocator;*/ import ecs.std; diff --git a/source/ecs/std.d b/source/ecs/std.d index 8dfbccf..80fc895 100644 --- a/source/ecs/std.d +++ b/source/ecs/std.d @@ -2,8 +2,8 @@ module ecs.std; import core.stdc.stdlib : malloc, free, realloc; import core.stdc.string : memcpy; + import std.traits; -import core.time; version (Windows) { From 633aad6cb786b6ecd2ac980e61729e5fcb5cd169 Mon Sep 17 00:00:00 2001 From: Mergul Date: Fri, 11 Oct 2019 08:31:26 +0200 Subject: [PATCH 072/217] -enabled handleEvent --- source/ecs/manager.d | 2 +- tests/tests.d | 14 +++++++------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/source/ecs/manager.d b/source/ecs/manager.d index 6868474..52a5c86 100644 --- a/source/ecs/manager.d +++ b/source/ecs/manager.d @@ -385,7 +385,7 @@ export struct EntityManager static if (__traits(hasMember, Sys, "handleEvent")) { - //setEventCallers!(Sys)(system); + setEventCallers!(Sys)(system); } } diff --git a/tests/tests.d b/tests/tests.d index 5b36007..a41c7fd 100644 --- a/tests/tests.d +++ b/tests/tests.d @@ -140,19 +140,19 @@ struct ChangeTestSystem void onCreate() { //writeln("On Change Test System create."); - printf("On Change Test System create."); + printf("On Change Test System create.\n"); } void onCreate(int i) { //writeln("On Change Test System create."); - printf("On Change Test System create."); + printf("On Change Test System create.\n"); } void onDestroy() { //writeln("On Change Test System destroy."); - printf("On Change Test System destroy."); + printf("On Change Test System destroy.\n"); } void onAddEntity(EntitiesData data) @@ -215,13 +215,13 @@ struct TestSystem void onCreate() { //writeln("On Test System create."); - printf("On Change Test System create."); + printf("On Change Test System create.\n"); } void onDestroy() { //writeln("On Test System destroy."); - printf("On Change Test System destroy."); + printf("On Change Test System destroy.\n"); } void onAddEntity(EntitiesData data) @@ -421,7 +421,7 @@ struct TestSystem2 import std.stdio; //writeln("TestSystem2 enabled"); - printf("TestSystem2 enabled"); + printf("TestSystem2 enabled\n"); } void onDisable() @@ -429,7 +429,7 @@ struct TestSystem2 import std.stdio; //writeln("TestSystem2 disabled"); - printf("TestSystem2 disabled"); + printf("TestSystem2 disabled\n"); } void initialize(ref Entity entity, ref TestComp comp) From cde772c077a0ad2c1c776fa9e4f13efab0ea1b21 Mon Sep 17 00:00:00 2001 From: Mergul Date: Fri, 11 Oct 2019 19:05:41 +0200 Subject: [PATCH 073/217] -betterC works on linux with DMD --- source/ecs/std.d | 5 ++--- tests/tests.d | 22 ++++++++++++++++++++++ 2 files changed, 24 insertions(+), 3 deletions(-) diff --git a/source/ecs/std.d b/source/ecs/std.d index 80fc895..e4dc5cd 100644 --- a/source/ecs/std.d +++ b/source/ecs/std.d @@ -131,9 +131,8 @@ static struct Mallocator static void* alignAlloc(size_t length, size_t alignment) nothrow @nogc { - void* ret; - version(Posix)ret = aligned_alloc(alignment, length); + version(Posix)posix_memalign(&ret, alignment, length);//ret = aligned_alloc(alignment, length); else version(Windows)ret = _aligned_malloc(length, alignment); else static assert(0, "Unimplemented platform!"); //posix_memalign(&ret, alignment, length); @@ -149,7 +148,7 @@ static struct Mallocator static void alignDispose(T)(T object) { static if(__traits(hasMember, T, "__dtor"))object.__dtor(); - version(Posix)aligned_free(cast(void*)object); + version(Posix)free(cast(void*)object); else version(Windows)_aligned_free(cast(void*)object); else static assert(0, "Unimplemented platform!"); diff --git a/tests/tests.d b/tests/tests.d index a41c7fd..6784ea9 100644 --- a/tests/tests.d +++ b/tests/tests.d @@ -27,6 +27,28 @@ version(Windows) } } } +else version(Posix) +{ + import core.sys.posix.time; + struct Time + { + static long getUSecTime() + { + time_t time; + timespec spec; + + clock_gettime(CLOCK_REALTIME, &spec); + + //time = spec.tv_sec; + return spec.tv_sec * 1000_000 + spec.tv_nsec / 1000;//time / 1000_000; + + /*LARGE_INTEGER time, freq; + QueryPerformanceFrequency(&freq); + QueryPerformanceCounter(&time); + return time.QuadPart / (freq.QuadPart / 1000_000);*/ + } + } +} struct TestEvent { From d8b01ee0973d213b171297287fa68a08ac5ac70e Mon Sep 17 00:00:00 2001 From: Mergul Date: Fri, 11 Oct 2019 19:15:01 +0200 Subject: [PATCH 074/217] -working betterC --- source/ecs/std.d | 62 ++++++++++++++---------------------------------- tests/tests.d | 2 +- 2 files changed, 19 insertions(+), 45 deletions(-) diff --git a/source/ecs/std.d b/source/ecs/std.d index e4dc5cd..249ec41 100644 --- a/source/ecs/std.d +++ b/source/ecs/std.d @@ -16,17 +16,6 @@ version (Windows) /*extern(Windows) void* __alloca(size_t size) @nogc nothrow @system; alias alloca = __alloca;*/ - private const uint max_alloca = 10000; - private char[max_alloca] alloca_array; - private uint alloca_pos = 0; - void* alloca(size_t length) @nogc nothrow - { - if(alloca_pos + length > max_alloca)alloca_pos = 0; - void* ret = &alloca_array[alloca_pos]; - alloca_pos += length; - return ret; - } - extern(Windows) void ___chkstk_ms() @nogc nothrow @system; extern(Windows) void __chkstk() @@ -34,34 +23,35 @@ version (Windows) ___chkstk_ms(); } } - else - { - private const uint max_alloca = 10000; - private char[max_alloca] alloca_array; - private uint alloca_pos = 0; - void* alloca(size_t length) @nogc nothrow - { - if(alloca_pos + length > max_alloca)alloca_pos = 0; - void* ret = &alloca_array[alloca_pos]; - alloca_pos += length; - return ret; - } - } } else version (Posix) { import core.sys.posix.pthread; import core.sys.posix.stdlib; - public import core.stdc.stdlib : alloca; } +version(D_betterC) +{ + private const uint max_alloca = 10000; + private char[max_alloca] alloca_array; + private uint alloca_pos = 0; + void* alloca(size_t length) @nogc nothrow + { + if(alloca_pos + length > max_alloca)alloca_pos = 0; + void* ret = &alloca_array[alloca_pos]; + alloca_pos += length; + return ret; + } +} +else public import core.stdc.stdlib : alloca; + static struct Mallocator { static T[] makeArray(T)(size_t length) nothrow @nogc { T[] ret = (cast(T*)malloc(T.sizeof * length))[0 .. length]; - /*static if(__traits(isPOD, T)) + static if(__traits(isPOD, T)) { static immutable T init = T.init; @@ -71,21 +61,13 @@ static struct Mallocator } } else - {*/ + { static import std.conv; foreach(i;0..ret.length) { std.conv.emplace(&ret[i]); } - // } - - //static if(is(T == struct))std.conv.emplace(ret); - //static import std.conv; - //emplace - /*foreach(i;0..ret.length) - { - memcpy(ret); - }*/ + } return ret; } @@ -94,7 +76,6 @@ static struct Mallocator T[] ret = (cast(T*)malloc(T.sizeof * length))[0 .. length]; foreach(ref v; ret)v = initializer; return ret; - //return (cast(T*)ret)[0 .. length]; } static T[] expandArray(T)(T[] array, size_t length) nothrow @nogc @@ -107,17 +88,12 @@ static struct Mallocator { T[] ret = (cast(T*)malloc(T.sizeof * array.length))[0 .. array.length];//Mallocator.makeArray!(T)(array.length); foreach(i, ref v;ret)v = array[i]; - //ret[0 .. $] = array; return ret; } static T* make(T, Args...)(Args args) { T* ret = cast(T*)malloc(T.sizeof); - //*ret = T.init; - //static immutable T init = T(); - //memcpy(ret, &init, T.sizeof); - //static if(__traits(hasMember, T, "__ctor"))ret.__ctor(args); static import std.conv; static if(__traits(isPOD, T)) { @@ -125,7 +101,6 @@ static struct Mallocator memcpy(ret, &init, T.sizeof); } else static if(is(T == struct))std.conv.emplace(ret, args); - //else std.conv.emplace(ret, args); return ret; } @@ -135,7 +110,6 @@ static struct Mallocator version(Posix)posix_memalign(&ret, alignment, length);//ret = aligned_alloc(alignment, length); else version(Windows)ret = _aligned_malloc(length, alignment); else static assert(0, "Unimplemented platform!"); - //posix_memalign(&ret, alignment, length); return ret; } diff --git a/tests/tests.d b/tests/tests.d index 6784ea9..f966005 100644 --- a/tests/tests.d +++ b/tests/tests.d @@ -512,7 +512,7 @@ extern(C) int main() printf("TestComp(%u, %u)",test_comp.a,test_comp.b);//write(*test_comp); TestComp2* test_comp2 = entity.getComponent!TestComp2; if (test_comp2) - printf("TestComp2(%u, %u)",test_comp2.a,test_comp2.b);//write(*test_comp2); + printf("TestComp2(%u, %u)",test_comp2.b,test_comp2.a);//write(*test_comp2); TestComp3* test_comp3 = entity.getComponent!TestComp3; if (test_comp3) printf("TestComp3(%u, %u)",test_comp3.gg,test_comp3.bg);//write(*test_comp3); From d0c392631698c9c8a0b419dbf8cd8be42da2a20d Mon Sep 17 00:00:00 2001 From: Mergul Date: Sat, 12 Oct 2019 14:54:13 +0200 Subject: [PATCH 075/217] -betterC working on GDC -added some attributes like export and nothrow --- dub.json | 24 +++++++++++++++++++----- source/ecs/manager.d | 12 ++++++------ 2 files changed, 25 insertions(+), 11 deletions(-) diff --git a/dub.json b/dub.json index 4f1f32c..89db254 100755 --- a/dub.json +++ b/dub.json @@ -56,9 +56,18 @@ "name" : "dynlib-betterC", "targetType" : "dynamicLibrary", "dflags": [ - "-betterC", - "-defaultlib=", - "--fvisibility=hidden" + "-betterC" + ], + "dflags-ldc": [ + "--fvisibility=hidden", + "-link-defaultlib-shared" + ], + "dflags-gdc": [ + "-fno-druntime", + "-fvisibility=hidden" + ], + "lflags-gdc": [ + "-lpthread" ] }, { @@ -69,8 +78,13 @@ "source\/win_dll.d" ], "dflags": [ - "-betterC", - "-defaultlib=" + "-betterC" + ], + "dflags-gdc": [ + "-fno-druntime" + ], + "lflags-gdc": [ + "-lpthread" ] } ] diff --git a/source/ecs/manager.d b/source/ecs/manager.d index 52a5c86..375a0e0 100644 --- a/source/ecs/manager.d +++ b/source/ecs/manager.d @@ -233,7 +233,7 @@ export struct EntityManager /************************************************************************************************************************ *Default constructor. */ - this(uint threads_count) nothrow @nogc + export this(uint threads_count) nothrow @nogc { if (threads_count == 0) threads_count = 1; @@ -252,7 +252,7 @@ export struct EntityManager //event_manager.manager = this; } - ~this() nothrow @nogc + export ~this() nothrow @nogc { id_manager.deinitialize(); event_manager.destroy(); @@ -2439,7 +2439,7 @@ export struct EntityManager */ struct ComponentInfo { - nothrow ~this(){} + export ~this() nothrow @nogc {} ///Component size ushort size; ///Component data alignment @@ -2583,7 +2583,7 @@ export struct EntityManager return new_info; } - ~this() @nogc nothrow + export ~this() @nogc nothrow { if(components)Mallocator.dispose(components); if(deltas)Mallocator.dispose(deltas); @@ -2738,7 +2738,7 @@ export struct EntityManager struct SystemCaller { - ~this() nothrow @nogc + export ~this() nothrow @nogc { if (dependencies) { @@ -2830,7 +2830,7 @@ export struct EntityManager uint allocated = 0; } - ~this() nothrow @nogc + export ~this() nothrow @nogc { foreach(block;blocks) { From 7fa41f76710e6493ed2f8457bef6edc962117f68 Mon Sep 17 00:00:00 2001 From: Mergul Date: Wed, 30 Oct 2019 19:41:21 +0100 Subject: [PATCH 076/217] -fixed bug (Events was called before onAddEntity callback) --- source/ecs/manager.d | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/source/ecs/manager.d b/source/ecs/manager.d index 375a0e0..3708969 100644 --- a/source/ecs/manager.d +++ b/source/ecs/manager.d @@ -2235,14 +2235,17 @@ export struct EntityManager { EntityID entity_id = *cast(EntityID*) event_pointer; Entity* entity = id_manager.getEntityPointer(entity_id); - call_data.block = getMetaData(entity); - call_data.id = call_data.block.entityIndex(entity); - - foreach (caller; events[i].callers) + if(entity) { - call_data.system_pointer = caller.system.m_system_pointer; - (cast(void function(ref EventCallData) nothrow @nogc) caller - .callback)(call_data); + call_data.block = getMetaData(entity); + call_data.id = call_data.block.entityIndex(entity); + + foreach (caller; events[i].callers) + { + call_data.system_pointer = caller.system.m_system_pointer; + (cast(void function(ref EventCallData) nothrow @nogc) caller + .callback)(call_data); + } } event_pointer += events[i].size; } @@ -2258,11 +2261,11 @@ export struct EntityManager export void commit() { - updateEvents(); id_manager.optimize(); updateBlocks(); removeEntities(); changeEntities(); + updateEvents(); event_manager.clearEvents(); } From 015783bf5cfbc6601e0b6a63cdb40d5f3d7cb411 Mon Sep 17 00:00:00 2001 From: Mergul Date: Sat, 2 Nov 2019 18:51:03 +0100 Subject: [PATCH 077/217] -remove '-defaultlib' from dub.json -start working with WebAssembly -modified .gitignore -added meson build file (WIP) --- .gitignore | 4 +- dub.json | 3 -- meson.build | 44 ++++++++++++++++++++++ meson_options.txt | 1 + source/ecs/manager.d | 4 +- source/ecs/simple_vector.d | 2 +- source/ecs/std.d | 76 +++++++++++++++++++++++++++++++++++++- source/ecs/vector.d | 5 ++- tests/tests.d | 23 +++++++++--- 9 files changed, 145 insertions(+), 17 deletions(-) create mode 100644 meson.build create mode 100644 meson_options.txt diff --git a/.gitignore b/.gitignore index 280be93..91092a6 100644 --- a/.gitignore +++ b/.gitignore @@ -4,4 +4,6 @@ !tests/** !README.md !./dub.json -!.gitignore \ No newline at end of file +!.gitignore +!meson.build +!meson_options.txt \ No newline at end of file diff --git a/dub.json b/dub.json index 89db254..e4d9704 100755 --- a/dub.json +++ b/dub.json @@ -7,9 +7,6 @@ "copyright": "Copyright © 2018-2019, Michał Masiukiewicz, Dawid Masiukiewicz", "license": "BSD", "sourcePaths" : ["source\/"], - "dflags-posix-ldc": [ - "-defaultlib=phobos2-ldc,druntime-ldc" - ], "dflagss": [ "-betterC" ], diff --git a/meson.build b/meson.build new file mode 100644 index 0000000..27c4a79 --- /dev/null +++ b/meson.build @@ -0,0 +1,44 @@ +project('DECS', 'd') + +src = [ + 'source/ecs/attributes.d', + 'source/ecs/block_allocator.d', + 'source/ecs/core.d', + 'source/ecs/entity.d', + 'source/ecs/events.d', + 'source/ecs/hash_map.d', + 'source/ecs/id_manager.d', + 'source/ecs/manager.d', + 'source/ecs/simple_vector.d', + 'source/ecs/simple_vector.d', + 'source/ecs/std.d', + 'source/ecs/system.d', + 'source/ecs/traits.d', + 'source/ecs/vector.d', + 'source/ecs/package.d' +] + +tests_src = [ + 'tests/tests.d' +] + +betterC_opt = get_option('betterC') + +comp = meson.get_compiler('d') + +comp_id = comp.get_id() + +args = [] +link_args = [] + +if betterC_opt + args += '-betterC' + link_args += '-betterC' +endif + +inc = include_directories('source/') +tests_inc = include_directories('source/') + +executable('ecs', [tests_src, src], include_directories : [tests_inc, inc], d_args: args, link_args: link_args) + + diff --git a/meson_options.txt b/meson_options.txt new file mode 100644 index 0000000..fdf13a4 --- /dev/null +++ b/meson_options.txt @@ -0,0 +1 @@ +option('betterC', type: 'boolean', value: false) \ No newline at end of file diff --git a/source/ecs/manager.d b/source/ecs/manager.d index 3708969..8d461fd 100644 --- a/source/ecs/manager.d +++ b/source/ecs/manager.d @@ -8,8 +8,8 @@ import std.conv : to; import std.traits; import core.atomic; -import core.stdc.stdlib : qsort; -import core.stdc.string; +//import core.stdc.stdlib : qsort; +//import core.stdc.string; import ecs.system;//not ordered as forward reference bug workaround import ecs.block_allocator; diff --git a/source/ecs/simple_vector.d b/source/ecs/simple_vector.d index 6310d69..175c015 100644 --- a/source/ecs/simple_vector.d +++ b/source/ecs/simple_vector.d @@ -2,7 +2,7 @@ module ecs.simple_vector; import ecs.std; -import core.stdc.string; +//import core.stdc.string; struct SimpleVector { diff --git a/source/ecs/std.d b/source/ecs/std.d index 249ec41..0e80660 100644 --- a/source/ecs/std.d +++ b/source/ecs/std.d @@ -1,10 +1,30 @@ module ecs.std; -import core.stdc.stdlib : malloc, free, realloc; -import core.stdc.string : memcpy; +//import core.stdc.stdlib : malloc, free, realloc; +//import core.stdc.string : memcpy; import std.traits; +version(WebAssembly) +{ + extern(C) void free(void*) @nogc nothrow @system; + extern(C) void* malloc(size_t size) @nogc nothrow @system; + extern(C) void* realloc(void*, size_t size) @nogc nothrow @system; + + extern(C) void* memcpy(return void*, scope const void*, size_t size) @nogc nothrow @system; + extern(C) void* memset(void*, int val, size_t size) @nogc nothrow @system; + + extern(C) void qsort(void* base, size_t num, size_t size, + int function(const void*,const void*) compar) @nogc nothrow @system; +} +else +{ + public import core.stdc.stdlib : malloc, free, realloc; + public import core.stdc.string : memcpy, memset; + public import core.stdc.stdlib : qsort; +} + + version (Windows) { import core.sys.windows.windows; @@ -43,6 +63,19 @@ version(D_betterC) return ret; } } +else version(WebAssembly) +{ + private const uint max_alloca = 10000; + private char[max_alloca] alloca_array; + private uint alloca_pos = 0; + void* alloca(size_t length) @nogc nothrow + { + if(alloca_pos + length > max_alloca)alloca_pos = 0; + void* ret = &alloca_array[alloca_pos]; + alloca_pos += length; + return ret; + } +} else public import core.stdc.stdlib : alloca; static struct Mallocator @@ -109,6 +142,7 @@ static struct Mallocator void* ret; version(Posix)posix_memalign(&ret, alignment, length);//ret = aligned_alloc(alignment, length); else version(Windows)ret = _aligned_malloc(length, alignment); + else version(WebAssembly)ret = malloc(length); else static assert(0, "Unimplemented platform!"); return ret; } @@ -124,6 +158,7 @@ static struct Mallocator static if(__traits(hasMember, T, "__dtor"))object.__dtor(); version(Posix)free(cast(void*)object); else version(Windows)_aligned_free(cast(void*)object); + else version(WebAssembly)free(cast(void*)object); else static assert(0, "Unimplemented platform!"); } @@ -197,4 +232,41 @@ struct Mutex private pthread_mutex_t m_handle; } + else version(WebAssembly) + { + void initialize() nothrow @nogc + { + /*pthread_mutexattr_t attr = void; + + pthread_mutexattr_init(&attr); + + pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); + pthread_mutex_init(cast(pthread_mutex_t*) &m_handle, &attr); + + pthread_mutexattr_destroy(&attr);*/ + } + + void destroy() nothrow @nogc + { + //pthread_mutex_destroy(&m_handle); + } + + void lock() nothrow @nogc + { + //pthread_mutex_lock(&m_handle); + } + + void unlock() nothrow @nogc + { + //pthread_mutex_unlock(&m_handle); + } + + int tryLock() nothrow @nogc + { + return 0;//return pthread_mutex_trylock(&m_handle) == 0; + } + + private int m_handle; + } + else static assert(0, "unsupported platform!"); } \ No newline at end of file diff --git a/source/ecs/vector.d b/source/ecs/vector.d index 7c029d0..81474f0 100644 --- a/source/ecs/vector.d +++ b/source/ecs/vector.d @@ -1,8 +1,9 @@ module ecs.vector; import core.bitop; -import core.stdc.stdlib : free, malloc; -import core.stdc.string : memcpy, memset; +//import core.stdc.stdlib : free, malloc; +import ecs.std; +//import core.stdc.string : memcpy, memset; //import std.algorithm : swap; import std.conv : emplace; import std.traits : hasMember, isCopyable, TemplateOf, Unqual; diff --git a/tests/tests.d b/tests/tests.d index f966005..57cb991 100644 --- a/tests/tests.d +++ b/tests/tests.d @@ -10,11 +10,24 @@ import ecs.system; import ecs.attributes; import ecs.core; -import core.time; -import std.stdio; -version(Windows) + +version(WebAssembly) { + extern(C) void printf(const char *format, ...) @nogc nothrow @system; + struct Time + { + static long getUSecTime() + { + return 0; + } + } + + extern(C) void _start() {} +} +else version(Windows) +{ + import core.stdc.stdio : printf; import core.sys.windows.windows; struct Time { @@ -29,6 +42,7 @@ version(Windows) } else version(Posix) { + import core.stdc.stdio : printf; import core.sys.posix.time; struct Time { @@ -287,7 +301,6 @@ struct TestSystem { assert(cast(size_t)&test % TestComp.alignof == 0); assert(cast(size_t)&test2 % TestComp2.alignof == 0); - import std.stdio; test.a += 1000; test.b += 2000; @@ -440,7 +453,6 @@ struct TestSystem2 void onEnable() { - import std.stdio; //writeln("TestSystem2 enabled"); printf("TestSystem2 enabled\n"); @@ -448,7 +460,6 @@ struct TestSystem2 void onDisable() { - import std.stdio; //writeln("TestSystem2 disabled"); printf("TestSystem2 disabled\n"); From a8c74d504566856483ae40208be2f2330339efcc Mon Sep 17 00:00:00 2001 From: Mergul Date: Tue, 5 Nov 2019 09:21:02 +0100 Subject: [PATCH 078/217] -make tests working on web -WebAssembly now is compiled with emscripten use (stdc functions bindings only) -added python script to build WASM version --- .gitignore | 3 +- compile_wasm.py | 91 +++++++++++++++++++++++++++++++++++++++++++++ source/ecs/std.d | 12 +++--- source/ecs/vector.d | 6 +-- tests/tests.d | 69 +++++++++++++++++++++++++++------- 5 files changed, 158 insertions(+), 23 deletions(-) create mode 100644 compile_wasm.py diff --git a/.gitignore b/.gitignore index 91092a6..8a5c5c8 100644 --- a/.gitignore +++ b/.gitignore @@ -6,4 +6,5 @@ !./dub.json !.gitignore !meson.build -!meson_options.txt \ No newline at end of file +!meson_options.txt +!compile_wasm.py \ No newline at end of file diff --git a/compile_wasm.py b/compile_wasm.py new file mode 100644 index 0000000..663ef19 --- /dev/null +++ b/compile_wasm.py @@ -0,0 +1,91 @@ +import os +import ntpath +import sys + +shared_flags = '' +clean = 0 + +for arg in sys.argv: + if(arg == '-O3'): + shared_flags += '-O3 ' + elif(arg == '-O2'): + shared_flags += '-O2 ' + elif(arg == '-O1'): + shared_flags += '-O1 ' + elif(arg == '-O0'): + shared_flags += '-O0 ' + elif(arg == '-Os'): + shared_flags += '-Os ' + elif(arg == '-Oz'): + shared_flags += '-Oz ' + elif(arg == '-g'): + shared_flags += '-g ' + elif(arg == '--clean'): + clean = 1 + +if clean == 1: + for path in ['bc']: + for r, d, f in os.walk(path): + for file in f: + filename, file_extension = os.path.splitext(file) + if file_extension == '.bc': + print('remove ' + os.path.join(r, file)) + os.remove(os.path.join(r, file)) + exit() + + +paths = ['tests', 'source'] + +files = [] +# r=root, d=directories, f = files +for path in paths: + for r, d, f in os.walk(path): + for file in f: + if ntpath.basename(file) != 'win_dll.d': + filename, file_extension = os.path.splitext(file) + if file_extension == '.d': + files.append(os.path.join(r, file)) + + +print('files:') +for f in files: + print(f) +print + +ldc_cmd = 'ldc2 ' + shared_flags + '-mtriple=wasm32-unknown-unknown-wasm -betterC -L-allow-undefined --output-bc --od=bc --checkaction=C ' + +for path in paths: + ldc_cmd += '-I' + path + ' ' + +for f in files: + ldc_cmd += f + ' ' + +print ldc_cmd + +os.system(ldc_cmd) + +print + +files = [] +# r=root, d=directories, f = files +for path in ['bc']: + for r, d, f in os.walk(path): + for file in f: + filename, file_extension = os.path.splitext(file) + if file_extension == '.bc': + files.append(os.path.join(r, file)) + + +print('BC files:') +for f in files: + print(f) +print + +emcc_cmd = 'emcc -v ' + shared_flags + '-s ALLOW_MEMORY_GROWTH=1 -s MALLOC=dlmalloc -s WASM=1 -o index.html ' + +for f in files: + emcc_cmd += f + ' ' + +print emcc_cmd + +os.system(emcc_cmd) diff --git a/source/ecs/std.d b/source/ecs/std.d index 0e80660..c52d3af 100644 --- a/source/ecs/std.d +++ b/source/ecs/std.d @@ -7,15 +7,16 @@ import std.traits; version(WebAssembly) { + extern(C) int memcmp (const void *s1, const void *s2, size_t size); + extern(C) void exit (int status) nothrow @nogc; + extern(C) void __assert(const(char)* msg, const(char)* file, uint line) { exit(-20);} extern(C) void free(void*) @nogc nothrow @system; extern(C) void* malloc(size_t size) @nogc nothrow @system; extern(C) void* realloc(void*, size_t size) @nogc nothrow @system; - extern(C) void* memcpy(return void*, scope const void*, size_t size) @nogc nothrow @system; extern(C) void* memset(void*, int val, size_t size) @nogc nothrow @system; - - extern(C) void qsort(void* base, size_t num, size_t size, - int function(const void*,const void*) compar) @nogc nothrow @system; + extern(C) int posix_memalign(void**, size_t, size_t) @nogc nothrow @system; + extern(C) void qsort(void* base, size_t num, size_t size, int function(const void*,const void*) compar) @nogc nothrow @system; } else { @@ -142,7 +143,7 @@ static struct Mallocator void* ret; version(Posix)posix_memalign(&ret, alignment, length);//ret = aligned_alloc(alignment, length); else version(Windows)ret = _aligned_malloc(length, alignment); - else version(WebAssembly)ret = malloc(length); + else version(WebAssembly)posix_memalign(&ret, alignment, length);//malloc(length); else static assert(0, "Unimplemented platform!"); return ret; } @@ -160,7 +161,6 @@ static struct Mallocator else version(Windows)_aligned_free(cast(void*)object); else version(WebAssembly)free(cast(void*)object); else static assert(0, "Unimplemented platform!"); - } } diff --git a/source/ecs/vector.d b/source/ecs/vector.d index 81474f0..84ecc51 100644 --- a/source/ecs/vector.d +++ b/source/ecs/vector.d @@ -198,7 +198,7 @@ public: } export ref T opIndex(size_t elemNum) { - debug assert(elemNum < used, "Range violation [index]"); + //debug assert(elemNum < used, "Range violation [index]"); return array.ptr[elemNum]; } @@ -221,12 +221,12 @@ public: } export void opOpAssign(string op)(T obj) { - static assert(op == "~"); + //static assert(op == "~"); add(obj); } export void opOpAssign(string op, X)(X[] obj) { - static assert(op == "~"); + //static assert(op == "~"); add(obj); } diff --git a/tests/tests.d b/tests/tests.d index 57cb991..2e5e3e6 100644 --- a/tests/tests.d +++ b/tests/tests.d @@ -14,15 +14,52 @@ import ecs.core; version(WebAssembly) { - extern(C) void printf(const char *format, ...) @nogc nothrow @system; - struct Time + extern(C) int printf(scope const char* format, ...) @nogc nothrow @system; + /*{ + return 0; + }*/ + //import core.stdc.stdio : printf; + /*struct Time { static long getUSecTime() { return 0; } + }*/ + + alias int time_t; + alias int clockid_t; + enum CLOCK_REALTIME = 0; + + struct timespec + { + time_t tv_sec; + int tv_nsec; } + extern(C) int clock_gettime(clockid_t, timespec*) @nogc nothrow @system; + + struct Time + { + + + static long getUSecTime() + { + time_t time; + timespec spec; + + clock_gettime(CLOCK_REALTIME, &spec); + + //time = spec.tv_sec; + return spec.tv_sec * 1000_000 + spec.tv_nsec / 1000;//time / 1000_000; + + /*LARGE_INTEGER time, freq; + QueryPerformanceFrequency(&freq); + QueryPerformanceCounter(&time); + return time.QuadPart / (freq.QuadPart / 1000_000);*/ + } + } + extern(C) void _start() {} } else version(Windows) @@ -195,20 +232,20 @@ struct ChangeTestSystem { //printf("Entity added! ID: "); foreach (i; 0 .. data.length) - printf("Entity added! ID: %u\n",data.entites[i].id); + printf("Entity added! ID: %u\n",cast(uint)data.entites[i].id.id); ////writeln("Entity added! ID: ", data.entites[i].id); } void onRemoveEntity(EntitiesData data) { ////writeln("Entity removed! ID: ", data.entites[0].id); - printf("Entity removed! ID: %u\n",data.entites[0].id); + printf("Entity removed! ID: %u\n",cast(uint)data.entites[0].id.id); } void onChangeEntity(EntitiesData data) { ////writeln("Entity changed! ID: ", data.entites[0].id); - printf("Entity changed! ID: %u\n",data.entites[0].id); + printf("Entity changed! ID: %u\n",cast(uint)data.entites[0].id.id); } bool onBegin() @@ -299,8 +336,8 @@ struct TestSystem void onUpdate(ref Entity entity, ref TestComp test, ref TestComp2 test2) //, TestComp3* test3) //ref TestComp comp) { - assert(cast(size_t)&test % TestComp.alignof == 0); - assert(cast(size_t)&test2 % TestComp2.alignof == 0); + //assert(cast(size_t)&test % TestComp.alignof == 0); + //assert(cast(size_t)&test2 % TestComp2.alignof == 0); test.a += 1000; test.b += 2000; @@ -504,6 +541,8 @@ struct TestSystem2 extern(C) int main() { + + void dispatch(EntityManager.JobGroup jobs) nothrow @nogc { foreach (job; jobs.jobs) @@ -516,28 +555,32 @@ extern(C) int main() void writeEntityComponents(Entity* entity) { - printf("EntityID(%u, %u)",entity.id.id,entity.id.counter); + printf("EntityID(%u, %u)",cast(uint)entity.id.id,cast(uint)entity.id.counter); //write(entity.id); TestComp* test_comp = entity.getComponent!TestComp; if (test_comp) - printf("TestComp(%u, %u)",test_comp.a,test_comp.b);//write(*test_comp); + printf("TestComp(%u, %u)",cast(uint)test_comp.a,cast(uint)test_comp.b);//write(*test_comp); TestComp2* test_comp2 = entity.getComponent!TestComp2; if (test_comp2) - printf("TestComp2(%u, %u)",test_comp2.b,test_comp2.a);//write(*test_comp2); + printf("TestComp2(%u, %u)",cast(uint)test_comp2.b,cast(uint)test_comp2.a);//write(*test_comp2); TestComp3* test_comp3 = entity.getComponent!TestComp3; if (test_comp3) - printf("TestComp3(%u, %u)",test_comp3.gg,test_comp3.bg);//write(*test_comp3); + printf("TestComp3(%u, %u)",cast(uint)test_comp3.gg,cast(uint)test_comp3.bg);//write(*test_comp3); TestComp4* test_comp4 = entity.getComponent!TestComp4; if (test_comp4) - printf("TestComp4(%u, %u, %u, %u, %u, %u)",test_comp4.gg,test_comp4.bg,test_comp4.a,test_comp4.b,test_comp4.c,test_comp4.g);//write(*test_comp4); + printf("TestComp4(%u, %u, %u, %u, %u, %u)",test_comp4.gg,test_comp4.bg,cast(uint)test_comp4.a,cast(uint)test_comp4.b,cast(uint)test_comp4.c,cast(uint)test_comp4.g);//write(*test_comp4); printf("\n"); //writeln(); ////writeln((cast(uint*) pp)[0 .. 14], " ", pp); } + /*int a = 0; + if(!a)assert(0);*/ + EntityManager.initialize(1); + gEM.setJobDispachFunc(&dispatch); - assert(gEM !is null); + //assert(gEM !is null); gEM.beginRegister(); gEM.registerPass("fixed"); From 73f2aa6861990187b630890a6d769c5319d1da72 Mon Sep 17 00:00:00 2001 From: Mergul Date: Wed, 6 Nov 2019 20:38:46 +0100 Subject: [PATCH 079/217] -improved WASM compilation scripts -added external bindbc.sdl import for WASM -working on demos (WIP, working simple demo with ECS and SDL2) -small change in ecs.std --- compile_wasm.py | 125 ++- demos/.gitignore | 12 + demos/SDL2.dll | Bin 0 -> 1401344 bytes demos/SDL2_image.dll | Bin 0 -> 125440 bytes demos/assets/textures/buckler.png | Bin 0 -> 575 bytes demos/compile_wasm.py | 93 +++ .../imports/bindbc/sdl/bind/package.d | 46 ++ demos/external/imports/bindbc/sdl/bind/sdl.d | 69 ++ .../imports/bindbc/sdl/bind/sdlassert.d | 70 ++ .../imports/bindbc/sdl/bind/sdlaudio.d | 283 +++++++ .../imports/bindbc/sdl/bind/sdlblendmode.d | 71 ++ .../imports/bindbc/sdl/bind/sdlclipboard.d | 31 + .../imports/bindbc/sdl/bind/sdlcpuinfo.d | 130 ++++ .../imports/bindbc/sdl/bind/sdlerror.d | 28 + .../imports/bindbc/sdl/bind/sdlevents.d | 674 +++++++++++++++++ .../imports/bindbc/sdl/bind/sdlfilesystem.d | 31 + .../bindbc/sdl/bind/sdlgamecontroller.d | 225 ++++++ .../imports/bindbc/sdl/bind/sdlgesture.d | 36 + .../imports/bindbc/sdl/bind/sdlhaptic.d | 240 ++++++ .../imports/bindbc/sdl/bind/sdlhints.d | 186 +++++ .../imports/bindbc/sdl/bind/sdljoystick.d | 231 ++++++ .../imports/bindbc/sdl/bind/sdlkeyboard.d | 80 ++ .../imports/bindbc/sdl/bind/sdlkeycode.d | 288 +++++++ .../imports/bindbc/sdl/bind/sdlloadso.d | 28 + .../external/imports/bindbc/sdl/bind/sdllog.d | 107 +++ .../imports/bindbc/sdl/bind/sdlmessagebox.d | 75 ++ .../imports/bindbc/sdl/bind/sdlmouse.d | 140 ++++ .../imports/bindbc/sdl/bind/sdlpixels.d | 283 +++++++ .../imports/bindbc/sdl/bind/sdlplatform.d | 22 + .../imports/bindbc/sdl/bind/sdlpower.d | 33 + .../imports/bindbc/sdl/bind/sdlrect.d | 80 ++ .../imports/bindbc/sdl/bind/sdlrender.d | 316 ++++++++ .../imports/bindbc/sdl/bind/sdlrwops.d | 208 +++++ .../imports/bindbc/sdl/bind/sdlscancode.d | 542 +++++++++++++ .../imports/bindbc/sdl/bind/sdlshape.d | 63 ++ .../imports/bindbc/sdl/bind/sdlstdinc.d | 42 ++ .../imports/bindbc/sdl/bind/sdlsurface.d | 230 ++++++ .../imports/bindbc/sdl/bind/sdlsystem.d | 152 ++++ .../imports/bindbc/sdl/bind/sdlsyswm.d | 240 ++++++ .../imports/bindbc/sdl/bind/sdltimer.d | 51 ++ .../imports/bindbc/sdl/bind/sdltouch.d | 67 ++ .../imports/bindbc/sdl/bind/sdlversion.d | 83 ++ .../imports/bindbc/sdl/bind/sdlvideo.d | 677 +++++++++++++++++ .../imports/bindbc/sdl/bind/sdlvulkan.d | 45 ++ demos/external/imports/bindbc/sdl/config.d | 44 ++ demos/external/imports/bindbc/sdl/dynload.d | 712 ++++++++++++++++++ demos/external/imports/bindbc/sdl/image.d | 353 +++++++++ demos/external/imports/bindbc/sdl/mixer.d | 569 ++++++++++++++ demos/external/imports/bindbc/sdl/package.d | 18 + demos/external/imports/bindbc/sdl/ttf.d | 368 +++++++++ demos/libpng16-16.dll | Bin 0 -> 210944 bytes demos/simple/dub.json | 50 ++ demos/simple/source/app.d | 216 ++++++ demos/simple/source/utils/texture.d | 49 ++ demos/simple/source/utils/utils.d | 110 +++ demos/utils/dub.json | 50 ++ demos/utils/source/ecs_utils/math/matrix.d | 6 + demos/utils/source/ecs_utils/math/vector.d | 100 +++ demos/zlib1.dll | Bin 0 -> 108544 bytes source/ecs/std.d | 4 +- 60 files changed, 9015 insertions(+), 67 deletions(-) create mode 100644 demos/.gitignore create mode 100644 demos/SDL2.dll create mode 100644 demos/SDL2_image.dll create mode 100644 demos/assets/textures/buckler.png create mode 100644 demos/compile_wasm.py create mode 100644 demos/external/imports/bindbc/sdl/bind/package.d create mode 100644 demos/external/imports/bindbc/sdl/bind/sdl.d create mode 100644 demos/external/imports/bindbc/sdl/bind/sdlassert.d create mode 100644 demos/external/imports/bindbc/sdl/bind/sdlaudio.d create mode 100644 demos/external/imports/bindbc/sdl/bind/sdlblendmode.d create mode 100644 demos/external/imports/bindbc/sdl/bind/sdlclipboard.d create mode 100644 demos/external/imports/bindbc/sdl/bind/sdlcpuinfo.d create mode 100644 demos/external/imports/bindbc/sdl/bind/sdlerror.d create mode 100644 demos/external/imports/bindbc/sdl/bind/sdlevents.d create mode 100644 demos/external/imports/bindbc/sdl/bind/sdlfilesystem.d create mode 100644 demos/external/imports/bindbc/sdl/bind/sdlgamecontroller.d create mode 100644 demos/external/imports/bindbc/sdl/bind/sdlgesture.d create mode 100644 demos/external/imports/bindbc/sdl/bind/sdlhaptic.d create mode 100644 demos/external/imports/bindbc/sdl/bind/sdlhints.d create mode 100644 demos/external/imports/bindbc/sdl/bind/sdljoystick.d create mode 100644 demos/external/imports/bindbc/sdl/bind/sdlkeyboard.d create mode 100644 demos/external/imports/bindbc/sdl/bind/sdlkeycode.d create mode 100644 demos/external/imports/bindbc/sdl/bind/sdlloadso.d create mode 100644 demos/external/imports/bindbc/sdl/bind/sdllog.d create mode 100644 demos/external/imports/bindbc/sdl/bind/sdlmessagebox.d create mode 100644 demos/external/imports/bindbc/sdl/bind/sdlmouse.d create mode 100644 demos/external/imports/bindbc/sdl/bind/sdlpixels.d create mode 100644 demos/external/imports/bindbc/sdl/bind/sdlplatform.d create mode 100644 demos/external/imports/bindbc/sdl/bind/sdlpower.d create mode 100644 demos/external/imports/bindbc/sdl/bind/sdlrect.d create mode 100644 demos/external/imports/bindbc/sdl/bind/sdlrender.d create mode 100644 demos/external/imports/bindbc/sdl/bind/sdlrwops.d create mode 100644 demos/external/imports/bindbc/sdl/bind/sdlscancode.d create mode 100644 demos/external/imports/bindbc/sdl/bind/sdlshape.d create mode 100644 demos/external/imports/bindbc/sdl/bind/sdlstdinc.d create mode 100644 demos/external/imports/bindbc/sdl/bind/sdlsurface.d create mode 100644 demos/external/imports/bindbc/sdl/bind/sdlsystem.d create mode 100644 demos/external/imports/bindbc/sdl/bind/sdlsyswm.d create mode 100644 demos/external/imports/bindbc/sdl/bind/sdltimer.d create mode 100644 demos/external/imports/bindbc/sdl/bind/sdltouch.d create mode 100644 demos/external/imports/bindbc/sdl/bind/sdlversion.d create mode 100644 demos/external/imports/bindbc/sdl/bind/sdlvideo.d create mode 100644 demos/external/imports/bindbc/sdl/bind/sdlvulkan.d create mode 100644 demos/external/imports/bindbc/sdl/config.d create mode 100644 demos/external/imports/bindbc/sdl/dynload.d create mode 100644 demos/external/imports/bindbc/sdl/image.d create mode 100644 demos/external/imports/bindbc/sdl/mixer.d create mode 100644 demos/external/imports/bindbc/sdl/package.d create mode 100644 demos/external/imports/bindbc/sdl/ttf.d create mode 100644 demos/libpng16-16.dll create mode 100644 demos/simple/dub.json create mode 100644 demos/simple/source/app.d create mode 100644 demos/simple/source/utils/texture.d create mode 100644 demos/simple/source/utils/utils.d create mode 100644 demos/utils/dub.json create mode 100644 demos/utils/source/ecs_utils/math/matrix.d create mode 100644 demos/utils/source/ecs_utils/math/vector.d create mode 100644 demos/zlib1.dll diff --git a/compile_wasm.py b/compile_wasm.py index 663ef19..da42783 100644 --- a/compile_wasm.py +++ b/compile_wasm.py @@ -2,11 +2,47 @@ import os import ntpath import sys +def compile(sources, output): + files = [] + # r=root, d=directories, f = files + for path in sources: + for r, d, f in os.walk(path): + for file in f: + if ntpath.basename(file) != 'win_dll.d': + filename, file_extension = os.path.splitext(file) + if file_extension == '.d' and filename != 'package': + files.append(os.path.join(r, file)) + + ldc_cmd = 'ldc2 ' + shared_flags + ldc_flags + '-oq -mtriple=wasm32-unknown-unknown-wasm -betterC -L-allow-undefined --output-bc --od=.bc --singleobj --checkaction=C --of=' + output + ' ' + + for path in sources: + ldc_cmd += '-I' + path + ' ' + + for path in import_paths: + ldc_cmd += '-I' + path + ' ' + + for f in files: + ldc_cmd += f + ' ' + + print ldc_cmd + + if os.system(ldc_cmd): + exit(0) + print + shared_flags = '' clean = 0 +emc_flags = '' +ldc_flags = '' +import_paths = ['source','tests'] +build_tests = 0 -for arg in sys.argv: - if(arg == '-O3'): +for arg in sys.argv[1:]: + if(arg == '-release'): + ldc_flags += '-release ' + elif(arg == '-enable-inlining'): + ldc_flags += '-enable-inlining ' + elif(arg == '-O3'): shared_flags += '-O3 ' elif(arg == '-O2'): shared_flags += '-O2 ' @@ -20,71 +56,30 @@ for arg in sys.argv: shared_flags += '-Oz ' elif(arg == '-g'): shared_flags += '-g ' - elif(arg == '--clean'): - clean = 1 - -if clean == 1: - for path in ['bc']: - for r, d, f in os.walk(path): - for file in f: - filename, file_extension = os.path.splitext(file) - if file_extension == '.bc': - print('remove ' + os.path.join(r, file)) - os.remove(os.path.join(r, file)) - exit() - - -paths = ['tests', 'source'] - -files = [] -# r=root, d=directories, f = files -for path in paths: - for r, d, f in os.walk(path): - for file in f: - if ntpath.basename(file) != 'win_dll.d': - filename, file_extension = os.path.splitext(file) - if file_extension == '.d': - files.append(os.path.join(r, file)) - - -print('files:') -for f in files: - print(f) -print - -ldc_cmd = 'ldc2 ' + shared_flags + '-mtriple=wasm32-unknown-unknown-wasm -betterC -L-allow-undefined --output-bc --od=bc --checkaction=C ' - -for path in paths: - ldc_cmd += '-I' + path + ' ' + elif(arg == '--build-tests'): + build_tests = 1 + elif(arg == '--llvm-lto'): + emc_flags += '--llvm-lto 3 ' + elif(arg == '--simd'): + emc_flags += '-s SIMD=1 ' + elif(arg == '-opt'): + shared_flags += '-O3 ' + ldc_flags += '-release -enable-inlining ' + emc_flags += '--llvm-lto 3 -s SIMD=1 ' + else: + print('unknown argument: ' + arg) + exit() -for f in files: - ldc_cmd += f + ' ' - -print ldc_cmd - -os.system(ldc_cmd) - -print - -files = [] -# r=root, d=directories, f = files -for path in ['bc']: - for r, d, f in os.walk(path): - for file in f: - filename, file_extension = os.path.splitext(file) - if file_extension == '.bc': - files.append(os.path.join(r, file)) +compile(['source'], 'ecs.bc') + +if build_tests == 0: + exit(0) + +compile(['tests'], 'tests.bc') - -print('BC files:') -for f in files: - print(f) -print - -emcc_cmd = 'emcc -v ' + shared_flags + '-s ALLOW_MEMORY_GROWTH=1 -s MALLOC=dlmalloc -s WASM=1 -o index.html ' - -for f in files: - emcc_cmd += f + ' ' +emcc_cmd = 'emcc -v ' + shared_flags + emc_flags + '-s ALLOW_MEMORY_GROWTH=1 -s MALLOC=dlmalloc -s WASM=1 -o index.html ' + +emcc_cmd += 'ecs.bc tests.bc' print emcc_cmd diff --git a/demos/.gitignore b/demos/.gitignore new file mode 100644 index 0000000..c799805 --- /dev/null +++ b/demos/.gitignore @@ -0,0 +1,12 @@ +* +!*/ +!**/dub.json +!libs/ +!*.dll +!utils/**/*.d +!simple/**/*.d +!launcher/**/*.d +!assets/** +!external/**/*.d +!.gitignore +!compile_wasm.py \ No newline at end of file diff --git a/demos/SDL2.dll b/demos/SDL2.dll new file mode 100644 index 0000000000000000000000000000000000000000..0edb386ee53cea568b80bf02306c9b256455ba0d GIT binary patch literal 1401344 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

B9_8fdI(TPE{Fb1CVgV-){zJ7y@Dg}nuTv{xn{ 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²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 hDPtF0CTiN7a>^tpU&b_-5txo$EJB>~9^F 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∓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

  • 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

    _cLxV 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 literal 0 HcmV?d00001 diff --git a/demos/SDL2_image.dll b/demos/SDL2_image.dll new file mode 100644 index 0000000000000000000000000000000000000000..d7016555aee06c8480f66c2cb1ad5ed15c8f1856 GIT binary patch literal 125440 zcmd44e|%KM)jz&B*+9Y%Z^T4Xf0SrfO%ySyQnR9MF1Z`-!Um)KkX9;aFrp%&>;kq3 ziFX$=UM`J-K3cW)X?l80;28)NCH$%f+C;~2CRB73m8#DKw&@cGjngUsO|Ig z_5J6Ym$LKY%*>fHXU?2Cb7pSUFB(0W9*@V1|5GWCrwPCGSI+4bI3I?ukks&nNgF*++%}B$vP%Zs))h&JcK0Jc}aq zH&-McpOWFE6!K(ImV&&JzMsC7+zd}O5uq@{6FLRI)ft{LB21U$S(rmm&fkm-&o^%P zdwvVcGdxA#lRoQ58J+^F@1OjQ4BxUajJ#eQ{UsEs?}Sg<-waRnjFB^M3g3jZZc2X& zFx2e^{HFbtduGH(-Xj3(EwY7N-uZd_I(?U=r`}48h~&f059;d_{X>5 zN&t7u?7INSd18iBpYX;ULKb)hra%L`#Yx<_b8#XGFl}VGYpF*`2Y3%I~+Z^kZW37NT@*n$5@|4CA zUqO7D+Nv4nd=jVnN8Nf_hKJ?f%k$S$)!mx>*VD9EJe;%6Lj9>7$xk%nk~Tma0gv9B z5ti2t2blF!plXjoiI8#rdgKO;AwKKwd4z2%6)z7Nm%PN&t31}vd3uYcAIjGJM-~jx zi~$7mS*ksm)Ywt$nR-;v3OR(oV5^r)rqZ~Rpe@U^|Bj5*Ryno_zqe?H_xutBfPNwG z#nfyd@#L@!^pVj2A=NEw{*Azu`k*p$--zX8=x6k zV>t*0DjpshWY&5DKu=TcsjMM~B##(HeN)j5H%|YhGEMpA#=gNTL|^zLb*N}FdNm-m zEiylOmHxF9$+8yR1#-LP4lW@O%D4n@#Yivhr25`PdS9d|J@OD*N?r^W%+kNkjGWh3 z(@Fuv(P5jdJ2*m-jM9V5QZT3~{Bc(0UET;j)j+62uY-O-+2hfVNs$XeO!bwqNxsW9 z7V;HY-E%@(mh~ilH8blG{A`qms~(S-GDcPdQrNcGmhe^VE&UTIJdm}}�b_8R3DeGs0u_ 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 SDLSupport.sdl209) { + enum : uint { + SDL_INIT_TIMER = 0x00000001, + SDL_INIT_AUDIO = 0x00000010, + SDL_INIT_VIDEO = 0x00000020, + SDL_INIT_JOYSTICK = 0x00000200, + SDL_INIT_HAPTIC = 0x00001000, + SDL_INIT_GAMECONTROLLER = 0x00002000, + SDL_INIT_EVENTS = 0x00004000, + SDL_INIT_SENSOR = 0x00008000, + SDL_INIT_NOPARACHUTE = 0x00100000, + SDL_INIT_EVERYTHING = + SDL_INIT_TIMER | SDL_INIT_AUDIO | SDL_INIT_VIDEO | + SDL_INIT_JOYSTICK | SDL_INIT_HAPTIC | SDL_INIT_GAMECONTROLLER | + SDL_INIT_EVENTS | SDL_INIT_SENSOR + } +} else { + enum : uint { + SDL_INIT_TIMER = 0x00000001, + SDL_INIT_AUDIO = 0x00000010, + SDL_INIT_VIDEO = 0x00000020, + SDL_INIT_JOYSTICK = 0x00000200, + SDL_INIT_HAPTIC = 0x00001000, + SDL_INIT_GAMECONTROLLER = 0x00002000, + SDL_INIT_EVENTS = 0x00004000, + SDL_INIT_NOPARACHUTE = 0x00100000, + SDL_INIT_EVERYTHING = + SDL_INIT_TIMER | SDL_INIT_AUDIO | SDL_INIT_VIDEO | + SDL_INIT_JOYSTICK | SDL_INIT_HAPTIC | SDL_INIT_GAMECONTROLLER | + SDL_INIT_EVENTS + } +} + +version(BindSDL_Static) { + extern(C) @nogc nothrow { + int SDL_Init(uint); + int SDL_InitSubSystem(uint); + void SDL_QuitSubSystem(uint); + uint SDL_WasInit(uint); + void SDL_Quit(); + } +} +else { + extern(C) @nogc nothrow { + alias pSDL_Init = int function(uint); + alias pSDL_InitSubSystem = int function(uint); + alias pSDL_QuitSubSystem = void function(uint); + alias pSDL_WasInit = uint function(uint); + alias pSDL_Quit = void function(); + } + + __gshared { + pSDL_Init SDL_Init; + pSDL_InitSubSystem SDL_InitSubSystem; + pSDL_QuitSubSystem SDL_QuitSubSystem; + pSDL_WasInit SDL_WasInit; + pSDL_Quit SDL_Quit; + } +} \ No newline at end of file diff --git a/demos/external/imports/bindbc/sdl/bind/sdlassert.d b/demos/external/imports/bindbc/sdl/bind/sdlassert.d new file mode 100644 index 0000000..784e0e8 --- /dev/null +++ b/demos/external/imports/bindbc/sdl/bind/sdlassert.d @@ -0,0 +1,70 @@ + +// Copyright Michael D. Parker 2018. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +module bindbc.sdl.bind.sdlassert; + +import bindbc.sdl.config; + +enum SDL_assert_state : uint { + SDL_ASSERTION_RETRY = 0, + SDL_ASSERTION_BREAK = 1, + SDL_ASSERTION_ABORT = 2, + SDL_ASSERTION_IGNORE = 3, + SDL_ASSERTION_ALWAYS_IGNORE = 4 +} +alias SDL_AssertState = SDL_assert_state; +mixin(expandEnum!SDL_AssertState); + +struct SDL_assert_data { + int always_ignore; + uint trigger_count; + const(char) *condition; + const(char) *filename; + int linenum; + const(char) *function_; + const(SDL_assert_data) *next; +} +alias SDL_AssertData = SDL_assert_data; + +extern(C) nothrow alias SDL_AssertionHandler = SDL_AssertState function(const(SDL_AssertData)* data, void* userdata); + +version(BindSDL_Static) { + extern(C) @nogc nothrow { + void SDL_SetAssertionHandler(SDL_AssertionHandler,void*); + const(SDL_assert_data)* SDL_GetAssertionReport(); + void SDL_ResetAssertionReport(); + + static if(sdlSupport >= SDLSupport.sdl202) { + SDL_AssertionHandler SDL_GetAssertionHandler(void**); + SDL_AssertionHandler SDL_GetDefaultAssertionHandler(); + } + } +} +else { + extern(C) @nogc nothrow { + alias pSDL_SetAssertionHandler = void function(SDL_AssertionHandler,void*); + alias pSDL_GetAssertionReport = const(SDL_assert_data)* function(); + alias pSDL_ResetAssertionReport = void function(); + } + + __gshared { + pSDL_SetAssertionHandler SDL_SetAssertionHandler; + pSDL_GetAssertionReport SDL_GetAssertionReport; + pSDL_ResetAssertionReport SDL_ResetAssertionReport; + } + + static if(sdlSupport >= SDLSupport.sdl202) { + extern(C) @nogc nothrow { + alias pSDL_GetAssertionHandler = SDL_AssertionHandler function(void**); + alias pSDL_GetDefaultAssertionHandler = SDL_AssertionHandler function(); + } + + __gshared { + pSDL_GetAssertionHandler SDL_GetAssertionHandler; + pSDL_GetDefaultAssertionHandler SDL_GetDefaultAssertionHandler; + } + } +} diff --git a/demos/external/imports/bindbc/sdl/bind/sdlaudio.d b/demos/external/imports/bindbc/sdl/bind/sdlaudio.d new file mode 100644 index 0000000..3cb37d8 --- /dev/null +++ b/demos/external/imports/bindbc/sdl/bind/sdlaudio.d @@ -0,0 +1,283 @@ + +// Copyright Michael D. Parker 2018. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +module bindbc.sdl.bind.sdlaudio; + +import bindbc.sdl.config; +import bindbc.sdl.bind.sdlrwops; + +enum : ushort { + SDL_AUDIO_MASK_BITSIZE = 0xFF, + SDL_AUDIO_MASK_DATATYPE = 1<<8, + SDL_AUDIO_MASK_ENDIAN = 1<<12, + SDL_AUDIO_MASK_SIGNED = 1<<15, +} + +enum SDL_AudioFormat : ushort { + AUDIO_U8 = 0x0008, + AUDIO_S8 = 0x8008, + AUDIO_U16LSB = 0x0010, + AUDIO_S16LSB = 0x8010, + AUDIO_U16MSB = 0x1010, + AUDIO_S16MSB = 0x9010, + AUDIO_U16 = AUDIO_U16LSB, + AUDIO_S16 = AUDIO_S16LSB, + AUDIO_S32LSB = 0x8020, + AUDIO_S32MSB = 0x9020, + AUDIO_S32 = AUDIO_S32LSB, + AUDIO_F32LSB = 0x8120, + AUDIO_F32MSB = 0x9120, + AUDIO_F32 = AUDIO_F32LSB, +} +mixin(expandEnum!SDL_AudioFormat); + +version(LittleEndian) { + alias AUDIO_U16SYS = AUDIO_U16LSB; + alias AUDIO_S16SYS = AUDIO_S16LSB; + alias AUDIO_S32SYS = AUDIO_S32LSB; + alias AUDIO_F32SYS = AUDIO_F32LSB; +} else { + alias AUDIO_U16SYS = AUDIO_U16MSB; + alias AUDIO_S16SYS = AUDIO_S16MSB; + alias AUDIO_S32SYS = AUDIO_S32MSB; + alias AUDIO_F32SYS = AUDIO_F32MSB; +} + +enum SDL_AUDIO_BITSIZE(SDL_AudioFormat x) = x & SDL_AUDIO_MASK_BITSIZE; +enum SDL_AUDIO_ISFLOAT(SDL_AudioFormat x) = x & SDL_AUDIO_MASK_DATATYPE; +enum SDL_AUDIO_ISBIGENDIAN(SDL_AudioFormat x) = x & SDL_AUDIO_MASK_ENDIAN; +enum SDL_AUDIO_ISSIGNED(SDL_AudioFormat x) = x & SDL_AUDIO_MASK_SIGNED; +enum SDL_AUDIO_ISINT(SDL_AudioFormat x) = !SDL_AUDIO_ISFLOAT!x; +enum SDL_AUDIO_ISLITTLEENDIAN(SDL_AudioFormat x) = !SDL_AUDIO_ISBIGENDIAN!x; +enum SDL_AUDIO_ISUNSIGNED(SDL_AudioFormat x) = !SDL_AUDIO_ISSIGNED!x; + +static if(sdlSupport >= SDLSupport.sdl209) { + enum { + SDL_AUDIO_ALLOW_FREQUENCY_CHANGE = 0x00000001, + SDL_AUDIO_ALLOW_FORMAT_CHANGE = 0x00000002, + SDL_AUDIO_ALLOW_CHANNELS_CHANGE = 0x00000004, + SDL_AUDIO_ALLOW_SAMPLES_CHANGE = 0x00000008, + SDL_AUDIO_ALLOW_ANY_CHANGE = SDL_AUDIO_ALLOW_FREQUENCY_CHANGE | + SDL_AUDIO_ALLOW_FORMAT_CHANGE | + SDL_AUDIO_ALLOW_CHANNELS_CHANGE | + SDL_AUDIO_ALLOW_SAMPLES_CHANGE, + } +} +else { + enum { + SDL_AUDIO_ALLOW_FREQUENCY_CHANGE = 0x00000001, + SDL_AUDIO_ALLOW_FORMAT_CHANGE = 0x00000002, + SDL_AUDIO_ALLOW_CHANNELS_CHANGE = 0x00000004, + SDL_AUDIO_ALLOW_ANY_CHANGE = SDL_AUDIO_ALLOW_FREQUENCY_CHANGE | + SDL_AUDIO_ALLOW_FORMAT_CHANGE | + SDL_AUDIO_ALLOW_CHANNELS_CHANGE, + } +} + +extern(C) nothrow alias SDL_AudioCallback = void function(void* userdata, ubyte* stream, int len); +struct SDL_AudioSpec { + int freq; + SDL_AudioFormat format; + ubyte channels; + ubyte silence; + ushort samples; + ushort padding; + uint size; + SDL_AudioCallback callback; + void* userdata; +} + +// Declared in 2.0.6, but doesn't hurt to use here +enum SDL_AUDIOCVT_MAX_FILTERS = 9; + +extern(C) nothrow alias SDL_AudioFilter = void function(SDL_AudioCVT* cvt, SDL_AudioFormat format); +struct SDL_AudioCVT { + int needed; + SDL_AudioFormat src_format; + SDL_AudioFormat dst_format; + double rate_incr; + ubyte* buf; + int len; + int len_cvt; + int len_mult; + double len_ratio; + SDL_AudioFilter[SDL_AUDIOCVT_MAX_FILTERS + 1] filters; + int filter_index; +} + +alias SDL_AudioDeviceID = uint; + +enum SDL_AudioStatus { + SDL_AUDIO_STOPPED = 0, + SDL_AUDIO_PLAYING, + SDL_AUDIO_PAUSED, +} +mixin(expandEnum!SDL_AudioStatus); + +enum SDL_MIX_MAXVOLUME = 128; + +static if(sdlSupport >= SDLSupport.sdl207) { + struct SDL_AudioStream; +} + +@nogc nothrow +SDL_AudioSpec* SDL_LoadWAV(const(char)* file, SDL_AudioSpec* spec, ubyte** audio_buf, uint* len) { + pragma(inline, true); + return SDL_LoadWAV_RW(SDL_RWFromFile(file,"rb"),1,spec,audio_buf,len); +} + +version(BindSDL_Static) { + extern(C) @nogc nothrow { + int SDL_GetNumAudioDrivers(); + const(char)* SDL_GetAudioDriver(int); + int SDL_AudioInit(const(char)*); + void SDL_AudioQuit(); + const(char)* SDL_GetCurrentAudioDriver(); + int SDL_OpenAudio(SDL_AudioSpec*,SDL_AudioSpec*); + int SDL_GetNumAudioDevices(int); + const(char)* SDL_GetAudioDeviceName(int,int); + SDL_AudioDeviceID SDL_OpenAudioDevice(const(char)*,int,const(SDL_AudioSpec)*,SDL_AudioSpec*,int); + SDL_AudioStatus SDL_GetAudioStatus(); + SDL_AudioStatus SDL_GetAudioDeviceStatus(SDL_AudioDeviceID); + void SDL_PauseAudio(int); + void SDL_PauseAudioDevice(SDL_AudioDeviceID,int); + SDL_AudioSpec* SDL_LoadWAV_RW(SDL_RWops*,int,SDL_AudioSpec*,ubyte**,uint*); + void SDL_FreeWAV(ubyte*); + int SDL_BuildAudioCVT(SDL_AudioCVT*,SDL_AudioFormat,ubyte,int,SDL_AudioFormat,ubyte,int); + int SDL_ConvertAudio(SDL_AudioCVT*); + void SDL_MixAudio(ubyte*,const(ubyte)*,uint,int); + void SDL_MixAudioFormat(ubyte*,const(ubyte)*,SDL_AudioFormat,uint,int); + void SDL_LockAudio(); + void SDL_LockAudioDevice(SDL_AudioDeviceID); + void SDL_UnlockAudio(); + void SDL_UnlockAudioDevice(SDL_AudioDeviceID); + void SDL_CloseAudio(); + void SDL_CloseAudioDevice(SDL_AudioDeviceID); + + static if(sdlSupport >= SDLSupport.sdl204) { + int SDL_ClearQueuedAudio(SDL_AudioDeviceID); + int SDL_GetQueuedAudioSize(SDL_AudioDeviceID); + int SDL_QueueAudio(SDL_AudioDeviceID,const (void)*,uint); + } + + static if(sdlSupport >= SDLSupport.sdl205) { + uint SDL_DequeueAudio(SDL_AudioDeviceID,void*,uint); + } + + static if(sdlSupport >= SDLSupport.sdl207) { + SDL_AudioStream* SDL_NewAudioStream(const(SDL_AudioFormat),const(ubyte),const(int),const(SDL_AudioFormat),const(ubyte),const(int)); + int SDL_AudioStreamPut(SDL_AudioStream*,const(void)*,int); + int SDL_AudioStreamGet(SDL_AudioStream*,void*,int); + int SDL_AudioStreamAvailable(SDL_AudioStream*); + int SDL_AudioStreamFlush(SDL_AudioStream*); + void SDL_AudioStreamClear(SDL_AudioStream*); + void SDL_FreeAudioStream(SDL_AudioStream*); + } + } +} +else { + extern(C) @nogc nothrow { + alias pSDL_GetNumAudioDrivers = int function(); + alias pSDL_GetAudioDriver = const(char)* function(int); + alias pSDL_AudioInit = int function(const(char)*); + alias pSDL_AudioQuit = void function(); + alias pSDL_GetCurrentAudioDriver = const(char)* function(); + alias pSDL_OpenAudio = int function(SDL_AudioSpec*,SDL_AudioSpec*); + alias pSDL_GetNumAudioDevices = int function(int); + alias pSDL_GetAudioDeviceName = const(char)* function(int,int); + alias pSDL_OpenAudioDevice = SDL_AudioDeviceID function(const(char)*,int,const(SDL_AudioSpec)*,SDL_AudioSpec*,int); + alias pSDL_GetAudioStatus = SDL_AudioStatus function(); + alias pSDL_GetAudioDeviceStatus = SDL_AudioStatus function(SDL_AudioDeviceID); + alias pSDL_PauseAudio = void function(int); + alias pSDL_PauseAudioDevice = void function(SDL_AudioDeviceID,int); + alias pSDL_LoadWAV_RW = SDL_AudioSpec* function(SDL_RWops*,int,SDL_AudioSpec*,ubyte**,uint*); + alias pSDL_FreeWAV = void function(ubyte*); + alias pSDL_BuildAudioCVT = int function(SDL_AudioCVT*,SDL_AudioFormat,ubyte,int,SDL_AudioFormat,ubyte,int); + alias pSDL_ConvertAudio = int function(SDL_AudioCVT*); + alias pSDL_MixAudio = void function(ubyte*,const(ubyte)*,uint,int); + alias pSDL_MixAudioFormat = void function(ubyte*,const(ubyte)*,SDL_AudioFormat,uint,int); + alias pSDL_LockAudio = void function(); + alias pSDL_LockAudioDevice = void function(SDL_AudioDeviceID); + alias pSDL_UnlockAudio = void function(); + alias pSDL_UnlockAudioDevice = void function(SDL_AudioDeviceID); + alias pSDL_CloseAudio = void function(); + alias pSDL_CloseAudioDevice = void function(SDL_AudioDeviceID); + } + + __gshared { + pSDL_GetNumAudioDrivers SDL_GetNumAudioDrivers; + pSDL_GetAudioDriver SDL_GetAudioDriver; + pSDL_AudioInit SDL_AudioInit; + pSDL_AudioQuit SDL_AudioQuit; + pSDL_GetCurrentAudioDriver SDL_GetCurrentAudioDriver; + pSDL_OpenAudio SDL_OpenAudio; + pSDL_GetNumAudioDevices SDL_GetNumAudioDevices; + pSDL_GetAudioDeviceName SDL_GetAudioDeviceName; + pSDL_OpenAudioDevice SDL_OpenAudioDevice; + pSDL_GetAudioStatus SDL_GetAudioStatus; + pSDL_GetAudioDeviceStatus SDL_GetAudioDeviceStatus; + pSDL_PauseAudio SDL_PauseAudio; + pSDL_PauseAudioDevice SDL_PauseAudioDevice; + pSDL_LoadWAV_RW SDL_LoadWAV_RW; + pSDL_FreeWAV SDL_FreeWAV; + pSDL_BuildAudioCVT SDL_BuildAudioCVT; + pSDL_ConvertAudio SDL_ConvertAudio; + pSDL_MixAudio SDL_MixAudio; + pSDL_MixAudioFormat SDL_MixAudioFormat; + pSDL_LockAudio SDL_LockAudio; + pSDL_LockAudioDevice SDL_LockAudioDevice; + pSDL_UnlockAudio SDL_UnlockAudio; + pSDL_UnlockAudioDevice SDL_UnlockAudioDevice; + pSDL_CloseAudio SDL_CloseAudio; + pSDL_CloseAudioDevice SDL_CloseAudioDevice; + } + + static if(sdlSupport >= SDLSupport.sdl204) { + extern(C) @nogc nothrow { + alias pSDL_ClearQueuedAudio = int function(SDL_AudioDeviceID); + alias pSDL_GetQueuedAudioSize = int function(SDL_AudioDeviceID); + alias pSDL_QueueAudio = int function(SDL_AudioDeviceID,const (void)*,uint); + } + + __gshared { + pSDL_ClearQueuedAudio SDL_ClearQueuedAudio; + pSDL_GetQueuedAudioSize SDL_GetQueuedAudioSize; + pSDL_QueueAudio SDL_QueueAudio; + } + } + + static if(sdlSupport >= SDLSupport.sdl205) { + extern(C) @nogc nothrow { + alias pSDL_DequeueAudio = uint function(SDL_AudioDeviceID,void*,uint); + } + + __gshared { + pSDL_DequeueAudio SDL_DequeueAudio; + } + } + + static if(sdlSupport >= SDLSupport.sdl207) { + extern(C) @nogc nothrow { + alias pSDL_NewAudioStream = SDL_AudioStream* function(const(SDL_AudioFormat),const(ubyte),const(int),const(SDL_AudioFormat),const(ubyte),const(int)); + alias pSDL_AudioStreamPut = int function(SDL_AudioStream*,const(void)*,int); + alias pSDL_AudioStreamGet = int function(SDL_AudioStream*,void*,int); + alias pSDL_AudioStreamAvailable = int function(SDL_AudioStream*); + alias pSDL_AudioStreamFlush = int function(SDL_AudioStream*); + alias pSDL_AudioStreamClear = void function(SDL_AudioStream*); + alias pSDL_FreeAudioStream = void function(SDL_AudioStream*); + } + + __gshared { + pSDL_NewAudioStream SDL_NewAudioStream; + pSDL_AudioStreamPut SDL_AudioStreamPut; + pSDL_AudioStreamGet SDL_AudioStreamGet; + pSDL_AudioStreamAvailable SDL_AudioStreamAvailable; + pSDL_AudioStreamFlush SDL_AudioStreamFlush; + pSDL_AudioStreamClear SDL_AudioStreamClear; + pSDL_FreeAudioStream SDL_FreeAudioStream; + } + } +} \ No newline at end of file diff --git a/demos/external/imports/bindbc/sdl/bind/sdlblendmode.d b/demos/external/imports/bindbc/sdl/bind/sdlblendmode.d new file mode 100644 index 0000000..a3360c2 --- /dev/null +++ b/demos/external/imports/bindbc/sdl/bind/sdlblendmode.d @@ -0,0 +1,71 @@ + +// Copyright Michael D. Parker 2018. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +module bindbc.sdl.bind.sdlblendmode; + +import bindbc.sdl.config; + +static if(sdlSupport >= SDLSupport.sdl206) { + enum SDL_BlendMode { + SDL_BLENDMODE_NONE = 0x00000000, + SDL_BLENDMODE_BLEND = 0x00000001, + SDL_BLENDMODE_ADD = 0x00000002, + SDL_BLENDMODE_MOD = 0x00000004, + SDL_BLENDMODE_INVALID = 0x7FFFFFFF, + } + mixin(expandEnum!SDL_BlendMode); + + enum SDL_BlendOperation { + SDL_BLENDOPERATION_ADD = 0x1, + SDL_BLENDOPERATION_SUBTRACT = 0x2, + SDL_BLENDOPERATION_REV_SUBTRACT = 0x3, + SDL_BLENDOPERATION_MINIMUM = 0x4, + SDL_BLENDOPERATION_MAXIMUM = 0x5, + } + mixin(expandEnum!SDL_BlendOperation); + + enum SDL_BlendFactor { + SDL_BLENDFACTOR_ZERO = 0x1, + SDL_BLENDFACTOR_ONE = 0x2, + SDL_BLENDFACTOR_SRC_COLOR = 0x3, + SDL_BLENDFACTOR_ONE_MINUS_SRC_COLOR = 0x4, + SDL_BLENDFACTOR_SRC_ALPHA = 0x5, + SDL_BLENDFACTOR_ONE_MINUS_SRC_ALPHA = 0x6, + SDL_BLENDFACTOR_DST_COLOR = 0x7, + SDL_BLENDFACTOR_ONE_MINUS_DST_COLOR = 0x8, + SDL_BLENDFACTOR_DST_ALPHA = 0x9, + SDL_BLENDFACTOR_ONE_MINUS_DST_ALPHA = 0xA, + } + mixin(expandEnum!SDL_BlendFactor); +} +else { + enum SDL_BlendMode { + SDL_BLENDMODE_NONE = 0x00000000, + SDL_BLENDMODE_BLEND = 0x00000001, + SDL_BLENDMODE_ADD = 0x00000002, + SDL_BLENDMODE_MOD = 0x00000004, + } + mixin(expandEnum!SDL_BlendMode); +} + +version(BindSDL_Static) { + extern(C) @nogc nothrow { + static if(sdlSupport >= SDLSupport.sdl206) { + SDL_BlendMode SDL_ComposeCustomBlendMode(SDL_BlendFactor,SDL_BlendFactor,SDL_BlendOperation,SDL_BlendFactor,SDL_BlendFactor,SDL_BlendOperation); + } + } +} +else { + static if(sdlSupport >= SDLSupport.sdl206) { + extern(C) @nogc nothrow { + alias pSDL_ComposeCustomBlendMode = SDL_BlendMode function(SDL_BlendFactor,SDL_BlendFactor,SDL_BlendOperation,SDL_BlendFactor,SDL_BlendFactor,SDL_BlendOperation); + } + + __gshared { + pSDL_ComposeCustomBlendMode SDL_ComposeCustomBlendMode; + } + } +} diff --git a/demos/external/imports/bindbc/sdl/bind/sdlclipboard.d b/demos/external/imports/bindbc/sdl/bind/sdlclipboard.d new file mode 100644 index 0000000..345c1ac --- /dev/null +++ b/demos/external/imports/bindbc/sdl/bind/sdlclipboard.d @@ -0,0 +1,31 @@ + +// Copyright Michael D. Parker 2018. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +module bindbc.sdl.bind.sdlclipboard; + +import bindbc.sdl.config; +import bindbc.sdl.bind.sdlstdinc : SDL_bool; + +version(BindSDL_Static) { + extern(C) @nogc nothrow { + int SDL_SetClipboardText(const(char)*); + char* SDL_GetClipboardText(); + SDL_bool SDL_HasClipboardText(); + } +} +else { + extern(C) @nogc nothrow { + alias pSDL_SetClipboardText = int function(const(char)*); + alias pSDL_GetClipboardText = char* function(); + alias pSDL_HasClipboardText = SDL_bool function(); + } + + __gshared { + pSDL_SetClipboardText SDL_SetClipboardText; + pSDL_GetClipboardText SDL_GetClipboardText; + pSDL_HasClipboardText SDL_HasClipboardText; + } +} \ No newline at end of file diff --git a/demos/external/imports/bindbc/sdl/bind/sdlcpuinfo.d b/demos/external/imports/bindbc/sdl/bind/sdlcpuinfo.d new file mode 100644 index 0000000..433ade0 --- /dev/null +++ b/demos/external/imports/bindbc/sdl/bind/sdlcpuinfo.d @@ -0,0 +1,130 @@ + +// Copyright Michael D. Parker 2018. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +module bindbc.sdl.bind.sdlcpuinfo; + +import bindbc.sdl.config; +import bindbc.sdl.bind.sdlstdinc : SDL_bool; + +enum SDL_CACHELINE_SIZE = 128; + +version(BindSDL_Static) { + extern(C) @nogc nothrow { + int SDL_GetCPUCount(); + int SDL_GetCPUCacheLineSize(); + SDL_bool SDL_HasRDTSC(); + SDL_bool SDL_HasAltiVec(); + SDL_bool SDL_HasMMX(); + SDL_bool SDL_Has3DNow(); + SDL_bool SDL_HasSSE(); + SDL_bool SDL_HasSSE2(); + SDL_bool SDL_HasSSE3(); + SDL_bool SDL_HasSSE41(); + SDL_bool SDL_HasSSE42(); + + static if(sdlSupport >= SDLSupport.sdl201) { + int SDL_GetSystemRAM(); + } + static if(sdlSupport >= SDLSupport.sdl202) { + SDL_bool SDL_HasAVX(); + } + static if(sdlSupport >= SDLSupport.sdl204) { + SDL_bool SDL_HasAVX2(); + } + static if(sdlSupport >= SDLSupport.sdl206) { + SDL_bool SDL_HasNEON(); + } + static if(sdlSupport >= SDLSupport.sdl209) { + SDL_bool SDL_HasAVX512F(); + } + static if(sdlSupport >= SDLSupport.sdl2010) { + size_t SDL_SIMDGetAlignment(); + void* SDL_SIMDAlloc(const(size_t)); + void SDL_SIMDFree(void*); + } + } +} +else { + extern(C) @nogc nothrow { + alias pSDL_GetCPUCount = int function(); + alias pSDL_GetCPUCacheLineSize = int function(); + alias pSDL_HasRDTSC = SDL_bool function(); + alias pSDL_HasAltiVec = SDL_bool function(); + alias pSDL_HasMMX = SDL_bool function(); + alias pSDL_Has3DNow = SDL_bool function(); + alias pSDL_HasSSE = SDL_bool function(); + alias pSDL_HasSSE2 = SDL_bool function(); + alias pSDL_HasSSE3 = SDL_bool function(); + alias pSDL_HasSSE41 = SDL_bool function(); + alias pSDL_HasSSE42 = SDL_bool function(); + } + + __gshared { + pSDL_GetCPUCount SDL_GetCPUCount; + pSDL_GetCPUCacheLineSize SDL_GetCPUCacheLineSize; + pSDL_HasRDTSC SDL_HasRDTSC; + pSDL_HasAltiVec SDL_HasAltiVec; + pSDL_HasMMX SDL_HasMMX; + pSDL_Has3DNow SDL_Has3DNow; + pSDL_HasSSE SDL_HasSSE; + pSDL_HasSSE2 SDL_HasSSE2; + pSDL_HasSSE3 SDL_HasSSE3; + pSDL_HasSSE41 SDL_HasSSE41; + pSDL_HasSSE42 SDL_HasSSE42; + } + static if(sdlSupport >= SDLSupport.sdl201) { + extern(C) @nogc nothrow { + alias pSDL_GetSystemRAM = int function(); + } + __gshared { + pSDL_GetSystemRAM SDL_GetSystemRAM; + } + } + static if(sdlSupport >= SDLSupport.sdl202) { + extern(C) @nogc nothrow { + alias pSDL_HasAVX = SDL_bool function(); + } + __gshared { + pSDL_HasAVX SDL_HasAVX; + } + } + static if(sdlSupport >= SDLSupport.sdl204) { + extern(C) @nogc nothrow { + alias pSDL_HasAVX2 = SDL_bool function(); + } + __gshared { + pSDL_HasAVX2 SDL_HasAVX2; + } + } + static if(sdlSupport >= SDLSupport.sdl206) { + extern(C) @nogc nothrow { + alias pSDL_HasNEON = SDL_bool function(); + } + __gshared { + pSDL_HasNEON SDL_HasNEON; + } + } + static if(sdlSupport >= SDLSupport.sdl209) { + extern(C) @nogc nothrow { + alias pSDL_HasAVX512F = SDL_bool function(); + } + __gshared { + pSDL_HasAVX512F SDL_HasAVX512F; + } + } + static if(sdlSupport >= SDLSupport.sdl2010) { + extern(C) @nogc nothrow { + alias pSDL_SIMDGetAlignment = size_t function(); + alias pSDL_SIMDAlloc = void* function(const(size_t)); + alias pSDL_SIMDFree = void function(void*); + } + __gshared { + pSDL_SIMDGetAlignment SDL_SIMDGetAlignment; + pSDL_SIMDAlloc SDL_SIMDAlloc; + pSDL_SIMDFree SDL_SIMDFree; + } + } +} \ No newline at end of file diff --git a/demos/external/imports/bindbc/sdl/bind/sdlerror.d b/demos/external/imports/bindbc/sdl/bind/sdlerror.d new file mode 100644 index 0000000..09b61e3 --- /dev/null +++ b/demos/external/imports/bindbc/sdl/bind/sdlerror.d @@ -0,0 +1,28 @@ + +// Copyright Michael D. Parker 2018. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +module bindbc.sdl.bind.sdlerror; + +version(BindSDL_Static) { + extern(C) @nogc nothrow { + void SDL_SetError(const(char)*,...); + const(char)* SDL_GetError(); + void SDL_ClearError(); + } +} +else { + extern(C) @nogc nothrow { + alias pSDL_SetError = void function(const(char)*,...); + alias pSDL_GetError = const(char)* function(); + alias pSDL_ClearError = void function(); + } + + __gshared { + pSDL_SetError SDL_SetError; + pSDL_GetError SDL_GetError; + pSDL_ClearError SDL_ClearError; + } +} \ No newline at end of file diff --git a/demos/external/imports/bindbc/sdl/bind/sdlevents.d b/demos/external/imports/bindbc/sdl/bind/sdlevents.d new file mode 100644 index 0000000..0fb7ce2 --- /dev/null +++ b/demos/external/imports/bindbc/sdl/bind/sdlevents.d @@ -0,0 +1,674 @@ + +// Copyright Michael D. Parker 2018. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +module bindbc.sdl.bind.sdlevents; + +import bindbc.sdl.config; + +import bindbc.sdl.bind.sdlgesture, + bindbc.sdl.bind.sdljoystick, + bindbc.sdl.bind.sdlkeyboard, + bindbc.sdl.bind.sdlkeycode, + bindbc.sdl.bind.sdlstdinc, + bindbc.sdl.bind.sdlsyswm, + bindbc.sdl.bind.sdltouch, + bindbc.sdl.bind.sdlvideo; + +enum { + SDL_RELEASED = 0, + SDL_PRESSED = 1, +} + +static if(sdlSupport >= SDLSupport.sdl209) { + enum SDL_EventType { + SDL_FIRSTEVENT = 0, + SDL_QUIT = 0x100, + SDL_APP_TERMINATING, + SDL_APP_LOWMEMORY, + SDL_APP_WILLENTERBACKGROUND, + SDL_APP_DIDENTERBACKGROUND, + SDL_APP_WILLENTERFOREGROUND, + SDL_APP_DIDENTERFOREGROUND, + SDL_DISPLAYEVENT = 0x150, + SDL_WINDOWEVENT = 0x200, + SDL_SYSWMEVENT, + SDL_KEYDOWN = 0x300, + SDL_KEYUP, + SDL_TEXTEDITING, + SDL_TEXTINPUT, + SDL_KEYMAPCHANGED, + SDL_MOUSEMOTION = 0x400, + SDL_MOUSEBUTTONDOWN, + SDL_MOUSEBUTTONUP, + SDL_MOUSEWHEEL, + SDL_JOYAXISMOTION = 0x600, + SDL_JOYBALLMOTION, + SDL_JOYHATMOTION, + SDL_JOYBUTTONDOWN, + SDL_JOYBUTTONUP, + SDL_JOYDEVICEADDED, + SDL_JOYDEVICEREMOVED, + SDL_CONTROLLERAXISMOTION = 0x650, + SDL_CONTROLLERBUTTONDOWN, + SDL_CONTROLLERBUTTONUP, + SDL_CONTROLLERDEVICEADDED, + SDL_CONTROLLERDEVICEREMOVED, + SDL_CONTROLLERDEVICEREMAPPED, + SDL_FINGERDOWN = 0x700, + SDL_FINGERUP, + SDL_FINGERMOTION, + SDL_DOLLARGESTURE = 0x800, + SDL_DOLLARRECORD, + SDL_MULTIGESTURE, + SDL_CLIPBOARDUPDATE = 0x900, + SDL_DROPFILE = 0x1000, + SDL_DROPTEXT, + SDL_DROPBEGIN, + SDL_DROPCOMPLETE, + SDL_AUDIODEVICEADDED = 0x1100, + SDL_AUDIODEVICEREMOVED, + SDL_SENSORUPDATE = 0x1200, + SDL_RENDER_TARGETS_RESET = 0x2000, + SDL_RENDER_DEVICE_RESET, + SDL_USEREVENT = 0x8000, + SDL_LASTEVENT = 0xFFFF + } +} +else static if(sdlSupport >= SDLSupport.sdl205) { + enum SDL_EventType { + SDL_FIRSTEVENT = 0, + SDL_QUIT = 0x100, + SDL_APP_TERMINATING, + SDL_APP_LOWMEMORY, + SDL_APP_WILLENTERBACKGROUND, + SDL_APP_DIDENTERBACKGROUND, + SDL_APP_WILLENTERFOREGROUND, + SDL_APP_DIDENTERFOREGROUND, + SDL_WINDOWEVENT = 0x200, + SDL_SYSWMEVENT, + SDL_KEYDOWN = 0x300, + SDL_KEYUP, + SDL_TEXTEDITING, + SDL_TEXTINPUT, + SDL_KEYMAPCHANGED, + SDL_MOUSEMOTION = 0x400, + SDL_MOUSEBUTTONDOWN, + SDL_MOUSEBUTTONUP, + SDL_MOUSEWHEEL, + SDL_JOYAXISMOTION = 0x600, + SDL_JOYBALLMOTION, + SDL_JOYHATMOTION, + SDL_JOYBUTTONDOWN, + SDL_JOYBUTTONUP, + SDL_JOYDEVICEADDED, + SDL_JOYDEVICEREMOVED, + SDL_CONTROLLERAXISMOTION = 0x650, + SDL_CONTROLLERBUTTONDOWN, + SDL_CONTROLLERBUTTONUP, + SDL_CONTROLLERDEVICEADDED, + SDL_CONTROLLERDEVICEREMOVED, + SDL_CONTROLLERDEVICEREMAPPED, + SDL_FINGERDOWN = 0x700, + SDL_FINGERUP, + SDL_FINGERMOTION, + SDL_DOLLARGESTURE = 0x800, + SDL_DOLLARRECORD, + SDL_MULTIGESTURE, + SDL_CLIPBOARDUPDATE = 0x900, + SDL_DROPFILE = 0x1000, + SDL_DROPTEXT, + SDL_DROPBEGIN, + SDL_DROPCOMPLETE, + SDL_AUDIODEVICEADDED = 0x1100, + SDL_AUDIODEVICEREMOVED, + SDL_RENDER_TARGETS_RESET = 0x2000, + SDL_RENDER_DEVICE_RESET, + SDL_USEREVENT = 0x8000, + SDL_LASTEVENT = 0xFFFF + } +} +else static if(sdlSupport >= SDLSupport.sdl204) { + enum SDL_EventType { + SDL_FIRSTEVENT = 0, + SDL_QUIT = 0x100, + SDL_APP_TERMINATING, + SDL_APP_LOWMEMORY, + SDL_APP_WILLENTERBACKGROUND, + SDL_APP_DIDENTERBACKGROUND, + SDL_APP_WILLENTERFOREGROUND, + SDL_APP_DIDENTERFOREGROUND, + SDL_WINDOWEVENT = 0x200, + SDL_SYSWMEVENT, + SDL_KEYDOWN = 0x300, + SDL_KEYUP, + SDL_TEXTEDITING, + SDL_TEXTINPUT, + SDL_KEYMAPCHANGED, + SDL_MOUSEMOTION = 0x400, + SDL_MOUSEBUTTONDOWN, + SDL_MOUSEBUTTONUP, + SDL_MOUSEWHEEL, + SDL_JOYAXISMOTION = 0x600, + SDL_JOYBALLMOTION, + SDL_JOYHATMOTION, + SDL_JOYBUTTONDOWN, + SDL_JOYBUTTONUP, + SDL_JOYDEVICEADDED, + SDL_JOYDEVICEREMOVED, + SDL_CONTROLLERAXISMOTION = 0x650, + SDL_CONTROLLERBUTTONDOWN, + SDL_CONTROLLERBUTTONUP, + SDL_CONTROLLERDEVICEADDED, + SDL_CONTROLLERDEVICEREMOVED, + SDL_CONTROLLERDEVICEREMAPPED, + SDL_FINGERDOWN = 0x700, + SDL_FINGERUP, + SDL_FINGERMOTION, + SDL_DOLLARGESTURE = 0x800, + SDL_DOLLARRECORD, + SDL_MULTIGESTURE, + SDL_CLIPBOARDUPDATE = 0x900, + SDL_DROPFILE = 0x1000, + SDL_AUDIODEVICEADDED = 0x1100, + SDL_AUDIODEVICEREMOVED, + SDL_RENDER_TARGETS_RESET = 0x2000, + SDL_RENDER_DEVICE_RESET, + SDL_USEREVENT = 0x8000, + SDL_LASTEVENT = 0xFFFF + } +} +else static if(sdlSupport >= SDLSupport.sdl201) { + enum SDL_EventType { + SDL_FIRSTEVENT = 0, + SDL_QUIT = 0x100, + SDL_APP_TERMINATING, + SDL_APP_LOWMEMORY, + SDL_APP_WILLENTERBACKGROUND, + SDL_APP_DIDENTERBACKGROUND, + SDL_APP_WILLENTERFOREGROUND, + SDL_APP_DIDENTERFOREGROUND, + SDL_WINDOWEVENT = 0x200, + SDL_SYSWMEVENT, + SDL_KEYDOWN = 0x300, + SDL_KEYUP, + SDL_TEXTEDITING, + SDL_TEXTINPUT, + SDL_MOUSEMOTION = 0x400, + SDL_MOUSEBUTTONDOWN, + SDL_MOUSEBUTTONUP, + SDL_MOUSEWHEEL, + SDL_JOYAXISMOTION = 0x600, + SDL_JOYBALLMOTION, + SDL_JOYHATMOTION, + SDL_JOYBUTTONDOWN, + SDL_JOYBUTTONUP, + SDL_JOYDEVICEADDED, + SDL_JOYDEVICEREMOVED, + SDL_CONTROLLERAXISMOTION = 0x650, + SDL_CONTROLLERBUTTONDOWN, + SDL_CONTROLLERBUTTONUP, + SDL_CONTROLLERDEVICEADDED, + SDL_CONTROLLERDEVICEREMOVED, + SDL_CONTROLLERDEVICEREMAPPED, + SDL_FINGERDOWN = 0x700, + SDL_FINGERUP, + SDL_FINGERMOTION, + SDL_DOLLARGESTURE = 0x800, + SDL_DOLLARRECORD, + SDL_MULTIGESTURE, + SDL_CLIPBOARDUPDATE = 0x900, + SDL_DROPFILE = 0x1000, + SDL_RENDER_TARGETS_RESET = 0x2000, + SDL_USEREVENT = 0x8000, + SDL_LASTEVENT = 0xFFFF + } +} +else { + enum SDL_EventType { + SDL_FIRSTEVENT = 0, + SDL_QUIT = 0x100, + SDL_APP_TERMINATING, + SDL_APP_LOWMEMORY, + SDL_APP_WILLENTERBACKGROUND, + SDL_APP_DIDENTERBACKGROUND, + SDL_APP_WILLENTERFOREGROUND, + SDL_APP_DIDENTERFOREGROUND, + SDL_WINDOWEVENT = 0x200, + SDL_SYSWMEVENT, + SDL_KEYDOWN = 0x300, + SDL_KEYUP, + SDL_TEXTEDITING, + SDL_TEXTINPUT, + SDL_MOUSEMOTION = 0x400, + SDL_MOUSEBUTTONDOWN, + SDL_MOUSEBUTTONUP, + SDL_MOUSEWHEEL, + SDL_JOYAXISMOTION = 0x600, + SDL_JOYBALLMOTION, + SDL_JOYHATMOTION, + SDL_JOYBUTTONDOWN, + SDL_JOYBUTTONUP, + SDL_JOYDEVICEADDED, + SDL_JOYDEVICEREMOVED, + SDL_CONTROLLERAXISMOTION = 0x650, + SDL_CONTROLLERBUTTONDOWN, + SDL_CONTROLLERBUTTONUP, + SDL_CONTROLLERDEVICEADDED, + SDL_CONTROLLERDEVICEREMOVED, + SDL_CONTROLLERDEVICEREMAPPED, + SDL_FINGERDOWN = 0x700, + SDL_FINGERUP, + SDL_FINGERMOTION, + SDL_DOLLARGESTURE = 0x800, + SDL_DOLLARRECORD, + SDL_MULTIGESTURE, + SDL_CLIPBOARDUPDATE = 0x900, + SDL_DROPFILE = 0x1000, + SDL_USEREVENT = 0x8000, + SDL_LASTEVENT = 0xFFFF + } +} +mixin(expandEnum!SDL_EventType); + +struct SDL_CommonEvent { + SDL_EventType type; + uint timestamp; +} + +static if(sdlSupport >= SDLSupport.sdl209) { + struct SDL_DisplayEvent { + SDL_EventType type; + uint timestamp; + uint display; + ubyte event; + ubyte padding1; + ubyte padding2; + ubyte padding3; + int data1; + } +} + +struct SDL_WindowEvent { + SDL_EventType type; + uint timestamp; + uint windowID; + SDL_WindowEventID event; + ubyte padding1; + ubyte padding2; + ubyte padding3; + int data1; + int data2; +} + +struct SDL_KeyboardEvent { + SDL_EventType type; + uint timestamp; + uint windowID; + ubyte state; + ubyte repeat; + ubyte padding2; + ubyte padding3; + SDL_Keysym keysym; +} + +enum SDL_TEXTEDITINGEVENT_TEXT_SIZE = 32; +struct SDL_TextEditingEvent { + SDL_EventType type; + uint timestamp; + uint windowID; + char[SDL_TEXTEDITINGEVENT_TEXT_SIZE] text; + int start; + int length; +} + +enum SDL_TEXTINPUTEVENT_TEXT_SIZE = 32; +struct SDL_TextInputEvent { + SDL_EventType type; + uint timestamp; + uint windowID; + char[SDL_TEXTINPUTEVENT_TEXT_SIZE] text; +} + +struct SDL_MouseMotionEvent { + SDL_EventType type; + uint timestamp; + uint windowID; + uint which; + uint state; + int x; + int y; + int xrel; + int yrel; +} + +struct SDL_MouseButtonEvent { + SDL_EventType type; + uint timestamp; + uint windowID; + uint which; + ubyte button; + ubyte state; + static if(sdlSupport == SDLSupport.sdl200) { + ubyte padding1; + ubyte padding2; + } + else { + ubyte clicks; + ubyte padding1; + } + int x; + int y; +} + +struct SDL_MouseWheelEvent { + SDL_EventType type; + uint timestamp; + uint windowID; + uint which; + int x; + int y; + static if(sdlSupport >= SDLSupport.sdl204) { + uint direction; + } +} + +struct SDL_JoyAxisEvent { + SDL_EventType type; + uint timestamp; + SDL_JoystickID which; + ubyte axis; + ubyte padding1; + ubyte padding2; + ubyte padding3; + short value; + ushort padding4; +} + +struct SDL_JoyBallEvent { + SDL_EventType type; + uint timestamp; + SDL_JoystickID which; + ubyte ball; + ubyte padding1; + ubyte padding2; + ubyte padding3; + short xrel; + short yrel; +} + +struct SDL_JoyHatEvent { + SDL_EventType type; + uint timestamp; + SDL_JoystickID which; + ubyte hat; + ubyte value; + ubyte padding1; + ubyte padding2; +} + +struct SDL_JoyButtonEvent { + SDL_EventType type; + uint timestamp; + SDL_JoystickID which; + ubyte button; + ubyte state; + ubyte padding1; + ubyte padding2; +} + +struct SDL_JoyDeviceEvent { + SDL_EventType type; + uint timestamp; + int which; +} + +struct SDL_ControllerAxisEvent { + SDL_EventType type; + uint timestamp; + SDL_JoystickID which; + ubyte axis; + ubyte padding1; + ubyte padding2; + ubyte padding3; + short value; + ushort padding4; +} + +struct SDL_ControllerButtonEvent { + SDL_EventType type; + uint timestamp; + SDL_JoystickID which; + ubyte button; + ubyte state; + ubyte padding1; + ubyte padding2; +} + +struct SDL_ControllerDeviceEvent { + SDL_EventType type; + uint timestamp; + int which; +} + +static if(sdlSupport >= SDLSupport.sdl204) { + struct SDL_AudioDeviceEvent { + uint type; + uint timestamp; + uint which; + ubyte iscapture; + ubyte padding1; + ubyte padding2; + ubyte padding3; + } +} + +struct SDL_TouchFingerEvent { + SDL_EventType type; + uint timestamp; + SDL_TouchID touchId; + SDL_FingerID fingerId; + float x; + float y; + float dx; + float dy; + float pressure; +} + +struct SDL_MultiGestureEvent { + SDL_EventType type; + uint timestamp; + SDL_TouchID touchId; + float dTheta; + float dDist; + float x; + float y; + ushort numFingers; + ushort padding; +} + +struct SDL_DollarGestureEvent { + SDL_EventType type; + uint timestamp; + SDL_TouchID touchId; + SDL_GestureID gestureId; + uint numFingers; + float error; + float x; + float y; +} + +struct SDL_DropEvent { + SDL_EventType type; + uint timestamp; + char* file; + static if(sdlSupport >= SDLSupport.sdl205) { + uint windowID; + } +} + +struct SDL_SensorEvent { + SDL_EventType type; + uint timestamp; + int which; + float[6] data; +} + +struct SDL_QuitEvent { + SDL_EventType type; + uint timestamp; +} + +struct SDL_OSEvent { + SDL_EventType type; + uint timestamp; +} + +struct SDL_UserEvent { + SDL_EventType type; + uint timestamp; + uint windowID; + int code; + void* data1; + void* data2; +} + +struct SDL_SysWMEvent { + SDL_EventType type; + uint timestamp; + SDL_SysWMmsg* msg; +} + +union SDL_Event { + SDL_EventType type; + SDL_CommonEvent common; + static if(sdlSupport >= SDLSupport.sdl209) { + SDL_DisplayEvent display; + } + SDL_WindowEvent window; + SDL_KeyboardEvent key; + SDL_TextEditingEvent edit; + SDL_TextInputEvent text; + SDL_MouseMotionEvent motion; + SDL_MouseButtonEvent button; + SDL_MouseWheelEvent wheel; + SDL_JoyAxisEvent jaxis; + SDL_JoyBallEvent jball; + SDL_JoyHatEvent jhat; + SDL_JoyButtonEvent jbutton; + SDL_JoyDeviceEvent jdevice; + SDL_ControllerAxisEvent caxis; + SDL_ControllerButtonEvent cbutton; + SDL_ControllerDeviceEvent cdevice; + static if(sdlSupport >= SDLSupport.sdl204) { + SDL_AudioDeviceEvent adevice; + } + static if(sdlSupport >= SDLSupport.sdl209) { + SDL_SensorEvent sensor; + } + SDL_QuitEvent quit; + SDL_UserEvent user; + SDL_SysWMEvent syswm; + SDL_TouchFingerEvent tfinger; + SDL_MultiGestureEvent mgesture; + SDL_DollarGestureEvent dgesture; + SDL_DropEvent drop; + + ubyte[56] padding; +} + +enum SDL_eventaction { + SDL_ADDEVENT, + SDL_PEEKEVENT, + SDL_GETEVENT +} +alias SDL_EventAction = SDL_eventaction; +mixin(expandEnum!SDL_EventAction); + +extern(C) nothrow alias SDL_EventFilter = int function(void* userdata, SDL_Event* event); + +enum { + SDL_QUERY = -1, + SDL_IGNORE = 0, + SDL_DISABLE = 0, + SDL_ENABLE = 1, +} + +@nogc nothrow { + int SDL_GetEventState(SDL_EventType type) { + pragma(inline, true); + return SDL_EventState(type, SDL_QUERY); + } + + // This is implemented in SDL_quit.h, but works better here. + bool SDL_QuitRequested() { + pragma(inline, true); + SDL_PumpEvents(); + return SDL_PeepEvents(null,0,SDL_PEEKEVENT,SDL_QUIT,SDL_QUIT) > 0; + } +} + +version(BindSDL_Static) { + extern(C) @nogc nothrow { + void SDL_PumpEvents(); + int SDL_PeepEvents(SDL_Event*,int,SDL_eventaction,uint,uint); + SDL_bool SDL_HasEvent(uint); + SDL_bool SDL_HasEvents(uint,uint); + void SDL_FlushEvent(uint); + void SDL_FlushEvents(uint,uint); + int SDL_PollEvent(SDL_Event*); + int SDL_WaitEvent(SDL_Event*); + int SDL_WaitEventTimeout(SDL_Event*,int); + int SDL_PushEvent(SDL_Event*); + void SDL_SetEventFilter(SDL_EventFilter,void*); + SDL_bool SDL_GetEventFilter(SDL_EventFilter*,void**); + void SDL_AddEventWatch(SDL_EventFilter,void*); + void SDL_DelEventWatch(SDL_EventFilter,void*); + void SDL_FilterEvents(SDL_EventFilter,void*); + ubyte SDL_EventState(uint,int); + uint SDL_RegisterEvents(int); + } +} +else { + extern(C) @nogc nothrow { + alias pSDL_PumpEvents = void function(); + alias pSDL_PeepEvents = int function(SDL_Event*,int,SDL_eventaction,uint,uint); + alias pSDL_HasEvent = SDL_bool function(uint); + alias pSDL_HasEvents = SDL_bool function(uint,uint); + alias pSDL_FlushEvent = void function(uint); + alias pSDL_FlushEvents = void function(uint,uint); + alias pSDL_PollEvent = int function(SDL_Event*); + alias pSDL_WaitEvent = int function(SDL_Event*); + alias pSDL_WaitEventTimeout = int function(SDL_Event*,int); + alias pSDL_PushEvent = int function(SDL_Event*); + alias pSDL_SetEventFilter = void function(SDL_EventFilter,void*); + alias pSDL_GetEventFilter = SDL_bool function(SDL_EventFilter*,void**); + alias pSDL_AddEventWatch = void function(SDL_EventFilter,void*); + alias pSDL_DelEventWatch = void function(SDL_EventFilter,void*); + alias pSDL_FilterEvents = void function(SDL_EventFilter,void*); + alias pSDL_EventState = ubyte function(uint,int); + alias pSDL_RegisterEvents = uint function(int); + } + + __gshared { + pSDL_PumpEvents SDL_PumpEvents; + pSDL_PeepEvents SDL_PeepEvents; + pSDL_HasEvent SDL_HasEvent; + pSDL_HasEvents SDL_HasEvents; + pSDL_FlushEvent SDL_FlushEvent; + pSDL_FlushEvents SDL_FlushEvents; + pSDL_PollEvent SDL_PollEvent; + pSDL_WaitEvent SDL_WaitEvent; + pSDL_WaitEventTimeout SDL_WaitEventTimeout; + pSDL_PushEvent SDL_PushEvent; + pSDL_SetEventFilter SDL_SetEventFilter; + pSDL_GetEventFilter SDL_GetEventFilter; + pSDL_AddEventWatch SDL_AddEventWatch; + pSDL_DelEventWatch SDL_DelEventWatch; + pSDL_FilterEvents SDL_FilterEvents; + pSDL_EventState SDL_EventState; + pSDL_RegisterEvents SDL_RegisterEvents; + } +} \ No newline at end of file diff --git a/demos/external/imports/bindbc/sdl/bind/sdlfilesystem.d b/demos/external/imports/bindbc/sdl/bind/sdlfilesystem.d new file mode 100644 index 0000000..a3edcdc --- /dev/null +++ b/demos/external/imports/bindbc/sdl/bind/sdlfilesystem.d @@ -0,0 +1,31 @@ + +// Copyright Michael D. Parker 2018. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +module bindbc.sdl.bind.sdlfilesystem; + +import bindbc.sdl.config; + +version(BindSDL_Static){ + extern(C) @nogc nothrow { + static if(sdlSupport >= SDLSupport.sdl201) { + char* SDL_GetBasePath(); + char* SDL_GetPrefPath(const(char)* org,const(char)* app); + } + } +} +else { + static if(sdlSupport >= SDLSupport.sdl201) { + extern(C) @nogc nothrow { + alias pSDL_GetBasePath = char* function(); + alias pSDL_GetPrefPath = char* function(const(char)* org,const(char)* app); + } + + __gshared { + pSDL_GetBasePath SDL_GetBasePath; + pSDL_GetPrefPath SDL_GetPrefPath; + } + } +} diff --git a/demos/external/imports/bindbc/sdl/bind/sdlgamecontroller.d b/demos/external/imports/bindbc/sdl/bind/sdlgamecontroller.d new file mode 100644 index 0000000..295d117 --- /dev/null +++ b/demos/external/imports/bindbc/sdl/bind/sdlgamecontroller.d @@ -0,0 +1,225 @@ + +// Copyright Michael D. Parker 2018. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +module bindbc.sdl.bind.sdlgamecontroller; + +import bindbc.sdl.config; + +import bindbc.sdl.bind.sdljoystick, + bindbc.sdl.bind.sdlrwops; +import bindbc.sdl.bind.sdlstdinc : SDL_bool; + +struct SDL_GameController; + +enum SDL_GameControllerBindType { + SDL_CONTROLLER_BINDTYPE_NONE = 0, + SDL_CONTROLLER_BINDTYPE_BUTTON, + SDL_CONTROLLER_BINDTYPE_AXIS, + SDL_CONTROLLER_BINDTYPE_HAT, +} +mixin(expandEnum!SDL_GameControllerBindType); + +struct SDL_GameControllerButtonBind { + SDL_GameControllerBindType bindType; + union value { + int button; + int axis; + struct hat { + int hat; + int hat_mask; + } + } + alias button = value.button; + alias axis = value.axis; + alias hat = value.hat; +} + +enum SDL_GameControllerAxis { + SDL_CONTROLLER_AXIS_INVALID = -1, + SDL_CONTROLLER_AXIS_LEFTX, + SDL_CONTROLLER_AXIS_LEFTY, + SDL_CONTROLLER_AXIS_RIGHTX, + SDL_CONTROLLER_AXIS_RIGHTY, + SDL_CONTROLLER_AXIS_TRIGGERLEFT, + SDL_CONTROLLER_AXIS_TRIGGERRIGHT, + SDL_CONTROLLER_AXIS_MAX +} +mixin(expandEnum!SDL_GameControllerAxis); + +enum SDL_GameControllerButton { + SDL_CONTROLLER_BUTTON_INVALID = -1, + SDL_CONTROLLER_BUTTON_A, + SDL_CONTROLLER_BUTTON_B, + SDL_CONTROLLER_BUTTON_X, + SDL_CONTROLLER_BUTTON_Y, + SDL_CONTROLLER_BUTTON_BACK, + SDL_CONTROLLER_BUTTON_GUIDE, + SDL_CONTROLLER_BUTTON_START, + SDL_CONTROLLER_BUTTON_LEFTSTICK, + SDL_CONTROLLER_BUTTON_RIGHTSTICK, + SDL_CONTROLLER_BUTTON_LEFTSHOULDER, + SDL_CONTROLLER_BUTTON_RIGHTSHOULDER, + SDL_CONTROLLER_BUTTON_DPAD_UP, + SDL_CONTROLLER_BUTTON_DPAD_DOWN, + SDL_CONTROLLER_BUTTON_DPAD_LEFT, + SDL_CONTROLLER_BUTTON_DPAD_RIGHT, + SDL_CONTROLLER_BUTTON_MAX +} +mixin(expandEnum!SDL_GameControllerButton); + +static if(sdlSupport >= SDLSupport.sdl202) { + @nogc nothrow + int SDL_GameControllerAddMappingsFromFile(const(char)* file) { + pragma(inline, true); + return SDL_GameControllerAddMappingsFromRW(SDL_RWFromFile(file,"rb"),1); + } +} + +version(BindSDL_Static) { + extern(C) @nogc nothrow { + int SDL_GameControllerAddMapping(const(char)*); + char* SDL_GameControllerMappingForGUID(SDL_JoystickGUID); + char* SDL_GameControllerMapping(SDL_GameController*); + SDL_bool SDL_IsGameController(int); + const(char)* SDL_GameControllerNameForIndex(int); + SDL_GameController* SDL_GameControllerOpen(int); + const(char)* SDL_GameControllerName(SDL_GameController*); + SDL_bool SDL_GameControllerGetAttached(SDL_GameController*); + SDL_Joystick* SDL_GameControllerGetJoystick(SDL_GameController*); + int SDL_GameControllerEventState(int); + void SDL_GameControllerUpdate(); + SDL_GameControllerAxis SDL_GameControllerGetAxisFromString(const(char)*); + const(char)* SDL_GameControllerGetStringForAxis(SDL_GameControllerAxis); + SDL_GameControllerButtonBind SDL_GameControllerGetBindForAxis(SDL_GameController*,SDL_GameControllerAxis); + short SDL_GameControllerGetAxis(SDL_GameController*,SDL_GameControllerAxis); + SDL_GameControllerButton SDL_GameControllerGetButtonFromString(const(char*)); + const(char)* SDL_GameControllerGetStringForButton(SDL_GameControllerButton); + SDL_GameControllerButtonBind SDL_GameControllerGetBindForButton(SDL_GameController*,SDL_GameControllerButton); + ubyte SDL_GameControllerGetButton(SDL_GameController*,SDL_GameControllerButton); + void SDL_GameControllerClose(SDL_GameController*); + + static if(sdlSupport >= SDLSupport.sdl202) { + int SDL_GameControllerAddMappingsFromRW(SDL_RWops*,int); + } + static if(sdlSupport >= SDLSupport.sdl204) { + SDL_GameController* SDL_GameControllerFromInstanceID(SDL_JoystickID); + } + static if(sdlSupport >= SDLSupport.sdl206) { + ushort SDL_GameControllerGetProduct(SDL_GameController*); + ushort SDL_GameControllerGetProductVersion(SDL_GameController*); + ushort SDL_GameControllerGetVendor(SDL_GameController*); + char* SDL_GameControllerMappingForIndex(int); + int SDL_GameControllerNumMappings(); + } + static if(sdlSupport >= SDLSupport.sdl209) { + char* SDL_GameControllerMappingForDeviceIndex(int); + int SDL_GameControllerRumble(SDL_GameController*,ushort,ushort,uint); + } + static if(sdlSupport >= SDLSupport.sdl2010) { + int SDL_GameControllerGetPlayerIndex(SDL_GameController*); + } + } +} +else { + extern(C) @nogc nothrow { + alias pSDL_GameControllerAddMapping = int function(const(char)*); + alias pSDL_GameControllerMappingForGUID = char* function(SDL_JoystickGUID); + alias pSDL_GameControllerMapping = char* function(SDL_GameController*); + alias pSDL_IsGameController = SDL_bool function(int); + alias pSDL_GameControllerNameForIndex = const(char)* function(int); + alias pSDL_GameControllerOpen = SDL_GameController* function(int); + alias pSDL_GameControllerName = const(char)* function(SDL_GameController*); + alias pSDL_GameControllerGetAttached = SDL_bool function(SDL_GameController*); + alias pSDL_GameControllerGetJoystick = SDL_Joystick* function(SDL_GameController*); + alias pSDL_GameControllerEventState = int function(int); + alias pSDL_GameControllerUpdate = void function(); + alias pSDL_GameControllerGetAxisFromString = SDL_GameControllerAxis function(const(char)*); + alias pSDL_GameControllerGetStringForAxis = const(char)* function(SDL_GameControllerAxis); + alias pSDL_GameControllerGetBindForAxis = SDL_GameControllerButtonBind function(SDL_GameController*,SDL_GameControllerAxis); + alias pSDL_GameControllerGetAxis = short function(SDL_GameController*,SDL_GameControllerAxis); + alias pSDL_GameControllerGetButtonFromString = SDL_GameControllerButton function(const(char*)); + alias pSDL_GameControllerGetStringForButton = const(char)* function(SDL_GameControllerButton); + alias pSDL_GameControllerGetBindForButton = SDL_GameControllerButtonBind function(SDL_GameController*,SDL_GameControllerButton); + alias pSDL_GameControllerGetButton = ubyte function(SDL_GameController*,SDL_GameControllerButton); + alias pSDL_GameControllerClose = void function(SDL_GameController*); + } + __gshared { + pSDL_GameControllerAddMapping SDL_GameControllerAddMapping; + pSDL_GameControllerMappingForGUID SDL_GameControllerMappingForGUID; + pSDL_GameControllerMapping SDL_GameControllerMapping; + pSDL_IsGameController SDL_IsGameController; + pSDL_GameControllerNameForIndex SDL_GameControllerNameForIndex; + pSDL_GameControllerOpen SDL_GameControllerOpen; + pSDL_GameControllerName SDL_GameControllerName; + pSDL_GameControllerGetAttached SDL_GameControllerGetAttached; + pSDL_GameControllerGetJoystick SDL_GameControllerGetJoystick; + pSDL_GameControllerEventState SDL_GameControllerEventState; + pSDL_GameControllerUpdate SDL_GameControllerUpdate; + pSDL_GameControllerGetAxisFromString SDL_GameControllerGetAxisFromString; + pSDL_GameControllerGetStringForAxis SDL_GameControllerGetStringForAxis; + pSDL_GameControllerGetBindForAxis SDL_GameControllerGetBindForAxis; + pSDL_GameControllerGetAxis SDL_GameControllerGetAxis; + pSDL_GameControllerGetButtonFromString SDL_GameControllerGetButtonFromString; + pSDL_GameControllerGetStringForButton SDL_GameControllerGetStringForButton; + pSDL_GameControllerGetBindForButton SDL_GameControllerGetBindForButton; + pSDL_GameControllerGetButton SDL_GameControllerGetButton; + pSDL_GameControllerClose SDL_GameControllerClose; + } + static if(sdlSupport >= SDLSupport.sdl202) { + extern(C) @nogc nothrow { + alias pSDL_GameControllerAddMappingsFromRW = int function(SDL_RWops*,int); + } + + __gshared { + pSDL_GameControllerAddMappingsFromRW SDL_GameControllerAddMappingsFromRW; + } + } + static if(sdlSupport >= SDLSupport.sdl204) { + extern(C) @nogc nothrow { + alias pSDL_GameControllerFromInstanceID = SDL_GameController* function(SDL_JoystickID); + } + + __gshared { + pSDL_GameControllerFromInstanceID SDL_GameControllerFromInstanceID; + } + } + static if(sdlSupport >= SDLSupport.sdl206) { + extern(C) @nogc nothrow { + alias pSDL_GameControllerGetProduct = ushort function(SDL_GameController*); + alias pSDL_GameControllerGetProductVersion = ushort function(SDL_GameController*); + alias pSDL_GameControllerGetVendor = ushort function(SDL_GameController*); + alias pSDL_GameControllerMappingForIndex = char* function(int); + alias pSDL_GameControllerNumMappings = int function(); + } + + __gshared { + pSDL_GameControllerGetProduct SDL_GameControllerGetProduct; + pSDL_GameControllerGetProductVersion SDL_GameControllerGetProductVersion; + pSDL_GameControllerGetVendor SDL_GameControllerGetVendor; + pSDL_GameControllerMappingForIndex SDL_GameControllerMappingForIndex; + pSDL_GameControllerNumMappings SDL_GameControllerNumMappings; + } + } + static if(sdlSupport >= SDLSupport.sdl209) { + extern(C) @nogc nothrow { + alias pSDL_GameControllerMappingForDeviceIndex = char* function(int); + alias pSDL_GameControllerRumble = int function(SDL_GameController*,ushort,ushort,uint); + } + + __gshared { + pSDL_GameControllerMappingForDeviceIndex SDL_GameControllerMappingForDeviceIndex; + pSDL_GameControllerRumble SDL_GameControllerRumble; + } + } + static if(sdlSupport >= SDLSupport.sdl2010) { + extern(C) @nogc nothrow { + alias pSDL_GameControllerGetPlayerIndex = int function(SDL_GameController*); + } + __gshared { + pSDL_GameControllerGetPlayerIndex SDL_GameControllerGetPlayerIndex; + } + } +} \ No newline at end of file diff --git a/demos/external/imports/bindbc/sdl/bind/sdlgesture.d b/demos/external/imports/bindbc/sdl/bind/sdlgesture.d new file mode 100644 index 0000000..62ea0e5 --- /dev/null +++ b/demos/external/imports/bindbc/sdl/bind/sdlgesture.d @@ -0,0 +1,36 @@ + +// Copyright Michael D. Parker 2018. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +module bindbc.sdl.bind.sdlgesture; + +import bindbc.sdl.bind.sdltouch : SDL_TouchID; +import bindbc.sdl.bind.sdlrwops : SDL_RWops; + +alias SDL_GestureID = long; + +version(BindSDL_Static) { + extern(C) @nogc nothrow { + int SDL_RecordGesture(SDL_TouchID); + int SDL_SaveAllDollarTemplates(SDL_RWops*); + int SDL_SaveDollarTemplate(SDL_GestureID,SDL_RWops*); + int SDL_LoadDollarTemplates(SDL_TouchID,SDL_RWops*); + } +} +else { + extern(C) @nogc nothrow { + alias pSDL_RecordGesture = int function(SDL_TouchID); + alias pSDL_SaveAllDollarTemplates = int function(SDL_RWops*); + alias pSDL_SaveDollarTemplate = int function(SDL_GestureID,SDL_RWops*); + alias pSDL_LoadDollarTemplates = int function(SDL_TouchID,SDL_RWops*); + } + + __gshared { + pSDL_RecordGesture SDL_RecordGesture; + pSDL_SaveAllDollarTemplates SDL_SaveAllDollarTemplates; + pSDL_SaveDollarTemplate SDL_SaveDollarTemplate; + pSDL_LoadDollarTemplates SDL_LoadDollarTemplates; + } +} \ No newline at end of file diff --git a/demos/external/imports/bindbc/sdl/bind/sdlhaptic.d b/demos/external/imports/bindbc/sdl/bind/sdlhaptic.d new file mode 100644 index 0000000..f706080 --- /dev/null +++ b/demos/external/imports/bindbc/sdl/bind/sdlhaptic.d @@ -0,0 +1,240 @@ + +// Copyright Michael D. Parker 2018. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +module bindbc.sdl.bind.sdlhaptic; + +import bindbc.sdl.bind.sdljoystick : SDL_Joystick; + +struct SDL_Haptic; + +enum : ushort { + SDL_HAPTIC_CONSTANT = 1u<<0, + SDL_HAPTIC_SINE = 1u<<1, + SDL_HAPTIC_LEFTRIGHT = 1u<<2, + SDL_HAPTIC_TRIANGLE = 1u<<3, + SDL_HAPTIC_SAWTOOTHUP = 1u<<4, + SDL_HAPTIC_SAWTOOTHDOWN = 1u<<5, + SDL_HAPTIC_RAMP = 1u<<6, + SDL_HAPTIC_SPRING = 1u<<7, + SDL_HAPTIC_DAMPER = 1u<<8, + SDL_HAPTIC_INERTIA = 1u<<9, + SDL_HAPTIC_FRICTION = 1u<<10, + SDL_HAPTIC_CUSTOM = 1u<<11, + SDL_HAPTIC_GAIN = 1u<<12, + SDL_HAPTIC_AUTOCENTER = 1u<<13, + SDL_HAPTIC_STATUS = 1u<<14, + SDL_HAPTIC_PAUSE = 1u<<15, +} + +enum { + SDL_HAPTIC_POLAR = 0, + SDL_HAPTIC_CARTESIAN = 1, + SDL_HAPTIC_SPHERICAL = 2, +} + +enum SDL_HAPTIC_INFINITY = 4294967295U; + +struct SDL_HapticDirection { + ubyte type; + int[3] dir; +} + +struct SDL_HapticConstant { + ushort type; + SDL_HapticDirection direction; + uint length; + ushort delay; + ushort button; + ushort interval; + short level; + ushort attack_length; + ushort attack_level; + ushort fade_length; + ushort fade_level; +} + +struct SDL_HapticPeriodic { + ushort type; + SDL_HapticDirection direction; + uint length; + uint delay; + ushort button; + ushort interval; + ushort period; + short magnitude; + short offset; + ushort phase; + ushort attack_length; + ushort attack_level; + ushort fade_length; + ushort fade_level; +} + +struct SDL_HapticCondition { + ushort type; + SDL_HapticDirection direciton; + uint length; + ushort delay; + ushort button; + ushort interval; + ushort[3] right_sat; + ushort[3] left_sat; + short[3] right_coeff; + short[3] left_coeff; + ushort[3] deadband; + ushort[3] center; +} + +struct SDL_HapticRamp { + ushort type; + SDL_HapticDirection direction; + uint length; + ushort delay; + ushort button; + ushort interval; + short start; + short end; + ushort attack_length; + ushort attack_level; + ushort fade_length; + ushort fade_level; +} + +struct SDL_HapticLeftRight { + ushort type; + uint length; + ushort large_magnitude; + ushort small_magnitude; +} + +struct SDL_HapticCustom { + ushort type; + SDL_HapticDirection direction; + uint length; + ushort delay; + ushort button; + ushort interval; + ubyte channels; + ushort period; + ushort samples; + ushort* data; + ushort attack_length; + ushort attack_level; + ushort fade_length; + ushort fade_level; +} + +union SDL_HapticEffect { + ushort type; + SDL_HapticConstant constant; + SDL_HapticPeriodic periodic; + SDL_HapticCondition condition; + SDL_HapticRamp ramp; + SDL_HapticLeftRight leftright; + SDL_HapticCustom custom; +} + +version(BindSDL_Static) { + extern(C) @nogc nothrow { + int SDL_NumHaptics(); + const(char)* SDL_HapticName(int); + SDL_Haptic* SDL_HapticOpen(int); + int SDL_HapticOpened(int); + int SDL_HapticIndex(SDL_Haptic*); + int SDL_MouseIsHaptic(); + SDL_Haptic* SDL_HapticOpenFromMouse(); + int SDL_JoystickIsHaptic(SDL_Joystick*); + SDL_Haptic* SDL_HapticOpenFromJoystick(SDL_Joystick*); + int SDL_HapticClose(SDL_Haptic*); + int SDL_HapticNumEffects(SDL_Haptic*); + int SDL_HapticNumEffectsPlaying(SDL_Haptic*); + uint SDL_HapticQuery(SDL_Haptic*); + int SDL_HapticNumAxes(SDL_Haptic*); + int SDL_HapticEffectSupported(SDL_Haptic*,SDL_HapticEffect*); + int SDL_HapticNewEffect(SDL_Haptic*,SDL_HapticEffect*); + int SDL_HapticUpdateEffect(SDL_Haptic*,int,SDL_HapticEffect*); + int SDL_HapticRunEffect(SDL_Haptic*,int,uint); + int SDL_HapticStopEffect(SDL_Haptic*,int); + int SDL_HapticDestroyEffect(SDL_Haptic*,int); + int SDL_HapticGetEffectStatus(SDL_Haptic*,int); + int SDL_HapticSetGain(SDL_Haptic*,int); + int SDL_HapticSetAutocenter(SDL_Haptic*,int); + int SDL_HapticPause(SDL_Haptic*); + int SDL_HapticUnpause(SDL_Haptic*); + int SDL_HapticStopAll(SDL_Haptic*); + int SDL_HapticRumbleSupported(SDL_Haptic*); + int SDL_HapticRumbleInit(SDL_Haptic*); + int SDL_HapticRumblePlay(SDL_Haptic*,float,uint); + int SDL_HapticRumbleStop(SDL_Haptic*); + } +} +else { + extern(C) @nogc nothrow { + alias pSDL_NumHaptics = int function(); + alias pSDL_HapticName = const(char)* function(int); + alias pSDL_HapticOpen = SDL_Haptic* function(int); + alias pSDL_HapticOpened = int function(int); + alias pSDL_HapticIndex = int function(SDL_Haptic*); + alias pSDL_MouseIsHaptic = int function(); + alias pSDL_HapticOpenFromMouse = SDL_Haptic* function(); + alias pSDL_JoystickIsHaptic = int function(SDL_Joystick*); + alias pSDL_HapticOpenFromJoystick = SDL_Haptic* function(SDL_Joystick*); + alias pSDL_HapticClose = int function(SDL_Haptic*); + alias pSDL_HapticNumEffects = int function(SDL_Haptic*); + alias pSDL_HapticNumEffectsPlaying = int function(SDL_Haptic*); + alias pSDL_HapticQuery = uint function(SDL_Haptic*); + alias pSDL_HapticNumAxes = int function(SDL_Haptic*); + alias pSDL_HapticEffectSupported = int function(SDL_Haptic*,SDL_HapticEffect*); + alias pSDL_HapticNewEffect = int function(SDL_Haptic*,SDL_HapticEffect*); + alias pSDL_HapticUpdateEffect = int function(SDL_Haptic*,int,SDL_HapticEffect*); + alias pSDL_HapticRunEffect = int function(SDL_Haptic*,int,uint); + alias pSDL_HapticStopEffect = int function(SDL_Haptic*,int); + alias pSDL_HapticDestroyEffect = int function(SDL_Haptic*,int); + alias pSDL_HapticGetEffectStatus = int function(SDL_Haptic*,int); + alias pSDL_HapticSetGain = int function(SDL_Haptic*,int); + alias pSDL_HapticSetAutocenter = int function(SDL_Haptic*,int); + alias pSDL_HapticPause = int function(SDL_Haptic*); + alias pSDL_HapticUnpause = int function(SDL_Haptic*); + alias pSDL_HapticStopAll = int function(SDL_Haptic*); + alias pSDL_HapticRumbleSupported = int function(SDL_Haptic*); + alias pSDL_HapticRumbleInit = int function(SDL_Haptic*); + alias pSDL_HapticRumblePlay = int function(SDL_Haptic*,float,uint); + alias pSDL_HapticRumbleStop = int function(SDL_Haptic*); + } + + __gshared { + pSDL_NumHaptics SDL_NumHaptics; + pSDL_HapticName SDL_HapticName; + pSDL_HapticOpen SDL_HapticOpen; + pSDL_HapticOpened SDL_HapticOpened; + pSDL_HapticIndex SDL_HapticIndex; + pSDL_MouseIsHaptic SDL_MouseIsHaptic; + pSDL_HapticOpenFromMouse SDL_HapticOpenFromMouse; + pSDL_JoystickIsHaptic SDL_JoystickIsHaptic; + pSDL_HapticOpenFromJoystick SDL_HapticOpenFromJoystick; + pSDL_HapticClose SDL_HapticClose; + pSDL_HapticNumEffects SDL_HapticNumEffects; + pSDL_HapticNumEffectsPlaying SDL_HapticNumEffectsPlaying; + pSDL_HapticQuery SDL_HapticQuery; + pSDL_HapticNumAxes SDL_HapticNumAxes; + pSDL_HapticEffectSupported SDL_HapticEffectSupported; + pSDL_HapticNewEffect SDL_HapticNewEffect; + pSDL_HapticUpdateEffect SDL_HapticUpdateEffect; + pSDL_HapticRunEffect SDL_HapticRunEffect; + pSDL_HapticStopEffect SDL_HapticStopEffect; + pSDL_HapticDestroyEffect SDL_HapticDestroyEffect; + pSDL_HapticGetEffectStatus SDL_HapticGetEffectStatus; + pSDL_HapticSetGain SDL_HapticSetGain; + pSDL_HapticSetAutocenter SDL_HapticSetAutocenter; + pSDL_HapticPause SDL_HapticPause; + pSDL_HapticUnpause SDL_HapticUnpause; + pSDL_HapticStopAll SDL_HapticStopAll; + pSDL_HapticRumbleSupported SDL_HapticRumbleSupported; + pSDL_HapticRumbleInit SDL_HapticRumbleInit; + pSDL_HapticRumblePlay SDL_HapticRumblePlay; + pSDL_HapticRumbleStop SDL_HapticRumbleStop; + } +} \ No newline at end of file diff --git a/demos/external/imports/bindbc/sdl/bind/sdlhints.d b/demos/external/imports/bindbc/sdl/bind/sdlhints.d new file mode 100644 index 0000000..e5aad86 --- /dev/null +++ b/demos/external/imports/bindbc/sdl/bind/sdlhints.d @@ -0,0 +1,186 @@ + +// Copyright Michael D. Parker 2018. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +module bindbc.sdl.bind.sdlhints; + +import bindbc.sdl.config; +import bindbc.sdl.bind.sdlstdinc : SDL_bool; + +enum SDL_HINT_FRAMEBUFFER_ACCELERATION = "SDL_FRAMEBUFFER_ACCELERATION"; +enum SDL_HINT_RENDER_DRIVER = "SDL_RENDER_DRIVER"; +enum SDL_HINT_RENDER_OPENGL_SHADERS = "SDL_RENDER_OPENGL_SHADERS"; +enum SDL_HINT_RENDER_SCALE_QUALITY = "SDL_RENDER_SCALE_QUALITY"; +enum SDL_HINT_RENDER_VSYNC = "SDL_RENDER_VSYNC"; +enum SDL_HINT_VIDEO_X11_XVIDMODE = "SDL_VIDEO_X11_XVIDMODE"; +enum SDL_HINT_VIDEO_X11_XINERAMA = "SDL_VIDEO_X11_XINERAMA"; +enum SDL_HINT_VIDEO_X11_XRANDR = "SDL_VIDEO_X11_XRANDR"; +enum SDL_HINT_GRAB_KEYBOARD = "SDL_GRAB_KEYBOARD"; +enum SDL_HINT_VIDEO_MINIMIZE_ON_FOCUS_LOSS = "SDL_VIDEO_MINIMIZE_ON_FOCUS_LOSS"; +enum SDL_HINT_IDLE_TIMER_DISABLED = "SDL_IOS_IDLE_TIMER_DISABLED"; +enum SDL_HINT_ORIENTATIONS = "SDL_IOS_ORIENTATIONS"; +enum SDL_HINT_XINPUT_ENABLED = "SDL_XINPUT_ENABLED"; +enum SDL_HINT_GAMECONTROLLERCONFIG = "SDL_GAMECONTROLLERCONFIG"; +enum SDL_HINT_JOYSTICK_ALLOW_BACKGROUND_EVENTS = "SDL_JOYSTICK_ALLOW_BACKGROUND_EVENTS"; +enum SDL_HINT_ALLOW_TOPMOST = "SDL_ALLOW_TOPMOST"; +enum SDL_HINT_TIMER_RESOLUTION = "SDL_TIMER_RESOLUTION"; + +static if(sdlSupport >= SDLSupport.sdl201) { + enum SDL_HINT_RENDER_DIRECT3D_THREADSAFE = "SDL_RENDER_DIRECT3D_THREADSAFE"; + enum SDL_HINT_VIDEO_HIGHDPI_DISABLED = "SDL_VIDEO_HIGHDPI_DISABLED"; +} + +static if(sdlSupport >= SDLSupport.sdl202) { + enum SDL_HINT_VIDEO_ALLOW_SCREENSAVER = "SDL_VIDEO_ALLOW_SCREENSAVER"; + enum SDL_HINT_MOUSE_RELATIVE_MODE_WARP = "SDL_MOUSE_RELATIVE_MODE_WARP"; + enum SDL_HINT_ACCELEROMETER_AS_JOYSTICK = "SDL_ACCELEROMETER_AS_JOYSTICK"; + enum SDL_HINT_MAC_CTRL_CLICK_EMULATE_RIGHT_CLICK = "SDL_MAC_CTRL_CLICK_EMULATE_RIGHT_CLICK"; + enum SDL_HINT_VIDEO_WIN_D3DCOMPILER = "SDL_VIDEO_WIN_D3DCOMPILER"; + enum SDL_HINT_VIDEO_WINDOW_SHARE_PIXEL_FORMAT = "SDL_VIDEO_WINDOW_SHARE_PIXEL_FORMAT"; + enum SDL_HINT_VIDEO_MAC_FULLSCREEN_SPACES = "SDL_HINT_VIDEO_MAC_FULLSCREEN_SPACES"; +} + +// This is *intended* to be == and not >=. The values for all of these changed in 2.0.4. +static if(sdlSupport == SDLSupport.sdl203) { + enum SDL_HINT_RENDER_DIRECT3D11_DEBUG = "SDL_HINT_RENDER_DIRECT3D11_DEBUG"; + enum SDL_HINT_WINRT_PRIVACY_POLICY_URL = "SDL_HINT_WINRT_PRIVACY_POLICY_URL"; + enum SDL_HINT_WINRT_PRIVACY_POLICY_LABEL = "SDL_HINT_WINRT_PRIVACY_POLICY_LABEL"; + enum SDL_HINT_WINRT_HANDLE_BACK_BUTTON = "SDL_HINT_WINRT_HANDLE_BACK_BUTTON"; +} + +static if(sdlSupport >= SDLSupport.sdl204) { + enum SDL_HINT_VIDEO_X11_NET_WM_PING = "SDL_VIDEO_X11_NET_WM_PING"; + enum SDL_HINT_WINDOW_FRAME_USABLE_WHILE_CURSOR_HIDDEN = "SDL_WINDOW_FRAME_USABLE_WHILE_CURSOR_HIDDEN"; + enum SDL_HINT_WINDOWS_ENABLE_MESSAGELOOP = "SDL_WINDOWS_ENABLE_MESSAGELOOP"; + enum SDL_HINT_XINPUT_USE_OLD_JOYSTICK_MAPPING = "SDL_XINPUT_USE_OLD_JOYSTICK_MAPPING"; + enum SDL_HINT_THREAD_STACK_SIZE = "SDL_THREAD_STACK_SIZE"; + enum SDL_HINT_MAC_BACKGROUND_APP = "SDL_MAC_BACKGROUND_APP"; + enum SDL_HINT_ANDROID_APK_EXPANSION_MAIN_FILE_VERSION = "SDL_ANDROID_APK_EXPANSION_MAIN_FILE_VERSION"; + enum SDL_HINT_ANDROID_APK_EXPANSION_PATCH_FILE_VERSION = "SDL_ANDROID_APK_EXPANSION_PATCH_FILE_VERSION"; + enum SDL_HINT_IME_INTERNAL_EDITING = "SDL_IME_INTERNAL_EDITING"; + enum SDL_HINT_EMSCRIPTEN_KEYBOARD_ELEMENT = "SDL_EMSCRIPTEN_KEYBOARD_ELEMENT"; + enum SDL_HINT_NO_SIGNAL_HANDLERS = "SDL_NO_SIGNAL_HANDLERS"; + enum SDL_HINT_WINDOWS_NO_CLOSE_ON_ALT_F4 = "SDL_WINDOWS_NO_CLOSE_ON_ALT_F4"; + + // Changed values from those introduced in 2.0.3 + enum SDL_HINT_RENDER_DIRECT3D11_DEBUG = "SDL_RENDER_DIRECT3D11_DEBUG"; + enum SDL_HINT_WINRT_PRIVACY_POLICY_URL = "SDL_WINRT_PRIVACY_POLICY_URL"; + enum SDL_HINT_WINRT_PRIVACY_POLICY_LABEL = "SDL_WINRT_PRIVACY_POLICY_LABEL"; + enum SDL_HINT_WINRT_HANDLE_BACK_BUTTON = "SDL_WINRT_HANDLE_BACK_BUTTON"; +} + +static if(sdlSupport >= SDLSupport.sdl205) { + enum SDL_HINT_MOUSE_FOCUS_CLICKTHROUGH = "SDL_MOUSE_FOCUS_CLICKTHROUGH"; + enum SDL_HINT_APPLE_TV_CONTROLLER_UI_EVENTS = "SDL_APPLE_TV_CONTROLLER_UI_EVENTS"; + enum SDL_HINT_APPLE_TV_REMOTE_ALLOW_ROTATION = "SDL_APPLE_TV_REMOTE_ALLOW_ROTATION"; + enum SDL_HINT_BMP_SAVE_LEGACY_FORMAT = "SDL_BMP_SAVE_LEGACY_FORMAT"; + enum SDL_HINT_WINDOWS_DISABLE_THREAD_NAMING = "SDL_WINDOWS_DISABLE_THREAD_NAMING"; + enum SDL_HINT_RPI_VIDEO_LAYER = "SDL_RPI_VIDEO_LAYER"; +} + +static if(sdlSupport >= SDLSupport.sdl206) { + enum SDL_HINT_RENDER_LOGICAL_SIZE_MODE = "SDL_RENDER_LOGICAL_SIZE_MODE"; + enum SDL_HINT_WINDOWS_INTRESOURCE_ICON = "SDL_WINDOWS_INTRESOURCE_ICON"; + enum SDL_HINT_WINDOWS_INTRESOURCE_ICON_SMALL = "SDL_WINDOWS_INTRESOURCE_ICON_SMALL"; + enum SDL_HINT_MOUSE_NORMAL_SPEED_SCALE = "SDL_MOUSE_NORMAL_SPEED_SCALE"; + enum SDL_HINT_MOUSE_RELATIVE_SPEED_SCALE = "SDL_MOUSE_RELATIVE_SPEED_SCALE"; + enum SDL_HINT_TOUCH_MOUSE_EVENTS = "SDL_TOUCH_MOUSE_EVENTS"; + enum SDL_HINT_GAMECONTROLLER_IGNORE_DEVICES = "SDL_GAMECONTROLLER_IGNORE_DEVICES"; + enum SDL_HINT_GAMECONTROLLER_IGNORE_DEVICES_EXCEPT = "SDL_GAMECONTROLLER_IGNORE_DEVICES_EXCEPT"; + enum SDL_HINT_QTWAYLAND_CONTENT_ORIENTATION = "SDL_QTWAYLAND_CONTENT_ORIENTATION"; + enum SDL_HINT_QTWAYLAND_WINDOW_FLAGS = "SDL_QTWAYLAND_WINDOW_FLAGS"; + enum SDL_HINT_OPENGL_ES_DRIVER = "SDL_OPENGL_ES_DRIVER"; + enum SDL_HINT_AUDIO_RESAMPLING_MODE = "SDL_AUDIO_RESAMPLING_MODE"; + enum SDL_HINT_AUDIO_CATEGORY = "SDL_AUDIO_CATEGORY"; +} + +static if(sdlSupport >= SDLSupport.sdl208) { + enum SDL_HINT_VIDEO_X11_NET_WM_BYPASS_COMPOSITOR = "SDL_VIDEO_X11_NET_WM_BYPASS_COMPOSITOR"; + enum SDL_HINT_IOS_HIDE_HOME_INDICATOR = "SDL_IOS_HIDE_HOME_INDICATOR"; + enum SDL_HINT_TV_REMOTE_AS_JOYSTICK = "SDL_TV_REMOTE_AS_JOYSTICK"; + enum SDL_HINT_RETURN_KEY_HIDES_IME = "SDL_RETURN_KEY_HIDES_IME"; + enum SDL_HINT_VIDEO_DOUBLE_BUFFER = "SDL_VIDEO_DOUBLE_BUFFER"; +} + +static if(sdlSupport >= SDLSupport.sdl209) { + enum SDL_HINT_MOUSE_DOUBLE_CLICK_TIME = "SDL_MOUSE_DOUBLE_CLICK_TIME"; + enum SDL_HINT_MOUSE_DOUBLE_CLICK_RADIUS = "SDL_MOUSE_DOUBLE_CLICK_RADIUS"; + enum SDL_HINT_JOYSTICK_HIDAPI = "SDL_JOYSTICK_HIDAPI"; + enum SDL_HINT_JOYSTICK_HIDAPI_PS4 = "SDL_JOYSTICK_HIDAPI_PS4"; + enum SDL_HINT_JOYSTICK_HIDAPI_PS4_RUMBLE = "SDL_JOYSTICK_HIDAPI_PS4_RUMBLE"; + enum SDL_HINT_JOYSTICK_HIDAPI_STEAM = "SDL_JOYSTICK_HIDAPI_STEAM"; + enum SDL_HINT_JOYSTICK_HIDAPI_SWITCH = "SDL_JOYSTICK_HIDAPI_SWITCH"; + enum SDL_HINT_JOYSTICK_HIDAPI_XBOX = "SDL_JOYSTICK_HIDAPI_XBOX"; + enum SDL_HINT_ENABLE_STEAM_CONTROLLERS = "SDL_ENABLE_STEAM_CONTROLLERS"; + enum SDL_HINT_ANDROID_TRAP_BACK_BUTTON = "SDL_ANDROID_TRAP_BACK_BUTTON"; +} + +static if(sdlSupport >= SDLSupport.sdl2010) { + enum SDL_HINT_MOUSE_TOUCH_EVENTS = "SDL_MOUSE_TOUCH_EVENTS"; + enum SDL_HINT_GAMECONTROLLERCONFIG_FILE = "SDL_GAMECONTROLLERCONFIG_FILE"; + enum SDL_HINT_ANDROID_BLOCK_ON_PAUSE = "SDL_ANDROID_BLOCK_ON_PAUSE"; + enum SDL_HINT_RENDER_BATCHING = "SDL_RENDER_BATCHING"; + enum SDL_HINT_EVENT_LOGGING = "SDL_EVENT_LOGGING"; + enum SDL_HINT_WAVE_RIFF_CHUNK_SIZE = "SDL_WAVE_RIFF_CHUNK_SIZE"; + enum SDL_HINT_WAVE_TRUNCATION = "SDL_WAVE_TRUNCATION"; + enum SDL_HINT_WAVE_FACT_CHUNK = "SDL_WAVE_FACT_CHUNK"; +} +else static if(sdlSupport >= SDLSupport.sdl204) { + // Added in 2.0.4, removed in 2.0.10. + enum SDL_HINT_ANDROID_SEPARATE_MOUSE_AND_TOUCH = "SDL_ANDROID_SEPARATE_MOUSE_AND_TOUCH"; +} + +enum SDL_HintPriority { + SDL_HINT_DEFAULT, + SDL_HINT_NORMAL, + SDL_HINT_OVERRIDE, +} +mixin(expandEnum!SDL_HintPriority); + +extern(C) nothrow alias SDL_HintCallback = void function(void*, const(char)*, const(char)*); + +version(BindSDL_Static) { + extern(C) @nogc nothrow { + SDL_bool SDL_SetHintWithPriority(const(char)*,const(char)*,SDL_HintPriority); + SDL_bool SDL_SetHint(const(char)*,const(char)*); + const(char)* SDL_GetHint(const(char)*); + void SDL_AddHintCallback(const(char)*,SDL_HintCallback,void*); + void SDL_DelHintCallback(const(char)*,SDL_HintCallback,void*); + void SDL_ClearHints(); + + static if(sdlSupport >= SDLSupport.sdl205) { + SDL_bool SDL_GetHintBoolean(const(char)*,SDL_bool); + } + } +} +else { + extern(C) @nogc nothrow { + alias pSDL_SetHintWithPriority = SDL_bool function(const(char)*,const(char)*,SDL_HintPriority); + alias pSDL_SetHint = SDL_bool function(const(char)*,const(char)*); + alias pSDL_GetHint = const(char)* function(const(char)*); + alias pSDL_AddHintCallback = void function(const(char)*,SDL_HintCallback,void*); + alias pSDL_DelHintCallback = void function(const(char)*,SDL_HintCallback,void*); + alias pSDL_ClearHints = void function(); + } + + __gshared { + pSDL_SetHintWithPriority SDL_SetHintWithPriority; + pSDL_SetHint SDL_SetHint; + pSDL_GetHint SDL_GetHint; + pSDL_AddHintCallback SDL_AddHintCallback; + pSDL_DelHintCallback SDL_DelHintCallback; + pSDL_ClearHints SDL_ClearHints; + } + + static if(sdlSupport >= SDLSupport.sdl205) { + extern(C) @nogc nothrow { + alias pSDL_GetHintBoolean = SDL_bool function(const(char)*,SDL_bool); + } + + __gshared { + pSDL_GetHintBoolean SDL_GetHintBoolean; + } + } +} \ No newline at end of file diff --git a/demos/external/imports/bindbc/sdl/bind/sdljoystick.d b/demos/external/imports/bindbc/sdl/bind/sdljoystick.d new file mode 100644 index 0000000..32f54ec --- /dev/null +++ b/demos/external/imports/bindbc/sdl/bind/sdljoystick.d @@ -0,0 +1,231 @@ + +// Copyright Michael D. Parker 2018. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +module bindbc.sdl.bind.sdljoystick; + +import bindbc.sdl.config; +import bindbc.sdl.bind.sdlstdinc : SDL_bool; + +struct SDL_Joystick; + +struct SDL_JoystickGUID { + ubyte[16] data; +} + +alias SDL_JoystickID = int; + +enum : ubyte { + SDL_HAT_CENTERED = 0x00, + SDL_HAT_UP = 0x01, + SDL_HAT_RIGHT = 0x02, + SDL_HAT_DOWN = 0x04, + SDL_HAT_LEFT = 0x08, + SDL_HAT_RIGHTUP = (SDL_HAT_RIGHT|SDL_HAT_UP), + SDL_HAT_RIGHTDOWN = (SDL_HAT_RIGHT|SDL_HAT_DOWN), + SDL_HAT_LEFTUP = (SDL_HAT_LEFT|SDL_HAT_UP), + SDL_HAT_LEFTDOWN = (SDL_HAT_LEFT|SDL_HAT_DOWN), +} + +static if(sdlSupport >= SDLSupport.sdl204) { + enum SDL_JoystickPowerLevel { + SDL_JOYSTICK_POWER_UNKNOWN = -1, + SDL_JOYSTICK_POWER_EMPTY, + SDL_JOYSTICK_POWER_LOW, + SDL_JOYSTICK_POWER_MEDIUM, + SDL_JOYSTICK_POWER_FULL, + SDL_JOYSTICK_POWER_WIRED, + SDL_JOYSTICK_POWER_MAX + } + mixin(expandEnum!SDL_JoystickPowerLevel); +} + +static if(sdlSupport >= SDLSupport.sdl206) { + enum SDL_JoystickType { + SDL_JOYSTICK_TYPE_UNKNOWN, + SDL_JOYSTICK_TYPE_GAMECONTROLLER, + SDL_JOYSTICK_TYPE_WHEEL, + SDL_JOYSTICK_TYPE_ARCADE_STICK, + SDL_JOYSTICK_TYPE_FLIGHT_STICK, + SDL_JOYSTICK_TYPE_DANCE_PAD, + SDL_JOYSTICK_TYPE_GUITAR, + SDL_JOYSTICK_TYPE_DRUM_KIT, + SDL_JOYSTICK_TYPE_ARCADE_PAD, + SDL_JOYSTICK_TYPE_THROTTLE, + } + mixin(expandEnum!SDL_JoystickType); + + enum { + SDL_JOYSTICK_AXIS_MAX = 32767, + SDL_JOYSTICK_AXIS_MIN = -32768, + } +} + +version(BindSDL_Static) { + extern(C) @nogc nothrow { + int SDL_NumJoysticks(); + const(char)* SDL_JoystickNameForIndex(int); + SDL_JoystickGUID SDL_JoystickGetDeviceGUID(int); + SDL_Joystick* SDL_JoystickOpen(int); + const(char)* SDL_JoystickName(SDL_Joystick*); + SDL_JoystickGUID SDL_JoystickGetGUID(SDL_Joystick*); + char* SDL_JoystickGetGUIDString(SDL_JoystickGUID); + SDL_JoystickGUID SDL_JoystickGetGUIDFromString(const(char)*); + SDL_bool SDL_JoystickGetAttached(SDL_Joystick*); + SDL_JoystickID SDL_JoystickInstanceID(SDL_Joystick*); + int SDL_JoystickNumAxes(SDL_Joystick*); + int SDL_JoystickNumBalls(SDL_Joystick*); + int SDL_JoystickNumHats(SDL_Joystick*); + int SDL_JoystickNumButtons(SDL_Joystick*); + void SDL_JoystickUpdate(); + int SDL_JoystickEventState(int); + short SDL_JoystickGetAxis(SDL_Joystick*,int); + ubyte SDL_JoystickGetHat(SDL_Joystick*,int); + int SDL_JoystickGetBall(SDL_Joystick*,int,int*,int*); + ubyte SDL_JoystickGetButton(SDL_Joystick*,int); + void SDL_JoystickClose(SDL_Joystick*); + + static if(sdlSupport >= SDLSupport.sdl204) { + SDL_JoystickPowerLevel SDL_JoystickCurrentPowerLevel(SDL_Joystick*); + SDL_Joystick* SDL_JoystickFromInstanceID(SDL_JoystickID); + } + static if(sdlSupport >= SDLSupport.sdl206) { + SDL_bool SDL_JoystickGetAxisInitialState(SDL_Joystick*,int,short*); + SDL_JoystickType SDL_JoystickGetDeviceInstanceID(int); + ushort SDL_JoystickGetDeviceProduct(int); + ushort SDL_JoystickGetDeviceProductVersion(int); + SDL_JoystickType SDL_JoystickGetDeviceType(int); + ushort SDL_JoystickGetDeviceVendor(int); + ushort SDL_JoystickGetProduct(SDL_Joystick*); + ushort SDL_JoystickGetProductVersion(SDL_Joystick*); + SDL_JoystickType SDL_JoystickGetType(SDL_Joystick*); + ushort SDL_JoystickGetVendor(SDL_Joystick*); + } + static if(sdlSupport >= SDLSupport.sdl207) { + void SDL_LockJoysticks(); + void SDL_UnlockJoysticks(); + } + static if(sdlSupport >= SDLSupport.sdl209) { + int SDL_JoystickRumble(SDL_Joystick*,ushort,ushort,uint); + } + static if(sdlSupport >= SDLSupport.sdl2010) { + int SDL_JoystickGetDevicePlayerIndex(int); + int SDL_JoystickGetPlayerIndex(SDL_Joystick*); + } + } +} +else { + extern(C) @nogc nothrow { + alias pSDL_NumJoysticks = int function(); + alias pSDL_JoystickNameForIndex = const(char)* function(int); + alias pSDL_JoystickGetDeviceGUID = SDL_JoystickGUID function(int); + alias pSDL_JoystickOpen = SDL_Joystick* function(int); + alias pSDL_JoystickName = const(char)* function(SDL_Joystick*); + alias pSDL_JoystickGetGUID = SDL_JoystickGUID function(SDL_Joystick*); + alias pSDL_JoystickGetGUIDString = char* function(SDL_JoystickGUID); + alias pSDL_JoystickGetGUIDFromString = SDL_JoystickGUID function(const(char)*); + alias pSDL_JoystickGetAttached = SDL_bool function(SDL_Joystick*); + alias pSDL_JoystickInstanceID = SDL_JoystickID function(SDL_Joystick*); + alias pSDL_JoystickNumAxes = int function(SDL_Joystick*); + alias pSDL_JoystickNumBalls = int function(SDL_Joystick*); + alias pSDL_JoystickNumHats = int function(SDL_Joystick*); + alias pSDL_JoystickNumButtons = int function(SDL_Joystick*); + alias pSDL_JoystickUpdate = void function(); + alias pSDL_JoystickEventState = int function(int); + alias pSDL_JoystickGetAxis = short function(SDL_Joystick*,int); + alias pSDL_JoystickGetHat = ubyte function(SDL_Joystick*,int); + alias pSDL_JoystickGetBall = int function(SDL_Joystick*,int,int*,int*); + alias pSDL_JoystickGetButton = ubyte function(SDL_Joystick*,int); + alias pSDL_JoystickClose = void function(SDL_Joystick*); + } + __gshared { + pSDL_NumJoysticks SDL_NumJoysticks; + pSDL_JoystickNameForIndex SDL_JoystickNameForIndex; + pSDL_JoystickGetDeviceGUID SDL_JoystickGetDeviceGUID; + pSDL_JoystickOpen SDL_JoystickOpen; + pSDL_JoystickName SDL_JoystickName; + pSDL_JoystickGetGUID SDL_JoystickGetGUID; + pSDL_JoystickGetGUIDString SDL_JoystickGetGUIDString; + pSDL_JoystickGetGUIDFromString SDL_JoystickGetGUIDFromString; + pSDL_JoystickGetAttached SDL_JoystickGetAttached; + pSDL_JoystickInstanceID SDL_JoystickInstanceID; + pSDL_JoystickNumAxes SDL_JoystickNumAxes; + pSDL_JoystickNumBalls SDL_JoystickNumBalls; + pSDL_JoystickNumHats SDL_JoystickNumHats; + pSDL_JoystickNumButtons SDL_JoystickNumButtons; + pSDL_JoystickUpdate SDL_JoystickUpdate; + pSDL_JoystickEventState SDL_JoystickEventState; + pSDL_JoystickGetAxis SDL_JoystickGetAxis; + pSDL_JoystickGetHat SDL_JoystickGetHat; + pSDL_JoystickGetBall SDL_JoystickGetBall; + pSDL_JoystickGetButton SDL_JoystickGetButton; + pSDL_JoystickClose SDL_JoystickClose; + } + static if(sdlSupport >= SDLSupport.sdl204) { + extern(C) @nogc nothrow { + alias pSDL_JoystickCurrentPowerLevel = SDL_JoystickPowerLevel function(SDL_Joystick*); + alias pSDL_JoystickFromInstanceID = SDL_Joystick* function(SDL_JoystickID); + } + __gshared { + pSDL_JoystickCurrentPowerLevel SDL_JoystickCurrentPowerLevel; + pSDL_JoystickFromInstanceID SDL_JoystickFromInstanceID; + } + } + static if(sdlSupport >= SDLSupport.sdl206) { + extern(C) @nogc nothrow { + alias pSDL_JoystickGetAxisInitialState = SDL_bool function(SDL_Joystick*,int,short*); + alias pSDL_JoystickGetDeviceInstanceID = SDL_JoystickType function(int); + alias pSDL_JoystickGetDeviceProduct = ushort function(int); + alias pSDL_JoystickGetDeviceProductVersion = ushort function(int); + alias pSDL_JoystickGetDeviceType = SDL_JoystickType function(int); + alias pSDL_JoystickGetDeviceVendor = ushort function(int); + alias pSDL_JoystickGetProduct = ushort function(SDL_Joystick*); + alias pSDL_JoystickGetProductVersion = ushort function(SDL_Joystick*); + alias pSDL_JoystickGetType = SDL_JoystickType function(SDL_Joystick*); + alias pSDL_JoystickGetVendor = ushort function(SDL_Joystick*); + } + __gshared { + pSDL_JoystickGetAxisInitialState SDL_JoystickGetAxisInitialState; + pSDL_JoystickGetDeviceInstanceID SDL_JoystickGetDeviceInstanceID; + pSDL_JoystickGetDeviceProduct SDL_JoystickGetDeviceProduct; + pSDL_JoystickGetDeviceProductVersion SDL_JoystickGetDeviceProductVersion; + pSDL_JoystickGetDeviceType SDL_JoystickGetDeviceType; + pSDL_JoystickGetDeviceVendor SDL_JoystickGetDeviceVendor; + pSDL_JoystickGetProduct SDL_JoystickGetProduct; + pSDL_JoystickGetProductVersion SDL_JoystickGetProductVersion; + pSDL_JoystickGetType SDL_JoystickGetType; + pSDL_JoystickGetVendor SDL_JoystickGetVendor; + } + } + static if(sdlSupport >= SDLSupport.sdl207) { + extern(C) @nogc nothrow { + alias pSDL_LockJoysticks = void function(); + alias pSDL_UnlockJoysticks = void function(); + } + __gshared { + pSDL_LockJoysticks SDL_LockJoysticks; + pSDL_UnlockJoysticks SDL_UnlockJoysticks; + } + } + static if(sdlSupport >= SDLSupport.sdl209) { + extern(C) @nogc nothrow { + alias pSDL_JoystickRumble = int function(SDL_Joystick*,ushort,ushort,uint); + } + __gshared { + pSDL_JoystickRumble SDL_JoystickRumble; + } + } + + static if(sdlSupport >= SDLSupport.sdl2010) { + extern(C) @nogc nothrow { + alias pSDL_JoystickGetDevicePlayerIndex = int function(int); + alias pSDL_JoystickGetPlayerIndex = int function(SDL_Joystick*); + } + __gshared { + pSDL_JoystickGetDevicePlayerIndex SDL_JoystickGetDevicePlayerIndex; + pSDL_JoystickGetPlayerIndex SDL_JoystickGetPlayerIndex; + } + } +} \ No newline at end of file diff --git a/demos/external/imports/bindbc/sdl/bind/sdlkeyboard.d b/demos/external/imports/bindbc/sdl/bind/sdlkeyboard.d new file mode 100644 index 0000000..4f4fabe --- /dev/null +++ b/demos/external/imports/bindbc/sdl/bind/sdlkeyboard.d @@ -0,0 +1,80 @@ + +// Copyright Michael D. Parker 2018. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +module bindbc.sdl.bind.sdlkeyboard; + +import bindbc.sdl.bind.sdlkeycode : SDL_Keycode, SDL_Keymod; +import bindbc.sdl.bind.sdlrect : SDL_Rect; +import bindbc.sdl.bind.sdlscancode : SDL_Scancode; +import bindbc.sdl.bind.sdlstdinc : SDL_bool; +import bindbc.sdl.bind.sdlvideo : SDL_Window; + +struct SDL_Keysym { + SDL_Scancode scancode; + SDL_Keycode sym; + ushort mod; + uint unused; +} + +version(BindSDL_Static) { + extern(C) @nogc nothrow { + SDL_Window* SDL_GetKeyboardFocus(); + ubyte* SDL_GetKeyboardState(int*); + SDL_Keymod SDL_GetModState(); + void SDL_SetModState(SDL_Keymod); + SDL_Keycode SDL_GetKeyFromScancode(SDL_Scancode); + SDL_Scancode SDL_GetScancodeFromKey(SDL_Keycode); + const(char)* SDL_GetScancodeName(SDL_Scancode); + SDL_Scancode SDL_GetScancodeFromName(const(char)*); + const(char)* SDL_GetKeyName(SDL_Keycode); + SDL_Keycode SDL_GetKeyFromName(const(char)*); + void SDL_StartTextInput(); + SDL_bool SDL_IsTextInputActive(); + void SDL_StopTextInput(); + void SDL_SetTextInputRect(SDL_Rect*); + SDL_bool SDL_HasScreenKeyboardSupport(); + SDL_bool SDL_IsScreenKeyboardShown(SDL_Window*); + } +} +else { + extern(C) @nogc nothrow { + alias pSDL_GetKeyboardFocus = SDL_Window* function(); + alias pSDL_GetKeyboardState = ubyte* function(int*); + alias pSDL_GetModState = SDL_Keymod function(); + alias pSDL_SetModState = void function(SDL_Keymod); + alias pSDL_GetKeyFromScancode = SDL_Keycode function(SDL_Scancode); + alias pSDL_GetScancodeFromKey = SDL_Scancode function(SDL_Keycode); + alias pSDL_GetScancodeName = const(char)* function(SDL_Scancode); + alias pSDL_GetScancodeFromName = SDL_Scancode function(const(char)*); + alias pSDL_GetKeyName = const(char)* function(SDL_Keycode); + alias pSDL_GetKeyFromName = SDL_Keycode function(const(char)*); + alias pSDL_StartTextInput = void function(); + alias pSDL_IsTextInputActive = SDL_bool function(); + alias pSDL_StopTextInput = void function(); + alias pSDL_SetTextInputRect = void function(SDL_Rect*); + alias pSDL_HasScreenKeyboardSupport = SDL_bool function(); + alias pSDL_IsScreenKeyboardShown = SDL_bool function(SDL_Window*); + } + + __gshared { + pSDL_GetKeyboardFocus SDL_GetKeyboardFocus; + pSDL_GetKeyboardState SDL_GetKeyboardState; + pSDL_GetModState SDL_GetModState; + pSDL_SetModState SDL_SetModState; + pSDL_GetKeyFromScancode SDL_GetKeyFromScancode; + pSDL_GetScancodeFromKey SDL_GetScancodeFromKey; + pSDL_GetScancodeName SDL_GetScancodeName; + pSDL_GetScancodeFromName SDL_GetScancodeFromName; + pSDL_GetKeyName SDL_GetKeyName; + pSDL_GetKeyFromName SDL_GetKeyFromName; + pSDL_StartTextInput SDL_StartTextInput; + pSDL_IsTextInputActive SDL_IsTextInputActive; + pSDL_StopTextInput SDL_StopTextInput; + pSDL_SetTextInputRect SDL_SetTextInputRect; + pSDL_HasScreenKeyboardSupport SDL_HasScreenKeyboardSupport; + pSDL_IsScreenKeyboardShown SDL_IsScreenKeyboardShown; + } +} diff --git a/demos/external/imports/bindbc/sdl/bind/sdlkeycode.d b/demos/external/imports/bindbc/sdl/bind/sdlkeycode.d new file mode 100644 index 0000000..127067e --- /dev/null +++ b/demos/external/imports/bindbc/sdl/bind/sdlkeycode.d @@ -0,0 +1,288 @@ + +// Copyright Michael D. Parker 2018. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +module bindbc.sdl.bind.sdlkeycode; + +import bindbc.sdl.config, + bindbc.sdl.bind.sdlscancode; + +enum SDLK_SCANCODE_MASK = 1<<30; + +enum SDL_SCANCODE_TO_KEYCODE(SDL_Scancode x) = x | SDLK_SCANCODE_MASK; + +enum SDL_Keycode { + SDLK_UNKNOWN = 0, + SDLK_RETURN = '\r', + SDLK_ESCAPE = '\033', + SDLK_BACKSPACE = '\b', + SDLK_TAB = '\t', + SDLK_SPACE = ' ', + SDLK_EXCLAIM = '!', + SDLK_QUOTEDBL = '"', + SDLK_HASH = '#', + SDLK_PERCENT = '%', + SDLK_DOLLAR = '$', + SDLK_AMPERSAND = '&', + SDLK_QUOTE = '\'', + SDLK_LEFTPAREN = '(', + SDLK_RIGHTPAREN = ')', + SDLK_ASTERISK = '*', + SDLK_PLUS = '+', + SDLK_COMMA = ',', + SDLK_MINUS = '-', + SDLK_PERIOD = '.', + SDLK_SLASH = '/', + SDLK_0 = '0', + SDLK_1 = '1', + SDLK_2 = '2', + SDLK_3 = '3', + SDLK_4 = '4', + SDLK_5 = '5', + SDLK_6 = '6', + SDLK_7 = '7', + SDLK_8 = '8', + SDLK_9 = '9', + SDLK_COLON = ':', + SDLK_SEMICOLON = ';', + SDLK_LESS = '<', + SDLK_EQUALS = '=', + SDLK_GREATER = '>', + SDLK_QUESTION = '?', + SDLK_AT = '@', + + SDLK_LEFTBRACKET = '[', + SDLK_BACKSLASH = '\\', + SDLK_RIGHTBRACKET = ']', + SDLK_CARET = '^', + SDLK_UNDERSCORE = '_', + SDLK_BACKQUOTE = '`', + SDLK_a = 'a', + SDLK_b = 'b', + SDLK_c = 'c', + SDLK_d = 'd', + SDLK_e = 'e', + SDLK_f = 'f', + SDLK_g = 'g', + SDLK_h = 'h', + SDLK_i = 'i', + SDLK_j = 'j', + SDLK_k = 'k', + SDLK_l = 'l', + SDLK_m = 'm', + SDLK_n = 'n', + SDLK_o = 'o', + SDLK_p = 'p', + SDLK_q = 'q', + SDLK_r = 'r', + SDLK_s = 's', + SDLK_t = 't', + SDLK_u = 'u', + SDLK_v = 'v', + SDLK_w = 'w', + SDLK_x = 'x', + SDLK_y = 'y', + SDLK_z = 'z', + + SDLK_CAPSLOCK = SDL_SCANCODE_TO_KEYCODE!(SDL_Scancode.SDL_SCANCODE_CAPSLOCK), + + SDLK_F1 = SDL_SCANCODE_TO_KEYCODE!(SDL_Scancode.SDL_SCANCODE_F1), + SDLK_F2 = SDL_SCANCODE_TO_KEYCODE!(SDL_Scancode.SDL_SCANCODE_F2), + SDLK_F3 = SDL_SCANCODE_TO_KEYCODE!(SDL_Scancode.SDL_SCANCODE_F3), + SDLK_F4 = SDL_SCANCODE_TO_KEYCODE!(SDL_Scancode.SDL_SCANCODE_F4), + SDLK_F5 = SDL_SCANCODE_TO_KEYCODE!(SDL_Scancode.SDL_SCANCODE_F5), + SDLK_F6 = SDL_SCANCODE_TO_KEYCODE!(SDL_Scancode.SDL_SCANCODE_F6), + SDLK_F7 = SDL_SCANCODE_TO_KEYCODE!(SDL_Scancode.SDL_SCANCODE_F7), + SDLK_F8 = SDL_SCANCODE_TO_KEYCODE!(SDL_Scancode.SDL_SCANCODE_F8), + SDLK_F9 = SDL_SCANCODE_TO_KEYCODE!(SDL_Scancode.SDL_SCANCODE_F9), + SDLK_F10 = SDL_SCANCODE_TO_KEYCODE!(SDL_Scancode.SDL_SCANCODE_F10), + SDLK_F11 = SDL_SCANCODE_TO_KEYCODE!(SDL_Scancode.SDL_SCANCODE_F11), + SDLK_F12 = SDL_SCANCODE_TO_KEYCODE!(SDL_Scancode.SDL_SCANCODE_F12), + + SDLK_PRINTSCREEN = SDL_SCANCODE_TO_KEYCODE!(SDL_Scancode.SDL_SCANCODE_PRINTSCREEN), + SDLK_SCROLLLOCK = SDL_SCANCODE_TO_KEYCODE!(SDL_Scancode.SDL_SCANCODE_SCROLLLOCK), + SDLK_PAUSE = SDL_SCANCODE_TO_KEYCODE!(SDL_Scancode.SDL_SCANCODE_PAUSE), + SDLK_INSERT = SDL_SCANCODE_TO_KEYCODE!(SDL_Scancode.SDL_SCANCODE_INSERT), + SDLK_HOME = SDL_SCANCODE_TO_KEYCODE!(SDL_Scancode.SDL_SCANCODE_HOME), + SDLK_PAGEUP = SDL_SCANCODE_TO_KEYCODE!(SDL_Scancode.SDL_SCANCODE_PAGEUP), + SDLK_DELETE = '\177', + SDLK_END = SDL_SCANCODE_TO_KEYCODE!(SDL_Scancode.SDL_SCANCODE_END), + SDLK_PAGEDOWN = SDL_SCANCODE_TO_KEYCODE!(SDL_Scancode.SDL_SCANCODE_PAGEDOWN), + SDLK_RIGHT = SDL_SCANCODE_TO_KEYCODE!(SDL_Scancode.SDL_SCANCODE_RIGHT), + SDLK_LEFT = SDL_SCANCODE_TO_KEYCODE!(SDL_Scancode.SDL_SCANCODE_LEFT), + SDLK_DOWN = SDL_SCANCODE_TO_KEYCODE!(SDL_Scancode.SDL_SCANCODE_DOWN), + SDLK_UP = SDL_SCANCODE_TO_KEYCODE!(SDL_Scancode.SDL_SCANCODE_UP), + + SDLK_NUMLOCKCLEAR = SDL_SCANCODE_TO_KEYCODE!(SDL_Scancode.SDL_SCANCODE_NUMLOCKCLEAR), + SDLK_KP_DIVIDE = SDL_SCANCODE_TO_KEYCODE!(SDL_Scancode.SDL_SCANCODE_KP_DIVIDE), + SDLK_KP_MULTIPLY = SDL_SCANCODE_TO_KEYCODE!(SDL_Scancode.SDL_SCANCODE_KP_MULTIPLY), + SDLK_KP_MINUS = SDL_SCANCODE_TO_KEYCODE!(SDL_Scancode.SDL_SCANCODE_KP_MINUS), + SDLK_KP_PLUS = SDL_SCANCODE_TO_KEYCODE!(SDL_Scancode.SDL_SCANCODE_KP_PLUS), + SDLK_KP_ENTER = SDL_SCANCODE_TO_KEYCODE!(SDL_Scancode.SDL_SCANCODE_KP_ENTER), + SDLK_KP_1 = SDL_SCANCODE_TO_KEYCODE!(SDL_Scancode.SDL_SCANCODE_KP_1), + SDLK_KP_2 = SDL_SCANCODE_TO_KEYCODE!(SDL_Scancode.SDL_SCANCODE_KP_2), + SDLK_KP_3 = SDL_SCANCODE_TO_KEYCODE!(SDL_Scancode.SDL_SCANCODE_KP_3), + SDLK_KP_4 = SDL_SCANCODE_TO_KEYCODE!(SDL_Scancode.SDL_SCANCODE_KP_4), + SDLK_KP_5 = SDL_SCANCODE_TO_KEYCODE!(SDL_Scancode.SDL_SCANCODE_KP_5), + SDLK_KP_6 = SDL_SCANCODE_TO_KEYCODE!(SDL_Scancode.SDL_SCANCODE_KP_6), + SDLK_KP_7 = SDL_SCANCODE_TO_KEYCODE!(SDL_Scancode.SDL_SCANCODE_KP_7), + SDLK_KP_8 = SDL_SCANCODE_TO_KEYCODE!(SDL_Scancode.SDL_SCANCODE_KP_8), + SDLK_KP_9 = SDL_SCANCODE_TO_KEYCODE!(SDL_Scancode.SDL_SCANCODE_KP_9), + SDLK_KP_0 = SDL_SCANCODE_TO_KEYCODE!(SDL_Scancode.SDL_SCANCODE_KP_0), + SDLK_KP_PERIOD = SDL_SCANCODE_TO_KEYCODE!(SDL_Scancode.SDL_SCANCODE_KP_PERIOD), + + SDLK_APPLICATION = SDL_SCANCODE_TO_KEYCODE!(SDL_Scancode.SDL_SCANCODE_APPLICATION), + SDLK_POWER = SDL_SCANCODE_TO_KEYCODE!(SDL_Scancode.SDL_SCANCODE_POWER), + SDLK_KP_EQUALS = SDL_SCANCODE_TO_KEYCODE!(SDL_Scancode.SDL_SCANCODE_KP_EQUALS), + SDLK_F13 = SDL_SCANCODE_TO_KEYCODE!(SDL_Scancode.SDL_SCANCODE_F13), + SDLK_F14 = SDL_SCANCODE_TO_KEYCODE!(SDL_Scancode.SDL_SCANCODE_F14), + SDLK_F15 = SDL_SCANCODE_TO_KEYCODE!(SDL_Scancode.SDL_SCANCODE_F15), + SDLK_F16 = SDL_SCANCODE_TO_KEYCODE!(SDL_Scancode.SDL_SCANCODE_F16), + SDLK_F17 = SDL_SCANCODE_TO_KEYCODE!(SDL_Scancode.SDL_SCANCODE_F17), + SDLK_F18 = SDL_SCANCODE_TO_KEYCODE!(SDL_Scancode.SDL_SCANCODE_F18), + SDLK_F19 = SDL_SCANCODE_TO_KEYCODE!(SDL_Scancode.SDL_SCANCODE_F19), + SDLK_F20 = SDL_SCANCODE_TO_KEYCODE!(SDL_Scancode.SDL_SCANCODE_F20), + SDLK_F21 = SDL_SCANCODE_TO_KEYCODE!(SDL_Scancode.SDL_SCANCODE_F21), + SDLK_F22 = SDL_SCANCODE_TO_KEYCODE!(SDL_Scancode.SDL_SCANCODE_F22), + SDLK_F23 = SDL_SCANCODE_TO_KEYCODE!(SDL_Scancode.SDL_SCANCODE_F23), + SDLK_F24 = SDL_SCANCODE_TO_KEYCODE!(SDL_Scancode.SDL_SCANCODE_F24), + SDLK_EXECUTE = SDL_SCANCODE_TO_KEYCODE!(SDL_Scancode.SDL_SCANCODE_EXECUTE), + SDLK_HELP = SDL_SCANCODE_TO_KEYCODE!(SDL_Scancode.SDL_SCANCODE_HELP), + SDLK_MENU = SDL_SCANCODE_TO_KEYCODE!(SDL_Scancode.SDL_SCANCODE_MENU), + SDLK_SELECT = SDL_SCANCODE_TO_KEYCODE!(SDL_Scancode.SDL_SCANCODE_SELECT), + SDLK_STOP = SDL_SCANCODE_TO_KEYCODE!(SDL_Scancode.SDL_SCANCODE_STOP), + SDLK_AGAIN = SDL_SCANCODE_TO_KEYCODE!(SDL_Scancode.SDL_SCANCODE_AGAIN), + SDLK_UNDO = SDL_SCANCODE_TO_KEYCODE!(SDL_Scancode.SDL_SCANCODE_UNDO), + SDLK_CUT = SDL_SCANCODE_TO_KEYCODE!(SDL_Scancode.SDL_SCANCODE_CUT), + SDLK_COPY = SDL_SCANCODE_TO_KEYCODE!(SDL_Scancode.SDL_SCANCODE_COPY), + SDLK_PASTE = SDL_SCANCODE_TO_KEYCODE!(SDL_Scancode.SDL_SCANCODE_PASTE), + SDLK_FIND = SDL_SCANCODE_TO_KEYCODE!(SDL_Scancode.SDL_SCANCODE_FIND), + SDLK_MUTE = SDL_SCANCODE_TO_KEYCODE!(SDL_Scancode.SDL_SCANCODE_MUTE), + SDLK_VOLUMEUP = SDL_SCANCODE_TO_KEYCODE!(SDL_Scancode.SDL_SCANCODE_VOLUMEUP), + SDLK_VOLUMEDOWN = SDL_SCANCODE_TO_KEYCODE!(SDL_Scancode.SDL_SCANCODE_VOLUMEDOWN), + SDLK_KP_COMMA = SDL_SCANCODE_TO_KEYCODE!(SDL_Scancode.SDL_SCANCODE_KP_COMMA), + SDLK_KP_EQUALSAS400 = SDL_SCANCODE_TO_KEYCODE!(SDL_Scancode.SDL_SCANCODE_KP_EQUALSAS400), + + SDLK_ALTERASE = SDL_SCANCODE_TO_KEYCODE!(SDL_Scancode.SDL_SCANCODE_ALTERASE), + SDLK_SYSREQ = SDL_SCANCODE_TO_KEYCODE!(SDL_Scancode.SDL_SCANCODE_SYSREQ), + SDLK_CANCEL = SDL_SCANCODE_TO_KEYCODE!(SDL_Scancode.SDL_SCANCODE_CANCEL), + SDLK_CLEAR = SDL_SCANCODE_TO_KEYCODE!(SDL_Scancode.SDL_SCANCODE_CLEAR), + SDLK_PRIOR = SDL_SCANCODE_TO_KEYCODE!(SDL_Scancode.SDL_SCANCODE_PRIOR), + SDLK_RETURN2 = SDL_SCANCODE_TO_KEYCODE!(SDL_Scancode.SDL_SCANCODE_RETURN2), + SDLK_SEPARATOR = SDL_SCANCODE_TO_KEYCODE!(SDL_Scancode.SDL_SCANCODE_SEPARATOR), + SDLK_OUT = SDL_SCANCODE_TO_KEYCODE!(SDL_Scancode.SDL_SCANCODE_OUT), + SDLK_OPER = SDL_SCANCODE_TO_KEYCODE!(SDL_Scancode.SDL_SCANCODE_OPER), + SDLK_CLEARAGAIN = SDL_SCANCODE_TO_KEYCODE!(SDL_Scancode.SDL_SCANCODE_CLEARAGAIN), + SDLK_CRSEL = SDL_SCANCODE_TO_KEYCODE!(SDL_Scancode.SDL_SCANCODE_CRSEL), + SDLK_EXSEL = SDL_SCANCODE_TO_KEYCODE!(SDL_Scancode.SDL_SCANCODE_EXSEL), + + SDLK_KP_00 = SDL_SCANCODE_TO_KEYCODE!(SDL_Scancode.SDL_SCANCODE_KP_00), + SDLK_KP_000 = SDL_SCANCODE_TO_KEYCODE!(SDL_Scancode.SDL_SCANCODE_KP_000), + SDLK_THOUSANDSSEPARATOR = SDL_SCANCODE_TO_KEYCODE!(SDL_Scancode.SDL_SCANCODE_THOUSANDSSEPARATOR), + SDLK_DECIMALSEPARATOR = SDL_SCANCODE_TO_KEYCODE!(SDL_Scancode.SDL_SCANCODE_DECIMALSEPARATOR), + SDLK_CURRENCYUNIT = SDL_SCANCODE_TO_KEYCODE!(SDL_Scancode.SDL_SCANCODE_CURRENCYUNIT), + SDLK_CURRENCYSUBUNIT = SDL_SCANCODE_TO_KEYCODE!(SDL_Scancode.SDL_SCANCODE_CURRENCYSUBUNIT), + SDLK_KP_LEFTPAREN = SDL_SCANCODE_TO_KEYCODE!(SDL_Scancode.SDL_SCANCODE_KP_LEFTPAREN), + SDLK_KP_RIGHTPAREN = SDL_SCANCODE_TO_KEYCODE!(SDL_Scancode.SDL_SCANCODE_KP_RIGHTPAREN), + SDLK_KP_LEFTBRACE = SDL_SCANCODE_TO_KEYCODE!(SDL_Scancode.SDL_SCANCODE_KP_LEFTBRACE), + SDLK_KP_RIGHTBRACE = SDL_SCANCODE_TO_KEYCODE!(SDL_Scancode.SDL_SCANCODE_KP_RIGHTBRACE), + SDLK_KP_TAB = SDL_SCANCODE_TO_KEYCODE!(SDL_Scancode.SDL_SCANCODE_KP_TAB), + SDLK_KP_BACKSPACE = SDL_SCANCODE_TO_KEYCODE!(SDL_Scancode.SDL_SCANCODE_KP_BACKSPACE), + SDLK_KP_A = SDL_SCANCODE_TO_KEYCODE!(SDL_Scancode.SDL_SCANCODE_KP_A), + SDLK_KP_B = SDL_SCANCODE_TO_KEYCODE!(SDL_Scancode.SDL_SCANCODE_KP_B), + SDLK_KP_C = SDL_SCANCODE_TO_KEYCODE!(SDL_Scancode.SDL_SCANCODE_KP_C), + SDLK_KP_D = SDL_SCANCODE_TO_KEYCODE!(SDL_Scancode.SDL_SCANCODE_KP_D), + SDLK_KP_E = SDL_SCANCODE_TO_KEYCODE!(SDL_Scancode.SDL_SCANCODE_KP_E), + SDLK_KP_F = SDL_SCANCODE_TO_KEYCODE!(SDL_Scancode.SDL_SCANCODE_KP_F), + SDLK_KP_XOR = SDL_SCANCODE_TO_KEYCODE!(SDL_Scancode.SDL_SCANCODE_KP_XOR), + SDLK_KP_POWER = SDL_SCANCODE_TO_KEYCODE!(SDL_Scancode.SDL_SCANCODE_KP_POWER), + SDLK_KP_PERCENT = SDL_SCANCODE_TO_KEYCODE!(SDL_Scancode.SDL_SCANCODE_KP_PERCENT), + SDLK_KP_LESS = SDL_SCANCODE_TO_KEYCODE!(SDL_Scancode.SDL_SCANCODE_KP_LESS), + SDLK_KP_GREATER = SDL_SCANCODE_TO_KEYCODE!(SDL_Scancode.SDL_SCANCODE_KP_GREATER), + SDLK_KP_AMPERSAND = SDL_SCANCODE_TO_KEYCODE!(SDL_Scancode.SDL_SCANCODE_KP_AMPERSAND), + SDLK_KP_DBLAMPERSAND = SDL_SCANCODE_TO_KEYCODE!(SDL_Scancode.SDL_SCANCODE_KP_DBLAMPERSAND), + SDLK_KP_VERTICALBAR = SDL_SCANCODE_TO_KEYCODE!(SDL_Scancode.SDL_SCANCODE_KP_VERTICALBAR), + SDLK_KP_DBLVERTICALBAR = SDL_SCANCODE_TO_KEYCODE!(SDL_Scancode.SDL_SCANCODE_KP_DBLVERTICALBAR), + SDLK_KP_COLON = SDL_SCANCODE_TO_KEYCODE!(SDL_Scancode.SDL_SCANCODE_KP_COLON), + SDLK_KP_HASH = SDL_SCANCODE_TO_KEYCODE!(SDL_Scancode.SDL_SCANCODE_KP_HASH), + SDLK_KP_SPACE = SDL_SCANCODE_TO_KEYCODE!(SDL_Scancode.SDL_SCANCODE_KP_SPACE), + SDLK_KP_AT = SDL_SCANCODE_TO_KEYCODE!(SDL_Scancode.SDL_SCANCODE_KP_AT), + SDLK_KP_EXCLAM = SDL_SCANCODE_TO_KEYCODE!(SDL_Scancode.SDL_SCANCODE_KP_EXCLAM), + SDLK_KP_MEMSTORE = SDL_SCANCODE_TO_KEYCODE!(SDL_Scancode.SDL_SCANCODE_KP_MEMSTORE), + SDLK_KP_MEMRECALL = SDL_SCANCODE_TO_KEYCODE!(SDL_Scancode.SDL_SCANCODE_KP_MEMRECALL), + SDLK_KP_MEMCLEAR = SDL_SCANCODE_TO_KEYCODE!(SDL_Scancode.SDL_SCANCODE_KP_MEMCLEAR), + SDLK_KP_MEMADD = SDL_SCANCODE_TO_KEYCODE!(SDL_Scancode.SDL_SCANCODE_KP_MEMADD), + SDLK_KP_MEMSUBTRACT = SDL_SCANCODE_TO_KEYCODE!(SDL_Scancode.SDL_SCANCODE_KP_MEMSUBTRACT), + SDLK_KP_MEMMULTIPLY = SDL_SCANCODE_TO_KEYCODE!(SDL_Scancode.SDL_SCANCODE_KP_MEMMULTIPLY), + SDLK_KP_MEMDIVIDE = SDL_SCANCODE_TO_KEYCODE!(SDL_Scancode.SDL_SCANCODE_KP_MEMDIVIDE), + SDLK_KP_PLUSMINUS = SDL_SCANCODE_TO_KEYCODE!(SDL_Scancode.SDL_SCANCODE_KP_PLUSMINUS), + SDLK_KP_CLEAR = SDL_SCANCODE_TO_KEYCODE!(SDL_Scancode.SDL_SCANCODE_KP_CLEAR), + SDLK_KP_CLEARENTRY = SDL_SCANCODE_TO_KEYCODE!(SDL_Scancode.SDL_SCANCODE_KP_CLEARENTRY), + SDLK_KP_BINARY = SDL_SCANCODE_TO_KEYCODE!(SDL_Scancode.SDL_SCANCODE_KP_BINARY), + SDLK_KP_OCTAL = SDL_SCANCODE_TO_KEYCODE!(SDL_Scancode.SDL_SCANCODE_KP_OCTAL), + SDLK_KP_DECIMAL = SDL_SCANCODE_TO_KEYCODE!(SDL_Scancode.SDL_SCANCODE_KP_DECIMAL), + SDLK_KP_HEXADECIMAL = SDL_SCANCODE_TO_KEYCODE!(SDL_Scancode.SDL_SCANCODE_KP_HEXADECIMAL), + + SDLK_LCTRL = SDL_SCANCODE_TO_KEYCODE!(SDL_Scancode.SDL_SCANCODE_LCTRL), + SDLK_LSHIFT = SDL_SCANCODE_TO_KEYCODE!(SDL_Scancode.SDL_SCANCODE_LSHIFT), + SDLK_LALT = SDL_SCANCODE_TO_KEYCODE!(SDL_Scancode.SDL_SCANCODE_LALT), + SDLK_LGUI = SDL_SCANCODE_TO_KEYCODE!(SDL_Scancode.SDL_SCANCODE_LGUI), + SDLK_RCTRL = SDL_SCANCODE_TO_KEYCODE!(SDL_Scancode.SDL_SCANCODE_RCTRL), + SDLK_RSHIFT = SDL_SCANCODE_TO_KEYCODE!(SDL_Scancode.SDL_SCANCODE_RSHIFT), + SDLK_RALT = SDL_SCANCODE_TO_KEYCODE!(SDL_Scancode.SDL_SCANCODE_RALT), + SDLK_RGUI = SDL_SCANCODE_TO_KEYCODE!(SDL_Scancode.SDL_SCANCODE_RGUI), + + SDLK_MODE = SDL_SCANCODE_TO_KEYCODE!(SDL_Scancode.SDL_SCANCODE_MODE), + + SDLK_AUDIONEXT = SDL_SCANCODE_TO_KEYCODE!(SDL_Scancode.SDL_SCANCODE_AUDIONEXT), + SDLK_AUDIOPREV = SDL_SCANCODE_TO_KEYCODE!(SDL_Scancode.SDL_SCANCODE_AUDIOPREV), + SDLK_AUDIOSTOP = SDL_SCANCODE_TO_KEYCODE!(SDL_Scancode.SDL_SCANCODE_AUDIOSTOP), + SDLK_AUDIOPLAY = SDL_SCANCODE_TO_KEYCODE!(SDL_Scancode.SDL_SCANCODE_AUDIOPLAY), + SDLK_AUDIOMUTE = SDL_SCANCODE_TO_KEYCODE!(SDL_Scancode.SDL_SCANCODE_AUDIOMUTE), + SDLK_MEDIASELECT = SDL_SCANCODE_TO_KEYCODE!(SDL_Scancode.SDL_SCANCODE_MEDIASELECT), + SDLK_WWW = SDL_SCANCODE_TO_KEYCODE!(SDL_Scancode.SDL_SCANCODE_WWW), + SDLK_MAIL = SDL_SCANCODE_TO_KEYCODE!(SDL_Scancode.SDL_SCANCODE_MAIL), + SDLK_CALCULATOR = SDL_SCANCODE_TO_KEYCODE!(SDL_Scancode.SDL_SCANCODE_CALCULATOR), + SDLK_COMPUTER = SDL_SCANCODE_TO_KEYCODE!(SDL_Scancode.SDL_SCANCODE_COMPUTER), + SDLK_AC_SEARCH = SDL_SCANCODE_TO_KEYCODE!(SDL_Scancode.SDL_SCANCODE_AC_SEARCH), + SDLK_AC_HOME = SDL_SCANCODE_TO_KEYCODE!(SDL_Scancode.SDL_SCANCODE_AC_HOME), + SDLK_AC_BACK = SDL_SCANCODE_TO_KEYCODE!(SDL_Scancode.SDL_SCANCODE_AC_BACK), + SDLK_AC_FORWARD = SDL_SCANCODE_TO_KEYCODE!(SDL_Scancode.SDL_SCANCODE_AC_FORWARD), + SDLK_AC_STOP = SDL_SCANCODE_TO_KEYCODE!(SDL_Scancode.SDL_SCANCODE_AC_STOP), + SDLK_AC_REFRESH = SDL_SCANCODE_TO_KEYCODE!(SDL_Scancode.SDL_SCANCODE_AC_REFRESH), + SDLK_AC_BOOKMARKS = SDL_SCANCODE_TO_KEYCODE!(SDL_Scancode.SDL_SCANCODE_AC_BOOKMARKS), + + SDLK_BRIGHTNESSDOWN = SDL_SCANCODE_TO_KEYCODE!(SDL_Scancode.SDL_SCANCODE_BRIGHTNESSDOWN), + SDLK_BRIGHTNESSUP = SDL_SCANCODE_TO_KEYCODE!(SDL_Scancode.SDL_SCANCODE_BRIGHTNESSUP), + SDLK_DISPLAYSWITCH = SDL_SCANCODE_TO_KEYCODE!(SDL_Scancode.SDL_SCANCODE_DISPLAYSWITCH), + SDLK_KBDILLUMTOGGLE = SDL_SCANCODE_TO_KEYCODE!(SDL_Scancode.SDL_SCANCODE_KBDILLUMTOGGLE), + SDLK_KBDILLUMDOWN = SDL_SCANCODE_TO_KEYCODE!(SDL_Scancode.SDL_SCANCODE_KBDILLUMDOWN), + SDLK_KBDILLUMUP = SDL_SCANCODE_TO_KEYCODE!(SDL_Scancode.SDL_SCANCODE_KBDILLUMUP), + SDLK_EJECT = SDL_SCANCODE_TO_KEYCODE!(SDL_Scancode.SDL_SCANCODE_EJECT), + SDLK_SLEEP = SDL_SCANCODE_TO_KEYCODE!(SDL_Scancode.SDL_SCANCODE_SLEEP), +} +mixin(expandEnum!SDL_Keycode); + +enum SDL_Keymod { + KMOD_NONE = 0x0000, + KMOD_LSHIFT = 0x0001, + KMOD_RSHIFT = 0x0002, + KMOD_LCTRL = 0x0040, + KMOD_RCTRL = 0x0080, + KMOD_LALT = 0x0100, + KMOD_RALT = 0x0200, + KMOD_LGUI = 0x0400, + KMOD_RGUI = 0x0800, + KMOD_NUM = 0x1000, + KMOD_CAPS = 0x2000, + KMOD_MODE = 0x4000, + KMOD_RESERVED = 0x8000, + + KMOD_CTRL = (KMOD_LCTRL|KMOD_RCTRL), + KMOD_SHIFT = (KMOD_LSHIFT|KMOD_RSHIFT), + KMOD_ALT = (KMOD_LALT|KMOD_RALT), + KMOD_GUI = (KMOD_LGUI|KMOD_RGUI), +} +mixin(expandEnum!SDL_Keymod); \ No newline at end of file diff --git a/demos/external/imports/bindbc/sdl/bind/sdlloadso.d b/demos/external/imports/bindbc/sdl/bind/sdlloadso.d new file mode 100644 index 0000000..02f9b62 --- /dev/null +++ b/demos/external/imports/bindbc/sdl/bind/sdlloadso.d @@ -0,0 +1,28 @@ + +// Copyright Michael D. Parker 2018. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +module bindbc.sdl.bind.sdlloadso; + +version(BindSDL_Static){ + extern(C) @nogc nothrow { + void* SDL_LoadObject(const(char)*); + void* SDL_LoadFunction(void*,const(char*)); + void SDL_UnloadObject(void*); + } +} +else { + extern(C) @nogc nothrow { + alias pSDL_LoadObject = void* function(const(char)*); + alias pSDL_LoadFunction = void* function(void*,const(char*)); + alias pSDL_UnloadObject = void function(void*); + } + + __gshared { + pSDL_LoadObject SDL_LoadObject; + pSDL_LoadFunction SDL_LoadFunction; + pSDL_UnloadObject SDL_UnloadObject; + } +} \ No newline at end of file diff --git a/demos/external/imports/bindbc/sdl/bind/sdllog.d b/demos/external/imports/bindbc/sdl/bind/sdllog.d new file mode 100644 index 0000000..3ff5b4c --- /dev/null +++ b/demos/external/imports/bindbc/sdl/bind/sdllog.d @@ -0,0 +1,107 @@ + +// Copyright Michael D. Parker 2018. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +module bindbc.sdl.bind.sdllog; + +import core.stdc.stdarg : va_list; +import bindbc.sdl.config; + +enum SDL_MAX_LOG_MESSAGE = 4096; + +enum { + SDL_LOG_CATEGORY_APPLICATION, + SDL_LOG_CATEGORY_ERROR, + SDL_LOG_CATEGORY_ASSERT, + SDL_LOG_CATEGORY_SYSTEM, + SDL_LOG_CATEGORY_AUDIO, + SDL_LOG_CATEGORY_VIDEO, + SDL_LOG_CATEGORY_RENDER, + SDL_LOG_CATEGORY_INPUT, + SDL_LOG_CATEGORY_TEST, + + SDL_LOG_CATEGORY_RESERVED1, + SDL_LOG_CATEGORY_RESERVED2, + SDL_LOG_CATEGORY_RESERVED3, + SDL_LOG_CATEGORY_RESERVED4, + SDL_LOG_CATEGORY_RESERVED5, + SDL_LOG_CATEGORY_RESERVED6, + SDL_LOG_CATEGORY_RESERVED7, + SDL_LOG_CATEGORY_RESERVED8, + SDL_LOG_CATEGORY_RESERVED9, + SDL_LOG_CATEGORY_RESERVED10, + + SDL_LOG_CATEGORY_CUSTOM +} + +enum SDL_LogPriority { + SDL_LOG_PRIORITY_VERBOSE = 1, + SDL_LOG_PRIORITY_DEBUG, + SDL_LOG_PRIORITY_INFO, + SDL_LOG_PRIORITY_WARN, + SDL_LOG_PRIORITY_ERROR, + SDL_LOG_PRIORITY_CRITICAL, + SDL_NUM_LOG_PRIORITIES +} +mixin(expandEnum!SDL_LogPriority); + +extern(C) nothrow alias SDL_LogOutputFunction = void function(void*, int, SDL_LogPriority, const(char)*); + +version(BindSDL_Static) { + extern(C) @nogc nothrow { + void SDL_LogSetAllPriority(SDL_LogPriority); + void SDL_LogSetPriority(int,SDL_LogPriority); + SDL_LogPriority SDL_LogGetPriority(int); + void SDL_LogResetPriorities(); + void SDL_Log(const(char)*,...); + void SDL_LogVerbose(int,const(char)*,...); + void SDL_LogDebug(int,const(char)*,...); + void SDL_LogInfo(int,const(char)*,...); + void SDL_LogWarn(int,const(char)*,...); + void SDL_LogError(int,const(char)*,...); + void SDL_LogCritical(int,const(char)*,...); + void SDL_LogMessage(int,SDL_LogPriority,const(char)*,...); + void SDL_LogMessageV(int,SDL_LogPriority,const(char)*,va_list); + void SDL_LogGetOutputFunction(SDL_LogOutputFunction,void**); + void SDL_LogSetOutputFunction(SDL_LogOutputFunction,void*); + } +} +else { + extern(C) @nogc nothrow { + alias pSDL_LogSetAllPriority = void function(SDL_LogPriority); + alias pSDL_LogSetPriority = void function(int,SDL_LogPriority); + alias pSDL_LogGetPriority = SDL_LogPriority function(int); + alias pSDL_LogResetPriorities = void function(); + alias pSDL_Log = void function(const(char)*,...); + alias pSDL_LogVerbose = void function(int,const(char)*,...); + alias pSDL_LogDebug = void function(int,const(char)*,...); + alias pSDL_LogInfo = void function(int,const(char)*,...); + alias pSDL_LogWarn = void function(int,const(char)*,...); + alias pSDL_LogError = void function(int,const(char)*,...); + alias pSDL_LogCritical = void function(int,const(char)*,...); + alias pSDL_LogMessage = void function(int,SDL_LogPriority,const(char)*,...); + alias pSDL_LogMessageV = void function(int,SDL_LogPriority,const(char)*,va_list); + alias pSDL_LogGetOutputFunction = void function(SDL_LogOutputFunction,void**); + alias pSDL_LogSetOutputFunction = void function(SDL_LogOutputFunction,void*); + } + + __gshared { + pSDL_LogSetAllPriority SDL_LogSetAllPriority; + pSDL_LogSetPriority SDL_LogSetPriority; + pSDL_LogGetPriority SDL_LogGetPriority; + pSDL_LogResetPriorities SDL_LogResetPriorities; + pSDL_Log SDL_Log; + pSDL_LogVerbose SDL_LogVerbose; + pSDL_LogDebug SDL_LogDebug; + pSDL_LogInfo SDL_LogInfo; + pSDL_LogWarn SDL_LogWarn; + pSDL_LogError SDL_LogError; + pSDL_LogCritical SDL_LogCritical; + pSDL_LogMessage SDL_LogMessage; + pSDL_LogMessageV SDL_LogMessageV; + pSDL_LogGetOutputFunction SDL_LogGetOutputFunction; + pSDL_LogSetOutputFunction SDL_LogSetOutputFunction; + } +} \ No newline at end of file diff --git a/demos/external/imports/bindbc/sdl/bind/sdlmessagebox.d b/demos/external/imports/bindbc/sdl/bind/sdlmessagebox.d new file mode 100644 index 0000000..89636f5 --- /dev/null +++ b/demos/external/imports/bindbc/sdl/bind/sdlmessagebox.d @@ -0,0 +1,75 @@ + +// Copyright Michael D. Parker 2018. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +module bindbc.sdl.bind.sdlmessagebox; + +import bindbc.sdl.config; +import bindbc.sdl.bind.sdlvideo : SDL_Window; + +enum SDL_MessageBoxFlags { + SDL_MESSAGEBOX_ERROR = 0x00000010, + SDL_MESSAGEBOX_WARNING = 0x00000020, + SDL_MESSAGEBOX_INFORMATION = 0x00000040, +} +mixin(expandEnum!SDL_MessageBoxFlags); + +enum SDL_MessageBoxButtonFlags { + SDL_MESSAGEBOX_BUTTON_RETURNKEY_DEFAULT = 0x00000001, + SDL_MESSAGEBOX_BUTTON_ESCAPEKEY_DEFAULT = 0x00000002, +} +mixin(expandEnum!SDL_MessageBoxButtonFlags); + +struct SDL_MessageBoxButtonData { + uint flags; + int buttonid; + const(char)* text; +} + +struct SDL_MessageBoxColor { + ubyte r, g, b; +} + +enum SDL_MessageBoxColorType { + SDL_MESSAGEBOX_COLOR_BACKGROUND, + SDL_MESSAGEBOX_COLOR_TEXT, + SDL_MESSAGEBOX_COLOR_BUTTON_BORDER, + SDL_MESSAGEBOX_COLOR_BUTTON_BACKGROUND, + SDL_MESSAGEBOX_COLOR_BUTTON_SELECTED, + SDL_MESSAGEBOX_COLOR_MAX, +} +mixin(expandEnum!SDL_MessageBoxColorType); + +struct SDL_MessageBoxColorScheme { + SDL_MessageBoxColor[SDL_MESSAGEBOX_COLOR_MAX] colors; +} + +struct SDL_MessageBoxData { + uint flags; + SDL_Window* window; + const(char)* title; + const(char)* message; + int numbuttons; + const(SDL_MessageBoxButtonData)* buttons; + const(SDL_MessageBoxColorScheme)* colorScheme; +} + +version(BindSDL_Static) { + extern(C) @nogc nothrow { + int SDL_ShowMessageBox(const(SDL_MessageBoxData)*,int*); + int SDL_ShowSimpleMessageBox(uint,const(char)*,const(char)*,SDL_Window*); + } +} +else { + extern(C) @nogc nothrow { + alias pSDL_ShowMessageBox = int function(const(SDL_MessageBoxData)*,int*); + alias pSDL_ShowSimpleMessageBox = int function(uint,const(char)*,const(char)*,SDL_Window*); + } + + __gshared { + pSDL_ShowMessageBox SDL_ShowMessageBox; + pSDL_ShowSimpleMessageBox SDL_ShowSimpleMessageBox; + } +} \ No newline at end of file diff --git a/demos/external/imports/bindbc/sdl/bind/sdlmouse.d b/demos/external/imports/bindbc/sdl/bind/sdlmouse.d new file mode 100644 index 0000000..f9fc492 --- /dev/null +++ b/demos/external/imports/bindbc/sdl/bind/sdlmouse.d @@ -0,0 +1,140 @@ + +// Copyright Michael D. Parker 2018. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +module bindbc.sdl.bind.sdlmouse; + +import bindbc.sdl.config; +import bindbc.sdl.bind.sdlstdinc : SDL_bool; +import bindbc.sdl.bind.sdlsurface : SDL_Surface; +import bindbc.sdl.bind.sdlvideo : SDL_Window; + +struct SDL_Cursor; + +enum SDL_SystemCursor { + SDL_SYSTEM_CURSOR_ARROW, + SDL_SYSTEM_CURSOR_IBEAM, + SDL_SYSTEM_CURSOR_WAIT, + SDL_SYSTEM_CURSOR_CROSSHAIR, + SDL_SYSTEM_CURSOR_WAITARROW, + SDL_SYSTEM_CURSOR_SIZENWSE, + SDL_SYSTEM_CURSOR_SIZENESW, + SDL_SYSTEM_CURSOR_SIZEWE, + SDL_SYSTEM_CURSOR_SIZENS, + SDL_SYSTEM_CURSOR_SIZEALL, + SDL_SYSTEM_CURSOR_NO, + SDL_SYSTEM_CURSOR_HAND, + SDL_NUM_SYSTEM_CURSORS +} + +alias SDL_SYSTEM_CURSOR_ARROW = SDL_SystemCursor.SDL_SYSTEM_CURSOR_ARROW; +alias SDL_SYSTEM_CURSOR_IBEAM = SDL_SystemCursor.SDL_SYSTEM_CURSOR_IBEAM; +alias SDL_SYSTEM_CURSOR_WAIT = SDL_SystemCursor.SDL_SYSTEM_CURSOR_WAIT; +alias SDL_SYSTEM_CURSOR_CROSSHAIR = SDL_SystemCursor.SDL_SYSTEM_CURSOR_CROSSHAIR; +alias SDL_SYSTEM_CURSOR_WAITARROW = SDL_SystemCursor.SDL_SYSTEM_CURSOR_WAITARROW; +alias SDL_SYSTEM_CURSOR_SIZENWSE = SDL_SystemCursor.SDL_SYSTEM_CURSOR_SIZENWSE; +alias SDL_SYSTEM_CURSOR_SIZENESW = SDL_SystemCursor.SDL_SYSTEM_CURSOR_SIZENESW; +alias SDL_SYSTEM_CURSOR_SIZEWE = SDL_SystemCursor.SDL_SYSTEM_CURSOR_SIZEWE; +alias SDL_SYSTEM_CURSOR_SIZENS = SDL_SystemCursor.SDL_SYSTEM_CURSOR_SIZENS; +alias SDL_SYSTEM_CURSOR_SIZEALL = SDL_SystemCursor.SDL_SYSTEM_CURSOR_SIZEALL; +alias SDL_SYSTEM_CURSOR_NO = SDL_SystemCursor.SDL_SYSTEM_CURSOR_NO; +alias SDL_SYSTEM_CURSOR_HAND = SDL_SystemCursor.SDL_SYSTEM_CURSOR_HAND; +alias SDL_NUM_SYSTEM_CURSORS = SDL_SystemCursor.SDL_NUM_SYSTEM_CURSORS; + +enum SDL_BUTTON(ubyte x) = 1 << (x-1); + +enum : ubyte { + SDL_BUTTON_LEFT = 1, + SDL_BUTTON_MIDDLE = 2, + SDL_BUTTON_RIGHT = 3, + SDL_BUTTON_X1 = 4, + SDL_BUTTON_X2 = 5, + SDL_BUTTON_LMASK = SDL_BUTTON!(SDL_BUTTON_LEFT), + SDL_BUTTON_MMASK = SDL_BUTTON!(SDL_BUTTON_MIDDLE), + SDL_BUTTON_RMASK = SDL_BUTTON!(SDL_BUTTON_RIGHT), + SDL_BUTTON_X1MASK = SDL_BUTTON!(SDL_BUTTON_X1), + SDL_BUTTON_X2MASK = SDL_BUTTON!(SDL_BUTTON_X2), +} + +static if(sdlSupport >= SDLSupport.sdl204) { + enum SDL_MouseWheelDirection { + SDL_MOUSEWHEEL_NORMAL, + SDL_MOUSEWHEEL_FLIPPED, + } +} + +version(BindSDL_Static) { + extern(C) @nogc nothrow { + SDL_Window* SDL_GetMouseFocus(); + uint SDL_GetMouseState(int*,int*); + uint SDL_GetRelativeMouseState(int*,int*); + void SDL_WarpMouseInWindow(SDL_Window*,int,int); + int SDL_SetRelativeMouseMode(SDL_bool); + SDL_bool SDL_GetRelativeMouseMode(); + SDL_Cursor* SDL_CreateCursor(const(ubyte)*,const(ubyte)*,int,int,int,int); + SDL_Cursor* SDL_CreateColorCursor(SDL_Surface*,int,int); + SDL_Cursor* SDL_CreateSystemCursor(SDL_SystemCursor); + void SDL_SetCursor(SDL_Cursor*); + SDL_Cursor* SDL_GetCursor(); + SDL_Cursor* SDL_GetDefaultCursor(); + void SDL_FreeCursor(SDL_Cursor*); + int SDL_ShowCursor(int); + + static if(sdlSupport >= SDLSupport.sdl204) { + int SDL_CaptureMouse(SDL_bool); + uint SDL_GetGlobalMouseState(int*,int*); + void SDL_WarpMouseGlobal(int,int); + } + } +} +else { + extern(C) @nogc nothrow { + alias pSDL_GetMouseFocus = SDL_Window* function(); + alias pSDL_GetMouseState = uint function(int*,int*); + alias pSDL_GetRelativeMouseState = uint function(int*,int*); + alias pSDL_WarpMouseInWindow = void function(SDL_Window*,int,int); + alias pSDL_SetRelativeMouseMode = int function(SDL_bool); + alias pSDL_GetRelativeMouseMode = SDL_bool function(); + alias pSDL_CreateCursor = SDL_Cursor* function(const(ubyte)*,const(ubyte)*,int,int,int,int); + alias pSDL_CreateColorCursor = SDL_Cursor* function(SDL_Surface*,int,int); + alias pSDL_CreateSystemCursor = SDL_Cursor* function(SDL_SystemCursor); + alias pSDL_SetCursor = void function(SDL_Cursor*); + alias pSDL_GetCursor = SDL_Cursor* function(); + alias pSDL_GetDefaultCursor = SDL_Cursor* function(); + alias pSDL_FreeCursor = void function(SDL_Cursor*); + alias pSDL_ShowCursor = int function(int); + } + + __gshared { + pSDL_GetMouseFocus SDL_GetMouseFocus; + pSDL_GetMouseState SDL_GetMouseState; + pSDL_GetRelativeMouseState SDL_GetRelativeMouseState; + pSDL_WarpMouseInWindow SDL_WarpMouseInWindow; + pSDL_SetRelativeMouseMode SDL_SetRelativeMouseMode; + pSDL_GetRelativeMouseMode SDL_GetRelativeMouseMode; + pSDL_CreateCursor SDL_CreateCursor; + pSDL_CreateColorCursor SDL_CreateColorCursor; + pSDL_CreateSystemCursor SDL_CreateSystemCursor; + pSDL_SetCursor SDL_SetCursor; + pSDL_GetCursor SDL_GetCursor; + pSDL_GetDefaultCursor SDL_GetDefaultCursor; + pSDL_FreeCursor SDL_FreeCursor; + pSDL_ShowCursor SDL_ShowCursor; + } + + static if(sdlSupport >= SDLSupport.sdl204) { + extern(C) @nogc nothrow { + alias pSDL_CaptureMouse = int function(SDL_bool); + alias pSDL_GetGlobalMouseState = uint function(int*,int*); + alias pSDL_WarpMouseGlobal = void function(int,int); + } + + __gshared { + pSDL_CaptureMouse SDL_CaptureMouse; + pSDL_GetGlobalMouseState SDL_GetGlobalMouseState; + pSDL_WarpMouseGlobal SDL_WarpMouseGlobal; + } + } +} diff --git a/demos/external/imports/bindbc/sdl/bind/sdlpixels.d b/demos/external/imports/bindbc/sdl/bind/sdlpixels.d new file mode 100644 index 0000000..7d65753 --- /dev/null +++ b/demos/external/imports/bindbc/sdl/bind/sdlpixels.d @@ -0,0 +1,283 @@ + +// Copyright Michael D. Parker 2018. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +module bindbc.sdl.bind.sdlpixels; + +import bindbc.sdl.config; +import bindbc.sdl.bind.sdlstdinc : SDL_FOURCC, SDL_bool; + +enum SDL_ALPHA_OPAQUE = 255; +enum SDL_ALPHA_TRANSPARENT = 0; + +enum { + SDL_PIXELTYPE_UNKNOWN, + SDL_PIXELTYPE_INDEX1, + SDL_PIXELTYPE_INDEX4, + SDL_PIXELTYPE_INDEX8, + SDL_PIXELTYPE_PACKED8, + SDL_PIXELTYPE_PACKED16, + SDL_PIXELTYPE_PACKED32, + SDL_PIXELTYPE_ARRAYU8, + SDL_PIXELTYPE_ARRAYU16, + SDL_PIXELTYPE_ARRAYU32, + SDL_PIXELTYPE_ARRAYF16, + SDL_PIXELTYPE_ARRAYF32 +} + +enum { + SDL_BITMAPORDER_NONE, + SDL_BITMAPORDER_4321, + SDL_BITMAPORDER_1234 +} + +enum { + SDL_PACKEDORDER_NONE, + SDL_PACKEDORDER_XRGB, + SDL_PACKEDORDER_RGBX, + SDL_PACKEDORDER_ARGB, + SDL_PACKEDORDER_RGBA, + SDL_PACKEDORDER_XBGR, + SDL_PACKEDORDER_BGRX, + SDL_PACKEDORDER_ABGR, + SDL_PACKEDORDER_BGRA +} + +enum { + SDL_ARRAYORDER_NONE, + SDL_ARRAYORDER_RGB, + SDL_ARRAYORDER_RGBA, + SDL_ARRAYORDER_ARGB, + SDL_ARRAYORDER_BGR, + SDL_ARRAYORDER_BGRA, + SDL_ARRAYORDER_ABGR +} + +enum { + SDL_PACKEDLAYOUT_NONE, + SDL_PACKEDLAYOUT_332, + SDL_PACKEDLAYOUT_4444, + SDL_PACKEDLAYOUT_1555, + SDL_PACKEDLAYOUT_5551, + SDL_PACKEDLAYOUT_565, + SDL_PACKEDLAYOUT_8888, + SDL_PACKEDLAYOUT_2101010, + SDL_PACKEDLAYOUT_1010102 +} + +alias SDL_DEFINE_PIXELFOURCC = SDL_FOURCC; + +enum uint SDL_DEFINE_PIXELFORMAT(int type, int order, int layout, int bits, int bytes) = + (1 << 28) | (type << 24) | (order << 20) | (layout << 16) | (bits << 8) | (bytes << 0); + +enum uint SDL_PIXELFLAG(uint x) = (x >> 28) & 0x0F; +enum uint SDL_PIXELTYPE(uint x) = (x >> 24) & 0x0F; +enum uint SDL_PIXELORDER(uint x) = (x >> 20) & 0x0F; +enum uint SDL_PIXELLAYOUT(uint x) = (x >> 16) & 0x0F; +enum uint SDL_BITSPERPIXEL(uint x) = (x >> 8) & 0xFF; + +template SDL_BYTESPERPIXEL(uint x) { + static if(SDL_ISPIXELFORMAT_FOURCC!x) { + static if(x == SDL_PIXELFORMAT_YUY2 || x == SDL_PIXELFORMAT_UYVY || x == SDL_PIXELFORMAT_YVYU) + enum SDL_BYTESPERPIXEL = 2; + else enum SDL_BYTESPERPIXEL = 1; + } + else enum SDL_BYTESPERPIXEL = (x >> 0) & 0xFF; +} + +template SDL_ISPIXELFORMAT_INDEXED(uint format) { + static if(SDL_ISPIXELFORMAT_FOURCC!format) { + enum SDL_ISPIXELFORMAT_INDEXED = SDL_PIXELTYPE!format == SDL_PIXELTYPE_INDEX1 || SDL_PIXELTYPE!format == SDL_PIXELTYPE_INDEX4 || + SDL_PIXELTYPE!format == SDL_PIXELTYPE_INDEX8; + } + else enum SDL_ISPIXELFORMAT_INDEXED = false; +} + +template SDL_ISPIXELFORMAT_PACKED(uint format) { + static if(SDL_ISPIXELFORMAT_FOURCC!format) { + enum SDL_ISPIXELFORMAT_PACKED = SDL_PIXELTYPE!format == SDL_PIXELTYPE_PACKED8 || SDL_PIXELTYPE!format == SDL_PIXELTYPE_PACKED16 || + SDL_PIXELTYPE!format == SDL_PIXELTYPE_PACKED32; + } + else enum SDL_ISPIXELFORMAT_PACKED = false; +} + +static if(sdlSupport >= SDLSupport.sdl204) { + template SDL_ISPIXELFORMAT_ARRAY(uint format) { + static if(SDL_ISPIXELFORMAT_FOURCC!format) { + enum SDL_ISPIXELFORMAT_ARRAY = SDL_PIXELTYPE!format == SDL_PIXELTYPE_ARRAYU8 || SDL_PIXELTYPE!format == SDL_PIXELTYPE_ARRAYU16 || + SDL_PIXELTYPE!format == SDL_PIXELTYPE_ARRAYU32 || SDL_PIXELTYPE!format == SDL_PIXELTYPE_ARRAYF16 || + SDL_PIXELTYPE!format == SDL_PIXELTYPE_ARRAYF32; + } + else enum SDL_ISPIXELFORMAT_ARRAY = false; + } +} + +template SDL_ISPIXELFORMAT_ALPHA(uint format) { + static if(SDL_ISPIXELFORMAT_PACKED!format) { + enum SDL_ISPIXELFORMAT_ALPHA = (SDL_PIXELORDER!format == SDL_PACKEDORDER_ARGB || SDL_PIXELORDER!format == SDL_PACKEDORDER_RGBA || + SDL_PIXELORDER!format == SDL_PACKEDORDER_ABGR || SDL_PIXELORDER!format == SDL_PACKEDORDER_BGRA); + } + else static if(sdlSupport >= SDLSupport.sdl204 && SDL_ISPIXELFORMAT_ARRAY!format) { + enum SDL_ISPIXELFORMAT_ALPHA = (SDL_PIXELORDER!format == SDL_ARRAYORDER_ARGB || SDL_PIXELORDER!format == SDL_ARRAYORDER_RGBA || + SDL_PIXELORDER!format == SDL_ARRAYORDER_ABGR || SDL_PIXELORDER!format == SDL_ARRAYORDER_BGRA); + } + else enum SDL_ISPIXELFORMAT_ALPHA = false; +} + +enum SDL_ISPIXELFORMAT_FOURCC(uint format) = format && !(format & 0x80000000); + +enum SDL_PIXELFORMAT_UNKNOWN = 0; +enum SDL_PIXELFORMAT_INDEX1LSB = SDL_DEFINE_PIXELFORMAT!(SDL_PIXELTYPE_INDEX1, SDL_BITMAPORDER_4321, 0, 1, 0); +enum SDL_PIXELFORMAT_INDEX1MSB = SDL_DEFINE_PIXELFORMAT!(SDL_PIXELTYPE_INDEX1, SDL_BITMAPORDER_1234, 0, 1, 0); +enum SDL_PIXELFORMAT_INDEX4LSB = SDL_DEFINE_PIXELFORMAT!(SDL_PIXELTYPE_INDEX4, SDL_BITMAPORDER_4321, 0, 4, 0); +enum SDL_PIXELFORMAT_INDEX4MSB = SDL_DEFINE_PIXELFORMAT!(SDL_PIXELTYPE_INDEX4, SDL_BITMAPORDER_1234, 0, 4, 0); +enum SDL_PIXELFORMAT_INDEX8 = SDL_DEFINE_PIXELFORMAT!(SDL_PIXELTYPE_INDEX8, 0, 0, 8, 1); +enum SDL_PIXELFORMAT_RGB332 = SDL_DEFINE_PIXELFORMAT!(SDL_PIXELTYPE_PACKED8, SDL_PACKEDORDER_XRGB, SDL_PACKEDLAYOUT_332, 8, 1); +enum SDL_PIXELFORMAT_RGB444 = SDL_DEFINE_PIXELFORMAT!(SDL_PIXELTYPE_PACKED16, SDL_PACKEDORDER_XRGB, SDL_PACKEDLAYOUT_4444, 12, 2); +enum SDL_PIXELFORMAT_RGB555 = SDL_DEFINE_PIXELFORMAT!(SDL_PIXELTYPE_PACKED16, SDL_PACKEDORDER_XRGB, SDL_PACKEDLAYOUT_1555, 15, 2); +enum SDL_PIXELFORMAT_BGR555 = SDL_DEFINE_PIXELFORMAT!(SDL_PIXELTYPE_PACKED16, SDL_PACKEDORDER_XBGR, SDL_PACKEDLAYOUT_1555, 15, 2); +enum SDL_PIXELFORMAT_ARGB4444 = SDL_DEFINE_PIXELFORMAT!(SDL_PIXELTYPE_PACKED16, SDL_PACKEDORDER_ARGB, SDL_PACKEDLAYOUT_4444, 16, 2); +enum SDL_PIXELFORMAT_RGBA4444 = SDL_DEFINE_PIXELFORMAT!(SDL_PIXELTYPE_PACKED16, SDL_PACKEDORDER_RGBA, SDL_PACKEDLAYOUT_4444, 16, 2); +enum SDL_PIXELFORMAT_ABGR4444 = SDL_DEFINE_PIXELFORMAT!(SDL_PIXELTYPE_PACKED16, SDL_PACKEDORDER_ABGR, SDL_PACKEDLAYOUT_4444, 16, 2); +enum SDL_PIXELFORMAT_BGRA4444 = SDL_DEFINE_PIXELFORMAT!(SDL_PIXELTYPE_PACKED16, SDL_PACKEDORDER_BGRA, SDL_PACKEDLAYOUT_4444, 16, 2); +enum SDL_PIXELFORMAT_ARGB1555 = SDL_DEFINE_PIXELFORMAT!(SDL_PIXELTYPE_PACKED16, SDL_PACKEDORDER_ARGB, SDL_PACKEDLAYOUT_1555, 16, 2); +enum SDL_PIXELFORMAT_RGBA5551 = SDL_DEFINE_PIXELFORMAT!(SDL_PIXELTYPE_PACKED16, SDL_PACKEDORDER_RGBA, SDL_PACKEDLAYOUT_5551, 16, 2); +enum SDL_PIXELFORMAT_ABGR1555 = SDL_DEFINE_PIXELFORMAT!(SDL_PIXELTYPE_PACKED16, SDL_PACKEDORDER_ABGR, SDL_PACKEDLAYOUT_1555, 16, 2); +enum SDL_PIXELFORMAT_BGRA5551 = SDL_DEFINE_PIXELFORMAT!(SDL_PIXELTYPE_PACKED16, SDL_PACKEDORDER_BGRA, SDL_PACKEDLAYOUT_5551, 16, 2); +enum SDL_PIXELFORMAT_RGB565 = SDL_DEFINE_PIXELFORMAT!(SDL_PIXELTYPE_PACKED16, SDL_PACKEDORDER_XRGB, SDL_PACKEDLAYOUT_565, 16, 2); +enum SDL_PIXELFORMAT_BGR565 = SDL_DEFINE_PIXELFORMAT!(SDL_PIXELTYPE_PACKED16, SDL_PACKEDORDER_XBGR, SDL_PACKEDLAYOUT_565, 16, 2); +enum SDL_PIXELFORMAT_RGB24 = SDL_DEFINE_PIXELFORMAT!(SDL_PIXELTYPE_ARRAYU8, SDL_ARRAYORDER_RGB, 0, 24, 3); +enum SDL_PIXELFORMAT_BGR24 = SDL_DEFINE_PIXELFORMAT!(SDL_PIXELTYPE_ARRAYU8, SDL_ARRAYORDER_BGR, 0, 24, 3); +enum SDL_PIXELFORMAT_RGB888 = SDL_DEFINE_PIXELFORMAT!(SDL_PIXELTYPE_PACKED32, SDL_PACKEDORDER_XRGB, SDL_PACKEDLAYOUT_8888, 24, 4); +enum SDL_PIXELFORMAT_RGBX8888 = SDL_DEFINE_PIXELFORMAT!(SDL_PIXELTYPE_PACKED32, SDL_PACKEDORDER_RGBX, SDL_PACKEDLAYOUT_8888, 24, 4); +enum SDL_PIXELFORMAT_BGR888 = SDL_DEFINE_PIXELFORMAT!(SDL_PIXELTYPE_PACKED32, SDL_PACKEDORDER_XBGR, SDL_PACKEDLAYOUT_8888, 24, 4); +enum SDL_PIXELFORMAT_BGRX8888 = SDL_DEFINE_PIXELFORMAT!(SDL_PIXELTYPE_PACKED32, SDL_PACKEDORDER_BGRX, SDL_PACKEDLAYOUT_8888, 24, 4); +enum SDL_PIXELFORMAT_ARGB8888 = SDL_DEFINE_PIXELFORMAT!(SDL_PIXELTYPE_PACKED32, SDL_PACKEDORDER_ARGB, SDL_PACKEDLAYOUT_8888, 32, 4); +enum SDL_PIXELFORMAT_RGBA8888 = SDL_DEFINE_PIXELFORMAT!(SDL_PIXELTYPE_PACKED32, SDL_PACKEDORDER_RGBA, SDL_PACKEDLAYOUT_8888, 32, 4); +enum SDL_PIXELFORMAT_ABGR8888 = SDL_DEFINE_PIXELFORMAT!(SDL_PIXELTYPE_PACKED32, SDL_PACKEDORDER_ABGR, SDL_PACKEDLAYOUT_8888, 32, 4); +enum SDL_PIXELFORMAT_BGRA8888 = SDL_DEFINE_PIXELFORMAT!(SDL_PIXELTYPE_PACKED32, SDL_PACKEDORDER_BGRA, SDL_PACKEDLAYOUT_8888, 32, 4); +enum SDL_PIXELFORMAT_ARGB2101010 = SDL_DEFINE_PIXELFORMAT!(SDL_PIXELTYPE_PACKED32, SDL_PACKEDORDER_ARGB, SDL_PACKEDLAYOUT_2101010, 32, 4); + +enum SDL_PIXELFORMAT_YV12 = SDL_DEFINE_PIXELFOURCC!('Y', 'V', '1', '2'); +enum SDL_PIXELFORMAT_IYUV = SDL_DEFINE_PIXELFOURCC!('I', 'Y', 'U', 'V'); +enum SDL_PIXELFORMAT_YUY2 = SDL_DEFINE_PIXELFOURCC!('Y', 'U', 'Y', '2'); +enum SDL_PIXELFORMAT_UYVY = SDL_DEFINE_PIXELFOURCC!('U', 'Y', 'V', 'Y'); +enum SDL_PIXELFORMAT_YVYU = SDL_DEFINE_PIXELFOURCC!('Y', 'V', 'Y', 'U'); + +static if(sdlSupport >= SDLSupport.sdl204) { + enum SDL_PIXELFORMAT_NV12 = SDL_DEFINE_PIXELFOURCC!('N', 'V', '1', '2'); + enum SDL_PIXELFORMAT_NV21 = SDL_DEFINE_PIXELFOURCC!('N', 'V', '2', '1'); +} + +static if(sdlSupport >= SDLSupport.sdl208) { + enum SDL_PIXELFORMAT_EXTERNAL_OES = SDL_DEFINE_PIXELFOURCC!('O', 'E', 'S', ' '); +} + +static assert(SDL_PIXELFORMAT_BGRX8888 == 0x16661804); + +// Added in SDL 2.0.5, but doesn't hurt to make available for every version. +version(BigEndian) { + alias SDL_PIXELFORMAT_RGBA32 = SDL_PIXELFORMAT_RGBA8888; + alias SDL_PIXELFORMAT_ARGB32 = SDL_PIXELFORMAT_ARGB8888; + alias SDL_PIXELFORMAT_BGRA32 = SDL_PIXELFORMAT_BGRA8888; + alias SDL_PIXELFORMAT_ABGR32 = SDL_PIXELFORMAT_ABGR8888; +} +else { + alias SDL_PIXELFORMAT_RGBA32 = SDL_PIXELFORMAT_ABGR8888; + alias SDL_PIXELFORMAT_ARGB32 = SDL_PIXELFORMAT_BGRA8888; + alias SDL_PIXELFORMAT_BGRA32 = SDL_PIXELFORMAT_ARGB8888; + alias SDL_PIXELFORMAT_ABGR32 = SDL_PIXELFORMAT_RGBA8888; +} + +struct SDL_Color { + ubyte r; + ubyte g; + ubyte b; + ubyte a; +} +alias SDL_Colour = SDL_Color; + +struct SDL_Palette { + int ncolors; + SDL_Color* colors; + uint version_; // NOTE: original was named 'version' + int refcount; +} + +struct SDL_PixelFormat { + uint format; + SDL_Palette *palette; + ubyte BitsPerPixel; + ubyte BytesPerPixel; + ubyte[2] padding; + uint Rmask; + uint Gmask; + uint Bmask; + uint Amask; + ubyte Rloss; + ubyte Gloss; + ubyte Bloss; + ubyte Aloss; + ubyte Rshift; + ubyte Gshift; + ubyte Bshift; + ubyte Ashift; + int refcount; + SDL_PixelFormat* next; +} + +version(BindSDL_Static) { + extern(C) @nogc nothrow { + const(char)* SDL_GetPixelFormatName(uint); + SDL_bool SDL_PixelFormatEnumToMasks(uint,int*,uint*,uint*,uint*,uint*); + uint SDL_MasksToPixelFormatEnum(int,uint,uint,uint,uint); + SDL_PixelFormat* SDL_AllocFormat(uint); + void SDL_FreeFormat(SDL_PixelFormat*); + SDL_Palette* SDL_AllocPalette(int); + int SDL_SetPixelFormatPalette(SDL_PixelFormat*,SDL_Palette*); + int SDL_SetPaletteColors(SDL_Palette*,const(SDL_Color)*,int,int); + void SDL_FreePalette(SDL_Palette*); + uint SDL_MapRGB(const(SDL_PixelFormat)*,ubyte,ubyte,ubyte); + uint SDL_MapRGBA(const(SDL_PixelFormat)*,ubyte,ubyte,ubyte,ubyte); + void SDL_GetRGB(uint,const(SDL_PixelFormat)*,ubyte*,ubyte*,ubyte*); + void SDL_GetRGBA(uint,const(SDL_PixelFormat)*,ubyte*,ubyte*,ubyte*,ubyte*); + void SDL_CalculateGammaRamp(float,ushort*); + } +} +else { + extern(C) @nogc nothrow { + alias pSDL_GetPixelFormatName = const(char)* function(uint); + alias pSDL_PixelFormatEnumToMasks = SDL_bool function(uint,int*,uint*,uint*,uint*,uint*); + alias pSDL_MasksToPixelFormatEnum = uint function(int,uint,uint,uint,uint); + alias pSDL_AllocFormat = SDL_PixelFormat* function(uint); + alias pSDL_FreeFormat = void function(SDL_PixelFormat*); + alias pSDL_AllocPalette = SDL_Palette* function(int); + alias pSDL_SetPixelFormatPalette = int function(SDL_PixelFormat*,SDL_Palette*); + alias pSDL_SetPaletteColors = int function(SDL_Palette*,const(SDL_Color)*,int,int); + alias pSDL_FreePalette = void function(SDL_Palette*); + alias pSDL_MapRGB = uint function(const(SDL_PixelFormat)*,ubyte,ubyte,ubyte); + alias pSDL_MapRGBA = uint function(const(SDL_PixelFormat)*,ubyte,ubyte,ubyte,ubyte); + alias pSDL_GetRGB = void function(uint,const(SDL_PixelFormat)*,ubyte*,ubyte*,ubyte*); + alias pSDL_GetRGBA = void function(uint,const(SDL_PixelFormat)*,ubyte*,ubyte*,ubyte*,ubyte*); + alias pSDL_CalculateGammaRamp = void function(float,ushort*); + } + + __gshared { + pSDL_GetPixelFormatName SDL_GetPixelFormatName; + pSDL_PixelFormatEnumToMasks SDL_PixelFormatEnumToMasks; + pSDL_MasksToPixelFormatEnum SDL_MasksToPixelFormatEnum; + pSDL_AllocFormat SDL_AllocFormat; + pSDL_FreeFormat SDL_FreeFormat; + pSDL_AllocPalette SDL_AllocPalette; + pSDL_SetPixelFormatPalette SDL_SetPixelFormatPalette; + pSDL_SetPaletteColors SDL_SetPaletteColors; + pSDL_FreePalette SDL_FreePalette; + pSDL_MapRGB SDL_MapRGB; + pSDL_MapRGBA SDL_MapRGBA; + pSDL_GetRGB SDL_GetRGB; + pSDL_GetRGBA SDL_GetRGBA; + pSDL_CalculateGammaRamp SDL_CalculateGammaRamp; + } +} \ No newline at end of file diff --git a/demos/external/imports/bindbc/sdl/bind/sdlplatform.d b/demos/external/imports/bindbc/sdl/bind/sdlplatform.d new file mode 100644 index 0000000..da23ff7 --- /dev/null +++ b/demos/external/imports/bindbc/sdl/bind/sdlplatform.d @@ -0,0 +1,22 @@ + +// Copyright Michael D. Parker 2018. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +module bindbc.sdl.bind.sdlplatform; + +version(BindSDL_Static) { + extern(C) @nogc nothrow { + const(char)* SDL_GetPlatform(); + } +} +else { + extern(C) @nogc nothrow { + alias pSDL_GetPlatform = const(char)* function(); + } + + __gshared { + pSDL_GetPlatform SDL_GetPlatform; + } +} \ No newline at end of file diff --git a/demos/external/imports/bindbc/sdl/bind/sdlpower.d b/demos/external/imports/bindbc/sdl/bind/sdlpower.d new file mode 100644 index 0000000..b6eac3b --- /dev/null +++ b/demos/external/imports/bindbc/sdl/bind/sdlpower.d @@ -0,0 +1,33 @@ + +// Copyright Michael D. Parker 2018. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +module bindbc.sdl.bind.sdlpower; + +import bindbc.sdl.config; + +enum SDL_PowerState { + SDL_POWERSTATE_UNKNOWN, + SDL_POWERSTATE_ON_BATTERY, + SDL_POWERSTATE_NO_BATTERY, + SDL_POWERSTATE_CHARGING, + SDL_POWERSTATE_CHARGED +} +mixin(expandEnum!SDL_PowerState); + +version(BindSDL_Static) { + extern(C) @nogc nothrow { + SDL_PowerState SDL_GetPowerInfo(int*,int*); + } +} +else { + extern(C) @nogc nothrow { + alias pSDL_GetPowerInfo = SDL_PowerState function(int*,int*); + } + + __gshared { + pSDL_GetPowerInfo SDL_GetPowerInfo; + } +} \ No newline at end of file diff --git a/demos/external/imports/bindbc/sdl/bind/sdlrect.d b/demos/external/imports/bindbc/sdl/bind/sdlrect.d new file mode 100644 index 0000000..5122fa6 --- /dev/null +++ b/demos/external/imports/bindbc/sdl/bind/sdlrect.d @@ -0,0 +1,80 @@ + +// Copyright Michael D. Parker 2018. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +module bindbc.sdl.bind.sdlrect; + +import bindbc.sdl.config; +import bindbc.sdl.bind.sdlstdinc : SDL_bool; + +struct SDL_Point { + int x; + int y; +} + +struct SDL_Rect { + int x, y; + int w, h; +} + +static if(sdlSupport >= SDLSupport.sdl2010) { + struct SDL_FPoint { + float x, y; + } + + struct SDL_FRect { + float x, y; + float w, h; + } +} + +@nogc nothrow pure { + // This macro was added to SDL_rect.h in 2.0.4, but hurts nothing to implement for + // all versions. + bool SDL_PointInRect(const SDL_Point *p, const SDL_Rect *r) { + pragma(inline, true); + return ((p.x >= r.x) && (p.x < (r.x + r.w)) && + (p.y >= r.y) && (p.y < (r.y + r.h))); + } + + bool SDL_RectEmpty(const(SDL_Rect)* X) { + pragma(inline, true); + return !X || (X.w <= 0) || (X.h <= 0); + } + + bool SDL_RectEquals(const(SDL_Rect)* A, const(SDL_Rect)* B) { + pragma(inline, true); + return A && B && + (A.x == B.x) && (A.y == B.y) && + (A.w == B.w) && (A.h == B.h); + } +} + +version(BindSDL_Static) { + extern(C) @nogc nothrow { + SDL_bool SDL_HasIntersection(const(SDL_Rect)*,const(SDL_Rect)*); + SDL_bool SDL_IntersectRect(const(SDL_Rect)*,const(SDL_Rect)*,SDL_Rect*); + void SDL_UnionRect(const(SDL_Rect)*,const(SDL_Rect)*,SDL_Rect*); + SDL_bool SDL_EnclosePoints(const(SDL_Point)*,int,const(SDL_Rect)*,SDL_Rect*); + SDL_bool SDL_IntersectRectAndLine(const(SDL_Rect)*,int*,int*,int*,int*); + } +} +else { + extern(C) @nogc nothrow { + alias pSDL_HasIntersection = SDL_bool function(const(SDL_Rect)*,const(SDL_Rect)*); + alias pSDL_IntersectRect = SDL_bool function(const(SDL_Rect)*,const(SDL_Rect)*,SDL_Rect*); + alias pSDL_UnionRect = void function(const(SDL_Rect)*,const(SDL_Rect)*,SDL_Rect*); + alias pSDL_EnclosePoints = SDL_bool function(const(SDL_Point)*,int,const(SDL_Rect)*,SDL_Rect*); + alias pSDL_IntersectRectAndLine = SDL_bool function(const(SDL_Rect)*,int*,int*,int*,int*); + } + + __gshared { + pSDL_HasIntersection SDL_HasIntersection; + pSDL_IntersectRect SDL_IntersectRect; + pSDL_UnionRect SDL_UnionRect; + pSDL_EnclosePoints SDL_EnclosePoints; + pSDL_IntersectRectAndLine SDL_IntersectRectAndLine; + } +} \ No newline at end of file diff --git a/demos/external/imports/bindbc/sdl/bind/sdlrender.d b/demos/external/imports/bindbc/sdl/bind/sdlrender.d new file mode 100644 index 0000000..b6b4d65 --- /dev/null +++ b/demos/external/imports/bindbc/sdl/bind/sdlrender.d @@ -0,0 +1,316 @@ + +// Copyright Michael D. Parker 2018. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +module bindbc.sdl.bind.sdlrender; + +import bindbc.sdl.config; +import bindbc.sdl.bind.sdlblendmode : SDL_BlendMode; +import bindbc.sdl.bind.sdlrect; +import bindbc.sdl.bind.sdlstdinc : SDL_bool; +import bindbc.sdl.bind.sdlsurface : SDL_Surface; +import bindbc.sdl.bind.sdlvideo : SDL_Window; + +enum SDL_RendererFlags : uint { + SDL_RENDERER_SOFTWARE = 0x00000001, + SDL_RENDERER_ACCELERATED = 0x00000002, + SDL_RENDERER_PRESENTVSYNC = 0x00000004, + SDL_RENDERER_TARGETTEXTURE = 0x00000008, +} + +mixin(expandEnum!SDL_RendererFlags); + +struct SDL_RendererInfo { + const(char)* name; + SDL_RendererFlags flags; + uint num_texture_formats; + uint[16] texture_formats; + int max_texture_width; + int max_texture_height; +} + +enum SDL_TextureAccess { + SDL_TEXTUREACCESS_STATIC, + SDL_TEXTUREACCESS_STREAMING, + SDL_TEXTUREACCESS_TARGET, +} +mixin(expandEnum!SDL_TextureAccess); + +enum SDL_TextureModulate { + SDL_TEXTUREMODULATE_NONE = 0x00000000, + SDL_TEXTUREMODULATE_COLOR = 0x00000001, + SDL_TEXTUREMODULATE_ALPHA = 0x00000002 +} +mixin(expandEnum!SDL_TextureModulate); + +enum SDL_RendererFlip { + SDL_FLIP_NONE = 0x00000000, + SDL_FLIP_HORIZONTAL = 0x00000001, + SDL_FLIP_VERTICAL = 0x00000002, +} +mixin(expandEnum!SDL_RendererFlip); + +struct SDL_Renderer; +struct SDL_Texture; + +version(BindSDL_Static) { + extern(C) @nogc nothrow { + int SDL_GetNumRenderDrivers(); + int SDL_GetRenderDriverInfo(int,SDL_RendererInfo*); + int SDL_CreateWindowAndRenderer(int,int,uint,SDL_Window**,SDL_Renderer**); + SDL_Renderer* SDL_CreateRenderer(SDL_Window*,int,SDL_RendererFlags); + SDL_Renderer* SDL_CreateSoftwareRenderer(SDL_Surface*); + SDL_Renderer* SDL_GetRenderer(SDL_Window*); + int SDL_GetRendererInfo(SDL_Renderer*,SDL_RendererInfo*); + int SDL_GetRendererOutputSize(SDL_Renderer*,int*,int*); + SDL_Texture* SDL_CreateTexture(SDL_Renderer*,uint,SDL_TextureAccess,int,int); + SDL_Texture* SDL_CreateTextureFromSurface(SDL_Renderer*,SDL_Surface*); + int SDL_QueryTexture(SDL_Texture*,uint*,int*,int*,int*); + int SDL_SetTextureColorMod(SDL_Texture*,ubyte,ubyte,ubyte); + int SDL_GetTextureColorMod(SDL_Texture*,ubyte*,ubyte*,ubyte*); + int SDL_SetTextureAlphaMod(SDL_Texture*,ubyte); + int SDL_GetTextureAlphaMod(SDL_Texture*,ubyte*); + int SDL_SetTextureBlendMode(SDL_Texture*,SDL_BlendMode); + int SDL_GetTextureBlendMode(SDL_Texture*,SDL_BlendMode*); + int SDL_UpdateTexture(SDL_Texture*,const(SDL_Rect)*,const(void)*,int); + int SDL_LockTexture(SDL_Texture*,const(SDL_Rect)*,void**,int*); + void SDL_UnlockTexture(SDL_Texture*); + SDL_bool SDL_RenderTargetSupported(SDL_Renderer*); + int SDL_SetRenderTarget(SDL_Renderer*,SDL_Texture*); + SDL_Texture* SDL_GetRenderTarget(SDL_Renderer*); + int SDL_RenderSetClipRect(SDL_Renderer*,const(SDL_Rect)*); + void SDL_RenderGetClipRect(SDL_Renderer* renderer,SDL_Rect*); + int SDL_RenderSetLogicalSize(SDL_Renderer*,int,int); + void SDL_RenderGetLogicalSize(SDL_Renderer*,int*,int*); + int SDL_RenderSetViewport(SDL_Renderer*,const(SDL_Rect)*); + void SDL_RenderGetViewport(SDL_Renderer*,SDL_Rect*); + int SDL_RenderSetScale(SDL_Renderer*,float,float); + int SDL_RenderGetScale(SDL_Renderer*,float*,float*); + int SDL_SetRenderDrawColor(SDL_Renderer*,ubyte,ubyte,ubyte,ubyte); + int SDL_GetRenderDrawColor(SDL_Renderer*,ubyte*,ubyte*,ubyte*,ubyte*); + int SDL_SetRenderDrawBlendMode(SDL_Renderer*,SDL_BlendMode); + int SDL_GetRenderDrawBlendMode(SDL_Renderer*,SDL_BlendMode*); + int SDL_RenderClear(SDL_Renderer*); + int SDL_RenderDrawPoint(SDL_Renderer*,int,int); + int SDL_RenderDrawPoints(SDL_Renderer*,const(SDL_Point)*,int); + int SDL_RenderDrawLine(SDL_Renderer*,int,int,int,int); + int SDL_RenderDrawLines(SDL_Renderer*,const(SDL_Point)*,int); + int SDL_RenderDrawRect(SDL_Renderer*,const(SDL_Rect)*); + int SDL_RenderDrawRects(SDL_Renderer*,const(SDL_Rect)*,int); + int SDL_RenderFillRect(SDL_Renderer*,const(SDL_Rect)*); + int SDL_RenderFillRects(SDL_Renderer*,const(SDL_Rect)*,int); + int SDL_RenderCopy(SDL_Renderer*,SDL_Texture*,const(SDL_Rect)*,const(SDL_Rect*)); + int SDL_RenderCopyEx(SDL_Renderer*,SDL_Texture*,const(SDL_Rect)*,const(SDL_Rect)*,const(double),const(SDL_Point)*,const(SDL_RendererFlip)); + int SDL_RenderReadPixels(SDL_Renderer*,const(SDL_Rect)*,uint,void*,int); + void SDL_RenderPresent(SDL_Renderer*); + void SDL_DestroyTexture(SDL_Texture*); + void SDL_DestroyRenderer(SDL_Renderer*); + int SDL_GL_BindTexture(SDL_Texture*,float*,float*); + int SDL_GL_UnbindTexture(SDL_Texture*); + + static if(sdlSupport >= SDLSupport.sdl201) { + int SDL_UpdateYUVTexture(SDL_Texture*,const(SDL_Rect)*,const(ubyte)*,int,const(ubyte)*,int,const(ubyte)*,int); + } + static if(sdlSupport >= SDLSupport.sdl204) { + SDL_bool SDL_RenderIsClipEnabled(SDL_Renderer*); + } + static if(sdlSupport >= SDLSupport.sdl205) { + SDL_bool SDL_RenderGetIntegerScale(SDL_Renderer*); + int SDL_RenderSetIntegerScale(SDL_Renderer*,SDL_bool); + } + static if(sdlSupport >= SDLSupport.sdl208) { + void* SDL_RenderGetMetalLayer(SDL_Renderer*); + void* SDL_RenderGetMetalCommandEncoder(SDL_Renderer*); + } + static if(sdlSupport >= SDLSupport.sdl2010) { + int SDL_RenderDrawPointF(SDL_Renderer*,float,float); + int SDL_RenderDrawPointsF(SDL_Renderer*,const(SDL_FPoint)*,int); + int SDL_RenderDrawLineF(SDL_Renderer*,float,float,float,float); + int SDL_RenderDrawLinesF(SDL_Renderer*,const(SDL_FPoint)*,int); + int SDL_RenderDrawRectF(SDL_Renderer*,const(SDL_FRect)*); + int SDL_RenderDrawRectsF(SDL_Renderer*,const(SDL_FRect)*,int); + int SDL_RenderFillRectF(SDL_Renderer*,const(SDL_FRect)*); + int SDL_RenderFillRectsF(SDL_Renderer*,const(SDL_FRect)*,int); + int SDL_RenderCopyF(SDL_Renderer*,SDL_Texture*,const(SDL_FRect)*,const(SDL_FRect)*); + int SDL_RenderCopyExF(SDL_Renderer*,SDL_Texture*,const(SDL_FRect)*,const(SDL_FRect)*,const(double),const(SDL_FPoint)*,const(SDL_RendererFlip)); + int SDL_RenderFlush(SDL_Renderer*); + } + } +} +else { + extern(C) @nogc nothrow { + alias pSDL_GetNumRenderDrivers = int function(); + alias pSDL_GetRenderDriverInfo = int function(int,SDL_RendererInfo*); + alias pSDL_CreateWindowAndRenderer = int function(int,int,uint,SDL_Window**,SDL_Renderer**); + alias pSDL_CreateRenderer = SDL_Renderer* function(SDL_Window*,int,SDL_RendererFlags); + alias pSDL_CreateSoftwareRenderer = SDL_Renderer* function(SDL_Surface*); + alias pSDL_GetRenderer = SDL_Renderer* function(SDL_Window*); + alias pSDL_GetRendererInfo = int function(SDL_Renderer*,SDL_RendererInfo*); + alias pSDL_GetRendererOutputSize = int function(SDL_Renderer*,int*,int*); + alias pSDL_CreateTexture = SDL_Texture* function(SDL_Renderer*,uint,SDL_TextureAccess,int,int); + alias pSDL_CreateTextureFromSurface = SDL_Texture* function(SDL_Renderer*,SDL_Surface*); + alias pSDL_QueryTexture = int function(SDL_Texture*,uint*,int*,int*,int*); + alias pSDL_SetTextureColorMod = int function(SDL_Texture*,ubyte,ubyte,ubyte); + alias pSDL_GetTextureColorMod = int function(SDL_Texture*,ubyte*,ubyte*,ubyte*); + alias pSDL_SetTextureAlphaMod = int function(SDL_Texture*,ubyte); + alias pSDL_GetTextureAlphaMod = int function(SDL_Texture*,ubyte*); + alias pSDL_SetTextureBlendMode = int function(SDL_Texture*,SDL_BlendMode); + alias pSDL_GetTextureBlendMode = int function(SDL_Texture*,SDL_BlendMode*); + alias pSDL_UpdateTexture = int function(SDL_Texture*,const(SDL_Rect)*,const(void)*,int); + alias pSDL_LockTexture = int function(SDL_Texture*,const(SDL_Rect)*,void**,int*); + alias pSDL_UnlockTexture = void function(SDL_Texture*); + alias pSDL_RenderTargetSupported = SDL_bool function(SDL_Renderer*); + alias pSDL_SetRenderTarget = int function(SDL_Renderer*,SDL_Texture*); + alias pSDL_GetRenderTarget = SDL_Texture* function(SDL_Renderer*); + alias pSDL_RenderSetClipRect = int function(SDL_Renderer*,const(SDL_Rect)*); + alias pSDL_RenderGetClipRect = void function(SDL_Renderer* renderer,SDL_Rect*); + alias pSDL_RenderSetLogicalSize = int function(SDL_Renderer*,int,int); + alias pSDL_RenderGetLogicalSize = void function(SDL_Renderer*,int*,int*); + alias pSDL_RenderSetViewport = int function(SDL_Renderer*,const(SDL_Rect)*); + alias pSDL_RenderGetViewport = void function(SDL_Renderer*,SDL_Rect*); + alias pSDL_RenderSetScale = int function(SDL_Renderer*,float,float); + alias pSDL_RenderGetScale = int function(SDL_Renderer*,float*,float*); + alias pSDL_SetRenderDrawColor = int function(SDL_Renderer*,ubyte,ubyte,ubyte,ubyte); + alias pSDL_GetRenderDrawColor = int function(SDL_Renderer*,ubyte*,ubyte*,ubyte*,ubyte*); + alias pSDL_SetRenderDrawBlendMode = int function(SDL_Renderer*,SDL_BlendMode); + alias pSDL_GetRenderDrawBlendMode = int function(SDL_Renderer*,SDL_BlendMode*); + alias pSDL_RenderClear = int function(SDL_Renderer*); + alias pSDL_RenderDrawPoint = int function(SDL_Renderer*,int,int); + alias pSDL_RenderDrawPoints = int function(SDL_Renderer*,const(SDL_Point)*,int); + alias pSDL_RenderDrawLine = int function(SDL_Renderer*,int,int,int,int); + alias pSDL_RenderDrawLines = int function(SDL_Renderer*,const(SDL_Point)*,int); + alias pSDL_RenderDrawRect = int function(SDL_Renderer*,const(SDL_Rect)*); + alias pSDL_RenderDrawRects = int function(SDL_Renderer*,const(SDL_Rect)*,int); + alias pSDL_RenderFillRect = int function(SDL_Renderer*,const(SDL_Rect)*); + alias pSDL_RenderFillRects = int function(SDL_Renderer*,const(SDL_Rect)*,int); + alias pSDL_RenderCopy = int function(SDL_Renderer*,SDL_Texture*,const(SDL_Rect)*,const(SDL_Rect*)); + alias pSDL_RenderCopyEx = int function(SDL_Renderer*,SDL_Texture*,const(SDL_Rect)*,const(SDL_Rect)*,const(double),const(SDL_Point)*,const(SDL_RendererFlip)); + alias pSDL_RenderReadPixels = int function(SDL_Renderer*,const(SDL_Rect)*,uint,void*,int); + alias pSDL_RenderPresent = void function(SDL_Renderer*); + alias pSDL_DestroyTexture = void function(SDL_Texture*); + alias pSDL_DestroyRenderer = void function(SDL_Renderer*); + alias pSDL_GL_BindTexture = int function(SDL_Texture*,float*,float*); + alias pSDL_GL_UnbindTexture = int function(SDL_Texture*); + } + + __gshared { + pSDL_GetNumRenderDrivers SDL_GetNumRenderDrivers; + pSDL_GetRenderDriverInfo SDL_GetRenderDriverInfo; + pSDL_CreateWindowAndRenderer SDL_CreateWindowAndRenderer; + pSDL_CreateRenderer SDL_CreateRenderer; + pSDL_CreateSoftwareRenderer SDL_CreateSoftwareRenderer; + pSDL_GetRenderer SDL_GetRenderer; + pSDL_GetRendererInfo SDL_GetRendererInfo; + pSDL_GetRendererOutputSize SDL_GetRendererOutputSize; + pSDL_CreateTexture SDL_CreateTexture; + pSDL_CreateTextureFromSurface SDL_CreateTextureFromSurface; + pSDL_QueryTexture SDL_QueryTexture; + pSDL_SetTextureColorMod SDL_SetTextureColorMod; + pSDL_GetTextureColorMod SDL_GetTextureColorMod; + pSDL_SetTextureAlphaMod SDL_SetTextureAlphaMod; + pSDL_GetTextureAlphaMod SDL_GetTextureAlphaMod; + pSDL_SetTextureBlendMode SDL_SetTextureBlendMode; + pSDL_GetTextureBlendMode SDL_GetTextureBlendMode; + pSDL_UpdateTexture SDL_UpdateTexture; + pSDL_LockTexture SDL_LockTexture; + pSDL_UnlockTexture SDL_UnlockTexture; + pSDL_RenderTargetSupported SDL_RenderTargetSupported; + pSDL_SetRenderTarget SDL_SetRenderTarget; + pSDL_GetRenderTarget SDL_GetRenderTarget; + pSDL_RenderSetClipRect SDL_RenderSetClipRect; + pSDL_RenderGetClipRect SDL_RenderGetClipRect; + pSDL_RenderSetLogicalSize SDL_RenderSetLogicalSize; + pSDL_RenderGetLogicalSize SDL_RenderGetLogicalSize; + pSDL_RenderSetViewport SDL_RenderSetViewport; + pSDL_RenderGetViewport SDL_RenderGetViewport; + pSDL_RenderSetScale SDL_RenderSetScale; + pSDL_RenderGetScale SDL_RenderGetScale; + pSDL_SetRenderDrawColor SDL_SetRenderDrawColor; + pSDL_GetRenderDrawColor SDL_GetRenderDrawColor; + pSDL_SetRenderDrawBlendMode SDL_SetRenderDrawBlendMode; + pSDL_GetRenderDrawBlendMode SDL_GetRenderDrawBlendMode; + pSDL_RenderClear SDL_RenderClear; + pSDL_RenderDrawPoint SDL_RenderDrawPoint; + pSDL_RenderDrawPoints SDL_RenderDrawPoints; + pSDL_RenderDrawLine SDL_RenderDrawLine; + pSDL_RenderDrawLines SDL_RenderDrawLines; + pSDL_RenderDrawRect SDL_RenderDrawRect; + pSDL_RenderDrawRects SDL_RenderDrawRects; + pSDL_RenderFillRect SDL_RenderFillRect; + pSDL_RenderFillRects SDL_RenderFillRects; + pSDL_RenderCopy SDL_RenderCopy; + pSDL_RenderCopyEx SDL_RenderCopyEx; + pSDL_RenderReadPixels SDL_RenderReadPixels; + pSDL_RenderPresent SDL_RenderPresent; + pSDL_DestroyTexture SDL_DestroyTexture; + pSDL_DestroyRenderer SDL_DestroyRenderer; + pSDL_GL_BindTexture SDL_GL_BindTexture; + pSDL_GL_UnbindTexture SDL_GL_UnbindTexture; + } + static if(sdlSupport >= SDLSupport.sdl201) { + extern(C) @nogc nothrow { + alias pSDL_UpdateYUVTexture = int function(SDL_Texture*,const(SDL_Rect)*,const(ubyte)*,int,const(ubyte)*,int,const(ubyte)*,int); + } + __gshared { + pSDL_UpdateYUVTexture SDL_UpdateYUVTexture; + } + } + static if(sdlSupport >= SDLSupport.sdl204) { + extern(C) @nogc nothrow { + alias pSDL_RenderIsClipEnabled = SDL_bool function(SDL_Renderer*); + } + __gshared { + pSDL_RenderIsClipEnabled SDL_RenderIsClipEnabled; + } + } + static if(sdlSupport >= SDLSupport.sdl205) { + extern(C) @nogc nothrow { + alias pSDL_RenderGetIntegerScale = SDL_bool function(SDL_Renderer*); + alias pSDL_RenderSetIntegerScale = int function(SDL_Renderer*,SDL_bool); + } + __gshared { + pSDL_RenderGetIntegerScale SDL_RenderGetIntegerScale; + pSDL_RenderSetIntegerScale SDL_RenderSetIntegerScale; + } + } + static if(sdlSupport >= SDLSupport.sdl208) { + extern(C) @nogc nothrow { + alias pSDL_RenderGetMetalLayer = void* function(SDL_Renderer*); + alias pSDL_RenderGetMetalCommandEncoder = void* function(SDL_Renderer*); + } + __gshared { + pSDL_RenderGetMetalLayer SDL_RenderGetMetalLayer; + pSDL_RenderGetMetalCommandEncoder SDL_RenderGetMetalCommandEncoder; + } + } + static if(sdlSupport >= SDLSupport.sdl2010) { + extern(C) @nogc nothrow { + alias pSDL_RenderDrawPointF = int function(SDL_Renderer*,float,float); + alias pSDL_RenderDrawPointsF = int function(SDL_Renderer*,const(SDL_FPoint)*,int); + alias pSDL_RenderDrawLineF = int function(SDL_Renderer*,float,float,float,float); + alias pSDL_RenderDrawLinesF = int function(SDL_Renderer*,const(SDL_FPoint)*,int); + alias pSDL_RenderDrawRectF = int function(SDL_Renderer*,const(SDL_FRect)*); + alias pSDL_RenderDrawRectsF = int function(SDL_Renderer*,const(SDL_FRect)*,int); + alias pSDL_RenderFillRectF = int function(SDL_Renderer*,const(SDL_FRect)*); + alias pSDL_RenderFillRectsF = int function(SDL_Renderer*,const(SDL_FRect)*,int); + alias pSDL_RenderCopyF = int function(SDL_Renderer*,SDL_Texture*,const(SDL_FRect)*,const(SDL_FRect)*); + alias pSDL_RenderCopyExF = int function(SDL_Renderer*,SDL_Texture*,const(SDL_FRect)*,const(SDL_FRect)*,const(double),const(SDL_FPoint)*,const(SDL_RendererFlip)); + alias pSDL_RenderFlush = int function(SDL_Renderer*); + } + __gshared { + pSDL_RenderDrawPointF SDL_RenderDrawPointF; + pSDL_RenderDrawPointsF SDL_RenderDrawPointsF; + pSDL_RenderDrawLineF SDL_RenderDrawLineF; + pSDL_RenderDrawLinesF SDL_RenderDrawLinesF; + pSDL_RenderDrawRectF SDL_RenderDrawRectF; + pSDL_RenderDrawRectsF SDL_RenderDrawRectsF; + pSDL_RenderFillRectF SDL_RenderFillRectF; + pSDL_RenderFillRectsF SDL_RenderFillRectsF; + pSDL_RenderCopyF SDL_RenderCopyF; + pSDL_RenderCopyExF SDL_RenderCopyExF; + pSDL_RenderFlush SDL_RenderFlush; + } + } +} \ No newline at end of file diff --git a/demos/external/imports/bindbc/sdl/bind/sdlrwops.d b/demos/external/imports/bindbc/sdl/bind/sdlrwops.d new file mode 100644 index 0000000..47ddd20 --- /dev/null +++ b/demos/external/imports/bindbc/sdl/bind/sdlrwops.d @@ -0,0 +1,208 @@ + +// Copyright Michael D. Parker 2018. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +module bindbc.sdl.bind.sdlrwops; + +//import core.stdc.stdio : FILE; + +struct FILE +{ +} + +import bindbc.sdl.config; +import bindbc.sdl.bind.sdlstdinc : SDL_bool; + +enum : uint { + SDL_RWOPS_UNKNOWN = 0, + SDL_RWOPS_WINFILE = 1, + SDL_RWOPS_STDFILE = 2, + SDL_RWOPS_JNIFILE = 3, + SDL_RWOPS_MEMORY = 4, + SDL_RWOPS_MEMORY_RO = 5, +} + +struct SDL_RWops { + extern(C) @nogc nothrow { + long function(SDL_RWops*) size; + long function(SDL_RWops*, long, int) seek; + size_t function(SDL_RWops*, void*, size_t, size_t) read; + size_t function(SDL_RWops*, const(void)*, size_t, size_t) write; + int function(SDL_RWops*) close; + } + + uint type; + + union Hidden { + // version(Android) + version(Windows) { + struct Windowsio { + int append; + void* h; + struct Buffer { + void* data; + size_t size; + size_t left; + } + Buffer buffer; + } + Windowsio windowsio; + } + + struct Stdio { + int autoclose; + FILE* fp; + } + Stdio stdio; + + struct Mem { + ubyte* base; + ubyte* here; + ubyte* stop; + } + Mem mem; + + struct Unknown { + void* data1; + void* data2; + } + Unknown unknown; + } + Hidden hidden; +} + +enum { + RW_SEEK_SET = 0, + RW_SEEK_CUR = 1, + RW_SEEK_END = 2, +} + +static if(sdlSupport < SDLSupport.sdl2010) { + @nogc nothrow { + long SDL_RWsize(SDL_RWops* ctx) { return ctx.size(ctx); } + long SDL_RWseek(SDL_RWops* ctx, long offset, int whence) { return ctx.seek(ctx, offset, whence); } + long SDL_RWtell(SDL_RWops* ctx) { return ctx.seek(ctx, 0, RW_SEEK_CUR); } + size_t SDL_RWread(SDL_RWops* ctx, void* ptr, size_t size, size_t n) { return ctx.read(ctx, ptr, size, n); } + size_t SDL_RWwrite(SDL_RWops* ctx, const(void)* ptr, size_t size, size_t n) { return ctx.write(ctx, ptr, size, n); } + int SDL_RWclose(SDL_RWops* ctx) { return ctx.close(ctx); } + } +} + +static if(sdlSupport >= SDLSupport.sdl206) { + @nogc nothrow + void* SDL_LoadFile(const(char)* filename, size_t datasize) { + pragma(inline, true); + return SDL_LoadFile_RW(SDL_RWFromFile(filename, "rb"), datasize, 1); + } +} + +version(BindSDL_Static) { + extern(C) @nogc nothrow { + SDL_RWops* SDL_RWFromFile(const(char)*,const(char)*); + SDL_RWops* SDL_RWFromFP(FILE*,SDL_bool); + SDL_RWops* SDL_RWFromMem(void*,int); + SDL_RWops* SDL_RWFromConstMem(const(void)*,int); + SDL_RWops* SDL_AllocRW(); + void SDL_FreeRW(SDL_RWops*); + ubyte SDL_ReadU8(SDL_RWops*); + ushort SDL_ReadLE16(SDL_RWops*); + ushort SDL_ReadBE16(SDL_RWops*); + uint SDL_ReadLE32(SDL_RWops*); + uint SDL_ReadBE32(SDL_RWops*); + ulong SDL_ReadLE64(SDL_RWops*); + ulong SDL_ReadBE64(SDL_RWops*); + size_t SDL_WriteU8(SDL_RWops*,ubyte); + size_t SDL_WriteLE16(SDL_RWops*,ushort); + size_t SDL_WriteBE16(SDL_RWops*,ushort); + size_t SDL_WriteLE32(SDL_RWops*,uint); + size_t SDL_WriteBE32(SDL_RWops*,uint); + size_t SDL_WriteLE64(SDL_RWops*,ulong); + size_t SDL_WriteBE64(SDL_RWops*,ulong); + + static if(sdlSupport >= SDLSupport.sdl206) { + void* SDL_LoadFile_RW(SDL_RWops*,size_t,int); + } + static if(sdlSupport >= SDLSupport.sdl2010) { + long SDL_RWsize(SDL_RWops*); + long SDL_RWseek(SDL_RWops*,long,int); + long SDL_RWtell(SDL_RWops*); + size_t SDL_RWread(SDL_RWops*,void*,size_t,size_t); + size_t SDL_RWwrite(SDL_RWops*,const(void)*,size_t,size_t); + int SDL_RWclose(SDL_RWops*); + } + } +} +else { + extern(C) @nogc nothrow { + alias pSDL_RWFromFile = SDL_RWops* function(const(char)*,const(char)*); + alias pSDL_RWFromFP = SDL_RWops* function(FILE*,SDL_bool); + alias pSDL_RWFromMem = SDL_RWops* function(void*,int); + alias pSDL_RWFromConstMem = SDL_RWops* function(const(void)*,int); + alias pSDL_AllocRW = SDL_RWops* function(); + alias pSDL_FreeRW = void function(SDL_RWops*); + alias pSDL_ReadU8 = ubyte function(SDL_RWops*); + alias pSDL_ReadLE16 = ushort function(SDL_RWops*); + alias pSDL_ReadBE16 = ushort function(SDL_RWops*); + alias pSDL_ReadLE32 = uint function(SDL_RWops*); + alias pSDL_ReadBE32 = uint function(SDL_RWops*); + alias pSDL_ReadLE64 = ulong function(SDL_RWops*); + alias pSDL_ReadBE64 = ulong function(SDL_RWops*); + alias pSDL_WriteU8 = size_t function(SDL_RWops*,ubyte); + alias pSDL_WriteLE16 = size_t function(SDL_RWops*,ushort); + alias pSDL_WriteBE16 = size_t function(SDL_RWops*,ushort); + alias pSDL_WriteLE32 = size_t function(SDL_RWops*,uint); + alias pSDL_WriteBE32 = size_t function(SDL_RWops*,uint); + alias pSDL_WriteLE64 = size_t function(SDL_RWops*,ulong); + alias pSDL_WriteBE64 = size_t function(SDL_RWops*,ulong); + } + __gshared { + pSDL_RWFromFile SDL_RWFromFile; + pSDL_RWFromFP SDL_RWFromFP; + pSDL_RWFromMem SDL_RWFromMem; + pSDL_RWFromConstMem SDL_RWFromConstMem; + pSDL_AllocRW SDL_AllocRW; + pSDL_FreeRW SDL_FreeRW; + pSDL_ReadU8 SDL_ReadU8; + pSDL_ReadLE16 SDL_ReadLE16; + pSDL_ReadBE16 SDL_ReadBE16; + pSDL_ReadLE32 SDL_ReadLE32; + pSDL_ReadBE32 SDL_ReadBE32; + pSDL_ReadLE64 SDL_ReadLE64; + pSDL_ReadBE64 SDL_ReadBE64; + pSDL_WriteU8 SDL_WriteU8; + pSDL_WriteLE16 SDL_WriteLE16; + pSDL_WriteBE16 SDL_WriteBE16; + pSDL_WriteLE32 SDL_WriteLE32; + pSDL_WriteBE32 SDL_WriteBE32; + pSDL_WriteLE64 SDL_WriteLE64; + pSDL_WriteBE64 SDL_WriteBE64; + } + static if(sdlSupport >= SDLSupport.sdl206) { + extern(C) @nogc nothrow { + alias pSDL_LoadFile_RW = void* function(SDL_RWops*,size_t,int); + } + __gshared { + pSDL_LoadFile_RW SDL_LoadFile_RW; + } + } + static if(sdlSupport >= SDLSupport.sdl2010) { + extern(C) @nogc nothrow { + alias pSDL_RWsize = long function(SDL_RWops*); + alias pSDL_RWseek = long function(SDL_RWops*,long,int); + alias pSDL_RWtell = long function(SDL_RWops*); + alias pSDL_RWread = size_t function(SDL_RWops*,void*,size_t,size_t); + alias pSDL_RWwrite = size_t function(SDL_RWops*,const(void)*,size_t,size_t); + alias pSDL_RWclose = int function(SDL_RWops*); + } + __gshared { + pSDL_RWsize SDL_RWsize; + pSDL_RWseek SDL_RWseek; + pSDL_RWtell SDL_RWtell; + pSDL_RWread SDL_RWread; + pSDL_RWwrite SDL_RWwrite; + pSDL_RWclose SDL_RWclose; + } + } +} \ No newline at end of file diff --git a/demos/external/imports/bindbc/sdl/bind/sdlscancode.d b/demos/external/imports/bindbc/sdl/bind/sdlscancode.d new file mode 100644 index 0000000..fc188dd --- /dev/null +++ b/demos/external/imports/bindbc/sdl/bind/sdlscancode.d @@ -0,0 +1,542 @@ + +// Copyright Michael D. Parker 2018. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +module bindbc.sdl.bind.sdlscancode; + +import bindbc.sdl.config; + +static if(sdlSupport >= SDLSupport.sdl206) { + enum SDL_Scancode { + SDL_SCANCODE_UNKNOWN = 0, + + SDL_SCANCODE_A = 4, + SDL_SCANCODE_B = 5, + SDL_SCANCODE_C = 6, + SDL_SCANCODE_D = 7, + SDL_SCANCODE_E = 8, + SDL_SCANCODE_F = 9, + SDL_SCANCODE_G = 10, + SDL_SCANCODE_H = 11, + SDL_SCANCODE_I = 12, + SDL_SCANCODE_J = 13, + SDL_SCANCODE_K = 14, + SDL_SCANCODE_L = 15, + SDL_SCANCODE_M = 16, + SDL_SCANCODE_N = 17, + SDL_SCANCODE_O = 18, + SDL_SCANCODE_P = 19, + SDL_SCANCODE_Q = 20, + SDL_SCANCODE_R = 21, + SDL_SCANCODE_S = 22, + SDL_SCANCODE_T = 23, + SDL_SCANCODE_U = 24, + SDL_SCANCODE_V = 25, + SDL_SCANCODE_W = 26, + SDL_SCANCODE_X = 27, + SDL_SCANCODE_Y = 28, + SDL_SCANCODE_Z = 29, + + SDL_SCANCODE_1 = 30, + SDL_SCANCODE_2 = 31, + SDL_SCANCODE_3 = 32, + SDL_SCANCODE_4 = 33, + SDL_SCANCODE_5 = 34, + SDL_SCANCODE_6 = 35, + SDL_SCANCODE_7 = 36, + SDL_SCANCODE_8 = 37, + SDL_SCANCODE_9 = 38, + SDL_SCANCODE_0 = 39, + + SDL_SCANCODE_RETURN = 40, + SDL_SCANCODE_ESCAPE = 41, + SDL_SCANCODE_BACKSPACE = 42, + SDL_SCANCODE_TAB = 43, + SDL_SCANCODE_SPACE = 44, + + SDL_SCANCODE_MINUS = 45, + SDL_SCANCODE_EQUALS = 46, + SDL_SCANCODE_LEFTBRACKET = 47, + SDL_SCANCODE_RIGHTBRACKET = 48, + SDL_SCANCODE_BACKSLASH = 49, + SDL_SCANCODE_NONUSHASH = 50, + SDL_SCANCODE_SEMICOLON = 51, + SDL_SCANCODE_APOSTROPHE = 52, + SDL_SCANCODE_GRAVE = 53, + SDL_SCANCODE_COMMA = 54, + SDL_SCANCODE_PERIOD = 55, + SDL_SCANCODE_SLASH = 56, + + SDL_SCANCODE_CAPSLOCK = 57, + + SDL_SCANCODE_F1 = 58, + SDL_SCANCODE_F2 = 59, + SDL_SCANCODE_F3 = 60, + SDL_SCANCODE_F4 = 61, + SDL_SCANCODE_F5 = 62, + SDL_SCANCODE_F6 = 63, + SDL_SCANCODE_F7 = 64, + SDL_SCANCODE_F8 = 65, + SDL_SCANCODE_F9 = 66, + SDL_SCANCODE_F10 = 67, + SDL_SCANCODE_F11 = 68, + SDL_SCANCODE_F12 = 69, + + SDL_SCANCODE_PRINTSCREEN = 70, + SDL_SCANCODE_SCROLLLOCK = 71, + SDL_SCANCODE_PAUSE = 72, + SDL_SCANCODE_INSERT = 73, + SDL_SCANCODE_HOME = 74, + SDL_SCANCODE_PAGEUP = 75, + SDL_SCANCODE_DELETE = 76, + SDL_SCANCODE_END = 77, + SDL_SCANCODE_PAGEDOWN = 78, + SDL_SCANCODE_RIGHT = 79, + SDL_SCANCODE_LEFT = 80, + SDL_SCANCODE_DOWN = 81, + SDL_SCANCODE_UP = 82, + + SDL_SCANCODE_NUMLOCKCLEAR = 83, + SDL_SCANCODE_KP_DIVIDE = 84, + SDL_SCANCODE_KP_MULTIPLY = 85, + SDL_SCANCODE_KP_MINUS = 86, + SDL_SCANCODE_KP_PLUS = 87, + SDL_SCANCODE_KP_ENTER = 88, + SDL_SCANCODE_KP_1 = 89, + SDL_SCANCODE_KP_2 = 90, + SDL_SCANCODE_KP_3 = 91, + SDL_SCANCODE_KP_4 = 92, + SDL_SCANCODE_KP_5 = 93, + SDL_SCANCODE_KP_6 = 94, + SDL_SCANCODE_KP_7 = 95, + SDL_SCANCODE_KP_8 = 96, + SDL_SCANCODE_KP_9 = 97, + SDL_SCANCODE_KP_0 = 98, + SDL_SCANCODE_KP_PERIOD = 99, + + SDL_SCANCODE_NONUSBACKSLASH = 100, + SDL_SCANCODE_APPLICATION = 101, + SDL_SCANCODE_POWER = 102, + SDL_SCANCODE_KP_EQUALS = 103, + SDL_SCANCODE_F13 = 104, + SDL_SCANCODE_F14 = 105, + SDL_SCANCODE_F15 = 106, + SDL_SCANCODE_F16 = 107, + SDL_SCANCODE_F17 = 108, + SDL_SCANCODE_F18 = 109, + SDL_SCANCODE_F19 = 110, + SDL_SCANCODE_F20 = 111, + SDL_SCANCODE_F21 = 112, + SDL_SCANCODE_F22 = 113, + SDL_SCANCODE_F23 = 114, + SDL_SCANCODE_F24 = 115, + SDL_SCANCODE_EXECUTE = 116, + SDL_SCANCODE_HELP = 117, + SDL_SCANCODE_MENU = 118, + SDL_SCANCODE_SELECT = 119, + SDL_SCANCODE_STOP = 120, + SDL_SCANCODE_AGAIN = 121, + SDL_SCANCODE_UNDO = 122, + SDL_SCANCODE_CUT = 123, + SDL_SCANCODE_COPY = 124, + SDL_SCANCODE_PASTE = 125, + SDL_SCANCODE_FIND = 126, + SDL_SCANCODE_MUTE = 127, + SDL_SCANCODE_VOLUMEUP = 128, + SDL_SCANCODE_VOLUMEDOWN = 129, + SDL_SCANCODE_KP_COMMA = 133, + SDL_SCANCODE_KP_EQUALSAS400 = 134, + + SDL_SCANCODE_INTERNATIONAL1 = 135, + SDL_SCANCODE_INTERNATIONAL2 = 136, + SDL_SCANCODE_INTERNATIONAL3 = 137, + SDL_SCANCODE_INTERNATIONAL4 = 138, + SDL_SCANCODE_INTERNATIONAL5 = 139, + SDL_SCANCODE_INTERNATIONAL6 = 140, + SDL_SCANCODE_INTERNATIONAL7 = 141, + SDL_SCANCODE_INTERNATIONAL8 = 142, + SDL_SCANCODE_INTERNATIONAL9 = 143, + SDL_SCANCODE_LANG1 = 144, + SDL_SCANCODE_LANG2 = 145, + SDL_SCANCODE_LANG3 = 146, + SDL_SCANCODE_LANG4 = 147, + SDL_SCANCODE_LANG5 = 148, + SDL_SCANCODE_LANG6 = 149, + SDL_SCANCODE_LANG7 = 150, + SDL_SCANCODE_LANG8 = 151, + SDL_SCANCODE_LANG9 = 152, + + SDL_SCANCODE_ALTERASE = 153, + SDL_SCANCODE_SYSREQ = 154, + SDL_SCANCODE_CANCEL = 155, + SDL_SCANCODE_CLEAR = 156, + SDL_SCANCODE_PRIOR = 157, + SDL_SCANCODE_RETURN2 = 158, + SDL_SCANCODE_SEPARATOR = 159, + SDL_SCANCODE_OUT = 160, + SDL_SCANCODE_OPER = 161, + SDL_SCANCODE_CLEARAGAIN = 162, + SDL_SCANCODE_CRSEL = 163, + SDL_SCANCODE_EXSEL = 164, + + SDL_SCANCODE_KP_00 = 176, + SDL_SCANCODE_KP_000 = 177, + SDL_SCANCODE_THOUSANDSSEPARATOR = 178, + SDL_SCANCODE_DECIMALSEPARATOR = 179, + SDL_SCANCODE_CURRENCYUNIT = 180, + SDL_SCANCODE_CURRENCYSUBUNIT = 181, + SDL_SCANCODE_KP_LEFTPAREN = 182, + SDL_SCANCODE_KP_RIGHTPAREN = 183, + SDL_SCANCODE_KP_LEFTBRACE = 184, + SDL_SCANCODE_KP_RIGHTBRACE = 185, + SDL_SCANCODE_KP_TAB = 186, + SDL_SCANCODE_KP_BACKSPACE = 187, + SDL_SCANCODE_KP_A = 188, + SDL_SCANCODE_KP_B = 189, + SDL_SCANCODE_KP_C = 190, + SDL_SCANCODE_KP_D = 191, + SDL_SCANCODE_KP_E = 192, + SDL_SCANCODE_KP_F = 193, + SDL_SCANCODE_KP_XOR = 194, + SDL_SCANCODE_KP_POWER = 195, + SDL_SCANCODE_KP_PERCENT = 196, + SDL_SCANCODE_KP_LESS = 197, + SDL_SCANCODE_KP_GREATER = 198, + SDL_SCANCODE_KP_AMPERSAND = 199, + SDL_SCANCODE_KP_DBLAMPERSAND = 200, + SDL_SCANCODE_KP_VERTICALBAR = 201, + SDL_SCANCODE_KP_DBLVERTICALBAR = 202, + SDL_SCANCODE_KP_COLON = 203, + SDL_SCANCODE_KP_HASH = 204, + SDL_SCANCODE_KP_SPACE = 205, + SDL_SCANCODE_KP_AT = 206, + SDL_SCANCODE_KP_EXCLAM = 207, + SDL_SCANCODE_KP_MEMSTORE = 208, + SDL_SCANCODE_KP_MEMRECALL = 209, + SDL_SCANCODE_KP_MEMCLEAR = 210, + SDL_SCANCODE_KP_MEMADD = 211, + SDL_SCANCODE_KP_MEMSUBTRACT = 212, + SDL_SCANCODE_KP_MEMMULTIPLY = 213, + SDL_SCANCODE_KP_MEMDIVIDE = 214, + SDL_SCANCODE_KP_PLUSMINUS = 215, + SDL_SCANCODE_KP_CLEAR = 216, + SDL_SCANCODE_KP_CLEARENTRY = 217, + SDL_SCANCODE_KP_BINARY = 218, + SDL_SCANCODE_KP_OCTAL = 219, + SDL_SCANCODE_KP_DECIMAL = 220, + SDL_SCANCODE_KP_HEXADECIMAL = 221, + + SDL_SCANCODE_LCTRL = 224, + SDL_SCANCODE_LSHIFT = 225, + SDL_SCANCODE_LALT = 226, + SDL_SCANCODE_LGUI = 227, + SDL_SCANCODE_RCTRL = 228, + SDL_SCANCODE_RSHIFT = 229, + SDL_SCANCODE_RALT = 230, + SDL_SCANCODE_RGUI = 231, + + SDL_SCANCODE_MODE = 257, + + SDL_SCANCODE_AUDIONEXT = 258, + SDL_SCANCODE_AUDIOPREV = 259, + SDL_SCANCODE_AUDIOSTOP = 260, + SDL_SCANCODE_AUDIOPLAY = 261, + SDL_SCANCODE_AUDIOMUTE = 262, + SDL_SCANCODE_MEDIASELECT = 263, + SDL_SCANCODE_WWW = 264, + SDL_SCANCODE_MAIL = 265, + SDL_SCANCODE_CALCULATOR = 266, + SDL_SCANCODE_COMPUTER = 267, + SDL_SCANCODE_AC_SEARCH = 268, + SDL_SCANCODE_AC_HOME = 269, + SDL_SCANCODE_AC_BACK = 270, + SDL_SCANCODE_AC_FORWARD = 271, + SDL_SCANCODE_AC_STOP = 272, + SDL_SCANCODE_AC_REFRESH = 273, + SDL_SCANCODE_AC_BOOKMARKS = 274, + + SDL_SCANCODE_BRIGHTNESSDOWN = 275, + SDL_SCANCODE_BRIGHTNESSUP = 276, + SDL_SCANCODE_DISPLAYSWITCH = 277, + SDL_SCANCODE_KBDILLUMTOGGLE = 278, + SDL_SCANCODE_KBDILLUMDOWN = 279, + SDL_SCANCODE_KBDILLUMUP = 280, + SDL_SCANCODE_EJECT = 281, + SDL_SCANCODE_SLEEP = 282, + + SDL_SCANCODE_APP1 = 283, + SDL_SCANCODE_APP2 = 284, + + SDL_SCANCODE_AUDIOREWIND = 285, + SDL_SCANCODE_AUDIOFASTFORWARD = 286, + + SDL_NUM_SCANCODES = 512 + } +} +else { + enum SDL_Scancode { + SDL_SCANCODE_UNKNOWN = 0, + + SDL_SCANCODE_A = 4, + SDL_SCANCODE_B = 5, + SDL_SCANCODE_C = 6, + SDL_SCANCODE_D = 7, + SDL_SCANCODE_E = 8, + SDL_SCANCODE_F = 9, + SDL_SCANCODE_G = 10, + SDL_SCANCODE_H = 11, + SDL_SCANCODE_I = 12, + SDL_SCANCODE_J = 13, + SDL_SCANCODE_K = 14, + SDL_SCANCODE_L = 15, + SDL_SCANCODE_M = 16, + SDL_SCANCODE_N = 17, + SDL_SCANCODE_O = 18, + SDL_SCANCODE_P = 19, + SDL_SCANCODE_Q = 20, + SDL_SCANCODE_R = 21, + SDL_SCANCODE_S = 22, + SDL_SCANCODE_T = 23, + SDL_SCANCODE_U = 24, + SDL_SCANCODE_V = 25, + SDL_SCANCODE_W = 26, + SDL_SCANCODE_X = 27, + SDL_SCANCODE_Y = 28, + SDL_SCANCODE_Z = 29, + + SDL_SCANCODE_1 = 30, + SDL_SCANCODE_2 = 31, + SDL_SCANCODE_3 = 32, + SDL_SCANCODE_4 = 33, + SDL_SCANCODE_5 = 34, + SDL_SCANCODE_6 = 35, + SDL_SCANCODE_7 = 36, + SDL_SCANCODE_8 = 37, + SDL_SCANCODE_9 = 38, + SDL_SCANCODE_0 = 39, + + SDL_SCANCODE_RETURN = 40, + SDL_SCANCODE_ESCAPE = 41, + SDL_SCANCODE_BACKSPACE = 42, + SDL_SCANCODE_TAB = 43, + SDL_SCANCODE_SPACE = 44, + + SDL_SCANCODE_MINUS = 45, + SDL_SCANCODE_EQUALS = 46, + SDL_SCANCODE_LEFTBRACKET = 47, + SDL_SCANCODE_RIGHTBRACKET = 48, + SDL_SCANCODE_BACKSLASH = 49, + SDL_SCANCODE_NONUSHASH = 50, + SDL_SCANCODE_SEMICOLON = 51, + SDL_SCANCODE_APOSTROPHE = 52, + SDL_SCANCODE_GRAVE = 53, + SDL_SCANCODE_COMMA = 54, + SDL_SCANCODE_PERIOD = 55, + SDL_SCANCODE_SLASH = 56, + + SDL_SCANCODE_CAPSLOCK = 57, + + SDL_SCANCODE_F1 = 58, + SDL_SCANCODE_F2 = 59, + SDL_SCANCODE_F3 = 60, + SDL_SCANCODE_F4 = 61, + SDL_SCANCODE_F5 = 62, + SDL_SCANCODE_F6 = 63, + SDL_SCANCODE_F7 = 64, + SDL_SCANCODE_F8 = 65, + SDL_SCANCODE_F9 = 66, + SDL_SCANCODE_F10 = 67, + SDL_SCANCODE_F11 = 68, + SDL_SCANCODE_F12 = 69, + + SDL_SCANCODE_PRINTSCREEN = 70, + SDL_SCANCODE_SCROLLLOCK = 71, + SDL_SCANCODE_PAUSE = 72, + SDL_SCANCODE_INSERT = 73, + SDL_SCANCODE_HOME = 74, + SDL_SCANCODE_PAGEUP = 75, + SDL_SCANCODE_DELETE = 76, + SDL_SCANCODE_END = 77, + SDL_SCANCODE_PAGEDOWN = 78, + SDL_SCANCODE_RIGHT = 79, + SDL_SCANCODE_LEFT = 80, + SDL_SCANCODE_DOWN = 81, + SDL_SCANCODE_UP = 82, + + SDL_SCANCODE_NUMLOCKCLEAR = 83, + SDL_SCANCODE_KP_DIVIDE = 84, + SDL_SCANCODE_KP_MULTIPLY = 85, + SDL_SCANCODE_KP_MINUS = 86, + SDL_SCANCODE_KP_PLUS = 87, + SDL_SCANCODE_KP_ENTER = 88, + SDL_SCANCODE_KP_1 = 89, + SDL_SCANCODE_KP_2 = 90, + SDL_SCANCODE_KP_3 = 91, + SDL_SCANCODE_KP_4 = 92, + SDL_SCANCODE_KP_5 = 93, + SDL_SCANCODE_KP_6 = 94, + SDL_SCANCODE_KP_7 = 95, + SDL_SCANCODE_KP_8 = 96, + SDL_SCANCODE_KP_9 = 97, + SDL_SCANCODE_KP_0 = 98, + SDL_SCANCODE_KP_PERIOD = 99, + + SDL_SCANCODE_NONUSBACKSLASH = 100, + SDL_SCANCODE_APPLICATION = 101, + SDL_SCANCODE_POWER = 102, + SDL_SCANCODE_KP_EQUALS = 103, + SDL_SCANCODE_F13 = 104, + SDL_SCANCODE_F14 = 105, + SDL_SCANCODE_F15 = 106, + SDL_SCANCODE_F16 = 107, + SDL_SCANCODE_F17 = 108, + SDL_SCANCODE_F18 = 109, + SDL_SCANCODE_F19 = 110, + SDL_SCANCODE_F20 = 111, + SDL_SCANCODE_F21 = 112, + SDL_SCANCODE_F22 = 113, + SDL_SCANCODE_F23 = 114, + SDL_SCANCODE_F24 = 115, + SDL_SCANCODE_EXECUTE = 116, + SDL_SCANCODE_HELP = 117, + SDL_SCANCODE_MENU = 118, + SDL_SCANCODE_SELECT = 119, + SDL_SCANCODE_STOP = 120, + SDL_SCANCODE_AGAIN = 121, + SDL_SCANCODE_UNDO = 122, + SDL_SCANCODE_CUT = 123, + SDL_SCANCODE_COPY = 124, + SDL_SCANCODE_PASTE = 125, + SDL_SCANCODE_FIND = 126, + SDL_SCANCODE_MUTE = 127, + SDL_SCANCODE_VOLUMEUP = 128, + SDL_SCANCODE_VOLUMEDOWN = 129, + SDL_SCANCODE_KP_COMMA = 133, + SDL_SCANCODE_KP_EQUALSAS400 = 134, + + SDL_SCANCODE_INTERNATIONAL1 = 135, + SDL_SCANCODE_INTERNATIONAL2 = 136, + SDL_SCANCODE_INTERNATIONAL3 = 137, + SDL_SCANCODE_INTERNATIONAL4 = 138, + SDL_SCANCODE_INTERNATIONAL5 = 139, + SDL_SCANCODE_INTERNATIONAL6 = 140, + SDL_SCANCODE_INTERNATIONAL7 = 141, + SDL_SCANCODE_INTERNATIONAL8 = 142, + SDL_SCANCODE_INTERNATIONAL9 = 143, + SDL_SCANCODE_LANG1 = 144, + SDL_SCANCODE_LANG2 = 145, + SDL_SCANCODE_LANG3 = 146, + SDL_SCANCODE_LANG4 = 147, + SDL_SCANCODE_LANG5 = 148, + SDL_SCANCODE_LANG6 = 149, + SDL_SCANCODE_LANG7 = 150, + SDL_SCANCODE_LANG8 = 151, + SDL_SCANCODE_LANG9 = 152, + + SDL_SCANCODE_ALTERASE = 153, + SDL_SCANCODE_SYSREQ = 154, + SDL_SCANCODE_CANCEL = 155, + SDL_SCANCODE_CLEAR = 156, + SDL_SCANCODE_PRIOR = 157, + SDL_SCANCODE_RETURN2 = 158, + SDL_SCANCODE_SEPARATOR = 159, + SDL_SCANCODE_OUT = 160, + SDL_SCANCODE_OPER = 161, + SDL_SCANCODE_CLEARAGAIN = 162, + SDL_SCANCODE_CRSEL = 163, + SDL_SCANCODE_EXSEL = 164, + + SDL_SCANCODE_KP_00 = 176, + SDL_SCANCODE_KP_000 = 177, + SDL_SCANCODE_THOUSANDSSEPARATOR = 178, + SDL_SCANCODE_DECIMALSEPARATOR = 179, + SDL_SCANCODE_CURRENCYUNIT = 180, + SDL_SCANCODE_CURRENCYSUBUNIT = 181, + SDL_SCANCODE_KP_LEFTPAREN = 182, + SDL_SCANCODE_KP_RIGHTPAREN = 183, + SDL_SCANCODE_KP_LEFTBRACE = 184, + SDL_SCANCODE_KP_RIGHTBRACE = 185, + SDL_SCANCODE_KP_TAB = 186, + SDL_SCANCODE_KP_BACKSPACE = 187, + SDL_SCANCODE_KP_A = 188, + SDL_SCANCODE_KP_B = 189, + SDL_SCANCODE_KP_C = 190, + SDL_SCANCODE_KP_D = 191, + SDL_SCANCODE_KP_E = 192, + SDL_SCANCODE_KP_F = 193, + SDL_SCANCODE_KP_XOR = 194, + SDL_SCANCODE_KP_POWER = 195, + SDL_SCANCODE_KP_PERCENT = 196, + SDL_SCANCODE_KP_LESS = 197, + SDL_SCANCODE_KP_GREATER = 198, + SDL_SCANCODE_KP_AMPERSAND = 199, + SDL_SCANCODE_KP_DBLAMPERSAND = 200, + SDL_SCANCODE_KP_VERTICALBAR = 201, + SDL_SCANCODE_KP_DBLVERTICALBAR = 202, + SDL_SCANCODE_KP_COLON = 203, + SDL_SCANCODE_KP_HASH = 204, + SDL_SCANCODE_KP_SPACE = 205, + SDL_SCANCODE_KP_AT = 206, + SDL_SCANCODE_KP_EXCLAM = 207, + SDL_SCANCODE_KP_MEMSTORE = 208, + SDL_SCANCODE_KP_MEMRECALL = 209, + SDL_SCANCODE_KP_MEMCLEAR = 210, + SDL_SCANCODE_KP_MEMADD = 211, + SDL_SCANCODE_KP_MEMSUBTRACT = 212, + SDL_SCANCODE_KP_MEMMULTIPLY = 213, + SDL_SCANCODE_KP_MEMDIVIDE = 214, + SDL_SCANCODE_KP_PLUSMINUS = 215, + SDL_SCANCODE_KP_CLEAR = 216, + SDL_SCANCODE_KP_CLEARENTRY = 217, + SDL_SCANCODE_KP_BINARY = 218, + SDL_SCANCODE_KP_OCTAL = 219, + SDL_SCANCODE_KP_DECIMAL = 220, + SDL_SCANCODE_KP_HEXADECIMAL = 221, + + SDL_SCANCODE_LCTRL = 224, + SDL_SCANCODE_LSHIFT = 225, + SDL_SCANCODE_LALT = 226, + SDL_SCANCODE_LGUI = 227, + SDL_SCANCODE_RCTRL = 228, + SDL_SCANCODE_RSHIFT = 229, + SDL_SCANCODE_RALT = 230, + SDL_SCANCODE_RGUI = 231, + + SDL_SCANCODE_MODE = 257, + + SDL_SCANCODE_AUDIONEXT = 258, + SDL_SCANCODE_AUDIOPREV = 259, + SDL_SCANCODE_AUDIOSTOP = 260, + SDL_SCANCODE_AUDIOPLAY = 261, + SDL_SCANCODE_AUDIOMUTE = 262, + SDL_SCANCODE_MEDIASELECT = 263, + SDL_SCANCODE_WWW = 264, + SDL_SCANCODE_MAIL = 265, + SDL_SCANCODE_CALCULATOR = 266, + SDL_SCANCODE_COMPUTER = 267, + SDL_SCANCODE_AC_SEARCH = 268, + SDL_SCANCODE_AC_HOME = 269, + SDL_SCANCODE_AC_BACK = 270, + SDL_SCANCODE_AC_FORWARD = 271, + SDL_SCANCODE_AC_STOP = 272, + SDL_SCANCODE_AC_REFRESH = 273, + SDL_SCANCODE_AC_BOOKMARKS = 274, + + SDL_SCANCODE_BRIGHTNESSDOWN = 275, + SDL_SCANCODE_BRIGHTNESSUP = 276, + SDL_SCANCODE_DISPLAYSWITCH = 277, + SDL_SCANCODE_KBDILLUMTOGGLE = 278, + SDL_SCANCODE_KBDILLUMDOWN = 279, + SDL_SCANCODE_KBDILLUMUP = 280, + SDL_SCANCODE_EJECT = 281, + SDL_SCANCODE_SLEEP = 282, + + SDL_SCANCODE_APP1 = 283, + SDL_SCANCODE_APP2 = 284, + + SDL_NUM_SCANCODES = 512 + } +} +mixin(expandEnum!SDL_Scancode); \ No newline at end of file diff --git a/demos/external/imports/bindbc/sdl/bind/sdlshape.d b/demos/external/imports/bindbc/sdl/bind/sdlshape.d new file mode 100644 index 0000000..aed3410 --- /dev/null +++ b/demos/external/imports/bindbc/sdl/bind/sdlshape.d @@ -0,0 +1,63 @@ + +// Copyright Michael D. Parker 2018. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +module bindbc.sdl.bind.sdlshape; + +import bindbc.sdl.config; +import bindbc.sdl.bind.sdlpixels : SDL_Color; +import bindbc.sdl.bind.sdlstdinc : SDL_bool; +import bindbc.sdl.bind.sdlsurface : SDL_Surface; +import bindbc.sdl.bind.sdlvideo : SDL_Window; + +enum { + SDL_NONSHAPEABLE_WINDOW = -1, + SDL_INVALID_SHAPE_ARGUMENT = -2, + SDL_WINDOW_LACKS_SHAPE = -3, +} + +enum WindowShapeMode { + ShapeModeDefault, + ShapeModeBinarizeAlpha, + ShapeModeReverseBinarizeAlpha, + ShapeModeColorKey +} +mixin(expandEnum!WindowShapeMode); + +enum SDL_SHAPEMODEALPHA(WindowShapeMode mode) = (mode == ShapeModeDefault || mode == ShapeModeBinarizeAlpha || mode == ShapeModeReverseBinarizeAlpha); + +union SDL_WindowShapeParams { + ubyte binarizationCutoff; + SDL_Color colorKey; +} + +struct SDL_WindowShapeMode { + WindowShapeMode mode; + SDL_WindowShapeParams parameters; +} + +version(BindSDL_Static) { + extern(C) @nogc nothrow { + SDL_Window* SDL_CreateShapedWindow(const(char)*,uint,uint,uint,uint,uint); + SDL_bool SDL_IsShapedWindow(const(SDL_Window)*); + int SDL_SetWindowShape(SDL_Window*,SDL_Surface*,SDL_WindowShapeMode*); + int SDL_GetShapedWindowMode(SDL_Window*,SDL_WindowShapeMode*); + } +} +else { + extern(C) @nogc nothrow { + alias pSDL_CreateShapedWindow = SDL_Window* function(const(char)*,uint,uint,uint,uint,uint); + alias pSDL_IsShapedWindow = SDL_bool function(const(SDL_Window)*); + alias pSDL_SetWindowShape = int function(SDL_Window*,SDL_Surface*,SDL_WindowShapeMode*); + alias pSDL_GetShapedWindowMode = int function(SDL_Window*,SDL_WindowShapeMode*); + } + + __gshared { + pSDL_CreateShapedWindow SDL_CreateShapedWindow; + pSDL_IsShapedWindow SDL_IsShapedWindow; + pSDL_SetWindowShape SDL_SetWindowShape; + pSDL_GetShapedWindowMode SDL_GetShapedWindowMode; + } +} \ No newline at end of file diff --git a/demos/external/imports/bindbc/sdl/bind/sdlstdinc.d b/demos/external/imports/bindbc/sdl/bind/sdlstdinc.d new file mode 100644 index 0000000..68d77d8 --- /dev/null +++ b/demos/external/imports/bindbc/sdl/bind/sdlstdinc.d @@ -0,0 +1,42 @@ + +// Copyright Michael D. Parker 2018. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +module bindbc.sdl.bind.sdlstdinc; + +import bindbc.sdl.config; + +enum SDL_bool { + SDL_FALSE = 0, + SDL_TRUE = 1 +} + +mixin(expandEnum!SDL_bool); + +alias Sint8 = byte; +alias Uint8 = ubyte; +alias Sint16 = short; +alias Uint16 = ushort; +alias Sint32 = int; +alias Uint32 = uint; +alias Sint64 = long; +alias Uint64 = ulong; + +enum SDL_FOURCC(char A, char B, char C, char D) = ((A << 0) | (B << 8) | (C << 16) | (D << 24)); + +version(BindSDL_Static) { + extern(C) @nogc nothrow { + void SDL_free(void* mem); + } +} +else { + extern(C) @nogc nothrow { + alias pSDL_free = void function(void* mem); + } + + __gshared { + pSDL_free SDL_free; + } +} \ No newline at end of file diff --git a/demos/external/imports/bindbc/sdl/bind/sdlsurface.d b/demos/external/imports/bindbc/sdl/bind/sdlsurface.d new file mode 100644 index 0000000..1b5cc5a --- /dev/null +++ b/demos/external/imports/bindbc/sdl/bind/sdlsurface.d @@ -0,0 +1,230 @@ + +// Copyright Michael D. Parker 2018. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +module bindbc.sdl.bind.sdlsurface; + +import bindbc.sdl.config; +import bindbc.sdl.bind.sdlblendmode : SDL_BlendMode; +import bindbc.sdl.bind.sdlrect : SDL_Rect; +import bindbc.sdl.bind.sdlrwops; +import bindbc.sdl.bind.sdlpixels : SDL_Palette, SDL_PixelFormat; +import bindbc.sdl.bind.sdlstdinc : SDL_bool; + +enum { + SDL_SWSURFACE = 0, + SDL_PREALLOC = 0x00000001, + SDL_RLEACCEL = 0x00000002, + SDL_DONTFREE = 0x00000004, +} + +@nogc nothrow pure +bool SDL_MUSTLOCK(const(SDL_Surface)* S) +{ + pragma(inline, true); + return (S.flags & SDL_RLEACCEL) != 0; +} + +struct SDL_BlitMap; +struct SDL_Surface { + int flags; + SDL_PixelFormat* format; + int w, h; + int pitch; + void* pixels; + void* userdata; + int locked; + void* lock_data; + SDL_Rect clip_rect; + SDL_BlitMap* map; + int refcount; +} + +extern(C) nothrow alias SDL_blit = int function(SDL_Surface* src, SDL_Rect* srcrect, SDL_Surface* dst, SDL_Rect* dstrect); + +@nogc nothrow { + SDL_Surface* SDL_LoadBMP(const(char)* file) { + pragma(inline, true); + return SDL_LoadBMP_RW(SDL_RWFromFile(file,"rb"),1); + } + + int SDL_SaveBMP(SDL_Surface* surface,const(char)* file) { + pragma(inline, true); + return SDL_SaveBMP_RW(surface,SDL_RWFromFile(file,"wb"),1); + } +} + +alias SDL_BlitSurface = SDL_UpperBlit; +alias SDL_BlitScaled = SDL_UpperBlitScaled; + +static if(sdlSupport >= SDLSupport.sdl208) { + enum SDL_YUV_CONVERSION_MODE { + SDL_YUV_CONVERSION_JPEG, + SDL_YUV_CONVERSION_BT601, + SDL_YUV_CONVERSION_BT709, + SDL_YUV_CONVERSION_AUTOMATIC, + } + mixin(expandEnum!SDL_YUV_CONVERSION_MODE); +} + +version(BindSDL_Static) { + extern(C) @nogc nothrow { + SDL_Surface* SDL_CreateRGBSurface(uint,int,int,int,uint,uint,uint,uint); + SDL_Surface* SDL_CreateRGBSurfaceFrom(void*,int,int,int,int,uint,uint,uint,uint); + void SDL_FreeSurface(SDL_Surface*); + int SDL_SetSurfacePalette(SDL_Surface*,SDL_Palette*); + int SDL_LockSurface(SDL_Surface*); + int SDL_UnlockSurface(SDL_Surface*); + SDL_Surface* SDL_LoadBMP_RW(SDL_RWops*,int); + int SDL_SaveBMP_RW(SDL_Surface*,SDL_RWops*,int); + int SDL_SetSurfaceRLE(SDL_Surface*,int); + int SDL_SetColorKey(SDL_Surface*,int,uint); + int SDL_GetColorKey(SDL_Surface*,uint*); + int SDL_SetSurfaceColorMod(SDL_Surface*,ubyte,ubyte,ubyte); + int SDL_GetSurfaceColorMod(SDL_Surface*,ubyte*,ubyte*,ubyte*); + int SDL_SetSurfaceAlphaMod(SDL_Surface*,ubyte); + int SDL_GetSurfaceAlphaMod(SDL_Surface*,ubyte*); + int SDL_SetSurfaceBlendMode(SDL_Surface*,SDL_BlendMode); + int SDL_GetSurfaceBlendMode(SDL_Surface*,SDL_BlendMode*); + SDL_bool SDL_SetClipRect(SDL_Surface*,const(SDL_Rect)*); + void SDL_GetClipRect(SDL_Surface*,SDL_Rect*); + SDL_Surface* SDL_ConvertSurface(SDL_Surface*,const(SDL_PixelFormat)*,uint); + SDL_Surface* SDL_ConvertSurfaceFormat(SDL_Surface*,uint,uint); + int SDL_ConvertPixels(int,int,uint,const(void)*,int,uint,void*,int); + int SDL_FillRect(SDL_Surface*,const(SDL_Rect)*,uint); + int SDL_FillRects(SDL_Surface*,const(SDL_Rect)*,int,uint); + int SDL_UpperBlit(SDL_Surface*,const(SDL_Rect)*,SDL_Surface*,SDL_Rect*); + int SDL_LowerBlit(SDL_Surface*,SDL_Rect*,SDL_Surface*,SDL_Rect*); + int SDL_SoftStretch(SDL_Surface*,const(SDL_Rect)*,SDL_Surface*,const(SDL_Rect)*); + int SDL_UpperBlitScaled(SDL_Surface*,const(SDL_Rect)*,SDL_Surface*,SDL_Rect*); + int SDL_LowerBlitScaled(SDL_Surface*,SDL_Rect*,SDL_Surface*,SDL_Rect*); + + static if(sdlSupport >= SDLSupport.sdl205) { + SDL_Surface* SDL_CreateRGBSurfaceWithFormat(uint,int,int,int,uint); + SDL_Surface* SDL_CreateRGBSurfaceWithFormatFrom(void*,int,int,int,int,uint); + } + static if(sdlSupport >= SDLSupport.sdl205) { + SDL_Surface* SDL_DuplicateSurface(SDL_Surface*); + } + static if(sdlSupport >= SDLSupport.sdl208) { + void SDL_SetYUVConversionMode(SDL_YUV_CONVERSION_MODE); + SDL_YUV_CONVERSION_MODE SDL_GetYUVConversionMode(); + SDL_YUV_CONVERSION_MODE SDL_GetYUVConversionModeForResolution(int,int); + } + static if(sdlSupport >= SDLSupport.sdl209) { + SDL_bool SDL_HasColorKey(SDL_Surface*); + } + } +} +else { + extern(C) @nogc nothrow {alias pSDL_CreateRGBSurface = SDL_Surface* function(uint,int,int,int,uint,uint,uint,uint); + alias pSDL_CreateRGBSurfaceFrom = SDL_Surface* function(void*,int,int,int,int,uint,uint,uint,uint); + alias pSDL_FreeSurface = void function(SDL_Surface*); + alias pSDL_SetSurfacePalette = int function(SDL_Surface*,SDL_Palette*); + alias pSDL_LockSurface = int function(SDL_Surface*); + alias pSDL_UnlockSurface = int function(SDL_Surface*); + alias pSDL_LoadBMP_RW = SDL_Surface* function(SDL_RWops*,int); + alias pSDL_SaveBMP_RW = int function(SDL_Surface*,SDL_RWops*,int); + alias pSDL_SetSurfaceRLE = int function(SDL_Surface*,int); + alias pSDL_SetColorKey = int function(SDL_Surface*,int,uint); + alias pSDL_GetColorKey = int function(SDL_Surface*,uint*); + alias pSDL_SetSurfaceColorMod = int function(SDL_Surface*,ubyte,ubyte,ubyte); + alias pSDL_GetSurfaceColorMod = int function(SDL_Surface*,ubyte*,ubyte*,ubyte*); + alias pSDL_SetSurfaceAlphaMod = int function(SDL_Surface*,ubyte); + alias pSDL_GetSurfaceAlphaMod = int function(SDL_Surface*,ubyte*); + alias pSDL_SetSurfaceBlendMode = int function(SDL_Surface*,SDL_BlendMode); + alias pSDL_GetSurfaceBlendMode = int function(SDL_Surface*,SDL_BlendMode*); + alias pSDL_SetClipRect = SDL_bool function(SDL_Surface*,const(SDL_Rect)*); + alias pSDL_GetClipRect = void function(SDL_Surface*,SDL_Rect*); + alias pSDL_ConvertSurface = SDL_Surface* function(SDL_Surface*,const(SDL_PixelFormat)*,uint); + alias pSDL_ConvertSurfaceFormat = SDL_Surface* function(SDL_Surface*,uint,uint); + alias pSDL_ConvertPixels = int function(int,int,uint,const(void)*,int,uint,void*,int); + alias pSDL_FillRect = int function(SDL_Surface*,const(SDL_Rect)*,uint); + alias pSDL_FillRects = int function(SDL_Surface*,const(SDL_Rect)*,int,uint); + alias pSDL_UpperBlit = int function(SDL_Surface*,const(SDL_Rect)*,SDL_Surface*,SDL_Rect*); + alias pSDL_LowerBlit = int function(SDL_Surface*,SDL_Rect*,SDL_Surface*,SDL_Rect*); + alias pSDL_SoftStretch = int function(SDL_Surface*,const(SDL_Rect)*,SDL_Surface*,const(SDL_Rect)*); + alias pSDL_UpperBlitScaled = int function(SDL_Surface*,const(SDL_Rect)*,SDL_Surface*,SDL_Rect*); + alias pSDL_LowerBlitScaled = int function(SDL_Surface*,SDL_Rect*,SDL_Surface*,SDL_Rect*); + } + + __gshared { + pSDL_CreateRGBSurface SDL_CreateRGBSurface; + pSDL_CreateRGBSurfaceFrom SDL_CreateRGBSurfaceFrom; + pSDL_FreeSurface SDL_FreeSurface; + pSDL_SetSurfacePalette SDL_SetSurfacePalette; + pSDL_LockSurface SDL_LockSurface; + pSDL_UnlockSurface SDL_UnlockSurface; + pSDL_LoadBMP_RW SDL_LoadBMP_RW; + pSDL_SaveBMP_RW SDL_SaveBMP_RW; + pSDL_SetSurfaceRLE SDL_SetSurfaceRLE; + pSDL_SetColorKey SDL_SetColorKey; + pSDL_GetColorKey SDL_GetColorKey; + pSDL_SetSurfaceColorMod SDL_SetSurfaceColorMod; + pSDL_GetSurfaceColorMod SDL_GetSurfaceColorMod; + pSDL_SetSurfaceAlphaMod SDL_SetSurfaceAlphaMod; + pSDL_GetSurfaceAlphaMod SDL_GetSurfaceAlphaMod; + pSDL_SetSurfaceBlendMode SDL_SetSurfaceBlendMode; + pSDL_GetSurfaceBlendMode SDL_GetSurfaceBlendMode; + pSDL_SetClipRect SDL_SetClipRect; + pSDL_GetClipRect SDL_GetClipRect; + pSDL_ConvertSurface SDL_ConvertSurface; + pSDL_ConvertSurfaceFormat SDL_ConvertSurfaceFormat; + pSDL_ConvertPixels SDL_ConvertPixels; + pSDL_FillRect SDL_FillRect; + pSDL_FillRects SDL_FillRects; + pSDL_UpperBlit SDL_UpperBlit; + pSDL_LowerBlit SDL_LowerBlit; + pSDL_SoftStretch SDL_SoftStretch; + pSDL_UpperBlitScaled SDL_UpperBlitScaled; + pSDL_LowerBlitScaled SDL_LowerBlitScaled; + } + + static if(sdlSupport >= SDLSupport.sdl205) { + extern(C) @nogc nothrow { + alias pSDL_CreateRGBSurfaceWithFormat = SDL_Surface* function(uint,int,int,int,uint); + alias pSDL_CreateRGBSurfaceWithFormatFrom = SDL_Surface* function(void*,int,int,int,int,uint); + } + + __gshared { + pSDL_CreateRGBSurfaceWithFormat SDL_CreateRGBSurfaceWithFormat; + pSDL_CreateRGBSurfaceWithFormatFrom SDL_CreateRGBSurfaceWithFormatFrom; + } + } + + static if(sdlSupport >= SDLSupport.sdl205) { + extern(C) @nogc nothrow { + alias pSDL_DuplicateSurface = SDL_Surface* function(SDL_Surface*); + } + + __gshared { + pSDL_DuplicateSurface SDL_DuplicateSurface; + } + } + + static if(sdlSupport >= SDLSupport.sdl208) { + extern(C) @nogc nothrow { + alias pSDL_SetYUVConversionMode = void function(SDL_YUV_CONVERSION_MODE); + alias pSDL_GetYUVConversionMode = SDL_YUV_CONVERSION_MODE function(); + alias pSDL_GetYUVConversionModeForResolution = SDL_YUV_CONVERSION_MODE function(int,int); + } + + __gshared { + pSDL_SetYUVConversionMode SDL_SetYUVConversionMode; + pSDL_GetYUVConversionMode SDL_GetYUVConversionMode; + pSDL_GetYUVConversionModeForResolution SDL_GetYUVConversionModeForResolution; + } + } + + static if(sdlSupport >= SDLSupport.sdl209) { + extern(C) @nogc nothrow { + alias pSDL_HasColorKey = SDL_bool function(SDL_Surface*); + } + + __gshared { + pSDL_HasColorKey SDL_HasColorKey; + } + } +} \ No newline at end of file diff --git a/demos/external/imports/bindbc/sdl/bind/sdlsystem.d b/demos/external/imports/bindbc/sdl/bind/sdlsystem.d new file mode 100644 index 0000000..39eb0b3 --- /dev/null +++ b/demos/external/imports/bindbc/sdl/bind/sdlsystem.d @@ -0,0 +1,152 @@ + +// Copyright Michael D. Parker 2018. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +module bindbc.sdl.bind.sdlsystem; + +import bindbc.sdl.config; +import bindbc.sdl.bind.sdlrender : SDL_Renderer; +import bindbc.sdl.bind.sdlstdinc : SDL_bool; + +version(Android) { + enum int SDL_ANDROID_EXTERNAL_STORAGE_READ = 0x01; + enum int SDL_ANDROID_EXTERNAL_STORAGE_WRITE = 0x02; +} + +static if(sdlSupport >= SDLSupport.sdl201) { + version(Windows) struct IDirect3DDevice9; +} + +static if(sdlSupport >= SDLSupport.sdl204) { + version(Windows) { + extern(C) nothrow alias SDL_WindowsMessageHook = void function(void*,void*,uint,ulong,long); + } +} + +version(BindSDL_Static) { + extern(C) @nogc nothrow { + version(Android) { + void* SDL_AndroidGetJNIEnv(); + void* SDL_AndroidGetActivity(); + const(char)* SDL_AndroidGetInternalStoragePath(); + int SDL_AndroidGetInternalStorageState(); + const(char)* SDL_AndroidGetExternalStoragePath(); + + static if(sdlSupport >= SDLSupport.sdl208) { + SDL_bool SDL_IsAndroidTV(); + } + static if(sdlSupport >= SDLSupport.sdl209) { + SDL_bool SDL_IsChromebook(); + SDL_bool SDL_IsDeXMode(); + void SDL_AndroidBackButton(); + } + } + else version(Windows) { + static if(sdlSupport >= SDLSupport.sdl201) { + int SDL_Direct3D9GetAdapterIndex(int); + IDirect3DDevice9* SDL_RenderGetD3D9Device(SDL_Renderer*); + } + static if(sdlSupport >= SDLSupport.sdl202) { + SDL_bool SDL_DXGIGetOutputInfo(int,int*,int*); + } + static if(sdlSupport >= SDLSupport.sdl204) { + void SDL_SetWindowsMessageHook(SDL_WindowsMessageHook,void*); + } + } + else version(linux) { + static if(sdlSupport >= SDLSupport.sdl209) { + int SDL_LinuxSetThreadPriority(long,int); + } + } + } +} +else { + version(Android) { + extern(C) @nogc nothrow { + alias pSDL_AndroidGetJNIEnv = void* function(); + alias pSDL_AndroidGetActivity = void* function(); + alias pSDL_AndroidGetInternalStoragePath = const(char)* function(); + alias pSDL_AndroidGetInternalStorageState = int function(); + alias pSDL_AndroidGetExternalStoragePath = const(char)* function(); + } + + __gshared { + pSDL_AndroidGetJNIEnv SDL_AndroidGetJNIEnv; + pSDL_AndroidGetActivity SDL_AndroidGetActivity; + + pSDL_AndroidGetInternalStoragePath SDL_AndroidGetInternalStoragePath; + pSDL_AndroidGetInternalStorageState SDL_AndroidGetInternalStorageState; + pSDL_AndroidGetExternalStoragePath SDL_AndroidGetExternalStoragePath; + } + + static if(sdlSupport >= SDLSupport.sdl208) { + extern(C) @nogc nothrow { + alias pSDL_IsAndroidTV = SDL_bool function(); + } + + __gshared { + pSDL_IsAndroidTV SDL_IsAndroidTV; + } + } + + static if(sdlSupport >= SDLSupport.sdl209) { + extern(C) @nogc nothrow { + alias pSDL_IsChromebook = SDL_bool function(); + alias pSDL_IsDeXMode = SDL_bool function(); + alias pSDL_AndroidBackButton = void function(); + } + + __gshared { + pSDL_IsChromebook SDL_IsChromebook; + pSDL_IsDeXMode SDL_IsDeXMode; + pSDL_AndroidBackButton SDL_AndroidBackButton; + } + } + } + else version(Windows) { + static if(sdlSupport >= SDLSupport.sdl201) { + extern(C) @nogc nothrow { + alias pSDL_Direct3D9GetAdapterIndex = int function(int); + alias pSDL_RenderGetD3D9Device = IDirect3DDevice9* function(SDL_Renderer*); + } + + __gshared { + pSDL_Direct3D9GetAdapterIndex SDL_Direct3D9GetAdapterIndex ; + pSDL_RenderGetD3D9Device SDL_RenderGetD3D9Device; + } + } + + static if(sdlSupport >= SDLSupport.sdl202) { + extern(C) @nogc nothrow { + alias pSDL_DXGIGetOutputInfo = SDL_bool function(int,int*,int*); + } + + __gshared { + pSDL_DXGIGetOutputInfo SDL_DXGIGetOutputInfo; + } + } + + static if(sdlSupport >= SDLSupport.sdl204) { + extern(C) @nogc nothrow { + alias pSDL_SetWindowsMessageHook = void function(SDL_WindowsMessageHook,void*); + } + + __gshared { + pSDL_SetWindowsMessageHook SDL_SetWindowsMessageHook; + } + } + } + else version(linux) { + static if(sdlSupport >= SDLSupport.sdl209) { + extern(C) @nogc nothrow { + alias pSDL_LinuxSetThreadPriority = int function(long,int); + } + + __gshared { + pSDL_LinuxSetThreadPriority SDL_LinuxSetThreadPriority; + } + } + } +} \ No newline at end of file diff --git a/demos/external/imports/bindbc/sdl/bind/sdlsyswm.d b/demos/external/imports/bindbc/sdl/bind/sdlsyswm.d new file mode 100644 index 0000000..02951c8 --- /dev/null +++ b/demos/external/imports/bindbc/sdl/bind/sdlsyswm.d @@ -0,0 +1,240 @@ + +// Copyright Michael D. Parker 2018. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +module bindbc.sdl.bind.sdlsyswm; + +//import core.stdc.config : c_long; +alias int c_long; +import bindbc.sdl.config; +import bindbc.sdl.bind.sdlstdinc : SDL_bool; +import bindbc.sdl.bind.sdlversion : SDL_version; +import bindbc.sdl.bind.sdlvideo : SDL_Window; + +static if(sdlSupport >= SDLSupport.sdl205) { + enum SDL_SYSWM_TYPE { + SDL_SYSWM_UNKNOWN, + SDL_SYSWM_WINDOWS, + SDL_SYSWM_X11, + SDL_SYSWM_DIRECTFB, + SDL_SYSWM_COCOA, + SDL_SYSWM_UIKIT, + SDL_SYSWM_WAYLAND, + SDL_SYSWM_MIR, + SDL_SYSWM_WINRT, + SDL_SYSWM_ANDROID, + SDL_SYSWM_VIVANTE, + SDL_SYSWM_OS2, + } +} +else static if(sdlSupport >= SDLSupport.sdl205) { + enum SDL_SYSWM_TYPE { + SDL_SYSWM_UNKNOWN, + SDL_SYSWM_WINDOWS, + SDL_SYSWM_X11, + SDL_SYSWM_DIRECTFB, + SDL_SYSWM_COCOA, + SDL_SYSWM_UIKIT, + SDL_SYSWM_WAYLAND, + SDL_SYSWM_MIR, + SDL_SYSWM_WINRT, + SDL_SYSWM_ANDROID, + SDL_SYSWM_VIVANTE, + } +} +else static if(sdlSupport >= SDLSupport.sdl204) { + enum SDL_SYSWM_TYPE { + SDL_SYSWM_UNKNOWN, + SDL_SYSWM_WINDOWS, + SDL_SYSWM_X11, + SDL_SYSWM_DIRECTFB, + SDL_SYSWM_COCOA, + SDL_SYSWM_UIKIT, + SDL_SYSWM_WAYLAND, + SDL_SYSWM_MIR, + SDL_SYSWM_WINRT, + SDL_SYSWM_ANDROID, + } +} +else static if(sdlSupport >= SDLSupport.sdl203) { + enum SDL_SYSWM_TYPE { + SDL_SYSWM_UNKNOWN, + SDL_SYSWM_WINDOWS, + SDL_SYSWM_X11, + SDL_SYSWM_DIRECTFB, + SDL_SYSWM_COCOA, + SDL_SYSWM_UIKIT, + SDL_SYSWM_WAYLAND, + SDL_SYSWM_MIR, + SDL_SYSWM_WINRT, + } +} +else static if(sdlSupport >= SDLSupport.sdl202) { + enum SDL_SYSWM_TYPE { + SDL_SYSWM_UNKNOWN, + SDL_SYSWM_WINDOWS, + SDL_SYSWM_X11, + SDL_SYSWM_DIRECTFB, + SDL_SYSWM_COCOA, + SDL_SYSWM_UIKIT, + SDL_SYSWM_WAYLAND, + SDL_SYSWM_MIR, + } +} +else { + enum SDL_SYSWM_TYPE { + SDL_SYSWM_UNKNOWN, + SDL_SYSWM_WINDOWS, + SDL_SYSWM_X11, + SDL_SYSWM_DIRECTFB, + SDL_SYSWM_COCOA, + SDL_SYSWM_UIKIT, + } +} +mixin(expandEnum!SDL_SYSWM_TYPE); + +version(Windows) { + // I don't want to import core.sys.windows.windows just for these + version(Win64) { + alias wparam = ulong; + alias lparam = long; + }else { + alias wparam = uint; + alias lparam = int; + } +} + +struct SDL_SysWMmsg { + SDL_version version_; + SDL_SYSWM_TYPE subsystem; + union msg_ { + version(Windows) { + struct win_ { + void* hwnd; + uint msg; + wparam wParam; + lparam lParam; + } + win_ win; + } + else version(OSX) { + struct cocoa_ { + int dummy; + } + cocoa_ cocoa; + } + else version(linux) { + struct dfb_ { + void* event; + } + dfb_ dfb; + } + + version(Posix) { + struct x11_ { + c_long[24] pad; // sufficient size for any X11 event + } + x11_ x11; + } + + static if(sdlSupport >= SDLSupport.sdl205) { + struct vivante_ { + int dummy; + } + vivante_ vivante; + } + + int dummy; + } + msg_ msg; +} + +struct SDL_SysWMinfo { + SDL_version version_; + SDL_SYSWM_TYPE subsystem; + + union info_ { + version(Windows) { + struct win_ { + void* window; + static if(sdlSupport >= SDLSupport.sdl204) void* hdc; + static if(sdlSupport >= SDLSupport.sdl206) void* hinstance; + } + win_ win; + } + else version(OSX) { + struct cocoa_ { + void* window; + } + cocoa_ cocoa; + + struct uikit_ { + void *window; + } + uikit_ uikit; + + } + else version(linux) { + struct dfb_ { + void *dfb; + void *window; + void *surface; + } + dfb_ dfb; + + static if(sdlSupport >= SDLSupport.sdl202) { + struct wl_ { + void *display; + void *surface; + void *shell_surface; + } + wl_ wl; + + struct mir_ { + void *connection; + void *surface; + } + mir_ mir; + } + } + + version(Posix) { + struct x11_ { + void* display; + uint window; + } + x11_ x11; + } + + static if(sdlSupport >= SDLSupport.sdl204) { + version(Android) { + struct android_ { + void* window; + void* surface; + } + android_ android; + } + } + + static if(sdlSupport >= SDLSupport.sdl206) ubyte[64] dummy; + else int dummy; + } + info_ info; +} + +version(BindSDL_Static) { + extern(C) @nogc nothrow { + SDL_bool SDL_GetWindowWMInfo(SDL_Window*,SDL_SysWMinfo*); + } +} +else { + extern(C) @nogc nothrow { + alias pSDL_GetWindowWMInfo = SDL_bool function(SDL_Window*,SDL_SysWMinfo*); + } + + __gshared { + pSDL_GetWindowWMInfo SDL_GetWindowWMInfo; + } +} \ No newline at end of file diff --git a/demos/external/imports/bindbc/sdl/bind/sdltimer.d b/demos/external/imports/bindbc/sdl/bind/sdltimer.d new file mode 100644 index 0000000..1661a41 --- /dev/null +++ b/demos/external/imports/bindbc/sdl/bind/sdltimer.d @@ -0,0 +1,51 @@ + +// Copyright Michael D. Parker 2018. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +module bindbc.sdl.bind.sdltimer; + +import bindbc.sdl.bind.sdlstdinc : SDL_bool; + +extern(C) nothrow alias SDL_TimerCallback = uint function(uint interval, void* param); +alias SDL_TimerID = int; + +// This was added to SDL 2.0.1 as a macro, but it's +// useful & has no dependency on the library version, +// so it's here for 2.0.0 as well. +@nogc nothrow pure +bool SDL_TICKS_PASSED(uint A, uint B) { + pragma(inline, true); + return cast(int)(B - A) <= 0; +} + +version(BindSDL_Static) { + extern(C) @nogc nothrow { + uint SDL_GetTicks(); + ulong SDL_GetPerformanceCounter(); + ulong SDL_GetPerformanceFrequency(); + void SDL_Delay(uint); + SDL_TimerID SDL_AddTimer(uint,SDL_TimerCallback,void*); + SDL_bool SDL_RemoveTimer(SDL_TimerID); + } +} +else { + extern(C) @nogc nothrow { + alias pSDL_GetTicks = uint function(); + alias pSDL_GetPerformanceCounter = ulong function(); + alias pSDL_GetPerformanceFrequency = ulong function(); + alias pSDL_Delay = void function(uint); + alias pSDL_AddTimer = SDL_TimerID function(uint,SDL_TimerCallback,void*); + alias pSDL_RemoveTimer = SDL_bool function(SDL_TimerID); + } + + __gshared { + pSDL_GetTicks SDL_GetTicks; + pSDL_GetPerformanceCounter SDL_GetPerformanceCounter; + pSDL_GetPerformanceFrequency SDL_GetPerformanceFrequency; + pSDL_Delay SDL_Delay; + pSDL_AddTimer SDL_AddTimer; + pSDL_RemoveTimer SDL_RemoveTimer; + } +} \ No newline at end of file diff --git a/demos/external/imports/bindbc/sdl/bind/sdltouch.d b/demos/external/imports/bindbc/sdl/bind/sdltouch.d new file mode 100644 index 0000000..182e08f --- /dev/null +++ b/demos/external/imports/bindbc/sdl/bind/sdltouch.d @@ -0,0 +1,67 @@ + +// Copyright Michael D. Parker 2018. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +module bindbc.sdl.bind.sdltouch; + +import bindbc.sdl.config; + +alias SDL_TouchID = long; +alias SDL_FingerID = long; + +struct SDL_Finger { + SDL_FingerID id; + float x; + float y; + float pressure; +} + +enum DL_TOUCH_MOUSEID = cast(uint)-1; + +static if(sdlSupport >= SDLSupport.sdl2010) { + enum SDL_TouchDeviceType { + SDL_TOUCH_DEVICE_INVALID = -1, + SDL_TOUCH_DEVICE_DIRECT, + SDL_TOUCH_DEVICE_INDIRECT_ABSOLUTE, + SDL_TOUCH_DEVICE_INDIRECT_RELATIVE, + } + mixin(expandEnum!SDL_TouchDeviceType); + + enum SDL_MOUSE_TOUCHID = -1L; +} + +version(BindSDL_Static) { + extern(C) @nogc nothrow { + int SDL_GetNumTouchDevices(); + SDL_TouchID SDL_GetTouchDevice(int); + int SDL_GetNumTouchFingers(SDL_TouchID); + SDL_Finger* SDL_GetTouchFinger(SDL_TouchID,int); + } + static if(sdlSupport >= SDLSupport.sdl2010) { + SDL_TouchDeviceType SDL_GetTouchDeviceType(SDL_TouchID); + } +} +else { + extern(C) @nogc nothrow { + alias pSDL_GetNumTouchDevices = int function(); + alias pSDL_GetTouchDevice = SDL_TouchID function(int); + alias pSDL_GetNumTouchFingers = int function(SDL_TouchID); + alias pSDL_GetTouchFinger = SDL_Finger* function(SDL_TouchID,int); + } + __gshared { + pSDL_GetNumTouchDevices SDL_GetNumTouchDevices; + pSDL_GetTouchDevice SDL_GetTouchDevice; + pSDL_GetNumTouchFingers SDL_GetNumTouchFingers; + pSDL_GetTouchFinger SDL_GetTouchFinger; + } + static if(sdlSupport >= SDLSupport.sdl2010) { + extern(C) @nogc nothrow { + alias pSDL_GetTouchDeviceType = SDL_TouchDeviceType function(SDL_TouchID); + } + __gshared { + pSDL_GetTouchDeviceType SDL_GetTouchDeviceType; + } + } +} \ No newline at end of file diff --git a/demos/external/imports/bindbc/sdl/bind/sdlversion.d b/demos/external/imports/bindbc/sdl/bind/sdlversion.d new file mode 100644 index 0000000..dd05628 --- /dev/null +++ b/demos/external/imports/bindbc/sdl/bind/sdlversion.d @@ -0,0 +1,83 @@ + +// Copyright Michael D. Parker 2018. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +module bindbc.sdl.bind.sdlversion; + +struct SDL_version { + ubyte major; + ubyte minor; + ubyte patch; +} + +enum SDL_MAJOR_VERSION = 2; +enum SDL_MINOR_VERSION = 0; + +version(SDL_201) { + enum ubyte SDL_PATCHLEVEL = 1; +} +else version(SDL_202) { + enum ubyte SDL_PATCHLEVEL = 2; +} +else version(SDL_203) { + enum ubyte SDL_PATCHLEVEL = 3; +} +else version(SDL_204) { + enum ubyte SDL_PATCHLEVEL = 4; +} +else version(SDL_205) { + enum ubyte SDL_PATCHLEVEL = 5; +} +else version(SDL_206) { + enum ubyte SDL_PATCHLEVEL = 6; +} +else version(SDL_207) { + enum ubyte SDL_PATCHLEVEL = 7; +} +else version(SDL_208) { + enum ubyte SDL_PATCHLEVEL = 8; +} +else version(SDL_209) { + enum ubyte SDL_PATCHLEVEL = 9; +} +else version(SDL_2010) { + enum ubyte SDL_PATCHLEVEL = 10; +} +else { + enum ubyte SDL_PATCHLEVEL = 0; +} + +@nogc nothrow pure +void SDL_VERSION(SDL_version* x) { + pragma(inline, true); + x.major = SDL_MAJOR_VERSION; + x.minor = SDL_MINOR_VERSION; + x.patch = SDL_PATCHLEVEL; +} + +enum SDL_VERSIONNUM(ubyte X, ubyte Y, ubyte Z) = X*1000 + Y*100 + Z; +enum SDL_COMPILEDVERSION = SDL_VERSIONNUM!(SDL_MAJOR_VERSION, SDL_MINOR_VERSION, SDL_PATCHLEVEL); +enum SDL_VERSION_ATLEAST(ubyte X, ubyte Y, ubyte Z) = SDL_COMPILEDVERSION >= SDL_VERSIONNUM!(X, Y, Z); + +version(BindSDL_Static) { + extern(C) @nogc nothrow { + void SDL_GetVersion(SDL_version*); + const(char)* SDL_GetRevision(); + int SDL_GetRevisionNumber(); + } +} +else { + extern(C) @nogc nothrow { + alias pSDL_GetVersion = void function(SDL_version*); + alias pSDL_GetRevision = const(char)* function(); + alias pSDL_GetRevisionNumber = int function(); + } + + __gshared { + pSDL_GetVersion SDL_GetVersion; + pSDL_GetRevision SDL_GetRevision; + pSDL_GetRevisionNumber SDL_GetRevisionNumber; + } +} \ No newline at end of file diff --git a/demos/external/imports/bindbc/sdl/bind/sdlvideo.d b/demos/external/imports/bindbc/sdl/bind/sdlvideo.d new file mode 100644 index 0000000..3384d8e --- /dev/null +++ b/demos/external/imports/bindbc/sdl/bind/sdlvideo.d @@ -0,0 +1,677 @@ + +// Copyright Michael D. Parker 2018. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +module bindbc.sdl.bind.sdlvideo; + +import bindbc.sdl.config; + +import bindbc.sdl.bind.sdlrect : SDL_Rect; +import bindbc.sdl.bind.sdlstdinc : SDL_bool; +import bindbc.sdl.bind.sdlsurface : SDL_Surface; + +struct SDL_DisplayMode { + uint format; + int w; + int h; + int refresh_rate; + void* driverdata; +} + +struct SDL_Window; + +static if(sdlSupport >= SDLSupport.sdl206) { + enum SDL_WindowFlags { + SDL_WINDOW_FULLSCREEN = 0x00000001, + SDL_WINDOW_OPENGL = 0x00000002, + SDL_WINDOW_SHOWN = 0x00000004, + SDL_WINDOW_HIDDEN = 0x00000008, + SDL_WINDOW_BORDERLESS = 0x00000010, + SDL_WINDOW_RESIZABLE = 0x00000020, + SDL_WINDOW_MINIMIZED = 0x00000040, + SDL_WINDOW_MAXIMIZED = 0x00000080, + SDL_WINDOW_INPUT_GRABBED = 0x00000100, + SDL_WINDOW_INPUT_FOCUS = 0x00000200, + SDL_WINDOW_MOUSE_FOCUS = 0x00000400, + SDL_WINDOW_FULLSCREEN_DESKTOP = SDL_WINDOW_FULLSCREEN | 0x00001000, + SDL_WINDOW_FOREIGN = 0x00000800, + SDL_WINDOW_ALLOW_HIGHDPI = 0x00002000, + SDL_WINDOW_MOUSE_CAPTURE = 0x00004000, + SDL_WINDOW_ALWAYS_ON_TOP = 0x00008000, + SDL_WINDOW_SKIP_TASKBAR = 0x00010000, + SDL_WINDOW_UTILITY = 0x00020000, + SDL_WINDOW_TOOLTIP = 0x00040000, + SDL_WINDOW_POPUP_MENU = 0x00080000, + SDL_WINDOW_VULKAN = 0x10000000, + } +} +else static if(sdlSupport >= SDLSupport.sdl205) { + enum SDL_WindowFlags { + SDL_WINDOW_FULLSCREEN = 0x00000001, + SDL_WINDOW_OPENGL = 0x00000002, + SDL_WINDOW_SHOWN = 0x00000004, + SDL_WINDOW_HIDDEN = 0x00000008, + SDL_WINDOW_BORDERLESS = 0x00000010, + SDL_WINDOW_RESIZABLE = 0x00000020, + SDL_WINDOW_MINIMIZED = 0x00000040, + SDL_WINDOW_MAXIMIZED = 0x00000080, + SDL_WINDOW_INPUT_GRABBED = 0x00000100, + SDL_WINDOW_INPUT_FOCUS = 0x00000200, + SDL_WINDOW_MOUSE_FOCUS = 0x00000400, + SDL_WINDOW_FULLSCREEN_DESKTOP = SDL_WINDOW_FULLSCREEN | 0x00001000, + SDL_WINDOW_FOREIGN = 0x00000800, + SDL_WINDOW_ALLOW_HIGHDPI = 0x00002000, + SDL_WINDOW_MOUSE_CAPTURE = 0x00004000, + SDL_WINDOW_ALWAYS_ON_TOP = 0x00008000, + SDL_WINDOW_SKIP_TASKBAR = 0x00010000, + SDL_WINDOW_UTILITY = 0x00020000, + SDL_WINDOW_TOOLTIP = 0x00040000, + SDL_WINDOW_POPUP_MENU = 0x00080000, + } +} +else static if(sdlSupport >= SDLSupport.sdl204) { + enum SDL_WindowFlags { + SDL_WINDOW_FULLSCREEN = 0x00000001, + SDL_WINDOW_OPENGL = 0x00000002, + SDL_WINDOW_SHOWN = 0x00000004, + SDL_WINDOW_HIDDEN = 0x00000008, + SDL_WINDOW_BORDERLESS = 0x00000010, + SDL_WINDOW_RESIZABLE = 0x00000020, + SDL_WINDOW_MINIMIZED = 0x00000040, + SDL_WINDOW_MAXIMIZED = 0x00000080, + SDL_WINDOW_INPUT_GRABBED = 0x00000100, + SDL_WINDOW_INPUT_FOCUS = 0x00000200, + SDL_WINDOW_MOUSE_FOCUS = 0x00000400, + SDL_WINDOW_FULLSCREEN_DESKTOP = SDL_WINDOW_FULLSCREEN | 0x00001000, + SDL_WINDOW_FOREIGN = 0x00000800, + SDL_WINDOW_ALLOW_HIGHDPI = 0x00002000, + SDL_WINDOW_MOUSE_CAPTURE = 0x00004000, + } +} +else static if(sdlSupport >= SDLSupport.sdl201) { + enum SDL_WindowFlags { + SDL_WINDOW_FULLSCREEN = 0x00000001, + SDL_WINDOW_OPENGL = 0x00000002, + SDL_WINDOW_SHOWN = 0x00000004, + SDL_WINDOW_HIDDEN = 0x00000008, + SDL_WINDOW_BORDERLESS = 0x00000010, + SDL_WINDOW_RESIZABLE = 0x00000020, + SDL_WINDOW_MINIMIZED = 0x00000040, + SDL_WINDOW_MAXIMIZED = 0x00000080, + SDL_WINDOW_INPUT_GRABBED = 0x00000100, + SDL_WINDOW_INPUT_FOCUS = 0x00000200, + SDL_WINDOW_MOUSE_FOCUS = 0x00000400, + SDL_WINDOW_FULLSCREEN_DESKTOP = SDL_WINDOW_FULLSCREEN | 0x00001000, + SDL_WINDOW_FOREIGN = 0x00000800, + SDL_WINDOW_ALLOW_HIGHDPI = 0x00002000, + } +} +else { + enum SDL_WindowFlags { + SDL_WINDOW_FULLSCREEN = 0x00000001, + SDL_WINDOW_OPENGL = 0x00000002, + SDL_WINDOW_SHOWN = 0x00000004, + SDL_WINDOW_HIDDEN = 0x00000008, + SDL_WINDOW_BORDERLESS = 0x00000010, + SDL_WINDOW_RESIZABLE = 0x00000020, + SDL_WINDOW_MINIMIZED = 0x00000040, + SDL_WINDOW_MAXIMIZED = 0x00000080, + SDL_WINDOW_INPUT_GRABBED = 0x00000100, + SDL_WINDOW_INPUT_FOCUS = 0x00000200, + SDL_WINDOW_MOUSE_FOCUS = 0x00000400, + SDL_WINDOW_FULLSCREEN_DESKTOP = SDL_WINDOW_FULLSCREEN | 0x00001000, + SDL_WINDOW_FOREIGN = 0x00000800, + } +} +mixin(expandEnum!SDL_WindowFlags); + +enum uint SDL_WINDOWPOS_UNDEFINED_MASK = 0x1FFF0000; +enum uint SDL_WINDOWPOS_UNDEFINED_DISPLAY(uint x) = SDL_WINDOWPOS_UNDEFINED_MASK | x; +enum uint SDL_WINDOWPOS_UNDEFINED = SDL_WINDOWPOS_UNDEFINED_DISPLAY!(0); +enum uint SDL_WINDOWPOS_ISUNDEFINED(uint x) = (x & 0xFFFF0000) == SDL_WINDOWPOS_UNDEFINED_MASK; + +enum uint SDL_WINDOWPOS_CENTERED_MASK = 0x2FFF0000; +enum uint SDL_WINDOWPOS_CENTERED_DISPLAY(uint x) = SDL_WINDOWPOS_CENTERED_MASK | x; +enum uint SDL_WINDOWPOS_CENTERED = SDL_WINDOWPOS_CENTERED_DISPLAY!(0); +enum uint SDL_WINDOWPOS_ISCENTERED(uint x) = (x & 0xFFFF0000) == SDL_WINDOWPOS_CENTERED_MASK; + +static if(sdlSupport >= SDLSupport.sdl205) { + enum SDL_WindowEventID : ubyte { + SDL_WINDOWEVENT_NONE, + SDL_WINDOWEVENT_SHOWN, + SDL_WINDOWEVENT_HIDDEN, + SDL_WINDOWEVENT_EXPOSED, + SDL_WINDOWEVENT_MOVED, + SDL_WINDOWEVENT_RESIZED, + SDL_WINDOWEVENT_SIZE_CHANGED, + SDL_WINDOWEVENT_MINIMIZED, + SDL_WINDOWEVENT_MAXIMIZED, + SDL_WINDOWEVENT_RESTORED, + SDL_WINDOWEVENT_ENTER, + SDL_WINDOWEVENT_LEAVE, + SDL_WINDOWEVENT_FOCUS_GAINED, + SDL_WINDOWEVENT_FOCUS_LOST, + SDL_WINDOWEVENT_CLOSE, + SDL_WINDOWEVENT_TAKE_FOCUS, + SDL_WINDOWEVENT_HIT_TEST, + } + +} +else { + enum SDL_WindowEventID : ubyte { + SDL_WINDOWEVENT_NONE, + SDL_WINDOWEVENT_SHOWN, + SDL_WINDOWEVENT_HIDDEN, + SDL_WINDOWEVENT_EXPOSED, + SDL_WINDOWEVENT_MOVED, + SDL_WINDOWEVENT_RESIZED, + SDL_WINDOWEVENT_SIZE_CHANGED, + SDL_WINDOWEVENT_MINIMIZED, + SDL_WINDOWEVENT_MAXIMIZED, + SDL_WINDOWEVENT_RESTORED, + SDL_WINDOWEVENT_ENTER, + SDL_WINDOWEVENT_LEAVE, + SDL_WINDOWEVENT_FOCUS_GAINED, + SDL_WINDOWEVENT_FOCUS_LOST, + SDL_WINDOWEVENT_CLOSE, + } +} +mixin(expandEnum!SDL_WindowEventID); + +static if(sdlSupport >= SDLSupport.sdl209) { + enum SDL_DisplayEventID { + SDL_DISPLAYEVENT_NONE, + SDL_DISPLAYEVENT_ORIENTATION, + } + mixin(expandEnum!SDL_DisplayEventID); + + enum SDL_DisplayOrientation { + SDL_ORIENTATION_UNKNOWN, + SDL_ORIENTATION_LANDSCAPE, + SDL_ORIENTATION_LANDSCAPE_FLIPPED, + SDL_ORIENTATION_PORTRAIT, + SDL_ORIENTATION_PORTRAIT_FLIPPED, + } + mixin(expandEnum!SDL_DisplayOrientation); +} + +alias SDL_GLContext = void*; + +static if(sdlSupport >= SDLSupport.sdl206) { + enum SDL_GLattr { + SDL_GL_RED_SIZE, + SDL_GL_GREEN_SIZE, + SDL_GL_BLUE_SIZE, + SDL_GL_ALPHA_SIZE, + SDL_GL_BUFFER_SIZE, + SDL_GL_DOUBLEBUFFER, + SDL_GL_DEPTH_SIZE, + SDL_GL_STENCIL_SIZE, + SDL_GL_ACCUM_RED_SIZE, + SDL_GL_ACCUM_GREEN_SIZE, + SDL_GL_ACCUM_BLUE_SIZE, + SDL_GL_ACCUM_ALPHA_SIZE, + SDL_GL_STEREO, + SDL_GL_MULTISAMPLEBUFFERS, + SDL_GL_MULTISAMPLESAMPLES, + SDL_GL_ACCELERATED_VISUAL, + SDL_GL_RETAINED_BACKING, + SDL_GL_CONTEXT_MAJOR_VERSION, + SDL_GL_CONTEXT_MINOR_VERSION, + SDL_GL_CONTEXT_EGL, + SDL_GL_CONTEXT_FLAGS, + SDL_GL_CONTEXT_PROFILE_MASK, + SDL_GL_SHARE_WITH_CURRENT_CONTEXT, + SDL_GL_FRAMEBUFFER_SRGB_CAPABLE, + SDL_GL_RELEASE_BEHAVIOR, + SDL_GL_CONTEXT_RESET_NOTIFICATION, + SDL_GL_CONTEXT_NO_ERROR, + } +} +else static if(sdlSupport >= SDLSupport.sdl204) { + enum SDL_GLattr { + SDL_GL_RED_SIZE, + SDL_GL_GREEN_SIZE, + SDL_GL_BLUE_SIZE, + SDL_GL_ALPHA_SIZE, + SDL_GL_BUFFER_SIZE, + SDL_GL_DOUBLEBUFFER, + SDL_GL_DEPTH_SIZE, + SDL_GL_STENCIL_SIZE, + SDL_GL_ACCUM_RED_SIZE, + SDL_GL_ACCUM_GREEN_SIZE, + SDL_GL_ACCUM_BLUE_SIZE, + SDL_GL_ACCUM_ALPHA_SIZE, + SDL_GL_STEREO, + SDL_GL_MULTISAMPLEBUFFERS, + SDL_GL_MULTISAMPLESAMPLES, + SDL_GL_ACCELERATED_VISUAL, + SDL_GL_RETAINED_BACKING, + SDL_GL_CONTEXT_MAJOR_VERSION, + SDL_GL_CONTEXT_MINOR_VERSION, + SDL_GL_CONTEXT_EGL, + SDL_GL_CONTEXT_FLAGS, + SDL_GL_CONTEXT_PROFILE_MASK, + SDL_GL_SHARE_WITH_CURRENT_CONTEXT, + SDL_GL_FRAMEBUFFER_SRGB_CAPABLE, + SDL_GL_RELEASE_BEHAVIOR, + } +} +else static if(sdlSupport >= SDLSupport.sdl201) { + enum SDL_GLattr { + SDL_GL_RED_SIZE, + SDL_GL_GREEN_SIZE, + SDL_GL_BLUE_SIZE, + SDL_GL_ALPHA_SIZE, + SDL_GL_BUFFER_SIZE, + SDL_GL_DOUBLEBUFFER, + SDL_GL_DEPTH_SIZE, + SDL_GL_STENCIL_SIZE, + SDL_GL_ACCUM_RED_SIZE, + SDL_GL_ACCUM_GREEN_SIZE, + SDL_GL_ACCUM_BLUE_SIZE, + SDL_GL_ACCUM_ALPHA_SIZE, + SDL_GL_STEREO, + SDL_GL_MULTISAMPLEBUFFERS, + SDL_GL_MULTISAMPLESAMPLES, + SDL_GL_ACCELERATED_VISUAL, + SDL_GL_RETAINED_BACKING, + SDL_GL_CONTEXT_MAJOR_VERSION, + SDL_GL_CONTEXT_MINOR_VERSION, + SDL_GL_CONTEXT_EGL, + SDL_GL_CONTEXT_FLAGS, + SDL_GL_CONTEXT_PROFILE_MASK, + SDL_GL_SHARE_WITH_CURRENT_CONTEXT, + SDL_GL_FRAMEBUFFER_SRGB_CAPABLE, + } +} +else { + enum SDL_GLattr { + SDL_GL_RED_SIZE, + SDL_GL_GREEN_SIZE, + SDL_GL_BLUE_SIZE, + SDL_GL_ALPHA_SIZE, + SDL_GL_BUFFER_SIZE, + SDL_GL_DOUBLEBUFFER, + SDL_GL_DEPTH_SIZE, + SDL_GL_STENCIL_SIZE, + SDL_GL_ACCUM_RED_SIZE, + SDL_GL_ACCUM_GREEN_SIZE, + SDL_GL_ACCUM_BLUE_SIZE, + SDL_GL_ACCUM_ALPHA_SIZE, + SDL_GL_STEREO, + SDL_GL_MULTISAMPLEBUFFERS, + SDL_GL_MULTISAMPLESAMPLES, + SDL_GL_ACCELERATED_VISUAL, + SDL_GL_RETAINED_BACKING, + SDL_GL_CONTEXT_MAJOR_VERSION, + SDL_GL_CONTEXT_MINOR_VERSION, + SDL_GL_CONTEXT_EGL, + SDL_GL_CONTEXT_FLAGS, + SDL_GL_CONTEXT_PROFILE_MASK, + SDL_GL_SHARE_WITH_CURRENT_CONTEXT, + } +} +mixin(expandEnum!SDL_GLattr); + +enum SDL_GLprofile { + SDL_GL_CONTEXT_PROFILE_CORE = 0x0001, + SDL_GL_CONTEXT_PROFILE_COMPATIBILITY = 0x0002, + SDL_GL_CONTEXT_PROFILE_ES = 0x0004, +} +mixin(expandEnum!SDL_GLprofile); + +enum SDL_GLcontextFlag { + SDL_GL_CONTEXT_DEBUG_FLAG = 0x0001, + SDL_GL_CONTEXT_FORWARD_COMPATIBLE_FLAG = 0x0002, + SDL_GL_CONTEXT_ROBUST_ACCESS_FLAG = 0x0004, + SDL_GL_CONTEXT_RESET_ISOLATION_FLAG = 0x0008, +} +mixin(expandEnum!SDL_GLcontextFlag); + +static if(sdlSupport >= SDLSupport.sdl204) { + enum SDL_GLcontextReleaseFlag { + SDL_GL_CONTEXT_RELEASE_BEHAVIOR_NONE = 0x0000, + SDL_GL_CONTEXT_RELEASE_BEHAVIOR_FLUSH = 0x0001, + } + mixin(expandEnum!SDL_GLcontextReleaseFlag); + + enum SDL_HitTestResult { + SDL_HITTEST_NORMAL, + SDL_HITTEST_DRAGGABLE, + SDL_HITTEST_RESIZE_TOPLEFT, + SDL_HITTEST_RESIZE_TOP, + SDL_HITTEST_RESIZE_TOPRIGHT, + SDL_HITTEST_RESIZE_RIGHT, + SDL_HITTEST_RESIZE_BOTTOMRIGHT, + SDL_HITTEST_RESIZE_BOTTOM, + SDL_HITTEST_RESIZE_BOTTOMLEFT, + SDL_HITTEST_RESIZE_LEFT, + } + mixin(expandEnum!SDL_HitTestResult); + + import bindbc.sdl.bind.sdlrect : SDL_Point; + extern(C) nothrow alias SDL_HitTest = SDL_HitTestResult function(SDL_Window*,const(SDL_Point)*,void*); +} + + static if(sdlSupport >= SDLSupport.sdl206) { + enum SDL_GLContextResetNotification { + SDL_GL_CONTEXT_RESET_NO_NOTIFICATION = 0x0000, + SDL_GL_CONTEXT_RESET_LOSE_CONTEXT = 0x0001, + } + mixin(expandEnum!SDL_GLContextResetNotification); +} + +version(BindSDL_Static) { + extern(C) @nogc nothrow { + int SDL_GetNumVideoDrivers(); + const(char)* SDL_GetVideoDriver(int); + int SDL_VideoInit(const(char)*); + void SDL_VideoQuit(); + const(char)* SDL_GetCurrentVideoDriver(); + int SDL_GetNumVideoDisplays(); + const(char)* SDL_GetDisplayName(int); + int SDL_GetDisplayBounds(int,SDL_Rect*); + int SDL_GetNumDisplayModes(int); + int SDL_GetDisplayMode(int,int,SDL_DisplayMode*); + int SDL_GetDesktopDisplayMode(int,SDL_DisplayMode*); + int SDL_GetCurrentDisplayMode(int,SDL_DisplayMode*); + SDL_DisplayMode* SDL_GetClosestDisplayMode(int,const(SDL_DisplayMode)*,SDL_DisplayMode*); + int SDL_GetWindowDisplayIndex(SDL_Window*); + int SDL_SetWindowDisplayMode(SDL_Window*,const(SDL_DisplayMode)*); + int SDL_GetWindowDisplayMode(SDL_Window*,SDL_DisplayMode*); + uint SDL_GetWindowPixelFormat(SDL_Window*); + SDL_Window* SDL_CreateWindow(const(char)*,int,int,int,int,SDL_WindowFlags); + SDL_Window* SDL_CreateWindowFrom(const(void)*); + uint SDL_GetWindowID(SDL_Window*); + SDL_Window* SDL_GetWindowFromID(uint); + SDL_WindowFlags SDL_GetWindowFlags(SDL_Window*); + void SDL_SetWindowTitle(SDL_Window*,const(char)*); + const(char)* SDL_GetWindowTitle(SDL_Window*); + void SDL_SetWindowIcon(SDL_Window*,SDL_Surface*); + void* SDL_SetWindowData(SDL_Window*,const(char)*,void*); + void* SDL_GetWindowData(SDL_Window*,const(char)*); + void SDL_SetWindowPosition(SDL_Window*,int,int); + void SDL_GetWindowPosition(SDL_Window*,int*,int*); + void SDL_SetWindowSize(SDL_Window*,int,int); + void SDL_GetWindowSize(SDL_Window*,int*,int*); + void SDL_SetWindowMinimumSize(SDL_Window*,int,int); + void SDL_GetWindowMinimumSize(SDL_Window*,int*,int*); + void SDL_SetWindowMaximumSize(SDL_Window*,int,int); + void SDL_GetWindowMaximumSize(SDL_Window*,int*,int*); + void SDL_SetWindowBordered(SDL_Window*,SDL_bool); + void SDL_ShowWindow(SDL_Window*); + void SDL_HideWindow(SDL_Window*); + void SDL_RaiseWindow(SDL_Window*); + void SDL_MaximizeWindow(SDL_Window*); + void SDL_MinimizeWindow(SDL_Window*); + void SDL_RestoreWindow(SDL_Window*); + int SDL_SetWindowFullscreen(SDL_Window*,uint); + SDL_Surface* SDL_GetWindowSurface(SDL_Window*); + int SDL_UpdateWindowSurface(SDL_Window*); + int SDL_UpdateWindowSurfaceRects(SDL_Window*,SDL_Rect*,int); + void SDL_SetWindowGrab(SDL_Window*,SDL_bool); + SDL_bool SDL_GetWindowGrab(SDL_Window*); + int SDL_SetWindowBrightness(SDL_Window*,float); + float SDL_GetWindowBrightness(SDL_Window*); + int SDL_SetWindowGammaRamp(SDL_Window*,const(ushort)*,const(ushort)*,const(ushort)*); + int SDL_GetWindowGammaRamp(SDL_Window*,ushort*,ushort*,ushort*); + void SDL_DestroyWindow(SDL_Window*); + SDL_bool SDL_IsScreenSaverEnabled(); + void SDL_EnableScreenSaver(); + void SDL_DisableScreenSaver(); + int SDL_GL_LoadLibrary(const(char)*); + void* SDL_GL_GetProcAddress(const(char)*); + void SDL_GL_UnloadLibrary(); + SDL_bool SDL_GL_ExtensionSupported(const(char)*); + int SDL_GL_SetAttribute(SDL_GLattr,int); + int SDL_GL_GetAttribute(SDL_GLattr,int*); + SDL_GLContext SDL_GL_CreateContext(SDL_Window*); + int SDL_GL_MakeCurrent(SDL_Window*,SDL_GLContext); + SDL_Window* SDL_GL_GetCurrentWindow(); + SDL_GLContext SDL_GL_GetCurrentContext(); + int SDL_GL_SetSwapInterval(int); + int SDL_GL_GetSwapInterval(); + void SDL_GL_SwapWindow(SDL_Window*); + void SDL_GL_DeleteContext(SDL_GLContext); + + static if(sdlSupport >= SDLSupport.sdl201) { + void SDL_GL_GetDrawableSize(SDL_Window*,int*,int*); + } + static if(sdlSupport >= SDLSupport.sdl202) { + void SDL_GL_ResetAttributes(); + } + static if(sdlSupport >= SDLSupport.sdl204) { + int SDL_GetDisplayDPI(int,float*,float*,float*); + SDL_Window* SDL_GetGrabbedWindow(); + int SDL_SetWindowHitTest(SDL_Window*,SDL_HitTest,void*); + } + static if(sdlSupport >= SDLSupport.sdl205) { + int SDL_GetDisplayUsableBounds(int,SDL_Rect*); + int SDL_GetWindowBordersSize(SDL_Window*,int*,int*,int*,int*); + int SDL_GetWindowOpacity(SDL_Window*,float*); + int SDL_SetWindowInputFocus(SDL_Window*); + int SDL_SetWindowModalFor(SDL_Window*,SDL_Window*); + int SDL_SetWindowOpacity(SDL_Window*,float); + void SDL_SetWindowResizable(SDL_Window*,SDL_bool); + } + static if(sdlSupport >= SDLSupport.sdl209) { + SDL_DisplayOrientation SDL_GetDisplayOrientation(int); + } + } +} +else { + extern(C) @nogc nothrow { + alias pSDL_GetNumVideoDrivers = int function(); + alias pSDL_GetVideoDriver = const(char)* function(int); + alias pSDL_VideoInit = int function(const(char)*); + alias pSDL_VideoQuit = void function(); + alias pSDL_GetCurrentVideoDriver = const(char)* function(); + alias pSDL_GetNumVideoDisplays = int function(); + alias pSDL_GetDisplayName = const(char)* function(int); + alias pSDL_GetDisplayBounds = int function(int,SDL_Rect*); + alias pSDL_GetNumDisplayModes = int function(int); + alias pSDL_GetDisplayMode = int function(int,int,SDL_DisplayMode*); + alias pSDL_GetDesktopDisplayMode = int function(int,SDL_DisplayMode*); + alias pSDL_GetCurrentDisplayMode = int function(int,SDL_DisplayMode*); + alias pSDL_GetClosestDisplayMode = SDL_DisplayMode* function(int,const(SDL_DisplayMode)*,SDL_DisplayMode*); + alias pSDL_GetWindowDisplayIndex = int function(SDL_Window*); + alias pSDL_SetWindowDisplayMode = int function(SDL_Window*,const(SDL_DisplayMode)*); + alias pSDL_GetWindowDisplayMode = int function(SDL_Window*,SDL_DisplayMode*); + alias pSDL_GetWindowPixelFormat = uint function(SDL_Window*); + alias pSDL_CreateWindow = SDL_Window* function(const(char)*,int,int,int,int,SDL_WindowFlags); + alias pSDL_CreateWindowFrom = SDL_Window* function(const(void)*); + alias pSDL_GetWindowID = uint function(SDL_Window*); + alias pSDL_GetWindowFromID = SDL_Window* function(uint); + alias pSDL_GetWindowFlags = SDL_WindowFlags function(SDL_Window*); + alias pSDL_SetWindowTitle = void function(SDL_Window*,const(char)*); + alias pSDL_GetWindowTitle = const(char)* function(SDL_Window*); + alias pSDL_SetWindowIcon = void function(SDL_Window*,SDL_Surface*); + alias pSDL_SetWindowData = void* function(SDL_Window*,const(char)*,void*); + alias pSDL_GetWindowData = void* function(SDL_Window*,const(char)*); + alias pSDL_SetWindowPosition = void function(SDL_Window*,int,int); + alias pSDL_GetWindowPosition = void function(SDL_Window*,int*,int*); + alias pSDL_SetWindowSize = void function(SDL_Window*,int,int); + alias pSDL_GetWindowSize = void function(SDL_Window*,int*,int*); + alias pSDL_SetWindowMinimumSize = void function(SDL_Window*,int,int); + alias pSDL_GetWindowMinimumSize = void function(SDL_Window*,int*,int*); + alias pSDL_SetWindowMaximumSize = void function(SDL_Window*,int,int); + alias pSDL_GetWindowMaximumSize = void function(SDL_Window*,int*,int*); + alias pSDL_SetWindowBordered = void function(SDL_Window*,SDL_bool); + alias pSDL_ShowWindow = void function(SDL_Window*); + alias pSDL_HideWindow = void function(SDL_Window*); + alias pSDL_RaiseWindow = void function(SDL_Window*); + alias pSDL_MaximizeWindow = void function(SDL_Window*); + alias pSDL_MinimizeWindow = void function(SDL_Window*); + alias pSDL_RestoreWindow = void function(SDL_Window*); + alias pSDL_SetWindowFullscreen = int function(SDL_Window*,uint); + alias pSDL_GetWindowSurface = SDL_Surface* function(SDL_Window*); + alias pSDL_UpdateWindowSurface = int function(SDL_Window*); + alias pSDL_UpdateWindowSurfaceRects = int function(SDL_Window*,SDL_Rect*,int); + alias pSDL_SetWindowGrab = void function(SDL_Window*,SDL_bool); + alias pSDL_GetWindowGrab = SDL_bool function(SDL_Window*); + alias pSDL_SetWindowBrightness = int function(SDL_Window*,float); + alias pSDL_GetWindowBrightness = float function(SDL_Window*); + alias pSDL_SetWindowGammaRamp = int function(SDL_Window*,const(ushort)*,const(ushort)*,const(ushort)*); + alias pSDL_GetWindowGammaRamp = int function(SDL_Window*,ushort*,ushort*,ushort*); + alias pSDL_DestroyWindow = void function(SDL_Window*); + alias pSDL_IsScreenSaverEnabled = SDL_bool function(); + alias pSDL_EnableScreenSaver = void function(); + alias pSDL_DisableScreenSaver = void function(); + alias pSDL_GL_LoadLibrary = int function(const(char)*); + alias pSDL_GL_GetProcAddress = void* function(const(char)*); + alias pSDL_GL_UnloadLibrary = void function(); + alias pSDL_GL_ExtensionSupported = SDL_bool function(const(char)*); + alias pSDL_GL_SetAttribute = int function(SDL_GLattr,int); + alias pSDL_GL_GetAttribute = int function(SDL_GLattr,int*); + alias pSDL_GL_CreateContext = SDL_GLContext function(SDL_Window*); + alias pSDL_GL_MakeCurrent = int function(SDL_Window*,SDL_GLContext); + alias pSDL_GL_GetCurrentWindow = SDL_Window* function(); + alias pSDL_GL_GetCurrentContext = SDL_GLContext function(); + alias pSDL_GL_SetSwapInterval = int function(int); + alias pSDL_GL_GetSwapInterval = int function(); + alias pSDL_GL_SwapWindow = void function(SDL_Window*); + alias pSDL_GL_DeleteContext = void function(SDL_GLContext); + } + + __gshared { + pSDL_GetNumVideoDrivers SDL_GetNumVideoDrivers; + pSDL_GetVideoDriver SDL_GetVideoDriver; + pSDL_VideoInit SDL_VideoInit; + pSDL_VideoQuit SDL_VideoQuit; + pSDL_GetCurrentVideoDriver SDL_GetCurrentVideoDriver; + pSDL_GetNumVideoDisplays SDL_GetNumVideoDisplays; + pSDL_GetDisplayName SDL_GetDisplayName; + pSDL_GetDisplayBounds SDL_GetDisplayBounds; + pSDL_GetNumDisplayModes SDL_GetNumDisplayModes; + pSDL_GetDisplayMode SDL_GetDisplayMode; + pSDL_GetDesktopDisplayMode SDL_GetDesktopDisplayMode; + pSDL_GetCurrentDisplayMode SDL_GetCurrentDisplayMode; + pSDL_GetClosestDisplayMode SDL_GetClosestDisplayMode; + pSDL_GetWindowDisplayIndex SDL_GetWindowDisplayIndex; + pSDL_SetWindowDisplayMode SDL_SetWindowDisplayMode; + pSDL_GetWindowDisplayMode SDL_GetWindowDisplayMode; + pSDL_GetWindowPixelFormat SDL_GetWindowPixelFormat; + pSDL_CreateWindow SDL_CreateWindow; + pSDL_CreateWindowFrom SDL_CreateWindowFrom; + pSDL_GetWindowID SDL_GetWindowID; + pSDL_GetWindowFromID SDL_GetWindowFromID; + pSDL_GetWindowFlags SDL_GetWindowFlags; + pSDL_SetWindowTitle SDL_SetWindowTitle; + pSDL_GetWindowTitle SDL_GetWindowTitle; + pSDL_SetWindowIcon SDL_SetWindowIcon; + pSDL_SetWindowData SDL_SetWindowData; + pSDL_GetWindowData SDL_GetWindowData; + pSDL_SetWindowPosition SDL_SetWindowPosition; + pSDL_GetWindowPosition SDL_GetWindowPosition; + pSDL_SetWindowSize SDL_SetWindowSize; + pSDL_GetWindowSize SDL_GetWindowSize; + pSDL_SetWindowMinimumSize SDL_SetWindowMinimumSize; + pSDL_GetWindowMinimumSize SDL_GetWindowMinimumSize; + pSDL_SetWindowMaximumSize SDL_SetWindowMaximumSize; + pSDL_GetWindowMaximumSize SDL_GetWindowMaximumSize; + pSDL_SetWindowBordered SDL_SetWindowBordered; + pSDL_ShowWindow SDL_ShowWindow; + pSDL_HideWindow SDL_HideWindow; + pSDL_RaiseWindow SDL_RaiseWindow; + pSDL_MaximizeWindow SDL_MaximizeWindow; + pSDL_MinimizeWindow SDL_MinimizeWindow; + pSDL_RestoreWindow SDL_RestoreWindow; + pSDL_SetWindowFullscreen SDL_SetWindowFullscreen; + pSDL_GetWindowSurface SDL_GetWindowSurface; + pSDL_UpdateWindowSurface SDL_UpdateWindowSurface; + pSDL_UpdateWindowSurfaceRects SDL_UpdateWindowSurfaceRects; + pSDL_SetWindowGrab SDL_SetWindowGrab; + pSDL_GetWindowGrab SDL_GetWindowGrab; + pSDL_SetWindowBrightness SDL_SetWindowBrightness; + pSDL_GetWindowBrightness SDL_GetWindowBrightness; + pSDL_SetWindowGammaRamp SDL_SetWindowGammaRamp; + pSDL_GetWindowGammaRamp SDL_GetWindowGammaRamp; + pSDL_DestroyWindow SDL_DestroyWindow; + pSDL_IsScreenSaverEnabled SDL_IsScreenSaverEnabled; + pSDL_EnableScreenSaver SDL_EnableScreenSaver; + pSDL_DisableScreenSaver SDL_DisableScreenSaver; + pSDL_GL_LoadLibrary SDL_GL_LoadLibrary; + pSDL_GL_GetProcAddress SDL_GL_GetProcAddress; + pSDL_GL_UnloadLibrary SDL_GL_UnloadLibrary; + pSDL_GL_ExtensionSupported SDL_GL_ExtensionSupported; + pSDL_GL_SetAttribute SDL_GL_SetAttribute; + pSDL_GL_GetAttribute SDL_GL_GetAttribute; + pSDL_GL_CreateContext SDL_GL_CreateContext; + pSDL_GL_MakeCurrent SDL_GL_MakeCurrent; + pSDL_GL_GetCurrentWindow SDL_GL_GetCurrentWindow; + pSDL_GL_GetCurrentContext SDL_GL_GetCurrentContext; + pSDL_GL_SetSwapInterval SDL_GL_SetSwapInterval; + pSDL_GL_GetSwapInterval SDL_GL_GetSwapInterval; + pSDL_GL_SwapWindow SDL_GL_SwapWindow; + pSDL_GL_DeleteContext SDL_GL_DeleteContext; + } + + static if(sdlSupport >= SDLSupport.sdl201) { + extern(C) @nogc nothrow { + alias pSDL_GL_GetDrawableSize = void function(SDL_Window*,int*,int*); + } + + __gshared { + pSDL_GL_GetDrawableSize SDL_GL_GetDrawableSize; + } + } + + static if(sdlSupport >= SDLSupport.sdl202) { + extern(C) @nogc nothrow { + alias pSDL_GL_ResetAttributes = void function(); + } + + __gshared { + pSDL_GL_ResetAttributes SDL_GL_ResetAttributes; + } + } + + static if(sdlSupport >= SDLSupport.sdl204) { + extern(C) @nogc nothrow { + alias pSDL_GetDisplayDPI = int function(int,float*,float*,float*); + alias pSDL_GetGrabbedWindow = SDL_Window* function(); + alias pSDL_SetWindowHitTest = int function(SDL_Window*,SDL_HitTest,void*); + } + + __gshared { + pSDL_GetDisplayDPI SDL_GetDisplayDPI; + pSDL_GetGrabbedWindow SDL_GetGrabbedWindow; + pSDL_SetWindowHitTest SDL_SetWindowHitTest; + } + } + + static if(sdlSupport >= SDLSupport.sdl205) { + extern(C) @nogc nothrow { + alias pSDL_GetDisplayUsableBounds = int function(int,SDL_Rect*); + alias pSDL_GetWindowBordersSize = int function(SDL_Window*,int*,int*,int*,int*); + alias pSDL_GetWindowOpacity = int function(SDL_Window*,float*); + alias pSDL_SetWindowInputFocus = int function(SDL_Window*); + alias pSDL_SetWindowModalFor = int function(SDL_Window*,SDL_Window*); + alias pSDL_SetWindowOpacity = int function(SDL_Window*,float); + alias pSDL_SetWindowResizable = void function(SDL_Window*,SDL_bool); + } + + __gshared { + pSDL_GetDisplayUsableBounds SDL_GetDisplayUsableBounds; + pSDL_GetWindowBordersSize SDL_GetWindowBordersSize; + pSDL_GetWindowOpacity SDL_GetWindowOpacity; + pSDL_SetWindowInputFocus SDL_SetWindowInputFocus; + pSDL_SetWindowModalFor SDL_SetWindowModalFor; + pSDL_SetWindowOpacity SDL_SetWindowOpacity; + pSDL_SetWindowResizable SDL_SetWindowResizable; + } + } + + static if(sdlSupport >= SDLSupport.sdl209) { + extern(C) @nogc nothrow { + alias pSDL_GetDisplayOrientation = SDL_DisplayOrientation function(int); + } + + __gshared { + pSDL_GetDisplayOrientation SDL_GetDisplayOrientation; + } + } +} \ No newline at end of file diff --git a/demos/external/imports/bindbc/sdl/bind/sdlvulkan.d b/demos/external/imports/bindbc/sdl/bind/sdlvulkan.d new file mode 100644 index 0000000..0dc287d --- /dev/null +++ b/demos/external/imports/bindbc/sdl/bind/sdlvulkan.d @@ -0,0 +1,45 @@ + +// Copyright Michael D. Parker 2018. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +module bindbc.sdl.bind.sdlvulkan; + +import bindbc.sdl.config; +import bindbc.sdl.bind.sdlstdinc : SDL_bool; +import bindbc.sdl.bind.sdlvideo : SDL_Window; + +version(BindSDL_Static) { + extern(C) @nogc nothrow { + static if(sdlSupport >= SDLSupport.sdl206) { + SDL_bool SDL_Vulkan_CreateSurface(SDL_Window*,void*,void*); + void SDL_Vulkan_GetDrawableSize(SDL_Window*,int*,int*); + SDL_bool SDL_Vulkan_GetInstanceExtensions(SDL_Window*,uint*,const(char)**); + void* SDL_Vulkan_GetVkGetInstanceProcAddr(); + int SDL_Vulkan_LoadLibrary(const(char)*); + void SDL_Vulkan_UnloadLibrary(); + } + } +} +else { + static if(sdlSupport >= SDLSupport.sdl206) { + extern(C) @nogc nothrow { + alias pSDL_Vulkan_CreateSurface = SDL_bool function(SDL_Window*,void*,void*); + alias pSDL_Vulkan_GetDrawableSize = void function(SDL_Window*,int*,int*); + alias pSDL_Vulkan_GetInstanceExtensions = SDL_bool function(SDL_Window*,uint*,const(char)**); + alias pSDL_Vulkan_GetVkGetInstanceProcAddr = void* function(); + alias pSDL_Vulkan_LoadLibrary = int function(const(char)*); + alias pSDL_Vulkan_UnloadLibrary = void function(); + } + + __gshared { + pSDL_Vulkan_CreateSurface SDL_Vulkan_CreateSurface; + pSDL_Vulkan_GetDrawableSize SDL_Vulkan_GetDrawableSize; + pSDL_Vulkan_GetInstanceExtensions SDL_Vulkan_GetInstanceExtensions; + pSDL_Vulkan_GetVkGetInstanceProcAddr SDL_Vulkan_GetVkGetInstanceProcAddr; + pSDL_Vulkan_LoadLibrary SDL_Vulkan_LoadLibrary; + pSDL_Vulkan_UnloadLibrary SDL_Vulkan_UnloadLibrary; + } + } +} diff --git a/demos/external/imports/bindbc/sdl/config.d b/demos/external/imports/bindbc/sdl/config.d new file mode 100644 index 0000000..1a76433 --- /dev/null +++ b/demos/external/imports/bindbc/sdl/config.d @@ -0,0 +1,44 @@ + +// Copyright Michael D. Parker 2018. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +module bindbc.sdl.config; + +enum SDLSupport { + noLibrary, + badLibrary, + sdl200 = 200, + sdl201 = 201, + sdl202 = 202, + sdl203 = 203, + sdl204 = 204, + sdl205 = 205, + sdl206 = 206, + sdl207 = 207, + sdl208 = 208, + sdl209 = 209, + sdl2010 = 2010, +} + +version(SDL_2010) enum sdlSupport = SDLSupport.sdl2010; +else version(SDL_209) enum sdlSupport = SDLSupport.sdl209; +else version(SDL_208) enum sdlSupport = SDLSupport.sdl208; +else version(SDL_207) enum sdlSupport = SDLSupport.sdl207; +else version(SDL_206) enum sdlSupport = SDLSupport.sdl206; +else version(SDL_205) enum sdlSupport = SDLSupport.sdl205; +else version(SDL_204) enum sdlSupport = SDLSupport.sdl204; +else version(SDL_203) enum sdlSupport = SDLSupport.sdl203; +else version(SDL_202) enum sdlSupport = SDLSupport.sdl202; +else version(SDL_201) enum sdlSupport = SDLSupport.sdl201; +else enum sdlSupport = SDLSupport.sdl200; + +enum expandEnum(EnumType, string fqnEnumType = EnumType.stringof) = (){ + string expandEnum = "enum {"; + foreach(m;__traits(allMembers, EnumType)) { + expandEnum ~= m ~ " = " ~ fqnEnumType ~ "." ~ m ~ ","; + } + expandEnum ~= "}"; + return expandEnum; +}(); \ No newline at end of file diff --git a/demos/external/imports/bindbc/sdl/dynload.d b/demos/external/imports/bindbc/sdl/dynload.d new file mode 100644 index 0000000..0aa3b84 --- /dev/null +++ b/demos/external/imports/bindbc/sdl/dynload.d @@ -0,0 +1,712 @@ + +// Copyright Michael D. Parker 2018. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +module bindbc.sdl.dynload; + +version(BindSDL_Static) {} +else: + +import bindbc.loader; +import bindbc.sdl.config, + bindbc.sdl.bind; + +private { + SharedLib lib; + SDLSupport loadedVersion; +} + +void unloadSDL() +{ + if(lib != invalidHandle) { + lib.unload(); + } +} + +SDLSupport loadedSDLVersion() { return loadedVersion; } + +bool isSDLLoaded() +{ + return lib != invalidHandle; +} + +SDLSupport loadSDL() +{ + // #1778 prevents me from using static arrays here :( + version(Windows) { + const(char)[][1] libNames = ["SDL2.dll"]; + } + else version(OSX) { + const(char)[][7] libNames = [ + "libSDL2.dylib", + "/usr/local/lib/libSDL2.dylib", + "/usr/local/lib/libSDL2/libSDL2.dylib", + "../Frameworks/SDL2.framework/SDL2", + "/Library/Frameworks/SDL2.framework/SDL2", + "/System/Library/Frameworks/SDL2.framework/SDL2", + "/opt/local/lib/libSDL2.dylib" + ]; + } + else version(Posix) { + const(char)[][6] libNames = [ + "libSDL2.so", + "/usr/local/lib/libSDL2.so", + "libSDL2-2.0.so", + "/usr/local/lib/libSDL2-2.0.so", + "libSDL2-2.0.so.0", + "/usr/local/lib/libSDL2-2.0.so.0" + ]; + } + else static assert(0, "bindbc-sdl is not yet supported on this platform."); + + SDLSupport ret; + foreach(name; libNames) { + ret = loadSDL(name.ptr); + if(ret != SDLSupport.noLibrary) break; + } + return ret; +} + +SDLSupport loadSDL(const(char)* libName) +{ + lib = load(libName); + if(lib == invalidHandle) { + return SDLSupport.noLibrary; + } + + auto errCount = errorCount(); + loadedVersion = SDLSupport.badLibrary; + + lib.bindSymbol(cast(void**)&SDL_Init, "SDL_Init"); + lib.bindSymbol(cast(void**)&SDL_InitSubSystem, "SDL_InitSubSystem"); + lib.bindSymbol(cast(void**)&SDL_QuitSubSystem, "SDL_QuitSubSystem"); + lib.bindSymbol(cast(void**)&SDL_WasInit, "SDL_WasInit"); + lib.bindSymbol(cast(void**)&SDL_Quit, "SDL_Quit"); + lib.bindSymbol(cast(void**)&SDL_SetAssertionHandler, "SDL_SetAssertionHandler"); + lib.bindSymbol(cast(void**)&SDL_GetAssertionReport, "SDL_GetAssertionReport"); + lib.bindSymbol(cast(void**)&SDL_ResetAssertionReport, "SDL_ResetAssertionReport"); + lib.bindSymbol(cast(void**)&SDL_GetNumAudioDrivers, "SDL_GetNumAudioDrivers"); + lib.bindSymbol(cast(void**)&SDL_GetAudioDriver, "SDL_GetAudioDriver"); + lib.bindSymbol(cast(void**)&SDL_AudioInit, "SDL_AudioInit"); + lib.bindSymbol(cast(void**)&SDL_AudioQuit, "SDL_AudioQuit"); + lib.bindSymbol(cast(void**)&SDL_GetCurrentAudioDriver, "SDL_GetCurrentAudioDriver"); + lib.bindSymbol(cast(void**)&SDL_OpenAudio, "SDL_OpenAudio"); + lib.bindSymbol(cast(void**)&SDL_GetNumAudioDevices, "SDL_GetNumAudioDevices"); + lib.bindSymbol(cast(void**)&SDL_GetAudioDeviceName, "SDL_GetAudioDeviceName"); + lib.bindSymbol(cast(void**)&SDL_OpenAudioDevice, "SDL_OpenAudioDevice"); + lib.bindSymbol(cast(void**)&SDL_GetAudioStatus, "SDL_GetAudioStatus"); + lib.bindSymbol(cast(void**)&SDL_GetAudioDeviceStatus, "SDL_GetAudioDeviceStatus"); + lib.bindSymbol(cast(void**)&SDL_PauseAudio, "SDL_PauseAudio"); + lib.bindSymbol(cast(void**)&SDL_PauseAudioDevice, "SDL_PauseAudioDevice"); + lib.bindSymbol(cast(void**)&SDL_LoadWAV_RW, "SDL_LoadWAV_RW"); + lib.bindSymbol(cast(void**)&SDL_FreeWAV, "SDL_FreeWAV"); + lib.bindSymbol(cast(void**)&SDL_BuildAudioCVT, "SDL_BuildAudioCVT"); + lib.bindSymbol(cast(void**)&SDL_ConvertAudio, "SDL_ConvertAudio"); + lib.bindSymbol(cast(void**)&SDL_MixAudio, "SDL_MixAudio"); + lib.bindSymbol(cast(void**)&SDL_MixAudioFormat, "SDL_MixAudioFormat"); + lib.bindSymbol(cast(void**)&SDL_LockAudio, "SDL_LockAudio"); + lib.bindSymbol(cast(void**)&SDL_LockAudioDevice, "SDL_LockAudioDevice"); + lib.bindSymbol(cast(void**)&SDL_UnlockAudio, "SDL_UnlockAudio"); + lib.bindSymbol(cast(void**)&SDL_UnlockAudioDevice, "SDL_UnlockAudioDevice"); + lib.bindSymbol(cast(void**)&SDL_CloseAudio, "SDL_CloseAudio"); + lib.bindSymbol(cast(void**)&SDL_CloseAudioDevice, "SDL_CloseAudioDevice"); + lib.bindSymbol(cast(void**)&SDL_SetClipboardText, "SDL_SetClipboardText"); + lib.bindSymbol(cast(void**)&SDL_GetClipboardText, "SDL_GetClipboardText"); + lib.bindSymbol(cast(void**)&SDL_HasClipboardText, "SDL_HasClipboardText"); + lib.bindSymbol(cast(void**)&SDL_GetCPUCount, "SDL_GetCPUCount"); + lib.bindSymbol(cast(void**)&SDL_GetCPUCacheLineSize, "SDL_GetCPUCacheLineSize"); + lib.bindSymbol(cast(void**)&SDL_HasRDTSC, "SDL_HasRDTSC"); + lib.bindSymbol(cast(void**)&SDL_HasAltiVec, "SDL_HasAltiVec"); + lib.bindSymbol(cast(void**)&SDL_HasMMX, "SDL_HasMMX"); + lib.bindSymbol(cast(void**)&SDL_Has3DNow, "SDL_Has3DNow"); + lib.bindSymbol(cast(void**)&SDL_HasSSE, "SDL_HasSSE"); + lib.bindSymbol(cast(void**)&SDL_HasSSE2, "SDL_HasSSE2"); + lib.bindSymbol(cast(void**)&SDL_HasSSE3, "SDL_HasSSE3"); + lib.bindSymbol(cast(void**)&SDL_HasSSE41, "SDL_HasSSE41"); + lib.bindSymbol(cast(void**)&SDL_HasSSE42, "SDL_HasSSE42"); + lib.bindSymbol(cast(void**)&SDL_SetError, "SDL_SetError"); + lib.bindSymbol(cast(void**)&SDL_GetError, "SDL_GetError"); + lib.bindSymbol(cast(void**)&SDL_ClearError, "SDL_ClearError"); + lib.bindSymbol(cast(void**)&SDL_PumpEvents, "SDL_PumpEvents"); + lib.bindSymbol(cast(void**)&SDL_PeepEvents, "SDL_PeepEvents"); + lib.bindSymbol(cast(void**)&SDL_HasEvent, "SDL_HasEvent"); + lib.bindSymbol(cast(void**)&SDL_HasEvents, "SDL_HasEvents"); + lib.bindSymbol(cast(void**)&SDL_FlushEvent, "SDL_FlushEvent"); + lib.bindSymbol(cast(void**)&SDL_FlushEvents, "SDL_FlushEvents"); + lib.bindSymbol(cast(void**)&SDL_PollEvent, "SDL_PollEvent"); + lib.bindSymbol(cast(void**)&SDL_WaitEvent, "SDL_WaitEvent"); + lib.bindSymbol(cast(void**)&SDL_WaitEventTimeout, "SDL_WaitEventTimeout"); + lib.bindSymbol(cast(void**)&SDL_PushEvent, "SDL_PushEvent"); + lib.bindSymbol(cast(void**)&SDL_SetEventFilter, "SDL_SetEventFilter"); + lib.bindSymbol(cast(void**)&SDL_GetEventFilter, "SDL_GetEventFilter"); + lib.bindSymbol(cast(void**)&SDL_AddEventWatch, "SDL_AddEventWatch"); + lib.bindSymbol(cast(void**)&SDL_DelEventWatch, "SDL_DelEventWatch"); + lib.bindSymbol(cast(void**)&SDL_FilterEvents, "SDL_FilterEvents"); + lib.bindSymbol(cast(void**)&SDL_EventState, "SDL_EventState"); + lib.bindSymbol(cast(void**)&SDL_RegisterEvents, "SDL_RegisterEvents"); + lib.bindSymbol(cast(void**)&SDL_GameControllerAddMapping, "SDL_GameControllerAddMapping"); + lib.bindSymbol(cast(void**)&SDL_GameControllerMappingForGUID, "SDL_GameControllerMappingForGUID"); + lib.bindSymbol(cast(void**)&SDL_GameControllerMapping, "SDL_GameControllerMapping"); + lib.bindSymbol(cast(void**)&SDL_IsGameController, "SDL_IsGameController"); + lib.bindSymbol(cast(void**)&SDL_GameControllerNameForIndex, "SDL_GameControllerNameForIndex"); + lib.bindSymbol(cast(void**)&SDL_GameControllerOpen, "SDL_GameControllerOpen"); + lib.bindSymbol(cast(void**)&SDL_GameControllerName, "SDL_GameControllerName"); + lib.bindSymbol(cast(void**)&SDL_GameControllerGetAttached, "SDL_GameControllerGetAttached"); + lib.bindSymbol(cast(void**)&SDL_GameControllerGetJoystick, "SDL_GameControllerGetJoystick"); + lib.bindSymbol(cast(void**)&SDL_GameControllerEventState, "SDL_GameControllerEventState"); + lib.bindSymbol(cast(void**)&SDL_GameControllerUpdate, "SDL_GameControllerUpdate"); + lib.bindSymbol(cast(void**)&SDL_GameControllerGetAxisFromString, "SDL_GameControllerGetAxisFromString"); + lib.bindSymbol(cast(void**)&SDL_GameControllerGetStringForAxis, "SDL_GameControllerGetStringForAxis"); + lib.bindSymbol(cast(void**)&SDL_GameControllerGetBindForAxis, "SDL_GameControllerGetBindForAxis"); + lib.bindSymbol(cast(void**)&SDL_GameControllerGetAxis, "SDL_GameControllerGetAxis"); + lib.bindSymbol(cast(void**)&SDL_GameControllerGetButtonFromString, "SDL_GameControllerGetButtonFromString"); + lib.bindSymbol(cast(void**)&SDL_GameControllerGetStringForButton, "SDL_GameControllerGetStringForButton"); + lib.bindSymbol(cast(void**)&SDL_GameControllerGetBindForButton, "SDL_GameControllerGetBindForButton"); + lib.bindSymbol(cast(void**)&SDL_GameControllerGetButton, "SDL_GameControllerGetButton"); + lib.bindSymbol(cast(void**)&SDL_GameControllerClose, "SDL_GameControllerClose"); + lib.bindSymbol(cast(void**)&SDL_RecordGesture, "SDL_RecordGesture"); + lib.bindSymbol(cast(void**)&SDL_SaveAllDollarTemplates, "SDL_SaveAllDollarTemplates"); + lib.bindSymbol(cast(void**)&SDL_SaveDollarTemplate, "SDL_SaveDollarTemplate"); + lib.bindSymbol(cast(void**)&SDL_LoadDollarTemplates, "SDL_LoadDollarTemplates"); + lib.bindSymbol(cast(void**)&SDL_NumHaptics, "SDL_NumHaptics"); + lib.bindSymbol(cast(void**)&SDL_HapticName, "SDL_HapticName"); + lib.bindSymbol(cast(void**)&SDL_HapticOpen, "SDL_HapticOpen"); + lib.bindSymbol(cast(void**)&SDL_HapticOpened, "SDL_HapticOpened"); + lib.bindSymbol(cast(void**)&SDL_HapticIndex, "SDL_HapticIndex"); + lib.bindSymbol(cast(void**)&SDL_MouseIsHaptic, "SDL_MouseIsHaptic"); + lib.bindSymbol(cast(void**)&SDL_HapticOpenFromMouse, "SDL_HapticOpenFromMouse"); + lib.bindSymbol(cast(void**)&SDL_JoystickIsHaptic, "SDL_JoystickIsHaptic"); + lib.bindSymbol(cast(void**)&SDL_HapticOpenFromJoystick, "SDL_HapticOpenFromJoystick"); + lib.bindSymbol(cast(void**)&SDL_HapticClose, "SDL_HapticClose"); + lib.bindSymbol(cast(void**)&SDL_HapticNumEffects, "SDL_HapticNumEffects"); + lib.bindSymbol(cast(void**)&SDL_HapticNumEffectsPlaying, "SDL_HapticNumEffectsPlaying"); + lib.bindSymbol(cast(void**)&SDL_HapticQuery, "SDL_HapticQuery"); + lib.bindSymbol(cast(void**)&SDL_HapticNumAxes, "SDL_HapticNumAxes"); + lib.bindSymbol(cast(void**)&SDL_HapticEffectSupported, "SDL_HapticEffectSupported"); + lib.bindSymbol(cast(void**)&SDL_HapticNewEffect, "SDL_HapticNewEffect"); + lib.bindSymbol(cast(void**)&SDL_HapticUpdateEffect, "SDL_HapticUpdateEffect"); + lib.bindSymbol(cast(void**)&SDL_HapticRunEffect, "SDL_HapticRunEffect"); + lib.bindSymbol(cast(void**)&SDL_HapticStopEffect, "SDL_HapticStopEffect"); + lib.bindSymbol(cast(void**)&SDL_HapticDestroyEffect, "SDL_HapticDestroyEffect"); + lib.bindSymbol(cast(void**)&SDL_HapticGetEffectStatus, "SDL_HapticGetEffectStatus"); + lib.bindSymbol(cast(void**)&SDL_HapticSetGain, "SDL_HapticSetGain"); + lib.bindSymbol(cast(void**)&SDL_HapticSetAutocenter, "SDL_HapticSetAutocenter"); + lib.bindSymbol(cast(void**)&SDL_HapticPause, "SDL_HapticPause"); + lib.bindSymbol(cast(void**)&SDL_HapticUnpause, "SDL_HapticUnpause"); + lib.bindSymbol(cast(void**)&SDL_HapticStopAll, "SDL_HapticStopAll"); + lib.bindSymbol(cast(void**)&SDL_HapticRumbleSupported, "SDL_HapticRumbleSupported"); + lib.bindSymbol(cast(void**)&SDL_HapticRumbleInit, "SDL_HapticRumbleInit"); + lib.bindSymbol(cast(void**)&SDL_HapticRumblePlay, "SDL_HapticRumblePlay"); + lib.bindSymbol(cast(void**)&SDL_HapticRumbleStop, "SDL_HapticRumbleStop"); + lib.bindSymbol(cast(void**)&SDL_SetHintWithPriority, "SDL_SetHintWithPriority"); + lib.bindSymbol(cast(void**)&SDL_SetHint, "SDL_SetHint"); + lib.bindSymbol(cast(void**)&SDL_GetHint, "SDL_GetHint"); + lib.bindSymbol(cast(void**)&SDL_AddHintCallback, "SDL_AddHintCallback"); + lib.bindSymbol(cast(void**)&SDL_DelHintCallback, "SDL_DelHintCallback"); + lib.bindSymbol(cast(void**)&SDL_ClearHints, "SDL_ClearHints"); + lib.bindSymbol(cast(void**)&SDL_NumJoysticks, "SDL_NumJoysticks"); + lib.bindSymbol(cast(void**)&SDL_JoystickNameForIndex, "SDL_JoystickNameForIndex"); + lib.bindSymbol(cast(void**)&SDL_JoystickOpen, "SDL_JoystickOpen"); + lib.bindSymbol(cast(void**)&SDL_JoystickName, "SDL_JoystickName"); + lib.bindSymbol(cast(void**)&SDL_JoystickGetDeviceGUID, "SDL_JoystickGetDeviceGUID"); + lib.bindSymbol(cast(void**)&SDL_JoystickGetGUID, "SDL_JoystickGetGUID"); + lib.bindSymbol(cast(void**)&SDL_JoystickGetGUIDString, "SDL_JoystickGetGUIDString"); + lib.bindSymbol(cast(void**)&SDL_JoystickGetGUIDFromString, "SDL_JoystickGetGUIDFromString"); + lib.bindSymbol(cast(void**)&SDL_JoystickGetAttached, "SDL_JoystickGetAttached"); + lib.bindSymbol(cast(void**)&SDL_JoystickInstanceID, "SDL_JoystickInstanceID"); + lib.bindSymbol(cast(void**)&SDL_JoystickNumAxes, "SDL_JoystickNumAxes"); + lib.bindSymbol(cast(void**)&SDL_JoystickNumBalls, "SDL_JoystickNumBalls"); + lib.bindSymbol(cast(void**)&SDL_JoystickNumHats, "SDL_JoystickNumHats"); + lib.bindSymbol(cast(void**)&SDL_JoystickNumButtons, "SDL_JoystickNumButtons"); + lib.bindSymbol(cast(void**)&SDL_JoystickUpdate, "SDL_JoystickUpdate"); + lib.bindSymbol(cast(void**)&SDL_JoystickEventState, "SDL_JoystickEventState"); + lib.bindSymbol(cast(void**)&SDL_JoystickGetAxis, "SDL_JoystickGetAxis"); + lib.bindSymbol(cast(void**)&SDL_JoystickGetHat, "SDL_JoystickGetHat"); + lib.bindSymbol(cast(void**)&SDL_JoystickGetBall, "SDL_JoystickGetBall"); + lib.bindSymbol(cast(void**)&SDL_JoystickGetButton, "SDL_JoystickGetButton"); + lib.bindSymbol(cast(void**)&SDL_JoystickClose, "SDL_JoystickClose"); + lib.bindSymbol(cast(void**)&SDL_GetKeyboardFocus, "SDL_GetKeyboardFocus"); + lib.bindSymbol(cast(void**)&SDL_GetKeyboardState, "SDL_GetKeyboardState"); + lib.bindSymbol(cast(void**)&SDL_GetModState, "SDL_GetModState"); + lib.bindSymbol(cast(void**)&SDL_SetModState, "SDL_SetModState"); + lib.bindSymbol(cast(void**)&SDL_GetKeyFromScancode, "SDL_GetKeyFromScancode"); + lib.bindSymbol(cast(void**)&SDL_GetScancodeFromKey, "SDL_GetScancodeFromKey"); + lib.bindSymbol(cast(void**)&SDL_GetScancodeName, "SDL_GetScancodeName"); + lib.bindSymbol(cast(void**)&SDL_GetScancodeFromName, "SDL_GetScancodeFromName"); + lib.bindSymbol(cast(void**)&SDL_GetKeyName, "SDL_GetKeyName"); + lib.bindSymbol(cast(void**)&SDL_GetKeyFromName, "SDL_GetKeyFromName"); + lib.bindSymbol(cast(void**)&SDL_StartTextInput, "SDL_StartTextInput"); + lib.bindSymbol(cast(void**)&SDL_IsTextInputActive, "SDL_IsTextInputActive"); + lib.bindSymbol(cast(void**)&SDL_StopTextInput, "SDL_StopTextInput"); + lib.bindSymbol(cast(void**)&SDL_SetTextInputRect, "SDL_SetTextInputRect"); + lib.bindSymbol(cast(void**)&SDL_HasScreenKeyboardSupport, "SDL_HasScreenKeyboardSupport"); + lib.bindSymbol(cast(void**)&SDL_IsScreenKeyboardShown, "SDL_IsScreenKeyboardShown"); + lib.bindSymbol(cast(void**)&SDL_LoadObject, "SDL_LoadObject"); + lib.bindSymbol(cast(void**)&SDL_LoadFunction, "SDL_LoadFunction"); + lib.bindSymbol(cast(void**)&SDL_UnloadObject, "SDL_UnloadObject"); + lib.bindSymbol(cast(void**)&SDL_LogSetAllPriority, "SDL_LogSetAllPriority"); + lib.bindSymbol(cast(void**)&SDL_LogSetPriority, "SDL_LogSetPriority"); + lib.bindSymbol(cast(void**)&SDL_LogGetPriority, "SDL_LogGetPriority"); + lib.bindSymbol(cast(void**)&SDL_LogResetPriorities, "SDL_LogResetPriorities"); + lib.bindSymbol(cast(void**)&SDL_Log, "SDL_Log"); + lib.bindSymbol(cast(void**)&SDL_LogVerbose, "SDL_LogVerbose"); + lib.bindSymbol(cast(void**)&SDL_LogDebug, "SDL_LogDebug"); + lib.bindSymbol(cast(void**)&SDL_LogInfo, "SDL_LogInfo"); + lib.bindSymbol(cast(void**)&SDL_LogWarn, "SDL_LogWarn"); + lib.bindSymbol(cast(void**)&SDL_LogError, "SDL_LogError"); + lib.bindSymbol(cast(void**)&SDL_LogCritical, "SDL_LogCritical"); + lib.bindSymbol(cast(void**)&SDL_LogMessage, "SDL_LogMessage"); + lib.bindSymbol(cast(void**)&SDL_LogMessageV, "SDL_LogMessageV"); + lib.bindSymbol(cast(void**)&SDL_LogGetOutputFunction, "SDL_LogGetOutputFunction"); + lib.bindSymbol(cast(void**)&SDL_LogSetOutputFunction, "SDL_LogSetOutputFunction"); + lib.bindSymbol(cast(void**)&SDL_ShowMessageBox, "SDL_ShowMessageBox"); + lib.bindSymbol(cast(void**)&SDL_ShowSimpleMessageBox, "SDL_ShowSimpleMessageBox"); + lib.bindSymbol(cast(void**)&SDL_GetMouseFocus, "SDL_GetMouseFocus"); + lib.bindSymbol(cast(void**)&SDL_GetMouseState, "SDL_GetMouseState"); + lib.bindSymbol(cast(void**)&SDL_GetRelativeMouseState, "SDL_GetRelativeMouseState"); + lib.bindSymbol(cast(void**)&SDL_WarpMouseInWindow, "SDL_WarpMouseInWindow"); + lib.bindSymbol(cast(void**)&SDL_SetRelativeMouseMode, "SDL_SetRelativeMouseMode"); + lib.bindSymbol(cast(void**)&SDL_GetRelativeMouseMode, "SDL_GetRelativeMouseMode"); + lib.bindSymbol(cast(void**)&SDL_CreateCursor, "SDL_CreateCursor"); + lib.bindSymbol(cast(void**)&SDL_CreateColorCursor, "SDL_CreateColorCursor"); + lib.bindSymbol(cast(void**)&SDL_CreateSystemCursor, "SDL_CreateSystemCursor"); + lib.bindSymbol(cast(void**)&SDL_SetCursor, "SDL_SetCursor"); + lib.bindSymbol(cast(void**)&SDL_GetCursor, "SDL_GetCursor"); + lib.bindSymbol(cast(void**)&SDL_GetDefaultCursor, "SDL_GetDefaultCursor"); + lib.bindSymbol(cast(void**)&SDL_FreeCursor, "SDL_FreeCursor"); + lib.bindSymbol(cast(void**)&SDL_ShowCursor, "SDL_ShowCursor"); + lib.bindSymbol(cast(void**)&SDL_GetPixelFormatName, "SDL_GetPixelFormatName"); + lib.bindSymbol(cast(void**)&SDL_PixelFormatEnumToMasks, "SDL_PixelFormatEnumToMasks"); + lib.bindSymbol(cast(void**)&SDL_MasksToPixelFormatEnum, "SDL_MasksToPixelFormatEnum"); + lib.bindSymbol(cast(void**)&SDL_AllocFormat, "SDL_AllocFormat"); + lib.bindSymbol(cast(void**)&SDL_FreeFormat, "SDL_FreeFormat"); + lib.bindSymbol(cast(void**)&SDL_AllocPalette, "SDL_AllocPalette"); + lib.bindSymbol(cast(void**)&SDL_SetPixelFormatPalette, "SDL_SetPixelFormatPalette"); + lib.bindSymbol(cast(void**)&SDL_SetPaletteColors, "SDL_SetPaletteColors"); + lib.bindSymbol(cast(void**)&SDL_FreePalette, "SDL_FreePalette"); + lib.bindSymbol(cast(void**)&SDL_MapRGB, "SDL_MapRGB"); + lib.bindSymbol(cast(void**)&SDL_MapRGBA, "SDL_MapRGBA"); + lib.bindSymbol(cast(void**)&SDL_GetRGB, "SDL_GetRGB"); + lib.bindSymbol(cast(void**)&SDL_GetRGBA, "SDL_GetRGBA"); + lib.bindSymbol(cast(void**)&SDL_CalculateGammaRamp, "SDL_CalculateGammaRamp"); + lib.bindSymbol(cast(void**)&SDL_GetPlatform, "SDL_GetPlatform"); + lib.bindSymbol(cast(void**)&SDL_GetPowerInfo, "SDL_GetPowerInfo"); + lib.bindSymbol(cast(void**)&SDL_HasIntersection, "SDL_HasIntersection"); + lib.bindSymbol(cast(void**)&SDL_IntersectRect, "SDL_IntersectRect"); + lib.bindSymbol(cast(void**)&SDL_UnionRect, "SDL_UnionRect"); + lib.bindSymbol(cast(void**)&SDL_EnclosePoints, "SDL_EnclosePoints"); + lib.bindSymbol(cast(void**)&SDL_IntersectRectAndLine, "SDL_IntersectRectAndLine"); + lib.bindSymbol(cast(void**)&SDL_GetNumRenderDrivers, "SDL_GetNumRenderDrivers"); + lib.bindSymbol(cast(void**)&SDL_GetRenderDriverInfo, "SDL_GetRenderDriverInfo"); + lib.bindSymbol(cast(void**)&SDL_CreateWindowAndRenderer, "SDL_CreateWindowAndRenderer"); + lib.bindSymbol(cast(void**)&SDL_CreateRenderer, "SDL_CreateRenderer"); + lib.bindSymbol(cast(void**)&SDL_CreateSoftwareRenderer, "SDL_CreateSoftwareRenderer"); + lib.bindSymbol(cast(void**)&SDL_GetRenderer, "SDL_GetRenderer"); + lib.bindSymbol(cast(void**)&SDL_GetRendererInfo, "SDL_GetRendererInfo"); + lib.bindSymbol(cast(void**)&SDL_GetRendererOutputSize, "SDL_GetRendererOutputSize"); + lib.bindSymbol(cast(void**)&SDL_CreateTexture, "SDL_CreateTexture"); + lib.bindSymbol(cast(void**)&SDL_CreateTextureFromSurface, "SDL_CreateTextureFromSurface"); + lib.bindSymbol(cast(void**)&SDL_QueryTexture, "SDL_QueryTexture"); + lib.bindSymbol(cast(void**)&SDL_SetTextureColorMod, "SDL_SetTextureColorMod"); + lib.bindSymbol(cast(void**)&SDL_GetTextureColorMod, "SDL_GetTextureColorMod"); + lib.bindSymbol(cast(void**)&SDL_SetTextureAlphaMod, "SDL_SetTextureAlphaMod"); + lib.bindSymbol(cast(void**)&SDL_GetTextureAlphaMod, "SDL_GetTextureAlphaMod"); + lib.bindSymbol(cast(void**)&SDL_SetTextureBlendMode, "SDL_SetTextureBlendMode"); + lib.bindSymbol(cast(void**)&SDL_GetTextureBlendMode, "SDL_GetTextureBlendMode"); + lib.bindSymbol(cast(void**)&SDL_UpdateTexture, "SDL_UpdateTexture"); + lib.bindSymbol(cast(void**)&SDL_LockTexture, "SDL_LockTexture"); + lib.bindSymbol(cast(void**)&SDL_UnlockTexture, "SDL_UnlockTexture"); + lib.bindSymbol(cast(void**)&SDL_RenderTargetSupported, "SDL_RenderTargetSupported"); + lib.bindSymbol(cast(void**)&SDL_SetRenderTarget, "SDL_SetRenderTarget"); + lib.bindSymbol(cast(void**)&SDL_GetRenderTarget, "SDL_GetRenderTarget"); + lib.bindSymbol(cast(void**)&SDL_RenderSetClipRect, "SDL_RenderSetClipRect"); + lib.bindSymbol(cast(void**)&SDL_RenderGetClipRect, "SDL_RenderGetClipRect"); + lib.bindSymbol(cast(void**)&SDL_RenderSetLogicalSize, "SDL_RenderSetLogicalSize"); + lib.bindSymbol(cast(void**)&SDL_RenderGetLogicalSize, "SDL_RenderGetLogicalSize"); + lib.bindSymbol(cast(void**)&SDL_RenderSetViewport, "SDL_RenderSetViewport"); + lib.bindSymbol(cast(void**)&SDL_RenderGetViewport, "SDL_RenderGetViewport"); + lib.bindSymbol(cast(void**)&SDL_RenderSetScale, "SDL_RenderSetScale"); + lib.bindSymbol(cast(void**)&SDL_RenderGetScale, "SDL_RenderGetScale"); + lib.bindSymbol(cast(void**)&SDL_SetRenderDrawColor, "SDL_SetRenderDrawColor"); + lib.bindSymbol(cast(void**)&SDL_GetRenderDrawColor, "SDL_GetRenderDrawColor"); + lib.bindSymbol(cast(void**)&SDL_SetRenderDrawBlendMode, "SDL_SetRenderDrawBlendMode"); + lib.bindSymbol(cast(void**)&SDL_GetRenderDrawBlendMode, "SDL_GetRenderDrawBlendMode"); + lib.bindSymbol(cast(void**)&SDL_RenderClear, "SDL_RenderClear"); + lib.bindSymbol(cast(void**)&SDL_RenderDrawPoint, "SDL_RenderDrawPoint"); + lib.bindSymbol(cast(void**)&SDL_RenderDrawPoints, "SDL_RenderDrawPoints"); + lib.bindSymbol(cast(void**)&SDL_RenderDrawLine, "SDL_RenderDrawLine"); + lib.bindSymbol(cast(void**)&SDL_RenderDrawLines, "SDL_RenderDrawLines"); + lib.bindSymbol(cast(void**)&SDL_RenderDrawRect, "SDL_RenderDrawRect"); + lib.bindSymbol(cast(void**)&SDL_RenderDrawRects, "SDL_RenderDrawRects"); + lib.bindSymbol(cast(void**)&SDL_RenderFillRect, "SDL_RenderFillRect"); + lib.bindSymbol(cast(void**)&SDL_RenderFillRects, "SDL_RenderFillRects"); + lib.bindSymbol(cast(void**)&SDL_RenderCopy, "SDL_RenderCopy"); + lib.bindSymbol(cast(void**)&SDL_RenderCopyEx, "SDL_RenderCopyEx"); + lib.bindSymbol(cast(void**)&SDL_RenderReadPixels, "SDL_RenderReadPixels"); + lib.bindSymbol(cast(void**)&SDL_RenderPresent, "SDL_RenderPresent"); + lib.bindSymbol(cast(void**)&SDL_DestroyTexture, "SDL_DestroyTexture"); + lib.bindSymbol(cast(void**)&SDL_DestroyRenderer, "SDL_DestroyRenderer"); + lib.bindSymbol(cast(void**)&SDL_GL_BindTexture, "SDL_GL_BindTexture"); + lib.bindSymbol(cast(void**)&SDL_GL_UnbindTexture, "SDL_GL_UnbindTexture"); + lib.bindSymbol(cast(void**)&SDL_RWFromFile, "SDL_RWFromFile"); + lib.bindSymbol(cast(void**)&SDL_RWFromFP, "SDL_RWFromFP"); + lib.bindSymbol(cast(void**)&SDL_RWFromMem, "SDL_RWFromMem"); + lib.bindSymbol(cast(void**)&SDL_RWFromConstMem, "SDL_RWFromConstMem"); + lib.bindSymbol(cast(void**)&SDL_AllocRW, "SDL_AllocRW"); + lib.bindSymbol(cast(void**)&SDL_FreeRW, "SDL_FreeRW"); + lib.bindSymbol(cast(void**)&SDL_ReadU8, "SDL_ReadU8"); + lib.bindSymbol(cast(void**)&SDL_ReadLE16, "SDL_ReadLE16"); + lib.bindSymbol(cast(void**)&SDL_ReadBE16, "SDL_ReadBE16"); + lib.bindSymbol(cast(void**)&SDL_ReadLE32, "SDL_ReadLE32"); + lib.bindSymbol(cast(void**)&SDL_ReadBE32, "SDL_ReadBE32"); + lib.bindSymbol(cast(void**)&SDL_ReadLE64, "SDL_ReadLE64"); + lib.bindSymbol(cast(void**)&SDL_ReadBE64, "SDL_ReadBE64"); + lib.bindSymbol(cast(void**)&SDL_WriteU8, "SDL_WriteU8"); + lib.bindSymbol(cast(void**)&SDL_WriteLE16, "SDL_WriteLE16"); + lib.bindSymbol(cast(void**)&SDL_WriteBE16, "SDL_WriteBE16"); + lib.bindSymbol(cast(void**)&SDL_WriteLE32, "SDL_WriteLE32"); + lib.bindSymbol(cast(void**)&SDL_WriteBE32, "SDL_WriteBE32"); + lib.bindSymbol(cast(void**)&SDL_WriteLE64, "SDL_WriteLE64"); + lib.bindSymbol(cast(void**)&SDL_WriteBE64, "SDL_WriteBE64"); + lib.bindSymbol(cast(void**)&SDL_CreateShapedWindow, "SDL_CreateShapedWindow"); + lib.bindSymbol(cast(void**)&SDL_IsShapedWindow, "SDL_IsShapedWindow"); + lib.bindSymbol(cast(void**)&SDL_SetWindowShape, "SDL_SetWindowShape"); + lib.bindSymbol(cast(void**)&SDL_GetShapedWindowMode, "SDL_GetShapedWindowMode"); + lib.bindSymbol(cast(void**)&SDL_free, "SDL_free"); + lib.bindSymbol(cast(void**)&SDL_CreateRGBSurface, "SDL_CreateRGBSurface"); + lib.bindSymbol(cast(void**)&SDL_CreateRGBSurfaceFrom, "SDL_CreateRGBSurfaceFrom"); + lib.bindSymbol(cast(void**)&SDL_FreeSurface, "SDL_FreeSurface"); + lib.bindSymbol(cast(void**)&SDL_SetSurfacePalette, "SDL_SetSurfacePalette"); + lib.bindSymbol(cast(void**)&SDL_LockSurface, "SDL_LockSurface"); + lib.bindSymbol(cast(void**)&SDL_UnlockSurface, "SDL_UnlockSurface"); + lib.bindSymbol(cast(void**)&SDL_LoadBMP_RW, "SDL_LoadBMP_RW"); + lib.bindSymbol(cast(void**)&SDL_SaveBMP_RW, "SDL_SaveBMP_RW"); + lib.bindSymbol(cast(void**)&SDL_SetSurfaceRLE, "SDL_SetSurfaceRLE"); + lib.bindSymbol(cast(void**)&SDL_SetColorKey, "SDL_SetColorKey"); + lib.bindSymbol(cast(void**)&SDL_GetColorKey, "SDL_GetColorKey"); + lib.bindSymbol(cast(void**)&SDL_SetSurfaceColorMod, "SDL_SetSurfaceColorMod"); + lib.bindSymbol(cast(void**)&SDL_GetSurfaceColorMod, "SDL_GetSurfaceColorMod"); + lib.bindSymbol(cast(void**)&SDL_SetSurfaceAlphaMod, "SDL_SetSurfaceAlphaMod"); + lib.bindSymbol(cast(void**)&SDL_GetSurfaceAlphaMod, "SDL_GetSurfaceAlphaMod"); + lib.bindSymbol(cast(void**)&SDL_SetSurfaceBlendMode, "SDL_SetSurfaceBlendMode"); + lib.bindSymbol(cast(void**)&SDL_GetSurfaceBlendMode, "SDL_GetSurfaceBlendMode"); + lib.bindSymbol(cast(void**)&SDL_SetClipRect, "SDL_SetClipRect"); + lib.bindSymbol(cast(void**)&SDL_GetClipRect, "SDL_GetClipRect"); + lib.bindSymbol(cast(void**)&SDL_ConvertSurface, "SDL_ConvertSurface"); + lib.bindSymbol(cast(void**)&SDL_ConvertSurfaceFormat, "SDL_ConvertSurfaceFormat"); + lib.bindSymbol(cast(void**)&SDL_ConvertPixels, "SDL_ConvertPixels"); + lib.bindSymbol(cast(void**)&SDL_FillRect, "SDL_FillRect"); + lib.bindSymbol(cast(void**)&SDL_FillRects, "SDL_FillRects"); + lib.bindSymbol(cast(void**)&SDL_UpperBlit, "SDL_UpperBlit"); + lib.bindSymbol(cast(void**)&SDL_LowerBlit, "SDL_LowerBlit"); + lib.bindSymbol(cast(void**)&SDL_SoftStretch, "SDL_SoftStretch"); + lib.bindSymbol(cast(void**)&SDL_UpperBlitScaled, "SDL_UpperBlitScaled"); + lib.bindSymbol(cast(void**)&SDL_LowerBlitScaled, "SDL_LowerBlitScaled"); + version(Android) { + lib.bindSymbol(cast(void**)&SDL_AndroidGetJNIEnv, "SDL_AndroidGetJNIEnv"); + lib.bindSymbol(cast(void**)&SDL_AndroidGetActivity, "SDL_AndroidGetActivity"); + + lib.bindSymbol(cast(void**)&SDL_AndroidGetInternalStoragePath, "SDL_AndroidGetInternalStoragePath"); + lib.bindSymbol(cast(void**)&SDL_AndroidGetInternalStorageState, "SDL_AndroidGetInternalStorageState"); + lib.bindSymbol(cast(void**)&SDL_AndroidGetExternalStoragePath, "SDL_AndroidGetExternalStoragePath"); + } + + lib.bindSymbol(cast(void**)&SDL_GetWindowWMInfo, "SDL_GetWindowWMInfo"); + lib.bindSymbol(cast(void**)&SDL_GetTicks, "SDL_GetTicks"); + lib.bindSymbol(cast(void**)&SDL_GetPerformanceCounter, "SDL_GetPerformanceCounter"); + lib.bindSymbol(cast(void**)&SDL_GetPerformanceFrequency, "SDL_GetPerformanceFrequency"); + lib.bindSymbol(cast(void**)&SDL_Delay, "SDL_Delay"); + lib.bindSymbol(cast(void**)&SDL_AddTimer, "SDL_AddTimer"); + lib.bindSymbol(cast(void**)&SDL_RemoveTimer, "SDL_RemoveTimer"); + lib.bindSymbol(cast(void**)&SDL_GetNumTouchDevices, "SDL_GetNumTouchDevices"); + lib.bindSymbol(cast(void**)&SDL_GetTouchDevice, "SDL_GetTouchDevice"); + lib.bindSymbol(cast(void**)&SDL_GetNumTouchFingers, "SDL_GetNumTouchFingers"); + lib.bindSymbol(cast(void**)&SDL_GetTouchFinger, "SDL_GetTouchFinger"); + lib.bindSymbol(cast(void**)&SDL_GetVersion, "SDL_GetVersion"); + lib.bindSymbol(cast(void**)&SDL_GetRevision, "SDL_GetRevision"); + lib.bindSymbol(cast(void**)&SDL_GetRevisionNumber, "SDL_GetRevisionNumber"); + lib.bindSymbol(cast(void**)&SDL_GetNumVideoDrivers, "SDL_GetNumVideoDrivers"); + lib.bindSymbol(cast(void**)&SDL_GetVideoDriver, "SDL_GetVideoDriver"); + lib.bindSymbol(cast(void**)&SDL_VideoInit, "SDL_VideoInit"); + lib.bindSymbol(cast(void**)&SDL_VideoQuit, "SDL_VideoQuit"); + lib.bindSymbol(cast(void**)&SDL_GetCurrentVideoDriver, "SDL_GetCurrentVideoDriver"); + lib.bindSymbol(cast(void**)&SDL_GetNumVideoDisplays, "SDL_GetNumVideoDisplays"); + lib.bindSymbol(cast(void**)&SDL_GetDisplayName, "SDL_GetDisplayName"); + lib.bindSymbol(cast(void**)&SDL_GetDisplayBounds, "SDL_GetDisplayBounds"); + lib.bindSymbol(cast(void**)&SDL_GetNumDisplayModes, "SDL_GetNumDisplayModes"); + lib.bindSymbol(cast(void**)&SDL_GetDisplayMode, "SDL_GetDisplayMode"); + lib.bindSymbol(cast(void**)&SDL_GetDesktopDisplayMode, "SDL_GetDesktopDisplayMode"); + lib.bindSymbol(cast(void**)&SDL_GetCurrentDisplayMode, "SDL_GetCurrentDisplayMode"); + lib.bindSymbol(cast(void**)&SDL_GetClosestDisplayMode, "SDL_GetClosestDisplayMode"); + lib.bindSymbol(cast(void**)&SDL_GetWindowDisplayIndex, "SDL_GetWindowDisplayIndex"); + lib.bindSymbol(cast(void**)&SDL_SetWindowDisplayMode, "SDL_SetWindowDisplayMode"); + lib.bindSymbol(cast(void**)&SDL_GetWindowDisplayMode, "SDL_GetWindowDisplayMode"); + lib.bindSymbol(cast(void**)&SDL_GetWindowPixelFormat, "SDL_GetWindowPixelFormat"); + lib.bindSymbol(cast(void**)&SDL_CreateWindow, "SDL_CreateWindow"); + lib.bindSymbol(cast(void**)&SDL_CreateWindowFrom, "SDL_CreateWindowFrom"); + lib.bindSymbol(cast(void**)&SDL_GetWindowID, "SDL_GetWindowID"); + lib.bindSymbol(cast(void**)&SDL_GetWindowFromID, "SDL_GetWindowFromID"); + lib.bindSymbol(cast(void**)&SDL_GetWindowFlags, "SDL_GetWindowFlags"); + lib.bindSymbol(cast(void**)&SDL_SetWindowTitle, "SDL_SetWindowTitle"); + lib.bindSymbol(cast(void**)&SDL_GetWindowTitle, "SDL_GetWindowTitle"); + lib.bindSymbol(cast(void**)&SDL_SetWindowIcon, "SDL_SetWindowIcon"); + lib.bindSymbol(cast(void**)&SDL_SetWindowData, "SDL_SetWindowData"); + lib.bindSymbol(cast(void**)&SDL_GetWindowData, "SDL_GetWindowData"); + lib.bindSymbol(cast(void**)&SDL_SetWindowPosition, "SDL_SetWindowPosition"); + lib.bindSymbol(cast(void**)&SDL_GetWindowPosition, "SDL_GetWindowPosition"); + lib.bindSymbol(cast(void**)&SDL_SetWindowSize, "SDL_SetWindowSize"); + lib.bindSymbol(cast(void**)&SDL_GetWindowSize, "SDL_GetWindowSize"); + lib.bindSymbol(cast(void**)&SDL_SetWindowMinimumSize, "SDL_SetWindowMinimumSize"); + lib.bindSymbol(cast(void**)&SDL_GetWindowMinimumSize, "SDL_GetWindowMinimumSize"); + lib.bindSymbol(cast(void**)&SDL_SetWindowMaximumSize, "SDL_SetWindowMaximumSize"); + lib.bindSymbol(cast(void**)&SDL_GetWindowMaximumSize, "SDL_GetWindowMaximumSize"); + lib.bindSymbol(cast(void**)&SDL_SetWindowBordered, "SDL_SetWindowBordered"); + lib.bindSymbol(cast(void**)&SDL_ShowWindow, "SDL_ShowWindow"); + lib.bindSymbol(cast(void**)&SDL_HideWindow, "SDL_HideWindow"); + lib.bindSymbol(cast(void**)&SDL_RaiseWindow, "SDL_RaiseWindow"); + lib.bindSymbol(cast(void**)&SDL_MaximizeWindow, "SDL_MaximizeWindow"); + lib.bindSymbol(cast(void**)&SDL_MinimizeWindow, "SDL_MinimizeWindow"); + lib.bindSymbol(cast(void**)&SDL_RestoreWindow, "SDL_RestoreWindow"); + lib.bindSymbol(cast(void**)&SDL_SetWindowFullscreen, "SDL_SetWindowFullscreen"); + lib.bindSymbol(cast(void**)&SDL_GetWindowSurface, "SDL_GetWindowSurface"); + lib.bindSymbol(cast(void**)&SDL_UpdateWindowSurface, "SDL_UpdateWindowSurface"); + lib.bindSymbol(cast(void**)&SDL_UpdateWindowSurfaceRects, "SDL_UpdateWindowSurfaceRects"); + lib.bindSymbol(cast(void**)&SDL_SetWindowGrab, "SDL_SetWindowGrab"); + lib.bindSymbol(cast(void**)&SDL_GetWindowGrab, "SDL_GetWindowGrab"); + lib.bindSymbol(cast(void**)&SDL_SetWindowBrightness, "SDL_SetWindowBrightness"); + lib.bindSymbol(cast(void**)&SDL_GetWindowBrightness, "SDL_GetWindowBrightness"); + lib.bindSymbol(cast(void**)&SDL_SetWindowGammaRamp, "SDL_SetWindowGammaRamp"); + lib.bindSymbol(cast(void**)&SDL_GetWindowGammaRamp, "SDL_GetWindowGammaRamp"); + lib.bindSymbol(cast(void**)&SDL_DestroyWindow, "SDL_DestroyWindow"); + lib.bindSymbol(cast(void**)&SDL_IsScreenSaverEnabled, "SDL_IsScreenSaverEnabled"); + lib.bindSymbol(cast(void**)&SDL_EnableScreenSaver, "SDL_EnableScreenSaver"); + lib.bindSymbol(cast(void**)&SDL_DisableScreenSaver, "SDL_DisableScreenSaver"); + lib.bindSymbol(cast(void**)&SDL_GL_LoadLibrary, "SDL_GL_LoadLibrary"); + lib.bindSymbol(cast(void**)&SDL_GL_GetProcAddress, "SDL_GL_GetProcAddress"); + lib.bindSymbol(cast(void**)&SDL_GL_UnloadLibrary, "SDL_GL_UnloadLibrary"); + lib.bindSymbol(cast(void**)&SDL_GL_ExtensionSupported, "SDL_GL_ExtensionSupported"); + lib.bindSymbol(cast(void**)&SDL_GL_SetAttribute, "SDL_GL_SetAttribute"); + lib.bindSymbol(cast(void**)&SDL_GL_GetAttribute, "SDL_GL_GetAttribute"); + lib.bindSymbol(cast(void**)&SDL_GL_CreateContext, "SDL_GL_CreateContext"); + lib.bindSymbol(cast(void**)&SDL_GL_MakeCurrent, "SDL_GL_MakeCurrent"); + lib.bindSymbol(cast(void**)&SDL_GL_GetCurrentWindow, "SDL_GL_GetCurrentWindow"); + lib.bindSymbol(cast(void**)&SDL_GL_GetCurrentContext, "SDL_GL_GetCurrentContext"); + lib.bindSymbol(cast(void**)&SDL_GL_SetSwapInterval, "SDL_GL_SetSwapInterval"); + lib.bindSymbol(cast(void**)&SDL_GL_GetSwapInterval, "SDL_GL_GetSwapInterval"); + lib.bindSymbol(cast(void**)&SDL_GL_SwapWindow, "SDL_GL_SwapWindow"); + lib.bindSymbol(cast(void**)&SDL_GL_DeleteContext, "SDL_GL_DeleteContext"); + + if(errorCount() != errCount) return SDLSupport.badLibrary; + else loadedVersion = SDLSupport.sdl200; + + static if(sdlSupport >= SDLSupport.sdl201) { + lib.bindSymbol(cast(void**)&SDL_GetSystemRAM, "SDL_GetSystemRAM"); + lib.bindSymbol(cast(void**)&SDL_GetBasePath, "SDL_GetBasePath"); + lib.bindSymbol(cast(void**)&SDL_GetPrefPath, "SDL_GetPrefPath"); + lib.bindSymbol(cast(void**)&SDL_UpdateYUVTexture, "SDL_UpdateYUVTexture"); + lib.bindSymbol(cast(void**)&SDL_GL_GetDrawableSize, "SDL_GL_GetDrawableSize"); + + version(Windows) { + lib.bindSymbol(cast(void**)&SDL_Direct3D9GetAdapterIndex, "SDL_Direct3D9GetAdapterIndex") ; + lib.bindSymbol(cast(void**)&SDL_RenderGetD3D9Device, "SDL_RenderGetD3D9Device"); + } + + if(errorCount() != errCount) return SDLSupport.badLibrary; + else loadedVersion = SDLSupport.sdl201; + } + + static if(sdlSupport >= SDLSupport.sdl202) { + lib.bindSymbol(cast(void**)&SDL_GetDefaultAssertionHandler, "SDL_GetDefaultAssertionHandler"); + lib.bindSymbol(cast(void**)&SDL_GetAssertionHandler, "SDL_GetAssertionHandler"); + lib.bindSymbol(cast(void**)&SDL_HasAVX, "SDL_HasAVX"); + lib.bindSymbol(cast(void**)&SDL_GameControllerAddMappingsFromRW, "SDL_GameControllerAddMappingsFromRW"); + lib.bindSymbol(cast(void**)&SDL_GL_ResetAttributes, "SDL_GL_ResetAttributes"); + + version(Windows) { + lib.bindSymbol(cast(void**)&SDL_DXGIGetOutputInfo, "SDL_DXGIGetOutputInfo"); + } + + if(errorCount() != errCount) return SDLSupport.badLibrary; + else loadedVersion = SDLSupport.sdl202; + } + + static if(sdlSupport >= SDLSupport.sdl203) { + loadedVersion = SDLSupport.sdl203; + } + + static if(sdlSupport >= SDLSupport.sdl204) { + lib.bindSymbol(cast(void**)&SDL_ClearQueuedAudio, "SDL_ClearQueuedAudio"); + lib.bindSymbol(cast(void**)&SDL_GetQueuedAudioSize, "SDL_GetQueuedAudioSize"); + lib.bindSymbol(cast(void**)&SDL_QueueAudio, "SDL_QueueAudio"); + lib.bindSymbol(cast(void**)&SDL_HasAVX2, "SDL_HasAVX2"); + lib.bindSymbol(cast(void**)&SDL_GameControllerFromInstanceID, "SDL_GameControllerFromInstanceID"); + lib.bindSymbol(cast(void**)&SDL_JoystickCurrentPowerLevel, "SDL_JoystickCurrentPowerLevel"); + lib.bindSymbol(cast(void**)&SDL_JoystickFromInstanceID, "SDL_JoystickFromInstanceID"); + lib.bindSymbol(cast(void**)&SDL_CaptureMouse, "SDL_CaptureMouse"); + lib.bindSymbol(cast(void**)&SDL_GetGlobalMouseState, "SDL_GetGlobalMouseState"); + lib.bindSymbol(cast(void**)&SDL_WarpMouseGlobal, "SDL_WarpMouseGlobal"); + lib.bindSymbol(cast(void**)&SDL_RenderIsClipEnabled, "SDL_RenderIsClipEnabled"); + lib.bindSymbol(cast(void**)&SDL_GetDisplayDPI, "SDL_GetDisplayDPI"); + lib.bindSymbol(cast(void**)&SDL_GetGrabbedWindow, "SDL_GetGrabbedWindow"); + lib.bindSymbol(cast(void**)&SDL_SetWindowHitTest, "SDL_SetWindowHitTest"); + + version(Windows) { + lib.bindSymbol(cast(void**)&SDL_SetWindowsMessageHook, "SDL_SetWindowsMessageHook"); + } + + if(errorCount() != errCount) return SDLSupport.badLibrary; + else loadedVersion = SDLSupport.sdl204; + } + + static if(sdlSupport >= SDLSupport.sdl205) { + lib.bindSymbol(cast(void**)&SDL_DequeueAudio, "SDL_DequeueAudio"); + lib.bindSymbol(cast(void**)&SDL_GetHintBoolean, "SDL_GetHintBoolean"); + lib.bindSymbol(cast(void**)&SDL_RenderGetIntegerScale, "SDL_RenderGetIntegerScale"); + lib.bindSymbol(cast(void**)&SDL_RenderSetIntegerScale, "SDL_RenderSetIntegerScale"); + lib.bindSymbol(cast(void**)&SDL_CreateRGBSurfaceWithFormat, "SDL_CreateRGBSurfaceWithFormat"); + lib.bindSymbol(cast(void**)&SDL_CreateRGBSurfaceWithFormatFrom, "SDL_CreateRGBSurfaceWithFormatFrom"); + lib.bindSymbol(cast(void**)&SDL_GetDisplayUsableBounds, "SDL_GetDisplayUsableBounds"); + lib.bindSymbol(cast(void**)&SDL_GetWindowBordersSize, "SDL_GetWindowBordersSize"); + lib.bindSymbol(cast(void**)&SDL_GetWindowOpacity, "SDL_GetWindowOpacity"); + lib.bindSymbol(cast(void**)&SDL_SetWindowInputFocus, "SDL_SetWindowInputFocus"); + lib.bindSymbol(cast(void**)&SDL_SetWindowModalFor, "SDL_SetWindowModalFor"); + lib.bindSymbol(cast(void**)&SDL_SetWindowOpacity, "SDL_SetWindowOpacity"); + lib.bindSymbol(cast(void**)&SDL_SetWindowResizable, "SDL_SetWindowResizable"); + + if(errorCount() != errCount) return SDLSupport.badLibrary; + else loadedVersion = SDLSupport.sdl205; + } + + static if(sdlSupport >= SDLSupport.sdl206) { + lib.bindSymbol(cast(void**)&SDL_ComposeCustomBlendMode, "SDL_ComposeCustomBlendMode"); + lib.bindSymbol(cast(void**)&SDL_HasNEON, "SDL_HasNEON"); + lib.bindSymbol(cast(void**)&SDL_GameControllerGetVendor, "SDL_GameControllerGetVendor"); + lib.bindSymbol(cast(void**)&SDL_GameControllerGetProduct, "SDL_GameControllerGetProduct"); + lib.bindSymbol(cast(void**)&SDL_GameControllerGetProductVersion, "SDL_GameControllerGetProductVersion"); + lib.bindSymbol(cast(void**)&SDL_GameControllerMappingForIndex, "SDL_GameControllerMappingForIndex"); + lib.bindSymbol(cast(void**)&SDL_GameControllerNumMappings, "SDL_GameControllerNumMappings"); + lib.bindSymbol(cast(void**)&SDL_JoystickGetAxisInitialState, "SDL_JoystickGetAxisInitialState"); + lib.bindSymbol(cast(void**)&SDL_JoystickGetDeviceVendor, "SDL_JoystickGetDeviceVendor"); + lib.bindSymbol(cast(void**)&SDL_JoystickGetDeviceProduct, "SDL_JoystickGetDeviceProduct"); + lib.bindSymbol(cast(void**)&SDL_JoystickGetDeviceProductVersion, "SDL_JoystickGetDeviceProductVersion"); + lib.bindSymbol(cast(void**)&SDL_JoystickGetDeviceInstanceID, "SDL_JoystickGetDeviceInstanceID"); + lib.bindSymbol(cast(void**)&SDL_JoystickGetDeviceType, "SDL_JoystickGetDeviceType"); + lib.bindSymbol(cast(void**)&SDL_JoystickGetProduct, "SDL_JoystickGetProduct"); + lib.bindSymbol(cast(void**)&SDL_JoystickGetProductVersion, "SDL_JoystickGetProductVersion"); + lib.bindSymbol(cast(void**)&SDL_JoystickGetType, "SDL_JoystickGetType"); + lib.bindSymbol(cast(void**)&SDL_JoystickGetVendor, "SDL_JoystickGetVendor"); + lib.bindSymbol(cast(void**)&SDL_LoadFile_RW, "SDL_LoadFile_RW"); + lib.bindSymbol(cast(void**)&SDL_DuplicateSurface, "SDL_DuplicateSurface"); + lib.bindSymbol(cast(void**)&SDL_Vulkan_CreateSurface, "SDL_Vulkan_CreateSurface"); + lib.bindSymbol(cast(void**)&SDL_Vulkan_GetDrawableSize, "SDL_Vulkan_GetDrawableSize"); + lib.bindSymbol(cast(void**)&SDL_Vulkan_GetInstanceExtensions, "SDL_Vulkan_GetInstanceExtensions"); + lib.bindSymbol(cast(void**)&SDL_Vulkan_GetVkGetInstanceProcAddr, "SDL_Vulkan_GetVkGetInstanceProcAddr"); + lib.bindSymbol(cast(void**)&SDL_Vulkan_LoadLibrary, "SDL_Vulkan_LoadLibrary"); + lib.bindSymbol(cast(void**)&SDL_Vulkan_UnloadLibrary, "SDL_Vulkan_UnloadLibrary"); + + if(errorCount() != errCount) return SDLSupport.badLibrary; + else loadedVersion = SDLSupport.sdl206; + } + + static if(sdlSupport >= SDLSupport.sdl207) { + lib.bindSymbol(cast(void**)&SDL_NewAudioStream, "SDL_NewAudioStream"); + lib.bindSymbol(cast(void**)&SDL_AudioStreamPut, "SDL_AudioStreamPut"); + lib.bindSymbol(cast(void**)&SDL_AudioStreamGet, "SDL_AudioStreamGet"); + lib.bindSymbol(cast(void**)&SDL_AudioStreamAvailable, "SDL_AudioStreamAvailable"); + lib.bindSymbol(cast(void**)&SDL_AudioStreamFlush, "SDL_AudioStreamFlush"); + lib.bindSymbol(cast(void**)&SDL_AudioStreamClear, "SDL_AudioStreamClear"); + lib.bindSymbol(cast(void**)&SDL_FreeAudioStream, "SDL_FreeAudioStream"); + lib.bindSymbol(cast(void**)&SDL_LockJoysticks, "SDL_LockJoysticks"); + lib.bindSymbol(cast(void**)&SDL_UnlockJoysticks, "SDL_UnlockJoysticks"); + lib.bindSymbol(cast(void**)&SDL_JoystickGetDeviceProduct, "SDL_JoystickGetDeviceProduct"); + lib.bindSymbol(cast(void**)&SDL_JoystickGetDeviceProductVersion, "SDL_JoystickGetDeviceProductVersion"); + lib.bindSymbol(cast(void**)&SDL_JoystickGetDeviceInstanceID, "SDL_JoystickGetDeviceInstanceID"); + lib.bindSymbol(cast(void**)&SDL_JoystickGetDeviceType, "SDL_JoystickGetDeviceType"); + lib.bindSymbol(cast(void**)&SDL_JoystickGetProduct, "SDL_JoystickGetProduct"); + lib.bindSymbol(cast(void**)&SDL_JoystickGetProductVersion, "SDL_JoystickGetProductVersion"); + lib.bindSymbol(cast(void**)&SDL_JoystickGetType, "SDL_JoystickGetType"); + lib.bindSymbol(cast(void**)&SDL_JoystickGetVendor, "SDL_JoystickGetVendor"); + lib.bindSymbol(cast(void**)&SDL_LoadFile_RW, "SDL_LoadFile_RW"); + lib.bindSymbol(cast(void**)&SDL_DuplicateSurface, "SDL_DuplicateSurface"); + lib.bindSymbol(cast(void**)&SDL_Vulkan_CreateSurface, "SDL_Vulkan_CreateSurface"); + lib.bindSymbol(cast(void**)&SDL_Vulkan_GetDrawableSize, "SDL_Vulkan_GetDrawableSize"); + lib.bindSymbol(cast(void**)&SDL_Vulkan_GetInstanceExtensions, "SDL_Vulkan_GetInstanceExtensions"); + lib.bindSymbol(cast(void**)&SDL_Vulkan_GetVkGetInstanceProcAddr, "SDL_Vulkan_GetVkGetInstanceProcAddr"); + lib.bindSymbol(cast(void**)&SDL_Vulkan_LoadLibrary, "SDL_Vulkan_LoadLibrary"); + lib.bindSymbol(cast(void**)&SDL_Vulkan_UnloadLibrary, "SDL_Vulkan_UnloadLibrary"); + + if(errorCount() != errCount) return SDLSupport.badLibrary; + else loadedVersion = SDLSupport.sdl207; + } + + static if(sdlSupport >= SDLSupport.sdl208) { + lib.bindSymbol(cast(void**)&SDL_RenderGetMetalLayer, "SDL_RenderGetMetalLayer"); + lib.bindSymbol(cast(void**)&SDL_RenderGetMetalCommandEncoder, "SDL_RenderGetMetalCommandEncoder"); + lib.bindSymbol(cast(void**)&SDL_SetYUVConversionMode, "SDL_SetYUVConversionMode"); + lib.bindSymbol(cast(void**)&SDL_GetYUVConversionMode, "SDL_GetYUVConversionMode"); + lib.bindSymbol(cast(void**)&SDL_GetYUVConversionModeForResolution, "SDL_GetYUVConversionModeForResolution"); + + version(Android) { + lib.bindSymbol(cast(void**)&SDL_IsAndroidTV, "SDL_IsAndroidTV"); + } + + if(errorCount() != errCount) return SDLSupport.badLibrary; + else loadedVersion = SDLSupport.sdl208; + } + + static if(sdlSupport >= SDLSupport.sdl209) { + lib.bindSymbol(cast(void**)&SDL_HasAVX512F, "SDL_HasAVX512F"); + lib.bindSymbol(cast(void**)&SDL_GameControllerMappingForDeviceIndex, "SDL_GameControllerMappingForDeviceIndex"); + lib.bindSymbol(cast(void**)&SDL_GameControllerRumble, "SDL_GameControllerRumble"); + lib.bindSymbol(cast(void**)&SDL_JoystickRumble, "SDL_JoystickRumble"); + lib.bindSymbol(cast(void**)&SDL_HasColorKey, "SDL_HasColorKey"); + lib.bindSymbol(cast(void**)&SDL_GetDisplayOrientation, "SDL_GetDisplayOrientation"); + + version(linux) { + lib.bindSymbol(cast(void**)&SDL_LinuxSetThreadPriority, "SDL_LinuxSetThreadPriority"); + } + else version(Android) { + lib.bindSymbol(cast(void**)&SDL_IsChromebook, "SDL_IsChromebook"); + lib.bindSymbol(cast(void**)&SDL_IsDeXMode, "SDL_IsDeXMode"); + lib.bindSymbol(cast(void**)&SDL_AndroidBackButton, "SDL_AndroidBackButton"); + } + + if(errorCount() != errCount) return SDLSupport.badLibrary; + else loadedVersion = SDLSupport.sdl209; + } + + static if(sdlSupport >= SDLSupport.sdl2010) { + lib.bindSymbol(cast(void**)&SDL_SIMDGetAlignment, "SDL_SIMDGetAlignment"); + lib.bindSymbol(cast(void**)&SDL_SIMDAlloc, "SDL_SIMDAlloc"); + lib.bindSymbol(cast(void**)&SDL_SIMDFree, "SDL_SIMDFree"); + lib.bindSymbol(cast(void**)&SDL_GameControllerGetPlayerIndex, "SDL_GameControllerGetPlayerIndex"); + lib.bindSymbol(cast(void**)&SDL_JoystickGetDevicePlayerIndex, "SDL_JoystickGetDevicePlayerIndex"); + lib.bindSymbol(cast(void**)&SDL_JoystickGetPlayerIndex, "SDL_JoystickGetPlayerIndex"); + lib.bindSymbol(cast(void**)&SDL_RenderDrawPointF, "SDL_RenderDrawPointF"); + lib.bindSymbol(cast(void**)&SDL_RenderDrawPointsF, "SDL_RenderDrawPointsF"); + lib.bindSymbol(cast(void**)&SDL_RenderDrawLineF, "SDL_RenderDrawLineF"); + lib.bindSymbol(cast(void**)&SDL_RenderDrawLinesF, "SDL_RenderDrawLinesF"); + lib.bindSymbol(cast(void**)&SDL_RenderDrawRectF, "SDL_RenderDrawRectF"); + lib.bindSymbol(cast(void**)&SDL_RenderDrawRectsF, "SDL_RenderDrawRectsF"); + lib.bindSymbol(cast(void**)&SDL_RenderFillRectF, "SDL_RenderFillRectF"); + lib.bindSymbol(cast(void**)&SDL_RenderFillRectsF, "SDL_RenderFillRectsF"); + lib.bindSymbol(cast(void**)&SDL_RenderCopyF, "SDL_RenderCopyF"); + lib.bindSymbol(cast(void**)&SDL_RenderCopyExF, "SDL_RenderCopyExF"); + lib.bindSymbol(cast(void**)&SDL_RenderFlush, "SDL_RenderFlush");lib.bindSymbol(cast(void**)&SDL_Vulkan_CreateSurface, "SDL_Vulkan_CreateSurface"); + lib.bindSymbol(cast(void**)&SDL_RWsize, "SDL_RWsize"); + lib.bindSymbol(cast(void**)&SDL_RWseek, "SDL_RWseek"); + lib.bindSymbol(cast(void**)&SDL_RWtell, "SDL_RWtell"); + lib.bindSymbol(cast(void**)&SDL_RWread, "SDL_RWread"); + lib.bindSymbol(cast(void**)&SDL_RWwrite, "SDL_RWwrite"); + lib.bindSymbol(cast(void**)&SDL_RWclose, "SDL_RWclose"); + lib.bindSymbol(cast(void**)&SDL_GetTouchDeviceType, "SDL_GetTouchDeviceType"); + + + if(errorCount() != errCount) return SDLSupport.badLibrary; + else loadedVersion = SDLSupport.sdl2010; + } + + return loadedVersion; +} \ No newline at end of file diff --git a/demos/external/imports/bindbc/sdl/image.d b/demos/external/imports/bindbc/sdl/image.d new file mode 100644 index 0000000..8cf160e --- /dev/null +++ b/demos/external/imports/bindbc/sdl/image.d @@ -0,0 +1,353 @@ + +// Copyright Michael D. Parker 2018. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +module bindbc.sdl.image; + +version(BindSDL_Image): + +import bindbc.sdl.bind.sdlerror : SDL_GetError, SDL_SetError; +import bindbc.sdl.bind.sdlrender : SDL_Renderer, SDL_Texture; +import bindbc.sdl.bind.sdlrwops : SDL_RWops; +import bindbc.sdl.bind.sdlsurface : SDL_Surface; +import bindbc.sdl.bind.sdlversion : SDL_version, SDL_VERSIONNUM; + +alias IMG_SetError = SDL_SetError; +alias IMG_GetError = SDL_GetError; + +enum SDLImageSupport { + noLibrary, + badLibrary, + sdlImage200 = 200, + sdlImage201, + sdlImage202, +} + +enum ubyte SDL_IMAGE_MAJOR_VERSION = 2; +enum ubyte SDL_IMAGE_MINOR_VERSION = 0; + +version(SDL_Image_202) { + enum sdlImageSupport = SDLImageSupport.sdlImage202; + enum ubyte SDL_IMAGE_PATCHLEVEL = 2; +} +else version(SDL_Image_201) { + enum sdlImageSupport = SDLImageSupport.sdlImage201; + enum ubyte SDL_IMAGE_PATCHLEVEL = 1; +} +else { + enum sdlImageSupport = SDLImageSupport.sdlImage200; + enum ubyte SDL_IMAGE_PATCHLEVEL = 0; +} + +@nogc nothrow void SDL_IMAGE_VERSION(SDL_version* X) +{ + X.major = SDL_IMAGE_MAJOR_VERSION; + X.minor = SDL_IMAGE_MINOR_VERSION; + X.patch = SDL_IMAGE_PATCHLEVEL; +} + +// These were implemented in SDL_image 2.0.2, but are fine for all versions. +enum SDL_IMAGE_COMPILEDVERSION = SDL_VERSIONNUM!(SDL_IMAGE_MAJOR_VERSION, SDL_IMAGE_MINOR_VERSION, SDL_IMAGE_PATCHLEVEL); +enum SDL_IMAGE_VERSION_ATLEAST(ubyte X, ubyte Y, ubyte Z) = SDL_IMAGE_COMPILEDVERSION >= SDL_VERSIONNUM!(X, Y, Z); + +enum { + IMG_INIT_JPG = 0x00000001, + IMG_INIT_PNG = 0x00000002, + IMG_INIT_TIF = 0x00000004, + IMG_INIT_WEBP = 0x00000008, +} + +version(BindSDL_Static) { + extern(C) @nogc nothrow { + int IMG_Init(int); + int IMG_Quit(); + const(SDL_version)* IMG_Linked_Version(); + SDL_Surface* IMG_LoadTyped_RW(SDL_RWops*,int,const(char)*); + SDL_Surface* IMG_Load(const(char)*); + SDL_Surface* IMG_Load_RW(SDL_RWops*,int); + + SDL_Texture* IMG_LoadTexture(SDL_Renderer*,const(char)*); + SDL_Texture* IMG_LoadTexture_RW(SDL_Renderer*,SDL_RWops*,int); + SDL_Texture* IMG_LoadTextureTyped_RW(SDL_Renderer*,SDL_RWops*,int,const(char)*); + + int IMG_isICO(SDL_RWops*); + int IMG_isCUR(SDL_RWops*); + int IMG_isBMP(SDL_RWops*); + int IMG_isGIF(SDL_RWops*); + int IMG_isJPG(SDL_RWops*); + int IMG_isLBM(SDL_RWops*); + int IMG_isPCX(SDL_RWops*); + int IMG_isPNG(SDL_RWops*); + int IMG_isPNM(SDL_RWops*); + int IMG_isTIF(SDL_RWops*); + int IMG_isXCF(SDL_RWops*); + int IMG_isXPM(SDL_RWops*); + int IMG_isXV(SDL_RWops*); + int IMG_isWEBP(SDL_RWops*); + + SDL_Surface* IMG_LoadICO_RW(SDL_RWops*); + SDL_Surface* IMG_LoadCUR_RW(SDL_RWops*); + SDL_Surface* IMG_LoadBMP_RW(SDL_RWops*); + SDL_Surface* IMG_LoadGIF_RW(SDL_RWops*); + SDL_Surface* IMG_LoadJPG_RW(SDL_RWops*); + SDL_Surface* IMG_LoadLBM_RW(SDL_RWops*); + SDL_Surface* IMG_LoadPCX_RW(SDL_RWops*); + SDL_Surface* IMG_LoadPNG_RW(SDL_RWops*); + SDL_Surface* IMG_LoadPNM_RW(SDL_RWops*); + SDL_Surface* IMG_LoadTGA_RW(SDL_RWops*); + SDL_Surface* IMG_LoadTIF_RW(SDL_RWops*); + SDL_Surface* IMG_LoadXCF_RW(SDL_RWops*); + SDL_Surface* IMG_LoadXPM_RW(SDL_RWops*); + SDL_Surface* IMG_LoadXV_RW(SDL_RWops*); + SDL_Surface* IMG_LoadWEBP_RW(SDL_RWops*); + + SDL_Surface* IMG_ReadXPMFromArray(char**); + + int IMG_SavePNG(SDL_Surface*,const(char)*); + int IMG_SavePNG_RW(SDL_Surface*,SDL_RWops*,int); + + static if(sdlImageSupport >= SDLImageSupport.sdlImage202) { + int IMG_isSVG(SDL_RWops*); + SDL_Surface* IMG_LoadSVG(SDL_RWops*); + int IMG_SaveJPG(SDL_Surface*,const(char)*,int); + int IMG_SaveJPG_RW(SDL_Surface*,SDL_RWops*,int,int); + } + } +} +else { + import bindbc.loader; + + extern(C) @nogc nothrow { + alias pIMG_Init = int function(int); + alias pIMG_Quit = int function(); + alias pIMG_Linked_Version = const(SDL_version)* function(); + alias pIMG_LoadTyped_RW = SDL_Surface* function(SDL_RWops*,int,const(char)*); + alias pIMG_Load = SDL_Surface* function(const(char)*); + alias pIMG_Load_RW = SDL_Surface* function(SDL_RWops*,int); + + alias pIMG_LoadTexture = SDL_Texture* function(SDL_Renderer*,const(char)*); + alias pIMG_LoadTexture_RW = SDL_Texture* function(SDL_Renderer*,SDL_RWops*,int); + alias pIMG_LoadTextureTyped_RW = SDL_Texture* function(SDL_Renderer*,SDL_RWops*,int,const(char)*); + + alias pIMG_isICO = int function(SDL_RWops*); + alias pIMG_isCUR = int function(SDL_RWops*); + alias pIMG_isBMP = int function(SDL_RWops*); + alias pIMG_isGIF = int function(SDL_RWops*); + alias pIMG_isJPG = int function(SDL_RWops*); + alias pIMG_isLBM = int function(SDL_RWops*); + alias pIMG_isPCX = int function(SDL_RWops*); + alias pIMG_isPNG = int function(SDL_RWops*); + alias pIMG_isPNM = int function(SDL_RWops*); + alias pIMG_isTIF = int function(SDL_RWops*); + alias pIMG_isXCF = int function(SDL_RWops*); + alias pIMG_isXPM = int function(SDL_RWops*); + alias pIMG_isXV = int function(SDL_RWops*); + alias pIMG_isWEBP = int function(SDL_RWops*); + + alias pIMG_LoadICO_RW = SDL_Surface* function(SDL_RWops*); + alias pIMG_LoadCUR_RW = SDL_Surface* function(SDL_RWops*); + alias pIMG_LoadBMP_RW = SDL_Surface* function(SDL_RWops*); + alias pIMG_LoadGIF_RW = SDL_Surface* function(SDL_RWops*); + alias pIMG_LoadJPG_RW = SDL_Surface* function(SDL_RWops*); + alias pIMG_LoadLBM_RW = SDL_Surface* function(SDL_RWops*); + alias pIMG_LoadPCX_RW = SDL_Surface* function(SDL_RWops*); + alias pIMG_LoadPNG_RW = SDL_Surface* function(SDL_RWops*); + alias pIMG_LoadPNM_RW = SDL_Surface* function(SDL_RWops*); + alias pIMG_LoadTGA_RW = SDL_Surface* function(SDL_RWops*); + alias pIMG_LoadTIF_RW = SDL_Surface* function(SDL_RWops*); + alias pIMG_LoadXCF_RW = SDL_Surface* function(SDL_RWops*); + alias pIMG_LoadXPM_RW = SDL_Surface* function(SDL_RWops*); + alias pIMG_LoadXV_RW = SDL_Surface* function(SDL_RWops*); + alias pIMG_LoadWEBP_RW = SDL_Surface* function(SDL_RWops*); + + alias pIMG_ReadXPMFromArray = SDL_Surface* function(char**); + + alias pIMG_SavePNG = int function(SDL_Surface*,const(char)*); + alias pIMG_SavePNG_RW = int function(SDL_Surface*,SDL_RWops*,int); + } + + __gshared { + pIMG_Init IMG_Init; + pIMG_Quit IMG_Quit; + pIMG_Linked_Version IMG_Linked_Version; + pIMG_LoadTyped_RW IMG_LoadTyped_RW; + pIMG_Load IMG_Load; + pIMG_Load_RW IMG_Load_RW; + pIMG_LoadTexture IMG_LoadTexture; + pIMG_LoadTexture_RW IMG_LoadTexture_RW; + pIMG_LoadTextureTyped_RW IMG_LoadTextureTyped_RW; + pIMG_isICO IMG_isICO; + pIMG_isCUR IMG_isCUR; + pIMG_isBMP IMG_isBMP; + pIMG_isGIF IMG_isGIF; + pIMG_isJPG IMG_isJPG; + pIMG_isLBM IMG_isLBM; + pIMG_isPCX IMG_isPCX; + pIMG_isPNG IMG_isPNG; + pIMG_isPNM IMG_isPNM; + pIMG_isTIF IMG_isTIF; + pIMG_isXCF IMG_isXCF; + pIMG_isXPM IMG_isXPM; + pIMG_isXV IMG_isXV; + pIMG_isWEBP IMG_isWEBP; + pIMG_LoadICO_RW IMG_LoadICO_RW; + pIMG_LoadCUR_RW IMG_LoadCUR_RW; + pIMG_LoadBMP_RW IMG_LoadBMP_RW; + pIMG_LoadGIF_RW IMG_LoadGIF_RW; + pIMG_LoadJPG_RW IMG_LoadJPG_RW; + pIMG_LoadLBM_RW IMG_LoadLBM_RW; + pIMG_LoadPCX_RW IMG_LoadPCX_RW; + pIMG_LoadPNG_RW IMG_LoadPNG_RW; + pIMG_LoadPNM_RW IMG_LoadPNM_RW; + pIMG_LoadTGA_RW IMG_LoadTGA_RW; + pIMG_LoadTIF_RW IMG_LoadTIF_RW; + pIMG_LoadXCF_RW IMG_LoadXCF_RW; + pIMG_LoadXPM_RW IMG_LoadXPM_RW; + pIMG_LoadXV_RW IMG_LoadXV_RW; + pIMG_LoadWEBP_RW IMG_LoadWEBP_RW; + pIMG_ReadXPMFromArray IMG_ReadXPMFromArray; + pIMG_SavePNG IMG_SavePNG; + pIMG_SavePNG_RW IMG_SavePNG_RW; + } + + static if(sdlImageSupport >= SDLImageSupport.sdlImage202) { + extern(C) @nogc nothrow { + alias pIMG_isSVG = int function(SDL_RWops*); + alias pIMG_LoadSVG_RW = SDL_Surface* function(SDL_RWops*); + alias pIMG_SaveJPG = int function(SDL_Surface*,const(char)*,int); + alias pIMG_SaveJPG_RW = int function(SDL_Surface*,SDL_RWops*,int,int); + } + + __gshared { + pIMG_isSVG IMG_isSVG; + pIMG_LoadSVG_RW IMG_LoadSVG; + pIMG_SaveJPG IMG_SaveJPG; + pIMG_SaveJPG_RW IMG_SaveJPG_RW; + } + } + + private { + SharedLib lib; + SDLImageSupport loadedVersion; + } + + void unloadSDLImage() + { + if(lib != invalidHandle) { + lib.unload(); + } + } + + SDLImageSupport loadedSDLImageVersion() { return loadedVersion; } + + bool isSDLImageLoaded() + { + return lib != invalidHandle; + } + + + SDLImageSupport loadSDLImage() + { + version(Windows) { + const(char)[][1] libNames = ["SDL2_image.dll"]; + } + else version(OSX) { + const(char)[][6] libNames = [ + "libSDL2_image.dylib", + "/usr/local/lib/libSDL2_image.dylib", + "../Frameworks/SDL2_image.framework/SDL2_image", + "/Library/Frameworks/SDL2_image.framework/SDL2_image", + "/System/Library/Frameworks/SDL2_image.framework/SDL2_image", + "/opt/local/lib/libSDL2_image.dylib" + ]; + } + else version(Posix) { + const(char)[][6] libNames = [ + "libSDL2_image.so", + "/usr/local/lib/libSDL2_image.so", + "libSDL2_image-2.0.so", + "/usr/local/lib/libSDL2_image-2.0.so", + "libSDL2_image-2.0.so.0", + "/usr/local/lib/libSDL2_image-2.0.so.0" + ]; + } + else static assert(0, "bindbc-sdl is not yet supported on this platform."); + + SDLImageSupport ret; + foreach(name; libNames) { + ret = loadSDLImage(name.ptr); + if(ret != SDLImageSupport.noLibrary) break; + } + return ret; + } + + SDLImageSupport loadSDLImage(const(char)* libName) + { + lib = load(libName); + if(lib == invalidHandle) { + return SDLImageSupport.noLibrary; + } + + auto errCount = errorCount(); + loadedVersion = SDLImageSupport.badLibrary; + + lib.bindSymbol(cast(void**)&IMG_Init,"IMG_Init"); + lib.bindSymbol(cast(void**)&IMG_Quit,"IMG_Quit"); + lib.bindSymbol(cast(void**)&IMG_Linked_Version,"IMG_Linked_Version"); + lib.bindSymbol(cast(void**)&IMG_LoadTyped_RW,"IMG_LoadTyped_RW"); + lib.bindSymbol(cast(void**)&IMG_Load,"IMG_Load"); + lib.bindSymbol(cast(void**)&IMG_Load_RW,"IMG_Load_RW"); + lib.bindSymbol(cast(void**)&IMG_LoadTexture,"IMG_LoadTexture"); + lib.bindSymbol(cast(void**)&IMG_LoadTexture_RW,"IMG_LoadTexture_RW"); + lib.bindSymbol(cast(void**)&IMG_LoadTextureTyped_RW,"IMG_LoadTextureTyped_RW"); + lib.bindSymbol(cast(void**)&IMG_isICO,"IMG_isICO"); + lib.bindSymbol(cast(void**)&IMG_isCUR,"IMG_isCUR"); + lib.bindSymbol(cast(void**)&IMG_isBMP,"IMG_isBMP"); + lib.bindSymbol(cast(void**)&IMG_isGIF,"IMG_isGIF"); + lib.bindSymbol(cast(void**)&IMG_isJPG,"IMG_isJPG"); + lib.bindSymbol(cast(void**)&IMG_isLBM,"IMG_isLBM"); + lib.bindSymbol(cast(void**)&IMG_isPCX,"IMG_isPCX"); + lib.bindSymbol(cast(void**)&IMG_isPNG,"IMG_isPNG"); + lib.bindSymbol(cast(void**)&IMG_isPNM,"IMG_isPNM"); + lib.bindSymbol(cast(void**)&IMG_isTIF,"IMG_isTIF"); + lib.bindSymbol(cast(void**)&IMG_isXCF,"IMG_isXCF"); + lib.bindSymbol(cast(void**)&IMG_isXPM,"IMG_isXPM"); + lib.bindSymbol(cast(void**)&IMG_isXV,"IMG_isXV"); + lib.bindSymbol(cast(void**)&IMG_isWEBP,"IMG_isWEBP"); + lib.bindSymbol(cast(void**)&IMG_LoadICO_RW,"IMG_LoadICO_RW"); + lib.bindSymbol(cast(void**)&IMG_LoadCUR_RW,"IMG_LoadCUR_RW"); + lib.bindSymbol(cast(void**)&IMG_LoadBMP_RW,"IMG_LoadBMP_RW"); + lib.bindSymbol(cast(void**)&IMG_LoadGIF_RW,"IMG_LoadGIF_RW"); + lib.bindSymbol(cast(void**)&IMG_LoadJPG_RW,"IMG_LoadJPG_RW"); + lib.bindSymbol(cast(void**)&IMG_LoadLBM_RW,"IMG_LoadLBM_RW"); + lib.bindSymbol(cast(void**)&IMG_LoadPCX_RW,"IMG_LoadPCX_RW"); + lib.bindSymbol(cast(void**)&IMG_LoadPNG_RW,"IMG_LoadPNG_RW"); + lib.bindSymbol(cast(void**)&IMG_LoadPNM_RW,"IMG_LoadPNM_RW"); + lib.bindSymbol(cast(void**)&IMG_LoadTGA_RW,"IMG_LoadTGA_RW"); + lib.bindSymbol(cast(void**)&IMG_LoadTIF_RW,"IMG_LoadTIF_RW"); + lib.bindSymbol(cast(void**)&IMG_LoadXCF_RW,"IMG_LoadXCF_RW"); + lib.bindSymbol(cast(void**)&IMG_LoadXPM_RW,"IMG_LoadXPM_RW"); + lib.bindSymbol(cast(void**)&IMG_LoadXV_RW,"IMG_LoadXV_RW"); + lib.bindSymbol(cast(void**)&IMG_isXV,"IMG_isXV"); + lib.bindSymbol(cast(void**)&IMG_LoadWEBP_RW,"IMG_LoadWEBP_RW"); + lib.bindSymbol(cast(void**)&IMG_SavePNG,"IMG_SavePNG"); + lib.bindSymbol(cast(void**)&IMG_SavePNG_RW,"IMG_SavePNG_RW"); + + if(errorCount() != errCount) return SDLImageSupport.badLibrary; + else loadedVersion = SDLImageSupport.sdlImage200; + + static if(sdlImageSupport >= SDLImageSupport.sdlImage202) { + lib.bindSymbol(cast(void**)&IMG_isSVG,"IMG_isSVG"); + lib.bindSymbol(cast(void**)&IMG_LoadSVG,"IMG_LoadSVG_RW"); + lib.bindSymbol(cast(void**)&IMG_SaveJPG,"IMG_SaveJPG"); + lib.bindSymbol(cast(void**)&IMG_SaveJPG_RW,"IMG_SaveJPG_RW"); + + if(errorCount() != errCount) return SDLImageSupport.badLibrary; + else loadedVersion = SDLImageSupport.sdlImage202; + } + + return loadedVersion; + } +} diff --git a/demos/external/imports/bindbc/sdl/mixer.d b/demos/external/imports/bindbc/sdl/mixer.d new file mode 100644 index 0000000..ed531b5 --- /dev/null +++ b/demos/external/imports/bindbc/sdl/mixer.d @@ -0,0 +1,569 @@ + +// Copyright Michael D. Parker 2018. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +module bindbc.sdl.mixer; + +version(BindSDL_Mixer): + +import bindbc.sdl.config; +import bindbc.sdl.bind.sdlaudio : AUDIO_S16LSB, SDL_MIX_MAXVOLUME; +import bindbc.sdl.bind.sdlerror : SDL_GetError, SDL_SetError, SDL_ClearError; +import bindbc.sdl.bind.sdlrwops : SDL_RWops, SDL_RWFromFile; +import bindbc.sdl.bind.sdlstdinc : SDL_bool; +import bindbc.sdl.bind.sdlversion : SDL_version, SDL_VERSIONNUM; + +alias Mix_SetError = SDL_SetError; +alias Mix_GetError = SDL_GetError; +alias Mix_ClearError = SDL_ClearError; + +enum SDLMixerSupport { + noLibrary, + badLibrary, + sdlMixer200 = 200, + sdlMixer201 = 201, + sdlMixer202 = 202, +} + +enum ubyte SDL_MIXER_MAJOR_VERSION = 2; +enum ubyte SDL_MIXER_MINOR_VERSION = 0; + +version(SDL_Mixer_202) { + enum sdlMixerSupport = SDLMixerSupport.sdlMixer202; + enum ubyte SDL_MIXER_PATCHLEVEL = 2; +} +else version(SDL_Mixer_201) { + enum sdlMixerSupport = SDLMixerSupport.sdlMixer201; + enum ubyte SDL_MIXER_PATCHLEVEL = 1; +} +else { + enum sdlMixerSupport = SDLMixerSupport.sdlMixer200; + enum ubyte SDL_MIXER_PATCHLEVEL = 0; +} + +alias MIX_MAJOR_VERSION = SDL_MIXER_MAJOR_VERSION; +alias MIX_MINOR_VERSION = SDL_MIXER_MINOR_VERSION; +alias MIX_PATCH_LEVEL = SDL_MIXER_PATCHLEVEL; + +@nogc nothrow void SDL_MIXER_VERSION(SDL_version* X) +{ + X.major = SDL_MIXER_MAJOR_VERSION; + X.minor = SDL_MIXER_MINOR_VERSION; + X.patch = SDL_MIXER_PATCHLEVEL; +} +alias SDL_MIX_VERSION = SDL_MIX_MAXVOLUME; + +// These were implemented in SDL_mixer 2.0.2, but are fine for all versions. +enum SDL_MIXER_COMPILEDVERSION = SDL_VERSIONNUM!(SDL_MIXER_MAJOR_VERSION, SDL_MIXER_MINOR_VERSION, SDL_MIXER_PATCHLEVEL); +enum SDL_MIXER_VERSION_ATLEAST(ubyte X, ubyte Y, ubyte Z) = SDL_MIXER_COMPILEDVERSION >= SDL_VERSIONNUM!(X, Y, Z); + +static if(sdlMixerSupport >= SDLMixerSupport.sdlMixer202) { + enum Mix_InitFlags { + MIX_INIT_FLAC = 0x00000001, + MIX_INIT_MOD = 0x00000002, + MIX_INIT_MP3 = 0x00000008, + MIX_INIT_OGG = 0x00000010, + MIX_INIT_MID = 0x00000020, + } +} +else { + enum Mix_InitFlags { + MIX_INIT_FLAC = 0x00000001, + MIX_INIT_MOD = 0x00000002, + MIX_INIT_MODPLUG = 0x00000004, + MIX_INIT_MP3 = 0x00000008, + MIX_INIT_OGG = 0x00000010, + MIX_INIT_FLUIDSYNTH = 0x00000020, + } +} +mixin(expandEnum!Mix_InitFlags); + +enum { + MIX_CHANNELS = 8, + MIX_DEFAULT_FREQUENCY = 22050, + MIX_DEFAULT_CHANNELS = 2, + MIX_MAX_VOLUME = 128, + MIX_CHANNEL_POST = -2, +} + +version(LittleEndian) { + enum MIX_DEFAULT_FORMAT = AUDIO_S16LSB; +} else { + enum MIX_DEFAULT_FORMAT = AUDIO_S16MSB; +} + +struct Mix_Chunk { + int allocated; + ubyte* abuf; + uint alen; + ubyte volume; +} + +enum Mix_Fading { + MIX_NO_FADING, + MIX_FADING_OUT, + MIX_FADING_IN +} +mixin(expandEnum!Mix_Fading); + +static if(sdlMixerSupport >= SDLMixerSupport.sdlMixer202) { + enum Mix_MusicType { + MUS_NONE, + MUS_CMD, + MUS_WAV, + MUS_MOD, + MUS_MID, + MUS_OGG, + MUS_MP3, + MUS_MP3_MAD_UNUSED, + MUS_FLAC, + MUS_MODPLUG_UNUSED, + } +} +else { + enum Mix_MusicType { + MUS_NONE, + MUS_CMD, + MUS_WAV, + MUS_MOD, + MUS_MID, + MUS_OGG, + MUS_MP3, + MUS_MP3_MAD, + MUS_FLAC, + MUS_MODPLUG, + } +} +mixin(expandEnum!Mix_MusicType); + +struct Mix_Music; +enum MIX_EFFECTSMAXSPEED = "MIX_EFFECTSMAXSPEED"; + +extern(C) nothrow { + alias Mix_EffectFunc_t = void function(int,void*,int,void*); + alias Mix_EffectDone_t = void function(int,void*); + + // These aren't in SDL_mixer.h and are just here as a convenient and + // visible means to add the proper attributes these callbacks. + alias callbackI = void function(int); + alias callbackVUi8I = void function(void*,ubyte*,int); + alias callbackN = void function(); +} + +@nogc nothrow { + Mix_Chunk* Mix_LoadWAV(const(char)* file) { + pragma(inline, true); + return Mix_LoadWAV_RW(SDL_RWFromFile(file,"rb"),1); + } + + int Mix_PlayChannel(int channel,Mix_Chunk* chunk,int loops) { + pragma(inline, true); + return Mix_PlayChannelTimed(channel,chunk,loops,-1); + } + + int Mix_FadeInChannel(int channel,Mix_Chunk* chunk,int loops,int ms) { + pragma(inline, true); + return Mix_FadeInChannelTimed(channel,chunk,loops,ms,-1); + } +} + +version(BindSDL_Static) { + extern(C) @nogc nothrow { + const(SDL_version)* Mix_Linked_Version(); + int Mix_Init(int); + void Mix_Quit(); + int Mix_OpenAudio(int,ushort,int,int); + int Mix_AllocateChannels(int); + int Mix_QuerySpec(int*,ushort*,int*); + Mix_Chunk* Mix_LoadWAV_RW(SDL_RWops*,int); + Mix_Music* Mix_LoadMUS(const(char)*); + Mix_Music* Mix_LoadMUS_RW(SDL_RWops*,int); + Mix_Music* Mix_LoadMUSType_RW(SDL_RWops*,Mix_MusicType,int); + Mix_Chunk* Mix_QuickLoad_WAV(ubyte*); + Mix_Chunk* Mix_QuickLoad_RAW(ubyte*,uint); + void Mix_FreeChunk(Mix_Chunk*); + void Mix_FreeMusic(Mix_Music*); + int Mix_GetNumChunkDecoders(); + const(char)* Mix_GetChunkDecoder(int); + int Mix_GetNumMusicDecoders(); + const(char)* Mix_GetMusicDecoder(int); + Mix_MusicType Mix_GetMusicType(const(Mix_Music)*); + void Mix_SetPostMix(callbackVUi8I,void*); + void Mix_HookMusic(callbackVUi8I,void*); + void Mix_HookMusicFinished(callbackN); + void* Mix_GetMusicHookData(); + void Mix_ChannelFinished(callbackI); + int Mix_RegisterEffect(int,Mix_EffectFunc_t,Mix_EffectDone_t,void*); + int Mix_UnregisterEffect(int,Mix_EffectFunc_t); + int Mix_UnregisterAllEffects(int); + int Mix_SetPanning(int,ubyte,ubyte); + int Mix_SetPosition(int,short,ubyte); + int Mix_SetDistance(int,ubyte); + int Mix_SetReverseStereo(int,int); + int Mix_ReserveChannels(int); + int Mix_GroupChannel(int,int); + int Mix_GroupChannels(int,int,int); + int Mix_GroupAvailable(int); + int Mix_GroupCount(int); + int Mix_GroupOldest(int); + int Mix_GroupNewer(int); + int Mix_PlayChannelTimed(int,Mix_Chunk*,int,int); + int Mix_PlayMusic(Mix_Music*,int); + int Mix_FadeInMusic(Mix_Music*,int,int); + int Mix_FadeInMusicPos(Mix_Music*,int,int,double); + int Mix_FadeInChannelTimed(int,Mix_Chunk*,int,int,int); + int Mix_Volume(int,int); + int Mix_VolumeChunk(Mix_Chunk*,int); + int Mix_VolumeMusic(int); + int Mix_HaltChannel(int); + int Mix_HaltGroup(int); + int Mix_HaltMusic(); + int Mix_ExpireChannel(int,int); + int Mix_FadeOutChannel(int,int); + int Mix_FadeOutGroup(int,int); + int Mix_FadeOutMusic(int); + Mix_Fading Mix_FadingMusic(); + Mix_Fading Mix_FadingChannel(int); + void Mix_Pause(int); + void Mix_Resume(int); + int Mix_Paused(int); + void Mix_PauseMusic(); + void Mix_ResumeMusic(); + void Mix_RewindMusic(); + int Mix_PausedMusic(); + int Mix_SetMusicPosition(double); + int Mix_Playing(int); + int Mix_PlayingMusic(); + int Mix_SetMusicCMD(in char*); + int Mix_SetSynchroValue(int); + int Mix_GetSynchroValue(); + Mix_Chunk* Mix_GetChunk(int); + void Mix_CloseAudio(); + + static if(sdlMixerSupport >= SDLMixerSupport.sdlMixer202) { + int Mix_OpenAudioDevice(int,ushort,int,int,const(char)*,int); + SDL_bool Mix_HasChunkDecoder(const(char)*); + + // Declared in SDL_mixer.h, but not implemented + // SDL_bool Mix_HasMusicDecoder(const(char)*); + } + } +} +else { + import bindbc.loader; + + extern(C) @nogc nothrow { + alias pMix_Linked_Version = const(SDL_version)* function(); + alias pMix_Init = int function(int); + alias pMix_Quit = void function(); + alias pMix_OpenAudio = int function(int,ushort,int,int); + alias pMix_AllocateChannels = int function(int); + alias pMix_QuerySpec = int function(int*,ushort*,int*); + alias pMix_LoadWAV_RW = Mix_Chunk* function(SDL_RWops*,int); + alias pMix_LoadMUS = Mix_Music* function(const(char)*); + alias pMix_LoadMUS_RW = Mix_Music* function(SDL_RWops*,int); + alias pMix_LoadMUSType_RW = Mix_Music* function(SDL_RWops*,Mix_MusicType,int); + alias pMix_QuickLoad_WAV = Mix_Chunk* function(ubyte*); + alias pMix_QuickLoad_RAW = Mix_Chunk* function(ubyte*,uint); + alias pMix_FreeChunk = void function(Mix_Chunk*); + alias pMix_FreeMusic = void function(Mix_Music*); + alias pMix_GetNumChunkDecoders = int function(); + alias pMix_GetChunkDecoder = const(char)* function(int); + alias pMix_GetNumMusicDecoders = int function(); + alias pMix_GetMusicDecoder = const(char)* function(int); + alias pMix_GetMusicType = Mix_MusicType function(const(Mix_Music)*); + alias pMix_SetPostMix = void function(callbackVUi8I,void*); + alias pMix_HookMusic = void function(callbackVUi8I,void*); + alias pMix_HookMusicFinished = void function(callbackN); + alias pMix_GetMusicHookData = void* function(); + alias pMix_ChannelFinished = void function(callbackI); + alias pMix_RegisterEffect = int function(int,Mix_EffectFunc_t,Mix_EffectDone_t,void*); + alias pMix_UnregisterEffect = int function(int,Mix_EffectFunc_t); + alias pMix_UnregisterAllEffects = int function(int); + alias pMix_SetPanning = int function(int,ubyte,ubyte); + alias pMix_SetPosition = int function(int,short,ubyte); + alias pMix_SetDistance = int function(int,ubyte); + alias pMix_SetReverseStereo = int function(int,int); + alias pMix_ReserveChannels = int function(int); + alias pMix_GroupChannel = int function(int,int); + alias pMix_GroupChannels = int function(int,int,int); + alias pMix_GroupAvailable = int function(int); + alias pMix_GroupCount = int function(int); + alias pMix_GroupOldest = int function(int); + alias pMix_GroupNewer = int function(int); + alias pMix_PlayChannelTimed = int function(int,Mix_Chunk*,int,int); + alias pMix_PlayMusic = int function(Mix_Music*,int); + alias pMix_FadeInMusic = int function(Mix_Music*,int,int); + alias pMix_FadeInMusicPos = int function(Mix_Music*,int,int,double); + alias pMix_FadeInChannelTimed = int function(int,Mix_Chunk*,int,int,int); + alias pMix_Volume = int function(int,int); + alias pMix_VolumeChunk = int function(Mix_Chunk*,int); + alias pMix_VolumeMusic = int function(int); + alias pMix_HaltChannel = int function(int); + alias pMix_HaltGroup = int function(int); + alias pMix_HaltMusic = int function(); + alias pMix_ExpireChannel = int function(int,int); + alias pMix_FadeOutChannel = int function(int,int); + alias pMix_FadeOutGroup = int function(int,int); + alias pMix_FadeOutMusic = int function(int); + alias pMix_FadingMusic = Mix_Fading function(); + alias pMix_FadingChannel = Mix_Fading function(int); + alias pMix_Pause = void function(int); + alias pMix_Resume = void function(int); + alias pMix_Paused = int function(int); + alias pMix_PauseMusic = void function(); + alias pMix_ResumeMusic = void function(); + alias pMix_RewindMusic = void function(); + alias pMix_PausedMusic = int function(); + alias pMix_SetMusicPosition = int function(double); + alias pMix_Playing = int function(int); + alias pMix_PlayingMusic = int function(); + alias pMix_SetMusicCMD = int function(in char*); + alias pMix_SetSynchroValue = int function(int); + alias pMix_GetSynchroValue = int function(); + alias pMix_GetChunk = Mix_Chunk* function(int); + alias pMix_CloseAudio = void function(); + } + + __gshared { + pMix_Linked_Version Mix_Linked_Version; + pMix_Init Mix_Init; + pMix_Quit Mix_Quit; + pMix_OpenAudio Mix_OpenAudio; + pMix_AllocateChannels Mix_AllocateChannels; + pMix_QuerySpec Mix_QuerySpec; + pMix_LoadWAV_RW Mix_LoadWAV_RW; + pMix_LoadMUS Mix_LoadMUS; + pMix_LoadMUS_RW Mix_LoadMUS_RW; + pMix_LoadMUSType_RW Mix_LoadMUSType_RW; + pMix_QuickLoad_WAV Mix_QuickLoad_WAV; + pMix_QuickLoad_RAW Mix_QuickLoad_RAW; + pMix_FreeChunk Mix_FreeChunk; + pMix_FreeMusic Mix_FreeMusic; + pMix_GetNumChunkDecoders Mix_GetNumChunkDecoders; + pMix_GetChunkDecoder Mix_GetChunkDecoder; + pMix_GetNumMusicDecoders Mix_GetNumMusicDecoders; + pMix_GetMusicDecoder Mix_GetMusicDecoder; + pMix_GetMusicType Mix_GetMusicType; + pMix_SetPostMix Mix_SetPostMix; + pMix_HookMusic Mix_HookMusic; + pMix_HookMusicFinished Mix_HookMusicFinished; + pMix_GetMusicHookData Mix_GetMusicHookData; + pMix_ChannelFinished Mix_ChannelFinished; + pMix_RegisterEffect Mix_RegisterEffect; + pMix_UnregisterEffect Mix_UnregisterEffect; + pMix_UnregisterAllEffects Mix_UnregisterAllEffects; + pMix_SetPanning Mix_SetPanning; + pMix_SetPosition Mix_SetPosition; + pMix_SetDistance Mix_SetDistance; + pMix_SetReverseStereo Mix_SetReverseStereo; + pMix_ReserveChannels Mix_ReserveChannels; + pMix_GroupChannel Mix_GroupChannel; + pMix_GroupChannels Mix_GroupChannels; + pMix_GroupAvailable Mix_GroupAvailable; + pMix_GroupCount Mix_GroupCount; + pMix_GroupOldest Mix_GroupOldest; + pMix_GroupNewer Mix_GroupNewer; + pMix_PlayChannelTimed Mix_PlayChannelTimed; + pMix_PlayMusic Mix_PlayMusic; + pMix_FadeInMusic Mix_FadeInMusic; + pMix_FadeInMusicPos Mix_FadeInMusicPos; + pMix_FadeInChannelTimed Mix_FadeInChannelTimed; + pMix_Volume Mix_Volume; + pMix_VolumeChunk Mix_VolumeChunk; + pMix_VolumeMusic Mix_VolumeMusic; + pMix_HaltChannel Mix_HaltChannel; + pMix_HaltGroup Mix_HaltGroup; + pMix_HaltMusic Mix_HaltMusic; + pMix_ExpireChannel Mix_ExpireChannel; + pMix_FadeOutChannel Mix_FadeOutChannel; + pMix_FadeOutGroup Mix_FadeOutGroup; + pMix_FadeOutMusic Mix_FadeOutMusic; + pMix_FadingMusic Mix_FadingMusic; + pMix_FadingChannel Mix_FadingChannel; + pMix_Pause Mix_Pause; + pMix_Resume Mix_Resume; + pMix_Paused Mix_Paused; + pMix_PauseMusic Mix_PauseMusic; + pMix_ResumeMusic Mix_ResumeMusic; + pMix_RewindMusic Mix_RewindMusic; + pMix_PausedMusic Mix_PausedMusic; + pMix_SetMusicPosition Mix_SetMusicPosition; + pMix_Playing Mix_Playing; + pMix_PlayingMusic Mix_PlayingMusic; + pMix_SetMusicCMD Mix_SetMusicCMD; + pMix_SetSynchroValue Mix_SetSynchroValue; + pMix_GetSynchroValue Mix_GetSynchroValue; + pMix_GetChunk Mix_GetChunk; + pMix_CloseAudio Mix_CloseAudio; + } + + + static if(sdlMixerSupport >= SDLMixerSupport.sdlMixer202) { + extern(C) @nogc nothrow { + alias pMix_OpenAudioDevice = int function(int,ushort,int,int,const(char)*,int); + alias pMix_HasChunkDecoder = SDL_bool function(const(char)*); + + // Declared in SDL_mixer.h, but not implemented + //alias pMix_HasMusicDecoder = SDL_bool function(const(char)*); + } + + __gshared { + pMix_OpenAudioDevice Mix_OpenAudioDevice; + pMix_HasChunkDecoder Mix_HasChunkDecoder; + //pMix_HasMusicDecoder Mix_HasMusicDecoder; + } + } + + private { + SharedLib lib; + SDLMixerSupport loadedVersion; + } + + void unloadSDLMixer() + { + if(lib != invalidHandle) { + lib.unload(); + } + } + + SDLMixerSupport loadedSDLMixerVersion() { return loadedVersion; } + + bool isSDLMixerLoaded() + { + return lib != invalidHandle; + } + + + SDLMixerSupport loadSDLMixer() + { + version(Windows) { + const(char)[][1] libNames = ["SDL2_mixer.dll"]; + } + else version(OSX) { + const(char)[][6] libNames = [ + "libSDL2_mixer.dylib", + "/usr/local/lib/libSDL2_mixer.dylib", + "../Frameworks/SDL2_mixer.framework/SDL2_mixer", + "/Library/Frameworks/SDL2_mixer.framework/SDL2_mixer", + "/System/Library/Frameworks/SDL2_mixer.framework/SDL2_mixer", + "/opt/local/lib/libSDL2_mixer.dylib" + ]; + } + else version(Posix) { + const(char)[][6] libNames = [ + "libSDL2_mixer.so", + "/usr/local/lib/libSDL2_mixer.so", + "libSDL2-2.0_mixer.so", + "/usr/local/lib/libSDL2-2.0_mixer.so", + "libSDL2-2.0_mixer.so.0", + "/usr/local/lib/libSDL2-2.0_mixer.so.0" + ]; + } + else static assert(0, "bindbc-sdl is not yet supported on this platform."); + + SDLMixerSupport ret; + foreach(name; libNames) { + ret = loadSDLMixer(name.ptr); + if(ret != SDLMixerSupport.noLibrary) break; + } + return ret; + } + + SDLMixerSupport loadSDLMixer(const(char)* libName) + { + lib = load(libName); + if(lib == invalidHandle) { + return SDLMixerSupport.noLibrary; + } + + auto errCount = errorCount(); + loadedVersion = SDLMixerSupport.badLibrary; + + lib.bindSymbol(cast(void**)&Mix_Linked_Version,"Mix_Linked_Version"); + lib.bindSymbol(cast(void**)&Mix_Init,"Mix_Init"); + lib.bindSymbol(cast(void**)&Mix_Quit,"Mix_Quit"); + lib.bindSymbol(cast(void**)&Mix_OpenAudio,"Mix_OpenAudio"); + lib.bindSymbol(cast(void**)&Mix_AllocateChannels,"Mix_AllocateChannels"); + lib.bindSymbol(cast(void**)&Mix_QuerySpec,"Mix_QuerySpec"); + lib.bindSymbol(cast(void**)&Mix_LoadWAV_RW,"Mix_LoadWAV_RW"); + lib.bindSymbol(cast(void**)&Mix_LoadMUS,"Mix_LoadMUS"); + lib.bindSymbol(cast(void**)&Mix_LoadMUS_RW,"Mix_LoadMUS_RW"); + lib.bindSymbol(cast(void**)&Mix_LoadMUSType_RW,"Mix_LoadMUSType_RW"); + lib.bindSymbol(cast(void**)&Mix_QuickLoad_WAV,"Mix_QuickLoad_WAV"); + lib.bindSymbol(cast(void**)&Mix_QuickLoad_RAW,"Mix_QuickLoad_RAW"); + lib.bindSymbol(cast(void**)&Mix_FreeChunk,"Mix_FreeChunk"); + lib.bindSymbol(cast(void**)&Mix_FreeMusic,"Mix_FreeMusic"); + lib.bindSymbol(cast(void**)&Mix_GetNumChunkDecoders,"Mix_GetNumChunkDecoders"); + lib.bindSymbol(cast(void**)&Mix_GetChunkDecoder,"Mix_GetChunkDecoder"); + lib.bindSymbol(cast(void**)&Mix_GetNumMusicDecoders,"Mix_GetNumMusicDecoders"); + lib.bindSymbol(cast(void**)&Mix_GetMusicDecoder,"Mix_GetMusicDecoder"); + lib.bindSymbol(cast(void**)&Mix_GetMusicType,"Mix_GetMusicType"); + lib.bindSymbol(cast(void**)&Mix_SetPostMix,"Mix_SetPostMix"); + lib.bindSymbol(cast(void**)&Mix_HookMusic,"Mix_HookMusic"); + lib.bindSymbol(cast(void**)&Mix_HookMusicFinished,"Mix_HookMusicFinished"); + lib.bindSymbol(cast(void**)&Mix_GetMusicHookData,"Mix_GetMusicHookData"); + lib.bindSymbol(cast(void**)&Mix_ChannelFinished,"Mix_ChannelFinished"); + lib.bindSymbol(cast(void**)&Mix_RegisterEffect,"Mix_RegisterEffect"); + lib.bindSymbol(cast(void**)&Mix_UnregisterEffect,"Mix_UnregisterEffect"); + lib.bindSymbol(cast(void**)&Mix_UnregisterAllEffects,"Mix_UnregisterAllEffects"); + lib.bindSymbol(cast(void**)&Mix_SetPanning,"Mix_SetPanning"); + lib.bindSymbol(cast(void**)&Mix_SetPosition,"Mix_SetPosition"); + lib.bindSymbol(cast(void**)&Mix_SetDistance,"Mix_SetDistance"); + lib.bindSymbol(cast(void**)&Mix_SetReverseStereo,"Mix_SetReverseStereo"); + lib.bindSymbol(cast(void**)&Mix_ReserveChannels,"Mix_ReserveChannels"); + lib.bindSymbol(cast(void**)&Mix_GroupChannel,"Mix_GroupChannel"); + lib.bindSymbol(cast(void**)&Mix_GroupChannels,"Mix_GroupChannels"); + lib.bindSymbol(cast(void**)&Mix_GroupAvailable,"Mix_GroupAvailable"); + lib.bindSymbol(cast(void**)&Mix_GroupCount,"Mix_GroupCount"); + lib.bindSymbol(cast(void**)&Mix_GroupOldest,"Mix_GroupOldest"); + lib.bindSymbol(cast(void**)&Mix_GroupNewer,"Mix_GroupNewer"); + lib.bindSymbol(cast(void**)&Mix_PlayChannelTimed,"Mix_PlayChannelTimed"); + lib.bindSymbol(cast(void**)&Mix_PlayMusic,"Mix_PlayMusic"); + lib.bindSymbol(cast(void**)&Mix_FadeInMusic,"Mix_FadeInMusic"); + lib.bindSymbol(cast(void**)&Mix_FadeInMusicPos,"Mix_FadeInMusicPos"); + lib.bindSymbol(cast(void**)&Mix_FadeInChannelTimed,"Mix_FadeInChannelTimed"); + lib.bindSymbol(cast(void**)&Mix_Volume,"Mix_Volume"); + lib.bindSymbol(cast(void**)&Mix_VolumeChunk,"Mix_VolumeChunk"); + lib.bindSymbol(cast(void**)&Mix_VolumeMusic,"Mix_VolumeMusic"); + lib.bindSymbol(cast(void**)&Mix_HaltChannel,"Mix_HaltChannel"); + lib.bindSymbol(cast(void**)&Mix_HaltGroup,"Mix_HaltGroup"); + lib.bindSymbol(cast(void**)&Mix_HaltMusic,"Mix_HaltMusic"); + lib.bindSymbol(cast(void**)&Mix_ExpireChannel,"Mix_ExpireChannel"); + lib.bindSymbol(cast(void**)&Mix_FadeOutChannel,"Mix_FadeOutChannel"); + lib.bindSymbol(cast(void**)&Mix_FadeOutGroup,"Mix_FadeOutGroup"); + lib.bindSymbol(cast(void**)&Mix_FadeOutMusic,"Mix_FadeOutMusic"); + lib.bindSymbol(cast(void**)&Mix_FadingMusic,"Mix_FadingMusic"); + lib.bindSymbol(cast(void**)&Mix_FadingChannel,"Mix_FadingChannel"); + lib.bindSymbol(cast(void**)&Mix_Pause,"Mix_Pause"); + lib.bindSymbol(cast(void**)&Mix_Resume,"Mix_Resume"); + lib.bindSymbol(cast(void**)&Mix_Paused,"Mix_Paused"); + lib.bindSymbol(cast(void**)&Mix_PauseMusic,"Mix_PauseMusic"); + lib.bindSymbol(cast(void**)&Mix_ResumeMusic,"Mix_ResumeMusic"); + lib.bindSymbol(cast(void**)&Mix_RewindMusic,"Mix_RewindMusic"); + lib.bindSymbol(cast(void**)&Mix_PausedMusic,"Mix_PausedMusic"); + lib.bindSymbol(cast(void**)&Mix_SetMusicPosition,"Mix_SetMusicPosition"); + lib.bindSymbol(cast(void**)&Mix_Playing,"Mix_Playing"); + lib.bindSymbol(cast(void**)&Mix_PlayingMusic,"Mix_PlayingMusic"); + lib.bindSymbol(cast(void**)&Mix_SetMusicCMD,"Mix_SetMusicCMD"); + lib.bindSymbol(cast(void**)&Mix_SetSynchroValue,"Mix_SetSynchroValue"); + lib.bindSymbol(cast(void**)&Mix_GetSynchroValue,"Mix_GetSynchroValue"); + lib.bindSymbol(cast(void**)&Mix_GetChunk,"Mix_GetChunk"); + lib.bindSymbol(cast(void**)&Mix_CloseAudio,"Mix_CloseAudio"); + + if(errorCount() != errCount) return SDLMixerSupport.badLibrary; + else loadedVersion = SDLMixerSupport.sdlMixer200; + + static if(sdlMixerSupport >= SDLMixerSupport.sdlMixer202) { + lib.bindSymbol(cast(void**)&Mix_OpenAudioDevice,"Mix_OpenAudioDevice"); + lib.bindSymbol(cast(void**)&Mix_HasChunkDecoder,"Mix_HasChunkDecoder"); + + if(errorCount() != errCount) return SDLMixerSupport.badLibrary; + else loadedVersion = SDLMixerSupport.sdlMixer202; + } + + return loadedVersion; + } +} \ No newline at end of file diff --git a/demos/external/imports/bindbc/sdl/package.d b/demos/external/imports/bindbc/sdl/package.d new file mode 100644 index 0000000..6bba9ad --- /dev/null +++ b/demos/external/imports/bindbc/sdl/package.d @@ -0,0 +1,18 @@ + +// Copyright Michael D. Parker 2018. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +module bindbc.sdl; + +public import bindbc.sdl.config, + bindbc.sdl.bind; + +version(BindSDL_Static) {} +else public import bindbc.sdl.dynload; + +version(BindSDL_Image) public import bindbc.sdl.image; +version(BindSDL_Mixer) public import bindbc.sdl.mixer; +version(BindSDL_TTF) public import bindbc.sdl.ttf; + diff --git a/demos/external/imports/bindbc/sdl/ttf.d b/demos/external/imports/bindbc/sdl/ttf.d new file mode 100644 index 0000000..bd63ff3 --- /dev/null +++ b/demos/external/imports/bindbc/sdl/ttf.d @@ -0,0 +1,368 @@ + +// Copyright Michael D. Parker 2018. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +module bindbc.sdl.ttf; + +version(BindSDL_TTF): + +import core.stdc.config; +import bindbc.sdl.bind.sdlerror : SDL_GetError, SDL_SetError; +import bindbc.sdl.bind.sdlpixels : SDL_Color; +import bindbc.sdl.bind.sdlrwops : SDL_RWops; +import bindbc.sdl.bind.sdlsurface : SDL_Surface; +import bindbc.sdl.bind.sdlversion : SDL_version; + +alias TTF_SetError = SDL_SetError; +alias TTF_GetError = SDL_GetError; + +enum SDLTTFSupport { + noLibrary, + badLibrary, + sdlTTF2012 = 2012, + sdlTTF2013 = 2013, + sdlTTF2014 = 2014, +} + +enum ubyte SDL_TTF_MAJOR_VERSION = 2; +enum ubyte SDL_TTF_MINOR_VERSION = 0; + +version(SDL_TTF_2014) { + enum sdlTTFSupport = SDLTTFSupport.sdlTTF2014; + enum ubyte SDL_TTF_PATCHLEVEL = 14; +} +else version(SDL_TTF_2013) { + enum sdlTTFSupport = SDLTTFSupport.sdlTTF2013; + enum ubyte SDL_TTF_PATCHLEVEL = 13; +} +else { + enum sdlTTFSupport = SDLTTFSupport.sdlTTF2012; + enum ubyte SDL_TTF_PATCHLEVEL = 12; +} + +alias TTF_MAJOR_VERSION = SDL_TTF_MAJOR_VERSION; +alias TTF_MINOR_VERSION = SDL_TTF_MINOR_VERSION; +alias TTF_PATCHLEVEL = SDL_TTF_PATCHLEVEL; + +@nogc nothrow +void SDL_TTF_VERSION(SDL_version* X) { + X.major = SDL_TTF_MAJOR_VERSION; + X.minor = SDL_TTF_MINOR_VERSION; + X.patch = SDL_TTF_PATCHLEVEL; +} +alias TTF_VERSION = SDL_TTF_VERSION; + +enum { + UNICODE_BOM_NATIVE = 0xFEFF, + UNICODE_BOM_SWAPPED = 0xFFFE, + TTF_STYLE_NORMAL = 0x00, + TTF_STYLE_BOLD = 0x01, + TTF_STYLE_ITALIC = 0x02, + TTF_STYLE_UNDERLINE = 0x04, + TTF_STYLE_STRIKETHROUGH = 0x08, +} + +enum { + TTF_HINTING_NORMAL = 0, + TTF_HINTING_LIGHT = 1, + TTF_HINTING_MONO = 2, + TTF_HINTING_NONE = 3, +} + +struct TTF_Font; + +version(BindSDL_Static) { + extern(C) @nogc nothrow { + SDL_version* TTF_Linked_Version(); + void TTF_ByteSwappedUNICODE(int); + int TTF_Init(); + TTF_Font * TTF_OpenFont(const(char)*,int); + TTF_Font * TTF_OpenFontIndex(const(char)*,int,c_long ); + TTF_Font * TTF_OpenFontRW(SDL_RWops*,int,int); + TTF_Font * TTF_OpenFontIndexRW(SDL_RWops*,int,int,c_long); + int TTF_GetFontStyle(const(TTF_Font)*); + void TTF_SetFontStyle(const(TTF_Font)*,int style); + int TTF_GetFontOutline(const(TTF_Font)*); + void TTF_SetFontOutline(TTF_Font*,int); + int TTF_GetFontHinting(const(TTF_Font)*); + void TTF_SetFontHinting(TTF_Font*,int); + int TTF_FontHeight(const(TTF_Font)*); + int TTF_FontAscent(const(TTF_Font)*); + int TTF_FontDescent(const(TTF_Font)*); + int TTF_FontLineSkip(const(TTF_Font)*); + int TTF_GetFontKerning(const(TTF_Font)*); + void TTF_SetFontKerning(TTF_Font*,int); + int TTF_FontFaces(const(TTF_Font)*); + int TTF_FontFaceIsFixedWidth(const(TTF_Font)*); + char* TTF_FontFaceFamilyName(const(TTF_Font)*); + char* TTF_FontFaceStyleName(const(TTF_Font)*); + int TTF_GlyphIsProvided(const(TTF_Font)*,ushort); + int TTF_GlyphMetrics(TTF_Font*,ushort,int*,int*,int*,int*,int*); + int TTF_SizeText(TTF_Font*,const(char)*,int*,int*); + int TTF_SizeUTF8(TTF_Font*,const(char)*,int*,int*); + int TTF_SizeUNICODE(TTF_Font*,ushort*,int*,int*); + SDL_Surface* TTF_RenderText_Solid(TTF_Font*,const(char)*,SDL_Color); + SDL_Surface* TTF_RenderUTF8_Solid(TTF_Font*,const(char)*,SDL_Color); + SDL_Surface* TTF_RenderUNICODE_Solid(TTF_Font*,const(ushort)*,SDL_Color); + SDL_Surface* TTF_RenderGlyph_Solid(TTF_Font*,ushort,SDL_Color); + SDL_Surface* TTF_RenderText_Shaded(TTF_Font*,const(char)*,SDL_Color,SDL_Color); + SDL_Surface* TTF_RenderUTF8_Shaded(TTF_Font*,const(char)*,SDL_Color,SDL_Color); + SDL_Surface* TTF_RenderUNICODE_Shaded(TTF_Font*,const(ushort)*,SDL_Color,SDL_Color); + SDL_Surface* TTF_RenderGlyph_Shaded(TTF_Font*,ushort,SDL_Color,SDL_Color); + SDL_Surface* TTF_RenderText_Blended(TTF_Font*,const(char)*,SDL_Color); + SDL_Surface* TTF_RenderUTF8_Blended(TTF_Font*,const(char)*,SDL_Color); + SDL_Surface* TTF_RenderUNICODE_Blended(TTF_Font*,const(ushort)*,SDL_Color); + SDL_Surface* TTF_RenderText_Blended_Wrapped(TTF_Font*,const(char)*,SDL_Color,uint); + SDL_Surface* TTF_RenderUTF8_Blended_Wrapped(TTF_Font*,const(char)*,SDL_Color,uint); + SDL_Surface* TTF_RenderUNICODE_Blended_Wrapped(TTF_Font*,const(ushort)*,SDL_Color,uint); + SDL_Surface* TTF_RenderGlyph_Blended(TTF_Font*,ushort,SDL_Color); + void TTF_CloseFont(TTF_Font*); + void TTF_Quit(); + int TTF_WasInit(); + int TTF_GetFontKerningSize(TTF_Font*,int,int); + + static if(sdlTTFSupport >= SDLTTFSupport.sdlTTF2014) { + int TTF_GetFontKerningSizeGlyphs(TTF_Font*,ushort,ushort); + } + } +} +else { + import bindbc.loader; + + extern(C) @nogc nothrow { + alias pTTF_Linked_Version = SDL_version* function(); + alias pTTF_ByteSwappedUNICODE = void function(int); + alias pTTF_Init = int function(); + alias pTTF_OpenFont = TTF_Font * function(const(char)*,int); + alias pTTF_OpenFontIndex = TTF_Font * function(const(char)*,int,c_long ); + alias pTTF_OpenFontRW = TTF_Font * function(SDL_RWops*,int,int); + alias pTTF_OpenFontIndexRW = TTF_Font * function(SDL_RWops*,int,int,c_long); + alias pTTF_GetFontStyle = int function(const(TTF_Font)*); + alias pTTF_SetFontStyle = void function(const(TTF_Font)*,int style); + alias pTTF_GetFontOutline = int function(const(TTF_Font)*); + alias pTTF_SetFontOutline = void function(TTF_Font*,int); + alias pTTF_GetFontHinting = int function(const(TTF_Font)*); + alias pTTF_SetFontHinting = void function(TTF_Font*,int); + alias pTTF_FontHeight = int function(const(TTF_Font)*); + alias pTTF_FontAscent = int function(const(TTF_Font)*); + alias pTTF_FontDescent = int function(const(TTF_Font)*); + alias pTTF_FontLineSkip = int function(const(TTF_Font)*); + alias pTTF_GetFontKerning = int function(const(TTF_Font)*); + alias pTTF_SetFontKerning = void function(TTF_Font*,int); + alias pTTF_FontFaces = int function(const(TTF_Font)*); + alias pTTF_FontFaceIsFixedWidth = int function(const(TTF_Font)*); + alias pTTF_FontFaceFamilyName = char* function(const(TTF_Font)*); + alias pTTF_FontFaceStyleName = char* function(const(TTF_Font)*); + alias pTTF_GlyphIsProvided = int function(const(TTF_Font)*,ushort); + alias pTTF_GlyphMetrics = int function(TTF_Font*,ushort,int*,int*,int*,int*,int*); + alias pTTF_SizeText = int function(TTF_Font*,const(char)*,int*,int*); + alias pTTF_SizeUTF8 = int function(TTF_Font*,const(char)*,int*,int*); + alias pTTF_SizeUNICODE = int function(TTF_Font*,ushort*,int*,int*); + alias pTTF_RenderText_Solid = SDL_Surface* function(TTF_Font*,const(char)*,SDL_Color); + alias pTTF_RenderUTF8_Solid = SDL_Surface* function(TTF_Font*,const(char)*,SDL_Color); + alias pTTF_RenderUNICODE_Solid = SDL_Surface* function(TTF_Font*,const(ushort)*,SDL_Color); + alias pTTF_RenderGlyph_Solid = SDL_Surface* function(TTF_Font*,ushort,SDL_Color); + alias pTTF_RenderText_Shaded = SDL_Surface* function(TTF_Font*,const(char)*,SDL_Color,SDL_Color); + alias pTTF_RenderUTF8_Shaded = SDL_Surface* function(TTF_Font*,const(char)*,SDL_Color,SDL_Color); + alias pTTF_RenderUNICODE_Shaded = SDL_Surface* function(TTF_Font*,const(ushort)*,SDL_Color,SDL_Color); + alias pTTF_RenderGlyph_Shaded = SDL_Surface* function(TTF_Font*,ushort,SDL_Color,SDL_Color); + alias pTTF_RenderText_Blended = SDL_Surface* function(TTF_Font*,const(char)*,SDL_Color); + alias pTTF_RenderUTF8_Blended = SDL_Surface* function(TTF_Font*,const(char)*,SDL_Color); + alias pTTF_RenderUNICODE_Blended = SDL_Surface* function(TTF_Font*,const(ushort)*,SDL_Color); + alias pTTF_RenderText_Blended_Wrapped = SDL_Surface* function(TTF_Font*,const(char)*,SDL_Color,uint); + alias pTTF_RenderUTF8_Blended_Wrapped = SDL_Surface* function(TTF_Font*,const(char)*,SDL_Color,uint); + alias pTTF_RenderUNICODE_Blended_Wrapped = SDL_Surface* function(TTF_Font*,const(ushort)*,SDL_Color,uint); + alias pTTF_RenderGlyph_Blended = SDL_Surface* function(TTF_Font*,ushort,SDL_Color); + alias pTTF_CloseFont = void function(TTF_Font*); + alias pTTF_Quit = void function(); + alias pTTF_WasInit = int function(); + alias pTTF_GetFontKerningSize = int function(TTF_Font*,int,int); + } + + __gshared { + pTTF_Linked_Version TTF_Linked_Version; + pTTF_ByteSwappedUNICODE TTF_ByteSwappedUNICODE; + pTTF_Init TTF_Init; + pTTF_OpenFont TTF_OpenFont; + pTTF_OpenFontIndex TTF_OpenFontIndex; + pTTF_OpenFontRW TTF_OpenFontRW; + pTTF_OpenFontIndexRW TTF_OpenFontIndexRW; + pTTF_GetFontStyle TTF_GetFontStyle; + pTTF_SetFontStyle TTF_SetFontStyle; + pTTF_GetFontOutline TTF_GetFontOutline; + pTTF_SetFontOutline TTF_SetFontOutline; + pTTF_GetFontHinting TTF_GetFontHinting; + pTTF_SetFontHinting TTF_SetFontHinting; + pTTF_FontHeight TTF_FontHeight; + pTTF_FontAscent TTF_FontAscent; + pTTF_FontDescent TTF_FontDescent; + pTTF_FontLineSkip TTF_FontLineSkip; + pTTF_GetFontKerning TTF_GetFontKerning; + pTTF_SetFontKerning TTF_SetFontKerning; + pTTF_FontFaces TTF_FontFaces; + pTTF_FontFaceIsFixedWidth TTF_FontFaceIsFixedWidth; + pTTF_FontFaceFamilyName TTF_FontFaceFamilyName; + pTTF_FontFaceStyleName TTF_FontFaceStyleName; + pTTF_GlyphIsProvided TTF_GlyphIsProvided; + pTTF_GlyphMetrics TTF_GlyphMetrics; + pTTF_SizeText TTF_SizeText; + pTTF_SizeUTF8 TTF_SizeUTF8; + pTTF_SizeUNICODE TTF_SizeUNICODE; + pTTF_RenderText_Solid TTF_RenderText_Solid; + pTTF_RenderUTF8_Solid TTF_RenderUTF8_Solid; + pTTF_RenderUNICODE_Solid TTF_RenderUNICODE_Solid; + pTTF_RenderGlyph_Solid TTF_RenderGlyph_Solid; + pTTF_RenderText_Shaded TTF_RenderText_Shaded; + pTTF_RenderUTF8_Shaded TTF_RenderUTF8_Shaded; + pTTF_RenderUNICODE_Shaded TTF_RenderUNICODE_Shaded; + pTTF_RenderGlyph_Shaded TTF_RenderGlyph_Shaded; + pTTF_RenderText_Blended TTF_RenderText_Blended; + pTTF_RenderUTF8_Blended TTF_RenderUTF8_Blended; + pTTF_RenderUNICODE_Blended TTF_RenderUNICODE_Blended; + pTTF_RenderText_Blended_Wrapped TTF_RenderText_Blended_Wrapped; + pTTF_RenderUTF8_Blended_Wrapped TTF_RenderUTF8_Blended_Wrapped; + pTTF_RenderUNICODE_Blended_Wrapped TTF_RenderUNICODE_Blended_Wrapped; + pTTF_RenderGlyph_Blended TTF_RenderGlyph_Blended; + pTTF_CloseFont TTF_CloseFont; + pTTF_Quit TTF_Quit; + pTTF_WasInit TTF_WasInit; + pTTF_GetFontKerningSize TTF_GetFontKerningSize; + } + + static if(sdlTTFSupport >= SDLTTFSupport.sdlTTF2014) { + extern(C) @nogc nothrow { + alias pTTF_GetFontKerningSizeGlyphs = int function(TTF_Font*,ushort,ushort); + } + + __gshared { + pTTF_GetFontKerningSizeGlyphs TTF_GetFontKerningSizeGlyphs; + } + } + + private { + SharedLib lib; + SDLTTFSupport loadedVersion; + } + + void unloadSDLTTF() + { + if(lib != invalidHandle) { + lib.unload(); + } + } + + SDLTTFSupport loadedSDLTTFVersion() { return loadedVersion; } + + bool isSDLTTFLoaded() + { + return lib != invalidHandle; + } + + SDLTTFSupport loadSDLTTF() + { + version(Windows) { + const(char)[][1] libNames = ["SDL2_ttf.dll"]; + } + else version(OSX) { + const(char)[][6] libNames = [ + "libSDL2_ttf.dylib", + "/usr/local/lib/libSDL2_ttf.dylib", + "../Frameworks/SDL2_ttf.framework/SDL2_ttf", + "/Library/Frameworks/SDL2_ttf.framework/SDL2_ttf", + "/System/Library/Frameworks/SDL2_ttf.framework/SDL2_ttf", + "/opt/local/lib/libSDL2_ttf.dylib" + ]; + } + else version(Posix) { + const(char)[][6] libNames = [ + "libSDL2_ttf.so", + "/usr/local/lib/libSDL2_ttf.so", + "libSDL2-2.0_ttf.so", + "/usr/local/lib/libSDL2-2.0_ttf.so", + "libSDL2-2.0_ttf.so.0", + "/usr/local/lib/libSDL2-2.0_ttf.so.0" + ]; + } + else static assert(0, "bindbc-sdl is not yet supported on this platform."); + + SDLTTFSupport ret; + foreach(name; libNames) { + ret = loadSDLTTF(name.ptr); + if(ret != SDLTTFSupport.noLibrary) break; + } + return ret; + } + + SDLTTFSupport loadSDLTTF(const(char)* libName) + { + lib = load(libName); + if(lib == invalidHandle) { + return SDLTTFSupport.noLibrary; + } + + auto errCount = errorCount(); + loadedVersion = SDLTTFSupport.badLibrary; + + lib.bindSymbol(cast(void**)&TTF_Linked_Version,"TTF_Linked_Version"); + lib.bindSymbol(cast(void**)&TTF_ByteSwappedUNICODE,"TTF_ByteSwappedUNICODE"); + lib.bindSymbol(cast(void**)&TTF_Init,"TTF_Init"); + lib.bindSymbol(cast(void**)&TTF_OpenFont,"TTF_OpenFont"); + lib.bindSymbol(cast(void**)&TTF_OpenFontIndex,"TTF_OpenFontIndex"); + lib.bindSymbol(cast(void**)&TTF_OpenFontRW,"TTF_OpenFontRW"); + lib.bindSymbol(cast(void**)&TTF_OpenFontIndexRW,"TTF_OpenFontIndexRW"); + lib.bindSymbol(cast(void**)&TTF_GetFontStyle,"TTF_GetFontStyle"); + lib.bindSymbol(cast(void**)&TTF_SetFontStyle,"TTF_SetFontStyle"); + lib.bindSymbol(cast(void**)&TTF_GetFontOutline,"TTF_GetFontOutline"); + lib.bindSymbol(cast(void**)&TTF_SetFontOutline,"TTF_SetFontOutline"); + lib.bindSymbol(cast(void**)&TTF_GetFontHinting,"TTF_GetFontHinting"); + lib.bindSymbol(cast(void**)&TTF_SetFontHinting,"TTF_SetFontHinting"); + lib.bindSymbol(cast(void**)&TTF_FontHeight,"TTF_FontHeight"); + lib.bindSymbol(cast(void**)&TTF_FontAscent,"TTF_FontAscent"); + lib.bindSymbol(cast(void**)&TTF_FontDescent,"TTF_FontDescent"); + lib.bindSymbol(cast(void**)&TTF_FontLineSkip,"TTF_FontLineSkip"); + lib.bindSymbol(cast(void**)&TTF_GetFontKerning,"TTF_GetFontKerning"); + lib.bindSymbol(cast(void**)&TTF_SetFontKerning,"TTF_SetFontKerning"); + lib.bindSymbol(cast(void**)&TTF_FontFaces,"TTF_FontFaces"); + lib.bindSymbol(cast(void**)&TTF_FontFaceIsFixedWidth,"TTF_FontFaceIsFixedWidth"); + lib.bindSymbol(cast(void**)&TTF_FontFaceFamilyName,"TTF_FontFaceFamilyName"); + lib.bindSymbol(cast(void**)&TTF_FontFaceStyleName,"TTF_FontFaceStyleName"); + lib.bindSymbol(cast(void**)&TTF_GlyphIsProvided,"TTF_GlyphIsProvided"); + lib.bindSymbol(cast(void**)&TTF_GlyphMetrics,"TTF_GlyphMetrics"); + lib.bindSymbol(cast(void**)&TTF_SizeText,"TTF_SizeText"); + lib.bindSymbol(cast(void**)&TTF_SizeUTF8,"TTF_SizeUTF8"); + lib.bindSymbol(cast(void**)&TTF_SizeUNICODE,"TTF_SizeUNICODE"); + lib.bindSymbol(cast(void**)&TTF_RenderText_Solid,"TTF_RenderText_Solid"); + lib.bindSymbol(cast(void**)&TTF_RenderUTF8_Solid,"TTF_RenderUTF8_Solid"); + lib.bindSymbol(cast(void**)&TTF_RenderUNICODE_Solid,"TTF_RenderUNICODE_Solid"); + lib.bindSymbol(cast(void**)&TTF_RenderGlyph_Solid,"TTF_RenderGlyph_Solid"); + lib.bindSymbol(cast(void**)&TTF_RenderText_Shaded,"TTF_RenderText_Shaded"); + lib.bindSymbol(cast(void**)&TTF_RenderUTF8_Shaded,"TTF_RenderUTF8_Shaded"); + lib.bindSymbol(cast(void**)&TTF_RenderUNICODE_Shaded,"TTF_RenderUNICODE_Shaded"); + lib.bindSymbol(cast(void**)&TTF_RenderGlyph_Shaded,"TTF_RenderGlyph_Shaded"); + lib.bindSymbol(cast(void**)&TTF_RenderText_Blended,"TTF_RenderText_Blended"); + lib.bindSymbol(cast(void**)&TTF_RenderUTF8_Blended,"TTF_RenderUTF8_Blended"); + lib.bindSymbol(cast(void**)&TTF_RenderUNICODE_Blended,"TTF_RenderUNICODE_Blended"); + lib.bindSymbol(cast(void**)&TTF_RenderText_Blended_Wrapped,"TTF_RenderText_Blended_Wrapped"); + lib.bindSymbol(cast(void**)&TTF_RenderUTF8_Blended_Wrapped,"TTF_RenderUTF8_Blended_Wrapped"); + lib.bindSymbol(cast(void**)&TTF_RenderUNICODE_Blended_Wrapped,"TTF_RenderUNICODE_Blended_Wrapped"); + lib.bindSymbol(cast(void**)&TTF_RenderGlyph_Blended,"TTF_RenderGlyph_Blended"); + lib.bindSymbol(cast(void**)&TTF_CloseFont,"TTF_CloseFont"); + lib.bindSymbol(cast(void**)&TTF_Quit,"TTF_Quit"); + lib.bindSymbol(cast(void**)&TTF_WasInit,"TTF_WasInit"); + lib.bindSymbol(cast(void**)&TTF_GetFontKerningSize,"TTF_GetFontKerningSize"); + + if(errorCount() != errCount) return SDLTTFSupport.badLibrary; + else loadedVersion = SDLTTFSupport.sdlTTF2012; + + static if(sdlTTFSupport >= SDLTTFSupport.sdlTTF2014) { + lib.bindSymbol(cast(void**)&TTF_GetFontKerningSizeGlyphs,"TTF_GetFontKerningSizeGlyphs"); + + if(errorCount() != errCount) return SDLTTFSupport.badLibrary; + else loadedVersion = SDLTTFSupport.sdlTTF2014; + } + + return loadedVersion; + } +} \ No newline at end of file diff --git a/demos/libpng16-16.dll b/demos/libpng16-16.dll new file mode 100644 index 0000000000000000000000000000000000000000..709f724459a3f036811cf7cfbac64f3c900ea739 GIT binary patch literal 210944 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 z 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

    nx_A^935R@isyve6#U7io@Q+h6 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 z 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

    >GtjdC_I5bi= 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%0AS^KG+!*epii@!y>j(|Wcyy(JE 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


    i7Ox%6FnXsA&JP#uRDOE5$mI?43eFDD2 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 #HalVR3Q{H+bK% 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 NL$+!{HW&~=D%-Ki+5i8~B91V#x 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

    L0_Soj*ZDjQn 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

    kOqzfj=Jc$A#}s!BEc0TSnik4U5qM7g#zmr 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

    B=}Z%ftifxlYn0Ip65Pr=Y9BnKYky;??d>( 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�G& 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 literal 0 HcmV?d00001 diff --git a/demos/cimgui.dll b/demos/cimgui.dll new file mode 100644 index 0000000000000000000000000000000000000000..ef645de09a097490758b3a0dba8ebfccd132964c GIT binary patch literal 571392 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

    0P3ww&tmFJ=cY@!XMf6bGK;kn^&4`6 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

    ci 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

    6S4qs^5BM==&2LED;`r4 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 Kh1+J+t;mt|-o;+mdrNZz4#J`LE02jc?^YqHA69 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�Z9w{Lv(GNlMBSXYBdf&nj=UoD3 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 =Y7F!(#t$cPAA^G29rcW=AhVrtn`ct9xpI5s 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 Date: Mon, 25 Nov 2019 20:06:16 +0000 Subject: [PATCH 083/217] -updated tests: *updated build scripts *removed tls variables from code (needed to support WebAssembly) *some mmutils tweaks *some fixes *pthread TLS thread ID implementation -added Atomic file (reimplementation of atomics templates for emscripten) -added emscripten support to ecs.std --- compile_wasm.py | 11 +- demos/compile_wasm.py | 18 ++- demos/external/sources/glad/gl/funcs.d | 28 ++-- demos/external/sources/glad/gl/loader.d | 2 +- demos/external/sources/mmutils/thread_pool.d | 114 +++++++++----- demos/source/app.d | 23 +-- demos/source/demos/simple.d | 5 +- demos/source/demos/snake.d | 4 +- demos/source/demos/space_invaders.d | 2 - demos/source/game_core/job_updater.d | 88 ++++++++--- demos/utils/source/ecs_utils/gfx/texture.d | 2 +- demos/utils/source/ecs_utils/imgui_bind.d | 14 +- demos/utils/source/ecs_utils/utils.d | 9 ++ source/ecs/atomic.d | 88 +++++++++++ source/ecs/id_manager.d | 2 +- source/ecs/manager.d | 57 +++++-- source/ecs/std.d | 149 +++++++++++-------- tests/tests.d | 56 ++----- 18 files changed, 443 insertions(+), 229 deletions(-) create mode 100644 source/ecs/atomic.d diff --git a/compile_wasm.py b/compile_wasm.py index e808354..3bd1afd 100644 --- a/compile_wasm.py +++ b/compile_wasm.py @@ -24,16 +24,16 @@ def compile(sources, output): for f in files: ldc_cmd += f + ' ' - print ldc_cmd + print(ldc_cmd) if os.system(ldc_cmd): exit(0) - print + print() shared_flags = '' clean = 0 emc_flags = '' -ldc_flags = '' +ldc_flags = '--d-version=ECSEmscripten ' import_paths = ['source','tests'] build_tests = 0 @@ -69,6 +69,8 @@ for arg in sys.argv[1:]: shared_flags += '-O3 ' ldc_flags += '-release -enable-inlining ' emc_flags += '--llvm-lto 3 -s SIMD=1 ' + elif(arg == '-pthread'): + emc_flags += '-s PTHREAD_POOL_SIZE=16 -s USE_PTHREADS=1 ' else: print('unknown argument: ' + arg) exit() @@ -84,7 +86,8 @@ emcc_cmd = 'emcc -v ' + shared_flags + emc_flags + '-s ALLOW_MEMORY_GROWTH=1 -s #-s ALLOW_MEMORY_GROWTH=1 emcc_cmd += 'ecs.bc tests.bc' +#emcc_cmd += 'tests.bc' -print emcc_cmd +print(emcc_cmd) os.system(emcc_cmd) diff --git a/demos/compile_wasm.py b/demos/compile_wasm.py index 9e3f46a..c985693 100644 --- a/demos/compile_wasm.py +++ b/demos/compile_wasm.py @@ -13,7 +13,7 @@ def compile(sources, output): if file_extension == '.d' and filename != 'package': files.append(os.path.join(r, file)) - ldc_cmd = 'ldc2 ' + shared_flags + ldc_flags + '-oq -mtriple=wasm32-unknown-unknown-wasm -betterC --output-bc --od=.bc --singleobj --checkaction=C --of=' + output + ' ' + ldc_cmd = compiler + shared_flags + ldc_flags + '-oq -mtriple=wasm32-unknown-unknown-wasm -betterC --output-bc --od=.bc --singleobj --checkaction=C --of=' + output + ' ' for path in sources: ldc_cmd += '-I' + path + ' ' @@ -31,12 +31,14 @@ def compile(sources, output): print() +compiler = 'ldc2 ' +#compiler = 'ldmd2 -vtls ' shared_flags = '' clean = 0 demo = 0 sources = ['tests', 'source'] emc_flags = '-s USE_SDL=2 -s USE_SDL_IMAGE=2 -s SDL2_IMAGE_FORMATS="[\'png\']" --preload-file assets ' -ldc_flags = '--d-version=SDL_209 --d-version=BindSDL_Static --d-version=BindSDL_Image --d-version=MM_USE_POSIX_THREADS ' +ldc_flags = '--d-version=ECSEmscripten --d-version=SDL_209 --d-version=BindSDL_Static --d-version=BindSDL_Image --d-version=MM_USE_POSIX_THREADS ' import_paths = ['external/sources', 'external/imports', 'external/wasm_imports', '../source', 'utils/source', 'simple/source'] for arg in sys.argv[1:]: @@ -60,7 +62,7 @@ for arg in sys.argv[1:]: shared_flags += '-g ' elif(arg == '-g4'): ldc_flags += '-g ' - emc_flags += '-g4 ' + emc_flags += '-g4 --source-map-base ./ ' elif(arg == '--llvm-lto'): emc_flags += '--llvm-lto 3 ' elif(arg == '--simd'): @@ -69,12 +71,12 @@ for arg in sys.argv[1:]: shared_flags += '-O3 ' ldc_flags += '-release -enable-inlining ' emc_flags += '--llvm-lto 3 -s SIMD=1 ' + elif(arg == '-quiet'): + emc_flags += "-Wl,--no-check-features " elif(arg == '--clean'): clean = 1 elif(arg == '-pthread'): - shared_flags += '-O3 ' - ldc_flags += '-release -enable-inlining ' - emc_flags += '-s PTHREAD_POOL_SIZE=16 -s USE_PTHREADS=1 ' + emc_flags += '-s USE_PTHREADS=1 ' elif(arg == '--demo=simple'): demo = 0 else: @@ -90,8 +92,8 @@ compile(['source'], 'demo.bc') if clean or os.path.exists('../ecs.bc') == 0 or os.path.isfile('../ecs.bc') == 0: compile(['../source'], '../ecs.bc') -emcc_cmd = 'emcc -v ' + shared_flags + emc_flags + '-s ERROR_ON_UNDEFINED_SYMBOLS=0 -s DISABLE_DEPRECATED_FIND_EVENT_TARGET_BEHAVIOR=1 -s TOTAL_MEMORY=256MB -s WASM_MEM_MAX=1024MB -s MALLOC=dlmalloc -s WASM=1 -o index.html ' -#-s ALLOW_MEMORY_GROWTH=1 -s PROXY_TO_PTHREAD=1 +emcc_cmd = 'emcc -v ' + shared_flags + emc_flags + '-s DISABLE_DEPRECATED_FIND_EVENT_TARGET_BEHAVIOR=1 -s ALLOW_MEMORY_GROWTH=1 -s WASM_MEM_MAX=2048MB -s MALLOC=dlmalloc -s WASM=1 -o index.html ' +#-s ALLOW_MEMORY_GROWTH=1 -s PROXY_TO_PTHREAD=1 -Wl,--no-check-features -s ERROR_ON_UNDEFINED_SYMBOLS=0 -s TOTAL_MEMORY=512MB emcc_cmd += '../ecs.bc ' emcc_cmd += 'utils.bc ' diff --git a/demos/external/sources/glad/gl/funcs.d b/demos/external/sources/glad/gl/funcs.d index 928cd83..bfad207 100644 --- a/demos/external/sources/glad/gl/funcs.d +++ b/demos/external/sources/glad/gl/funcs.d @@ -2,20 +2,20 @@ module glad.gl.funcs; private import glad.gl.types; -bool GL_VERSION_1_0; -bool GL_VERSION_1_1; -bool GL_VERSION_1_2; -bool GL_VERSION_1_3; -bool GL_VERSION_1_4; -bool GL_VERSION_1_5; -bool GL_VERSION_2_0; -bool GL_VERSION_2_1; -bool GL_VERSION_3_0; -bool GL_VERSION_3_1; -bool GL_VERSION_3_2; -bool GL_VERSION_3_3; -bool GL_ES_VERSION_2_0; -bool GL_ES_VERSION_3_0; +__gshared bool GL_VERSION_1_0; +__gshared bool GL_VERSION_1_1; +__gshared bool GL_VERSION_1_2; +__gshared bool GL_VERSION_1_3; +__gshared bool GL_VERSION_1_4; +__gshared bool GL_VERSION_1_5; +__gshared bool GL_VERSION_2_0; +__gshared bool GL_VERSION_2_1; +__gshared bool GL_VERSION_3_0; +__gshared bool GL_VERSION_3_1; +__gshared bool GL_VERSION_3_2; +__gshared bool GL_VERSION_3_3; +__gshared bool GL_ES_VERSION_2_0; +__gshared bool GL_ES_VERSION_3_0; nothrow @nogc extern(System) { alias fp_glCullFace = void function(GLenum); alias fp_glFrontFace = void function(GLenum); diff --git a/demos/external/sources/glad/gl/loader.d b/demos/external/sources/glad/gl/loader.d index 35eca05..d640c61 100644 --- a/demos/external/sources/glad/gl/loader.d +++ b/demos/external/sources/glad/gl/loader.d @@ -109,7 +109,7 @@ bool gladLoadGL() { return status; } -static struct GLVersion { static int major = 0; static int minor = 0; } +__gshared struct GLVersion { __gshared int major = 0; __gshared int minor = 0; } private extern(C) char* strstr(const(char)*, const(char)*) @nogc; private extern(C) int strcmp(const(char)*, const(char)*) @nogc; private extern(C) int strncmp(const(char)*, const(char)*, size_t) @nogc; diff --git a/demos/external/sources/mmutils/thread_pool.d b/demos/external/sources/mmutils/thread_pool.d index eb4d53f..a5fbf91 100644 --- a/demos/external/sources/mmutils/thread_pool.d +++ b/demos/external/sources/mmutils/thread_pool.d @@ -1,12 +1,11 @@ module mmutils.thread_pool; -import core.atomic; +import ecs.atomic; + //import core.stdc.stdio; //import core.stdc.stdlib : free, malloc, realloc; //import core.stdc.string : memcpy; - - //import std.stdio; import std.algorithm : map; @@ -108,6 +107,9 @@ version (WebAssembly) } extern(C) int clock_gettime(clockid_t, timespec*) @nogc nothrow @system; + + extern(C) double emscripten_get_now() @nogc nothrow @system; + } /// High precison timer @@ -122,13 +124,14 @@ long useconds() return t.tv_sec * 1_000_000 + t.tv_usec;*/ - time_t time; - timespec spec; + //time_t time; + //timespec spec; - clock_gettime(CLOCK_REALTIME, &spec); + //lock_gettime(CLOCK_REALTIME, &spec); + return cast(long)(emscripten_get_now() * 1000.0); //time = spec.tv_sec; - return spec.tv_sec * 1000_000 + spec.tv_nsec / 1000; + //return spec.tv_sec * 1000_000 + spec.tv_nsec / 1000; } else version (Posix) { @@ -190,6 +193,22 @@ void instructionPause() static assert(0); } } + else version(WebAssembly) + { + version(LDC) + { + import ldc.attributes; + @optStrategy("none") + static void nop() + { + int i; + i++; +} + nop(); + } + else static assert(0); + } + else static assert(0); } ////////////////////////////////////////////// @@ -198,18 +217,17 @@ void instructionPause() version (MM_USE_POSIX_THREADS) { - version (Posix) - { - import core.sys.posix.pthread; - import core.sys.posix.semaphore; - } - else version (WebAssembly) + version (WebAssembly) { extern(C): //alias uint time_t; struct pthread_attr_t { - + union + { + int[10] __i; + uint[10] __s; + } } struct pthread_t @@ -230,7 +248,11 @@ version (MM_USE_POSIX_THREADS) void pthread_exit(void *retval); // semaphore.h - alias sem_t = void*; + //alias sem_t = void*; + struct sem_t + { + shared int[4] __val; + } int sem_init(sem_t*, int, uint); int sem_wait(sem_t*); int sem_trywait(sem_t*); @@ -240,6 +262,11 @@ version (MM_USE_POSIX_THREADS) //import core.sys.posix.pthread; //import core.sys.posix.semaphore; } + else version (Posix) + { + import core.sys.posix.pthread; + import core.sys.posix.semaphore; + } else version (Windows) { extern (C): @@ -317,7 +344,7 @@ version (MM_USE_POSIX_THREADS) void post() { int ret = sem_post(&mutex); - assert(ret == 0); + assert(ret >= 0); } void destroy() @@ -362,6 +389,9 @@ else version(D_BetterC) { version(Posix) { + import core.sys.posix.pthread; + import core.sys.posix.semaphore; + struct Semaphore { sem_t mutex; @@ -619,7 +649,7 @@ else ///////////////// ThreadPool ///////////////// ////////////////////////////////////////////// -private enum gMaxThreadsNum = 128; +private enum gMaxThreadsNum = 32; alias JobDelegate = void delegate(ThreadData*, JobData*); @@ -634,7 +664,7 @@ struct JobLog /// First in first out queue with atomic lock struct JobQueue { - alias LockType = long; + alias LockType = int; align(64) shared LockType lock; /// Lock for accesing list of Jobs align(64) JobData* first; /// Fist element in list of Jobs @@ -849,7 +879,8 @@ public: threadData.threadPool = &this; threadData.semaphore.initialize(); threadData.externalThread = true; - threadData.acceptJobs = true; + atomicStore(threadData.acceptJobs, true); + //threadData.acceptJobs = true; int threadNum = atomicOp!"+="(threadsNum, 1) - 1; @@ -866,18 +897,19 @@ public: void unregistExternalThread(ThreadData* threadData) { lockThreadsData(); - scope (exit) - unlockThreadsData(); + //scope (exit) + // unlockThreadsData(); disposeThreadData(threadData); + unlockThreadsData(); } /// Allows external threads to return from threadStartFunc void releaseExternalThreads() { lockThreadsData(); - scope (exit) - unlockThreadsData(); + //scope (exit) + // unlockThreadsData(); // Release external threads (including main thread) foreach (i, ref ThreadData* th; threadsData) @@ -891,14 +923,15 @@ public: addJobsRange(rng, cast(int) i); atomicStore(th.end, true); } + unlockThreadsData(); } /// Waits for all threads to finish and joins them (excluding external threads) void waitThreads() { lockThreadsData(); - scope (exit) - unlockThreadsData(); + //scope (exit) + // unlockThreadsData(); foreach (i, ref ThreadData* th; threadsData) { if (th is null) @@ -915,6 +948,7 @@ public: th.thread.join(); disposeThreadData(th); } + unlockThreadsData(); } /// Sets number of threads to accept new jobs @@ -927,8 +961,8 @@ public: assert(num > 0); lockThreadsData(); - scope (exit) - unlockThreadsData(); + //scope (exit) + // unlockThreadsData(); foreach (i, ref ThreadData* th; threadsData) { @@ -947,14 +981,15 @@ public: th = makeThreadData(); th.threadPool = &this; th.threadId = cast(int) i; - th.acceptJobs = true; + atomicStore(th.acceptJobs, true); + //th.acceptJobs = true; th.semaphore.initialize(); th.thread.start(&th.threadStartFunc); } atomicStore(threadsNum, num); - + unlockThreadsData(); } /// Adds job to be executed by thread pool, such a job won't be synchronized with any group or job @@ -1012,8 +1047,9 @@ public: { assert(rng[0].group == threadData.group); } + atomicOp!"+="(rng[0].group.jobsToBeDoneCount, cast(int) rng.length); - int threadsNumLocal = threadsNum; + int threadsNumLocal = atomicLoad(threadsNum); int part = cast(int) rng.length / threadsNumLocal; if (part > 0) { @@ -1040,13 +1076,13 @@ public: void addGroupAsynchronous(JobsGroup* group) { group.thPool = &this; + if (group.jobs.length == 0) { // Immediately call group end group.onGroupFinish(); return; } - group.setUpJobs(); auto rng = group.jobs[].map!((ref a) => &a); addJobsRange(rng, group.executeOnThreadNum); @@ -1066,8 +1102,8 @@ public: void flushAllLogs() { lockThreadsData(); - scope (exit) - unlockThreadsData(); + //scope (exit) + // unlockThreadsData(); foreach (thNum; 0 .. atomicLoad(threadsNum)) { ThreadData* th = threadsData[thNum]; @@ -1081,6 +1117,7 @@ public: onThreadFlushLogs(th); } + unlockThreadsData(); } /// Default implementation of flushing logs @@ -1161,7 +1198,7 @@ private: foreach (i; 0 .. 1_000) { - if (threadNum >= threadsNum) + if (threadNum >= atomicLoad(threadsNum)) { threadNum = 0; atomicStore(threadSelector, 0); @@ -1287,7 +1324,10 @@ public: this.name = name; this.jobs = jobs; this.executeOnThreadNum = executeOnThreadNum; - jobsToBeDoneCount = 0; + //jobsToBeDoneCount = 0; + //dependenciesWaitCount = 0; + atomicStore(jobsToBeDoneCount,0); + atomicStore(dependenciesWaitCount,0); } ~this() nothrow @@ -1330,6 +1370,7 @@ private: if (spawnedByGroup) { auto num = atomicOp!"-="(spawnedByGroup.jobsToBeDoneCount, 1); + assert(num >= 0); if (num == 0) { spawnedByGroup.onGroupFinish(); @@ -1438,7 +1479,8 @@ private void threadFunc(ThreadData* threadData) } } - threadData.end = false; + //threadData.end = false; + atomicStore(threadData.end, false); assert(threadData.jobsQueue.empty()); } diff --git a/demos/source/app.d b/demos/source/app.d index 10592ac..137ac1a 100644 --- a/demos/source/app.d +++ b/demos/source/app.d @@ -160,14 +160,14 @@ struct CleanSystem void mainLoop(void* arg) { - static double time = 0; + __gshared double time = 0; launcher.delta_time = launcher.getTime() - time; time = launcher.getTime(); if(launcher.delta_time > 1000)launcher.delta_time = 1000; - static uint temp_fps = 0; - static double fps_time = 0; + __gshared uint temp_fps = 0; + __gshared double fps_time = 0; temp_fps++; fps_time += launcher.delta_time; while(fps_time > 1000) @@ -295,7 +295,7 @@ void mainLoop(void* arg) { launcher.setStyle(2); } - else if(igMenuItemBool("Super",null,launcher.style == 3,true)) + else if(igMenuItemBool("Default",null,launcher.style == 3,true)) { launcher.setStyle(3); } @@ -466,8 +466,8 @@ void mainLoop(void* arg) launcher.renderer.present(); draw_time = launcher.getTime() - draw_time; - static float plot_time = 0; - static uint plot_samples = 0; + __gshared float plot_time = 0; + __gshared uint plot_samples = 0; plot_time += launcher.delta_time; plot_samples++; launcher.plot_values[100].delta_time += launcher.delta_time; @@ -602,14 +602,15 @@ int main(int argc, char** argv) setStyle(3); - launcher.job_updater = Mallocator.make!ECSJobUpdater(8); + launcher.job_updater = Mallocator.make!ECSJobUpdater(12); //launcher.job_updater.onCreate(); - EntityManager.initialize(8); + EntityManager.initialize(12); launcher.manager = EntityManager.instance; - launcher.manager.m_thread_id_func = &launcher.job_updater.getThreadID; - launcher.manager.setJobDispachFunc(&launcher.job_updater.dispatch); + //launcher.manager.m_thread_id_func = &launcher.job_updater.getThreadID; + //launcher.manager.setJobDispachFunc(&launcher.job_updater.dispatch); + launcher.manager.setMultithreadingCallbacks(&launcher.job_updater.dispatch, &launcher.job_updater.getThreadID); launcher.manager.beginRegister(); @@ -645,7 +646,7 @@ int main(int argc, char** argv) //int result = emscripten_request_fullscreen_strategy(null, true, &strategy); //emscripten_enter_soft_fullscreen(null, &strategy); //printf("Fullscreen request: %s.\n", emscripten_result_to_string(result)); - emscripten_set_main_loop_arg(&mainLoop, null, -1, 1); + emscripten_set_main_loop_arg(&mainLoop, null, 0, 1); } else { diff --git a/demos/source/demos/simple.d b/demos/source/demos/simple.d index 9340458..9dfa83b 100644 --- a/demos/source/demos/simple.d +++ b/demos/source/demos/simple.d @@ -86,7 +86,7 @@ struct MoveSystem } } -Simple* simple; +__gshared Simple* simple; void simpleStart() { @@ -149,7 +149,7 @@ bool simpleLoop() { if(launcher.getKeyState(SDL_SCANCODE_SPACE)) { - spawnEntity(); + foreach(i;0..10000)spawnEntity(); } @@ -159,7 +159,6 @@ bool simpleLoop() launcher.job_updater.begin(); launcher.manager.updateMT(); launcher.job_updater.call(); - launcher.multithreading = false; } else { diff --git a/demos/source/demos/snake.d b/demos/source/demos/snake.d index 19f08ad..9df3fcc 100644 --- a/demos/source/demos/snake.d +++ b/demos/source/demos/snake.d @@ -409,7 +409,7 @@ struct CleanSystem } } -Snake* snake; +__gshared Snake* snake; void snakeStart() { @@ -500,7 +500,7 @@ bool snakeLoop() float delta_time = launcher.delta_time; if(delta_time > 2000)delta_time = 2000; - static float time = 0; + __gshared float time = 0; if(launcher.getKeyState(SDL_SCANCODE_SPACE))time += delta_time * 3; else time += delta_time; diff --git a/demos/source/demos/space_invaders.d b/demos/source/demos/space_invaders.d index 2d8ebc0..3ef90c4 100644 --- a/demos/source/demos/space_invaders.d +++ b/demos/source/demos/space_invaders.d @@ -746,8 +746,6 @@ bool spaceInvadersLoop() launcher.job_updater.begin(); launcher.manager.updateMT(); launcher.job_updater.call(); - launcher.multithreading = false; - printf("Disable mt\n"); } else { diff --git a/demos/source/game_core/job_updater.d b/demos/source/game_core/job_updater.d index 26cd8e3..46cd609 100644 --- a/demos/source/game_core/job_updater.d +++ b/demos/source/game_core/job_updater.d @@ -2,6 +2,7 @@ module game_core.job_updater; import ecs.std; import ecs.vector; +import ecs.atomic; import ecs_utils.utils; @@ -9,6 +10,17 @@ import ecs_utils.utils; import ecs.manager; import mmutils.thread_pool; +version(LDC) +{ + import ldc.attributes; +} +else +{ + struct optStrategy { + string strategy; + } +} + //import supre.core.call_graph_generator; struct ECSJobUpdater @@ -24,14 +36,21 @@ struct ECSJobUpdater pool.waitThreads(); //pool.unregistExternalThread(thread_data); if(jobs)Mallocator.dispose(jobs); + version(WebAssembly)pthread_key_delete(tls_key); } + version(WebAssembly) + { + __gshared pthread_key_t tls_key; + } + else static uint thread_id = 0; + ThreadPool pool; ThreadData* thread_data; int job_id = 0; int no_dep_count = 0; - static uint thread_id = 0; + //static uint thread_id = 0; struct Group { @@ -78,21 +97,25 @@ struct ECSJobUpdater Group[] jobs; Vector!(Group*) call_jobs; Group last_job; + JobData[1] groupEndJobs; //TrackData[32] trackers; void onCreate(uint threads_count) { + version(WebAssembly)pthread_key_create(&tls_key, null); + pool.initialize(); - //thread_data = pool.registerExternalThread(); + thread_data = pool.registerExternalThread(); pool.setThreadsNum(threads_count); jobs = Mallocator.makeArray!Group(256); } - uint getThreadID() nothrow + uint getThreadID() @nogc nothrow { - return thread_id; + version(WebAssembly)return cast(int)pthread_getspecific(tls_key); + else return thread_id; } void begin() @@ -113,36 +136,44 @@ struct ECSJobUpdater //foreach(ref tracker;trackers)tracker.clear(); } + @optStrategy("none") + void nop() + { + int i; + i++; + } + + //@optStrategy("none") void call() { if(last_job.group.getDependenciesWaitCount() == 0)return; if(call_jobs.length == 0)return; - JobData[1] groupEndJobs; - groupEndJobs[0] = JobData(&releaseMainThread, "Stop Threads"); + //JobData[1] groupEndJobs; + groupEndJobs[0] = JobData(&releaseMainThread, "Stop Threads", null, null); last_job.group.jobs = groupEndJobs; + last_job.group.thPool = &pool; last_job.group.executeOnThreadNum = 0; foreach(job;call_jobs) { job.start(); } - ret = false; - while(!ret) + + /*while(atomicLoad(ret) == 1)//!cas(&ret,0,1)) { - printf("SDL\n"); - } - printf("NonSDL\n"); - //thread_data.threadStartFunc(); + nop(); + version(WebAssembly)//emscripten_main_thread_process_queued_calls(); + }//*/ - int i = 10; + thread_data.threadStartFunc(); } -shared bool ret = false; + void releaseMainThread(ThreadData* th_data, JobData* data) { - //pool.releaseExternalThreads(); - ret = true; + //atomicStore(ret,0); + pool.releaseExternalThreads(); } static struct JobCaller @@ -153,10 +184,27 @@ shared bool ret = false; void callJob(ThreadData* th_data, JobData* data) { - updater.thread_id = th_data.threadId; - uint job_id = updater.getThreadID(); + + //uint job_id = updater.getThreadID(); //updater.trackers[job_id].begin(id); - job.execute(); + version(WebAssembly) + { + //updater.thread_id = th_data.threadId; + pthread_setspecific(tls_key, cast(void*)th_data.threadId); + if(th_data.threadId == 0) + { + emscripten_main_thread_process_queued_calls(); + job.execute(); + emscripten_main_thread_process_queued_calls(); + } + else job.execute(); + } + else + { + updater.thread_id = th_data.threadId; + job.execute(); + } + //atomicOp!"-="(updater.jobs_count,1); //updater.trackers[job_id].end(); } } @@ -178,7 +226,7 @@ shared bool ret = false; caller.id = index; jobs[group.id].add(caller); } - + jobs[group.id].build(&pool); uint deps = cast(uint)group.dependencies.length; diff --git a/demos/utils/source/ecs_utils/gfx/texture.d b/demos/utils/source/ecs_utils/gfx/texture.d index 6f41fe2..4407123 100644 --- a/demos/utils/source/ecs_utils/gfx/texture.d +++ b/demos/utils/source/ecs_utils/gfx/texture.d @@ -87,7 +87,7 @@ struct Texture } } - static bool function(ref Texture this_, const char[] path) __load; + __gshared bool function(ref Texture this_, const char[] path) __load; struct Data { diff --git a/demos/utils/source/ecs_utils/imgui_bind.d b/demos/utils/source/ecs_utils/imgui_bind.d index 3e84328..b6572cb 100644 --- a/demos/utils/source/ecs_utils/imgui_bind.d +++ b/demos/utils/source/ecs_utils/imgui_bind.d @@ -28,12 +28,12 @@ import cimgui.cimgui; extern(C): -SDL_Window* g_Window; -ulong g_Time; -bool[3] g_MousePressed; -SDL_Cursor*[ImGuiMouseCursor_COUNT] g_MouseCursors; -char* g_ClipboardTextData; -GLuint g_FontTexture = 0; +__gshared SDL_Window* g_Window; +__gshared ulong g_Time; +__gshared bool[3] g_MousePressed; +__gshared SDL_Cursor*[ImGuiMouseCursor_COUNT] g_MouseCursors; +__gshared char* g_ClipboardTextData; +__gshared GLuint g_FontTexture = 0; const (char)* ImGuiImplSDL2GetClipboardText(void*) { @@ -280,7 +280,7 @@ static void ImGui_ImplSDL2_UpdateGamepads() } -private long frequency; +__gshared private long frequency; void ImGuiImplSDL2NewFrame(SDL_Window* window) { diff --git a/demos/utils/source/ecs_utils/utils.d b/demos/utils/source/ecs_utils/utils.d index aa223eb..4c143fd 100644 --- a/demos/utils/source/ecs_utils/utils.d +++ b/demos/utils/source/ecs_utils/utils.d @@ -50,6 +50,12 @@ version(D_BetterC) version(WebAssembly) { + alias pthread_key_t = uint; + + extern (C) int pthread_key_create(pthread_key_t *, void* function(void *)) @nogc nothrow; + extern (C) int pthread_key_delete(pthread_key_t) @nogc nothrow; + extern (C) void* pthread_getspecific(pthread_key_t) @nogc nothrow; + extern (C) int pthread_setspecific(pthread_key_t, const void *) @nogc nothrow; enum EMSCRIPTEN_RESULT_SUCCESS = 0; enum EMSCRIPTEN_RESULT_DEFERRED = 1; @@ -109,6 +115,9 @@ version(WebAssembly) extern (C) void emscripten_cancel_main_loop(); extern (C) int emscripten_request_fullscreen_strategy(const char *target, bool deferUntilInEventHandler, const EmscriptenFullscreenStrategy *fullscreenStrategy); extern (C) int emscripten_enter_soft_fullscreen(const char *target, const EmscriptenFullscreenStrategy *fullscreenStrategy); + extern (C) void emscripten_main_thread_process_queued_calls(); + extern (C) void emscripten_pause_main_loop(); + extern (C) void emscripten_resume_main_loop(); alias int time_t; alias int clockid_t; diff --git a/source/ecs/atomic.d b/source/ecs/atomic.d new file mode 100644 index 0000000..1ab78af --- /dev/null +++ b/source/ecs/atomic.d @@ -0,0 +1,88 @@ +module ecs.atomic; + +version(Emscripten)version = ECSEmscripten; + +version(ECSEmscripten) +{ + import std.traits; + + enum MemoryOrder + { + acq, + acq_rel, + raw, + rel, + seq + } + + extern(C) ubyte emscripten_atomic_cas_u8(void *addr, ubyte oldVal, ubyte newVal) @nogc nothrow pure; + extern(C) ushort emscripten_atomic_cas_u16(void *addr, ushort oldVal, ushort newVal) @nogc nothrow pure; + extern(C) uint emscripten_atomic_cas_u32(void *addr, uint oldVal, uint newVal) @nogc nothrow pure; + + extern(C) ubyte emscripten_atomic_load_u8(const void *addr) @nogc nothrow pure; + extern(C) ushort emscripten_atomic_load_u16(const void *addr) @nogc nothrow pure; + extern(C) uint emscripten_atomic_load_u32(const void *addr) @nogc nothrow pure; + + extern(C) ubyte emscripten_atomic_store_u8(void *addr, ubyte val) @nogc nothrow pure; + extern(C) ushort emscripten_atomic_store_u16(void *addr, ushort val) @nogc nothrow pure; + extern(C) uint emscripten_atomic_store_u32(void *addr, uint val) @nogc nothrow pure; + + extern(C) ubyte emscripten_atomic_add_u8(void *addr, ubyte val) @nogc nothrow pure; + extern(C) ushort emscripten_atomic_add_u16(void *addr, ushort val) @nogc nothrow pure; + extern(C) uint emscripten_atomic_add_u32(void *addr, uint val) @nogc nothrow pure; + + extern(C) ubyte emscripten_atomic_sub_u8(void *addr, ubyte val) @nogc nothrow pure; + extern(C) ushort emscripten_atomic_sub_u16(void *addr, ushort val) @nogc nothrow pure; + extern(C) uint emscripten_atomic_sub_u32(void *addr, uint val) @nogc nothrow pure; + + pure nothrow @nogc Unqual!T atomicOp(string op, T, V1)(ref shared T val, V1 mod) + { + static if(op == "+=") + { + static if(is(T == byte) || is(T == ubyte))return cast(Unqual!T)(emscripten_atomic_add_u8(cast(void*)&val, cast(Unqual!T)mod) + 1); + else static if(is(T == short) || is(T == ushort))return cast(Unqual!T)(emscripten_atomic_add_u16(cast(void*)&val, cast(Unqual!T)mod) + 1); + else static if(is(T == int) || is(T == uint))return cast(Unqual!T)(emscripten_atomic_add_u32(cast(void*)&val, cast(Unqual!T)mod) + 1); + else static assert(0); + } + else static if(op == "-=") + { + static if(is(T == byte) || is(T == ubyte))return cast(Unqual!T)(emscripten_atomic_sub_u8(cast(void*)&val, cast(Unqual!T)mod) - 1); + else static if(is(T == short) || is(T == ushort))return cast(Unqual!T)(emscripten_atomic_sub_u16(cast(void*)&val, cast(Unqual!T)mod) - 1); + else static if(is(T == int) || is(T == uint))return cast(Unqual!T)(emscripten_atomic_sub_u32(cast(void*)&val, cast(Unqual!T)mod) - 1); + else static assert(0); + } + } + + pure nothrow @nogc @trusted void atomicStore(MemoryOrder ms = MemoryOrder.seq, T, V)(ref T val, V newval) + { + alias UT = Unqual!T; + static if(is(UT == bool) || is(UT == byte) || is(UT == ubyte))emscripten_atomic_store_u8(cast(void*)&val, cast(UT)newval); + else static if(is(UT == short) || is(UT == ushort))emscripten_atomic_store_u16(cast(void*)&val, cast(UT)newval); + else static if(is(UT == int) || is(UT == uint))emscripten_atomic_store_u32(cast(void*)&val, cast(UT)newval); + else static assert(0); + } + + pure nothrow @nogc @trusted T atomicLoad(MemoryOrder ms = MemoryOrder.seq, T)(ref const T val) + { + alias UT = Unqual!T; + static if(is(UT == bool))return emscripten_atomic_load_u8(cast(const void*)&val) != 0; + else static if(is(UT == byte) || is(UT == ubyte))return emscripten_atomic_load_u8(cast(const void*)&val); + else static if(is(UT == short) || is(UT == ushort))return emscripten_atomic_load_u16(cast(const void*)&val); + else static if(is(UT == int) || is(UT == uint))return emscripten_atomic_load_u32(cast(const void*)&val); + else static assert(0); + } + + pure nothrow @nogc @trusted bool cas(MemoryOrder succ = MemoryOrder.seq, MemoryOrder fail = MemoryOrder.seq, T, V1, V2)(T* here, V1 ifThis, V2 writeThis) + { + alias UT = Unqual!T; + static if(is(UT == bool))return emscripten_atomic_cas_u8(cast(void*)here, cast(Unqual!T)ifThis, cast(Unqual!T)writeThis) == ifThis; + else static if(is(UT == byte) || is(UT == ubyte))return emscripten_atomic_cas_u8(cast(void*)here, cast(Unqual!T)ifThis, cast(Unqual!T)writeThis) == ifThis; + else static if(is(UT == short) || is(UT == ushort))return emscripten_atomic_cas_u16(cast(void*)here, cast(Unqual!T)ifThis, cast(Unqual!T)writeThis) == ifThis; + else static if(is(UT == int) || is(UT == uint))return emscripten_atomic_cas_u32(cast(void*)here, cast(Unqual!T)ifThis, cast(Unqual!T)writeThis) == ifThis; + else static assert(0); + } +} +else +{ + public import core.atomic; +} \ No newline at end of file diff --git a/source/ecs/id_manager.d b/source/ecs/id_manager.d index 1804390..ebd7679 100644 --- a/source/ecs/id_manager.d +++ b/source/ecs/id_manager.d @@ -4,7 +4,7 @@ import ecs.entity; import ecs.std; import ecs.vector; -import core.atomic; +import ecs.atomic; import core.stdc.string : memcpy; /************************************************************************************************************************ diff --git a/source/ecs/manager.d b/source/ecs/manager.d index 8d461fd..b80e0e7 100644 --- a/source/ecs/manager.d +++ b/source/ecs/manager.d @@ -7,7 +7,7 @@ import std.algorithm : max; import std.conv : to; import std.traits; -import core.atomic; +//import core.atomic; //import core.stdc.stdlib : qsort; //import core.stdc.string; @@ -21,6 +21,7 @@ import ecs.simple_vector; import ecs.std; import ecs.traits; import ecs.vector; +import ecs.atomic; export alias gEM = EntityManager.instance; export alias gEntityManager = EntityManager.instance; @@ -1119,10 +1120,16 @@ export struct EntityManager } } - export void setJobDispachFunc(void delegate(JobGroup) func) nothrow @nogc + export void setMultithreadingCallbacks(void delegate(JobGroup) dispatch_callback, uint delegate() get_id_callback) + { + m_dispatch_jobs = cast(void delegate(JobGroup jobs) nothrow @nogc)dispatch_callback; + m_thread_id_func = cast(uint delegate() nothrow @nogc)get_id_callback; + } + + /*export void setJobDispachFunc(void delegate(JobGroup) @nogc nothrow func) nothrow @nogc { m_dispatch_jobs = func; - } + }*/ static void alignNum(ref ushort num, ushort alignment) nothrow @nogc pure { @@ -1502,7 +1509,7 @@ export struct EntityManager */ export void removeComponents(EntityID entity_id, ushort[] del_ids) nothrow @nogc { - ThreadData* data = &threads[thread_id]; + ThreadData* data = &threads[threadID]; uint num = cast(uint) del_ids.length; data.change_entities_list.add(0); data.change_entities_list.add((cast(ubyte*)&entity_id)[0 .. EntityID.sizeof]); @@ -1753,7 +1760,7 @@ export struct EntityManager new_ids[i] = comp.component_id; } - ThreadData* data = &threads[thread_id]; + ThreadData* data = &threads[threadID]; data.change_entities_list.add(cast(ubyte)1u); data.change_entities_list.add((cast(ubyte*)&entity_id)[0 .. EntityID.sizeof]); data.change_entities_list.add((cast(ubyte*)&num)[0 .. uint.sizeof]); @@ -1820,7 +1827,7 @@ export struct EntityManager } if (new_index == 1) - threads[thread_id].blocks_to_update.add(new_block); + threads[threadID].blocks_to_update.add(new_block); Entity* new_entity = cast(Entity*) start; //add_mutex.lock_nothrow(); @@ -1870,7 +1877,7 @@ export struct EntityManager } if (index == 1) - threads[thread_id].blocks_to_update.add(block); + threads[threadID].blocks_to_update.add(block); Entity* entity = cast(Entity*) start; //add_mutex.lock_nothrow(); @@ -1961,7 +1968,7 @@ export struct EntityManager */ export void removeEntity(EntityID id) { - threads[thread_id].entities_to_remove.add(id); + threads[threadID].entities_to_remove.add(id); } private void __removeEntity(EntityID id) nothrow @nogc @@ -2301,17 +2308,17 @@ export struct EntityManager commit(); } - private void getThreadID() nothrow @nogc + /*private void getThreadID() nothrow @nogc { if (m_thread_id_func) thread_id = (cast(uint delegate() nothrow @nogc) m_thread_id_func)(); else thread_id = 0; - } + }*/ void sendEvent(Ev)(EntityID id, Ev event) nothrow @nogc { - event_manager.sendEvent(id, event, thread_id); + event_manager.sendEvent(id, event, threadID); } private void generateDependencies() nothrow @nogc @@ -2722,7 +2729,7 @@ export struct EntityManager export void execute() nothrow @nogc { - EntityManager.instance.getThreadID(); + //EntityManager.instance.getThreadID(); foreach (ref caller; callers) { caller.update(); @@ -2789,7 +2796,27 @@ export struct EntityManager Vector!(SystemCaller*) system_callers; } - static uint thread_id; + export uint threadID() @nogc nothrow + { + if (m_thread_id_func) + return m_thread_id_func(); + else + return 0; + } + + /*uint thread_id() @nogc nothrow + { + if (m_thread_id_func) + return (cast(uint delegate() nothrow @nogc) m_thread_id_func)(); + else + return 0; + } + + void thread_id(uint) @nogc nothrow + { + }*/ + + //static uint thread_id; ThreadData[] threads; @@ -2809,8 +2836,8 @@ export struct EntityManager EventManager event_manager; - void delegate(JobGroup jobs) m_dispatch_jobs; - uint delegate() m_thread_id_func; + void delegate(JobGroup jobs) nothrow @nogc m_dispatch_jobs; + uint delegate() nothrow @nogc m_thread_id_func; HashMap!(ushort[], EntityInfo*) entities_infos; HashMap!(char[], ushort) systems_map; diff --git a/source/ecs/std.d b/source/ecs/std.d index c8b7ecd..81eed0a 100644 --- a/source/ecs/std.d +++ b/source/ecs/std.d @@ -1,12 +1,25 @@ module ecs.std; -//import core.stdc.stdlib : malloc, free, realloc; -//import core.stdc.string : memcpy; +version(Emscripten)version = ECSEmscripten; import std.traits; -version(WebAssembly) +version(ECSEmscripten) { + extern(C) struct pthread_mutex_t + { + union + { + int[6] __i; + void[6] *__p; + } + } + + extern(C) struct pthread_mutexattr_t + { + uint __attr; + } + extern(C) int memcmp (const void *s1, const void *s2, size_t size); extern(C) void exit (int status) nothrow @nogc; extern(C) void __assert(const(char)* msg, const(char)* file, uint line) { exit(-20);} @@ -17,6 +30,16 @@ version(WebAssembly) extern(C) void* memset(void*, int val, size_t size) @nogc nothrow @system; extern(C) int posix_memalign(void**, size_t, size_t) @nogc nothrow @system; extern(C) void qsort(void* base, size_t num, size_t size, int function(const void*,const void*) compar) @nogc nothrow @system; + + extern(C) int pthread_mutex_lock(pthread_mutex_t *mutex) @nogc nothrow; + extern(C) int pthread_mutex_trylock(pthread_mutex_t *mutex) @nogc nothrow; + extern(C) int pthread_mutex_unlock(pthread_mutex_t *mutex) @nogc nothrow; + extern(C) void pthread_mutexattr_settype(pthread_mutexattr_t *attr, int type) @nogc nothrow; + extern(C) void pthread_mutexattr_destroy(pthread_mutexattr_t *attr) @nogc nothrow; + extern(C) int pthread_mutexattr_init(pthread_mutexattr_t *attr) @nogc nothrow; + extern(C) int pthread_mutex_destroy(pthread_mutex_t *mutex) @nogc nothrow; + extern(C) int pthread_mutex_init(pthread_mutex_t* mutex, const pthread_mutexattr_t* attr) @nogc nothrow; + } else { @@ -25,8 +48,10 @@ else public import core.stdc.stdlib : qsort; } - -version (Windows) +version(ECSEmscripten) +{ +} +else version (Windows) { import core.sys.windows.windows; extern(Windows) void* _aligned_malloc(size_t size,size_t alignment) @nogc nothrow @system; @@ -51,10 +76,28 @@ else version (Posix) import core.sys.posix.stdlib; } -version(D_betterC) +version(ECSEmscripten) { private const uint max_alloca = 10000; - private char[max_alloca] alloca_array; + private __gshared byte[max_alloca] alloca_array; + private __gshared uint alloca_pos = 0; + export extern(C) void* alloca(size_t length) @nogc nothrow + { + if(alloca_pos + length > max_alloca)alloca_pos = 0; + void* ret = &alloca_array[alloca_pos]; + alloca_pos += length; + return ret; + } + //extern(C) void* alloca(size_t size) @nogc nothrow; + /*export extern(C) void* alloca(size_t length) @nogc nothrow + { + return null; + }*/ +} +else version(D_BetterC) +{ + private const uint max_alloca = 10000; + private __gshared byte[max_alloca] alloca_array; private uint alloca_pos = 0; export extern(C) void* alloca(size_t length) @nogc nothrow { @@ -64,20 +107,10 @@ version(D_betterC) return ret; } } -else version(WebAssembly) +else { - private const uint max_alloca = 10000; - private char[max_alloca] alloca_array; - private uint alloca_pos = 0; - export extern(C) void* alloca(size_t length) @nogc nothrow - { - if(alloca_pos + length > max_alloca)alloca_pos = 0; - void* ret = &alloca_array[alloca_pos]; - alloca_pos += length; - return ret; - } + public import core.stdc.stdlib : alloca; } -else public import core.stdc.stdlib : alloca; static struct Mallocator { @@ -143,7 +176,7 @@ static struct Mallocator void* ret; version(Posix)posix_memalign(&ret, alignment, length);//ret = aligned_alloc(alignment, length); else version(Windows)ret = _aligned_malloc(length, alignment); - else version(WebAssembly)posix_memalign(&ret, alignment, length);//malloc(length); + else version(ECSEmscripten)posix_memalign(&ret, alignment, length);//malloc(length); else static assert(0, "Unimplemented platform!"); return ret; } @@ -159,7 +192,7 @@ static struct Mallocator static if(__traits(hasMember, T, "__dtor"))object.__dtor(); version(Posix)free(cast(void*)object); else version(Windows)_aligned_free(cast(void*)object); - else version(WebAssembly)free(cast(void*)object); + else version(ECSEmscripten)free(cast(void*)object); else static assert(0, "Unimplemented platform!"); } } @@ -167,7 +200,43 @@ static struct Mallocator struct Mutex { - version (Windows) + version(ECSEmscripten) + { + void initialize() nothrow @nogc + { + pthread_mutexattr_t attr = void; + + //pthread_mutexattr_init(&attr); + + //pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); + pthread_mutex_init(cast(pthread_mutex_t*) &m_handle, &attr); + + //pthread_mutexattr_destroy(&attr); + } + + void destroy() nothrow @nogc + { + pthread_mutex_destroy(&m_handle); + } + + void lock() nothrow @nogc + { + pthread_mutex_lock(&m_handle); + } + + void unlock() nothrow @nogc + { + pthread_mutex_unlock(&m_handle); + } + + int tryLock() nothrow @nogc + { + return pthread_mutex_trylock(&m_handle) == 0; + } + + private pthread_mutex_t m_handle; + } + else version (Windows) { void initialize() nothrow @nogc { @@ -232,41 +301,5 @@ struct Mutex private pthread_mutex_t m_handle; } - else version(WebAssembly) - { - void initialize() nothrow @nogc - { - /*pthread_mutexattr_t attr = void; - - pthread_mutexattr_init(&attr); - - pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); - pthread_mutex_init(cast(pthread_mutex_t*) &m_handle, &attr); - - pthread_mutexattr_destroy(&attr);*/ - } - - void destroy() nothrow @nogc - { - //pthread_mutex_destroy(&m_handle); - } - - void lock() nothrow @nogc - { - //pthread_mutex_lock(&m_handle); - } - - void unlock() nothrow @nogc - { - //pthread_mutex_unlock(&m_handle); - } - - int tryLock() nothrow @nogc - { - return 0;//return pthread_mutex_trylock(&m_handle) == 0; - } - - private int m_handle; - } else static assert(0, "unsupported platform!"); } \ No newline at end of file diff --git a/tests/tests.d b/tests/tests.d index 2e5e3e6..703f391 100644 --- a/tests/tests.d +++ b/tests/tests.d @@ -10,22 +10,9 @@ import ecs.system; import ecs.attributes; import ecs.core; - - version(WebAssembly) { extern(C) int printf(scope const char* format, ...) @nogc nothrow @system; - /*{ - return 0; - }*/ - //import core.stdc.stdio : printf; - /*struct Time - { - static long getUSecTime() - { - return 0; - } - }*/ alias int time_t; alias int clockid_t; @@ -52,11 +39,6 @@ version(WebAssembly) //time = spec.tv_sec; return spec.tv_sec * 1000_000 + spec.tv_nsec / 1000;//time / 1000_000; - - /*LARGE_INTEGER time, freq; - QueryPerformanceFrequency(&freq); - QueryPerformanceCounter(&time); - return time.QuadPart / (freq.QuadPart / 1000_000);*/ } } @@ -92,11 +74,6 @@ else version(Posix) //time = spec.tv_sec; return spec.tv_sec * 1000_000 + spec.tv_nsec / 1000;//time / 1000_000; - - /*LARGE_INTEGER time, freq; - QueryPerformanceFrequency(&freq); - QueryPerformanceCounter(&time); - return time.QuadPart / (freq.QuadPart / 1000_000);*/ } } } @@ -380,11 +357,6 @@ struct TestSystemWithHighPriority { } - - /*void handleEvent(Event event, ref TestComp comp) - { - - }*/ } struct Sys1 @@ -468,12 +440,7 @@ struct TestSystem2 //TestComp* tt; } - /*void handleEvent(EventInput input) - { - - }*/ - - void handleEvent(/*EventInput input, */Entity* entity, ref TestEvent event) + void handleEvent(Entity* entity, ref TestEvent event) { TestComp3* test = entity.getComponent!TestComp3; test.bg = event.a; @@ -482,7 +449,7 @@ struct TestSystem2 gEM.sendEvent(entity.id, event2); } - void handleEvent(/*EventInput input, */Entity* entity, ref TestEvent2 event) + void handleEvent(Entity* entity, ref TestEvent2 event) { TestComp3* test = entity.getComponent!TestComp3; test.gg = cast(uint) event.a; @@ -532,17 +499,11 @@ struct TestSystem2 } } - /*void handleEvent(Event event, ref TestComp comp) - { - - }*/ } extern(C) int main() { - - void dispatch(EntityManager.JobGroup jobs) nothrow @nogc { foreach (job; jobs.jobs) @@ -552,6 +513,11 @@ extern(C) int main() } } + uint getID() nothrow @nogc + { + return 0; + } + void writeEntityComponents(Entity* entity) { @@ -574,12 +540,10 @@ extern(C) int main() ////writeln((cast(uint*) pp)[0 .. 14], " ", pp); } - /*int a = 0; - if(!a)assert(0);*/ - EntityManager.initialize(1); - gEM.setJobDispachFunc(&dispatch); + //gEM.setJobDispachFunc(&dispatch); + gEM.setMultithreadingCallbacks(&dispatch, &getID); //assert(gEM !is null); gEM.beginRegister(); @@ -612,7 +576,7 @@ extern(C) int main() gEM.registerSystem!Sys2(-100); gEM.registerSystem!Sys3(-2); //gEM.registerSystem!TestSystemWithHighPriority(100); - //gEM.registerSystem!TestSystem2(0);*/ + //gEM.registerSystem!TestSystem2(0); gEM.endRegister(); /*dur = (MonoTime.currTime - time).total!"usecs"; From 19fc440ed6fd2851daf6f3e231c4a0a5f284fa34 Mon Sep 17 00:00:00 2001 From: Mergul Date: Mon, 25 Nov 2019 21:15:44 +0000 Subject: [PATCH 084/217] -updated meson.build --- meson.build | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/meson.build b/meson.build index 27c4a79..b26bdcc 100644 --- a/meson.build +++ b/meson.build @@ -12,6 +12,7 @@ src = [ 'source/ecs/simple_vector.d', 'source/ecs/simple_vector.d', 'source/ecs/std.d', + 'source/ecs/atomic.d', 'source/ecs/system.d', 'source/ecs/traits.d', 'source/ecs/vector.d', @@ -39,6 +40,8 @@ endif inc = include_directories('source/') tests_inc = include_directories('source/') -executable('ecs', [tests_src, src], include_directories : [tests_inc, inc], d_args: args, link_args: link_args) +ecs_lib = shared_library('ecs', src, include_directories : [tests_inc, inc], d_args: args, link_args: link_args) + +executable('tests', tests_src, include_directories : [tests_inc, inc], d_args: args, link_args: link_args, link_with: ecs_lib) From 1f78f2506c8b77360413d3a98e797bdba9a20f2b Mon Sep 17 00:00:00 2001 From: Mergul Date: Sun, 9 Feb 2020 15:24:26 +0100 Subject: [PATCH 085/217] -Events system update order is now choosen according to system priority -added mixin for adding exluded components using it's type -demos: *added GUI for selecting templates and choosing tools *change SpaceInvades SideMove system to not using events for better performance and multithreading *added Entites spawning support *fixed some Snake demo bugs *GUI work's better now --- demos/source/app.d | 108 +++++++++++++--- demos/source/demos/simple.d | 34 ++++- demos/source/demos/snake.d | 74 ++++++++++- demos/source/demos/space_invaders.d | 190 +++++++++++++++++++++++----- demos/source/gui/manager.d | 52 +++++++- demos/source/gui/template_.d | 9 ++ source/ecs/core.d | 5 + source/ecs/hash_map.d | 2 +- source/ecs/manager.d | 22 +++- 9 files changed, 436 insertions(+), 60 deletions(-) create mode 100644 demos/source/gui/template_.d diff --git a/demos/source/app.d b/demos/source/app.d index 137ac1a..ed4817a 100644 --- a/demos/source/app.d +++ b/demos/source/app.d @@ -33,6 +33,12 @@ enum Tool __gshared const (char)*[3] tool_strings = ["Entity spawner", "Component manipulator", "Selector"]; +struct Mouse +{ + vec2 position; + bool left, right, middle; +} + struct Launcher { ECSJobUpdater* job_updater; @@ -44,6 +50,7 @@ struct Launcher bool function() loop; void function() end; void function(SDL_Event*) event; + void function(vec2, Tool, int) tool; ivec2 window_size = ivec2(1024,768); Renderer renderer; ubyte[] keys; @@ -55,6 +62,9 @@ struct Launcher uint fps; Tool used_tool; + int tool_size = 0; + float tool_repeat = 0; + float repeat_time = 0; bool swap_interval = true; @@ -71,6 +81,8 @@ struct Launcher int plot_index; PlotStruct[] plot_values; + Mouse mouse; + struct PlotStruct { float delta_time = 0; @@ -78,7 +90,7 @@ struct Launcher float draw_time = 0; } - void switchDemo(void function() start, bool function() loop, void function() end, void function(SDL_Event*) event, const (char)* tips) + void switchDemo(void function() start, bool function() loop, void function() end, void function(SDL_Event*) event, void function(vec2, Tool, int) tool, const (char)* tips) { gui_manager.clear(); @@ -93,6 +105,7 @@ struct Launcher this.end = end; this.event = event; this.tips = tips; + this.tool = tool; } bool getKeyState(SDL_Scancode key) @@ -204,6 +217,46 @@ void mainLoop(void* arg) default:break; } } + else if(event.type == SDL_MOUSEBUTTONDOWN) + { + switch(event.button.button) + { + case SDL_BUTTON_LEFT:launcher.mouse.left = true;break; + case SDL_BUTTON_RIGHT:launcher.mouse.right = true;break; + case SDL_BUTTON_MIDDLE:launcher.mouse.middle = true;break; + default:break; + } + if(launcher.tool && event.button.button == SDL_BUTTON_LEFT && launcher.tool_repeat == 0 && !igIsWindowHovered(ImGuiHoveredFlags_AnyWindow)) + { + launcher.tool(vec2(event.button.x, launcher.window_size.y - event.button.y), launcher.used_tool, launcher.tool_size); + } + } + else if(event.type == SDL_MOUSEBUTTONUP) + { + switch(event.button.button) + { + case SDL_BUTTON_LEFT:launcher.mouse.left = false;break; + case SDL_BUTTON_RIGHT:launcher.mouse.right = false;break; + case SDL_BUTTON_MIDDLE:launcher.mouse.middle = false;break; + default:break; + } + } + else if(event.type == SDL_MOUSEMOTION) + { + launcher.mouse.position = vec2(event.motion.x, launcher.window_size.y - event.motion.y); + } + } + + if(launcher.tool && launcher.tool_repeat != 0 && launcher.mouse.left && !igIsWindowHovered(ImGuiHoveredFlags_AnyWindow) && !igIsWindowFocused(ImGuiFocusedFlags_AnyWindow)) + { + float range = 500.0 / cast(float)launcher.tool_repeat; + launcher.repeat_time += launcher.delta_time; + while(launcher.repeat_time > range) + { + launcher.repeat_time -= range; + launcher.tool(launcher.mouse.position, launcher.used_tool, launcher.tool_size); + } + } version(WebAssembly) @@ -236,17 +289,17 @@ void mainLoop(void* arg) if(igMenuItemBool("Simpe",null,false,true)) { import demos.simple; - launcher.switchDemo(&simpleStart,&simpleLoop,&simpleEnd,&simpleEvent,Simple.tips); + launcher.switchDemo(&simpleStart,&simpleLoop,&simpleEnd,&simpleEvent,&simpleTool,Simple.tips); } if(igMenuItemBool("Snake",null,false,true)) { import demos.snake; - launcher.switchDemo(&snakeStart,&snakeLoop,&snakeEnd,&snakeEvent,Snake.tips); + launcher.switchDemo(&snakeStart,&snakeLoop,&snakeEnd,&snakeEvent,&snakeTool,Snake.tips); } if(igMenuItemBool("Space invaders",null,false,true)) { import demos.space_invaders; - launcher.switchDemo(&spaceInvadersStart,&spaceInvadersLoop,&spaceInvadersEnd,&spaceInvadersEvent,SpaceInvaders.tips); + launcher.switchDemo(&spaceInvadersStart,&spaceInvadersLoop,&spaceInvadersEnd,&spaceInvadersEvent,&spaceInvadersTool,SpaceInvaders.tips); } igEndMenu(); } @@ -386,23 +439,44 @@ void mainLoop(void* arg) igSetNextWindowSize(ImVec2(250, 250), ImGuiCond_Once); if(igBegin("Demo",&launcher.show_demo_wnd,0)) { + ImDrawList* draw_list = igGetWindowDrawList(); + //igBeginGroup(); launcher.gui_manager.gui(); - if(igBeginCombo("Tool",tool_strings[launcher.used_tool],0)) + //igEndGroup(); + //ImDrawList_AddRect(draw_list, igGetItemRectMin(), igGetItemRectMax(), igColorConvertFloat4ToU32(ImVec4(0.4,0.4,0.4,0.4)), -1, 0, 1); + //igBeginChildFrame(1,ImVec2(0,-1),ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_ChildWindow); + //igBeginChild("Tool frame",ImVec2(-1,-1),true,0); + if(igCollapsingHeader("Tool##ToolHeader", ImGuiTreeNodeFlags_SpanAvailWidth)) { - if(igSelectable("Entity spawner",false,0,ImVec2(0,0))) + igIndent(8); + igBeginGroup(); + if(igBeginCombo("Tool",tool_strings[launcher.used_tool],0)) { - launcher.used_tool = Tool.entity_spawner; + if(igSelectable("Entity spawner",false,0,ImVec2(0,0))) + { + launcher.used_tool = Tool.entity_spawner; + } + if(igSelectable("Component manipulator",false,0,ImVec2(0,0))) + { + launcher.used_tool = Tool.component_manipulator; + } + if(igSelectable("Selector",false,0,ImVec2(0,0))) + { + launcher.used_tool = Tool.selector; + } + igEndCombo(); } - if(igSelectable("Component manipulator",false,0,ImVec2(0,0))) - { - launcher.used_tool = Tool.component_manipulator; - } - if(igSelectable("Selector",false,0,ImVec2(0,0))) - { - launcher.used_tool = Tool.selector; - } - igEndCombo(); + + igSliderInt("Tool size", &launcher.tool_size, 0, 256, null); + igSliderFloat("Tool repeat", &launcher.tool_repeat, 0, 1024, null, 4); + launcher.gui_manager.toolGui(); + igEndGroup(); + ImDrawList_AddRect(draw_list, igGetItemRectMin(), igGetItemRectMax(), igColorConvertFloat4ToU32(ImVec4(0.4,0.4,0.4,0.4)), 4, ImDrawCornerFlags_All, 1); + igUnindent(8); } + + //igEndChild(); + //igEndChildFrame(); if(igButton("Clear",ImVec2(-1,0))) { launcher.manager.begin(); @@ -629,7 +703,7 @@ int main(int argc, char** argv) { import demos.simple; - launcher.switchDemo(&simpleStart,&simpleLoop,&simpleEnd,&simpleEvent,Simple.tips); + launcher.switchDemo(&simpleStart,&simpleLoop,&simpleEnd,&simpleEvent,&simpleTool,Simple.tips); } int key_num; diff --git a/demos/source/demos/simple.d b/demos/source/demos/simple.d index 9dfa83b..36187c8 100644 --- a/demos/source/demos/simple.d +++ b/demos/source/demos/simple.d @@ -114,6 +114,8 @@ void simpleStart() tex_comp.tex = simple.texture; CLocation* loc_comp = simple.tmpl.getComponent!CLocation; + launcher.gui_manager.addTemplate(simple.tmpl, "Basic"); + foreach(i; 0..10) foreach(j; 0..10) { @@ -129,13 +131,39 @@ void simpleEnd() simple.texture.destroy(); - launcher.manager.freeTemplate(simple.tmpl); + //launcher.manager.freeTemplate(simple.tmpl); Mallocator.dispose(simple); } +void simpleTool(vec2 position, Tool tool, int size) +{ + switch(tool) + { + case Tool.entity_spawner: + { + EntityTemplate* tmpl = launcher.gui_manager.getSelectedTemplate(); + CLocation* location = tmpl.getComponent!CLocation; + if(location) + { + position.x += (randomf - 0.5) * size; + position.y += (randomf - 0.5) * size; + *location = position; + } + launcher.manager.addEntity(tmpl); + } + break; + default: + break; + } +} + void simpleEvent(SDL_Event* event) { - + /*if(event.type == event.button) + { + vec2 position = vec2(event.button.x, event.button.y); + + }*/ } void spawnEntity() @@ -149,7 +177,7 @@ bool simpleLoop() { if(launcher.getKeyState(SDL_SCANCODE_SPACE)) { - foreach(i;0..10000)spawnEntity(); + foreach(i;0..1)spawnEntity(); } diff --git a/demos/source/demos/snake.d b/demos/source/demos/snake.d index 9df3fcc..2195aaa 100644 --- a/demos/source/demos/snake.d +++ b/demos/source/demos/snake.d @@ -51,29 +51,36 @@ struct Snake MapElement element(ivec2 pos) { - return map[pos.x + pos.y * map_size]; + uint index = pos.x + pos.y * map_size; + if(index >= map.length)index = map.length - 1; + return map[index]; } void element(MapElement el, ivec2 pos) { - map[pos.x + pos.y * map_size] = el; + uint index = pos.x + pos.y * map_size; + if(index >= map.length)index = map.length - 1; + map[index] = el; } void addApple() { ivec2 random_pos = ivec2(rand()%map_size,rand()%map_size); + ivec2 base_pos = random_pos; while(element(random_pos).type != MapElement.Type.empty) { random_pos.x += 1; if(random_pos.x > map_size) { - random_pos.y = 0; + random_pos.x = 0; random_pos.y += 1; if(random_pos.y > map_size)random_pos.y = 0; } + if(base_pos.x == random_pos.x && base_pos.y == random_pos.y)return; } + CILocation* location = apple_tmpl.getComponent!CILocation; + *location = random_pos; Entity* apple = launcher.manager.addEntity(apple_tmpl); - element(MapElement(MapElement.Type.apple,apple.id),random_pos); } void drawMap() @@ -199,6 +206,27 @@ struct CInput mixin ECS.Component; } +struct AppleSystem +{ + mixin ECS.System!1; + + struct EntitiesData + { + uint length; + @readonly Entity[] entities; + @readonly CApple[] movement; + @readonly CILocation[] location; + } + + void onAddEntity(EntitiesData data) + { + foreach(i;0..data.length) + { + snake.element(MapElement(MapElement.Type.apple,data.entities[i].id),data.location[i]); + } + } +} + struct MoveSystem { mixin ECS.System!64; @@ -270,6 +298,7 @@ struct MoveSystem snake.element(MapElement(MapElement.Type.snake, data.entities[i].id),data.location[i].location); break; case MapElement.Type.apple: + launcher.manager.removeEntity(snake.element(data.location[i].location).id); data.snakes[i].parts.add(new_location); snake.element(MapElement(MapElement.Type.snake, data.entities[i].id),new_location); snake.element(MapElement(MapElement.Type.snake, data.entities[i].id),data.location[i].location); @@ -439,6 +468,7 @@ void snakeStart() launcher.manager.registerSystem!MoveSystem(0,"fixed"); launcher.manager.registerSystem!InputSystem(-100); launcher.manager.registerSystem!FixSnakeDirectionSystem(-1,"fixed"); + launcher.manager.registerSystem!AppleSystem(-1,"fixed"); launcher.manager.endRegister(); @@ -460,6 +490,9 @@ void snakeStart() snake.addApple(); } + launcher.gui_manager.addTemplate(snake.snake_tmpl, "Snake"); + launcher.gui_manager.addTemplate(snake.apple_tmpl, "Apple"); + /*foreach(i; 0..10) foreach(j; 0..10) { @@ -478,6 +511,39 @@ void snakeEnd() Mallocator.dispose(snake); } +void snakeTool(vec2 position, Tool tool, int size) +{ + switch(tool) + { + case Tool.entity_spawner: + { + EntityTemplate* tmpl = launcher.gui_manager.getSelectedTemplate(); + CLocation* location = tmpl.getComponent!CLocation; + if(location) + { + position.x += (randomf - 0.5) * size; + position.y += (randomf - 0.5) * size; + *location = position; + } + CILocation* ilocation = tmpl.getComponent!CILocation; + if(ilocation) + { + position.x += (randomf - 0.5) * size; + position.y += (randomf - 0.5) * size; + ivec2 ipos; + ipos.x = cast(int)(position.x / 32); + ipos.y = cast(int)(position.y / 32); + *ilocation = ipos; + if(snake.element(ipos).type != MapElement.Type.empty)return; + } + launcher.manager.addEntity(tmpl); + } + break; + default: + break; + } +} + void snakeEvent(SDL_Event* event) { diff --git a/demos/source/demos/space_invaders.d b/demos/source/demos/space_invaders.d index 3ef90c4..2ded925 100644 --- a/demos/source/demos/space_invaders.d +++ b/demos/source/demos/space_invaders.d @@ -306,17 +306,19 @@ struct LaserShootingSystem struct ChangeDirectionSystem { - mixin ECS.System; + mixin ECS.System!32; Direction[8] groups_directions; + bool has_changes; struct EntitiesData { uint length; const (Entity)[] entities; + const (CLocation)[] locations; CVelocity[] velocity; - @optional const(CSideMove)[] side_move; + const(CSideMove)[] side_move; } void onCreate() @@ -327,49 +329,113 @@ struct ChangeDirectionSystem } } - bool onBegin() + /*bool onBegin() { foreach(direction; groups_directions) { - if(direction != cast(Direction)-1)return true; + if(direction != cast(Direction)-1)//return true; + { + has_changes = true; + break; + } } - return false; - } + return true; + }*/ void onEnd() { + if(has_changes) + { + foreach(ref direction; groups_directions) + { + direction = cast(Direction)-1; + } + } + has_changes = false; foreach(ref direction; groups_directions) { - direction = cast(Direction)-1; + if(direction != cast(Direction)-1) + { + has_changes = true; + //direction = cast(Direction)-1; + } } + /*foreach(ref direction; groups_directions) + { + direction = cast(Direction)-1; + }*/ } void onUpdate(EntitiesData data) { - if(!data.side_move)return; + //if(!data.side_move)return; + if(has_changes) foreach(i;0..data.length) { byte group = data.side_move[i].group; - if(group == -1)continue; - Direction direction = groups_directions[group]; - if(direction != cast(Direction)-1) + if(group == -1) { - CVelocity* velocity = &data.velocity[i]; - final switch(direction) + if(data.locations[i].x < 0) { - case Direction.up: - if(velocity.value.y > 0)velocity.value.y = -velocity.value.y; - break; - case Direction.down: - if(velocity.value.y < 0)velocity.value.y = -velocity.value.y; - break; - case Direction.left: - if(velocity.value.x > 0)velocity.value.x = -velocity.value.x; - break; - case Direction.right: - if(velocity.value.x < 0)velocity.value.x = -velocity.value.x; - break; + if(data.velocity[i].x < 0)data.velocity[i].x = -data.velocity[i].x; } + else if(data.locations[i].x > space_invaders.map_size.x) + { + if(data.velocity[i].x > 0)data.velocity[i].x = -data.velocity[i].x; + } + } + else + { + Direction direction = groups_directions[group]; + if(direction != cast(Direction)-1) + { + CVelocity* velocity = &data.velocity[i]; + final switch(direction) + { + case Direction.up: + if(velocity.value.y > 0)velocity.value.y = -velocity.value.y; + break; + case Direction.down: + if(velocity.value.y < 0)velocity.value.y = -velocity.value.y; + break; + case Direction.left: + if(velocity.value.x > 0)velocity.value.x = -velocity.value.x; + break; + case Direction.right: + if(velocity.value.x < 0)velocity.value.x = -velocity.value.x; + break; + } + } + } + } + else + { + foreach(i;0..data.length) + { + if(data.locations[i].x < 0) + { + if(data.side_move[i].group == -1) + { + if(data.velocity[i].x < 0)data.velocity[i].x = -data.velocity[i].x; + } + else + { + groups_directions[data.side_move[i].group] = Direction.right; + } + } + else if(data.locations[i].x > space_invaders.map_size.x) + { + if(data.side_move[i].group == -1) + { + if(data.velocity[i].x > 0)data.velocity[i].x = -data.velocity[i].x; + } + else + { + groups_directions[data.side_move[i].group] = Direction.left; + } + } + //if(data.locations[i].y < 0) data.locations[i].y = 0; + //else if(data.locations[i].y > space_invaders.map_size.y)data.locations[i].y = space_invaders.map_size.y; } } } @@ -405,6 +471,7 @@ struct ChangeDirectionSystem struct ClampPositionSystem { mixin ECS.System!32; + mixin ECS.ExcludedComponents!(CSideMove); struct EntitiesData { @@ -414,9 +481,12 @@ struct ClampPositionSystem CLocation[] locations; @optional const (CLaser)[] laser; - @optional const (CSideMove)[] side_move; + //@optional CVelocity[] velocity; + //@optional const (CSideMove)[] side_move; } + //ChangeDirectionSystem change_direction_system; + void onUpdate(EntitiesData data) { if(data.laser) @@ -427,24 +497,40 @@ struct ClampPositionSystem data.locations[i].y < 0 || data.locations[i].y > space_invaders.map_size.y)launcher.manager.removeEntity(data.entities[i].id); } } - else if(data.side_move) + /*else if(data.side_move) { foreach(i;0..data.length) { if(data.locations[i].x < 0) { //data.locations[i].x = 0; - launcher.manager.sendEvent(data.entities[i].id,EChangeDirection(Direction.right)); + //launcher.manager.sendEvent(data.entities[i].id,EChangeDirection(Direction.right)); + if(data.side_move[i].group == -1) + { + if(data.velocity[i].x < 0)data.velocity[i].x = -data.velocity[i].x; + } + else + { + change_direction_system.groups_directions[data.side_move[i].group] = Direction.left; + } } else if(data.locations[i].x > space_invaders.map_size.x) { //data.locations[i].x = space_invaders.map_size.x; - launcher.manager.sendEvent(data.entities[i].id,EChangeDirection(Direction.left)); + //launcher.manager.sendEvent(data.entities[i].id,EChangeDirection(Direction.left)); + if(data.side_move[i].group == -1) + { + if(data.velocity[i].x > 0)data.velocity[i].x = -data.velocity[i].x; + } + else + { + change_direction_system.groups_directions[data.side_move[i].group] = Direction.right; + } } if(data.locations[i].y < 0) data.locations[i].y = 0; else if(data.locations[i].y > space_invaders.map_size.y)data.locations[i].y = space_invaders.map_size.y; } - } + }*/ else { foreach(i;0..data.length) @@ -628,6 +714,11 @@ void spaceInvadersStart() vel_comp.value = vec2(0,1); } + EntityTemplate* enemy_tmpl; + EntityTemplate* grouped_tmpl; + EntityID enemy_id; + EntityID grouped_id; + { ushort[8] components = [CVelocity.component_id, CAutoShoot.component_id, CLocation.component_id, CTexture.component_id, CScale.component_id, CLaserWeapon.component_id, CEnemy.component_id, CShootDirection.component_id];//, CVelocity.component_id]; space_invaders.enemy_tmpl = launcher.manager.allocateTemplate(components); @@ -649,6 +740,9 @@ void spaceInvadersStart() loc_comp.value = vec2(128,space_invaders.map_size.y - 64); current_entity = launcher.manager.addEntity(space_invaders.enemy_tmpl); launcher.manager.addComponents(current_entity.id,CSideMove(-1)); + + enemy_id = current_entity.id; + //enemy_tmpl = launcher.manager.allocateTemplate(current_entity.id); loc_comp.value = vec2(256,space_invaders.map_size.y - 64); launcher.manager.addEntity(space_invaders.enemy_tmpl); @@ -656,7 +750,19 @@ void spaceInvadersStart() loc_comp.value = vec2(0,space_invaders.map_size.y - 64); current_entity = launcher.manager.addEntity(space_invaders.enemy_tmpl); launcher.manager.addComponents(current_entity.id,CSideMove(0)); + + grouped_id = current_entity.id; + //grouped_tmpl = launcher.manager.allocateTemplate(current_entity.id); } + launcher.manager.commit(); + + enemy_tmpl = launcher.manager.allocateTemplate(enemy_id); + grouped_tmpl = launcher.manager.allocateTemplate(grouped_id); + + launcher.gui_manager.addTemplate(space_invaders.ship_tmpl,"Ship"); + launcher.gui_manager.addTemplate(enemy_tmpl,"Enemy"); + launcher.gui_manager.addTemplate(grouped_tmpl,"Grouped enemy"); + launcher.gui_manager.addTemplate(space_invaders.laser_tmpl,"Laser"); } @@ -671,10 +777,32 @@ void spaceInvadersEnd() space_invaders.ship_tex.destroy(); - launcher.manager.freeTemplate(space_invaders.ship_tmpl); + launcher.manager.freeTemplate(space_invaders.enemy_tmpl); Mallocator.dispose(space_invaders); } +void spaceInvadersTool(vec2 position, Tool tool, int size) +{ + switch(tool) + { + case Tool.entity_spawner: + { + EntityTemplate* tmpl = launcher.gui_manager.getSelectedTemplate(); + CLocation* location = tmpl.getComponent!CLocation; + if(location) + { + position.x += (randomf - 0.5) * size; + position.y += (randomf - 0.5) * size; + *location = position; + } + launcher.manager.addEntity(tmpl); + } + break; + default: + break; + } +} + void spaceInvadersEvent(SDL_Event* event) { diff --git a/demos/source/gui/manager.d b/demos/source/gui/manager.d index 10727eb..8a46a92 100644 --- a/demos/source/gui/manager.d +++ b/demos/source/gui/manager.d @@ -7,18 +7,35 @@ import cimgui.cimgui; import ecs.std; import ecs.system; import ecs.vector; +import ecs.entity; import gui.system; +import gui.template_; extern(C): struct GUIManager { Vector!SystemGUI systems; + Vector!TemplateGUI templates; + uint selected_tempalte = 0; + void clear() { + foreach(tmpl; templates) + { + launcher.manager.freeTemplate(tmpl.tmpl); + } + systems.clear(); + templates.clear(); + } + + EntityTemplate* getSelectedTemplate() + { + if(templates.length > selected_tempalte)return templates[selected_tempalte].tmpl; + else return null; } void addSystem(ushort id, const (char)* name, bool enabled = true) @@ -28,9 +45,19 @@ struct GUIManager systems.add(SystemGUI(name,system,enabled)); } + void addTemplate(ushort[] components, const (char)* name) + { + templates.add(TemplateGUI(name, launcher.manager.allocateTemplate(components))); + } + + void addTemplate(EntityTemplate* tmpl, const (char)* name) + { + templates.add(TemplateGUI(name, tmpl)); + } + void gui() { - if(igCollapsingHeader("Systems", ImGuiTreeNodeFlags_Framed)) + if(igCollapsingHeader("Systems", ImGuiTreeNodeFlags_Framed | ImGuiTreeNodeFlags_SpanFullWidth | ImGuiTreeNodeFlags_FramePadding)) { bool true_ = true; igIndent(8); @@ -44,6 +71,27 @@ struct GUIManager } igUnindent(8); } - + } + + void toolGui() + { + if(templates.length) + { + if(igBeginCombo("Template",templates[selected_tempalte].name,0)) + { + foreach(i, tmpl; templates) + { + if(igSelectable(tmpl.name,false,0,ImVec2(0,0))) + { + selected_tempalte = cast(uint)i; + } + } + igEndCombo(); + } + } + else + { + if(igBeginCombo("Template",null,0))igEndCombo(); + } } } \ No newline at end of file diff --git a/demos/source/gui/template_.d b/demos/source/gui/template_.d new file mode 100644 index 0000000..2aa1833 --- /dev/null +++ b/demos/source/gui/template_.d @@ -0,0 +1,9 @@ +module gui.template_; + +import ecs.entity; + +struct TemplateGUI +{ + const (char)* name; + EntityTemplate* tmpl; +} \ No newline at end of file diff --git a/source/ecs/core.d b/source/ecs/core.d index 431f57b..956c324 100644 --- a/source/ecs/core.d +++ b/source/ecs/core.d @@ -21,4 +21,9 @@ static struct ECS __gshared ushort event_id; EntityID entity_id; } + + mixin template ExcludedComponents(T...) + { + alias ExcludedComponents = T; + } } \ No newline at end of file diff --git a/source/ecs/hash_map.d b/source/ecs/hash_map.d index f6d1642..5a8b253 100755 --- a/source/ecs/hash_map.d +++ b/source/ecs/hash_map.d @@ -211,7 +211,7 @@ struct HashMap(KeyPar, ValuePar, alias hashFunc = defaultHashFunc) { return cast(float) forElementsNum / (elements.length); } - export void rehash() { + export void rehash()() { mixin(doNotInline); // Get all elements Vector!KeyVal allElements; diff --git a/source/ecs/manager.d b/source/ecs/manager.d index b80e0e7..62847a5 100644 --- a/source/ecs/manager.d +++ b/source/ecs/manager.d @@ -223,6 +223,24 @@ export struct EntityManager } } + extern (C) static int comapreEventCaller(const void* a, const void* b) nothrow @nogc + { + EventCaller _a = *cast(EventCaller*) a; + EventCaller _b = *cast(EventCaller*) b; + if (_a.system.priority < _b.system.priority) + return -1; + else if (_a.system.priority == _b.system.priority) + return 0; + else + return 1; + } + + foreach(ref event; events) + { + qsort(event.callers.ptr, event.callers.length, EventCaller.sizeof, &comapreEventCaller); + } + //qsort(event_callers.ptr, event_callers.length, EventInfo.sizeof, &compareUShorts); + foreach(EntityInfo* info;&entities_infos.byValue) { generateListeners(info); @@ -569,11 +587,11 @@ export struct EntityManager //components_info.excluded ~= CompInfo(str,str); } } - else static if (checkExcludedComponentsSomething!Sys) + else //static if (checkExcludedComponentsSomething!Sys) { foreach (str; Sys.ExcludedComponents) { - components_info.addExcluded(CompInfo(str,str)); + components_info.addExcluded(CompInfo(str.stringof,str.stringof)); //components_info.excluded ~= CompInfo(str,str); } From 87e9a31d7f375cfa79b85e3d327ded9600a01c00 Mon Sep 17 00:00:00 2001 From: Mergul Date: Sun, 9 Feb 2020 21:51:54 +0100 Subject: [PATCH 086/217] -PageSize and PagesInBlock values can be adjust in runtime (at initialization time) -added support for calling custon delegate function for all entities supported by selected system --- source/ecs/manager.d | 477 ++++++++++++++++++++++++++++--------------- source/ecs/system.d | 7 +- tests/tests.d | 22 +- 3 files changed, 335 insertions(+), 171 deletions(-) diff --git a/source/ecs/manager.d b/source/ecs/manager.d index 62847a5..7c89b71 100644 --- a/source/ecs/manager.d +++ b/source/ecs/manager.d @@ -11,7 +11,7 @@ import std.traits; //import core.stdc.stdlib : qsort; //import core.stdc.string; -import ecs.system;//not ordered as forward reference bug workaround +import ecs.system; //not ordered as forward reference bug workaround import ecs.block_allocator; import ecs.entity; import ecs.events; @@ -33,17 +33,21 @@ alias SerializeVector = ecs.vector.Vector!ubyte; */ export struct EntityManager { - export static void initialize(uint threads_count) + /************************************************************************************************************************ + *Initialize ECS. + */ + export static void initialize(uint threads_count, uint page_size = 32768, + uint block_pages_count = 128) { if (instance is null) { //instance = Mallocator.make!EntityManager(threads_count); - instance = Mallocator.make!EntityManager(threads_count); - - with(instance) + instance = Mallocator.make!EntityManager(threads_count, page_size, block_pages_count); + + with (instance) { UpdatePass* pass = Mallocator.make!UpdatePass; - pass.name = Mallocator.makeArray(cast(char[])"update"); + pass.name = Mallocator.makeArray(cast(char[]) "update"); //pass.name = Mallocator.makeArray!char("update".length); //pass.name[0..$] = "update"; passes.add(pass); @@ -52,12 +56,15 @@ export struct EntityManager } } + /************************************************************************************************************************ + *Deinitialize and destroy ECS. This function release whole memory. + */ export static void destroy() { if (instance is null) return; - with(instance) + with (instance) { foreach (ref system; systems) { @@ -65,44 +72,56 @@ export struct EntityManager if (system.m_destroy) (cast(void function(void*)) system.m_destroy)(system.m_system_pointer); - if(system.jobs)Mallocator.dispose(system.jobs); - if(system.m_read_only_components)Mallocator.dispose(system.m_read_only_components); - if(system.m_modified_components)Mallocator.dispose(system.m_modified_components); - if(system.m_components)Mallocator.dispose(system.m_components); - if(system.m_excluded_components)Mallocator.dispose(system.m_excluded_components); - if(system.m_optional_components)Mallocator.dispose(system.m_optional_components); - if(system.m_name)Mallocator.dispose(system.m_name); - if(system.m_event_callers)Mallocator.dispose(system.m_event_callers); - - if(system.m_system_pointer)Mallocator.dispose(system.m_system_pointer); + if (system.jobs) + Mallocator.dispose(system.jobs); + if (system.m_read_only_components) + Mallocator.dispose(system.m_read_only_components); + if (system.m_modified_components) + Mallocator.dispose(system.m_modified_components); + if (system.m_components) + Mallocator.dispose(system.m_components); + if (system.m_excluded_components) + Mallocator.dispose(system.m_excluded_components); + if (system.m_optional_components) + Mallocator.dispose(system.m_optional_components); + if (system.m_name) + Mallocator.dispose(system.m_name); + if (system.m_event_callers) + Mallocator.dispose(system.m_event_callers); + + if (system.m_system_pointer) + Mallocator.dispose(system.m_system_pointer); } - foreach(EntityInfo* info;&entities_infos.byValue) + foreach (EntityInfo* info; &entities_infos.byValue) { //if(info.components)Mallocator.dispose(info.components); Mallocator.dispose(info); - }//*/ + } //*/ - foreach(UpdatePass* pass; passes) + foreach (UpdatePass* pass; passes) { Mallocator.dispose(pass); } passes.clear(); - foreach(ComponentInfo info; components) + foreach (ComponentInfo info; components) { - if(info.init_data)Mallocator.dispose(info.init_data); + if (info.init_data) + Mallocator.dispose(info.init_data); } - foreach(EventInfo info; events) + foreach (EventInfo info; events) { - if(info.callers)Mallocator.dispose(info.callers); + if (info.callers) + Mallocator.dispose(info.callers); } - foreach(name; &components_map.byKey) + foreach (name; &components_map.byKey) { - if(name)Mallocator.dispose(name); + if (name) + Mallocator.dispose(name); } } @@ -165,6 +184,7 @@ export struct EntityManager SystemCaller* sys_caller = Mallocator.make!SystemCaller; sys_caller.system_id = system.id; sys_caller.job_group.caller = sys_caller; + system.m_any_system_caller = sys_caller; passes[system.m_pass].system_callers.add(sys_caller, i); added = true; break; @@ -175,6 +195,7 @@ export struct EntityManager SystemCaller* sys_caller = Mallocator.make!SystemCaller; sys_caller.system_id = system.id; sys_caller.job_group.caller = sys_caller; + system.m_any_system_caller = sys_caller; passes[system.m_pass].system_callers.add(sys_caller); } @@ -235,13 +256,14 @@ export struct EntityManager return 1; } - foreach(ref event; events) + foreach (ref event; events) { - qsort(event.callers.ptr, event.callers.length, EventCaller.sizeof, &comapreEventCaller); + qsort(event.callers.ptr, event.callers.length, + EventCaller.sizeof, &comapreEventCaller); } //qsort(event_callers.ptr, event_callers.length, EventInfo.sizeof, &compareUShorts); - foreach(EntityInfo* info;&entities_infos.byValue) + foreach (EntityInfo* info; &entities_infos.byValue) { generateListeners(info); } @@ -252,17 +274,20 @@ export struct EntityManager /************************************************************************************************************************ *Default constructor. */ - export this(uint threads_count) nothrow @nogc + export this(uint threads_count, uint page_size, uint block_pages_count) nothrow @nogc { if (threads_count == 0) threads_count = 1; threads = Mallocator.makeArray!ThreadData(threads_count); //foreach(ref thread;threads)thread = ThreadData().init; + m_page_size = page_size; + m_pages_in_block = block_pages_count; + id_manager.initialize(); event_manager.initialize(&this); - allocator = BlockAllocator(page_size, pages_in_block); + allocator = BlockAllocator(m_page_size, m_pages_in_block); //add_mutex = Mallocator.make!Mutex; entity_block_alloc_mutex = Mallocator.make!Mutex; @@ -276,8 +301,9 @@ export struct EntityManager id_manager.deinitialize(); event_manager.destroy(); - if(threads)Mallocator.dispose(threads); - if(entity_block_alloc_mutex) + if (threads) + Mallocator.dispose(threads); + if (entity_block_alloc_mutex) { entity_block_alloc_mutex.destroy(); Mallocator.dispose(entity_block_alloc_mutex); @@ -293,7 +319,7 @@ export struct EntityManager void registerSystem(Sys)(int priority, const(char)[] pass_name) { ushort pass = passes_map.get(pass_name, ushort.max); - assert(pass != ushort.max);//, "Update pass (Name " ~ pass_name ~ ") doesn't exist."); + assert(pass != ushort.max); //, "Update pass (Name " ~ pass_name ~ ") doesn't exist."); registerSystem!(Sys)(priority, pass); } @@ -312,19 +338,19 @@ export struct EntityManager assert(register_state, "registerSystem must be called between beginRegister() and endRegister()."); - assert(pass < passes.length);//, "Update pass (ID " ~ pass.to!string ~ ") doesn't exist."); + assert(pass < passes.length); //, "Update pass (ID " ~ pass.to!string ~ ") doesn't exist."); System system; system.m_pass = pass; static if (!(hasMember!(Sys, "system_id")) || !is(typeof(Sys.system_id) == ushort)) { - static assert(0);//, "Add \"mixin ECS.System;\" in top of system structure;"); //"System should have \"__gshared ushort system_id"); + static assert(0); //, "Add \"mixin ECS.System;\" in top of system structure;"); //"System should have \"__gshared ushort system_id"); } static if (!(hasMember!(Sys, "EntitiesData"))) { - static assert(0);//, "System should gave \"EntitiesData\" struct for input components"); + static assert(0); //, "System should gave \"EntitiesData\" struct for input components"); } static if (hasMember!(Sys, "handleEvent")) @@ -378,28 +404,28 @@ export struct EntityManager void setEventCallers(Sys)(ref System system) { enum event_handlers_num = __traits(getOverloads, Sys, "handleEvent").length; - System.EventCaller[] callers = (cast(System.EventCaller*)alloca(event_handlers_num * System.EventCaller.sizeof))[0..event_handlers_num]; + System.EventCaller[] callers = (cast(System.EventCaller*) alloca( + event_handlers_num * System.EventCaller.sizeof))[0 .. event_handlers_num]; int i = 0; foreach (j, func; __traits(getOverloads, Sys, "handleEvent")) { - alias Params = Parameters!(__traits(getOverloads, - Sys, "handleEvent")[j]); - static if(Params.length == 2 && is(Params[0] == Entity*)) + alias Params = Parameters!(__traits(getOverloads, Sys, "handleEvent")[j]); + static if (Params.length == 2 && is(Params[0] == Entity*)) { alias EventParamType = Params[1]; enum EventName = Unqual!(EventParamType).stringof; ushort evt = events_map.get(cast(char[]) EventName, ushort.max); - assert(evt != ushort.max, "Can't register system \""~Sys.stringof~"\" due to non existing event \""~EventName~"\"."); - - callers[i].callback = cast( - void*)&callEventHandler!(EventParamType); + assert(evt != ushort.max, "Can't register system \"" ~ Sys.stringof + ~ "\" due to non existing event \"" ~ EventName ~ "\"."); + + callers[i].callback = cast(void*)&callEventHandler!(EventParamType); callers[i].id = EventParamType.event_id; i++; } } - system.m_event_callers = Mallocator.makeArray(callers[0..i]); + system.m_event_callers = Mallocator.makeArray(callers[0 .. i]); } static if (__traits(hasMember, Sys, "handleEvent")) @@ -416,7 +442,7 @@ export struct EntityManager static struct ComponentsIndices { - + CompInfo[] readonly() { return m_readonly[0 .. m_readonly_counter]; @@ -516,9 +542,11 @@ export struct EntityManager foreach (member; __traits(allMembers, Sys.EntitiesData)) { alias MemberType = typeof(__traits(getMember, Sys.EntitiesData, member)); - if (member == "length" || is(MemberType == Entity[]) || is(MemberType == const(Entity)[])) + if (member == "length" || is(MemberType == Entity[]) + || is(MemberType == const(Entity)[])) { - if(is(MemberType == Entity[]) || is(MemberType == const(Entity)[]))components_info.entites_array = member; + if (is(MemberType == Entity[]) || is(MemberType == const(Entity)[])) + components_info.entites_array = member; continue; } @@ -536,7 +564,8 @@ export struct EntityManager is_read_only = true; } - foreach (att; __traits(getAttributes, __traits(getMember, Sys.EntitiesData, member))) + foreach (att; __traits(getAttributes, __traits(getMember, + Sys.EntitiesData, member))) { if (att == "optional") { @@ -549,22 +578,22 @@ export struct EntityManager } if (is_read_only) { - components_info.addReadonly(CompInfo(member,name)); + components_info.addReadonly(CompInfo(member, name)); //components_info.readonly ~= CompInfo(member,name); } else { - components_info.addMutable(CompInfo(member,name)); + components_info.addMutable(CompInfo(member, name)); //components_info.mutable ~= CompInfo(member,name); } if (is_optional) { - components_info.addOptional(CompInfo(member,name)); + components_info.addOptional(CompInfo(member, name)); //components_info.optional ~= CompInfo(member,name); } else { - components_info.addReq(CompInfo(member,name)); + components_info.addReq(CompInfo(member, name)); //components_info.req ~= CompInfo(member,name); } /*if (is_read_only) @@ -583,16 +612,16 @@ export struct EntityManager { foreach (str; __traits(allMembers, Sys.ExcludedComponents)) { - components_info.addExcluded(CompInfo(str,str)); - //components_info.excluded ~= CompInfo(str,str); + components_info.addExcluded(CompInfo(str, str)); + //components_info.excluded ~= CompInfo(str,str); } } else //static if (checkExcludedComponentsSomething!Sys) { foreach (str; Sys.ExcludedComponents) { - components_info.addExcluded(CompInfo(str.stringof,str.stringof)); - //components_info.excluded ~= CompInfo(str,str); + components_info.addExcluded(CompInfo(str.stringof, str.stringof)); + //components_info.excluded ~= CompInfo(str,str); } } @@ -608,14 +637,16 @@ export struct EntityManager foreach (member; __traits(allMembers, Sys.EntitiesData)) { - alias MemberType=typeof(__traits(getMember, Sys.EntitiesData, member)); + alias MemberType = typeof(__traits(getMember, Sys.EntitiesData, member)); static if (isFunction!(__traits(getMember, Sys.EntitiesData, member))) static assert(0, "EntitiesData can't have any function!"); else static if (member == "length") { - static assert(isIntegral!(MemberType), "EntitiesData 'length' member must be integral type."); - static assert(MemberType.sizeof > 1, "EntitiesData 'length' member can't be byte or ubyte."); + static assert(isIntegral!(MemberType), + "EntitiesData 'length' member must be integral type."); + static assert(MemberType.sizeof > 1, + "EntitiesData 'length' member can't be byte or ubyte."); } else static if (!(isArray!(MemberType))) static assert(0, "EntitiesData members should be arrays of elements!"); @@ -627,31 +658,31 @@ export struct EntityManager foreach (iii, comp_info; components_info.req) { ushort comp = components_map.get(cast(char[]) comp_info.type, ushort.max); - assert(comp != ushort.max);//, "Can't register system \""~Sys.stringof~"\" due to non existing component \""~comp_info.type~"\"."); + assert(comp != ushort.max); //, "Can't register system \""~Sys.stringof~"\" due to non existing component \""~comp_info.type~"\"."); system.m_components[iii] = comp; } foreach (iii, comp_info; components_info.excluded) { ushort comp = components_map.get(cast(char[]) comp_info.type, ushort.max); - assert(comp != ushort.max);//, "Can't register system \""~Sys.stringof~"\" due to non existing component \""~comp_info.type~"\"."); + assert(comp != ushort.max); //, "Can't register system \""~Sys.stringof~"\" due to non existing component \""~comp_info.type~"\"."); system.m_excluded_components[iii] = comp; } foreach (iii, comp_info; components_info.optional) { ushort comp = components_map.get(cast(char[]) comp_info.type, ushort.max); - assert(comp != ushort.max);//, "Can't register system \""~Sys.stringof~"\" due to non existing component \""~comp_info.type~"\"."); + assert(comp != ushort.max); //, "Can't register system \""~Sys.stringof~"\" due to non existing component \""~comp_info.type~"\"."); system.m_optional_components[iii] = comp; } foreach (iii, comp_info; components_info.readonly) { ushort comp = components_map.get(cast(char[]) comp_info.type, ushort.max); - assert(comp != ushort.max);//, "Can't register system \""~Sys.stringof~"\" due to non existing component \""~comp_info.type~"\"."); + assert(comp != ushort.max); //, "Can't register system \""~Sys.stringof~"\" due to non existing component \""~comp_info.type~"\"."); system.m_read_only_components[iii] = comp; } foreach (iii, comp_info; components_info.mutable) { ushort comp = components_map.get(cast(char[]) comp_info.type, ushort.max); - assert(comp != ushort.max);//, "Can't register system \""~Sys.stringof~"\" due to non existing component \""~comp_info.type~"\"."); + assert(comp != ushort.max); //, "Can't register system \""~Sys.stringof~"\" due to non existing component \""~comp_info.type~"\"."); system.m_modified_components[iii] = comp; } @@ -662,36 +693,40 @@ export struct EntityManager { //enum ComponentsIndices components_info = getComponentsInfo(); - static if(components_info.entites_array) + static if (components_info.entites_array) { - __traits(getMember, input_data, components_info.entites_array) = (cast(Entity*) block.dataBegin())[offset .. entities_count]; + __traits(getMember, input_data, components_info.entites_array) = ( + cast(Entity*) block.dataBegin())[offset .. entities_count]; } - static if(hasMember!(Sys.EntitiesData,"length")) + static if (hasMember!(Sys.EntitiesData, "length")) { input_data.length = cast(typeof(input_data.length))(entities_count - offset); } static foreach (iii, comp_info; components_info.req) { - __traits(getMember, input_data, comp_info.name) = - (cast(ForeachType!(typeof(__traits(getMember, - Sys.EntitiesData, comp_info.name)))*)(cast(void*) block + info.deltas[ system.m_components[iii]]))[offset .. entities_count]; + __traits(getMember, input_data, comp_info.name) = (cast(ForeachType!(typeof(__traits(getMember, + Sys.EntitiesData, comp_info.name)))*)( + cast(void*) block + info.deltas[system.m_components[iii]]))[offset + .. entities_count]; } static foreach (iii, comp_info; components_info.optional) { - if(system.m_optional_components[iii] < info.deltas.length && info.deltas[system.m_optional_components[iii]] != 0) + if (system.m_optional_components[iii] < info.deltas.length + && info.deltas[system.m_optional_components[iii]] != 0) { - __traits(getMember, input_data, comp_info.name) = - (cast(ForeachType!(typeof(__traits(getMember, - Sys.EntitiesData, comp_info.name)))*)(cast(void*) block + info.deltas[ system.m_optional_components[iii]]))[offset .. entities_count]; - + __traits(getMember, input_data, comp_info.name) = (cast(ForeachType!(typeof(__traits(getMember, + Sys.EntitiesData, comp_info.name)))*)(cast( + void*) block + info.deltas[system.m_optional_components[iii]]))[offset + .. entities_count]; + } } } - - bool checkOnUpdateParams()() + + /*bool checkOnUpdateParams()() { bool ret = false; foreach (func; __traits(getOverloads, Sys, "onUpdate")) @@ -703,9 +738,29 @@ export struct EntityManager } } return ret; + }*/ + + int getOnUpdateOverload()() + { + int ret = -1; + foreach (i, func; __traits(getOverloads, Sys, "onUpdate")) + { + if ((Parameters!(func)).length == 1 && is(Parameters!(func)[0] == Sys.EntitiesData)) + { + ret = i; + break; + } + } + return ret; } - static if (hasMember!(Sys, "onUpdate") && checkOnUpdateParams()) + static if (hasMember!(Sys, "onUpdate")) + enum OnUpdateOverloadNum = getOnUpdateOverload(); + else + enum OnUpdateOverloadNum = -1; + //enum HasOnUpdate = (hasMember!(Sys, "onUpdate") && checkOnUpdateParams()); + + static if (OnUpdateOverloadNum != -1) { static void callUpdate(ref CallData data) { @@ -744,8 +799,10 @@ export struct EntityManager assert(entities_count <= block.entities_count && offset <= block.entities_count); fillInputData(input_data, info, block, offset, entities_count, system); - - s.onUpdate(input_data); + + //s.onUpdate(input_data); + (cast(typeof(&__traits(getOverloads, s, + "onUpdate")[OnUpdateOverloadNum])) data.update_delegate)(input_data); block = block.next_block; offset = 0; @@ -758,7 +815,7 @@ export struct EntityManager static void catchFunction(string func_name, RetType = void)(void** member) { - static if(hasMember!(Sys,func_name)) + static if (hasMember!(Sys, func_name)) { foreach (func; __traits(getOverloads, Sys, func_name)) { @@ -767,9 +824,12 @@ export struct EntityManager static RetType callFunc(void* system_pointer) { Sys* s = cast(Sys*) system_pointer; - static if(is(RetTyp == void))mixin("s."~func_name~"()"); - else return mixin("s."~func_name~"()"); + static if (is(RetTyp == void)) + mixin("s." ~ func_name ~ "()"); + else + return mixin("s." ~ func_name ~ "()"); } + *member = cast(void*)&callFunc; break; } @@ -779,20 +839,26 @@ export struct EntityManager static void catchEntityFunction(string func_name, RetType = void)(void** member) { - static if(hasMember!(Sys,func_name)) + static if (hasMember!(Sys, func_name)) { foreach (func; __traits(getOverloads, Sys, func_name)) { - static if ((Parameters!(func)).length == 1 && is(Parameters!(func)[0] == Sys.EntitiesData) && is(ReturnType!(func) == RetType)) + static if ((Parameters!(func)).length == 1 + && is(Parameters!(func)[0] == Sys.EntitiesData) + && is(ReturnType!(func) == RetType)) { static RetType callFunc(ref ListenerCallData data) { Sys* s = cast(Sys*) data.system.m_system_pointer; Sys.EntitiesData input_data; - fillInputData(input_data, data.block.type_info, data.block, data.begin, data.end, data.system); - static if(is(RetTyp == void))mixin("s."~func_name~"(input_data)"); - else return mixin("s."~func_name~"(input_data)"); + fillInputData(input_data, data.block.type_info, + data.block, data.begin, data.end, data.system); + static if (is(RetTyp == void)) + mixin("s." ~ func_name ~ "(input_data)"); + else + return mixin("s." ~ func_name ~ "(input_data)"); } + *member = cast(void*)&callFunc; break; } @@ -804,7 +870,7 @@ export struct EntityManager catchFunction!("onDisable")(&system.m_disable); catchFunction!("onCreate")(&system.m_create); catchFunction!("onDestroy")(&system.m_destroy); - catchFunction!("onBegin",bool)(&system.m_begin); + catchFunction!("onBegin", bool)(&system.m_begin); catchFunction!("onEnd")(&system.m_end); catchEntityFunction!("onAddEntity")(&system.m_add_entity); @@ -815,11 +881,19 @@ export struct EntityManager system.m_priority = priority; //(cast(Sys*) system.m_system_pointer).__ecsInitialize(); //system.jobs = (cast(Sys*) system.m_system_pointer)._ecs_jobs; - system.jobs = Mallocator.makeArray!(Job)((cast(Sys*) system.m_system_pointer).__ecs_jobs_count); + system.jobs = Mallocator.makeArray!(Job)((cast(Sys*) system.m_system_pointer) + .__ecs_jobs_count); + + static if (OnUpdateOverloadNum != -1) + { + Sys* s = cast(Sys*) system.m_system_pointer; + system.m_update_delegate = cast(void delegate())&__traits(getOverloads, + s, "onUpdate")[OnUpdateOverloadNum]; + } genCompList(system, components_map); - ushort sys_id = systems_map.get(cast(char[])Sys.stringof, ushort.max); + ushort sys_id = systems_map.get(cast(char[]) Sys.stringof, ushort.max); if (sys_id < systems.length) { system.enable(); @@ -832,7 +906,7 @@ export struct EntityManager } else { - system.m_name = Mallocator.makeArray(cast(char[])Sys.stringof); + system.m_name = Mallocator.makeArray(cast(char[]) Sys.stringof); systems_map.add(system.m_name, cast(ushort) systems.length); system.m_id = cast(ushort)(systems.length); @@ -866,7 +940,7 @@ export struct EntityManager export ushort registerPass(const(char)[] name) { UpdatePass* pass = Mallocator.make!UpdatePass; - pass.name = Mallocator.makeArray(cast(char[])name); + pass.name = Mallocator.makeArray(cast(char[]) name); /*pass.name = Mallocator.makeArray!char(name.length); pass.name[0..$] = name[0..$];*/ passes.add(pass); @@ -914,7 +988,7 @@ export struct EntityManager info.init_data = Mallocator.makeArray!ubyte(Comp.sizeof); *cast(Comp*) info.init_data.ptr = Comp.init; // = Comp(); - ushort comp_id = components_map.get(cast(char[])Comp.stringof, ushort.max); + ushort comp_id = components_map.get(cast(char[]) Comp.stringof, ushort.max); if (comp_id < components.length) { Comp.component_id = comp_id; @@ -924,7 +998,7 @@ export struct EntityManager { components.add(info); Comp.component_id = cast(ushort)(components.length - 1); - char[] name = Mallocator.makeArray(cast(char[])Comp.stringof); + char[] name = Mallocator.makeArray(cast(char[]) Comp.stringof); /*char[] name = Mallocator.makeArray!char(Comp.stringof.length); name[0..$] = Comp.stringof;*/ components_map.add(name, cast(ushort)(components.length - 1)); @@ -967,6 +1041,28 @@ export struct EntityManager } } + export void callEntitiesFunction(Sys, T)(T func) + { + Sys* s; + static assert(isDelegate!func, "Function must be delegate."); + static assert(__traits(hasMember, Sys, "EntitiesData"), + "Can't call function with system which hasn't EntitesData structure."); + static assert(__traits(hasMember, Sys, "onUpdate"), + "Can't call function with system which hasn't onUpdate function callback."); + static assert(is(T == typeof(&s.onUpdate)), "Function must match system update function."); + static assert(__traits(hasMember, Sys, "system_id"), "Sys must be system type."); + + System* system = getSystem(Sys.system_id); + assert(system != null, + "System must be registered in EntityManager before any funcion can be called."); + + foreach (info; system.m_any_system_caller.infos) + { + CallData data = CallData(system.id, system, info, cast(void delegate()) func); + data.update(); + } + } + /************************************************************************************************************************ *Same as "void update(int pass = 0)" but use pass name instead of id. */ @@ -991,7 +1087,7 @@ export struct EntityManager { foreach (info; caller.infos) { - CallData data = CallData(caller.system_id, sys, info); + CallData data = CallData(caller.system_id, sys, info, sys.m_update_delegate); data.update(); } } @@ -1085,7 +1181,8 @@ export struct EntityManager if (full_blocks_count * info.max_entities + entities_count + ( first_block.entities_count - first_elem) >= entities_per_job) { - CallData data = CallData(caller.system_id, sys, info, first_block, + CallData data = CallData(caller.system_id, sys, + info, sys.m_update_delegate, first_block, cast(ushort)(full_blocks_count + 1), cast(ushort) first_elem, 0); tmp_datas.add(data); @@ -1098,8 +1195,9 @@ export struct EntityManager entities_count += full_blocks_count * info.max_entities + ( first_block.entities_count - first_elem); // - first_elem; uint last_elem = entities_per_job - entities_count; // + first_elem - 1; - CallData data = CallData(caller.system_id, sys, info, - first_block, cast(ushort)(full_blocks_count + 2), + CallData data = CallData(caller.system_id, sys, + info, sys.m_update_delegate, first_block, + cast(ushort)(full_blocks_count + 2), cast(ushort) first_elem, cast(ushort) last_elem); tmp_datas.add(data); first_elem = last_elem; @@ -1111,7 +1209,8 @@ export struct EntityManager else { uint last_elem = entities_per_job - entities_count; - CallData data = CallData(caller.system_id, sys, info, first_block, 1, + CallData data = CallData(caller.system_id, sys, + info, sys.m_update_delegate, first_block, 1, cast(ushort) first_elem, cast(ushort)(first_elem + last_elem)); tmp_datas.add(data); first_elem += last_elem; @@ -1123,7 +1222,7 @@ export struct EntityManager } else { - CallData data = CallData(caller.system_id, sys, info, + CallData data = CallData(caller.system_id, sys, info, sys.m_update_delegate, first_block, cast(ushort) blocks_count, cast(ushort) first_elem); tmp_datas.add(data); entities_count += (blocks_count - 1) * info.max_entities @@ -1138,10 +1237,11 @@ export struct EntityManager } } - export void setMultithreadingCallbacks(void delegate(JobGroup) dispatch_callback, uint delegate() get_id_callback) + export void setMultithreadingCallbacks(void delegate(JobGroup) dispatch_callback, + uint delegate() get_id_callback) { - m_dispatch_jobs = cast(void delegate(JobGroup jobs) nothrow @nogc)dispatch_callback; - m_thread_id_func = cast(uint delegate() nothrow @nogc)get_id_callback; + m_dispatch_jobs = cast(void delegate(JobGroup jobs) nothrow @nogc) dispatch_callback; + m_thread_id_func = cast(uint delegate() nothrow @nogc) get_id_callback; } /*export void setJobDispachFunc(void delegate(JobGroup) @nogc nothrow func) nothrow @nogc @@ -1149,6 +1249,23 @@ export struct EntityManager m_dispatch_jobs = func; }*/ + /************************************************************************************************************************ + *Return size of single page (block). Every entity data block has size of page. + */ + uint pageSize() + { + return m_page_size; + } + + /************************************************************************************************************************ + *Return number of pages in single block allocation. Library allocate defined number of pages at once and assign it's + *for entities. + */ + uint pagesInBlock() + { + return m_pages_in_block; + } + static void alignNum(ref ushort num, ushort alignment) nothrow @nogc pure { num = cast(ushort)((num + alignment - 1) & (-cast(int) alignment)); //num += alignment - (num & (alignment - 1)); @@ -1183,12 +1300,13 @@ export struct EntityManager temp.entity_data = Mallocator.makeArray!ubyte(info.size); temp.info = info; - if(fill_default) + if (fill_default) { //fill components with default data foreach (comp; info.components) { - memcpy(temp.entity_data.ptr + info.tmpl_deltas[comp], components[comp].init_data.ptr, components[comp].size); + memcpy(temp.entity_data.ptr + info.tmpl_deltas[comp], + components[comp].init_data.ptr, components[comp].size); /*temp.entity_data[info.tmpl_deltas[comp] .. info.tmpl_deltas[comp] + components[comp].size] = components[comp].init_data;*/ } @@ -1199,10 +1317,11 @@ export struct EntityManager foreach (comp; info.components) { memcpy(cast(void*) temp.entity_data + info.tmpl_deltas[comp], - cast(void*) block + info.deltas[comp] + components[comp].size * index, components[comp].size); + cast(void*) block + info.deltas[comp] + components[comp].size * index, + components[comp].size); } } - + return temp; } @@ -1244,7 +1363,8 @@ export struct EntityManager //fill components with default data foreach (comp; info.components) { - memcpy(temp.entity_data.ptr + info.tmpl_deltas[comp], components[comp].init_data.ptr, components[comp].size); + memcpy(temp.entity_data.ptr + info.tmpl_deltas[comp], + components[comp].init_data.ptr, components[comp].size); /*temp.entity_data[info.tmpl_deltas[comp] .. info.tmpl_deltas[comp] + components[comp].size] = components[comp].init_data;*/ } @@ -1287,7 +1407,7 @@ export struct EntityManager alignNum(info.size, info.alignment); uint block_memory = cast(uint)( - page_size - EntitiesBlock.sizeof - (info.size - components_size)); + m_page_size - EntitiesBlock.sizeof - (info.size - components_size)); //uint entity_comps_size = EntityID.sizeof; uint mem_begin = EntitiesBlock.sizeof; @@ -1532,7 +1652,7 @@ export struct EntityManager data.change_entities_list.add(0); data.change_entities_list.add((cast(ubyte*)&entity_id)[0 .. EntityID.sizeof]); data.change_entities_list.add((cast(ubyte*)&num)[0 .. uint.sizeof]); - data.change_entities_list.add((cast(ubyte*)del_ids.ptr)[0 .. num * 2]); + data.change_entities_list.add((cast(ubyte*) del_ids.ptr)[0 .. num * 2]); } private void __removeComponents(EntityID entity_id, ushort[] del_ids) @@ -1550,12 +1670,13 @@ export struct EntityManager EntityInfo* new_info = info; - foreach(id;del_ids) + foreach (id; del_ids) { new_info = new_info.getNewInfoRemove(id); } - if(new_info == info)return; + if (new_info == info) + return; //EntityInfo* new_info = getEntityInfo(ids[0 .. j]); @@ -1669,12 +1790,13 @@ export struct EntityManager EntityInfo* new_info = info; - foreach(id;new_ids) + foreach (id; new_ids) { new_info = new_info.getNewInfoAdd(id); } - if(new_info == info)return; + if (new_info == info) + return; //EntityInfo* new_info = getEntityInfo(ids[0 .. len]); @@ -1701,10 +1823,10 @@ export struct EntityManager } } - foreach (ref id; new_info.components)//ids[0 .. len]) + foreach (ref id; new_info.components) //ids[0 .. len]) { void* dst = cast(void*) new_block + new_info.deltas[id] + ( - new_block.entities_count ) * components[id].size; + new_block.entities_count) * components[id].size; uint size = components[id].size; if (k >= new_ids.length) { @@ -1779,7 +1901,7 @@ export struct EntityManager } ThreadData* data = &threads[threadID]; - data.change_entities_list.add(cast(ubyte)1u); + data.change_entities_list.add(cast(ubyte) 1u); data.change_entities_list.add((cast(ubyte*)&entity_id)[0 .. EntityID.sizeof]); data.change_entities_list.add((cast(ubyte*)&num)[0 .. uint.sizeof]); data.change_entities_list.add(cast(ubyte[]) new_ids); @@ -1835,12 +1957,13 @@ export struct EntityManager foreach (i, comp; info.components) { memcpy(cast(void*) new_block + info.deltas[comp] + components[comp].size * new_id, - cast(void*) block + info.deltas[comp] + components[comp].size * index, components[comp].size); + cast(void*) block + info.deltas[comp] + components[comp].size * index, + components[comp].size); if (components[comp].create_callback) { - components[comp].create_callback( - cast(void*) block + info.deltas[comp] + new_id * components[comp].size); + components[comp].create_callback(cast( + void*) block + info.deltas[comp] + new_id * components[comp].size); } } @@ -2072,7 +2195,7 @@ export struct EntityManager */ export EntitiesBlock* getMetaData(const void* pointer) nothrow @nogc { - return cast(EntitiesBlock*)(cast(size_t) pointer & (~cast(size_t)(page_size - 1))); + return cast(EntitiesBlock*)(cast(size_t) pointer & (~cast(size_t)(m_page_size - 1))); } private void changeEntities() @@ -2081,7 +2204,7 @@ export struct EntityManager { uint index = 0; uint len = cast(uint) thread.change_entities_list.length; - void*[32] pointers;// = (cast(void**) alloca(num * (void*).sizeof))[0 .. num]; + void*[32] pointers; // = (cast(void**) alloca(num * (void*).sizeof))[0 .. num]; while (index < len) { if (!thread.change_entities_list[index++]) @@ -2090,7 +2213,7 @@ export struct EntityManager index += EntityID.sizeof; uint num = *cast(uint*)&thread.change_entities_list[index]; index += uint.sizeof; - ushort[] ids;// = (cast(ushort*) alloca(num * ushort.sizeof))[0 .. num]; + ushort[] ids; // = (cast(ushort*) alloca(num * ushort.sizeof))[0 .. num]; ids = (cast(ushort*)&thread.change_entities_list[index])[0 .. num]; index += ushort.sizeof * num; __removeComponents(id, ids); @@ -2101,7 +2224,7 @@ export struct EntityManager index += EntityID.sizeof; uint num = *cast(uint*)&thread.change_entities_list[index]; index += uint.sizeof; - ushort[] ids;// = (cast(ushort*) alloca(num * ushort.sizeof))[0 .. num]; + ushort[] ids; // = (cast(ushort*) alloca(num * ushort.sizeof))[0 .. num]; ids = (cast(ushort*)&thread.change_entities_list[index])[0 .. num]; index += ushort.sizeof * num; //void*[] pointers = (cast(void**) alloca(num * (void*).sizeof))[0 .. num]; @@ -2110,7 +2233,7 @@ export struct EntityManager pointers[i] = &thread.change_entities_list[index]; index += components[ids[i]].size; } - __addComponents(id, ids, pointers[0..num]); + __addComponents(id, ids, pointers[0 .. num]); } } thread.change_entities_list.clear(); @@ -2260,7 +2383,7 @@ export struct EntityManager { EntityID entity_id = *cast(EntityID*) event_pointer; Entity* entity = id_manager.getEntityPointer(entity_id); - if(entity) + if (entity) { call_data.block = getMetaData(entity); call_data.id = call_data.block.entityIndex(entity); @@ -2268,8 +2391,9 @@ export struct EntityManager foreach (caller; events[i].callers) { call_data.system_pointer = caller.system.m_system_pointer; - (cast(void function(ref EventCallData) nothrow @nogc) caller - .callback)(call_data); + (cast(void function( + ref EventCallData) nothrow @nogc) caller.callback)( + call_data); } } event_pointer += events[i].size; @@ -2360,7 +2484,7 @@ export struct EntityManager index = 0; out_for: foreach (caller2; pass.system_callers) { - if ( caller is caller2) + if (caller is caller2) continue; foreach (cmp; caller.system.m_read_only_components) { @@ -2448,8 +2572,7 @@ export struct EntityManager caller.dependencies = Mallocator.makeArray(exclusion[0 .. index]); /*caller.dependencies = Mallocator.makeArray!(SystemCaller*)(index); caller.dependencies[0..$] = exclusion[0 .. index];*/ - caller.job_group.dependencies = Mallocator.makeArray!( - JobGroup*)(index); + caller.job_group.dependencies = Mallocator.makeArray!(JobGroup*)(index); foreach (j, dep; caller.dependencies) { @@ -2467,7 +2590,9 @@ export struct EntityManager */ struct ComponentInfo { - export ~this() nothrow @nogc {} + export ~this() nothrow @nogc + { + } ///Component size ushort size; ///Component data alignment @@ -2535,37 +2660,42 @@ export struct EntityManager EntityInfo* getNewInfoAdd(ushort id) { - if(comp_add_info.length < id) + if (comp_add_info.length < id) { - EntityInfo*[] new_infos = Mallocator.makeArray!(EntityInfo*)(instance.components.length); - if(comp_add_info !is null) + EntityInfo*[] new_infos = Mallocator.makeArray!(EntityInfo*)( + instance.components.length); + if (comp_add_info !is null) { //new_infos[0 .. comp_add_info.length] = comp_add_info[0 .. $]; - memcpy(new_infos.ptr, comp_add_info.ptr, (EntityInfo*).sizeof * comp_add_info.length); + memcpy(new_infos.ptr, comp_add_info.ptr, (EntityInfo*) + .sizeof * comp_add_info.length); Mallocator.dispose(comp_add_info); } comp_add_info = new_infos; } - if(comp_add_info[id])return comp_add_info[id]; + if (comp_add_info[id]) + return comp_add_info[id]; ushort[] ids = (cast(ushort*) alloca(ushort.sizeof * (components.length + 1)))[0 - .. components.length + 1]; + .. components.length + 1]; uint len = 0; - foreach(comp; components) + foreach (comp; components) { - if(id > comp) + if (id > comp) { ids[len++] = comp; } - else if(id == comp)return &this; - else + else if (id == comp) + return &this; + else { ids[len++] = id; ids[len++] = comp; } } - if(id > components[$ - 1])ids[len++] = id; + if (id > components[$ - 1]) + ids[len++] = id; assert(len == components.length + 1); @@ -2577,31 +2707,35 @@ export struct EntityManager EntityInfo* getNewInfoRemove(ushort id) { - if(comp_rem_info.length < id) + if (comp_rem_info.length < id) { - EntityInfo*[] new_infos = Mallocator.makeArray!(EntityInfo*)(instance.components.length); - if(comp_rem_info !is null) + EntityInfo*[] new_infos = Mallocator.makeArray!(EntityInfo*)( + instance.components.length); + if (comp_rem_info !is null) { //new_infos[0 .. comp_rem_info.length] = comp_rem_info[0 .. $]; - memcpy(new_infos.ptr, comp_rem_info.ptr, (EntityInfo*).sizeof * comp_rem_info.length); + memcpy(new_infos.ptr, comp_rem_info.ptr, (EntityInfo*) + .sizeof * comp_rem_info.length); Mallocator.dispose(comp_rem_info); } comp_rem_info = new_infos; } - if(comp_rem_info[id])return comp_rem_info[id]; + if (comp_rem_info[id]) + return comp_rem_info[id]; ushort[] ids = (cast(ushort*) alloca(ushort.sizeof * (components.length - 1)))[0 - .. components.length - 1]; + .. components.length - 1]; uint len = 0; - foreach(comp; components) + foreach (comp; components) { - if(id != comp) + if (id != comp) { ids[len++] = comp; } } - if(len == components.length)return &this; + if (len == components.length) + return &this; assert(len == components.length - 1); @@ -2613,13 +2747,20 @@ export struct EntityManager export ~this() @nogc nothrow { - if(components)Mallocator.dispose(components); - if(deltas)Mallocator.dispose(deltas); - if(tmpl_deltas)Mallocator.dispose(tmpl_deltas); - if(systems)Mallocator.dispose(systems); - if(add_listeners)Mallocator.dispose(add_listeners); - if(remove_listeners)Mallocator.dispose(remove_listeners); - if(change_listeners)Mallocator.dispose(change_listeners); + if (components) + Mallocator.dispose(components); + if (deltas) + Mallocator.dispose(deltas); + if (tmpl_deltas) + Mallocator.dispose(tmpl_deltas); + if (systems) + Mallocator.dispose(systems); + if (add_listeners) + Mallocator.dispose(add_listeners); + if (remove_listeners) + Mallocator.dispose(remove_listeners); + if (change_listeners) + Mallocator.dispose(change_listeners); } ///entity components @@ -2722,6 +2863,8 @@ export struct EntityManager System* system; ///poiner to Entity type info EntityManager.EntityInfo* info; + ///delegate function to call (by default it's delegate to onUpdate call) + void delegate() update_delegate; ///pointer to first block into process (if 0 then first block will be used) EntitiesBlock* first_block; @@ -2772,7 +2915,7 @@ export struct EntityManager { Mallocator.dispose(dependencies); } - if(exclusion) + if (exclusion) { Mallocator.dispose(exclusion); } @@ -2803,7 +2946,7 @@ export struct EntityManager assert(name); if (name) Mallocator.dispose(name); - foreach(caller; system_callers) + foreach (caller; system_callers) { Mallocator.dispose(caller); } @@ -2845,9 +2988,9 @@ export struct EntityManager alias SytemFuncType = void function(ref EntityManager.CallData data) nothrow @nogc; ///Single page size. Must be power of two. - enum page_size = 32768; //4096; + int m_page_size = 32768; //32768; //4096; ///Number of pages in block. - enum pages_in_block = 128; + int m_pages_in_block = 128; IDManager id_manager; BlockAllocator allocator; @@ -2880,7 +3023,7 @@ export struct EntityManager export ~this() nothrow @nogc { - foreach(block;blocks) + foreach (block; blocks) { Mallocator.dispose(block); } diff --git a/source/ecs/system.d b/source/ecs/system.d index 30e9389..c63a2b2 100644 --- a/source/ecs/system.d +++ b/source/ecs/system.d @@ -77,9 +77,9 @@ struct System /************************************************************************************************************************ *Get system name. */ - export const (char)[] name() nothrow @nogc + export const(char)[] name() nothrow @nogc { - return cast(const (char)[])m_name; + return cast(const(char)[]) m_name; } struct EventCaller @@ -120,10 +120,13 @@ package: ushort[] m_read_only_components; ushort[] m_modified_components; + EntityManager.SystemCaller* m_any_system_caller; + EventCaller[] m_event_callers; //void function(ref EntityManager.CallData data) m_update; void* m_update; ///workaroud for DMD bug with upper line + void delegate() m_update_delegate; //void function(void* system_pointer) m_enable; //void function(void* system_pointer) m_disable; diff --git a/tests/tests.d b/tests/tests.d index 703f391..9f432fa 100644 --- a/tests/tests.d +++ b/tests/tests.d @@ -501,6 +501,20 @@ struct TestSystem2 } +struct ExternalUpdateCallTest +{ + int print_count = 3; + + void update(TestSystem2.EntitiesData data) + { + if(print_count > 0) + { + print_count--; + printf("ExternalUpdateCallTest %u %u\n", data.test[0].gg, cast(uint)data.length); + } + } +} + extern(C) int main() { @@ -660,8 +674,6 @@ extern(C) int main() gEM.registerSystem!TestSystem2(0); gEM.endRegister(); - System* sys = EntityManager.instance.getSystem(TestSystem2.system_id); - //gEM.generateDependencies(); //assert(*(cast(EntityID*)(cast(void*)tmpl.info.first_block+24)) == EntityID(1,1)); @@ -799,6 +811,12 @@ extern(C) int main() gEM.commit(); + System* sys = EntityManager.instance.getSystem(TestSystem2.system_id); + + ExternalUpdateCallTest external_update_test; + + EntityManager.instance.callEntitiesFunction!TestSystem2(&external_update_test.update); + printf("pre end\n"); writeEntityComponents(gEM.getEntity(entity)); From 5399b584dd0f47efa3f5ac151257fb3e1cd737da Mon Sep 17 00:00:00 2001 From: Mergul Date: Fri, 6 Mar 2020 10:12:52 +0100 Subject: [PATCH 087/217] -IDManager reserve EntityID(0) as empty -fixed bug with events called on destroyed entities (crash) -don't call event on system for unsupported entity -added "entity_id" property to EntitiesData --- source/ecs/id_manager.d | 27 ++++++++++++++++++++------- source/ecs/manager.d | 19 ++++++++++++++++--- tests/tests.d | 8 ++++++++ 3 files changed, 44 insertions(+), 10 deletions(-) diff --git a/source/ecs/id_manager.d b/source/ecs/id_manager.d index ebd7679..04cc360 100644 --- a/source/ecs/id_manager.d +++ b/source/ecs/id_manager.d @@ -136,7 +136,9 @@ begin: */ export bool isExist(EntityID id) nothrow @nogc { + if(id.id >= m_ids_array.length)return false; Data* data = &m_ids_array[id.id]; + if(data.entity is null)return false; return data.counter == id.counter; } @@ -151,6 +153,9 @@ begin: add_mutex = Mallocator.make!Mutex(); add_mutex.initialize(); + + getNewID(); + optimize(); } void deinitialize() @trusted @nogc nothrow @@ -243,23 +248,31 @@ private: unittest { IDManager manager; + manager.initialize(); EntityID id1 = manager.getNewID(); EntityID id2 = manager.getNewID(); EntityID id3 = manager.getNewID(); - assert(id1 == EntityID(0, 1)); - assert(id2 == EntityID(1, 1)); - assert(id3 == EntityID(2, 1)); + assert(id1 == EntityID(1, 0)); + assert(id2 == EntityID(2, 0)); + assert(id3 == EntityID(3, 0)); + manager.optimize(); manager.releaseID(id2); manager.releaseID(id1); id2 = manager.getNewID(); id1 = manager.getNewID(); - assert(id1 == EntityID(1, 2)); - assert(id2 == EntityID(0, 2)); - assert(id3 == EntityID(2, 1)); + Entity e; + e.id = id3; + manager.update(e); + + assert(id1 == EntityID(2, 1)); + assert(id2 == EntityID(1, 1)); + assert(id3 == EntityID(3, 0)); assert(manager.isExist(id3)); - assert(!manager.isExist(EntityID(0, 1))); + assert(!manager.isExist(EntityID(1, 0))); + assert(!manager.isExist(EntityID(0, 0))); + manager.deinitialize(); } diff --git a/source/ecs/manager.d b/source/ecs/manager.d index 7c89b71..27eaa40 100644 --- a/source/ecs/manager.d +++ b/source/ecs/manager.d @@ -542,7 +542,7 @@ export struct EntityManager foreach (member; __traits(allMembers, Sys.EntitiesData)) { alias MemberType = typeof(__traits(getMember, Sys.EntitiesData, member)); - if (member == "length" || is(MemberType == Entity[]) + if (member == "length" || member == "thread_id" || is(MemberType == Entity[]) || is(MemberType == const(Entity)[])) { if (is(MemberType == Entity[]) || is(MemberType == const(Entity)[])) @@ -648,6 +648,13 @@ export struct EntityManager static assert(MemberType.sizeof > 1, "EntitiesData 'length' member can't be byte or ubyte."); } + else static if(member == "thread_id") + { + static assert(isIntegral!(MemberType), + "EntitiesData 'thread_id' member must be integral type."); + static assert(MemberType.sizeof > 1, + "EntitiesData 'thread_id' member can't be byte or ubyte."); + } else static if (!(isArray!(MemberType))) static assert(0, "EntitiesData members should be arrays of elements!"); } @@ -703,6 +710,11 @@ export struct EntityManager { input_data.length = cast(typeof(input_data.length))(entities_count - offset); } + + static if (hasMember!(Sys.EntitiesData, "thread_id")) + { + input_data.thread_id = cast(typeof(input_data.thread_id))threadID(); + } static foreach (iii, comp_info; components_info.req) { @@ -2378,9 +2390,9 @@ export struct EntityManager { EventCallData call_data; void* event_pointer = cast(void*) block + event.data_offset; - call_data.event = event_pointer; foreach (j; 0 .. block.count) { + call_data.event = event_pointer; EntityID entity_id = *cast(EntityID*) event_pointer; Entity* entity = id_manager.getEntityPointer(entity_id); if (entity) @@ -2390,6 +2402,7 @@ export struct EntityManager foreach (caller; events[i].callers) { + if(call_data.block.type_info.systems[caller.system.m_id] == false)continue; call_data.system_pointer = caller.system.m_system_pointer; (cast(void function( ref EventCallData) nothrow @nogc) caller.callback)( @@ -2412,9 +2425,9 @@ export struct EntityManager { id_manager.optimize(); updateBlocks(); - removeEntities(); changeEntities(); updateEvents(); + removeEntities(); event_manager.clearEvents(); } diff --git a/tests/tests.d b/tests/tests.d index 9f432fa..3ff9d00 100644 --- a/tests/tests.d +++ b/tests/tests.d @@ -515,6 +515,14 @@ struct ExternalUpdateCallTest } } +version(unittest) +{ + void main() + { + + } +} +else: extern(C) int main() { From d6b53425dd73abe8bb3f08a8c259e8418e39756f Mon Sep 17 00:00:00 2001 From: Mergul Date: Fri, 6 Mar 2020 13:52:21 +0100 Subject: [PATCH 088/217] -added EmptySystem supprort (called once per frame, sholud be once per jobs) -EntitiesData can contain "thread_id" which is filled with ID of current thread --- source/ecs/manager.d | 243 ++++++++++++++++++++++++++----------------- source/ecs/system.d | 2 + tests/tests.d | 148 +++++++++++++++----------- 3 files changed, 237 insertions(+), 156 deletions(-) diff --git a/source/ecs/manager.d b/source/ecs/manager.d index 27eaa40..f3c5db8 100644 --- a/source/ecs/manager.d +++ b/source/ecs/manager.d @@ -164,6 +164,11 @@ export struct EntityManager foreach (ref system; systems) { + if (system.m_empty == true) + { + addSystemCaller(system.id); + continue; + } if (system.m_update is null) { if (system.m_add_entity || system.m_remove_entity || system.m_change_entity) @@ -357,46 +362,8 @@ export struct EntityManager { static void callEventHandler(Type)(ref EventCallData data) { - //Sys.EventInput input; Sys* data_system = cast(Sys*) data.system_pointer; - /*EntityInfo* info = data.block.type_info; - alias EventFields = Fields!(Sys.EventInput); - foreach (ref event_field; input.tupleof) - { - alias EventFieldType = Unqual!(typeof(*event_field)); - enum bool is_entity = is(EventFieldType == ecs.entity.Entity); - - static if (is_entity) - { - event_field = cast(Entity*) data.block.dataBegin() + data.id; - continue; - } - else - { - enum long index_in_entities_data = getIndexOfTypeInEntitiesData!(Sys.EntitiesData, - EventFieldType); - static assert(index_in_entities_data != -1, - "Component present in EventInput has to be present in EntitiesData!"); // Type present in EventInput has to be present in EntitiesData - - enum bool is_optional = hasUDA!(Sys.EntitiesData.tupleof[index_in_entities_data], - "optional"); - static if (is_optional) - { - if(info.deltas[EventFieldType.component_id] != 0)event_field = cast(EventFieldType*)(cast(void*) data.block - + info.deltas[EventFieldType.component_id] - + data.id * EventFieldType.sizeof); - else event_field = null; - } - else - { - event_field = cast(EventFieldType*)(cast(void*) data.block - + info.deltas[EventFieldType.component_id] - + data.id * EventFieldType.sizeof); - } - } - - }//*/ Type* event = cast(Type*) data.event; data_system.handleEvent(gEM.getEntity(event.entity_id), *event); } @@ -542,8 +509,8 @@ export struct EntityManager foreach (member; __traits(allMembers, Sys.EntitiesData)) { alias MemberType = typeof(__traits(getMember, Sys.EntitiesData, member)); - if (member == "length" || member == "thread_id" || is(MemberType == Entity[]) - || is(MemberType == const(Entity)[])) + if (member == "length" || member == "thread_id" + || is(MemberType == Entity[]) || is(MemberType == const(Entity)[])) { if (is(MemberType == Entity[]) || is(MemberType == const(Entity)[])) components_info.entites_array = member; @@ -648,7 +615,7 @@ export struct EntityManager static assert(MemberType.sizeof > 1, "EntitiesData 'length' member can't be byte or ubyte."); } - else static if(member == "thread_id") + else static if (member == "thread_id") { static assert(isIntegral!(MemberType), "EntitiesData 'thread_id' member must be integral type."); @@ -710,11 +677,11 @@ export struct EntityManager { input_data.length = cast(typeof(input_data.length))(entities_count - offset); } - - static if (hasMember!(Sys.EntitiesData, "thread_id")) + + /*static if (hasMember!(Sys.EntitiesData, "thread_id")) { input_data.thread_id = cast(typeof(input_data.thread_id))threadID(); - } + }//*/ static foreach (iii, comp_info; components_info.req) { @@ -774,52 +741,86 @@ export struct EntityManager static if (OnUpdateOverloadNum != -1) { - static void callUpdate(ref CallData data) + static if (components_info.req.length != 0 || components_info.optional.length != 0) { - Sys* s = cast(Sys*) data.system.m_system_pointer; - - Sys.EntitiesData input_data; - EntityInfo* info = data.info; //block.type_info; - System* system = data.system; - - EntitiesBlock* block; - if (data.first_block) - block = data.first_block; - else - block = info.first_block; - - uint offset = data.begin; - uint entities_count; - uint blocks; - if (data.blocks) - blocks = data.blocks; - else - blocks = uint.max; - - while (block !is null && blocks > 0) + static void callUpdate(ref CallData data) { - if (blocks == 1) + Sys* s = cast(Sys*) data.system.m_system_pointer; + + Sys.EntitiesData input_data; + EntityInfo* info = data.info; //block.type_info; + System* system = data.system; + + EntitiesBlock* block; + if (data.first_block) + block = data.first_block; + else + block = info.first_block; + + uint offset = data.begin; + uint entities_count; + uint blocks; + if (data.blocks) + blocks = data.blocks; + else + blocks = uint.max; + + while (block !is null && blocks > 0) { - if (data.end) - entities_count = data.end; + if (blocks == 1) + { + if (data.end) + entities_count = data.end; + else + entities_count = block.entities_count; + } else entities_count = block.entities_count; + + assert(entities_count <= block.entities_count + && offset <= block.entities_count); + + fillInputData(input_data, info, block, offset, entities_count, system); + + static if (hasMember!(Sys.EntitiesData, "thread_id")) + { + input_data.thread_id = cast(typeof(input_data.thread_id)) data + .thread_id; + } + + //s.onUpdate(input_data); + (cast(typeof(&__traits(getOverloads, s, + "onUpdate")[OnUpdateOverloadNum])) data.update_delegate)(input_data); + + block = block.next_block; + offset = 0; + blocks--; } - else - entities_count = block.entities_count; + } + } + else + { + static void callUpdate(ref CallData data) + { + Sys* s = cast(Sys*) data.system.m_system_pointer; - assert(entities_count <= block.entities_count && offset <= block.entities_count); + Sys.EntitiesData input_data; - fillInputData(input_data, info, block, offset, entities_count, system); + /*static if (hasMember!(Sys.EntitiesData, "length")) + { + input_data.length = 0; + }//*/ + + static if (hasMember!(Sys.EntitiesData, "thread_id")) + { + input_data.thread_id = cast(typeof(input_data.thread_id)) data.thread_id; + } - //s.onUpdate(input_data); (cast(typeof(&__traits(getOverloads, s, "onUpdate")[OnUpdateOverloadNum])) data.update_delegate)(input_data); - - block = block.next_block; - offset = 0; - blocks--; } + + system.m_empty = true; } system.m_update = &callUpdate; @@ -1097,11 +1098,18 @@ export struct EntityManager System* sys = &systems[caller.system_id]; if (sys.enabled && sys.execute) { - foreach (info; caller.infos) + if (sys.m_empty) { - CallData data = CallData(caller.system_id, sys, info, sys.m_update_delegate); + CallData data = CallData(caller.system_id, sys, null, sys.m_update_delegate); data.update(); } + else + foreach (info; caller.infos) + { + CallData data = CallData(caller.system_id, sys, info, + sys.m_update_delegate); + data.update(); + } } } } @@ -1130,6 +1138,26 @@ export struct EntityManager System* sys = &systems[caller.system_id]; if (sys.enabled && sys.execute) { + uint job_id = 0; + void nextJob() + { + CallData[] callers = m_call_data_allocator.getCallData( + cast(uint) tmp_datas.length); + //callers[0 .. $] = tmp_datas[0 .. $]; + memcpy(callers.ptr, &tmp_datas[0], CallData.sizeof * tmp_datas.length); + tmp_datas.clear(); + sys.jobs[job_id].callers = callers; + job_id++; + } + + if (sys.m_empty) + { + tmp_datas.add(CallData(caller.system_id, sys, null, sys.m_update_delegate)); + nextJob(); + caller.job_group.jobs = sys.jobs[0 .. 1]; + (cast(void delegate(JobGroup) nothrow @nogc) m_dispatch_jobs)(caller.job_group); + continue; + } uint entities_count = 0; foreach (info; caller.infos) { @@ -1155,20 +1183,8 @@ export struct EntityManager entities_per_job = entities_count / jobs_count + 1; } - uint job_id = 0; entities_count = 0; - void nextJob() - { - CallData[] callers = m_call_data_allocator.getCallData( - cast(uint) tmp_datas.length); - //callers[0 .. $] = tmp_datas[0 .. $]; - memcpy(callers.ptr, &tmp_datas[0], CallData.sizeof * tmp_datas.length); - tmp_datas.clear(); - sys.jobs[job_id].callers = callers; - job_id++; - } - foreach (info; caller.infos) { uint blocks_count = info.nonEmptyBlocksCount(); @@ -1596,6 +1612,41 @@ export struct EntityManager entity.systems[system_id] = true; } + export void addSystemCaller(uint system_id) nothrow @nogc + { + System* system = &systems[system_id]; + + uint index = 0; + for (; index < passes[system.m_pass].system_callers.length; index++) + { + if (passes[system.m_pass].system_callers[index].system_id == system_id) + return; + } + + bool added = false; + foreach (i, caller; passes[system.m_pass].system_callers) + { + if (systems[caller.system_id].priority > system.priority) + { + SystemCaller* sys_caller = Mallocator.make!SystemCaller; + sys_caller.system_id = system.id; + sys_caller.job_group.caller = sys_caller; + system.m_any_system_caller = sys_caller; + passes[system.m_pass].system_callers.add(sys_caller, i); + added = true; + break; + } + } + if (!added) + { + SystemCaller* sys_caller = Mallocator.make!SystemCaller; + sys_caller.system_id = system.id; + sys_caller.job_group.caller = sys_caller; + system.m_any_system_caller = sys_caller; + passes[system.m_pass].system_callers.add(sys_caller); + } + } + export void addSystemCaller(ref EntityInfo info, uint system_id) nothrow @nogc { System* system = &systems[system_id]; @@ -2402,7 +2453,10 @@ export struct EntityManager foreach (caller; events[i].callers) { - if(call_data.block.type_info.systems[caller.system.m_id] == false)continue; + if ( + call_data.block.type_info.systems[caller.system.m_id] + == false) + continue; call_data.system_pointer = caller.system.m_system_pointer; (cast(void function( ref EventCallData) nothrow @nogc) caller.callback)( @@ -2887,6 +2941,8 @@ export struct EntityManager ushort begin; ///index of last element in last block ushort end; + ///current thread index + uint thread_id; } struct ListenerCallData @@ -2906,6 +2962,7 @@ export struct EntityManager //EntityManager.instance.getThreadID(); foreach (ref caller; callers) { + caller.thread_id = EntityManager.instance.threadID(); caller.update(); } } diff --git a/source/ecs/system.d b/source/ecs/system.d index c63a2b2..54b3555 100644 --- a/source/ecs/system.d +++ b/source/ecs/system.d @@ -94,6 +94,8 @@ package: bool m_execute = true; ///system id ushort m_id; + ///is system empty? Empty systems don't update entities, and is called once per update + bool m_empty = false; ///should system update and catch events? bool m_enabled = false; diff --git a/tests/tests.d b/tests/tests.d index 3ff9d00..d75eb47 100644 --- a/tests/tests.d +++ b/tests/tests.d @@ -10,9 +10,9 @@ import ecs.system; import ecs.attributes; import ecs.core; -version(WebAssembly) +version (WebAssembly) { - extern(C) int printf(scope const char* format, ...) @nogc nothrow @system; + extern (C) int printf(scope const char* format, ...) @nogc nothrow @system; alias int time_t; alias int clockid_t; @@ -20,62 +20,65 @@ version(WebAssembly) struct timespec { - time_t tv_sec; - int tv_nsec; + time_t tv_sec; + int tv_nsec; } - extern(C) int clock_gettime(clockid_t, timespec*) @nogc nothrow @system; + extern (C) int clock_gettime(clockid_t, timespec*) @nogc nothrow @system; struct Time - { - + { - static long getUSecTime() - { + static long getUSecTime() + { time_t time; timespec spec; clock_gettime(CLOCK_REALTIME, &spec); //time = spec.tv_sec; - return spec.tv_sec * 1000_000 + spec.tv_nsec / 1000;//time / 1000_000; - } - } + return spec.tv_sec * 1000_000 + spec.tv_nsec / 1000; //time / 1000_000; + } + } - extern(C) void _start() {} + extern (C) void _start() + { + } } -else version(Windows) +else version (Windows) { import core.stdc.stdio : printf; import core.sys.windows.windows; + struct Time - { - static long getUSecTime() - { - LARGE_INTEGER time, freq; - QueryPerformanceFrequency(&freq); + { + static long getUSecTime() + { + LARGE_INTEGER time, freq; + QueryPerformanceFrequency(&freq); QueryPerformanceCounter(&time); - return time.QuadPart / (freq.QuadPart / 1000_000); - } - } + return time.QuadPart / (freq.QuadPart / 1000_000); + } + } } -else version(Posix) +else version (Posix) { import core.stdc.stdio : printf; import core.sys.posix.time; + struct Time - { - static long getUSecTime() - { + { + static long getUSecTime() + { time_t time; timespec spec; clock_gettime(CLOCK_REALTIME, &spec); //time = spec.tv_sec; - return spec.tv_sec * 1000_000 + spec.tv_nsec / 1000;//time / 1000_000; - } - } + return spec.tv_sec * 1000_000 + spec.tv_nsec / 1000; //time / 1000_000; + } + } } struct TestEvent @@ -209,20 +212,20 @@ struct ChangeTestSystem { //printf("Entity added! ID: "); foreach (i; 0 .. data.length) - printf("Entity added! ID: %u\n",cast(uint)data.entites[i].id.id); - ////writeln("Entity added! ID: ", data.entites[i].id); + printf("Entity added! ID: %u\n", cast(uint) data.entites[i].id.id); + ////writeln("Entity added! ID: ", data.entites[i].id); } void onRemoveEntity(EntitiesData data) { ////writeln("Entity removed! ID: ", data.entites[0].id); - printf("Entity removed! ID: %u\n",cast(uint)data.entites[0].id.id); + printf("Entity removed! ID: %u\n", cast(uint) data.entites[0].id.id); } void onChangeEntity(EntitiesData data) { ////writeln("Entity changed! ID: ", data.entites[0].id); - printf("Entity changed! ID: %u\n",cast(uint)data.entites[0].id.id); + printf("Entity changed! ID: %u\n", cast(uint) data.entites[0].id.id); } bool onBegin() @@ -409,6 +412,21 @@ struct Sys3 } } +struct EmptySystem +{ + mixin ECS.System; + + struct EntitiesData + { + uint thread_id; + } + + void onUpdate(EntitiesData data) + { + printf("EmptySystem.onUpdate() - this should be called once per update\n"); + } +} + import std.meta; struct TestSystem2 @@ -422,7 +440,7 @@ struct TestSystem2 }*/ //alias ExcludedComponents = AliasSeq!("TestComp", "TestComp4"); -/* + /* string ExcludedComponents2;*/ static struct EntitiesData @@ -507,15 +525,15 @@ struct ExternalUpdateCallTest void update(TestSystem2.EntitiesData data) { - if(print_count > 0) + if (print_count > 0) { print_count--; - printf("ExternalUpdateCallTest %u %u\n", data.test[0].gg, cast(uint)data.length); + printf("ExternalUpdateCallTest %u %u\n", data.test[0].gg, cast(uint) data.length); } } } -version(unittest) +version (unittest) { void main() { @@ -523,7 +541,7 @@ version(unittest) } } else: -extern(C) int main() + extern (C) int main() { void dispatch(EntityManager.JobGroup jobs) nothrow @nogc @@ -542,28 +560,30 @@ extern(C) int main() void writeEntityComponents(Entity* entity) { - - printf("EntityID(%u, %u)",cast(uint)entity.id.id,cast(uint)entity.id.counter); + + printf("EntityID(%u, %u)", cast(uint) entity.id.id, cast(uint) entity.id.counter); //write(entity.id); TestComp* test_comp = entity.getComponent!TestComp; if (test_comp) - printf("TestComp(%u, %u)",cast(uint)test_comp.a,cast(uint)test_comp.b);//write(*test_comp); + printf("TestComp(%u, %u)", cast(uint) test_comp.a, cast(uint) test_comp.b); //write(*test_comp); TestComp2* test_comp2 = entity.getComponent!TestComp2; if (test_comp2) - printf("TestComp2(%u, %u)",cast(uint)test_comp2.b,cast(uint)test_comp2.a);//write(*test_comp2); + printf("TestComp2(%u, %u)", cast(uint) test_comp2.b, cast(uint) test_comp2.a); //write(*test_comp2); TestComp3* test_comp3 = entity.getComponent!TestComp3; if (test_comp3) - printf("TestComp3(%u, %u)",cast(uint)test_comp3.gg,cast(uint)test_comp3.bg);//write(*test_comp3); + printf("TestComp3(%u, %u)", cast(uint) test_comp3.gg, cast(uint) test_comp3.bg); //write(*test_comp3); TestComp4* test_comp4 = entity.getComponent!TestComp4; if (test_comp4) - printf("TestComp4(%u, %u, %u, %u, %u, %u)",test_comp4.gg,test_comp4.bg,cast(uint)test_comp4.a,cast(uint)test_comp4.b,cast(uint)test_comp4.c,cast(uint)test_comp4.g);//write(*test_comp4); + printf("TestComp4(%u, %u, %u, %u, %u, %u)", test_comp4.gg, test_comp4.bg, + cast(uint) test_comp4.a, cast(uint) test_comp4.b, + cast(uint) test_comp4.c, cast(uint) test_comp4.g); //write(*test_comp4); printf("\n"); //writeln(); ////writeln((cast(uint*) pp)[0 .. 14], " ", pp); } EntityManager.initialize(1); - + //gEM.setJobDispachFunc(&dispatch); gEM.setMultithreadingCallbacks(&dispatch, &getID); //assert(gEM !is null); @@ -588,7 +608,7 @@ extern(C) int main() time = MonoTime.currTime;*/ - printf("Components register: %f usecs\n",cast(float)(Time.getUSecTime() - time)); + printf("Components register: %f usecs\n", cast(float)(Time.getUSecTime() - time)); time = Time.getUSecTime(); gEM.registerSystem!TestSystemWithHighPriority(100, "fixed"); @@ -597,6 +617,7 @@ extern(C) int main() gEM.registerSystem!Sys1(10); gEM.registerSystem!Sys2(-100); gEM.registerSystem!Sys3(-2); + gEM.registerSystem!EmptySystem(2); //gEM.registerSystem!TestSystemWithHighPriority(100); //gEM.registerSystem!TestSystem2(0); gEM.endRegister(); @@ -605,7 +626,7 @@ extern(C) int main() //writeln("Systems register: ", dur, " usecs"); time = MonoTime.currTime;*/ - printf("Systems register: %f usecs\n",cast(float)(Time.getUSecTime() - time)); + printf("Systems register: %f usecs\n", cast(float)(Time.getUSecTime() - time)); time = Time.getUSecTime(); //ushort[3] ids = [TestComp2.component_id, TestComp.component_id, TestComp4.component_id]; @@ -620,7 +641,7 @@ extern(C) int main() //dur = (MonoTime.currTime - time).total!"usecs"; //writeln("Template allocating: ", dur, " usecs"); - printf("Template allocating: %f usecs\n",cast(float)(Time.getUSecTime() - time)); + printf("Template allocating: %f usecs\n", cast(float)(Time.getUSecTime() - time)); time = Time.getUSecTime(); EntityID entity; @@ -644,7 +665,7 @@ extern(C) int main() import ecs.std; - EntityID[] idss = Mallocator.makeArray!EntityID(5000);//[5000] + EntityID[] idss = Mallocator.makeArray!EntityID(5000); //[5000] //scope(exit)Mallocator.dispose(idss); foreach (i; 0 .. 200) @@ -660,7 +681,7 @@ extern(C) int main() //dur = (MonoTime.currTime - time).total!"usecs"; //writeln("Entities adding: ", dur, " usecs"); - printf("Entities adding: %f usecs\n",cast(float)(Time.getUSecTime() - time)); + printf("Entities adding: %f usecs\n", cast(float)(Time.getUSecTime() - time)); time = Time.getUSecTime(); uint blocks = 0; @@ -674,7 +695,7 @@ extern(C) int main() } } //writeln("Entities blocks: ", blocks); - printf("Entities blocks: %u\n",blocks); + printf("Entities blocks: %u\n", blocks); //foreach(j; 0..1_000)gEM.addEntity(tmpl); @@ -696,8 +717,8 @@ extern(C) int main() foreach (i; 0 .. 500_000) { entity2 = gEM.addEntity(tmpl).id; - entities[i*2] = entity2; - entities[i*2+1] = gEM.addEntity(tmpl2).id; + entities[i * 2] = entity2; + entities[i * 2 + 1] = gEM.addEntity(tmpl2).id; } gEM.commit(); @@ -705,13 +726,14 @@ extern(C) int main() //writeln("Entities adding2: ", dur, " usecs"); //time = MonoTime.currTime; - printf("Entities adding2: %f usecs\n",cast(float)(Time.getUSecTime() - time)); + printf("Entities adding2: %f usecs\n", cast(float)(Time.getUSecTime() - time)); time = Time.getUSecTime(); foreach (i; 0 .. 1_000_000) { - EntityManager.instance.addComponents(entities[i],TestComp5()); - if((i & 0x00FFFF) == 0)gEM.commit(); + EntityManager.instance.addComponents(entities[i], TestComp5()); + if ((i & 0x00FFFF) == 0) + gEM.commit(); } gEM.commit(); @@ -719,7 +741,7 @@ extern(C) int main() //writeln("Components adding: ", dur, " usecs"); //time = MonoTime.currTime; - printf("Components adding: %f usecs\n",cast(float)(Time.getUSecTime() - time)); + printf("Components adding: %f usecs\n", cast(float)(Time.getUSecTime() - time)); time = Time.getUSecTime(); foreach (i; 0 .. 1_000_000) @@ -731,7 +753,7 @@ extern(C) int main() gEM.commit(); //dur = (MonoTime.currTime - time).total!"usecs"; //writeln("Components removing: ", dur, " usecs"); - printf("Components removing: %f usecs\n",cast(float)(Time.getUSecTime() - time)); + printf("Components removing: %f usecs\n", cast(float)(Time.getUSecTime() - time)); time = Time.getUSecTime(); Mallocator.dispose(entities); @@ -746,7 +768,7 @@ extern(C) int main() //dur = (MonoTime.currTime - time).total!"usecs"; //writeln("Update: ", dur, " usecs"); - printf("Update: %f usecs\n",cast(float)(Time.getUSecTime() - time)); + printf("Update: %f usecs\n", cast(float)(Time.getUSecTime() - time)); writeEntityComponents(gEM.getEntity(entity2)); @@ -760,7 +782,7 @@ extern(C) int main() //dur = (MonoTime.currTime - time).total!"usecs"; //writeln("Update: ", dur, " usecs"); - printf("Update: %f usecs\n",cast(float)(Time.getUSecTime() - time)); + printf("Update: %f usecs\n", cast(float)(Time.getUSecTime() - time)); writeEntityComponents(gEM.getEntity(entity2)); @@ -774,7 +796,7 @@ extern(C) int main() //dur = (MonoTime.currTime - time).total!"usecs"; //writeln("Update: ", dur, " usecs"); - printf("Update: %f usecs\n",cast(float)(Time.getUSecTime() - time)); + printf("Update: %f usecs\n", cast(float)(Time.getUSecTime() - time)); writeEntityComponents(gEM.getEntity(entity2)); @@ -794,7 +816,7 @@ extern(C) int main() writeEntityComponents(gEM.addEntityCopy(entity)); EntityTemplate* copy_tempalte = gEM.allocateTemplate(entity); writeEntityComponents(gEM.addEntity(copy_tempalte)); - EntityTemplate* copy_default_tempalte = gEM.allocateTemplate(entity,true); + EntityTemplate* copy_default_tempalte = gEM.allocateTemplate(entity, true); writeEntityComponents(gEM.addEntity(copy_default_tempalte)); gEM.addComponents(entity, TestComp4()); @@ -838,7 +860,7 @@ extern(C) int main() Mallocator.dispose(idss); - printf("end\n");//*/ + printf("end\n"); //*/ return 0; } From 546b73c5674c745536cf222c08c55175accc28fc Mon Sep 17 00:00:00 2001 From: Mergul Date: Sat, 7 Mar 2020 13:21:29 +0100 Subject: [PATCH 089/217] -fixed events bug with calls for unsupported systems -now empty systems can't handle events and listeners --- meson.build | 7 +++--- source/ecs/manager.d | 23 +++++++++++------- tests/tests.d | 55 ++++++++++++++++++++++++++++++++++++++++++-- 3 files changed, 71 insertions(+), 14 deletions(-) diff --git a/meson.build b/meson.build index b26bdcc..3317d5c 100644 --- a/meson.build +++ b/meson.build @@ -1,6 +1,7 @@ project('DECS', 'd') src = [ + 'source/ecs/atomic.d', 'source/ecs/attributes.d', 'source/ecs/block_allocator.d', 'source/ecs/core.d', @@ -9,14 +10,12 @@ src = [ 'source/ecs/hash_map.d', 'source/ecs/id_manager.d', 'source/ecs/manager.d', - 'source/ecs/simple_vector.d', + 'source/ecs/package.d', 'source/ecs/simple_vector.d', 'source/ecs/std.d', - 'source/ecs/atomic.d', 'source/ecs/system.d', 'source/ecs/traits.d', - 'source/ecs/vector.d', - 'source/ecs/package.d' + 'source/ecs/vector.d' ] tests_src = [ diff --git a/source/ecs/manager.d b/source/ecs/manager.d index f3c5db8..853cf14 100644 --- a/source/ecs/manager.d +++ b/source/ecs/manager.d @@ -164,14 +164,16 @@ export struct EntityManager foreach (ref system; systems) { - if (system.m_empty == true) + if (system.m_empty) { - addSystemCaller(system.id); + if (system.m_update) + addSystemCaller(system.id); continue; } if (system.m_update is null) { - if (system.m_add_entity || system.m_remove_entity || system.m_change_entity) + if (system.m_add_entity || system.m_remove_entity + || system.m_change_entity || system.m_event_callers.length) { foreach (info; &entities_infos.byValue) { @@ -181,7 +183,7 @@ export struct EntityManager continue; } - bool added = false; + /*bool added = false; foreach (i, caller; passes[system.m_pass].system_callers) { if (systems[caller.system_id].priority > system.priority) @@ -202,7 +204,8 @@ export struct EntityManager sys_caller.job_group.caller = sys_caller; system.m_any_system_caller = sys_caller; passes[system.m_pass].system_callers.add(sys_caller); - } + }*/ + addSystemCaller(system.id); foreach (info; &entities_infos.byValue) { @@ -739,6 +742,9 @@ export struct EntityManager enum OnUpdateOverloadNum = -1; //enum HasOnUpdate = (hasMember!(Sys, "onUpdate") && checkOnUpdateParams()); + static if (components_info.req.length == 0 && components_info.optional.length == 0) + system.m_empty = true; + static if (OnUpdateOverloadNum != -1) { static if (components_info.req.length != 0 || components_info.optional.length != 0) @@ -819,8 +825,6 @@ export struct EntityManager (cast(typeof(&__traits(getOverloads, s, "onUpdate")[OnUpdateOverloadNum])) data.update_delegate)(input_data); } - - system.m_empty = true; } system.m_update = &callUpdate; @@ -1454,9 +1458,12 @@ export struct EntityManager foreach (i, ref system; systems) { + if (system.m_empty) + continue; if (system.m_update is null) { - if (system.m_add_entity || system.m_remove_entity || system.m_change_entity) + if (system.m_add_entity || system.m_remove_entity + || system.m_change_entity || system.m_event_callers.length) connectListenerToEntityInfo(*info, cast(uint) i); continue; } diff --git a/tests/tests.d b/tests/tests.d index d75eb47..33ce587 100644 --- a/tests/tests.d +++ b/tests/tests.d @@ -412,6 +412,55 @@ struct Sys3 } } +struct EmptyEventSystem +{ + mixin ECS.System; + + bool handled = false; + + struct EntitiesData + { + uint thread_id; + } + + void handleEvent(Entity* entity, TestEvent event) + { + if(!handled) + { + printf("EmptyEventSystem.handleEvent() called!\n"); + handled = true; + } + assert(0,"this shouldn't be called!"); + } +} + +struct EventSystem +{ + mixin ECS.System; + + bool handled = false; + + struct EntitiesData + { + uint thread_id; + TestComp[] comp; + } + + void handleEvent(Entity* entity, TestEvent event) + { + if(!handled) + { + printf("EventSystem.handleEvent() called!\n"); + handled = true; + } + } + + /*void onUpdate(EntitiesData) + { + + }*/ +} + struct EmptySystem { mixin ECS.System; @@ -458,7 +507,7 @@ struct TestSystem2 //TestComp* tt; } - void handleEvent(Entity* entity, ref TestEvent event) + void handleEvent(Entity* entity, TestEvent event) { TestComp3* test = entity.getComponent!TestComp3; test.bg = event.a; @@ -467,7 +516,7 @@ struct TestSystem2 gEM.sendEvent(entity.id, event2); } - void handleEvent(Entity* entity, ref TestEvent2 event) + void handleEvent(Entity* entity, TestEvent2 event) { TestComp3* test = entity.getComponent!TestComp3; test.gg = cast(uint) event.a; @@ -618,6 +667,8 @@ else: gEM.registerSystem!Sys2(-100); gEM.registerSystem!Sys3(-2); gEM.registerSystem!EmptySystem(2); + gEM.registerSystem!EmptyEventSystem(2); + gEM.registerSystem!EventSystem(2); //gEM.registerSystem!TestSystemWithHighPriority(100); //gEM.registerSystem!TestSystem2(0); gEM.endRegister(); From 845f468d59dcfef52c86c4551b15182deac186ef Mon Sep 17 00:00:00 2001 From: Mergul Date: Sat, 21 Mar 2020 13:27:14 +0100 Subject: [PATCH 090/217] -added more documentation -remove update() function from entity -currently max supported components count is 64 per type --- source/ecs/atomic.d | 16 +++++--- source/ecs/attributes.d | 17 ++++++++- source/ecs/block_allocator.d | 71 +++++++++++++++++++++++------------- source/ecs/core.d | 47 ++++++++++++++++++++++++ source/ecs/entity.d | 26 +++++++------ source/ecs/events.d | 4 +- source/ecs/id_manager.d | 11 +++++- source/ecs/manager.d | 61 +++++++++++++++++++++++-------- source/ecs/std.d | 4 ++ source/ecs/system.d | 6 ++- 10 files changed, 199 insertions(+), 64 deletions(-) diff --git a/source/ecs/atomic.d b/source/ecs/atomic.d index 1ab78af..91cc3d4 100644 --- a/source/ecs/atomic.d +++ b/source/ecs/atomic.d @@ -1,3 +1,9 @@ +/************************************************************************************************************************ +*It's internal code. Can be used for atomics if emscripten backend will be used. +* +*This module contain atomic operations which include support for emscripten atomics functions. +*Emscripten functions are contained in API similar to druntime. +*/ module ecs.atomic; version(Emscripten)version = ECSEmscripten; @@ -14,7 +20,7 @@ version(ECSEmscripten) rel, seq } - + extern(C) ubyte emscripten_atomic_cas_u8(void *addr, ubyte oldVal, ubyte newVal) @nogc nothrow pure; extern(C) ushort emscripten_atomic_cas_u16(void *addr, ushort oldVal, ushort newVal) @nogc nothrow pure; extern(C) uint emscripten_atomic_cas_u32(void *addr, uint oldVal, uint newVal) @nogc nothrow pure; @@ -35,7 +41,7 @@ version(ECSEmscripten) extern(C) ushort emscripten_atomic_sub_u16(void *addr, ushort val) @nogc nothrow pure; extern(C) uint emscripten_atomic_sub_u32(void *addr, uint val) @nogc nothrow pure; - pure nothrow @nogc Unqual!T atomicOp(string op, T, V1)(ref shared T val, V1 mod) + public pure nothrow @nogc Unqual!T atomicOp(string op, T, V1)(ref shared T val, V1 mod) { static if(op == "+=") { @@ -53,7 +59,7 @@ version(ECSEmscripten) } } - pure nothrow @nogc @trusted void atomicStore(MemoryOrder ms = MemoryOrder.seq, T, V)(ref T val, V newval) + public pure nothrow @nogc @trusted void atomicStore(MemoryOrder ms = MemoryOrder.seq, T, V)(ref T val, V newval) { alias UT = Unqual!T; static if(is(UT == bool) || is(UT == byte) || is(UT == ubyte))emscripten_atomic_store_u8(cast(void*)&val, cast(UT)newval); @@ -62,7 +68,7 @@ version(ECSEmscripten) else static assert(0); } - pure nothrow @nogc @trusted T atomicLoad(MemoryOrder ms = MemoryOrder.seq, T)(ref const T val) + public pure nothrow @nogc @trusted T atomicLoad(MemoryOrder ms = MemoryOrder.seq, T)(ref const T val) { alias UT = Unqual!T; static if(is(UT == bool))return emscripten_atomic_load_u8(cast(const void*)&val) != 0; @@ -72,7 +78,7 @@ version(ECSEmscripten) else static assert(0); } - pure nothrow @nogc @trusted bool cas(MemoryOrder succ = MemoryOrder.seq, MemoryOrder fail = MemoryOrder.seq, T, V1, V2)(T* here, V1 ifThis, V2 writeThis) + public pure nothrow @nogc @trusted bool cas(MemoryOrder succ = MemoryOrder.seq, MemoryOrder fail = MemoryOrder.seq, T, V1, V2)(T* here, V1 ifThis, V2 writeThis) { alias UT = Unqual!T; static if(is(UT == bool))return emscripten_atomic_cas_u8(cast(void*)here, cast(Unqual!T)ifThis, cast(Unqual!T)writeThis) == ifThis; diff --git a/source/ecs/attributes.d b/source/ecs/attributes.d index cb49933..2b24178 100644 --- a/source/ecs/attributes.d +++ b/source/ecs/attributes.d @@ -1,8 +1,21 @@ +/************************************************************************************************************************ +*This module contain attributes used to mark components. +*Currently only two attributes are supported: +* - optional: mark component as optional for system update +* - readonly: mark component access as read only (used for multithreading) +* +*By default components are required and mutable. "const" attribute can be used insteac od readonly mark. +*ex. +*Struct EntitiesData +*{ +* Comp1[] cmp; //mutable required component +* @readonly @optional Comp2[] cmp2; //optional read only component +* @optional const (Comp3)[] cmp3; //same as cmp2 +*} +*/ module ecs.attributes; ///Used to mark optional components for system. enum optional = "optional"; -//Used to mark components excluded from update for system. Enum 'ExcludedComponents' should be used instead of it. -//enum excluded = "excluded"; ///Used to mark readonly components for system. "const" can be used insted. enum readonly = "readonly"; \ No newline at end of file diff --git a/source/ecs/block_allocator.d b/source/ecs/block_allocator.d index edd2275..5db4dab 100644 --- a/source/ecs/block_allocator.d +++ b/source/ecs/block_allocator.d @@ -1,23 +1,23 @@ +/************************************************************************************************************************ +*It's internal code. +* +*Module contain memory allocator. +*/ module ecs.block_allocator; import ecs.manager; import ecs.std; +/************************************************************************************************************************ +*Allocator allocate large blocks and return smaller blocks. When there is no more blocks then next large block is allocated. +*By default freeing memory only returns it to allocator. To free large memory chunks freeMemory function is used. +*freeMemory function return to system memory even if chunk blocks wasn't freed. +*/ struct BlockAllocator { - private uint block_size; - private uint blocks_in_allocation; - - struct BlockPointers - { - void*[32] blocks; - uint numberof = 0; - BlockPointers* next_pointers = null; - } - - void* next_block = null; - BlockPointers* pointers = null; - + /************************************************************************************************************************ + *Get new block. Allocator automatically allocate next memory chunk if needed. + */ void* getBlock() nothrow @nogc { if (next_block is null) @@ -27,13 +27,35 @@ struct BlockAllocator return ret; } + /************************************************************************************************************************ + *Return block to allocator for further use. + */ void freeBlock(void* block) nothrow @nogc { *cast(void**)block = next_block; next_block = block; } - private void allocBlock() nothrow @nogc + /************************************************************************************************************************ + *Free whole used memory. This function return to system all memory chunks even if not every black was freed. + */ + void freeMemory() nothrow @nogc + { + while(pointers) + { + foreach(i;0..pointers.numberof) + { + Mallocator.alignDispose(pointers.blocks[i]); + } + BlockPointers* next_pointers = pointers.next_pointers; + Mallocator.dispose(pointers); + pointers = next_pointers; + } + } + +private: + + void allocBlock() nothrow @nogc { next_block = cast(void*) Mallocator.alignAlloc( block_size * blocks_in_allocation, block_size); @@ -57,17 +79,16 @@ struct BlockAllocator *pointer = null; } - void freeMemory() nothrow @nogc + struct BlockPointers { - while(pointers) - { - foreach(i;0..pointers.numberof) - { - Mallocator.alignDispose(pointers.blocks[i]); - } - BlockPointers* next_pointers = pointers.next_pointers; - Mallocator.dispose(pointers); - pointers = next_pointers; - } + void*[32] blocks; + uint numberof = 0; + BlockPointers* next_pointers = null; } + + uint block_size; + uint blocks_in_allocation; + + void* next_block = null; + BlockPointers* pointers = null; } diff --git a/source/ecs/core.d b/source/ecs/core.d index 956c324..dde39a5 100644 --- a/source/ecs/core.d +++ b/source/ecs/core.d @@ -1,27 +1,74 @@ +/************************************************************************************************************************ +*This module contain main templates for user. +*There are three structure templates (mixins) which should be added on top of structure: +* - System: make system structure +* - Component: make component structure +* - Event: make event structure +* +*ex. +*Struct System1 +*{ +* mixin!ECS.System; +*} +* +*Struct System2 +*{ +* mixin!ECS.System(16);//set number of jobs generated for system by multithreaded update +*} +* +*Struct Component1 +*{ +* mixin!ECS.Component; +*} +* +*Struct Event1 +*{ +* mixin!ECS.Event; +*} +* +*There is also template for generating list of excluded components "ExcludedComponets(T...)". +*This template takes component structure types and making list of excluded components used in "registerSystem" function. +* +*/ module ecs.core; public import ecs.manager; public import ecs.entity; +/************************************************************************************************************************ +*Main struct used as namespace for templates. +*/ static struct ECS { + /************************************************************************************************************************ + *Mark structure as System. Should be added on top of structure (before any data). + */ mixin template System(uint jobs_count = 32) { __gshared ushort system_id; uint __ecs_jobs_count = jobs_count; } + /************************************************************************************************************************ + *Mark structure as Component. Should be added on top of structure (before any data). + */ mixin template Component() { __gshared ushort component_id; } + /************************************************************************************************************************ + *Mark structure as Event. Should be added on top of structure (before any data). + */ mixin template Event() { __gshared ushort event_id; EntityID entity_id; } + /************************************************************************************************************************ + *Make list of excluded components. This template get structure types as argument. Should be added inside System structure. + */ mixin template ExcludedComponents(T...) { alias ExcludedComponents = T; diff --git a/source/ecs/entity.d b/source/ecs/entity.d index 8fbc6e4..699bf61 100644 --- a/source/ecs/entity.d +++ b/source/ecs/entity.d @@ -7,7 +7,7 @@ import ecs.system; import ecs.manager; /************************************************************************************************************************ -*Entity ID structure. +*Entity ID structure. Used as reference to Entity. Pointer to entity should be ever used to store entity reference! */ struct EntityID { @@ -26,15 +26,8 @@ struct Entity EntityID id; /************************************************************************************************************************ - *Update pointer to it in IDManager - */ - void updateID() nothrow @nogc - { - EntityManager.instance.id_manager.update(this); - } - - /************************************************************************************************************************ - *Get specified component. If component doesn't exist function retun null. + *Get specified component. If component doesn't exist function retun null. Pointer is valid only before next "commit()", "begin()" or "end()" + *function is called. Returned pointer shouldn't be used to store reference to entity data. */ T* getComponent(T)() const { @@ -49,10 +42,21 @@ struct Entity uint ind = cast(uint)((cast(void*)&this - block.dataBegin()) / EntityID.sizeof()); return cast(T*)(cast(void*)block + info.deltas[T.component_id] + ind * T.sizeof); } + + /*package void updateID() nothrow @nogc + { + EntityManager.instance.id_manager.update(this); + }*/ } /************************************************************************************************************************ *Entity template structure. +*Entity contain whole information needed to create new entity. Allocating EntityTemplate is considered as more expensive operation +*than adding entity. Whole components memory is stored in EntityTemplate and is copyied to newly added entity. +*If you want to place several entity with small difference in data then you should take pointer to component and change it before every +*entity addition. +*There is no restriction about number of allocated templates. Single template can be used from multiple threads, but if you +*want to changes some components data before add entity (entity position for example) it's better to use multiple templates. */ export struct EntityTemplate { @@ -62,7 +66,7 @@ export struct EntityTemplate EntityManager.EntityInfo* info; /************************************************************************************************************************ - *Get specified component. If component doesn't exist function return null. + *Get specified component. If component doesn't exist function return null. Returned pointer is valid during EntityTemplate lifetime. */ T* getComponent(T)() nothrow @nogc { diff --git a/source/ecs/events.d b/source/ecs/events.d index 6aa773f..7186d13 100644 --- a/source/ecs/events.d +++ b/source/ecs/events.d @@ -7,7 +7,7 @@ import ecs.std; import std.algorithm.comparison : max; -struct EventManager +package struct EventManager { void initialize(EntityManager* m) nothrow @nogc @@ -34,7 +34,7 @@ struct EventManager EventData* data = &events[Ev.event_id]; EventBlock* block = data.blocks[block_id]; - EntityManager.EventInfo* info = &gEM.events[Ev.event_id]; + //EntityManager.EventInfo* info = &gEM.events[Ev.event_id]; event.entity_id = id; if(block is null) diff --git a/source/ecs/id_manager.d b/source/ecs/id_manager.d index 04cc360..475eb94 100644 --- a/source/ecs/id_manager.d +++ b/source/ecs/id_manager.d @@ -19,7 +19,7 @@ struct IDManager { //uint current = m_next_id; //uint next;// = m_ids_array[m_next_id].next_id; -begin: +//begin: //if (current == uint.max)//> m_last_id) int current = m_stack_top.atomicOp!"-="(1) + 1; if(current < 0) @@ -142,6 +142,9 @@ begin: return data.counter == id.counter; } + /************************************************************************************************************************ + *Initialize manager. + */ void initialize() nothrow @nogc { m_ids_array = Mallocator.makeArray!Data(65536); @@ -158,6 +161,9 @@ begin: optimize(); } + /************************************************************************************************************************ + *Free manager memory. + */ void deinitialize() @trusted @nogc nothrow { if(m_ids_array)Mallocator.dispose(m_ids_array); @@ -178,6 +184,9 @@ begin: } } + /************************************************************************************************************************ + *Optimize memory. Must be called if any ID was added and some ID will be removed. + */ void optimize() nothrow @nogc { if(m_stack_top < -1)m_stack_top = -1; diff --git a/source/ecs/manager.d b/source/ecs/manager.d index 853cf14..747e1ed 100644 --- a/source/ecs/manager.d +++ b/source/ecs/manager.d @@ -1,5 +1,5 @@ /************************************************************************************************************************ -*Most important module. +*Most important module. Almost every function is called from EntityManager. */ module ecs.manager; @@ -25,11 +25,35 @@ import ecs.atomic; export alias gEM = EntityManager.instance; export alias gEntityManager = EntityManager.instance; -export alias gEventManager = EntityManager.instance; alias SerializeVector = ecs.vector.Vector!ubyte; /************************************************************************************************************************ *Entity manager is responsible for everything. +* +*Entity manager can be in three states: +* - registration: time between beginRegister() and endRegister() calls. +* - update: time between being() and end() calls. +* - default: when it's not in registration or update time +* +*Manager can be only in one state simultaneously. +* +*Manager must be initialized before use. There is global instance of EntityManager: EntityManager.instance or gEM as alias. +* +*Registration process consist of registration of passes, systems, entities and events. +* +*Pass is group of system which should be used inside one update() call. Passes are added as name (string) and can be referenced by name or id.
      +*System is structure responsible for update of specified group of entities. System consist of EntitiesData structure which contain components used +*by system and some callback. Main callback is onUpdate() which is called by update() entity manager function. Other callbacks are used as listeners for +*adding entites, tracking system lifetime and events handling.
      +*Component is basicly small fraction of data which is considered to be used as whole. In best scenario every byte of component is used when it's refered to. +*In practice sometimes it's better to join data into one component even if it's can be accessed separetly.
      +*Events are structures with data used to handle events. Event can contain for exmaple one floating point number used as damage dealt to entity.
      +*Entity is group of components. In memory entity is only ID which makes it's possible to take it's components. Components are grouped into chunks, and +*grouped by component type so entity can be fracted in big memory chunk.
      +* +*There is two types of update: +*
      - update(): function used to call update pass. +*
      - updateMT(): function used to call update pass multithreaded. This call only generates jobs which must be called by user. */ export struct EntityManager { @@ -353,7 +377,7 @@ export struct EntityManager static if (!(hasMember!(Sys, "system_id")) || !is(typeof(Sys.system_id) == ushort)) { - static assert(0); //, "Add \"mixin ECS.System;\" in top of system structure;"); //"System should have \"__gshared ushort system_id"); + static assert(0); //, "Add \"mixin ECS.System;\" in top of system structure;"); } static if (!(hasMember!(Sys, "EntitiesData"))) @@ -463,11 +487,11 @@ export struct EntityManager m_req[m_req_counter++] = info; } - CompInfo[32] m_readonly; - CompInfo[32] m_mutable; - CompInfo[32] m_excluded; - CompInfo[32] m_optional; - CompInfo[32] m_req; + CompInfo[64] m_readonly; + CompInfo[64] m_mutable; + CompInfo[64] m_excluded; + CompInfo[64] m_optional; + CompInfo[64] m_req; uint m_readonly_counter; uint m_mutable_counter; @@ -635,7 +659,12 @@ export struct EntityManager foreach (iii, comp_info; components_info.req) { ushort comp = components_map.get(cast(char[]) comp_info.type, ushort.max); - assert(comp != ushort.max); //, "Can't register system \""~Sys.stringof~"\" due to non existing component \""~comp_info.type~"\"."); + version (betterC) + assert(comp != ushort.max, + "Can't register system due to non existing component."); + else + assert(comp != ushort.max, "Can't register system \"" ~ Sys.stringof + ~ "\" due to non existing component \"" ~ comp_info.type ~ "\"."); system.m_components[iii] = comp; } foreach (iii, comp_info; components_info.excluded) @@ -1319,7 +1348,7 @@ export struct EntityManager *Allocate EntityTemplate with all components from entity witch it's data and returns pointer to it. * *Params: - *id = ID of entity from which should be created template + *entity_id = ID of entity from which should be created template *fill_default = if true, components will be filled with default data, instead entity data will be taken */ export EntityTemplate* allocateTemplate(EntityID entity_id, bool fill_default = false) @@ -1756,7 +1785,7 @@ export struct EntityManager Entity* new_entity = cast(Entity*) start; new_entity.id = entity.id; - new_entity.updateID(); + id_manager.update(*new_entity); //new_entity.updateID(); uint ind = block.entityIndex(entity); @@ -1876,7 +1905,7 @@ export struct EntityManager Entity* new_entity = cast(Entity*) start; new_entity.id = entity.id; - new_entity.updateID(); + id_manager.update(*new_entity); //new_entity.updateID(); uint j = 0; uint k = 0; @@ -2001,7 +2030,7 @@ export struct EntityManager *instead of pointer. * *Params: - *tmpl = pointer entity template allocated by EntityManager. + *id = ID of entity to be copyied. */ export Entity* addEntityCopy(EntityID id) { @@ -2044,7 +2073,7 @@ export struct EntityManager //add_mutex.lock_nothrow(); new_entity.id = id_manager.getNewID(); //add_mutex.unlock_nothrow(); - new_entity.updateID(); + id_manager.update(*new_entity); //new_entity.updateID(); return new_entity; } @@ -2094,7 +2123,7 @@ export struct EntityManager //add_mutex.lock_nothrow(); entity.id = id_manager.getNewID(); //add_mutex.unlock_nothrow(); - entity.updateID(); + id_manager.update(*entity); //entity.updateID(); return entity; } @@ -2237,7 +2266,7 @@ export struct EntityManager block = info.last_block; entity.id = *cast(EntityID*)(block.dataBegin() + block.entities_count * EntityID.sizeof); - entity.updateID(); + id_manager.update(*entity); //entity.updateID(); } block = info.last_block; diff --git a/source/ecs/std.d b/source/ecs/std.d index 81eed0a..a3a4f5e 100644 --- a/source/ecs/std.d +++ b/source/ecs/std.d @@ -1,3 +1,7 @@ +/************************************************************************************************************************ +*It's internal code! +*This module contain implementation of standard functionality. +*/ module ecs.std; version(Emscripten)version = ECSEmscripten; diff --git a/source/ecs/system.d b/source/ecs/system.d index 54b3555..35eb996 100644 --- a/source/ecs/system.d +++ b/source/ecs/system.d @@ -18,6 +18,8 @@ import ecs.manager; *
      -void onDestroy(); *
      -void onAddEntity(EntitesData); *
      -void onRemoveEntity(EntitiesData); +*
      -void onChangeEntity(EntitiesData); +*
      -void handleEvent(Entity*, Event); */ struct System { @@ -82,14 +84,14 @@ struct System return cast(const(char)[]) m_name; } +package: + struct EventCaller { ushort id; void* callback; } -package: - ///should system be executed in current update? bool m_execute = true; ///system id From 3eb124ae4688ba74971706010352e1ab261e885f Mon Sep 17 00:00:00 2001 From: mmcomando Date: Sat, 21 Mar 2020 19:07:09 +0000 Subject: [PATCH 091/217] Add GitLab CI script --- .gitlab-ci.yml | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 .gitlab-ci.yml diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml new file mode 100644 index 0000000..56089c0 --- /dev/null +++ b/.gitlab-ci.yml @@ -0,0 +1,6 @@ +test_dmd: + stage: test + image: mmcomando/ecs_enviroment + script: + - source $(/script/dlang/install.sh dmd -a) && dmd --version + - source $(/script/dlang/install.sh dmd -a) && dub test From 67a785f2dc1ad336abd7485ac07e9bb012d627eb Mon Sep 17 00:00:00 2001 From: mmcomando Date: Sat, 21 Mar 2020 23:13:08 +0100 Subject: [PATCH 092/217] Add betterC test runner --- dub.json | 16 ++++ tests/runner.d | 206 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 222 insertions(+) create mode 100644 tests/runner.d diff --git a/dub.json b/dub.json index 87b9b7b..b7de52f 100755 --- a/dub.json +++ b/dub.json @@ -86,6 +86,22 @@ "lflags-gdc": [ "-lpthread" ] + }, + + { + "name": "unittest-runner", + "targetType" : "executable", + "dflags": [ + "-betterC" + ], + "sourceFiles":[ + "tests/runner.d" + ], + "excludedSourceFiles":[ + "source\/win_dll.d" + ] } + + ] } \ No newline at end of file diff --git a/tests/runner.d b/tests/runner.d new file mode 100644 index 0000000..a31b1a6 --- /dev/null +++ b/tests/runner.d @@ -0,0 +1,206 @@ +module tests.runner; + +import core.stdc.stdio; +import core.stdc.string; +import core.sys.posix.setjmp; + +import ecs.vector; +import ecs.std; + +unittest +{ + assert(0, "AAAAAAAA"); +} + +enum int ASSERTED = 123; +enum string OUT_FILE = "test_report.xml"; + +__gshared jmp_buf gEnvBuffer; +__gshared TestSuite[2] gSuites; +__gshared AssertInfo gAssertInfo; + +struct AssertInfo +{ + const(char)* msg; + const(char)* file; + int line; +} + +extern (C) void __assert(const char* msg, const char* file, int line) +{ + gAssertInfo = AssertInfo(msg, file, line); + longjmp(gEnvBuffer, ASSERTED); +} + +struct Test +{ + string file; + string msg; + int fileLine; + string name; + int time; + bool passed; + bool executed; +} + +struct TestSuite +{ + string name; + Vector!Test tests; +} + +void writeToFile(string data) +{ + auto file = fopen(OUT_FILE, "a"); + fwrite(data.ptr, 1, data.length, file); + fclose(file); + +} + +void writeToFile(int num) +{ + auto file = fopen(OUT_FILE, "a"); + fprintf(file, "%d", num); + fclose(file); +} + +void writeResulStart(int num) +{ + // Clear file + auto file = fopen(OUT_FILE, "w"); + fclose(file); + + writeToFile("\n"); + +} + +void writeResulEnd() +{ + writeToFile("\n"); +} + +void writeResult(ref TestSuite suite, ref Test result) +{ + writeToFile(" \n"); + } + else + { + writeToFile(">\n"); + writeToFile(" "); + + if (result.file.length != 0) + { + writeToFile("Assert! File: "); + writeToFile(result.file[0 .. $ - 1]); + writeToFile(":"); + writeToFile(result.fileLine); + writeToFile(" Message: "); + writeToFile(result.msg[0 .. $ - 1]); + } + else + { + + writeToFile("No Message"); + } + + writeToFile("\n"); + writeToFile(" \n"); + } + +} + +void writeTests(TestSuite[] suites) +{ + writeResulStart(cast(int) suites.length); + foreach (ref TestSuite suite; suites) + { + foreach (ref Test test; suite.tests) + { + writeResult(suite, test); + } + } + writeResulEnd(); +} + +string copyString(const char* str) +{ + auto length = strlen(str); + char[] arr = cast(char[]) str[0 .. length + 1]; + return cast(string) Mallocator.makeArray(arr); +} + +void runTestSuite(alias testModule)(ref TestSuite suite) +{ + suite.name = testModule.stringof; + foreach (index, testDelegate; __traits(getUnitTests, testModule)) + { + suite.tests[index].executed = true; + writeTests(gSuites); // Save executed info + + // Save calling environment for longjmp + int jmpRet = setjmp(gEnvBuffer); + + if (jmpRet == ASSERTED) + { + suite.tests[index].passed = false; + suite.tests[index].file = copyString(gAssertInfo.file); + suite.tests[index].fileLine = gAssertInfo.line; + suite.tests[index].msg = copyString(gAssertInfo.msg); + } + else + { + testDelegate(); + suite.tests[index].passed = true; + } + } +} + +void addTestSuite(alias testModule)(ref TestSuite suite) +{ + suite.name = testModule.stringof; + foreach (index, testDelegate; __traits(getUnitTests, testModule)) + { + enum attributes = __traits(getAttributes, testDelegate); + static if (attributes.length == 0) + { + enum string testName = "No name"; + } + else + { + enum string testName = attributes[0]; + + } + Test test; + test.name = testName; + + suite.tests ~= test; + } +} + +void main() +{ + addTestSuite!(tests.runner)(gSuites[0]); + addTestSuite!(ecs.id_manager)(gSuites[1]); + + writeTests(gSuites); // Save results in case that there are no tests + + runTestSuite!(tests.runner)(gSuites[0]); + runTestSuite!(ecs.id_manager)(gSuites[1]); + + writeTests(gSuites); // Save result of last test +} From 3c4f2be9c6075058787f5b67d3420bf28acaf88d Mon Sep 17 00:00:00 2001 From: mmcomando Date: Sat, 21 Mar 2020 22:18:38 +0000 Subject: [PATCH 093/217] Update .gitlab-ci.yml --- .gitlab-ci.yml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 56089c0..25b0820 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -3,4 +3,7 @@ test_dmd: image: mmcomando/ecs_enviroment script: - source $(/script/dlang/install.sh dmd -a) && dmd --version - - source $(/script/dlang/install.sh dmd -a) && dub test + - source $(/script/dlang/install.sh dmd -a) && dub -c unittest-runner -b unittest + artifacts: + reports: + junit: test_report.xml From a080a6d415eafa881edf2fd423e1c45f9e204df3 Mon Sep 17 00:00:00 2001 From: Mergul Date: Sat, 28 Mar 2020 22:34:11 +0100 Subject: [PATCH 094/217] -fixed bug with adding components -optimize adding and removing components --- dub.json | 3 -- source/ecs/manager.d | 90 ++++++++++++++++++++++++++++++-------------- 2 files changed, 61 insertions(+), 32 deletions(-) diff --git a/dub.json b/dub.json index 87b9b7b..02ea4b2 100755 --- a/dub.json +++ b/dub.json @@ -7,9 +7,6 @@ "copyright": "Copyright © 2018-2019, Michał Masiukiewicz, Dawid Masiukiewicz", "license": "BSD", "sourcePaths" : ["source\/"], - "dflagss": [ - "-betterC" - ], "excludedSourceFiles":[ "source\/ecs\/traits.d" ], diff --git a/source/ecs/manager.d b/source/ecs/manager.d index 747e1ed..ae94cf7 100644 --- a/source/ecs/manager.d +++ b/source/ecs/manager.d @@ -1499,6 +1499,15 @@ export struct EntityManager addSystemCaller(*info, cast(uint) i); } + info.comp_add_info = Mallocator.makeArray!(EntityInfo*)(instance.components.length); + info.comp_rem_info = Mallocator.makeArray!(EntityInfo*)(instance.components.length, info); + + foreach(comp; info.components) + { + info.comp_add_info[comp] = info; + info.comp_rem_info[comp] = null; + } + entities_infos.add(info.components, info); generateListeners(info); @@ -1762,10 +1771,22 @@ export struct EntityManager EntitiesBlock* block = getMetaData(entity); EntityInfo* info = block.type_info; - qsort(del_ids.ptr, del_ids.length, ushort.sizeof, &compareUShorts); + //remove non-existing components + uint num = cast(uint)del_ids.length; + foreach_reverse(i; 0 .. num) + { + if(info.deltas.length <= del_ids[i] || info.deltas[del_ids[i]] == 0) + { + num--; + del_ids[i] = del_ids[num]; + } + } + + if(num == 0)return; + del_ids = del_ids[0 .. num]; - ushort[] ids = (cast(ushort*) alloca(ushort.sizeof * (info.components.length)))[0 - .. info.components.length]; + //sort components + qsort(del_ids.ptr, del_ids.length, ushort.sizeof, &compareUShorts); EntityInfo* new_info = info; @@ -1774,10 +1795,8 @@ export struct EntityManager new_info = new_info.getNewInfoRemove(id); } - if (new_info == info) - return; - - //EntityInfo* new_info = getEntityInfo(ids[0 .. j]); + /*if (new_info == info) + return;*/ EntitiesBlock* new_block = findBlockWithFreeSpace(new_info); @@ -1785,7 +1804,7 @@ export struct EntityManager Entity* new_entity = cast(Entity*) start; new_entity.id = entity.id; - id_manager.update(*new_entity); //new_entity.updateID(); + id_manager.update(*new_entity); uint ind = block.entityIndex(entity); @@ -1864,6 +1883,18 @@ export struct EntityManager EntitiesBlock* block = getMetaData(entity); EntityInfo* info = block.type_info; + foreach_reverse(i; 0 .. num) + { + if(info.deltas.length > new_ids[i] && info.deltas[new_ids[i]] != 0) + { + num--; + new_ids[i] = new_ids[num]; + } + } + + if(num == 0)return; + new_ids = new_ids[0 .. num]; + foreach (int i; 0 .. num) { ushort min = new_ids[i]; @@ -1893,9 +1924,10 @@ export struct EntityManager { new_info = new_info.getNewInfoAdd(id); } - - if (new_info == info) - return; + + assert(new_info != info); + /*if (new_info == info) + return;*/ //EntityInfo* new_info = getEntityInfo(ids[0 .. len]); @@ -1922,28 +1954,25 @@ export struct EntityManager } } - foreach (ref id; new_info.components) //ids[0 .. len]) + foreach (id; new_info.components) //ids[0 .. len]) { void* dst = cast(void*) new_block + new_info.deltas[id] + ( new_block.entities_count) * components[id].size; uint size = components[id].size; + if (k >= new_ids.length) { memcpy(dst, cast(void*) block + info.deltas[id] + ind * size, size); j++; } - else if (j >= info.components.length) - { - memcpy(dst, data_pointers[k], size); - k++; - } - else if (id == new_ids[k]) + else if (j >= info.components.length || id == new_ids[k]) { memcpy(dst, data_pointers[k], size); k++; } else { + assert(id != new_ids[0]); memcpy(dst, cast(void*) block + info.deltas[id] + ind * size, size); j++; } @@ -1987,11 +2016,11 @@ export struct EntityManager void addComponents(Components...)(const EntityID entity_id, Components comps) nothrow @nogc { const uint num = Components.length; - Entity* entity = id_manager.getEntityPointer(entity_id); - EntitiesBlock* block = getMetaData(entity); - EntityInfo* info = block.type_info; - ushort[] ids = (cast(ushort*) alloca(ushort.sizeof * (info.components.length + num)))[0 - .. info.components.length + num]; + //Entity* entity = id_manager.getEntityPointer(entity_id); + //EntitiesBlock* block = getMetaData(entity); + //EntityInfo* info = block.type_info; + /*ushort[] ids = (cast(ushort*) alloca(ushort.sizeof * (info.components.length + num)))[0 + .. info.components.length + num];*/ ushort[num] new_ids; static foreach (i, comp; Components) @@ -2763,7 +2792,7 @@ export struct EntityManager EntityInfo* getNewInfoAdd(ushort id) { - if (comp_add_info.length < id) + if (comp_add_info.length <= id) { EntityInfo*[] new_infos = Mallocator.makeArray!(EntityInfo*)( instance.components.length); @@ -2789,12 +2818,15 @@ export struct EntityManager { ids[len++] = comp; } - else if (id == comp) - return &this; else { ids[len++] = id; ids[len++] = comp; + foreach (comp2; components[len - 1 .. $]) + { + ids[len++] = comp2; + } + break; } } if (id > components[$ - 1]) @@ -2802,7 +2834,7 @@ export struct EntityManager assert(len == components.length + 1); - EntityInfo* new_info = instance.getEntityInfo(ids[0 .. len]); + EntityInfo* new_info = instance.getEntityInfo(ids);//[0 .. len]); comp_add_info[id] = new_info; return new_info; @@ -2810,10 +2842,10 @@ export struct EntityManager EntityInfo* getNewInfoRemove(ushort id) { - if (comp_rem_info.length < id) + if (comp_rem_info.length <= id) { EntityInfo*[] new_infos = Mallocator.makeArray!(EntityInfo*)( - instance.components.length); + instance.components.length, &this); if (comp_rem_info !is null) { //new_infos[0 .. comp_rem_info.length] = comp_rem_info[0 .. $]; From 19687b9f88fca07efa70568941feba96a99ed13f Mon Sep 17 00:00:00 2001 From: Mergul Date: Sat, 4 Apr 2020 13:58:31 +0200 Subject: [PATCH 095/217] -fixed critical bug with adding components -some fixes -minor optimization -added debug assert test --- source/ecs/core.d | 6 +++--- source/ecs/manager.d | 42 ++++++++++++++++++++++++++---------------- 2 files changed, 29 insertions(+), 19 deletions(-) diff --git a/source/ecs/core.d b/source/ecs/core.d index dde39a5..91c9065 100644 --- a/source/ecs/core.d +++ b/source/ecs/core.d @@ -45,7 +45,7 @@ static struct ECS */ mixin template System(uint jobs_count = 32) { - __gshared ushort system_id; + __gshared ushort system_id = ushort.max; uint __ecs_jobs_count = jobs_count; } @@ -54,7 +54,7 @@ static struct ECS */ mixin template Component() { - __gshared ushort component_id; + __gshared ushort component_id = ushort.max; } /************************************************************************************************************************ @@ -62,7 +62,7 @@ static struct ECS */ mixin template Event() { - __gshared ushort event_id; + __gshared ushort event_id = ushort.max; EntityID entity_id; } diff --git a/source/ecs/manager.d b/source/ecs/manager.d index ae94cf7..0e91095 100644 --- a/source/ecs/manager.d +++ b/source/ecs/manager.d @@ -770,13 +770,15 @@ export struct EntityManager else enum OnUpdateOverloadNum = -1; //enum HasOnUpdate = (hasMember!(Sys, "onUpdate") && checkOnUpdateParams()); + enum IsEmpty = components_info.req.length == 0 && components_info.optional.length == 0 + && components_info.excluded.length == 0 && components_info.entites_array.length == 0; - static if (components_info.req.length == 0 && components_info.optional.length == 0) + static if (IsEmpty) system.m_empty = true; static if (OnUpdateOverloadNum != -1) { - static if (components_info.req.length != 0 || components_info.optional.length != 0) + static if (!IsEmpty) { static void callUpdate(ref CallData data) { @@ -972,6 +974,8 @@ export struct EntityManager */ export System* getSystem(ushort id) nothrow @nogc { + if (id >= systems.length) + return null; return &systems[id]; } @@ -980,6 +984,8 @@ export struct EntityManager */ Sys* getSystem(Sys)() nothrow @nogc { + if (Sys.system_id >= systems.length) + return null; return cast(Sys*) systems[Sys.system_id].m_system_pointer; } @@ -1404,6 +1410,7 @@ export struct EntityManager uint j = 1; foreach (i; 1 .. ids.length) { + assert(ids[i] != ushort.max); if (ids[i] != ids[j - 1]) { ids[j] = ids[i]; @@ -1500,9 +1507,10 @@ export struct EntityManager } info.comp_add_info = Mallocator.makeArray!(EntityInfo*)(instance.components.length); - info.comp_rem_info = Mallocator.makeArray!(EntityInfo*)(instance.components.length, info); + info.comp_rem_info = Mallocator.makeArray!(EntityInfo*)(instance.components.length, + info); - foreach(comp; info.components) + foreach (comp; info.components) { info.comp_add_info[comp] = info; info.comp_rem_info[comp] = null; @@ -1772,17 +1780,18 @@ export struct EntityManager EntityInfo* info = block.type_info; //remove non-existing components - uint num = cast(uint)del_ids.length; - foreach_reverse(i; 0 .. num) + uint num = cast(uint) del_ids.length; + foreach_reverse (i; 0 .. num) { - if(info.deltas.length <= del_ids[i] || info.deltas[del_ids[i]] == 0) + if (info.deltas.length <= del_ids[i] || info.deltas[del_ids[i]] == 0) { num--; del_ids[i] = del_ids[num]; } } - - if(num == 0)return; + + if (num == 0) + return; del_ids = del_ids[0 .. num]; //sort components @@ -1883,16 +1892,17 @@ export struct EntityManager EntitiesBlock* block = getMetaData(entity); EntityInfo* info = block.type_info; - foreach_reverse(i; 0 .. num) + foreach_reverse (i; 0 .. num) { - if(info.deltas.length > new_ids[i] && info.deltas[new_ids[i]] != 0) + if (info.deltas.length > new_ids[i] && info.deltas[new_ids[i]] != 0) { num--; new_ids[i] = new_ids[num]; } } - - if(num == 0)return; + + if (num == 0) + return; new_ids = new_ids[0 .. num]; foreach (int i; 0 .. num) @@ -1924,7 +1934,7 @@ export struct EntityManager { new_info = new_info.getNewInfoAdd(id); } - + assert(new_info != info); /*if (new_info == info) return;*/ @@ -2825,7 +2835,7 @@ export struct EntityManager foreach (comp2; components[len - 1 .. $]) { ids[len++] = comp2; - } + } break; } } @@ -2834,7 +2844,7 @@ export struct EntityManager assert(len == components.length + 1); - EntityInfo* new_info = instance.getEntityInfo(ids);//[0 .. len]); + EntityInfo* new_info = instance.getEntityInfo(ids); comp_add_info[id] = new_info; return new_info; From c63f3a97277aa7ecd050fccf742e90af301b5343 Mon Sep 17 00:00:00 2001 From: Mergul Date: Sat, 4 Apr 2020 22:11:52 +0200 Subject: [PATCH 096/217] -added some tests -improved test runner --- dub.json | 10 ++--- source/ecs/id_manager.d | 32 -------------- tests/basic.d | 2 + tests/id_manager.d | 36 ++++++++++++++++ tests/runner.d | 96 ++++++++++++++++++++++++++++++++++++----- tests/vector.d | 18 ++++++++ 6 files changed, 147 insertions(+), 47 deletions(-) create mode 100644 tests/basic.d create mode 100644 tests/id_manager.d create mode 100644 tests/vector.d diff --git a/dub.json b/dub.json index 1df36ba..3bf07c4 100755 --- a/dub.json +++ b/dub.json @@ -17,7 +17,7 @@ }, { "name" : "tests", - "sourcePaths" : ["source\/","tests\/"], + "sourceFiles" : ["tests/tests.d"], "targetType" : "executable", "excludedSourceFiles":[ "source\/win_dll.d" @@ -91,11 +91,11 @@ "dflags": [ "-betterC" ], - "sourceFiles":[ - "tests/runner.d" - ], + "sourcePaths": ["source/","tests/"], + "mainSourceFile":"tests/runner.d", "excludedSourceFiles":[ - "source\/win_dll.d" + "source\/win_dll.d", + "tests/tests.d" ] } diff --git a/source/ecs/id_manager.d b/source/ecs/id_manager.d index 475eb94..4f5a949 100644 --- a/source/ecs/id_manager.d +++ b/source/ecs/id_manager.d @@ -253,35 +253,3 @@ private: align(64) shared uint m_last_id = 0; align(64) shared int m_stack_top = -1; } - -unittest -{ - IDManager manager; - manager.initialize(); - EntityID id1 = manager.getNewID(); - EntityID id2 = manager.getNewID(); - EntityID id3 = manager.getNewID(); - - assert(id1 == EntityID(1, 0)); - assert(id2 == EntityID(2, 0)); - assert(id3 == EntityID(3, 0)); - - manager.optimize(); - manager.releaseID(id2); - manager.releaseID(id1); - - id2 = manager.getNewID(); - id1 = manager.getNewID(); - - Entity e; - e.id = id3; - manager.update(e); - - assert(id1 == EntityID(2, 1)); - assert(id2 == EntityID(1, 1)); - assert(id3 == EntityID(3, 0)); - assert(manager.isExist(id3)); - assert(!manager.isExist(EntityID(1, 0))); - assert(!manager.isExist(EntityID(0, 0))); - manager.deinitialize(); -} diff --git a/tests/basic.d b/tests/basic.d new file mode 100644 index 0000000..c359fe3 --- /dev/null +++ b/tests/basic.d @@ -0,0 +1,2 @@ +module tests.basic; + diff --git a/tests/id_manager.d b/tests/id_manager.d new file mode 100644 index 0000000..6601582 --- /dev/null +++ b/tests/id_manager.d @@ -0,0 +1,36 @@ +module tests.id_manager; + +import ecs.id_manager; +import ecs.entity; + +unittest +{ + IDManager manager; + manager.initialize(); + EntityID id1 = manager.getNewID(); + EntityID id2 = manager.getNewID(); + EntityID id3 = manager.getNewID(); + + assert(id1 == EntityID(1, 0)); + assert(id2 == EntityID(2, 0)); + assert(id3 == EntityID(3, 0)); + + manager.optimize(); + manager.releaseID(id2); + manager.releaseID(id1); + + id2 = manager.getNewID(); + id1 = manager.getNewID(); + + Entity e; + e.id = id3; + manager.update(e); + + assert(id1 == EntityID(2, 1)); + assert(id2 == EntityID(1, 1)); + assert(id3 == EntityID(3, 0)); + assert(manager.isExist(id3)); + assert(!manager.isExist(EntityID(1, 0))); + assert(!manager.isExist(EntityID(0, 0))); + manager.deinitialize(); +} \ No newline at end of file diff --git a/tests/runner.d b/tests/runner.d index 2b8597f..9271d7c 100644 --- a/tests/runner.d +++ b/tests/runner.d @@ -16,9 +16,9 @@ unittest enum int ASSERTED = 123; enum string OUT_FILE = "test_report.xml"; -__gshared jmp_buf gEnvBuffer; -__gshared TestSuite[2] gSuites; -__gshared AssertInfo gAssertInfo; +static jmp_buf gEnvBuffer; +//__gshared TestSuite[4] gSuites; +static AssertInfo gAssertInfo; struct AssertInfo { @@ -47,6 +47,8 @@ struct Test struct TestSuite { string name; + uint passed = 0; + uint failed = 0; Vector!Test tests; } @@ -193,15 +195,89 @@ void addTestSuite(alias testModule)(ref TestSuite suite) } } -void main() +struct TestRunner(Args...) { - addTestSuite!(tests.runner)(gSuites[0]); - addTestSuite!(ecs.id_manager)(gSuites[1]); + TestSuite[Args.length] suites; + uint passed = 0; + uint failed = 0; - writeTests(gSuites); // Save results in case that there are no tests + void runTests() + { + foreach(i, module_; Args) + { + TestSuite* suite = &suites[i]; + suite.name = module_.stringof; + foreach (index, unittest_; __traits(getUnitTests, module_)) + { + enum attributes = __traits(getAttributes, unittest_); + Test test; - runTestSuite!(tests.runner)(gSuites[0]); - runTestSuite!(ecs.id_manager)(gSuites[1]); + static if (attributes.length == 0)test.name = "None"; + else test.name = attributes[0]; - writeTests(gSuites); // Save result of last test + // Save calling environment for longjmp + int jmpRet = setjmp(gEnvBuffer); + + if (jmpRet == ASSERTED) + { + passed = false; + test.passed = false; + test.file = copyString(gAssertInfo.file); + test.fileLine = gAssertInfo.line; + test.msg = copyString(gAssertInfo.msg); + } + else + { + unittest_(); + test.passed = true; + } + + if(test.passed)suite.passed++; + else suite.failed++; + suite.tests ~= test; + } + passed += suite.passed; + failed += suite.failed; + } + } + + void writeFile() + { + writeTests(suites); + } + + void writeOutput() + { + import core.stdc.stdio; + foreach(ref TestSuite suite; suites) + { + printf("Suite: \"%s\" Passed: %u/%u\n", suite.name.ptr, suite.passed, suite.passed + suite.failed); + foreach(ref Test test;suite.tests) + { + if(!test.passed) + { + printf("\tTest: \"%s\" Failed! Line: %u Message: %s\n",test.name.ptr, test.fileLine, test.msg.ptr); + } + } + } + printf("Passed: %u/%u tests.\n", passed, passed+failed); + } +} + +int main() +{ + import tests.vector; + import tests.id_manager; + import tests.basic; + + TestRunner!(tests.runner, tests.id_manager, tests.vector, tests.basic) runner; + + runner.runTests(); + + runner.writeFile(); + + runner.writeOutput(); + + if(!runner.failed)return 0; + else return 1; } diff --git a/tests/vector.d b/tests/vector.d new file mode 100644 index 0000000..9b76d0b --- /dev/null +++ b/tests/vector.d @@ -0,0 +1,18 @@ +module tests.vector; + +import ecs.simple_vector; +//import ecs.vector; + +unittest +{ + SimpleVector vector; + vector.add(cast(ubyte[])"a"); + vector.add(cast(ubyte[])"bsdf"); + assert(vector[0..5] == cast(ubyte[])"absdf"); + assert(vector[4] == 'f'); + assert(vector[] == cast(ubyte[])"absdf"); + assert(vector[$ - 1] == 'f'); + + vector.clear(); + assert(vector.length == 0); +} \ No newline at end of file From 09633d1056299c056083ba75bd677cf3242d3711 Mon Sep 17 00:00:00 2001 From: Mergul Date: Sat, 4 Apr 2020 22:20:08 +0200 Subject: [PATCH 097/217] -removed not used code and testing (failure) unittest --- tests/runner.d | 54 -------------------------------------------------- 1 file changed, 54 deletions(-) diff --git a/tests/runner.d b/tests/runner.d index 9271d7c..1149ee7 100644 --- a/tests/runner.d +++ b/tests/runner.d @@ -8,16 +8,10 @@ import core.sys.posix.setjmp; import ecs.vector; import ecs.std; -unittest -{ - assert(0, "AAAAAAAA"); -} - enum int ASSERTED = 123; enum string OUT_FILE = "test_report.xml"; static jmp_buf gEnvBuffer; -//__gshared TestSuite[4] gSuites; static AssertInfo gAssertInfo; struct AssertInfo @@ -147,54 +141,6 @@ string copyString(const char* str) return cast(string) Mallocator.makeArray(arr); } -void runTestSuite(alias testModule)(ref TestSuite suite) -{ - suite.name = testModule.stringof; - foreach (index, testDelegate; __traits(getUnitTests, testModule)) - { - suite.tests[index].executed = true; - writeTests(gSuites); // Save executed info - - // Save calling environment for longjmp - int jmpRet = setjmp(gEnvBuffer); - - if (jmpRet == ASSERTED) - { - suite.tests[index].passed = false; - suite.tests[index].file = copyString(gAssertInfo.file); - suite.tests[index].fileLine = gAssertInfo.line; - suite.tests[index].msg = copyString(gAssertInfo.msg); - } - else - { - testDelegate(); - suite.tests[index].passed = true; - } - } -} - -void addTestSuite(alias testModule)(ref TestSuite suite) -{ - suite.name = testModule.stringof; - foreach (index, testDelegate; __traits(getUnitTests, testModule)) - { - enum attributes = __traits(getAttributes, testDelegate); - static if (attributes.length == 0) - { - enum string testName = "No name"; - } - else - { - enum string testName = attributes[0]; - - } - Test test; - test.name = testName; - - suite.tests ~= test; - } -} - struct TestRunner(Args...) { TestSuite[Args.length] suites; From d485824ab589f3d715486a278c3d6684c882cdb2 Mon Sep 17 00:00:00 2001 From: Mergul Date: Sun, 5 Apr 2020 21:11:38 +0200 Subject: [PATCH 098/217] -better JUnit generation -testing unittest failure --- tests/runner.d | 84 +++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 80 insertions(+), 4 deletions(-) diff --git a/tests/runner.d b/tests/runner.d index 1149ee7..84b6646 100644 --- a/tests/runner.d +++ b/tests/runner.d @@ -6,8 +6,14 @@ import core.stdc.string; import core.sys.posix.setjmp; import ecs.vector; +import ecs.simple_vector; import ecs.std; +unittest +{ + assert(0,"This will fail!"); +} + enum int ASSERTED = 123; enum string OUT_FILE = "test_report.xml"; @@ -33,9 +39,10 @@ struct Test string msg; int fileLine; string name; + //string classname; int time; bool passed; - bool executed; + //bool executed; } struct TestSuite @@ -87,8 +94,8 @@ void writeResult(ref TestSuite suite, ref Test result) writeToFile("\" time=\""); writeToFile(result.time); writeToFile("\" "); - writeToFile(" executed=\""); - writeToFile(cast(int) result.executed); + //writeToFile(" executed=\""); + //writeToFile(cast(int) result.executed); writeToFile("\" "); if (result.passed) @@ -147,6 +154,71 @@ struct TestRunner(Args...) uint passed = 0; uint failed = 0; + SimpleVector junit; + + void write(string txt) + { + junit.add(cast(ubyte[]) txt); + } + + void write(uint num) + { + ubyte[20] buffer; + int len; + len = sprintf(cast(char*)buffer.ptr, "%u", num); + junit.add(buffer[0..len]); + } + + void generateJUnit() + { + write("\n\n"); + + write("\n"); + + foreach(ref TestSuite suite; suites) + { + write("\t\n"); + + foreach(ref Test test; suite.tests) + { + write("\t\t\n"); + if(test.msg) + { + write("\t\t\t\n"); + write("\t\t\t\tAssert! File: "); + write(test.file[0 .. $ - 1]); + write(":"); + write(test.fileLine); + write(" Message: "); + write(test.msg[0 .. $ - 1]); + write("\n"); + write("\t\t\t\n"); + } + write("\t\t\n"); + } + + write("\t\n"); + } + + write(""); + } + void runTests() { foreach(i, module_; Args) @@ -189,7 +261,11 @@ struct TestRunner(Args...) void writeFile() { - writeTests(suites); + if(junit.length == 0)generateJUnit(); + auto file = fopen(OUT_FILE, "w"); + fwrite(junit.data.ptr,junit.length,1,file); + fclose(file); + //writeTests(suites); } void writeOutput() From 7b053a6abc85c68afc4efeca9053e2ae5d3afd16 Mon Sep 17 00:00:00 2001 From: Mergul Date: Sun, 5 Apr 2020 21:16:11 +0200 Subject: [PATCH 099/217] Added better formating --- tests/runner.d | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/runner.d b/tests/runner.d index 84b6646..d85fdcf 100644 --- a/tests/runner.d +++ b/tests/runner.d @@ -200,15 +200,15 @@ struct TestRunner(Args...) { write("\t\t\t\n"); - write("\t\t\t\tAssert! File: "); + write("\">"); + write("Assert! File: "); write(test.file[0 .. $ - 1]); write(":"); write(test.fileLine); write(" Message: "); write(test.msg[0 .. $ - 1]); - write("\n"); - write("\t\t\t\n"); + //write("\n"); + write("\n"); } write("\t\t\n"); } From 8f5f2f3bafd817ed7a311dda0352bb19bae3407f Mon Sep 17 00:00:00 2001 From: Mergul Date: Sun, 5 Apr 2020 21:23:12 +0200 Subject: [PATCH 100/217] Removed unused code and failure test --- source/ecs/entity.d | 5 -- tests/runner.d | 109 +++----------------------------------------- 2 files changed, 6 insertions(+), 108 deletions(-) diff --git a/source/ecs/entity.d b/source/ecs/entity.d index 699bf61..f3a8d97 100644 --- a/source/ecs/entity.d +++ b/source/ecs/entity.d @@ -42,11 +42,6 @@ struct Entity uint ind = cast(uint)((cast(void*)&this - block.dataBegin()) / EntityID.sizeof()); return cast(T*)(cast(void*)block + info.deltas[T.component_id] + ind * T.sizeof); } - - /*package void updateID() nothrow @nogc - { - EntityManager.instance.id_manager.update(this); - }*/ } /************************************************************************************************************************ diff --git a/tests/runner.d b/tests/runner.d index d85fdcf..4aa2ed1 100644 --- a/tests/runner.d +++ b/tests/runner.d @@ -9,11 +9,6 @@ import ecs.vector; import ecs.simple_vector; import ecs.std; -unittest -{ - assert(0,"This will fail!"); -} - enum int ASSERTED = 123; enum string OUT_FILE = "test_report.xml"; @@ -37,12 +32,11 @@ struct Test { string file; string msg; - int fileLine; + int file_line; string name; //string classname; int time; bool passed; - //bool executed; } struct TestSuite @@ -53,94 +47,6 @@ struct TestSuite Vector!Test tests; } -void writeToFile(string data) -{ - auto file = fopen(OUT_FILE, "a"); - fwrite(data.ptr, 1, data.length, file); - fclose(file); - -} - -void writeToFile(int num) -{ - auto file = fopen(OUT_FILE, "a"); - fprintf(file, "%d", num); - fclose(file); -} - -void writeResulStart(int num) -{ - // Clear file - auto file = fopen(OUT_FILE, "w"); - fclose(file); - - writeToFile("\n"); - -} - -void writeResulEnd() -{ - writeToFile("\n"); -} - -void writeResult(ref TestSuite suite, ref Test result) -{ - writeToFile(" \n"); - } - else - { - writeToFile(">\n"); - writeToFile(" "); - - if (result.file.length != 0) - { - writeToFile("Assert! File: "); - writeToFile(result.file[0 .. $ - 1]); - writeToFile(":"); - writeToFile(result.fileLine); - writeToFile(" Message: "); - writeToFile(result.msg[0 .. $ - 1]); - } - else - { - - writeToFile("No Message"); - } - - writeToFile("\n"); - writeToFile(" \n"); - } - -} - -void writeTests(TestSuite[] suites) -{ - writeResulStart(cast(int) suites.length); - foreach (ref TestSuite suite; suites) - { - foreach (ref Test test; suite.tests) - { - writeResult(suite, test); - } - } - writeResulEnd(); -} - string copyString(const char* str) { auto length = strlen(str); @@ -204,10 +110,9 @@ struct TestRunner(Args...) write("Assert! File: "); write(test.file[0 .. $ - 1]); write(":"); - write(test.fileLine); + write(test.file_line); write(" Message: "); write(test.msg[0 .. $ - 1]); - //write("\n"); write("\n"); } write("\t\t\n"); @@ -234,14 +139,14 @@ struct TestRunner(Args...) else test.name = attributes[0]; // Save calling environment for longjmp - int jmpRet = setjmp(gEnvBuffer); + int jmp_ret = setjmp(gEnvBuffer); - if (jmpRet == ASSERTED) + if (jmp_ret == ASSERTED) { passed = false; test.passed = false; test.file = copyString(gAssertInfo.file); - test.fileLine = gAssertInfo.line; + test.file_line = gAssertInfo.line; test.msg = copyString(gAssertInfo.msg); } else @@ -265,12 +170,10 @@ struct TestRunner(Args...) auto file = fopen(OUT_FILE, "w"); fwrite(junit.data.ptr,junit.length,1,file); fclose(file); - //writeTests(suites); } void writeOutput() { - import core.stdc.stdio; foreach(ref TestSuite suite; suites) { printf("Suite: \"%s\" Passed: %u/%u\n", suite.name.ptr, suite.passed, suite.passed + suite.failed); @@ -278,7 +181,7 @@ struct TestRunner(Args...) { if(!test.passed) { - printf("\tTest: \"%s\" Failed! Line: %u Message: %s\n",test.name.ptr, test.fileLine, test.msg.ptr); + printf("\tTest: \"%s\" Failed! Line: %u Message: %s\n",test.name.ptr, test.file_line, test.msg.ptr); } } } From 998240f7be80da8f485ccc523ffe24b12e28cae9 Mon Sep 17 00:00:00 2001 From: Mergul Date: Thu, 9 Apr 2020 22:14:51 +0200 Subject: [PATCH 101/217] Template allocation update and some tests -test runner support before/after everty test callback funcion -added some basic tests for template allocation -added function to allocate new template from different template and list of addition and removed components --- source/ecs/manager.d | 72 +++++++++++++++++- tests/basic.d | 172 +++++++++++++++++++++++++++++++++++++++++++ tests/runner.d | 2 + 3 files changed, 243 insertions(+), 3 deletions(-) diff --git a/source/ecs/manager.d b/source/ecs/manager.d index 0e91095..9f26584 100644 --- a/source/ecs/manager.d +++ b/source/ecs/manager.d @@ -1374,8 +1374,6 @@ export struct EntityManager { memcpy(temp.entity_data.ptr + info.tmpl_deltas[comp], components[comp].init_data.ptr, components[comp].size); - /*temp.entity_data[info.tmpl_deltas[comp] .. info.tmpl_deltas[comp] + components[comp].size] - = components[comp].init_data;*/ } } else @@ -1383,7 +1381,7 @@ export struct EntityManager ushort index = block.entityIndex(entity); foreach (comp; info.components) { - memcpy(cast(void*) temp.entity_data + info.tmpl_deltas[comp], + memcpy(cast(void*) temp.entity_data.ptr + info.tmpl_deltas[comp], cast(void*) block + info.deltas[comp] + components[comp].size * index, components[comp].size); } @@ -1440,6 +1438,74 @@ export struct EntityManager return temp; } + /************************************************************************************************************************ + *Allocate EntityTemplate with specifed components and returns pointer to it. + * + *Params: + *components_ids = array of components allocated with template + */ + export EntityTemplate* allocateTemplate(EntityTemplate* base_tmpl, ushort[] components_ids, ushort[] remove_components_ids = null) + { + size_t len = base_tmpl.info.components.length + components_ids.length; + ushort[] ids = (cast(ushort*) alloca(ushort.sizeof * len))[0 + .. len]; + memcpy(ids.ptr, base_tmpl.info.components.ptr, ushort.sizeof * base_tmpl.info.components.length); + memcpy(ids.ptr + base_tmpl.info.components.length, components_ids.ptr, ushort.sizeof * components_ids.length); + + qsort(ids.ptr, ids.length, ushort.sizeof, &compareUShorts); + qsort(remove_components_ids.ptr, remove_components_ids.length, ushort.sizeof, &compareUShorts); + { + uint k = 0; + uint j = 1; + foreach (i; 1 .. ids.length) + { + assert(ids[i] != ushort.max); + if(k < remove_components_ids.length) + { + while(k < remove_components_ids.length && remove_components_ids[k] < ids[i]) + { + k++; + } + if(k < remove_components_ids.length) + { + if(remove_components_ids[k] == ids[i])continue; + } + } + if (ids[i] != ids[j - 1]) + { + ids[j] = ids[i]; + j++; + } + else + debug assert(0, "Duplicated components in template!!!"); + } + ids = ids[0 .. j]; + } + + EntityInfo* info = getEntityInfo(ids); + + EntityTemplate* temp = Mallocator.make!EntityTemplate; + temp.entity_data = Mallocator.makeArray!ubyte(info.size); + temp.info = info; + + //fill components with default data and copy from base template + foreach (comp; info.components) + { + if(comp < base_tmpl.info.deltas.length && base_tmpl.info.deltas[comp] != ushort.max) //copy data from base component + { + memcpy(temp.entity_data.ptr + info.tmpl_deltas[comp], + base_tmpl.entity_data.ptr + base_tmpl.info.tmpl_deltas[comp], components[comp].size); + } + else //fill with default data + { + memcpy(temp.entity_data.ptr + info.tmpl_deltas[comp], + components[comp].init_data.ptr, components[comp].size); + } + } + + return temp; + } + /************************************************************************************************************************ *Returns entity type info. * diff --git a/tests/basic.d b/tests/basic.d index c359fe3..33006a7 100644 --- a/tests/basic.d +++ b/tests/basic.d @@ -1,2 +1,174 @@ module tests.basic; +import ecs.manager; +import ecs.core; + +struct CInt +{ + mixin ECS.Component; + + alias value this; + + int value = 1; +} + +struct CFloat +{ + mixin ECS.Component; + + alias value this; + + float value = 2.0; +} + +struct CDouble +{ + mixin ECS.Component; + + alias value this; + + double value = 3.0; +} + +struct CLong +{ + mixin ECS.Component; + + alias value this; + + long value = 10; +} + +struct CShort +{ + mixin ECS.Component; + + alias value this; + + short value = 12; +} + +void beforeEveryTest() +{ + gEM.initialize(1); + + gEM.registerComponent!CInt; + gEM.registerComponent!CFloat; + gEM.registerComponent!CDouble; + gEM.registerComponent!CLong; + gEM.registerComponent!CShort; +} + +void afterEveryTest() +{ + gEM.destroy(); +} + +@("AddEntity") +unittest +{ + ushort[2] ids = [CInt.component_id, CFloat.component_id]; + EntityTemplate* tmpl_ = gEM.allocateTemplate(ids); + assert(tmpl_.info.components.length == 2); + assert(tmpl_.getComponent!CInt); + assert(tmpl_.getComponent!CFloat); + assert(*tmpl_.getComponent!CInt == 1); + assert(*tmpl_.getComponent!CFloat == 2.0); + + Entity* entity = gEM.addEntity(tmpl_); + assert(entity.getComponent!CInt); + assert(entity.getComponent!CFloat); + assert(*entity.getComponent!CInt == 1); + assert(*entity.getComponent!CFloat == 2.0); +} + +//allocate templates +@("AllocateTemplates") +unittest +{ + //basic template allocation + ushort[2] ids = [CInt.component_id, CFloat.component_id]; + EntityTemplate* tmpl_ = gEM.allocateTemplate(ids); + assert(tmpl_.info.components.length == 2); + assert(tmpl_.getComponent!CInt); + assert(tmpl_.getComponent!CFloat); + assert(*tmpl_.getComponent!CInt == 1); + assert(*tmpl_.getComponent!CFloat == 2.0); + *tmpl_.getComponent!CInt = 4; + *tmpl_.getComponent!CFloat = 5.0; + + //allocate template from template with additional component + ushort[1] ids2 = [CDouble.component_id]; + EntityTemplate* tmpl_2 = gEM.allocateTemplate(tmpl_, ids2); + assert(tmpl_2.info.components.length == 3); + assert(tmpl_2.getComponent!CInt); + assert(tmpl_2.getComponent!CFloat); + assert(tmpl_2.getComponent!CDouble); + assert(*tmpl_2.getComponent!CInt == 4); + assert(*tmpl_2.getComponent!CFloat == 5.0); + assert(*tmpl_2.getComponent!CDouble == 3.0); + + Entity* entity = gEM.addEntity(tmpl_); + gEM.addComponents(entity.id, CDouble(8.0)); + + //apply entity changes + gEM.commit(); + + //allocate template as entity copy + EntityTemplate* tmpl_3 = gEM.allocateTemplate(entity.id); + assert(tmpl_3.info.components.length == 3); + assert(tmpl_3.getComponent!CInt); + assert(tmpl_3.getComponent!CFloat); + assert(tmpl_3.getComponent!CDouble); + assert(*tmpl_3.getComponent!CInt == 4); + assert(*tmpl_3.getComponent!CFloat == 5.0); + assert(*tmpl_3.getComponent!CDouble == 8.0); + + //allocate template with entity data but default values + EntityTemplate* tmpl_4 = gEM.allocateTemplate(entity.id, true); + assert(tmpl_4.info.components.length == 3); + assert(tmpl_4.getComponent!CInt); + assert(tmpl_4.getComponent!CFloat); + assert(tmpl_4.getComponent!CDouble); + assert(*tmpl_4.getComponent!CInt == 1); + assert(*tmpl_4.getComponent!CFloat == 2.0); + assert(*tmpl_4.getComponent!CDouble == 3.0); + + //allocate template from template with two additional component + ushort[2] ids3 = [CDouble.component_id, CLong.component_id]; + EntityTemplate* tmpl_5 = gEM.allocateTemplate(tmpl_, ids3); + assert(tmpl_5.info.components.length == 4); + assert(tmpl_5.getComponent!CInt); + assert(tmpl_5.getComponent!CFloat); + assert(tmpl_5.getComponent!CDouble); + assert(tmpl_5.getComponent!CLong); + assert(*tmpl_5.getComponent!CInt == 4); + assert(*tmpl_5.getComponent!CFloat == 5.0); + assert(*tmpl_5.getComponent!CDouble == 3.0); + assert(*tmpl_5.getComponent!CLong == 10); + + //allocate template from template without one component + ushort[1] rem_ids = [CFloat.component_id]; + EntityTemplate* tmpl_6 = gEM.allocateTemplate(tmpl_, null, rem_ids); + assert(tmpl_6.info.components.length == 1); + assert(tmpl_6.getComponent!CInt); + assert(*tmpl_6.getComponent!CInt == 4); + + //allocate template from template without one component and two additional + EntityTemplate* tmpl_7 = gEM.allocateTemplate(tmpl_, ids3, rem_ids); + assert(tmpl_7.info.components.length == 3); + assert(tmpl_7.getComponent!CInt); + assert(tmpl_7.getComponent!CDouble); + assert(tmpl_7.getComponent!CLong); + assert(*tmpl_7.getComponent!CInt == 4); + assert(*tmpl_7.getComponent!CDouble == 3.0); + assert(*tmpl_7.getComponent!CLong == 10); + + gEM.freeTemplate(tmpl_); + gEM.freeTemplate(tmpl_2); + gEM.freeTemplate(tmpl_3); + gEM.freeTemplate(tmpl_4); + gEM.freeTemplate(tmpl_5); + gEM.freeTemplate(tmpl_6); + gEM.freeTemplate(tmpl_7); +} \ No newline at end of file diff --git a/tests/runner.d b/tests/runner.d index 4aa2ed1..105a7a2 100644 --- a/tests/runner.d +++ b/tests/runner.d @@ -130,6 +130,7 @@ struct TestRunner(Args...) { TestSuite* suite = &suites[i]; suite.name = module_.stringof; + static if(__traits(hasMember, module_, "beforeEveryTest"))module_.beforeEveryTest(); foreach (index, unittest_; __traits(getUnitTests, module_)) { enum attributes = __traits(getAttributes, unittest_); @@ -161,6 +162,7 @@ struct TestRunner(Args...) } passed += suite.passed; failed += suite.failed; + static if(__traits(hasMember, module_, "afterEveryTest"))module_.afterEveryTest(); } } From 2aef76d75a1631f6480350c6fe51a68f6b9b586c Mon Sep 17 00:00:00 2001 From: Mergul Date: Tue, 14 Apr 2020 13:41:39 +0200 Subject: [PATCH 102/217] Unitests update -unittest runner works for non betterC build -working unittest coverage generation -unittest runner support for named tests. Simple regex is supported (* as any substring) and two list of expressions are used, one for include regex and one for exclude regex --- dub.json | 33 ++++++++- tests/basic.d | 11 +++ tests/runner.d | 189 +++++++++++++++++++++++++++++++++++++++++-------- tests/vector.d | 1 + 4 files changed, 201 insertions(+), 33 deletions(-) diff --git a/dub.json b/dub.json index 3bf07c4..31ef8f9 100755 --- a/dub.json +++ b/dub.json @@ -38,6 +38,33 @@ "-op" ] }, + { + "name": "unittest-runner", + "targetType" : "executable", + "sourcePaths": ["source/","tests/"], + "mainSourceFile":"tests/runner.d", + "excludedSourceFiles":[ + "source\/win_dll.d", + "tests/tests.d" + ], + "dflags": [ + "-unittest" + ] + }, + { + "name": "unittest-runner-cov", + "targetType" : "executable", + "sourcePaths": ["source/","tests/"], + "mainSourceFile":"tests/runner.d", + "excludedSourceFiles":[ + "source\/win_dll.d", + "tests/tests.d" + ], + "dflags": [ + "-unittest", + "-cov" + ] + }, { "name" : "library-betterC", "targetType" : "library", @@ -84,12 +111,12 @@ "-lpthread" ] }, - { - "name": "unittest-runner", + "name": "unittest-runner-betterC", "targetType" : "executable", "dflags": [ - "-betterC" + "-betterC", + "-unittest" ], "sourcePaths": ["source/","tests/"], "mainSourceFile":"tests/runner.d", diff --git a/tests/basic.d b/tests/basic.d index 33006a7..f794475 100644 --- a/tests/basic.d +++ b/tests/basic.d @@ -48,6 +48,15 @@ struct CShort short value = 12; } +struct CUnregistered +{ + mixin ECS.Component; + + alias value this; + + short value = 12; +} + void beforeEveryTest() { gEM.initialize(1); @@ -72,6 +81,8 @@ unittest assert(tmpl_.info.components.length == 2); assert(tmpl_.getComponent!CInt); assert(tmpl_.getComponent!CFloat); + assert(!tmpl_.getComponent!CLong); + assert(!tmpl_.getComponent!CUnregistered); assert(*tmpl_.getComponent!CInt == 1); assert(*tmpl_.getComponent!CFloat == 2.0); diff --git a/tests/runner.d b/tests/runner.d index 105a7a2..d2f9210 100644 --- a/tests/runner.d +++ b/tests/runner.d @@ -15,6 +15,9 @@ enum string OUT_FILE = "test_report.xml"; static jmp_buf gEnvBuffer; static AssertInfo gAssertInfo; +version(betterC){} +else version = notBetterC; + struct AssertInfo { const(char)* msg; @@ -44,6 +47,7 @@ struct TestSuite string name; uint passed = 0; uint failed = 0; + uint skipped = 0; Vector!Test tests; } @@ -56,25 +60,6 @@ string copyString(const char* str) struct TestRunner(Args...) { - TestSuite[Args.length] suites; - uint passed = 0; - uint failed = 0; - - SimpleVector junit; - - void write(string txt) - { - junit.add(cast(ubyte[]) txt); - } - - void write(uint num) - { - ubyte[20] buffer; - int len; - len = sprintf(cast(char*)buffer.ptr, "%u", num); - junit.add(buffer[0..len]); - } - void generateJUnit() { write("\n\n"); @@ -93,6 +78,8 @@ struct TestRunner(Args...) write(suite.passed + suite.failed); write("\" failures=\""); write(suite.failed); + write("\" skipped=\""); + write(suite.skipped); write("\">\n"); foreach(ref Test test; suite.tests) @@ -124,21 +111,59 @@ struct TestRunner(Args...) write(""); } - void runTests() + void runTests(string[] include = null, string[] exclude = null) { foreach(i, module_; Args) { TestSuite* suite = &suites[i]; suite.name = module_.stringof; - static if(__traits(hasMember, module_, "beforeEveryTest"))module_.beforeEveryTest(); foreach (index, unittest_; __traits(getUnitTests, module_)) { enum attributes = __traits(getAttributes, unittest_); + static if (attributes.length != 0) + { + if(include.length > 0) + { + bool matched = false; + foreach(str; include) + { + if(match(str, attributes[0])) + { + matched = true; + break; + } + } + + foreach(str; exclude) + { + if(match(str, attributes[0])) + { + matched = false; + break; + } + } + + if(!matched) + { + suite.skipped++; + continue; + } + } + } + else if(include.length > 0) + { + suite.skipped++; + continue; + } + Test test; static if (attributes.length == 0)test.name = "None"; else test.name = attributes[0]; + + static if(__traits(hasMember, module_, "beforeEveryTest"))module_.beforeEveryTest(); + // Save calling environment for longjmp int jmp_ret = setjmp(gEnvBuffer); @@ -159,10 +184,11 @@ struct TestRunner(Args...) if(test.passed)suite.passed++; else suite.failed++; suite.tests ~= test; + static if(__traits(hasMember, module_, "afterEveryTest"))module_.afterEveryTest(); } passed += suite.passed; failed += suite.failed; - static if(__traits(hasMember, module_, "afterEveryTest"))module_.afterEveryTest(); + skipped += suite.skipped; } } @@ -178,7 +204,7 @@ struct TestRunner(Args...) { foreach(ref TestSuite suite; suites) { - printf("Suite: \"%s\" Passed: %u/%u\n", suite.name.ptr, suite.passed, suite.passed + suite.failed); + printf("Suite: \"%s\" Passed: %u/%u Skipped: %u\n", suite.name.ptr, suite.passed, suite.passed + suite.failed, suite.skipped); foreach(ref Test test;suite.tests) { if(!test.passed) @@ -187,24 +213,127 @@ struct TestRunner(Args...) } } } - printf("Passed: %u/%u tests.\n", passed, passed+failed); + printf("Passed %u/%u tests. Skipped: %u.\n", passed, passed+failed, skipped); + } + + bool match(string a, string b) + { + uint i = 0; + foreach(char c; b) + { + if(i > a.length)return false; + if(a[i] == c)i++; + else + { + if(a[i] == '*') + { + if(i+1 >= a.length)return true; + else if(a[i + 1] == c)i += 2; + } + else return false; + } + } + return i == a.length; + } + + void write(string txt) + { + junit.add(cast(ubyte[]) txt); + } + + void write(uint num) + { + ubyte[20] buffer; + int len; + len = sprintf(cast(char*)buffer.ptr, "%u", num); + junit.add(buffer[0..len]); + } + + TestSuite[Args.length] suites; + uint passed = 0; + uint failed = 0; + uint skipped = 0; + + SimpleVector junit; +} + +version(notBetterC) +{ + extern(C) int rt_init(); + extern(C) int rt_term(); + version(D_Coverage) extern (C) void dmd_coverDestPath(string path); +} + +void extractStrings(ref Vector!string container, string str) +{ + uint s = 0; + foreach(j, char c; str) + { + if(c == ',') + { + if(s < j) + { + container.add(str[s .. j]); + } + s = cast(uint)j+1; + } + } + if(s < str.length) + { + container.add(str[s .. $]); } } -int main() +extern(C) int main(int argc, char** args) { - import tests.vector; - import tests.id_manager; - import tests.basic; + Vector!string include; + Vector!string exclude; + + version(notBetterC) + { + rt_init(); + version(D_Coverage) dmd_coverDestPath("reports"); + } + + for(int i=1;i= argc)break; + i++; + arg = cast(string)args[i][0..strlen(args[i])]; + extractStrings(include, arg); + } + else if(arg =="-e") + { + if(i + 1 >= argc)break; + i++; + arg = cast(string)args[i][0..strlen(args[i])]; + extractStrings(exclude, arg); + } + else if(arg.length < 10)continue; + else if(arg[0..10] == "--include=") + { + extractStrings(include, arg[10..$]); + } + else if(arg[0..10] == "--exclude=") + { + extractStrings(exclude, arg[10..$]); + } + } TestRunner!(tests.runner, tests.id_manager, tests.vector, tests.basic) runner; - runner.runTests(); + runner.runTests(include[], exclude[]); runner.writeFile(); runner.writeOutput(); + + version(notBetterC)rt_term(); if(!runner.failed)return 0; else return 1; -} +} \ No newline at end of file diff --git a/tests/vector.d b/tests/vector.d index 9b76d0b..5b52b79 100644 --- a/tests/vector.d +++ b/tests/vector.d @@ -3,6 +3,7 @@ module tests.vector; import ecs.simple_vector; //import ecs.vector; +@("simple-vector") unittest { SimpleVector vector; From 0670aed50629c4304c3afa7f9d1b5de792af0476 Mon Sep 17 00:00:00 2001 From: Mergul Date: Tue, 14 Apr 2020 17:29:49 +0200 Subject: [PATCH 103/217] BetterC improvement -fixed some bugs -non betterC code has better assertion messages -fixed limited count of components in system -small dub.json fix --- dub.json | 2 +- source/ecs/manager.d | 157 +++++++++++++++++++++++++++++++++---------- tests/runner.d | 2 +- 3 files changed, 124 insertions(+), 37 deletions(-) diff --git a/dub.json b/dub.json index 31ef8f9..dd0933c 100755 --- a/dub.json +++ b/dub.json @@ -97,7 +97,7 @@ { "name" : "tests-betterC", "targetType" : "executable", - "sourcePaths" : ["source\/","tests\/"], + "sourceFiles" : ["tests/tests.d"], "excludedSourceFiles":[ "source\/win_dll.d" ], diff --git a/source/ecs/manager.d b/source/ecs/manager.d index 9f26584..f95027c 100644 --- a/source/ecs/manager.d +++ b/source/ecs/manager.d @@ -351,7 +351,8 @@ export struct EntityManager void registerSystem(Sys)(int priority, const(char)[] pass_name) { ushort pass = passes_map.get(pass_name, ushort.max); - assert(pass != ushort.max); //, "Update pass (Name " ~ pass_name ~ ") doesn't exist."); + version(D_BetterC)assert(pass != ushort.max, "Update pass doesn't exist."); + else assert(pass != ushort.max, "Update pass (Name " ~ pass_name ~ ") doesn't exist."); registerSystem!(Sys)(priority, pass); } @@ -370,19 +371,20 @@ export struct EntityManager assert(register_state, "registerSystem must be called between beginRegister() and endRegister()."); - assert(pass < passes.length); //, "Update pass (ID " ~ pass.to!string ~ ") doesn't exist."); + version(D_BetterC)assert(pass < passes.length, "Update pass doesn't exist."); + else assert(pass < passes.length, "Update pass (ID " ~ pass.to!string ~ ") doesn't exist."); System system; system.m_pass = pass; static if (!(hasMember!(Sys, "system_id")) || !is(typeof(Sys.system_id) == ushort)) { - static assert(0); //, "Add \"mixin ECS.System;\" in top of system structure;"); + static assert(0, "Add \"mixin ECS.System;\" in top of system structure;"); } static if (!(hasMember!(Sys, "EntitiesData"))) { - static assert(0); //, "System should gave \"EntitiesData\" struct for input components"); + static assert(0, "System should gave \"EntitiesData\" struct for input components"); } static if (hasMember!(Sys, "handleEvent")) @@ -434,9 +436,104 @@ export struct EntityManager string type; } - static struct ComponentsIndices + static struct ComponentsCounts { + uint readonly; + uint mutable; + uint excluded; + uint optional; + uint req; + } + static ComponentsCounts getComponentsCounts()() + { + ComponentsCounts components_counts; + + bool checkExcludedComponentsSomething(Sys)() + { + return __traits(compiles, allSameType!(string, typeof(Sys.ExcludedComponents))) && allSameType!(string, + typeof(Sys.ExcludedComponents)) && isExpressions!(Sys.ExcludedComponents); + } + + foreach (member; __traits(allMembers, Sys.EntitiesData)) + { + alias MemberType = typeof(__traits(getMember, Sys.EntitiesData, member)); + if (member == "length" || member == "thread_id" + || is(MemberType == Entity[]) || is(MemberType == const(Entity)[])) + { + continue; + } + + string name; + static if (isArray!MemberType) + { // Workaround. This code is never called with: not an array type, but compiler prints an error + name = Unqual!(ForeachType!MemberType).stringof; + } + + bool is_optional; + bool is_read_only; + + if (is(CopyConstness!(ForeachType!(MemberType), int) == const(int))) + { + is_read_only = true; + } + + foreach (att; __traits(getAttributes, __traits(getMember, + Sys.EntitiesData, member))) + { + if (att == "optional") + { + is_optional = true; + } + if (att == "readonly") + { + is_read_only = true; + } + } + if (is_read_only) + { + components_counts.readonly++; + } + else + { + components_counts.mutable++; + } + if (is_optional) + { + components_counts.optional++; + } + else + { + components_counts.req++; + } + } + + static if (__traits(hasMember, Sys, "ExcludedComponents")) + { + static if (is(Sys.ExcludedComponents == enum)) + { + foreach (str; __traits(allMembers, Sys.ExcludedComponents)) + { + components_counts.excluded++; + } + } + else //static if (checkExcludedComponentsSomething!Sys) + { + foreach (str; Sys.ExcludedComponents) + { + components_counts.excluded++; + } + + } + } + + return components_counts; + } + + enum ComponentsCounts component_counts = getComponentsCounts(); + + static struct ComponentsIndices(ComponentsCounts counts) + { CompInfo[] readonly() { return m_readonly[0 .. m_readonly_counter]; @@ -487,11 +584,11 @@ export struct EntityManager m_req[m_req_counter++] = info; } - CompInfo[64] m_readonly; - CompInfo[64] m_mutable; - CompInfo[64] m_excluded; - CompInfo[64] m_optional; - CompInfo[64] m_req; + CompInfo[counts.readonly] m_readonly; + CompInfo[counts.mutable] m_mutable; + CompInfo[counts.excluded] m_excluded; + CompInfo[counts.optional] m_optional; + CompInfo[counts.req] m_req; uint m_readonly_counter; uint m_mutable_counter; @@ -502,7 +599,7 @@ export struct EntityManager string entites_array; } - static void allocateSystemComponents(ComponentsIndices components_info)(ref System system) + static void allocateSystemComponents(ComponentsIndices!component_counts components_info)(ref System system) { size_t req = components_info.req.length; size_t opt = components_info.optional.length; @@ -523,9 +620,9 @@ export struct EntityManager } - static ComponentsIndices getComponentsInfo()() + static ComponentsIndices!component_counts getComponentsInfo()() { - ComponentsIndices components_info; + ComponentsIndices!component_counts components_info; bool checkExcludedComponentsSomething(Sys)() { @@ -573,31 +670,19 @@ export struct EntityManager if (is_read_only) { components_info.addReadonly(CompInfo(member, name)); - //components_info.readonly ~= CompInfo(member,name); } else { components_info.addMutable(CompInfo(member, name)); - //components_info.mutable ~= CompInfo(member,name); } if (is_optional) { components_info.addOptional(CompInfo(member, name)); - //components_info.optional ~= CompInfo(member,name); } else { components_info.addReq(CompInfo(member, name)); - //components_info.req ~= CompInfo(member,name); } - /*if (is_read_only) - { - //components_info.readonly ~= CompInfo(member,name); - } - if (is_optional == false) - { //is Req - //components_info.req ~= CompInfo(member,name); - }*/ } static if (__traits(hasMember, Sys, "ExcludedComponents")) @@ -607,7 +692,6 @@ export struct EntityManager foreach (str; __traits(allMembers, Sys.ExcludedComponents)) { components_info.addExcluded(CompInfo(str, str)); - //components_info.excluded ~= CompInfo(str,str); } } else //static if (checkExcludedComponentsSomething!Sys) @@ -615,7 +699,6 @@ export struct EntityManager foreach (str; Sys.ExcludedComponents) { components_info.addExcluded(CompInfo(str.stringof, str.stringof)); - //components_info.excluded ~= CompInfo(str,str); } } @@ -624,7 +707,7 @@ export struct EntityManager return components_info; } - enum ComponentsIndices components_info = getComponentsInfo(); + enum ComponentsIndices!component_counts components_info = getComponentsInfo(); static void genCompList()(ref System system, ref HashMap!(char[], ushort) components_map) { @@ -659,7 +742,7 @@ export struct EntityManager foreach (iii, comp_info; components_info.req) { ushort comp = components_map.get(cast(char[]) comp_info.type, ushort.max); - version (betterC) + version (D_BetterC) assert(comp != ushort.max, "Can't register system due to non existing component."); else @@ -670,25 +753,29 @@ export struct EntityManager foreach (iii, comp_info; components_info.excluded) { ushort comp = components_map.get(cast(char[]) comp_info.type, ushort.max); - assert(comp != ushort.max); //, "Can't register system \""~Sys.stringof~"\" due to non existing component \""~comp_info.type~"\"."); + version (D_BetterC)assert(comp != ushort.max, "Can't register system due to non existing component."); + else assert(comp != ushort.max, "Can't register system \""~Sys.stringof~"\" due to non existing component \""~comp_info.type~"\"."); system.m_excluded_components[iii] = comp; } foreach (iii, comp_info; components_info.optional) { ushort comp = components_map.get(cast(char[]) comp_info.type, ushort.max); - assert(comp != ushort.max); //, "Can't register system \""~Sys.stringof~"\" due to non existing component \""~comp_info.type~"\"."); + version (D_BetterC)assert(comp != ushort.max, "Can't register system due to non existing component."); + else assert(comp != ushort.max, "Can't register system \""~Sys.stringof~"\" due to non existing component \""~comp_info.type~"\"."); system.m_optional_components[iii] = comp; } foreach (iii, comp_info; components_info.readonly) { ushort comp = components_map.get(cast(char[]) comp_info.type, ushort.max); - assert(comp != ushort.max); //, "Can't register system \""~Sys.stringof~"\" due to non existing component \""~comp_info.type~"\"."); + version (D_BetterC)assert(comp != ushort.max, "Can't register system due to non existing component."); + else assert(comp != ushort.max, "Can't register system \""~Sys.stringof~"\" due to non existing component \""~comp_info.type~"\"."); system.m_read_only_components[iii] = comp; } foreach (iii, comp_info; components_info.mutable) { ushort comp = components_map.get(cast(char[]) comp_info.type, ushort.max); - assert(comp != ushort.max); //, "Can't register system \""~Sys.stringof~"\" due to non existing component \""~comp_info.type~"\"."); + version (D_BetterC)assert(comp != ushort.max, "Can't register system due to non existing component."); + else assert(comp != ushort.max, "Can't register system \""~Sys.stringof~"\" due to non existing component \""~comp_info.type~"\"."); system.m_modified_components[iii] = comp; } @@ -1009,7 +1096,7 @@ export struct EntityManager static if (!(hasMember!(Comp, "component_id")) || !is(typeof(Comp.component_id) == ushort)) { - static assert(0, "Add \"mixin ECS.Component;\" in top of component structure;"); //"Component should have \"__gshared ushort component_id"); + static assert(0, "Add \"mixin ECS.Component;\" in top of component structure;"); } static if (hasMember!(Comp, "onDestroy") && isFunction!(Comp.onDestroy) @@ -1063,7 +1150,7 @@ export struct EntityManager static if (!(hasMember!(Ev, "event_id")) || !is(typeof(Ev.event_id) == ushort)) { - static assert(0, "Add \"mixin ECS.Event;\" in top of event structure;"); //"Event should have \"__gshared ushort event_id"); + static assert(0, "Add \"mixin ECS.Event;\" in top of event structure;"); } static if (hasMember!(Ev, "onDestroy") && isFunction!(Ev.onDestroy) diff --git a/tests/runner.d b/tests/runner.d index d2f9210..98c024d 100644 --- a/tests/runner.d +++ b/tests/runner.d @@ -15,7 +15,7 @@ enum string OUT_FILE = "test_report.xml"; static jmp_buf gEnvBuffer; static AssertInfo gAssertInfo; -version(betterC){} +version(D_BetterC){} else version = notBetterC; struct AssertInfo From 14839b3765d3330f1f60b6a913564206469efb14 Mon Sep 17 00:00:00 2001 From: Mergul Date: Tue, 14 Apr 2020 17:39:52 +0200 Subject: [PATCH 104/217] Better assertion infos and formatted code --- source/ecs/manager.d | 85 +++++++++++++++-------- tests/basic.d | 4 +- tests/id_manager.d | 2 +- tests/runner.d | 161 ++++++++++++++++++++++++------------------- tests/tests.d | 8 +-- tests/vector.d | 12 ++-- 6 files changed, 163 insertions(+), 109 deletions(-) diff --git a/source/ecs/manager.d b/source/ecs/manager.d index f95027c..f6f345a 100644 --- a/source/ecs/manager.d +++ b/source/ecs/manager.d @@ -351,8 +351,10 @@ export struct EntityManager void registerSystem(Sys)(int priority, const(char)[] pass_name) { ushort pass = passes_map.get(pass_name, ushort.max); - version(D_BetterC)assert(pass != ushort.max, "Update pass doesn't exist."); - else assert(pass != ushort.max, "Update pass (Name " ~ pass_name ~ ") doesn't exist."); + version (D_BetterC) + assert(pass != ushort.max, "Update pass doesn't exist."); + else + assert(pass != ushort.max, "Update pass (Name " ~ pass_name ~ ") doesn't exist."); registerSystem!(Sys)(priority, pass); } @@ -371,8 +373,10 @@ export struct EntityManager assert(register_state, "registerSystem must be called between beginRegister() and endRegister()."); - version(D_BetterC)assert(pass < passes.length, "Update pass doesn't exist."); - else assert(pass < passes.length, "Update pass (ID " ~ pass.to!string ~ ") doesn't exist."); + version (D_BetterC) + assert(pass < passes.length, "Update pass doesn't exist."); + else + assert(pass < passes.length, "Update pass (ID " ~ pass.to!string ~ ") doesn't exist."); System system; system.m_pass = pass; @@ -599,7 +603,8 @@ export struct EntityManager string entites_array; } - static void allocateSystemComponents(ComponentsIndices!component_counts components_info)(ref System system) + static void allocateSystemComponents(ComponentsIndices!component_counts components_info)( + ref System system) { size_t req = components_info.req.length; size_t opt = components_info.optional.length; @@ -744,7 +749,8 @@ export struct EntityManager ushort comp = components_map.get(cast(char[]) comp_info.type, ushort.max); version (D_BetterC) assert(comp != ushort.max, - "Can't register system due to non existing component."); + "Can't register system \"" ~ Sys.stringof + ~ "\" due to non existing component."); else assert(comp != ushort.max, "Can't register system \"" ~ Sys.stringof ~ "\" due to non existing component \"" ~ comp_info.type ~ "\"."); @@ -753,29 +759,49 @@ export struct EntityManager foreach (iii, comp_info; components_info.excluded) { ushort comp = components_map.get(cast(char[]) comp_info.type, ushort.max); - version (D_BetterC)assert(comp != ushort.max, "Can't register system due to non existing component."); - else assert(comp != ushort.max, "Can't register system \""~Sys.stringof~"\" due to non existing component \""~comp_info.type~"\"."); + version (D_BetterC) + assert(comp != ushort.max, + "Can't register system \"" ~ Sys.stringof + ~ "\" due to non existing component."); + else + assert(comp != ushort.max, "Can't register system \"" ~ Sys.stringof + ~ "\" due to non existing component \"" ~ comp_info.type ~ "\"."); system.m_excluded_components[iii] = comp; } foreach (iii, comp_info; components_info.optional) { ushort comp = components_map.get(cast(char[]) comp_info.type, ushort.max); - version (D_BetterC)assert(comp != ushort.max, "Can't register system due to non existing component."); - else assert(comp != ushort.max, "Can't register system \""~Sys.stringof~"\" due to non existing component \""~comp_info.type~"\"."); + version (D_BetterC) + assert(comp != ushort.max, + "Can't register system \"" ~ Sys.stringof + ~ "\" due to non existing component."); + else + assert(comp != ushort.max, "Can't register system \"" ~ Sys.stringof + ~ "\" due to non existing component \"" ~ comp_info.type ~ "\"."); system.m_optional_components[iii] = comp; } foreach (iii, comp_info; components_info.readonly) { ushort comp = components_map.get(cast(char[]) comp_info.type, ushort.max); - version (D_BetterC)assert(comp != ushort.max, "Can't register system due to non existing component."); - else assert(comp != ushort.max, "Can't register system \""~Sys.stringof~"\" due to non existing component \""~comp_info.type~"\"."); + version (D_BetterC) + assert(comp != ushort.max, + "Can't register system \"" ~ Sys.stringof + ~ "\" due to non existing component."); + else + assert(comp != ushort.max, "Can't register system \"" ~ Sys.stringof + ~ "\" due to non existing component \"" ~ comp_info.type ~ "\"."); system.m_read_only_components[iii] = comp; } foreach (iii, comp_info; components_info.mutable) { ushort comp = components_map.get(cast(char[]) comp_info.type, ushort.max); - version (D_BetterC)assert(comp != ushort.max, "Can't register system due to non existing component."); - else assert(comp != ushort.max, "Can't register system \""~Sys.stringof~"\" due to non existing component \""~comp_info.type~"\"."); + version (D_BetterC) + assert(comp != ushort.max, + "Can't register system \"" ~ Sys.stringof + ~ "\" due to non existing component."); + else + assert(comp != ushort.max, "Can't register system \"" ~ Sys.stringof + ~ "\" due to non existing component \"" ~ comp_info.type ~ "\"."); system.m_modified_components[iii] = comp; } @@ -1531,31 +1557,35 @@ export struct EntityManager *Params: *components_ids = array of components allocated with template */ - export EntityTemplate* allocateTemplate(EntityTemplate* base_tmpl, ushort[] components_ids, ushort[] remove_components_ids = null) + export EntityTemplate* allocateTemplate(EntityTemplate* base_tmpl, + ushort[] components_ids, ushort[] remove_components_ids = null) { size_t len = base_tmpl.info.components.length + components_ids.length; - ushort[] ids = (cast(ushort*) alloca(ushort.sizeof * len))[0 - .. len]; - memcpy(ids.ptr, base_tmpl.info.components.ptr, ushort.sizeof * base_tmpl.info.components.length); - memcpy(ids.ptr + base_tmpl.info.components.length, components_ids.ptr, ushort.sizeof * components_ids.length); - + ushort[] ids = (cast(ushort*) alloca(ushort.sizeof * len))[0 .. len]; + memcpy(ids.ptr, base_tmpl.info.components.ptr, + ushort.sizeof * base_tmpl.info.components.length); + memcpy(ids.ptr + base_tmpl.info.components.length, components_ids.ptr, + ushort.sizeof * components_ids.length); + qsort(ids.ptr, ids.length, ushort.sizeof, &compareUShorts); - qsort(remove_components_ids.ptr, remove_components_ids.length, ushort.sizeof, &compareUShorts); + qsort(remove_components_ids.ptr, remove_components_ids.length, + ushort.sizeof, &compareUShorts); { uint k = 0; uint j = 1; foreach (i; 1 .. ids.length) { assert(ids[i] != ushort.max); - if(k < remove_components_ids.length) + if (k < remove_components_ids.length) { - while(k < remove_components_ids.length && remove_components_ids[k] < ids[i]) + while (k < remove_components_ids.length && remove_components_ids[k] < ids[i]) { k++; } - if(k < remove_components_ids.length) + if (k < remove_components_ids.length) { - if(remove_components_ids[k] == ids[i])continue; + if (remove_components_ids[k] == ids[i]) + continue; } } if (ids[i] != ids[j - 1]) @@ -1578,10 +1608,11 @@ export struct EntityManager //fill components with default data and copy from base template foreach (comp; info.components) { - if(comp < base_tmpl.info.deltas.length && base_tmpl.info.deltas[comp] != ushort.max) //copy data from base component + if (comp < base_tmpl.info.deltas.length && base_tmpl.info.deltas[comp] != ushort.max) //copy data from base component { memcpy(temp.entity_data.ptr + info.tmpl_deltas[comp], - base_tmpl.entity_data.ptr + base_tmpl.info.tmpl_deltas[comp], components[comp].size); + base_tmpl.entity_data.ptr + base_tmpl.info.tmpl_deltas[comp], + components[comp].size); } else //fill with default data { diff --git a/tests/basic.d b/tests/basic.d index f794475..c3dfcc5 100644 --- a/tests/basic.d +++ b/tests/basic.d @@ -85,7 +85,7 @@ unittest assert(!tmpl_.getComponent!CUnregistered); assert(*tmpl_.getComponent!CInt == 1); assert(*tmpl_.getComponent!CFloat == 2.0); - + Entity* entity = gEM.addEntity(tmpl_); assert(entity.getComponent!CInt); assert(entity.getComponent!CFloat); @@ -182,4 +182,4 @@ unittest gEM.freeTemplate(tmpl_5); gEM.freeTemplate(tmpl_6); gEM.freeTemplate(tmpl_7); -} \ No newline at end of file +} diff --git a/tests/id_manager.d b/tests/id_manager.d index 6601582..afaafe5 100644 --- a/tests/id_manager.d +++ b/tests/id_manager.d @@ -33,4 +33,4 @@ unittest assert(!manager.isExist(EntityID(1, 0))); assert(!manager.isExist(EntityID(0, 0))); manager.deinitialize(); -} \ No newline at end of file +} diff --git a/tests/runner.d b/tests/runner.d index 98c024d..94b5ed2 100644 --- a/tests/runner.d +++ b/tests/runner.d @@ -15,7 +15,9 @@ enum string OUT_FILE = "test_report.xml"; static jmp_buf gEnvBuffer; static AssertInfo gAssertInfo; -version(D_BetterC){} +version (D_BetterC) +{ +} else version = notBetterC; struct AssertInfo @@ -70,7 +72,7 @@ struct TestRunner(Args...) write(failed); write("\">\n"); - foreach(ref TestSuite suite; suites) + foreach (ref TestSuite suite; suites) { write("\t\n"); - foreach(ref Test test; suite.tests) + foreach (ref Test test; suite.tests) { write("\t\t\n"); - if(test.msg) + if (test.msg) { write("\t\t\t\n"); - } + } write(""); } void runTests(string[] include = null, string[] exclude = null) { - foreach(i, module_; Args) + foreach (i, module_; Args) { TestSuite* suite = &suites[i]; suite.name = module_.stringof; @@ -122,35 +124,35 @@ struct TestRunner(Args...) enum attributes = __traits(getAttributes, unittest_); static if (attributes.length != 0) { - if(include.length > 0) + if (include.length > 0) { bool matched = false; - foreach(str; include) + foreach (str; include) { - if(match(str, attributes[0])) + if (match(str, attributes[0])) { matched = true; break; } } - foreach(str; exclude) + foreach (str; exclude) { - if(match(str, attributes[0])) + if (match(str, attributes[0])) { matched = false; break; } } - if(!matched) + if (!matched) { suite.skipped++; continue; } } } - else if(include.length > 0) + else if (include.length > 0) { suite.skipped++; continue; @@ -158,11 +160,13 @@ struct TestRunner(Args...) Test test; - static if (attributes.length == 0)test.name = "None"; - else test.name = attributes[0]; + static if (attributes.length == 0) + test.name = "None"; + else + test.name = attributes[0]; - - static if(__traits(hasMember, module_, "beforeEveryTest"))module_.beforeEveryTest(); + static if (__traits(hasMember, module_, "beforeEveryTest")) + module_.beforeEveryTest(); // Save calling environment for longjmp int jmp_ret = setjmp(gEnvBuffer); @@ -181,10 +185,13 @@ struct TestRunner(Args...) test.passed = true; } - if(test.passed)suite.passed++; - else suite.failed++; + if (test.passed) + suite.passed++; + else + suite.failed++; suite.tests ~= test; - static if(__traits(hasMember, module_, "afterEveryTest"))module_.afterEveryTest(); + static if (__traits(hasMember, module_, "afterEveryTest")) + module_.afterEveryTest(); } passed += suite.passed; failed += suite.failed; @@ -194,43 +201,51 @@ struct TestRunner(Args...) void writeFile() { - if(junit.length == 0)generateJUnit(); + if (junit.length == 0) + generateJUnit(); auto file = fopen(OUT_FILE, "w"); - fwrite(junit.data.ptr,junit.length,1,file); + fwrite(junit.data.ptr, junit.length, 1, file); fclose(file); } void writeOutput() { - foreach(ref TestSuite suite; suites) + foreach (ref TestSuite suite; suites) { - printf("Suite: \"%s\" Passed: %u/%u Skipped: %u\n", suite.name.ptr, suite.passed, suite.passed + suite.failed, suite.skipped); - foreach(ref Test test;suite.tests) + printf("Suite: \"%s\" Passed: %u/%u Skipped: %u\n", suite.name.ptr, + suite.passed, suite.passed + suite.failed, suite.skipped); + foreach (ref Test test; suite.tests) { - if(!test.passed) + if (!test.passed) { - printf("\tTest: \"%s\" Failed! Line: %u Message: %s\n",test.name.ptr, test.file_line, test.msg.ptr); + printf("\tTest: \"%s\" Failed! Line: %u Message: %s\n", + test.name.ptr, test.file_line, test.msg.ptr); } } } - printf("Passed %u/%u tests. Skipped: %u.\n", passed, passed+failed, skipped); + printf("Passed %u/%u tests. Skipped: %u.\n", passed, passed + failed, skipped); } bool match(string a, string b) { uint i = 0; - foreach(char c; b) + foreach (char c; b) { - if(i > a.length)return false; - if(a[i] == c)i++; - else + if (i > a.length) + return false; + if (a[i] == c) + i++; + else { - if(a[i] == '*') + if (a[i] == '*') { - if(i+1 >= a.length)return true; - else if(a[i + 1] == c)i += 2; + if (i + 1 >= a.length) + return true; + else if (a[i + 1] == c) + i += 2; } - else return false; + else + return false; } } return i == a.length; @@ -245,8 +260,8 @@ struct TestRunner(Args...) { ubyte[20] buffer; int len; - len = sprintf(cast(char*)buffer.ptr, "%u", num); - junit.add(buffer[0..len]); + len = sprintf(cast(char*) buffer.ptr, "%u", num); + junit.add(buffer[0 .. len]); } TestSuite[Args.length] suites; @@ -257,70 +272,75 @@ struct TestRunner(Args...) SimpleVector junit; } -version(notBetterC) +version (notBetterC) { - extern(C) int rt_init(); - extern(C) int rt_term(); - version(D_Coverage) extern (C) void dmd_coverDestPath(string path); + extern (C) int rt_init(); + extern (C) int rt_term(); + version (D_Coverage) extern (C) void dmd_coverDestPath(string path); } void extractStrings(ref Vector!string container, string str) { uint s = 0; - foreach(j, char c; str) + foreach (j, char c; str) { - if(c == ',') + if (c == ',') { - if(s < j) + if (s < j) { container.add(str[s .. j]); } - s = cast(uint)j+1; + s = cast(uint) j + 1; } } - if(s < str.length) + if (s < str.length) { container.add(str[s .. $]); } } -extern(C) int main(int argc, char** args) +extern (C) int main(int argc, char** args) { Vector!string include; Vector!string exclude; - version(notBetterC) + version (notBetterC) { rt_init(); - version(D_Coverage) dmd_coverDestPath("reports"); + version (D_Coverage) + dmd_coverDestPath("reports"); } - for(int i=1;i= argc)break; + if (i + 1 >= argc) + break; i++; - arg = cast(string)args[i][0..strlen(args[i])]; + arg = cast(string) args[i][0 .. strlen(args[i])]; extractStrings(include, arg); } - else if(arg =="-e") + else if (arg == "-e") { - if(i + 1 >= argc)break; + if (i + 1 >= argc) + break; i++; - arg = cast(string)args[i][0..strlen(args[i])]; + arg = cast(string) args[i][0 .. strlen(args[i])]; extractStrings(exclude, arg); } - else if(arg.length < 10)continue; - else if(arg[0..10] == "--include=") + else if (arg.length < 10) + continue; + else if (arg[0 .. 10] == "--include=") { - extractStrings(include, arg[10..$]); + extractStrings(include, arg[10 .. $]); } - else if(arg[0..10] == "--exclude=") + else if (arg[0 .. 10] == "--exclude=") { - extractStrings(exclude, arg[10..$]); + extractStrings(exclude, arg[10 .. $]); } } @@ -332,8 +352,11 @@ extern(C) int main(int argc, char** args) runner.writeOutput(); - version(notBetterC)rt_term(); - - if(!runner.failed)return 0; - else return 1; -} \ No newline at end of file + version (notBetterC) + rt_term(); + + if (!runner.failed) + return 0; + else + return 1; +} diff --git a/tests/tests.d b/tests/tests.d index 33ce587..ea554d1 100644 --- a/tests/tests.d +++ b/tests/tests.d @@ -425,19 +425,19 @@ struct EmptyEventSystem void handleEvent(Entity* entity, TestEvent event) { - if(!handled) + if (!handled) { printf("EmptyEventSystem.handleEvent() called!\n"); handled = true; } - assert(0,"this shouldn't be called!"); + assert(0, "this shouldn't be called!"); } } struct EventSystem { mixin ECS.System; - + bool handled = false; struct EntitiesData @@ -448,7 +448,7 @@ struct EventSystem void handleEvent(Entity* entity, TestEvent event) { - if(!handled) + if (!handled) { printf("EventSystem.handleEvent() called!\n"); handled = true; diff --git a/tests/vector.d b/tests/vector.d index 5b52b79..109ff37 100644 --- a/tests/vector.d +++ b/tests/vector.d @@ -7,13 +7,13 @@ import ecs.simple_vector; unittest { SimpleVector vector; - vector.add(cast(ubyte[])"a"); - vector.add(cast(ubyte[])"bsdf"); - assert(vector[0..5] == cast(ubyte[])"absdf"); + vector.add(cast(ubyte[]) "a"); + vector.add(cast(ubyte[]) "bsdf"); + assert(vector[0 .. 5] == cast(ubyte[]) "absdf"); assert(vector[4] == 'f'); - assert(vector[] == cast(ubyte[])"absdf"); + assert(vector[] == cast(ubyte[]) "absdf"); assert(vector[$ - 1] == 'f'); - + vector.clear(); assert(vector.length == 0); -} \ No newline at end of file +} From 72617bc2a58225f0367762316d98740b2d9ef2d4 Mon Sep 17 00:00:00 2001 From: Dawid Masiukiewicz Date: Tue, 14 Apr 2020 18:37:00 +0000 Subject: [PATCH 105/217] Added pipeline status indicator to README.md --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 08cab68..76fff75 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,5 @@ # Dynamic Entity Component System +[![pipeline status](https://gitlab.com/Mergul/bubel-ecs/badges/master/pipeline.svg)](https://gitlab.com/Mergul/bubel-ecs/-/commits/master) +[![coverage report](https://gitlab.com/Mergul/bubel-ecs/badges/master/coverage.svg)](https://gitlab.com/Mergul/bubel-ecs/-/commits/master) Entity-Component-System implementation in D language. \ No newline at end of file From 84e04191c8b1d466996ca47e748cdcb3273ce27b Mon Sep 17 00:00:00 2001 From: Mergul Date: Thu, 16 Apr 2020 22:16:20 +0200 Subject: [PATCH 106/217] Unittests and demos update -fixed bug in EntityManager -added better support for non-betterC unittests -added many new unittests -slightly improved JUnit xml output -fixed WASM compile script -added new textures -fixed model texture coordinaes in demos -some minor bug fixes in demo TODO: demos cpu usage in non-betterC mode --- demos/assets/textures/apple.png | Bin 0 -> 2402 bytes demos/assets/textures/atlas.png | Bin 0 -> 17825 bytes demos/assets/textures/snake.png | Bin 0 -> 2385 bytes demos/assets/textures/snake_head.png | Bin 0 -> 2517 bytes demos/assets/textures/snake_horizontal.png | Bin 0 -> 2718 bytes demos/compile_wasm.py | 2 +- demos/source/app.d | 3 +- demos/source/demos/snake.d | 25 +- demos/source/demos/space_invaders.d | 27 +- dub.json | 2 - source/ecs/manager.d | 3 + tests/basic.d | 389 ++++++++++++++++++++- tests/runner.d | 53 ++- 13 files changed, 453 insertions(+), 51 deletions(-) create mode 100644 demos/assets/textures/apple.png create mode 100644 demos/assets/textures/atlas.png create mode 100644 demos/assets/textures/snake.png create mode 100644 demos/assets/textures/snake_head.png create mode 100644 demos/assets/textures/snake_horizontal.png diff --git a/demos/assets/textures/apple.png b/demos/assets/textures/apple.png new file mode 100644 index 0000000000000000000000000000000000000000..63d8fb4be09a56b1f63063c0e9a96b263c636418 GIT binary patch literal 2402 zcmV-o37z(dP) zaB^>EX>4U6ba`-PAZ2)IW&i+q+ND=(lJq7F{Ld+J1SDSKI6SLzgB(B2%bwYp-JLHP z*BXpLYSfM7Rqda@yZQ@1Hjb5bL45RH<7cCdoX`=yereuG+j-v)`gESg)%AigWYC)R zD1MJOj5Fr*9xvNY!nk`d6x)80pI@YHh-EuC9=9Vy%Ym-jP}+tJZ_jo;=k3`?36EQ- zX9u!JWc{gevnH^2o`S{QvJSyV^o6wzh+7>%O_=^KM_-@SnaaS#&5+UaE(@hue+hpU zcQPLH@D_cCHwmLFzFL7YK!D}AW83r<&8OI0ti1oJPqww?@I?33+cHouFTTjYw>@sY zu;;IKj;pUP$i1g~a{7QM*vm0LAftB%U+-0VZ)pmImWb3oGqeciA$!0W z%#Ayyff4FEsBQ-MT+f2s#2QfOW|##VOgb+U+0m^nGl@2s=g_V*Mxn0t!;pn<2QXwn zf%aq^dD4M75FwBPf)Z(AV>yEXa*iuNvNbq*fpG}nT47C~IhP%;ab!s_;fyx{+(eT= zmbDK0309z?3!&y2B(#W^cc%;$T^vWss<)gIV)rlCDyuBeGQ?Y%9 z&BjD-naC(U*)I$YfzSQ2H&!Yv9mVxB_dWO<`#Y@a3)pgljb>Yy940&@5g&_NGa8N> z&fX;`wH39u5~2;&#jrg()OdX0&9LL-%G%_}I%X>-Cn$z|0wTOArH!<+$>l-r_mTbv zw7OAWN<7PwDaFJc-|CTc$`z%wHN&+ zWj?gx~dlbhmFa~^h&0(K|k%PsBzRx!=t`@qga zi(S~Wy9&WP%Q&nh5p|E262|ASUDc`Bb|o;y>tqOD;;S2uH&S*VUj;j=8sFbLT+;GG z8dN6_wjIvyQ9>=(6~q|pl}jwhcoM>{n$4s12enmIuf$mC#3#Qb&A26PUg{f7L2{H& zW4c0G59|1JiG}JcN3Kb1{-`ZP9V%T~Y|BqfmjaWy(#1<%`zqmU(dqyMitsL;8FeyI zJ^9_mZhhb|4b3Vl_^14oNjqw4t9chyK=icmANVQW`IMJ96&#y6$BO^7)NiHZODTr! zJgI=p`3C7XKwox$0aqU)|2~qtRk!gQ=6^w{ejx3qc)u)CzX1OjnR*kzj&Iqh{sqIh zSDuxx6Mg^y0flKpLr_UWLm+T+Z)Rz1WdHzpoPCi!NW(xFhTr~3MJft*5OK&*6~uz5 zh@)1a2o*xD(5i#UrGL<*AxUv@6kH1q{w!79}p);Cq)-2@w=qZBE~z8 zdwB1AU+%sG{Pi+Z&EPnoYL<~o#Dz?DRS3Nzh+di_7?qf*&xv9Zp5yBtKEB_@c$RnF zpQBsJnGEm=#IsB{EaDB~=}k-LyiXiqMM)t(Cmu8Cg2azpmtB72TyWUWGb2ViHBTHN z77A@Fw=pXkD)AI?R8cj`_h(#IIB#)Q%T?CACx2l$r>!h=oz@@{Si}-U2#`@l31wJ_ z(XNqVB1PwM5C4GU7s(})s{}@l1yrCya{ScGq=>9v*?Jpy{Rfs5;wChq~4J3#-FE*X*|1!(#6dEotwz9|dz z-2z=}Zr_^cIDG)p)T`tTaBv6=7btt(xDGT}XZ)uK)l532;bRa{vGf6951U69E94oEQKA00(qQO+^Rf1P~B3DFG(RfB*mh z8FWQhbVF}#ZDnqB07G(RVRU6=Aa`kWXdp*PO;A^X4i^9b0YgbdK~y-)rIWu-!ay9y zKi5(UG-xpCWDKTZ;SqcaR%R0u!{TH32yV`n z7mlKydAXzJnX@=<6CSkyczJ%JNx*liw`;J^;>nb~g9I>q{~~Hs`Ak(F_Um}``zZIL zQ1|@Ut<807*qoM6N<$g0EF=?*IS* literal 0 HcmV?d00001 diff --git a/demos/assets/textures/atlas.png b/demos/assets/textures/atlas.png new file mode 100644 index 0000000000000000000000000000000000000000..498f34dd82959385bc9a96199c88707d782b46a0 GIT binary patch literal 17825 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 DhDLD3 literal 0 HcmV?d00001 diff --git a/demos/assets/textures/snake_head.png b/demos/assets/textures/snake_head.png new file mode 100644 index 0000000000000000000000000000000000000000..9c8dbae6bf5094c1ae8bbef837d7a4a55f3b386c GIT binary patch literal 2517 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 Y0VDO}TI_4aMF0Q*07*qoM6N<$f~@!p@Bjb+ literal 0 HcmV?d00001 diff --git a/demos/compile_wasm.py b/demos/compile_wasm.py index c985693..30d0a0f 100644 --- a/demos/compile_wasm.py +++ b/demos/compile_wasm.py @@ -92,7 +92,7 @@ compile(['source'], 'demo.bc') if clean or os.path.exists('../ecs.bc') == 0 or os.path.isfile('../ecs.bc') == 0: compile(['../source'], '../ecs.bc') -emcc_cmd = 'emcc -v ' + shared_flags + emc_flags + '-s DISABLE_DEPRECATED_FIND_EVENT_TARGET_BEHAVIOR=1 -s ALLOW_MEMORY_GROWTH=1 -s WASM_MEM_MAX=2048MB -s MALLOC=dlmalloc -s WASM=1 -o index.html ' +emcc_cmd = 'emcc -v ' + shared_flags + emc_flags + '-s ERROR_ON_UNDEFINED_SYMBOLS=0 -s DISABLE_DEPRECATED_FIND_EVENT_TARGET_BEHAVIOR=1 -s ALLOW_MEMORY_GROWTH=1 -s MINIFY_HTML=0 -s WASM_MEM_MAX=2048MB -s MALLOC=dlmalloc -s WASM=1 -o ecs_demo.html ' #-s ALLOW_MEMORY_GROWTH=1 -s PROXY_TO_PTHREAD=1 -Wl,--no-check-features -s ERROR_ON_UNDEFINED_SYMBOLS=0 -s TOTAL_MEMORY=512MB emcc_cmd += '../ecs.bc ' diff --git a/demos/source/app.d b/demos/source/app.d index ed4817a..6338035 100644 --- a/demos/source/app.d +++ b/demos/source/app.d @@ -138,6 +138,7 @@ struct CountSystem struct EntitiesData { uint length; + const (Entity)[] entity; } bool onBegin() @@ -749,7 +750,7 @@ void loadGFX() GfxConfig.materials = Mallocator.makeArray!Material(1); GfxConfig.meshes = Mallocator.makeArray!Mesh(1); - float[16] vertices = [-0.5,-0.5, 0,0, -0.5,0.5, 0,1, 0.5,-0.5, 1,0, 0.5,0.5, 1,1]; + float[16] vertices = [-0.5,-0.5, 0,1, -0.5,0.5, 0,0, 0.5,-0.5, 1,1, 0.5,0.5, 1,0]; GfxConfig.meshes[0].vertices = Mallocator.makeArray(vertices); ushort[6] indices = [0,1,2,1,2,3]; GfxConfig.meshes[0].indices = Mallocator.makeArray(indices); diff --git a/demos/source/demos/snake.d b/demos/source/demos/snake.d index 2195aaa..f43c5a5 100644 --- a/demos/source/demos/snake.d +++ b/demos/source/demos/snake.d @@ -38,9 +38,7 @@ struct Snake EntityTemplate* apple_tmpl; EntityTemplate* snake_tmpl; - Texture snake_texture; - Texture wall_texture; - Texture apple_texture; + Texture texture; bool move_system = true; bool draw_system = true; @@ -85,15 +83,16 @@ struct Snake void drawMap() { + const float px = 1.0/512.0; foreach(x; 0 .. map_size) { foreach(y; 0 .. map_size) { switch(element(ivec2(x,y)).type) { - case MapElement.Type.apple:launcher.renderer.draw(apple_texture, vec2(x*32,y*32), vec2(32,32), vec4(0,0,1,1), 0, 0 , 0);break; - case MapElement.Type.snake:launcher.renderer.draw(snake_texture, vec2(x*32,y*32), vec2(32,32), vec4(0,0,1,1), 0, 0 , 0);break; - case MapElement.Type.wall:launcher.renderer.draw(wall_texture, vec2(x*32,y*32), vec2(32,32), vec4(0,0,1,1), 0, 0 , 0);break; + case MapElement.Type.apple:launcher.renderer.draw(texture, vec2(x*32,y*32), vec2(32,32), vec4(0,32*px,16*px,16*px), 0, 0 , 0);break; + case MapElement.Type.snake:launcher.renderer.draw(texture, vec2(x*32,y*32), vec2(32,32), vec4(0,48*px,16*px,16*px), 0, 0 , 0);break; + case MapElement.Type.wall:launcher.renderer.draw(texture, vec2(x*32,y*32), vec2(32,32), vec4(0,0,1,1), 0, 0 , 0);break; default:break; } } @@ -444,14 +443,8 @@ void snakeStart() { snake = Mallocator.make!Snake; - snake.snake_texture.create(); - snake.snake_texture.load("assets/textures/buckler.png"); - - snake.apple_texture.create(); - snake.apple_texture.load("assets/textures/buckler.png"); - - snake.wall_texture.create(); - snake.wall_texture.load("assets/textures/buckler.png"); + snake.texture.create(); + snake.texture.load("assets/textures/atlas.png"); launcher.manager.beginRegister(); @@ -503,10 +496,6 @@ void snakeStart() void snakeEnd() { - snake.wall_texture.destroy(); - snake.apple_texture.destroy(); - snake.snake_texture.destroy(); - //launcher.manager.freeTemplate(simple.tmpl); Mallocator.dispose(snake); } diff --git a/demos/source/demos/space_invaders.d b/demos/source/demos/space_invaders.d index 2ded925..5473aed 100644 --- a/demos/source/demos/space_invaders.d +++ b/demos/source/demos/space_invaders.d @@ -29,9 +29,7 @@ struct SpaceInvaders EntityTemplate* enemy_tmpl; EntityTemplate* ship_tmpl; EntityTemplate* laser_tmpl; - Texture enemy_tex; - Texture ship_tex; - Texture laser_tex; + Texture texture; bool move_system = true; bool draw_system = true; @@ -111,6 +109,7 @@ struct CTexture mixin ECS.Component; Texture tex; + vec4 coords = vec4(0,0,0,1); } struct CVelocity @@ -214,7 +213,7 @@ struct DrawSystem { foreach(i; 0..data.length) { - launcher.renderer.draw(data.textures[i].tex, data.locations[i].value, data.scale[i], vec4(0,0,1,1), 0, 0 , 0); + launcher.renderer.draw(data.textures[i].tex, data.locations[i].value, data.scale[i], data.textures[i].coords, 0, 0 , 0); //draw(renderer, data.textures[i].tex, data.locations[i], vec2(32,32), vec4(0,0,1,1)); } } @@ -645,13 +644,12 @@ __gshared SpaceInvaders* space_invaders; void spaceInvadersStart() { + const float px = 1.0/512.0; + space_invaders = Mallocator.make!SpaceInvaders; - space_invaders.ship_tex.create(); - space_invaders.ship_tex.load("assets/textures/buckler.png"); - - space_invaders.laser_tex.create(); - space_invaders.laser_tex.load("assets/textures/buckler.png"); + space_invaders.texture.create(); + space_invaders.texture.load("assets/textures/atlas.png"); launcher.manager.beginRegister(); @@ -693,7 +691,8 @@ void spaceInvadersStart() space_invaders.ship_tmpl = launcher.manager.allocateTemplate(components); CTexture* tex_comp = space_invaders.ship_tmpl.getComponent!CTexture; - tex_comp.tex = space_invaders.ship_tex; + tex_comp.tex = space_invaders.texture;//ship_tex; + tex_comp.coords = vec4(0*px,48*px,16*px,16*px); CLocation* loc_comp = space_invaders.ship_tmpl.getComponent!CLocation; loc_comp.value = vec2(64,64); CLaserWeapon* weapon = space_invaders.ship_tmpl.getComponent!CLaserWeapon; @@ -707,7 +706,8 @@ void spaceInvadersStart() space_invaders.laser_tmpl = launcher.manager.allocateTemplate(components); CTexture* tex_comp = space_invaders.laser_tmpl.getComponent!CTexture; - tex_comp.tex = space_invaders.laser_tex; + tex_comp.tex = space_invaders.texture;//laser_tex; + tex_comp.coords = vec4(0*px,48*px,16*px,16*px); CScale* scale_comp = space_invaders.laser_tmpl.getComponent!CScale; scale_comp.value = vec2(4,16); CVelocity* vel_comp = space_invaders.laser_tmpl.getComponent!CVelocity; @@ -724,7 +724,8 @@ void spaceInvadersStart() space_invaders.enemy_tmpl = launcher.manager.allocateTemplate(components); CTexture* tex_comp = space_invaders.enemy_tmpl.getComponent!CTexture; - tex_comp.tex = space_invaders.ship_tex; + tex_comp.tex = space_invaders.texture;//ship_tex; + tex_comp.coords = vec4(32*px,32*px,16*px,16*px); CLocation* loc_comp = space_invaders.enemy_tmpl.getComponent!CLocation; loc_comp.value = vec2(64,space_invaders.map_size.y - 64); CShootDirection* shoot_dir_comp = space_invaders.enemy_tmpl.getComponent!CShootDirection; @@ -775,8 +776,6 @@ void spaceInvadersEnd() launcher.manager.getSystem(MovementSystem.system_id).disable(); launcher.manager.getSystem(ClampPositionSystem.system_id).disable(); - space_invaders.ship_tex.destroy(); - launcher.manager.freeTemplate(space_invaders.enemy_tmpl); Mallocator.dispose(space_invaders); } diff --git a/dub.json b/dub.json index dd0933c..1709ae0 100755 --- a/dub.json +++ b/dub.json @@ -125,7 +125,5 @@ "tests/tests.d" ] } - - ] } \ No newline at end of file diff --git a/source/ecs/manager.d b/source/ecs/manager.d index f6f345a..04b1c31 100644 --- a/source/ecs/manager.d +++ b/source/ecs/manager.d @@ -1752,6 +1752,7 @@ export struct EntityManager } add_len++; //move elements after new listener + if(add_len < tmp_add.length) for (int k = add_len; k > j; k--) { tmp_add[k] = tmp_add[k - 1]; @@ -1771,6 +1772,7 @@ export struct EntityManager } rem_len++; //move elements after new listener + if(rem_len < tmp_add.length) for (int k = rem_len; k > j; k--) { tmp_rem[k] = tmp_rem[k - 1]; @@ -1790,6 +1792,7 @@ export struct EntityManager } ch_len++; //move elements after new listener + if(ch_len < tmp_add.length) for (int k = ch_len; k > j; k--) { tmp_ch[k] = tmp_ch[k - 1]; diff --git a/tests/basic.d b/tests/basic.d index c3dfcc5..451f230 100644 --- a/tests/basic.d +++ b/tests/basic.d @@ -1,7 +1,9 @@ module tests.basic; -import ecs.manager; import ecs.core; +import ecs.manager; +import ecs.system; +import ecs.attributes; struct CInt { @@ -57,15 +59,59 @@ struct CUnregistered short value = 12; } +struct LongAddSystem +{ + mixin ECS.System; + + struct EntitiesData + { + int length; + + CLong[] long_; + } + + void onUpdate(EntitiesData data) + { + updates_count++; + foreach(i;0..data.length) + { + data.long_[i] += 1; + } + } + + int updates_count = 0; +} + +struct EmptySystem +{ + mixin ECS.System!16; + + struct EntitiesData + { + int thread_id; + } + + void onUpdate(EntitiesData data) + { + count++; + } + + int count = 0; +} + void beforeEveryTest() { gEM.initialize(1); + gEM.beginRegister(); + gEM.registerComponent!CInt; gEM.registerComponent!CFloat; gEM.registerComponent!CDouble; gEM.registerComponent!CLong; gEM.registerComponent!CShort; + + gEM.endRegister(); } void afterEveryTest() @@ -183,3 +229,344 @@ unittest gEM.freeTemplate(tmpl_6); gEM.freeTemplate(tmpl_7); } + +@("UnsortedComponentIDs") +unittest +{ + //basic template allocation + ushort[2] ids = [CFloat.component_id, CInt.component_id]; + ushort[2] ids2 = [CInt.component_id, CFloat.component_id]; + EntityTemplate* tmpl_ = gEM.allocateTemplate(ids); + EntityTemplate* tmpl_2 = gEM.allocateTemplate(ids2); + assert(tmpl_.info.components.length == 2); + assert(tmpl_.getComponent!CInt); + assert(tmpl_.getComponent!CFloat); + assert(*tmpl_.getComponent!CInt == 1); + assert(*tmpl_.getComponent!CFloat == 2.0); + assert(tmpl_.info == tmpl_2.info); +} + +@("MultiRegister") +unittest +{ + gEM.beginRegister(); + + gEM.endRegister(); + + gEM.beginRegister(); + + gEM.registerComponent!CLong; + gEM.registerComponent!CShort; + + gEM.endRegister(); +} + +@("EmptySystem") +unittest +{ + gEM.beginRegister(); + + gEM.registerSystem!EmptySystem(0); + + gEM.endRegister(); + + EmptySystem* system = gEM.getSystem!EmptySystem; + assert(system !is null); + assert(system.count == 0); + + System* ecs_system = gEM.getSystem(EmptySystem.system_id); + assert(ecs_system !is null); + assert(ecs_system.id == EmptySystem.system_id); + assert(ecs_system.name == "EmptySystem"); + + gEM.begin(); + + gEM.update(); + + gEM.end(); + + assert(system.count == 1); +} + +@("SystemCallbacks") +unittest +{ + struct TestSystem + { + mixin ECS.System!16; + + mixin ECS.ExcludedComponents!(CShort); + + struct EntitiesData + { + int length; + CLong[] long_; + @optional CInt[] int_; + } + + void onCreate() + { + create++; + } + + void onDestroy() + { + (*destroy)++; + } + + void onEnable() + { + enable++; + } + + void onDisable() + { + disable++; + } + + bool onBegin() + { + begin++; + update = 0; + return pass; + } + + void onEnd() + { + end++; + } + + void onUpdate(EntitiesData data) + { + update++; + } + + int create = 0; + int* destroy; + int update = 0; + int begin = 0; + int end = 0; + int enable = 0; + int disable = 0; + bool pass = true; + } + + gEM.beginRegister(); + + gEM.registerSystem!TestSystem(0); + + gEM.endRegister(); + + TestSystem* system = gEM.getSystem!TestSystem; + int destroy = 0; + system.destroy = &destroy; + + gEM.beginRegister(); + + gEM.registerSystem!TestSystem(0); + + gEM.endRegister(); + + system = gEM.getSystem!TestSystem; + system.destroy = &destroy; + assert(system !is null); + assert(system.create == 1); + assert(system.begin == 0); + assert(system.end == 0); + assert(system.enable == 1); + assert(system.disable == 0); + //FIXME: currently destroy is only called with Manager.destory which is bug, but there is no workaround for this by now + //assert(destroy == 1); + + System* ecs_system = gEM.getSystem(system.system_id); + + ecs_system.enable(); + assert(system.enable == 1); + ecs_system.disable(); + ecs_system.disable(); + ecs_system.enable(); + assert(system.enable == 2); + assert(system.disable == 1); + + + ushort[2] ids = [CLong.component_id,CFloat.component_id]; + EntityTemplate* tmpl = gEM.allocateTemplate(ids); + scope (exit) gEM.freeTemplate(tmpl); + gEM.addEntity(tmpl); + + gEM.begin(); + assert(system.begin == 1); + + gEM.update(); + assert(system.update == 1); + + gEM.end(); + assert(system.end == 1); + + ushort[2] ids2 = [CLong.component_id, CInt.component_id]; + EntityTemplate* tmpl2 = gEM.allocateTemplate(ids2); + scope (exit) gEM.freeTemplate(tmpl2); + gEM.addEntity(tmpl2); + gEM.addEntity(tmpl2); + + gEM.begin(); + assert(system.begin == 2); + + gEM.update(); + assert(system.update == 2);//system is updated number of entity blocks times + + gEM.end(); + assert(system.end == 2); + + ushort[2] ids3 = [CLong.component_id, CShort.component_id]; + EntityTemplate* tmpl3 = gEM.allocateTemplate(ids3); + scope (exit) gEM.freeTemplate(tmpl3); + gEM.addEntity(tmpl3); + + //entity with excluded component shouldn't be updated + gEM.begin(); + assert(system.begin == 3); + + gEM.update(); + assert(system.update == 2); + + gEM.end(); + assert(system.end == 3); + + //system can be disable form update in onBegin() callback, onEnd() callback is called + system.pass = false; + gEM.begin(); + assert(system.begin == 4); + + gEM.update(); + assert(system.update == 0); + + gEM.end(); + assert(system.end == 4); + system.pass = true; + + //disabled system is't called + ecs_system.disable(); + gEM.begin(); + assert(system.begin == 4); + + gEM.update(); + assert(system.update == 0); + + gEM.end(); + assert(system.end == 4); + ecs_system.enable(); +} + +@("CustomPass") +unittest +{ + gEM.beginRegister(); + + gEM.registerPass("custom"); + gEM.registerSystem!LongAddSystem(-1,"custom"); + + gEM.endRegister(); + + LongAddSystem* system = gEM.getSystem!LongAddSystem; + assert(system !is null); + assert(system.updates_count == 0); + + System* ecs_system = gEM.getSystem(LongAddSystem.system_id); + assert(ecs_system !is null); + assert(ecs_system.id == LongAddSystem.system_id); + assert(ecs_system.priority == -1); + assert(ecs_system.name == "LongAddSystem"); + + ushort[1] ids = [CLong.component_id]; + EntityTemplate* tmpl = gEM.allocateTemplate(ids); + scope (exit) gEM.freeTemplate(tmpl); + gEM.addEntity(tmpl); + + gEM.begin(); + + gEM.update(); + assert(system.updates_count == 0); + gEM.update("custom"); + assert(system.updates_count == 1); + + gEM.end(); +} + + + +@("SystemEntityCallbacks") +unittest +{ + struct TestSystem + { + mixin ECS.System!16; + + mixin ECS.ExcludedComponents!(CShort); + + struct EntitiesData + { + int length; + CLong[] long_; + @optional CInt[] int_; + } + + void onAddEntity(EntitiesData data) + { + add++; + } + + void onRemoveEntity(EntitiesData data) + { + remove++; + } + + void onChangeEntity(EntitiesData data) + { + change++; + } + + void onUpdate(EntitiesData data) + { + } + + int add = 0; + int remove = 0; + int change = 0; + } + + gEM.beginRegister(); + + gEM.registerSystem!TestSystem(0); + + gEM.endRegister(); + + TestSystem* system = gEM.getSystem!TestSystem; + assert(system !is null); + assert(system.add == 0); + assert(system.remove == 0); + assert(system.change == 0); + + ushort[2] ids = [CLong.component_id,CFloat.component_id]; + EntityTemplate* tmpl = gEM.allocateTemplate(ids); + scope (exit) gEM.freeTemplate(tmpl); + EntityID id0 = gEM.addEntity(tmpl).id; + gEM.commit(); + assert(system.add == 1); + + ushort[2] ids2 = [CLong.component_id, CInt.component_id]; + EntityTemplate* tmpl2 = gEM.allocateTemplate(ids2); + scope (exit) gEM.freeTemplate(tmpl2); + EntityID id1 = gEM.addEntity(tmpl2).id; + gEM.commit(); + assert(system.add == 2); + + ushort[2] ids3 = [CLong.component_id, CShort.component_id]; + EntityTemplate* tmpl3 = gEM.allocateTemplate(ids3); + scope (exit) gEM.freeTemplate(tmpl3); + EntityID id2 = gEM.addEntity(tmpl3).id; + gEM.commit(); + assert(system.add == 2); + + gEM.commit(); +} \ No newline at end of file diff --git a/tests/runner.d b/tests/runner.d index 94b5ed2..9f219bd 100644 --- a/tests/runner.d +++ b/tests/runner.d @@ -60,6 +60,11 @@ string copyString(const char* str) return cast(string) Mallocator.makeArray(arr); } +string copyString(string str) +{ + return cast(string) Mallocator.makeArray((cast(char*)str)[0 .. str.length + 1]); +} + struct TestRunner(Args...) { void generateJUnit() @@ -90,10 +95,10 @@ struct TestRunner(Args...) write(test.name); write("\" classname=\""); write(suite.name); - write("\">\n"); + write("\">"); if (test.msg) { - write("\t\t\t"); write("Assert! File: "); @@ -103,8 +108,10 @@ struct TestRunner(Args...) write(" Message: "); write(test.msg[0 .. $ - 1]); write("\n"); + write("\t\t\n"); } - write("\t\t\n"); + else write("\n"); + } write("\t\n"); @@ -168,21 +175,39 @@ struct TestRunner(Args...) static if (__traits(hasMember, module_, "beforeEveryTest")) module_.beforeEveryTest(); - // Save calling environment for longjmp - int jmp_ret = setjmp(gEnvBuffer); - - if (jmp_ret == ASSERTED) + version(D_BetterC) { - passed = false; - test.passed = false; - test.file = copyString(gAssertInfo.file); - test.file_line = gAssertInfo.line; - test.msg = copyString(gAssertInfo.msg); + // Save calling environment for longjmp + int jmp_ret = setjmp(gEnvBuffer); + + if (jmp_ret == ASSERTED) + { + test.passed = false; + test.file = copyString(gAssertInfo.file); + test.file_line = gAssertInfo.line; + test.msg = copyString(gAssertInfo.msg); + } + else + { + unittest_(); + test.passed = true; + } } else { - unittest_(); - test.passed = true; + import core.exception : AssertError; + try + { + unittest_(); + test.passed = true; + } + catch(AssertError error) + { + test.passed = false; + test.file = copyString(error.file); + test.file_line = cast(int)error.line; + test.msg = copyString(error.msg); + } } if (test.passed) From d0b7138f9f36f0ee957a16d8600c870c9d6982e6 Mon Sep 17 00:00:00 2001 From: Mergul Date: Fri, 17 Apr 2020 17:17:37 +0200 Subject: [PATCH 107/217] More tests: -fixed bug in EntityManger.addComponents -added many new tests --- source/ecs/manager.d | 2 + tests/basic.d | 289 ++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 288 insertions(+), 3 deletions(-) diff --git a/source/ecs/manager.d b/source/ecs/manager.d index 04b1c31..c3c615c 100644 --- a/source/ecs/manager.d +++ b/source/ecs/manager.d @@ -2085,6 +2085,7 @@ export struct EntityManager { num--; new_ids[i] = new_ids[num]; + data_pointers[i] = data_pointers[num]; } } @@ -2558,6 +2559,7 @@ export struct EntityManager pointers[i] = &thread.change_entities_list[index]; index += components[ids[i]].size; } + __addComponents(id, ids, pointers[0 .. num]); } } diff --git a/tests/basic.d b/tests/basic.d index 451f230..f0ab2ef 100644 --- a/tests/basic.d +++ b/tests/basic.d @@ -101,7 +101,7 @@ struct EmptySystem void beforeEveryTest() { - gEM.initialize(1); + gEM.initialize(0); gEM.beginRegister(); @@ -493,11 +493,10 @@ unittest gEM.end(); } - - @("SystemEntityCallbacks") unittest { + //TODO: this test is WIP by now struct TestSystem { mixin ECS.System!16; @@ -569,4 +568,288 @@ unittest assert(system.add == 2); gEM.commit(); +} + +@("TemplateCoverage") +unittest +{ + struct TestSystem + { + mixin ECS.System; + + struct EntitiesData + { + int length; + Entity[] entity; + @readonly CLong[] long_; + @optional CInt[] int_; + @readonly CFloat[] float_; + } + + mixin ECS.ExcludedComponents!(CUnregistered); + + void onUpdate(EntitiesData data) + { + + } + } + + gEM.beginRegister(); + + gEM.registerComponent!CUnregistered; + + gEM.registerSystem!TestSystem(0); + + gEM.endRegister(); +} + +@("UnregisteredSystem") +unittest +{ + struct TestSystem + { + mixin ECS.System; + + struct EntitiesData + { + int length; + Entity[] entity; + @readonly CLong[] long_; + @optional CInt[] int_; + @readonly CFloat[] float_; + } + + void onUpdate(EntitiesData data) + { + + } + } + + assert(gEM.getSystem!TestSystem is null); + assert(gEM.getSystem(TestSystem.system_id) is null); +} + +@("MultithreadedUpdate") +unittest +{ + struct TestSystem + { + mixin ECS.System; + + struct EntitiesData + { + int length; + Entity[] entity; + @readonly CLong[] long_; + @optional CInt[] int_; + @readonly CFloat[] float_; + } + + void onUpdate(EntitiesData data) + { + update++; + entities += data.length; + } + + int update = 0; + int entities = 0; + } + + struct TestEmptySystem + { + mixin ECS.System; + + struct EntitiesData + { + int length; + } + + void onUpdate(EntitiesData data) + { + update++; + } + + int update = 0; + } + + void dispatch(EntityManager.JobGroup grp) + { + foreach(job; grp.jobs) + { + job.execute(); + } + } + + uint getID() + { + return 0; + } + + gEM.setMultithreadingCallbacks(&dispatch, &getID); + + gEM.beginRegister(); + + gEM.registerPass("custom"); + gEM.registerSystem!TestSystem(-1,"custom"); + gEM.registerSystem!TestEmptySystem(1,"custom"); + + gEM.endRegister(); + + TestSystem* system = gEM.getSystem!TestSystem; + TestEmptySystem* empty_system = gEM.getSystem!TestEmptySystem; + + gEM.begin(); + + gEM.updateMT("custom"); + + gEM.end(); + + assert(system.update == 0); + assert(system.entities == 0); + assert(empty_system.update == 1); + + ushort[2] ids = [CLong.component_id,CFloat.component_id]; + EntityTemplate* tmpl = gEM.allocateTemplate(ids); + scope (exit) gEM.freeTemplate(tmpl); + gEM.addEntity(tmpl); + + gEM.begin(); + + gEM.updateMT("custom"); + + gEM.end(); + + assert(system.update == 1); + assert(system.entities == 1); + assert(empty_system.update == 2); + system.entities = 0; + + foreach(i;0..2000)gEM.addEntity(tmpl); + + gEM.begin(); + + gEM.updateMT("custom"); + + gEM.end(); + + assert(system.update > 2); + assert(system.entities == 2001); + assert(empty_system.update == 3); + system.entities = 0; + + foreach(i;0..10000)gEM.addEntity(tmpl); + + gEM.begin(); + + gEM.updateMT("custom"); + + gEM.end(); + + assert(system.entities == 12001); +} + +unittest +{ + assert(gEM.pageSize == 32768); + assert(gEM.pagesInBlock == 128); +} + +@("AddRemoveEntities") +unittest +{ + ushort[3] ids = [CLong.component_id,CFloat.component_id,CShort.component_id]; + EntityTemplate* tmpl = gEM.allocateTemplate(ids); + scope (exit) gEM.freeTemplate(tmpl); + + EntityID[5000] entities; + + foreach(i;0..4) + { + foreach(j;0..5000) + { + entities[j] = gEM.addEntity(tmpl).id; + } + gEM.commit(); + foreach(j;0..5000) + { + gEM.removeEntity(entities[j]); + } + gEM.commit(); + } +} + +@("ChangeEntityComponents") +unittest +{ + gEM.beginRegister(); + + gEM.registerComponent!CUnregistered; + + gEM.endRegister(); + + ushort[1] ids = [CLong.component_id]; + EntityTemplate* tmpl = gEM.allocateTemplate(ids); + scope (exit) gEM.freeTemplate(tmpl); + + EntityID id = gEM.addEntity(tmpl).id; + gEM.commit(); + Entity* entity = gEM.getEntity(id); + assert(entity.id == id); + assert(entity.getComponent!CLong !is null); + assert(entity.getComponent!CFloat is null); + assert(entity.getComponent!CUnregistered is null); + assert(entity.getComponent!CShort is null); + assert(entity.getComponent!CInt is null); + assert(*entity.getComponent!CLong == 10); + + gEM.addComponents(id, CShort(15), CFloat(13)); + gEM.commit(); + + entity = gEM.getEntity(id); + assert(entity.id == id); + assert(entity.getComponent!CLong !is null); + assert(entity.getComponent!CFloat !is null); + assert(entity.getComponent!CUnregistered is null); + assert(entity.getComponent!CShort !is null); + assert(entity.getComponent!CInt is null); + assert(*entity.getComponent!CLong == 10); + assert(*entity.getComponent!CShort == 15); + assert(*entity.getComponent!CFloat == 13); + + ushort[3] ids2 = [CFloat.component_id, CLong.component_id, CUnregistered.component_id]; + gEM.removeComponents(id, ids2); + gEM.commit(); + + entity = gEM.getEntity(id); + assert(entity.id == id); + assert(entity.getComponent!CLong is null); + assert(entity.getComponent!CFloat is null); + assert(entity.getComponent!CUnregistered is null); + assert(entity.getComponent!CShort !is null); + assert(entity.getComponent!CInt is null); + assert(*entity.getComponent!CShort == 15); + + gEM.removeComponents(id, ids2); + gEM.addComponents(id, CShort(11), CLong(2)); //wrong order of components + gEM.commit(); + + entity = gEM.getEntity(id); + assert(entity.id == id); + assert(entity.getComponent!CLong !is null); + assert(entity.getComponent!CFloat is null); + assert(entity.getComponent!CUnregistered is null); + assert(entity.getComponent!CShort !is null); + assert(entity.getComponent!CInt is null); + assert(*entity.getComponent!CLong == 2); + assert(*entity.getComponent!CShort == 15); + + gEM.removeEntity(id); + + entity = gEM.getEntity(id); + assert(entity !is null); + assert(entity.id == id); + + gEM.commit(); + entity = gEM.getEntity(id); + assert(entity is null); } \ No newline at end of file From cb9eaad123d4c79b6e401220f24142763d412144 Mon Sep 17 00:00:00 2001 From: Mergul Date: Sat, 18 Apr 2020 19:16:45 +0200 Subject: [PATCH 108/217] More tests: -removed some unused code -fixed bug with struct destructors (Mallocator called __dtor instead of __xdtor) -added unittests for events -addded _d_eh_personality null implementation as LDC betterC bug workaround --- source/ecs/events.d | 16 +---- source/ecs/manager.d | 5 +- source/ecs/std.d | 6 +- tests/basic.d | 141 ++++++++++++++++++++++++++++++++++++++++++- tests/runner.d | 11 ++++ 5 files changed, 160 insertions(+), 19 deletions(-) diff --git a/source/ecs/events.d b/source/ecs/events.d index 7186d13..317b2f0 100644 --- a/source/ecs/events.d +++ b/source/ecs/events.d @@ -95,7 +95,7 @@ package struct EventManager void clearEvents() nothrow @nogc { - uint threads_count = cast(uint)manager.threads.length; + //uint threads_count = cast(uint)manager.threads.length; foreach(ref event;events) { foreach(ref first_block; event.first_blocks) @@ -133,23 +133,11 @@ package struct EventManager private void disposeData() nothrow @nogc { + clearEvents(); if(events) { foreach(ref event;events) { - foreach(first_block; event.first_blocks) - { - EventBlock* block = first_block; - EventBlock* next_block; - if(block)next_block = first_block.next; - while(block) - { - Mallocator.dispose(block); - block = next_block; - if(block)next_block = block.next; - } - } - Mallocator.dispose(event.blocks); Mallocator.dispose(event.first_blocks); } diff --git a/source/ecs/manager.d b/source/ecs/manager.d index c3c615c..49662dc 100644 --- a/source/ecs/manager.d +++ b/source/ecs/manager.d @@ -3138,12 +3138,13 @@ export struct EntityManager struct EntitiesBlock { ///return distance (in bytes) from begin of block to data - export uint dataDelta() nothrow @nogc pure + ///TODO: probably to remove. It's used by old code if I remeber correctly. + /*export uint dataDelta() nothrow @nogc pure { ushort dif = EntitiesBlock.sizeof; alignNum(dif, type_info.alignment); return dif; - } + }*/ ///return pointer to first element in block export void* dataBegin() nothrow @nogc pure diff --git a/source/ecs/std.d b/source/ecs/std.d index a3a4f5e..6077ede 100644 --- a/source/ecs/std.d +++ b/source/ecs/std.d @@ -187,13 +187,15 @@ static struct Mallocator static void dispose(T)(T object) nothrow @nogc { - static if(__traits(hasMember, T, "__dtor"))object.__dtor(); + static if(__traits(hasMember, T, "__xdtor"))object.__xdtor(); + else static if(__traits(hasMember, T, "__dtor"))object.__dtor(); free(cast(void*)object); } static void alignDispose(T)(T object) { - static if(__traits(hasMember, T, "__dtor"))object.__dtor(); + static if(__traits(hasMember, T, "__xdtor"))object.__xdtor(); + else static if(__traits(hasMember, T, "__dtor"))object.__dtor(); version(Posix)free(cast(void*)object); else version(Windows)_aligned_free(cast(void*)object); else version(ECSEmscripten)free(cast(void*)object); diff --git a/tests/basic.d b/tests/basic.d index f0ab2ef..38b5605 100644 --- a/tests/basic.d +++ b/tests/basic.d @@ -311,7 +311,7 @@ unittest void onDestroy() { - (*destroy)++; + if(destroy)(*destroy)++; } void onEnable() @@ -456,6 +456,7 @@ unittest gEM.end(); assert(system.end == 4); ecs_system.enable(); + system.destroy = null; } @("CustomPass") @@ -852,4 +853,142 @@ unittest gEM.commit(); entity = gEM.getEntity(id); assert(entity is null); +} + +@("EventCallbacks") +unittest +{ + struct ETest + { + mixin ECS.Event; + } + + struct ETest2 + { + mixin ECS.Event; + int super_liczba = 0; + } + + struct TestSystem + { + mixin ECS.System; + + struct EntitiesData + { + int length; + Entity[] entity; + @readonly CLong[] long_; + @optional CInt[] int_; + } + + void onUpdate(EntitiesData data) + { + + } + + void handleEvent(Entity* entity, ETest event) + { + CLong* long_ = entity.getComponent!CLong; + CInt* int_ = entity.getComponent!CInt; + *long_ += 16; + if(int_)*int_ += 6; + } + + void handleEvent(Entity* entity, ETest2 event) + { + CLong* long_ = entity.getComponent!CLong; + CInt* int_ = entity.getComponent!CInt; + *long_ += event.super_liczba * 2; + if(int_)*int_ += event.super_liczba * 4; + } + } + + struct TestSystem2 + { + mixin ECS.System; + + struct EntitiesData + { + int length; + Entity[] entity; + CShort[] short_; + @optional CInt[] int_; + } + + void handleEvent(Entity* entity, ETest event) + { + CShort* short_ = entity.getComponent!CShort; + CInt* int_ = entity.getComponent!CInt; + *short_ += 8; + if(int_)*int_ += 2; + } + + void handleEvent(Entity* entity, ETest2 event) + { + CShort* short_ = entity.getComponent!CShort; + CInt* int_ = entity.getComponent!CInt; + *short_ += event.super_liczba; + if(int_)*int_ *= event.super_liczba; + } + } + + gEM.beginRegister(); + + gEM.registerEvent!ETest; + gEM.registerEvent!ETest2; + + gEM.registerSystem!TestSystem2(1); + gEM.registerSystem!TestSystem(0); + + gEM.endRegister(); + + ushort[1] ids = [CLong.component_id]; + EntityTemplate* tmpl = gEM.allocateTemplate(ids); + scope (exit) gEM.freeTemplate(tmpl); + ushort[1] ids2 = [CShort.component_id]; + EntityTemplate* tmpl2 = gEM.allocateTemplate(ids2); + scope (exit) gEM.freeTemplate(tmpl2); + + Entity* entity = gEM.addEntity(tmpl); + EntityID id = entity.id; + assert(*entity.getComponent!CLong == 10); + Entity* entity2 = gEM.addEntity(tmpl2); + EntityID id2 = entity2.id; + assert(*entity2.getComponent!CShort == 12); + + gEM.sendEvent(id,ETest()); + gEM.sendEvent(id,ETest2(id,10)); + gEM.sendEvent(id2,ETest()); + gEM.sendEvent(id2,ETest2(id2,12)); + gEM.commit(); + + entity = gEM.getEntity(id); + entity2 = gEM.getEntity(id2); + assert(*entity.getComponent!CLong == 46); + assert(*entity2.getComponent!CShort == 32); + + gEM.addComponents(id, CInt(2), CShort(1)); + gEM.sendEvent(id,ETest()); + gEM.sendEvent(id,ETest2(id,2)); + gEM.commit(); + + entity = gEM.getEntity(id); + assert(*entity.getComponent!CLong == 66); + assert(*entity.getComponent!CInt == 36); + + //test for multiple event blocks + long result = *entity.getComponent!CLong; + foreach(i;0..10000) + { + gEM.sendEvent(id,ETest()); + gEM.sendEvent(id,ETest2(id,4)); + result += 16; + result += 8; + } + gEM.commit(); + entity = gEM.getEntity(id); + assert(*entity.getComponent!CLong == result); + + //cover funcion to clearEvents before destroying manager + gEM.sendEvent(id,ETest()); } \ No newline at end of file diff --git a/tests/runner.d b/tests/runner.d index 9f219bd..5eaf99b 100644 --- a/tests/runner.d +++ b/tests/runner.d @@ -385,3 +385,14 @@ extern (C) int main(int argc, char** args) else return 1; } + +version (D_BetterC) +{ + version(LDC) + { + extern (C) __gshared int _d_eh_personality(int, int, size_t, void*, void*) + { + return 0; + } + } +} \ No newline at end of file From f7a1e9bd05fb9640b8e7b2aeb2fa3fd28bdcbd4b Mon Sep 17 00:00:00 2001 From: Mergul Date: Wed, 22 Apr 2020 16:23:42 +0200 Subject: [PATCH 109/217] More test and fixes: -added test for addEntityCopy -test order of onAddEntity, onRemoveEntity, onChangeEntity callbacks calls -testing onAddEntity, onRemoveEntity, onChangeEntity callback -test callEntityFunction call -fixed bug with crashing ECS (setting callers for entity change callbacks) -commented debug asserts conering duplicated components ids (to further consideration) --- source/ecs/manager.d | 23 ++-- tests/basic.d | 249 +++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 250 insertions(+), 22 deletions(-) diff --git a/source/ecs/manager.d b/source/ecs/manager.d index 49662dc..1b9b959 100644 --- a/source/ecs/manager.d +++ b/source/ecs/manager.d @@ -1187,7 +1187,7 @@ export struct EntityManager (cast(Ev*) pointer).onDestroy(); } - info.destroy_callback = &callDestroy; + info.destroy_callback = cast(void function(void*) nothrow @nogc)&callDestroy; } info.size = Ev.sizeof; @@ -1214,7 +1214,7 @@ export struct EntityManager "Can't call function with system which hasn't EntitesData structure."); static assert(__traits(hasMember, Sys, "onUpdate"), "Can't call function with system which hasn't onUpdate function callback."); - static assert(is(T == typeof(&s.onUpdate)), "Function must match system update function."); + static assert(is(SetFunctionAttributes!(T,functionLinkage!(s.onUpdate), functionAttributes!(s.onUpdate)) == typeof(&s.onUpdate)), "Function must match system update function."); static assert(__traits(hasMember, Sys, "system_id"), "Sys must be system type."); System* system = getSystem(Sys.system_id); @@ -1527,8 +1527,8 @@ export struct EntityManager ids[j] = ids[i]; j++; } - else - debug assert(0, "Duplicated components in template!!!"); + //else + // debug assert(0, "Duplicated components in template!!!"); } ids = ids[0 .. j]; } @@ -1544,8 +1544,6 @@ export struct EntityManager { memcpy(temp.entity_data.ptr + info.tmpl_deltas[comp], components[comp].init_data.ptr, components[comp].size); - /*temp.entity_data[info.tmpl_deltas[comp] .. info.tmpl_deltas[comp] + components[comp].size] - = components[comp].init_data;*/ } return temp; @@ -1593,8 +1591,8 @@ export struct EntityManager ids[j] = ids[i]; j++; } - else - debug assert(0, "Duplicated components in template!!!"); + //else + // debug assert(0, "Duplicated components in template!!!"); } ids = ids[0 .. j]; } @@ -1747,7 +1745,7 @@ export struct EntityManager int j; for (j = 0; j < add_len; j++) { - if (systems[i].priority > systems[tmp_add[j]].priority) + if (systems[i].priority < systems[tmp_add[j]].priority) break; } add_len++; @@ -1767,7 +1765,7 @@ export struct EntityManager int j; for (j = 0; j < rem_len; j++) { - if (systems[i].priority > systems[tmp_rem[j]].priority) + if (systems[i].priority < systems[tmp_rem[j]].priority) break; } rem_len++; @@ -1787,7 +1785,7 @@ export struct EntityManager int j; for (j = 0; j < ch_len; j++) { - if (systems[i].priority > systems[tmp_ch[j]].priority) + if (systems[i].priority < systems[tmp_ch[j]].priority) break; } ch_len++; @@ -2727,6 +2725,7 @@ export struct EntityManager call_data); } } + if(events[i].destroy_callback)events[i].destroy_callback(event_pointer); event_pointer += events[i].size; } block = block.next; @@ -2957,7 +2956,7 @@ export struct EntityManager ushort size; ushort alignment; EventCaller[] callers; - void function(void* pointer) destroy_callback; + void function(void* pointer) nothrow @nogc destroy_callback; } /************************************************************************************************************************ diff --git a/tests/basic.d b/tests/basic.d index 38b5605..f3f2832 100644 --- a/tests/basic.d +++ b/tests/basic.d @@ -5,6 +5,8 @@ import ecs.manager; import ecs.system; import ecs.attributes; +import std.array : staticArray; + struct CInt { mixin ECS.Component; @@ -137,6 +139,13 @@ unittest assert(entity.getComponent!CFloat); assert(*entity.getComponent!CInt == 1); assert(*entity.getComponent!CFloat == 2.0); + *entity.getComponent!CInt = 2; + + Entity* entity2 = gEM.addEntityCopy(entity.id); + assert(entity2.getComponent!CInt); + assert(entity2.getComponent!CFloat); + assert(*entity2.getComponent!CInt == 2); + assert(*entity2.getComponent!CFloat == 2.0); } //allocate templates @@ -146,6 +155,8 @@ unittest //basic template allocation ushort[2] ids = [CInt.component_id, CFloat.component_id]; EntityTemplate* tmpl_ = gEM.allocateTemplate(ids); + EntityTemplate* tmpl_d = gEM.allocateTemplate([CFloat.component_id, CInt.component_id, CFloat.component_id].staticArray); + assert(tmpl_d.info == tmpl_.info); assert(tmpl_.info.components.length == 2); assert(tmpl_.getComponent!CInt); assert(tmpl_.getComponent!CFloat); @@ -221,6 +232,7 @@ unittest assert(*tmpl_7.getComponent!CDouble == 3.0); assert(*tmpl_7.getComponent!CLong == 10); + gEM.freeTemplate(tmpl_d); gEM.freeTemplate(tmpl_); gEM.freeTemplate(tmpl_2); gEM.freeTemplate(tmpl_3); @@ -497,7 +509,9 @@ unittest @("SystemEntityCallbacks") unittest { - //TODO: this test is WIP by now + static int add_order = 0; + static int rem_order = 0; + static int change_order = 0; struct TestSystem { mixin ECS.System!16; @@ -514,16 +528,22 @@ unittest void onAddEntity(EntitiesData data) { add++; + assert(add_order == 1); + add_order++; } void onRemoveEntity(EntitiesData data) { remove++; + assert(rem_order == 1); + rem_order++; } void onChangeEntity(EntitiesData data) { change++; + assert(change_order == 1); + change_order++; } void onUpdate(EntitiesData data) @@ -535,9 +555,83 @@ unittest int change = 0; } + struct TestSystem2 + { + mixin ECS.System!16; + + mixin ECS.ExcludedComponents!(CShort); + + struct EntitiesData + { + int length; + CLong[] long_; + @optional CInt[] int_; + } + + void onAddEntity(EntitiesData data) + { + assert(add_order == 2); + add_order = 0; + } + + void onRemoveEntity(EntitiesData data) + { + assert(rem_order == 2); + rem_order = 0 ; + } + + void onChangeEntity(EntitiesData data) + { + assert(change_order == 2); + change_order = 0; + } + + void onUpdate(EntitiesData data) + { + } + } + + struct TestSystem3 + { + mixin ECS.System!16; + + mixin ECS.ExcludedComponents!(CShort); + + struct EntitiesData + { + int length; + CLong[] long_; + @optional CInt[] int_; + } + + void onAddEntity(EntitiesData data) + { + assert(add_order == 0); + add_order++; + } + + void onRemoveEntity(EntitiesData data) + { + assert(rem_order == 0); + rem_order++; + } + + void onChangeEntity(EntitiesData data) + { + assert(change_order == 0); + change_order++; + } + + void onUpdate(EntitiesData data) + { + } + } + gEM.beginRegister(); + gEM.registerSystem!TestSystem3(-1); gEM.registerSystem!TestSystem(0); + gEM.registerSystem!TestSystem2(1); gEM.endRegister(); @@ -547,28 +641,80 @@ unittest assert(system.remove == 0); assert(system.change == 0); - ushort[2] ids = [CLong.component_id,CFloat.component_id]; - EntityTemplate* tmpl = gEM.allocateTemplate(ids); + EntityTemplate* tmpl = gEM.allocateTemplate([CLong.component_id,CFloat.component_id].staticArray); scope (exit) gEM.freeTemplate(tmpl); EntityID id0 = gEM.addEntity(tmpl).id; gEM.commit(); assert(system.add == 1); - ushort[2] ids2 = [CLong.component_id, CInt.component_id]; - EntityTemplate* tmpl2 = gEM.allocateTemplate(ids2); + EntityTemplate* tmpl2 = gEM.allocateTemplate([CLong.component_id, CInt.component_id].staticArray); scope (exit) gEM.freeTemplate(tmpl2); EntityID id1 = gEM.addEntity(tmpl2).id; gEM.commit(); assert(system.add == 2); - ushort[2] ids3 = [CLong.component_id, CShort.component_id]; - EntityTemplate* tmpl3 = gEM.allocateTemplate(ids3); + EntityTemplate* tmpl3 = gEM.allocateTemplate([CLong.component_id, CShort.component_id].staticArray); scope (exit) gEM.freeTemplate(tmpl3); EntityID id2 = gEM.addEntity(tmpl3).id; gEM.commit(); assert(system.add == 2); + gEM.beginRegister(); + gEM.endRegister(); + + gEM.removeComponents(id0, [CFloat.component_id].staticArray); gEM.commit(); + assert(system.add == 2); + assert(system.remove == 0); + assert(system.change == 0); + + gEM.removeComponents(id1, [CInt.component_id].staticArray); + gEM.commit(); + assert(system.add == 2); + assert(system.remove == 0); + assert(system.change == 1); + + gEM.removeComponents(id2, [CShort.component_id].staticArray); + gEM.commit(); + assert(system.add == 3); + assert(system.remove == 0); + assert(system.change == 1); + + gEM.addComponents(id2, CShort(1)); + gEM.commit(); + assert(system.add == 3); + assert(system.remove == 1); + assert(system.change == 1); + + gEM.removeEntity(id0); + gEM.commit(); + assert(system.add == 3); + assert(system.remove == 2); + assert(system.change == 1); + + gEM.addComponents(id1, CInt(1)); + gEM.commit(); + assert(system.add == 3); + assert(system.remove == 2); + assert(system.change == 2); + + gEM.addComponents(id0, CFloat(1)); + gEM.commit(); + assert(system.add == 3); + assert(system.remove == 2); + assert(system.change == 2); + + gEM.removeEntity(id1); + gEM.commit(); + assert(system.add == 3); + assert(system.remove == 3); + assert(system.change == 2); + + gEM.removeEntity(id2); + gEM.commit(); + assert(system.add == 3); + assert(system.remove == 3); + assert(system.change == 2); } @("TemplateCoverage") @@ -699,6 +845,12 @@ unittest TestSystem* system = gEM.getSystem!TestSystem; TestEmptySystem* empty_system = gEM.getSystem!TestEmptySystem; + ushort[2] ids = [CLong.component_id,CFloat.component_id]; + EntityTemplate* tmpl = gEM.allocateTemplate(ids); + scope (exit) gEM.freeTemplate(tmpl); + EntityTemplate* tmpl2 = gEM.allocateTemplate([CLong.component_id,CInt.component_id,CShort.component_id,CFloat.component_id].staticArray); + scope (exit) gEM.freeTemplate(tmpl2); + gEM.begin(); gEM.updateMT("custom"); @@ -709,9 +861,6 @@ unittest assert(system.entities == 0); assert(empty_system.update == 1); - ushort[2] ids = [CLong.component_id,CFloat.component_id]; - EntityTemplate* tmpl = gEM.allocateTemplate(ids); - scope (exit) gEM.freeTemplate(tmpl); gEM.addEntity(tmpl); gEM.begin(); @@ -866,7 +1015,14 @@ unittest struct ETest2 { mixin ECS.Event; + + void onDestroy() + { + destory++; + } + int super_liczba = 0; + static int destory = 0; } struct TestSystem @@ -937,6 +1093,9 @@ unittest gEM.registerEvent!ETest; gEM.registerEvent!ETest2; + gEM.registerEvent!ETest; + gEM.registerEvent!ETest2; + gEM.registerSystem!TestSystem2(1); gEM.registerSystem!TestSystem(0); @@ -961,6 +1120,7 @@ unittest gEM.sendEvent(id2,ETest()); gEM.sendEvent(id2,ETest2(id2,12)); gEM.commit(); + assert(ETest2.destory == 2); entity = gEM.getEntity(id); entity2 = gEM.getEntity(id2); @@ -971,6 +1131,7 @@ unittest gEM.sendEvent(id,ETest()); gEM.sendEvent(id,ETest2(id,2)); gEM.commit(); + assert(ETest2.destory == 3); entity = gEM.getEntity(id); assert(*entity.getComponent!CLong == 66); @@ -986,9 +1147,77 @@ unittest result += 8; } gEM.commit(); + assert(ETest2.destory == 10003); entity = gEM.getEntity(id); assert(*entity.getComponent!CLong == result); //cover funcion to clearEvents before destroying manager gEM.sendEvent(id,ETest()); +} + +@("EntitiesFunction") +unittest +{ + struct TestSystem + { + mixin ECS.System; + + struct EntitiesData + { + uint length; + CInt[] int_; + } + + void onUpdate(EntitiesData entities) + { + + } + } + + void func1(TestSystem.EntitiesData entities) + { + foreach(i;0 .. entities.length) + { + entities.int_[i] += entities.int_[i] / 2; + } + } + + void func2(TestSystem.EntitiesData entities) + { + foreach(i;0 .. entities.length) + { + entities.int_[i] += 8; + } + } + + gEM.beginRegister(); + + gEM.registerSystem!TestSystem(1); + + gEM.endRegister(); + + EntityTemplate* tmpl = gEM.allocateTemplate([CInt.component_id].staticArray); + scope (exit) gEM.freeTemplate(tmpl); + EntityID id1 = gEM.addEntity(tmpl).id; + + EntityTemplate* tmpl2 = gEM.allocateTemplate([CInt.component_id, CLong.component_id].staticArray); + scope (exit) gEM.freeTemplate(tmpl2); + EntityID id2 = gEM.addEntity(tmpl2).id; + + gEM.begin(); + + Entity* entity1 = gEM.getEntity(id1); + Entity* entity2 = gEM.getEntity(id2); + assert(*entity1.getComponent!CInt == 1); + assert(*entity2.getComponent!CInt == 1); + + gEM.callEntitiesFunction!TestSystem(&func2); + assert(*entity1.getComponent!CInt == 9); + assert(*entity2.getComponent!CInt == 9); + + gEM.callEntitiesFunction!TestSystem(&func1); + assert(*entity1.getComponent!CInt == 13); + assert(*entity2.getComponent!CInt == 13); + + gEM.end(); } \ No newline at end of file From 7c263d3ed48b450e2a2a2d3487cb2c75c3b17208 Mon Sep 17 00:00:00 2001 From: Mergul Date: Fri, 24 Apr 2020 20:47:42 +0200 Subject: [PATCH 110/217] SimpleVector test improvement --- tests/vector.d | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/tests/vector.d b/tests/vector.d index 109ff37..4b2ad5b 100644 --- a/tests/vector.d +++ b/tests/vector.d @@ -16,4 +16,20 @@ unittest vector.clear(); assert(vector.length == 0); + + ubyte[1025] array; + foreach(i;0..cast(uint)array.length)array[i] = cast(ubyte)i; + vector.add(array); + assert(vector.length == 1025); + assert(vector[] == array[]); + + SimpleVector vector2; + vector2.clear(); + vector2.add(array[0..1023]); + vector2.add('a'); + vector2.add('b'); + assert(vector2.length == 1025); + assert(vector2[0..1023] == array[0..1023]); + assert(vector2[1023] == 'a'); + assert(vector2[1024] == 'b'); } From 8381ac166bb672b512279ac0d5bc2fda0ded385e Mon Sep 17 00:00:00 2001 From: Mergul Date: Fri, 24 Apr 2020 20:55:25 +0200 Subject: [PATCH 111/217] Common update: -added VBo batch rendering (current default, no render mode switch yet) -fixed camera positioning calculation -fixed buffer issue with WebGL -added viewport scalling (at least 300 pixels height). Pixels are scalled if screen is bigger. -center demos gameplay area -added fullpage html template for Emscripten build --- demos/compile_wasm.py | 2 +- demos/source/app.d | 15 ++++++++--- demos/source/demos/simple.d | 15 +++++++---- demos/source/demos/snake.d | 12 +++++---- demos/source/demos/space_invaders.d | 23 +++++++++-------- demos/utils/source/ecs_utils/gfx/buffer.d | 6 ++--- demos/utils/source/ecs_utils/gfx/renderer.d | 28 ++++++++++++--------- 7 files changed, 61 insertions(+), 40 deletions(-) diff --git a/demos/compile_wasm.py b/demos/compile_wasm.py index 30d0a0f..b1f3a7e 100644 --- a/demos/compile_wasm.py +++ b/demos/compile_wasm.py @@ -92,7 +92,7 @@ compile(['source'], 'demo.bc') if clean or os.path.exists('../ecs.bc') == 0 or os.path.isfile('../ecs.bc') == 0: compile(['../source'], '../ecs.bc') -emcc_cmd = 'emcc -v ' + shared_flags + emc_flags + '-s ERROR_ON_UNDEFINED_SYMBOLS=0 -s DISABLE_DEPRECATED_FIND_EVENT_TARGET_BEHAVIOR=1 -s ALLOW_MEMORY_GROWTH=1 -s MINIFY_HTML=0 -s WASM_MEM_MAX=2048MB -s MALLOC=dlmalloc -s WASM=1 -o ecs_demo.html ' +emcc_cmd = 'emcc -v ' + shared_flags + emc_flags + '-s ERROR_ON_UNDEFINED_SYMBOLS=0 -s DISABLE_DEPRECATED_FIND_EVENT_TARGET_BEHAVIOR=1 -s ALLOW_MEMORY_GROWTH=1 -s MINIFY_HTML=0 -s WASM_MEM_MAX=2048MB -s MALLOC=dlmalloc -s WASM=1 -o ecs_demo.html --shell-file emscripten_shell.html ' #-s ALLOW_MEMORY_GROWTH=1 -s PROXY_TO_PTHREAD=1 -Wl,--no-check-features -s ERROR_ON_UNDEFINED_SYMBOLS=0 -s TOTAL_MEMORY=512MB emcc_cmd += '../ecs.bc ' diff --git a/demos/source/app.d b/demos/source/app.d index 6338035..150d653 100644 --- a/demos/source/app.d +++ b/demos/source/app.d @@ -51,6 +51,7 @@ struct Launcher void function() end; void function(SDL_Event*) event; void function(vec2, Tool, int) tool; + float scalling; ivec2 window_size = ivec2(1024,768); Renderer renderer; ubyte[] keys; @@ -60,6 +61,7 @@ struct Launcher ulong timer_freq; double delta_time; uint fps; + vec2 render_position; Tool used_tool; int tool_size = 0; @@ -229,7 +231,7 @@ void mainLoop(void* arg) } if(launcher.tool && event.button.button == SDL_BUTTON_LEFT && launcher.tool_repeat == 0 && !igIsWindowHovered(ImGuiHoveredFlags_AnyWindow)) { - launcher.tool(vec2(event.button.x, launcher.window_size.y - event.button.y), launcher.used_tool, launcher.tool_size); + launcher.tool(vec2(event.button.x, launcher.window_size.y - event.button.y) * launcher.scalling - launcher.render_position, launcher.used_tool, launcher.tool_size); } } else if(event.type == SDL_MOUSEBUTTONUP) @@ -255,7 +257,7 @@ void mainLoop(void* arg) while(launcher.repeat_time > range) { launcher.repeat_time -= range; - launcher.tool(launcher.mouse.position, launcher.used_tool, launcher.tool_size); + launcher.tool((launcher.mouse.position*launcher.scalling)-launcher.render_position, launcher.used_tool, launcher.tool_size); } } @@ -525,7 +527,14 @@ void mainLoop(void* arg) } launcher.renderer.resize(launcher.window_size); - launcher.renderer.view(vec2(0,0),vec2(launcher.window_size.x,launcher.window_size.y)); + //launcher.renderer.view(vec2(0,0),vec2(launcher.window_size.x,launcher.window_size.y)); + //if(384, 768, 1152, 1536) + //576 960 1344 1728 + //float scalling; + if(launcher.window_size.y < 360)launcher.scalling = 1; + else launcher.scalling = 1.0 / ((launcher.window_size.y+120)/360); + launcher.renderer.view(launcher.render_position,vec2(launcher.window_size.x,launcher.window_size.y)*launcher.scalling); + //launcher.renderer.view(vec2(0,0),vec2(1024*launcher.window_size.x/launcher.window_size.y,768)); //glClear(GL_COLOR_BUFFER_BIT); launcher.renderer.clear(); diff --git a/demos/source/demos/simple.d b/demos/source/demos/simple.d index 36187c8..edd20c6 100644 --- a/demos/source/demos/simple.d +++ b/demos/source/demos/simple.d @@ -60,7 +60,7 @@ struct DrawSystem { foreach(i; 0..data.length) { - launcher.renderer.draw(data.textures[i].tex, data.locations[i].location, vec2(32,32), vec4(0,0,1,1), 0, 0 , 0); + launcher.renderer.draw(data.textures[i].tex, data.locations[i].location, vec2(16,16), vec4(0,0,1,1), 0, 0 , 0); //draw(renderer, data.textures[i].tex, data.locations[i], vec2(32,32), vec4(0,0,1,1)); } } @@ -81,7 +81,7 @@ struct MoveSystem foreach(i; 0..data.length) { data.locations[i].location.y = data.locations[i].location.y + 1; - if(data.locations[i].location.y > 400)data.locations[i].location.y = 0; + if(data.locations[i].location.y > 300)data.locations[i].location.y = 0; } } } @@ -119,7 +119,7 @@ void simpleStart() foreach(i; 0..10) foreach(j; 0..10) { - loc_comp.location = vec2(i*32+64,j*32+64); + loc_comp.location = vec2(i*16+64,j*16+64); launcher.manager.addEntity(simple.tmpl); } } @@ -147,6 +147,10 @@ void simpleTool(vec2 position, Tool tool, int size) { position.x += (randomf - 0.5) * size; position.y += (randomf - 0.5) * size; + if(position.x > 400)position.x -= 400; + else if(position.x < 0)position.x += 400; + if(position.y > 300)position.y -= 300; + else if(position.y < 0)position.y += 300; *location = position; } launcher.manager.addEntity(tmpl); @@ -169,17 +173,18 @@ void simpleEvent(SDL_Event* event) void spawnEntity() { CLocation* loc_comp = simple.tmpl.getComponent!CLocation; - loc_comp.location = vec2(randomf() * 600,0); + loc_comp.location = vec2(randomf() * 400,0); launcher.manager.addEntity(simple.tmpl); } bool simpleLoop() { + launcher.render_position = (vec2(launcher.window_size.x,launcher.window_size.y)*launcher.scalling - vec2(400,300)) * 0.5; + if(launcher.getKeyState(SDL_SCANCODE_SPACE)) { foreach(i;0..1)spawnEntity(); } - launcher.manager.begin(); if(launcher.multithreading) diff --git a/demos/source/demos/snake.d b/demos/source/demos/snake.d index f43c5a5..19d0e31 100644 --- a/demos/source/demos/snake.d +++ b/demos/source/demos/snake.d @@ -90,9 +90,9 @@ struct Snake { switch(element(ivec2(x,y)).type) { - case MapElement.Type.apple:launcher.renderer.draw(texture, vec2(x*32,y*32), vec2(32,32), vec4(0,32*px,16*px,16*px), 0, 0 , 0);break; - case MapElement.Type.snake:launcher.renderer.draw(texture, vec2(x*32,y*32), vec2(32,32), vec4(0,48*px,16*px,16*px), 0, 0 , 0);break; - case MapElement.Type.wall:launcher.renderer.draw(texture, vec2(x*32,y*32), vec2(32,32), vec4(0,0,1,1), 0, 0 , 0);break; + case MapElement.Type.apple:launcher.renderer.draw(texture, vec2(x*16,y*16), vec2(16,16), vec4(0,32*px,16*px,16*px), 0, 0 , 0);break; + case MapElement.Type.snake:launcher.renderer.draw(texture, vec2(x*16,y*16), vec2(16,16), vec4(0,48*px,16*px,16*px), 0, 0 , 0);break; + case MapElement.Type.wall:launcher.renderer.draw(texture, vec2(x*16,y*16), vec2(16,16), vec4(0,0,1,1), 0, 0 , 0);break; default:break; } } @@ -520,8 +520,8 @@ void snakeTool(vec2 position, Tool tool, int size) position.x += (randomf - 0.5) * size; position.y += (randomf - 0.5) * size; ivec2 ipos; - ipos.x = cast(int)(position.x / 32); - ipos.y = cast(int)(position.y / 32); + ipos.x = cast(int)(position.x / 16); + ipos.y = cast(int)(position.y / 16); *ilocation = ipos; if(snake.element(ipos).type != MapElement.Type.empty)return; } @@ -540,6 +540,8 @@ void snakeEvent(SDL_Event* event) bool snakeLoop() { + launcher.render_position = (vec2(launcher.window_size.x,launcher.window_size.y)*launcher.scalling - vec2(288,288)) * 0.5; + /*if(launcher.show_demo_wnd) { igSetNextWindowPos(ImVec2(800 - 260, 30), ImGuiCond_Once, ImVec2(0,0)); diff --git a/demos/source/demos/space_invaders.d b/demos/source/demos/space_invaders.d index 5473aed..7058b59 100644 --- a/demos/source/demos/space_invaders.d +++ b/demos/source/demos/space_invaders.d @@ -34,7 +34,7 @@ struct SpaceInvaders bool move_system = true; bool draw_system = true; - const vec2 map_size = vec2(600,600); + const vec2 map_size = vec2(400,300); const float cell_size = 60; } @@ -101,7 +101,7 @@ struct CScale ///use component as it value alias value this; - vec2 value = vec2(32,32); + vec2 value = vec2(16,16); } struct CTexture @@ -564,8 +564,8 @@ struct MovementSystem { foreach(i;0..data.length) { - data.locations[i].x += data.velocity[i].x * launcher.delta_time; - data.locations[i].y += data.velocity[i].y * launcher.delta_time; + data.locations[i].x += data.velocity[i].x * launcher.delta_time * 0.5; + data.locations[i].y += data.velocity[i].y * launcher.delta_time * 0.5; } } } @@ -630,8 +630,8 @@ struct InputMovementSystem //move every entity using movement vector foreach(i; 0..data.length) { - data.locations[i].x += move_vector.x * launcher.delta_time * 0.5; - data.locations[i].y += move_vector.y * launcher.delta_time * 0.5; + data.locations[i].x += move_vector.x * launcher.delta_time * 0.25; + data.locations[i].y += move_vector.y * launcher.delta_time * 0.25; } } } @@ -709,7 +709,7 @@ void spaceInvadersStart() tex_comp.tex = space_invaders.texture;//laser_tex; tex_comp.coords = vec4(0*px,48*px,16*px,16*px); CScale* scale_comp = space_invaders.laser_tmpl.getComponent!CScale; - scale_comp.value = vec2(4,16); + scale_comp.value = vec2(2,8); CVelocity* vel_comp = space_invaders.laser_tmpl.getComponent!CVelocity; vel_comp.value = vec2(0,1); } @@ -727,7 +727,7 @@ void spaceInvadersStart() tex_comp.tex = space_invaders.texture;//ship_tex; tex_comp.coords = vec4(32*px,32*px,16*px,16*px); CLocation* loc_comp = space_invaders.enemy_tmpl.getComponent!CLocation; - loc_comp.value = vec2(64,space_invaders.map_size.y - 64); + loc_comp.value = vec2(64,space_invaders.map_size.y - 16); CShootDirection* shoot_dir_comp = space_invaders.enemy_tmpl.getComponent!CShootDirection; shoot_dir_comp.direction = Direction.down; CVelocity* vel_comp = space_invaders.enemy_tmpl.getComponent!CVelocity; @@ -738,17 +738,17 @@ void spaceInvadersStart() current_entity = launcher.manager.addEntity(space_invaders.enemy_tmpl); launcher.manager.addComponents(current_entity.id,CSideMove(0)); - loc_comp.value = vec2(128,space_invaders.map_size.y - 64); + loc_comp.value = vec2(128,space_invaders.map_size.y - 16); current_entity = launcher.manager.addEntity(space_invaders.enemy_tmpl); launcher.manager.addComponents(current_entity.id,CSideMove(-1)); enemy_id = current_entity.id; //enemy_tmpl = launcher.manager.allocateTemplate(current_entity.id); - loc_comp.value = vec2(256,space_invaders.map_size.y - 64); + loc_comp.value = vec2(256,space_invaders.map_size.y - 16); launcher.manager.addEntity(space_invaders.enemy_tmpl); - loc_comp.value = vec2(0,space_invaders.map_size.y - 64); + loc_comp.value = vec2(0,space_invaders.map_size.y - 16); current_entity = launcher.manager.addEntity(space_invaders.enemy_tmpl); launcher.manager.addComponents(current_entity.id,CSideMove(0)); @@ -809,6 +809,7 @@ void spaceInvadersEvent(SDL_Event* event) bool spaceInvadersLoop() { + launcher.render_position = (vec2(launcher.window_size.x,launcher.window_size.y)*launcher.scalling - vec2(400,300)) * 0.5; /*if(launcher.show_demo_wnd) { diff --git a/demos/utils/source/ecs_utils/gfx/buffer.d b/demos/utils/source/ecs_utils/gfx/buffer.d index 1f38624..2c25324 100644 --- a/demos/utils/source/ecs_utils/gfx/buffer.d +++ b/demos/utils/source/ecs_utils/gfx/buffer.d @@ -55,10 +55,10 @@ struct Buffer glBufferStorage(GL_ARRAY_BUFFER,size*count,data, flags); }*/ - void bufferSubData(uint size, uint offset, void* data) nothrow + void bufferSubData(BindTarget target, uint size, uint offset, void* data) nothrow { - bind(BindTarget.array); - glBufferSubData(GL_ARRAY_BUFFER,offset,size,data); + bind(target); + glBufferSubData(target,offset,size,data); } void map(BindTarget target) nothrow diff --git a/demos/utils/source/ecs_utils/gfx/renderer.d b/demos/utils/source/ecs_utils/gfx/renderer.d index e064c9e..2a04c57 100644 --- a/demos/utils/source/ecs_utils/gfx/renderer.d +++ b/demos/utils/source/ecs_utils/gfx/renderer.d @@ -98,7 +98,7 @@ struct Renderer alias Technique = RenderTechnique; - __gshared Technique technique = Technique.simple; + __gshared Technique technique = Technique.vbo_batch; void* data_ptr; //import ecs_utils.core : RenderTechnique; @@ -339,6 +339,7 @@ struct Renderer //import core.stdc.string; with(this_) { + if(item_id >= MaxObjects)return; //pos += view_pos; size.x *= view_size.x; size.y *= view_size.y; @@ -470,8 +471,8 @@ struct Renderer break; case Technique.vbo_batch: //if(data_index){ - batch_vbo[0].bufferSubData(item_id*4*16,0,batch_vertices.ptr); - batch_ibo[0].bufferSubData(item_id*6*2,0,batch_indices.ptr); + batch_vbo[0].bufferSubData(Buffer.BindTarget.array,item_id*4*16,0,batch_vertices.ptr); + batch_ibo[0].bufferSubData(Buffer.BindTarget.element_array,item_id*6*2,0,batch_indices.ptr); batch_vbo[0].bind(Buffer.BindTarget.array); batch_ibo[0].bind(Buffer.BindTarget.element_array); @@ -480,8 +481,8 @@ struct Renderer glVertexAttribPointer(1,2,GL_FLOAT,false,16,cast(void*)8);//} break; case Technique.instanced_attrib_divisor: - ubos[0].bufferSubData(data_index,0,uniform_block.ptr); - ubos[0].bind(Buffer.BindTarget.array); + ubos[0].bufferSubData(Buffer.BindTarget.uniform,data_index,0,uniform_block.ptr); + ubos[0].bind(Buffer.BindTarget.uniform); glEnableVertexAttribArray(2); glEnableVertexAttribArray(3); glEnableVertexAttribArray(4); @@ -496,7 +497,7 @@ struct Renderer break; case Technique.uniform_buffer: //ubos[0].bufferData(1,64*MaxObjects,BufferUsage,null); - /*if(data_index)*/ubos[0].bufferSubData(data_index,0,uniform_block.ptr); + /*if(data_index)*/ubos[0].bufferSubData(Buffer.BindTarget.uniform,data_index,0,uniform_block.ptr); break; case Technique.uniform_buffer_indexed: ubos[0].bindRange(Buffer.BindTarget.uniform,0,0,block_max_size); @@ -581,6 +582,8 @@ struct Renderer { material_id = render_list[i].material_id; GfxConfig.materials[material_id].bind(); + float[3*4] data = [1,0,0,1,0,0,0,0,0,0,1,1]; + GfxConfig.materials[material_id].pushUniforms(data.ptr); } if(texture.data != render_list[i].texture.data) { @@ -589,17 +592,17 @@ struct Renderer } uint instance_count = 16_384; - if(i*16_384 > item_id) + if((i+1)*16_384 > item_id) { - instance_count = i*16_384 - item_id; + instance_count = item_id%16_384; } - /*glVertexAttribPointer(0,2,GL_FLOAT,false,16,cast(void*)(i*16_384*4*16)); + glVertexAttribPointer(0,2,GL_FLOAT,false,16,cast(void*)(i*16_384*4*16)); glVertexAttribPointer(1,2,GL_FLOAT,false,16,cast(void*)(i*16_384*4*16+8)); - glDrawElements(GL_TRIANGLES,instance_count*6,GL_UNSIGNED_SHORT,cast(void*)(i*16_384*6*2));*/ + glDrawElements(GL_TRIANGLES,instance_count*6,GL_UNSIGNED_SHORT,cast(void*)(i*16_384*6*2)); - glDrawElementsBaseVertex(GL_TRIANGLES,instance_count*6,GL_UNSIGNED_SHORT,cast(void*)(i*16_384*6*2),i*16_384*4); + //glDrawElementsBaseVertex(GL_TRIANGLES,instance_count*6,GL_UNSIGNED_SHORT,cast(void*)(i*16_384*6*2),i*16_384*4); } } else if(technique == Technique.ssbo_instanced || technique == Technique.instanced_attrib_divisor) @@ -794,9 +797,10 @@ struct Renderer void view(vec2 pos, vec2 size) { - view_pos = pos * size - 1; + //view_pos = pos * size - 1; view_size = vec2(2/size.x,2/size.y); sdl_transform = vec4(0,0,1.0/size.x,1.0/size.y); + view_pos = (pos - size * 0.5) * view_size; } __gshared void function(ref Renderer this_, Texture tex, vec2 pos, vec2 size, vec4 coords, float angle, uint material_id, uint mesh_id) __draw; From d68eecf2725d457fb66c52091abf58a8341114b6 Mon Sep 17 00:00:00 2001 From: Dawid Masiukiewicz Date: Fri, 24 Apr 2020 20:10:23 +0000 Subject: [PATCH 112/217] Add LICENSE --- LICENSE | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 LICENSE diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..ede0cb3 --- /dev/null +++ b/LICENSE @@ -0,0 +1,29 @@ +BSD 3-Clause License + +Copyright (c) 2020, Dawid Masiukiewicz +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +* Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. From b434d851edab42452ffbcc847fa7b6ebd5608c5e Mon Sep 17 00:00:00 2001 From: Dawid Masiukiewicz Date: Sat, 25 Apr 2020 11:09:35 +0000 Subject: [PATCH 113/217] CIUpdate - added build test - probably fixed some trash - coverage test should only wait for test_dmd_debug --- .gitlab-ci.yml | 59 +++++++++++++++++++++++++++++++++++++++++--- README.md | 4 +-- codecov.yml | 3 +++ source/ecs/manager.d | 11 +++++---- 4 files changed, 66 insertions(+), 11 deletions(-) create mode 100644 codecov.yml diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 25b0820..cccf254 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,9 +1,60 @@ -test_dmd: - stage: test - image: mmcomando/ecs_enviroment +image: "registry.gitlab.com/mergul/bubel-ecs:latest" + +variables: + DOCKER_DRIVER: overlay2 + +stages: + - build + - test + - testcov + +test_compile: + stage: build script: - source $(/script/dlang/install.sh dmd -a) && dmd --version - - source $(/script/dlang/install.sh dmd -a) && dub -c unittest-runner -b unittest + - dub build -c unittest-runner -b debug --verror + - dub build -c unittest-runner -b release --verror + - dub build -c unittest-runner-betterC -b debug --verror + - dub build -c unittest-runner-betterC -b release --verror + - deactivate + - source $(/script/dlang/install.sh ldc -a) && ldc2 --version + - dub build -c unittest-runner --compiler=ldc2 -b debug --verror + - dub build -c unittest-runner --compiler=ldc2 -b release --verror + - dub build -c unittest-runner-betterC --compiler=ldc2 -b debug --verror + - dub build -c unittest-runner-betterC --compiler=ldc2 -b release --verror + - deactivate + allow_failure: true + +test_dmd_debug: + stage: test + script: + - source $(/script/dlang/install.sh dmd -a) && dmd --version + - dub -c unittest-runner -b debug --verror artifacts: reports: junit: test_report.xml +test_dmd: + stage: test + script: + - source $(/script/dlang/install.sh dmd -a) && dmd --version + - dub -c unittest-runner -b release --verror + artifacts: + reports: + junit: test_report.xml +test_dmd_betterC: + stage: test + script: + - source $(/script/dlang/install.sh dmd -a) && dmd --version + - dub -c unittest-runner-betterC -b release --verror + artifacts: + reports: + junit: test_report.xml +coverage_test_dmd: + stage: testcov + needs: ["test_dmd_debug"] + script: + - mkdir reports + - source $(/script/dlang/install.sh dmd -a) && dmd --version + - dub -c unittest-runner-cov -b debug --verror + after_script: + - bash <(curl -s https://codecov.io/bash) -s reports -t 1a0c0169-a721-4085-8252-fed4755dcd8c diff --git a/README.md b/README.md index 76fff75..d3f6816 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ # Dynamic Entity Component System [![pipeline status](https://gitlab.com/Mergul/bubel-ecs/badges/master/pipeline.svg)](https://gitlab.com/Mergul/bubel-ecs/-/commits/master) -[![coverage report](https://gitlab.com/Mergul/bubel-ecs/badges/master/coverage.svg)](https://gitlab.com/Mergul/bubel-ecs/-/commits/master) +[![codecov](https://codecov.io/gl/Mergul/bubel-ecs/branch/master/graph/badge.svg?token=Unm0TJhFoW)](https://codecov.io/gl/Mergul/bubel-ecs) -Entity-Component-System implementation in D language. \ No newline at end of file +Entity-Component-System implementation in D language. diff --git a/codecov.yml b/codecov.yml new file mode 100644 index 0000000..a6afdbc --- /dev/null +++ b/codecov.yml @@ -0,0 +1,3 @@ +ignore: + - "tests/*" + - "**/traits*" \ No newline at end of file diff --git a/source/ecs/manager.d b/source/ecs/manager.d index 1b9b959..5ec5b87 100644 --- a/source/ecs/manager.d +++ b/source/ecs/manager.d @@ -442,11 +442,12 @@ export struct EntityManager static struct ComponentsCounts { - uint readonly; - uint mutable; - uint excluded; - uint optional; - uint req; + //one more than should be to prevent null arrays (zero length arrays) + uint readonly = 1; + uint mutable = 1; + uint excluded = 1; + uint optional = 1; + uint req = 1; } static ComponentsCounts getComponentsCounts()() From 50715fbc40a8ea4821ab840e42e60e8600b938ef Mon Sep 17 00:00:00 2001 From: Mergul Date: Tue, 28 Apr 2020 14:13:55 +0200 Subject: [PATCH 114/217] Demos update: -modified texture atlas -fixed bug with high CPU usage (use pthread instead of builtin D multithreading) -added new graphics -snake now render tile coresponding to body part -snake is destroyed after collision and emit some particles -added some functionality to vectors -fixed documentation issue in Manager.d --- demos/assets/textures/atlas.png | Bin 17825 -> 24668 bytes demos/external/sources/mmutils/thread_pool.d | 2 + demos/source/demos/snake.d | 337 ++++++++++++++++++- demos/source/demos/space_invaders.d | 24 +- demos/utils/source/ecs_utils/math/vector.d | 19 ++ source/ecs/manager.d | 7 +- 6 files changed, 366 insertions(+), 23 deletions(-) diff --git a/demos/assets/textures/atlas.png b/demos/assets/textures/atlas.png index 498f34dd82959385bc9a96199c88707d782b46a0..c628969c0e7149419eb62313fb5c3274457838f3 100644 GIT binary patch literal 24668 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 literal 17825 zcmd72bx>Q;_b(c}MJq^gDDEv%99k$&f#M#D6nD3T8Wbqd;_mKFkq{^aio3fPf)ois zlXv+2?wxrv@6Nor?|uKclXE6J=j80Y_R`N<>x64*D3K7-5Q0D;5*6jw+8_`%FvJGk z!w0_3{3fq}>(l|dhF;q5e3{%lT;JO}*)VzeyV)?=_}RY)f&AtVlFedi#YsP}_(w=% zV_q?Yv3~su>tuk+#!ou8_CDVTpPS`qDrAdl`Tg`q_~7TR+Yvb5O=K1gTiCqy*<9de z(Xhnn`q0;^ETmMCVb)Ge)(!eBY@}<4QIL_sd;md~2Z#Gyrt@e+pb+ya`(yuWmmL2U z=&UUI9gM1fBluGcJhxOYv!e$A(b%c>7crQsi%Egmrfzwg9IIqaaVuv zs--9lgy0jDz6^;S`V}a!+k6ys=sUhTocdFkgHkPMOMr3Bfd8s4ECr>ly0#>=i|6Ju zUq_-eoYhSHIu;f=pNS2Xg0ODV&SHN);5uCm;W?an)LP)W$W1o-1wm6)#h{j3b#yJ4 z5GeX0j_|?nOjR{$<^Ut@-0wIc`VlNisiODtr)z8bOo=KuQrK6gKO89sR1WdMWt7-n zTv0!7jCeC|S65*kK;mV1G;ZdSL|!tUANl7ymt*`}CEDOW zPpqOvPI-&n)9N?qJck>8?pSV3b**1@b4VW5B3xQs=d4Cxq-WyD`iYoy_idxp2F~De zGleh>Gf}f*FNE{jIgjt6e^RFikA8)bXwAEcX$}WhUCh4=+TsFHhs#&}RdJe=7rL8B z8iw}juU7b$&Fl}Tlt6N}y}Z%7jy{`obz(whV}fZ;(NTpzwMRta19V&xWooWN7gv7q zon00E+yX1`i+N!lG!rzrE%^St#TD^hkRh|I;y+96kwba&&lSxX2iSa`J4UxTn-AGE zd6>wA)EYnD3gH`ql#yG_=!*=jLLx=DMdP%S*kOSJBvvJn$;%QWe_ z*i)`wBywI)M#U-&DRYMnnrSx$8SHYT8=6#_;@;2C@ItleI3Ae{v?#`mf9@wO_L1et zoI71ltFKFF*g!rqjmusPuTpj(cvBuQbzd5hKsc1KO>~8N(!3=NBJTfJ{4w|rn2F_~Rg6hNjl+x~c#F(+^^#(VsI{x_mz z?fE{Rh`Hpg+-Q$0Q*v5MR|~Q2;2+N0k~N^>_hA|Z7%78dWNQVVXMZ!rBsf(5*_u6*;ICo%I34LZTaakt~u)k-qYJ24d1KVR=W|g`(pG*9AajrGRpEW zVouGX1GZKZCwkSs^+Pef#o<6UX<8#0o^#JN1>uf&RD5USPt~*Yrk!jLKRi2#Z|XQC zbUbgrrm6k@7Qf}W(NVcNiGZGb>sy!2nU4e|@=g7-2=3mxXpg82FCy))jXN)fr{pww zzx@_6%4H)pDNxmA)MfI2@Das#hP_Lq`@ll|!0q)Td6_T|*DICW%y5u9`(HU)u?TN6 zwm)U?MW*5hu83hf&9&$`7I4cSy}WW^*7~O6&n}UZuGMBs{mc)ZX|q{kz3lo#=|F6f zI}pSBEWIN76Y+T<#Z-wwY_7mf@I?OC*pJU}TQeyAT zOv#W~n>4=N=z1m?Es^+33KW1tS6!*nEO1KGRuWk}5K;TRMZ55Hqfj5zu^_iI0j3Ry z@b!og;5l+MI((&Z(33l1pI{r2!iize;E9AW50xQa*eR#Pdj;8(RJq8|VW)jj{HuhL zn^c)dRTCgwxU%H)WmdQzKj0ji?_G#BrnNy3taAo+e14wmdGO+y_t4XtSG}AuGA-`f z-BQP$EPqN{b_G}nd>&yssvZe*Kwc*0*5^e;(pILjdKIVV`uwI0QHP|{1~YpY)3yz1GMzc6==g8tiCWUT*P5E~ zl!Oj36avLjQ|sW2`Sm47%jI;E7mrY!_-iKV7hM<^I4|VHkfI zW#&@*f&8f|1COf)O_nd`7OH9uL9ha|d|K!~Q}c?Hu~J5!#m8eVjm?#1Jp9SpyN#!R z(gYDa`>9@i>=Ps$v0*TXGO-~|#_Ce)=!pM|Fqz@X&k*1DUUu&|UNaXy4AEc#ZTmIM z^}P6}&uj6_7V81K)8{0s<&|K1eA8mWjUk4DHe=u9O8xB@-|(MA^(}XVHfAZiNQSVz z*5&=4s81ic7yMw!r##U zeB=8KtKm3f>nLPpyvL&%PbB*>1#L&Ls|h(-L|lEIEtj{Tp?TEugPY8+P^$3Q{%780 zp@arZ3+k|LwPb5SdUrqEuPz#6!%Oksl6@`cidcDnj=8OOrAVbXZI*<6gqQZ(6VK5n zj$1-!1qmby1MJMS@tT{gyyIJ+De5J%8{iOWX%V+S@@OV7VoDQT4g3Bni1W#Nn^dv1 zm)83o@${@bwz+5=%eQHv%Sc4mhtWl5S|`2y%<~T7c+w9z-H#vL%cVV|eoRT40m9QP z^|N98%=2FGX?84HtM${wc%94i_Y!Xm2YVs;J{IBkdsAKXyKX7k&!Q;2S-vX7(oYbc znz6akyiok=Ce4x*717K4ngKp*?^0#@KE1i(^{?*?Sx9#KM=zX6Tf?>X8I1xSRSHgm zxWg=HSrrM#?>Tg{YmAu@x#tJ#$2ijpKFm=(*805r&fr4yehM-TPygTazi(J9vkGTs z*{>b;=}DOdW2XGGyHmqe8Pc`o+uU}y``RARWB)#+jrv9X75&&$Z0o&74=%XL0A3xG z{+X7{awd;#0F!cZOVbYd7g*&pMNNQE~B*3PX)F|I?wa!`jlrK-yqi&HlrixeB08A z7rHDbKNA}o@HNLS|ETQpc}VxtLcWN@)!*{{T0RMmxO)4y=8~8$(8#57U&oPt+=s^` z1yj@#e|cTYX0^TJ-<_UT_FULjtyS?~G|c#n?RO`?|Mq}Y^;J1dC6f5o2K)>0QgNJ~ zNN?3Kzp2kUp^%nwS(?Y=>slpEwl@pi=yPjnQL}NDPeJpKq}jdkX|ma|oKo+x{ zO8(>C;5TB=fALb-((Lv(r(IvbE#K#fuD)QtS6i{;GCd!Bgp0={^lO9IGxmP1^@`Uo z<#WHQNBo4bduOkRy>-ghlt!$b6vgo`*EU}gRC}HXryc;9oH@70P%wGKS$cz=>mi4@ zp#T*fBauzbyk4SsZ zJWft2qKgWKEH<`rnh*0rZ+Z^HpWHkV|BT(QPaDnwMJTc(C&& zIm4AT`=By0WFjnT$a}-@uTE%8p9bTy9OK!KP0zDTwH@O6(kL^8YhQ0#c*&;2+Y;T`!-6uAr3_xCwn8 zxc||j`2Df?Yo312Jqo#s(b7+S1<=uaW)*jLa#JEwG_O9rX}Y(!8wGAB;{y&Q4h1T% zFDl(5hIrL*ftB-(S>y^zOl)el<^Jd6JM^G7@h2D02hB zAk)6m?U(4gl$B@FmqPsS{_i?zOgl^vLk{ zqu2Mozg4(zWB7Hf@`vS9g&lV?Ob8$pwzx7}#b`X;Y&nmcRp`IgruPt!UvCI|KSWb4 zpr2sNwZ6=Izp&EVxFm*!J<^ddePXcJG03sokVq+w9nkn85|PM$gq0-u5);Qy9m|4e zcX{f+di$-Ni|A|#+sx5rC3QzE7&Javwn^gVc8{2fGjM5RDdQmcx~Xsu&KRxXQ41DK zPy&)yd`mT@*C4aIk1~X*3b=CLP1(p31R{ETcVdB3)1Lqr3A|L^C=hJoK6oVZ^qb>3 z2XKknOTo}f-qqRJ#>ERH?_u-K%f_0?*WSyHNlE36mca*7DiDYXr1JWeE|C2$1tzn4 z2Ok}4B4I^EfjjN3I0O8=wL?#t+zdZF-ZY9acqI2v{H?Ckqul$k511a-tz|23j)@F( zo8Z1>+2elVseX^6*bg_{gUXcY&+vM!sE^O#gpjm!a7F2<(i^1L$l0J5YH)wJ`e^3# ztWMq+Q(D>@c?E&MTc{hI5z3Lh8x&NQJHr{FAuMo+Lnty%fS{w+M)xsjxqZ3#qA=^A zaYrwE=@*=RMei7igC>c5gnNhyBW3I1MUtgmT_lB3Ikl{`Hou8I>rBI^bV{9R6DVvb zYr9&Dd364mzzO^97E(v3Jc~&CqRdb>=4xeiQ6w}|%%V;ZyDAB^N{J?^NB|$vl*``x zz2UyFR6Q(m3oJrJiJggYDPpx3wy}r0zKYd-RzQZiy@@=JTQTHQk=S7g+m@~%1J81* zocQHuj1=t;7f)t*nVWoNazjiFIk=vevTeWB$y3?^&(%2*K`9WnX5H`}N+{NLG$k$M>0?G(!YCx`9Yyo9ukr?8ebl){!6GP?9(SKhEM%n;>z9a&YW%e(%Tb(0(#GlQ6fXjWe^ zn2bA;l_%JwN*uN$}`r=qNB5Di=f4U!^;?v8Phzab`QNb6X1qpr`z3wky+ncJ#Pi!^(0dE zj3_6t!!~M*Z%4YpDZBQ|-U{uR_<*+Ny?d9eS+(aCxDAI9OIF%y#Vxzd z-Eb#7x4l}z!n4^^uFE#Aj8k@7Q5BS?hHrr1Q9%3N$TdJ*1PhUQOwL+<#acdBUwSgQ zasRe#A;V_x>Q#}TxP2v3DfY1KRAZ_Jve&wD>!Jt41k8;1Ntq)#J06+IIuc?L!64XT zZBhl8<0*v67K-|6tioV7M)r1u&_5$;A@lW?lBY7Ef5BPLz~t$L&t==Vm2Xw5XCYDp z9LuW~aKXdlIR9t6B8744{8xXwu>48jHpGu|y%u(EQpSH90!{q3V)3b?xL+jz3b^o+{));>C53;9IV);T4y zA_Po$QQ$WEeMR(=GkN?&W_b&NI$Q5SS1nrCs-_4^UX|tK{-Hn&`(OBgzTJ{TR)rSkziGA=h7RiFr?kwPNmL3Y?&6y4b2rhHg(|0MfX#@p>Y{KLZ^qagME$+hTMY`g z$_ZjOkx%-!GW?C%WYc>$K7U;Ijh78VXo^qw*1y(EVWInZ<-+TNcr{k9sF~0fnx*YG9Nmxe2^?&eeFp1q3&Uz)#Pd zS01KzKvEA&b;;Pu?0(#=%RmiMe&a36Umbaf?cvXXn_t(Mxi}_Wqt>B~iqX{HX$5D# zI6&}6m2mBi0mRnw7X3_nOtgXj;n(C5{MXT1V~YLl4|aeSBk1-#iI&6-_~^=Lz$JvO z1)^`3P33Wm>xQcY;+GO&ov20TEmV$YIp5j_??B;Avm5TBUOIsbwpj^M(Or0~6u~VI^32|&6A>&=ud0@Q>RqiQ5c(%!xo8dpM zziM*NYUKPej-Bx!&5gv(pRN{uc1Ra2ZSu2vzwcvK9edzv0rSgRihtC#1_}kCT14l|CGnOcfxFpxLtm# zg~_rdIN$WY2zV@AQz#17e?jbEG@hn;e^_k7UlZQ%tjv8xT%~v;Bukn&SY&*7^Tu&o zY4`d>|CT@wCbcTX?lZ@;?@3x)%TDOzsYO%b!FU|rdlkX_(j#BpzZ91d&_tC9LkLT)>)v4)}X|w!en-s>Kpwv!Lg;y0XePi83+)!FN;Z8 zmvs8&$#3rn4VN^jkbzjwNpHa&IyM=TBUx~@clL}|M3rsrjH?m%;Ul-KINe1yrU`Me zXK7hC9e2T@C@8yi-FN-Du=D4hCDhUJ;35tm{rzWU7alux|82POmH%b9l%U0^FE%P= z!>#Hmwi(NVnb77};os`fa<+_iUGY5|@Ec2aocD7Y3qfl+5kji08GPuVBIs(0ZQ+q- zW~UrkMT@1#dEyP*m#V}K(Bj01YV(eMSkSPq;4^b2_hc4a0k%8?P@L7fpQuI0e+2W!Npjx?)pNB5nc@dchU|G89$ z8^6n%OpCSbY!>~&o96V4RW#ZpTv5;UOj=Up~fp zW)A~Nk&7MI)L;H-qv>ugdp7Iit$w44K3Q(lFyF~KUw&O16ls2RhL}?xDx6;)UrRn* zOOCNo!yKik8wtSY&9E!Sbp1tZyl(rpowmwLV7GlM%k=NQb7#e64$nIfk4URm&mzbW zJL4&2AqvExqxMQo+4em7M&|)Ir0#5tH!K}r)aBmV9dk+v(rfi0@|#K-O$LcsA(OXy zzCX&fulZ6b@b#YkO1b9Enp&vyLO^dr0%{D36bOqdYk%5$Iy+Qqd$qK*q_;vjdtheV zSjSvi51tDi0_t9y-KmFb=`pm}kP~a;B-2r?=eR$muNHrQ3076Y!JZ)Si$KK8@X$An z7cCK}@mq=31To~@$S1QAc)oZc)=N9sh*lo&B9kp|YDZRhSICmd-ux?H85quxq=@Mi z8A0j*Fj$lk6j@YG<}=oNZEZAu!4tz-_ulgu>gAi|Q~+lyfm_w}fc;+s$b4x=Z`p6< z{Prz9jaTCZQUg9s5`XnZeiv^WcOIVmV^$f?MEzNE}}`zPz{u=TvG+cg;`&niUTe%Kw@E5ov!x1(8CihYb7xw zkcC*hxzw1ECbg)HJm;N08QH3YJ9{6p?xe|3`$BKSFp%s*d-TGN;7<6M*rH!<0 zR1VF|NNEv$Ot0R~RSEZu=G5gi|DM;<257s*Zp4yLHiYdFXz>A)c+=G&WqQ;*LCMRe zK;}3O1gF%o-=d4EcS-8*jP}hEw(&^P+c%)(5iiI4pvan=hM$3Ijz$kI;!N-p7yAQ; ze;?QY`H)`kRS6BSMm3~#c*XZ^k%=0}@Y@za^=Ir5MEP((-tOGtB}KZQl#80Sb$!`7 zq9ob#ZGv$GMt7y9W@xU-SyFyEa<^YC9nrartm-q8{~bhx%({7Hb-XUQ0&&|f28WOA zmEU;FEJ(vYJ_fe5b#>Wt$=_@y@De0e4gklgAVS&d5Jb^?L)l9YP#YS%V={_?RuTj< zmkko4K=YY2>IP*pfj}JyUJ#I|OR8f_$Av|Evtr3T`MezgJxE z*Lu^L9oyF@xlv(QlUx2(!1|6K@*qFVRkYrlP=>^8nF9^!g%O)mHdyz+eGLC~`& z<9^43SUb)vEG$h$edpLqih3-xwI*f=R2~R=hl$|3T@i`>C5>l z(hjbU<2*Rb^t{pYl6Zkqaa{hx{zn(sO#p+u@k4@M@F?I6LzCma$hIB6R?+^uDuXl$ zH{!SmZT$B1N43v>T}G~Rxt1Uo%)TN=w|{PGRJPjhPH2k}t)TJDpgAIDI2btAyg5o? z1x5#aL;ahl5vdRHhC=Nh150aTUdsJY{yD2A5Ui}t`bZ!6dEoqpXqf>7ntTY_9+wrC zLLdTBnhbxMd{=TT-}**2TrWUwu;Nnv-C^`%>@rUaP-$9ZS)UZ8u} z{-^8GR159|{Xmnro?fB(Cb-h|Im!-r?7XpX{Q+7R?hi?NTM{e<30*%H;%*dh#sPsG zh(V~sL!nGgv97~Imk@(q&u-D5ubAR|&1qjaFNsr*!CJ5T3IFvS3r#*TsVJO&T<@A2 zhECh@rFO|#23A-LopShAF`YIn<~sjz-w%@XgJy(05Jg`Woy3aQ^{#uvmOKz$a{SFl z>jn#yjJekV%=hiO?m*jE)s{oPW3pGRt0ba(h3|yQ+%M-k{_VWH015VCAUAT=R|-Bb zdwj!h1@3!*p|%z4hOVG9*AX{PAkbjUyM?%-Q#dp@EVyP$b|dWwRj}#0`rdNl9N`Y_y;VWV8R_fU2Khb&y~Q!TcN7;iHS72gG3sZ;I{% z?uPe0$gO+hxR%Q2a8U)zT=C)-1gbk8(iLlTn$te^C+zzn@YnMeAMo7hZUIP+G(ox! zM_qIJ`ti@;pU~FJVbA6!f)Ja>Am9Sb8=3ph*zbAP4osP#$aoo3yMNV7j=Eu*I<`y*h9C0ZHJ zwDW!0>>6wBM!ivS*H-K4U-dg3%wKLp`C(_;D&uA=H;tJ~$G>u;C3LwnZB+sqqo1}c zF5q<3-Uqq-Psdy0IO_l0Ru!x2)U_x6#S4{~rQi&H_>HFxZ8s2Vs!W7sIP0Q@i%K09sG)T-|CW==_)8OQ`i@Tj z_G{k2K0;Q~Cq}kC<`*POH6iEvm%&(3tU4kTm`a`2{FQ`qdYKZQMZF1krZm}$SJLOd zh~{rP$)@#QCItq93{S9tptWGq=ro3M`T3fMHeb^Rad?43o;qE zf=69lf<)rdD1$y756YIxm!xO8%DyEj$bfF#w88W$<&JZp-J+^Ytn%R~omy z2aIX%Pk$)C&ZHqKrU>W#d$uhko5d_LDF)Yd5d_r>2MRyGJiv8< zXD=V{slIpjc7)vcuz80;q^a`8Y-c#B@yeyy#)Iwj@@%kTWf`#Amik*Q%b97{Ls)R_ zts~?XnbvOTef=R5T>(aSLlXyAs%SBPV@h3CtW6lH=|)8(@}x`hpYptLc}EVwyl`7U zGkc~hOpw!MN0V-SO93-4RAe#Zy=SvaGxjzco2M|V@gCXsJCL%H4ja$9+2okW^dvfw zD;B=}l0FlZgxNMx1mcik0?}VG$c4bX&vnvSf9E?2b)A?+4E@$g;W;BsvE$_ut>o>c z5~jZN;pYrVUm9A5xo3!DJlf2;)o=F(vvUwzk5P+Wk>)=lVv>mPGElyZOU6TjaEX)t z@T_2qw876tLDmF{ZKn>D8Gp>5PuRC8Qh|0N)69Un)8qVw5UA^D}mwshD6vL5uc7+5-YI@~k!{6sbzZ zA=yp`oVpBL#ljhAG{nDgd5wI%X49I}?wf<*xT&l>6bf%Y1A~)T*{(TIKVCnL>i4C} zx7u;RkjVy{#|pog6&1%Q=auKkr!E#f_q^^jy%uFHsoJqPzKquEtu6rlyCMd%;M;zl zqtOj8Tq7r(ufgQTv(VFGwf!{`hROEzXnHxyQ*iqD%T#$g(}-^V(#+yJ|2O`Sy|&uI zNiEHbWSh$+OlAe}5~YM`4XoUU{d zrj@HBP0rc&+I=J+)X$~ipsBIZd2xJRe|eea@?d&y9*9WvSZ<;rNno_N%6Rkvlw%;# zX<-+ch5V4lT2i_WE}j1fR%=Z$FY`6OOP}g};n%+CW2LhRMu_}T&{0-dm8;fK>xt_Q z1-3TJCmKy#cE=^Doi0Tket0QVdNim&>v# z%{jQ7IPlu+ijEW^=S<3Y)=?{g=}U{7Q<3nYeqm=LeP_nXJXm{B-DyI)d4PCXjQMgo z6w_&ZO}5fhRk{URmmfM$DGHk$U)N!`DtW&C_L;@sb<`2ZYarE&uYEk;xZF05o~M#L zK*2Z)e>~KYm&ZdQC1Ws1H2dwp*50`l^n8uyq0mKI*~0$yk@PTRqel^mq!Lbl)^I&l z9uRnHJhe7)kY!>v1tEa1jH(IPPAzWgy>N82u5T>6DmPry^VD$;`?7B~e1?umnkM~0Tuc!pW4hzztBs9B^zr#Hb>tihV;>c~oJKndxB_`Hj>)mZINRLN zP&oz)c83d7yklEbRb9;P*}%pRe0(CHA-OR#?bDmt^Hqt2Br|p1tMa6z1}Hu^QV@zu zU-UwJew7bgg*z@dtEfgTbdT&ED?3Ib5uIT@XOmSE61P#WZuimNK(5>|ejmhm=@uEh zejjTtu|j#a!~&2$@=Qa9wWPU^$1(TwQjmOay`|4cM(?bPNz*^n8AU`FDo;i2vaKT1 ze5W}jXqQoc!MrMm@%Flyu+Z8_J7<;r%vf01&%tHl$uVbEQ{<~HAimcfLU48*-26gX`&Vi!5f7 zgzTIN-DUC5wnU-%XJXb8 zS#_+qhCcrH{LV$~oyEBRq!NI{PFO&N_BoOY13EH&(bv1&ykS?F;!1+T&_<-j>iX#V9uU- zylQdG9jOf1ylRAD#KBwoq=dL2x=xTAA_<>(AhxHc+_Hv`@4TRUA^0162KKGy3jGUK zE^=XE85asA{Ka3csXp#memP9A7EuoPO0xF_l-GvqftTXr#b6Acjzr-E_%v(*YGHa! z_HAl$SlT7qi<~K=CNj&t@GU6IfQDLRpq)n)_b0T=JX?;1U_$4c zy}f+W=t;l1b_~(Va`6$yGk2RTX=uLRx;%A38e^#ly@IC>C}O$Xj)!RPrbr(6-fV;% z|DLeF+yISwLVtB%esBW=}1fqhyvDM4tVvNR)f&t2pu%X3ABwM zCh)AS;{7d>yTa*`0EIzd1l;}44DP0V za5v%q_F!_jDW2-EUZ_Z5nP`N?z`sMMFlzoO2gFH@{V1(CaR+Zq^)`S7u zGH&##JsGHD%tD18_b(-;u(6tTH-93HA{=jW{GopD)o`sDb{z#KU;zgN6os+7F|!xP zCw|0Hq&DQ?c=1EYvH3ae^-pU;q)7PcC^45n$uR`vhO1zS1sny6p50+1M{l2PPR*0l zSQ;kV2Bu{(0P`4P!=O!mMT(v_U!)!pDaSs-p;pn}Q9*E@qjx5Nsu*_1Lyx^n+5~lL zkU;=_G!maS z^B9_32;1X1OQvFSTyC?%8NTEx-07*03_PTh}eM zLfWV94J_4#ET6)vQn|zBY`gv)4#1KUMK&gd+9-$`P0DA|gXE6mo2{Sn#Po79ycUfc zj+>^g;Gtzz5kQ|b#abt|v8(JYH~1Dd#^!S!WMH?ycyH~|MI*b(M?!Hp;N#@|=@-eH zlj~0oyKWkIyyQ+%9Gp}hBOS{9!%llZM5F2sqQU7rX@1uD~18ztL zM@5{y2E)slaRwiayi*#9t+qIkSxNqwrnbi`fb?2?4;os1_4xPs4&Jfh3rW0ywDCH6 zGy;^x52UKH*V;f`XX|tPf-y5bhc&eN1IZF*zLyL7FSruCqOW{MZe71#Q8*KFizI4$ zs^yU)#aKXxCnLfRZx42W-h>f;$e~%_LCA_YR3>SJdzGwzVpO}$(_HX}o?4)xRi1cM z)b?ac?JJf~)NGH9@IIOwC01;oS9=}?J1X-Xa5&nns|Lkxo{INUx4i27_vGYK8c;8e zs@WMD?#y;7VA&*ZmyPRL=-J*)q&|h~iH`Pu)OZK8O3f4r4Go>%vj;l$T*Wm%(sSPo z^L>b8DOo>JKSM_jK<86rhIUSY0x6w8E7v1FPT*K2E42zPns)ih_2h(GI?;gX?-UMd zUys?fz=xZE@ zuNQYdMC$p|?@tCfMN)N`{_>#_lu!d5lUaI|WFHdfLR>s+g`NAauYr?r;AIRF(r>D< z8q(0bw=FlPw>JQm8~}Y+m5^VhM@UWquE;^SXl$)q%3K~mciqr{He-ojg2eKn@9dmd zIqEFR3Rudmrn>>3w0RmhxyYc;N;&!*VcBo<2Jk~$wS|^^%-zOvf^SUBvx@xk7@ESQ zO(X$;y$w7dEV22SNQJ_6b7Fa{(%SL_`z4^sA`PE~1>^NSP4X{-c27o7cT94^d0FDr z!`1Pnt-xZo2(Y-&YoYGoJ;22%q_GEXh39;0lL3t8!}@5jxt&h2u4kgY<#JxlEpBPb~??EbfjAvE!sRt%Ocq3Pl7DiLQ*@JKICkq-BUxLT@QcE*!~f8?oRy_@f#c1ZkelZ6YEZgw2FfR z(eC7_DCG#DoxP)0fRq{CTTU3)_g=^1cMTJ*zDeLzsU&#j2oNrT6g~XILpFTHNk~xH z7~no0;lxR=PTFa}gR+bEJKB_avkRxcry9%C9BK|Y3$RqlF_(>X*8h4dUzm~rM8xvB zD)slKHHG+51y_^7ZdHPFuYi$o;$A}U2KnWWaK{TEG+f>=n0Z}F0NVR23SuKvc+RU8pjXp=i~Yak0!Rt7-qofJ$?DiJgwtmyZRV%kCl?)Pba76Gig-v*UILhe z+?mipDkaI@7>G(uek|EqpK`pot3I?tNDgQ-^n;e{f1+><{ng{{oB`ruWE3*pN;B+Z z#R8NRMX@Z}w>=jY!yC6ytbPNEUD9jgtgWL(?hCV{s*R}n-cUUPXKZBPMr{E4D+tE$~W`U__ca?O*!W#0L*0yp0XJJ)wwA(zbA zMC0b90_e=G{vYp`FK$YtizcAfontbTZF(7j#-dnpiHNXHV4w`pLu3NcF$0{N`uCg5 zZ!A3TV#&NMuw-@oDSY(5Z*DI`fel9#9aJQX0cA)R$YDv)Wt*P<;L28cq)z;DZs;7~s@x%Y|hp?2u%OyapvBHyC)7vO7 zjn=dk!1iS?m(jJ%=nD#zmIjUe73^0GDakUKOi z_S}d5p!vxIP{_j&mLb?MM8~AquzD$sRl)MZ`bq-7gsxR!gzOy-%x}gE2G0}&xCrp= z%Dh@Z@suaj^R#!!_zr5-_Jjc#ltKWHj@UneW{7M0QLN2efb&kKk$||VO<({96q1+f zTEeHrpQX2Q=%SMGm<5}<0dT+1zw4taVV=vb*%9aDP*BHP*FHL2PH_Tk{F_$_xp4|I z31?hMzR`!??nLk(+V0D{x&A|z5OO!yf65a6vtHx>B^0PlVF= data.animation[i].frames.length)data.animation[i].time -= cast(float)data.animation[i].frames.length; + } + } +} + + +struct AnimationRenderSystem +{ + mixin ECS.System!1; + + struct EntitiesData + { + uint length; + @readonly CAnimation[] animation; + @readonly CLocation[] location; + } + + void onUpdate(EntitiesData data) + { + foreach(i;0..data.length) + { + launcher.renderer.draw(snake.texture, cast(vec2)cast(ivec2)data.location[i].location, vec2(16,16), data.animation[i].frames[cast(int)(data.animation[i].time)], 0, 0 , 0); + } + } +} + struct MoveSystem { mixin ECS.System!64; + EntityTemplate* destroy_template; + CLocation* destroy_location; + CParticleVector* destroy_vector; + struct EntitiesData { uint length; @@ -239,6 +380,13 @@ struct MoveSystem CILocation[] location; } + void setTemplates() + { + destroy_template = snake.snake_destroy_particle; + destroy_location = destroy_template.getComponent!CLocation; + destroy_vector = destroy_template.getComponent!CParticleVector; + } + void moveLocation(ref CILocation location, CMovement.Direction direction) { final switch(direction) @@ -276,6 +424,56 @@ struct MoveSystem else .snake.element(MapElement(),location); } + static CMovement.Direction getDirection(ivec2 p1, ivec2 p2) + { + if(p1.x - p2.x == -1)return CMovement.direction.right; + else if(p1.x - p2.x == 1)return CMovement.direction.left; + else if(p1.y - p2.y == -1)return CMovement.direction.up; + else if(p1.y - p2.y == 1)return CMovement.direction.down; + else if(p1.x - p2.x > 1)return CMovement.direction.right; + else if(p1.x - p2.x < -1)return CMovement.direction.left; + else if(p1.y - p2.y > 1)return CMovement.direction.up; + else return CMovement.direction.down; + } + + static MapElement.Type snakePart(ivec2 p1, ivec2 p2, ivec2 p3) + { + CMovement.Direction direction = getDirection(p1, p2); + CMovement.Direction direction2 = getDirection(p1, p3); + uint case_ = direction*4 + direction2; + final switch(case_) + { + case 0:return MapElement.Type.snake_horizontal; + case 1:return MapElement.Type.snake_horizontal; + case 2:return MapElement.Type.snake_turn_lu; + case 3:return MapElement.Type.snake_turn_ru; + case 4:return MapElement.Type.snake_horizontal; + case 5:return MapElement.Type.snake_horizontal; + case 6:return MapElement.Type.snake_turn_ld; + case 7:return MapElement.Type.snake_turn_rd; + case 8:return MapElement.Type.snake_turn_lu; + case 9:return MapElement.Type.snake_turn_ld; + case 10:return MapElement.Type.snake_vertical; + case 11:return MapElement.Type.snake_vertical; + case 12:return MapElement.Type.snake_turn_ru; + case 13:return MapElement.Type.snake_turn_rd; + case 14:return MapElement.Type.snake_vertical; + case 15:return MapElement.Type.snake_vertical; + } + } + + static MapElement.Type snakeTail(ivec2 p1, ivec2 p2) + { + CMovement.Direction direction = getDirection(p1, p2); + final switch(direction) + { + case CMovement.Direction.up:return MapElement.Type.snake_tail_up; + case CMovement.Direction.down:return MapElement.Type.snake_tail_down; + case CMovement.Direction.left:return MapElement.Type.snake_tail_left; + case CMovement.Direction.right:return MapElement.Type.snake_tail_right; + } + } + void onUpdate(EntitiesData data) { if(data.snakes) @@ -286,21 +484,104 @@ struct MoveSystem moveLocation(data.location[i], data.movement[i].direction); final switch(snake.element(data.location[i].location).type) { - case MapElement.Type.snake: - launcher.manager.removeEntity(data.entities[i].id); - break; - case MapElement.Type.wall: + case MapElement.Type.snake_head_up:goto case(MapElement.Type.snake_horizontal); + case MapElement.Type.snake_head_down:goto case(MapElement.Type.snake_horizontal); + case MapElement.Type.snake_head_left:goto case(MapElement.Type.snake_horizontal); + case MapElement.Type.snake_head_right:goto case(MapElement.Type.snake_horizontal); + case MapElement.Type.snake_tail_up:goto case(MapElement.Type.snake_horizontal); + case MapElement.Type.snake_tail_down:goto case(MapElement.Type.snake_horizontal); + case MapElement.Type.snake_tail_left:goto case(MapElement.Type.snake_horizontal); + case MapElement.Type.snake_tail_right:goto case(MapElement.Type.snake_horizontal); + case MapElement.Type.snake_turn_ld:goto case(MapElement.Type.snake_horizontal); + case MapElement.Type.snake_turn_lu:goto case(MapElement.Type.snake_horizontal); + case MapElement.Type.snake_turn_rd:goto case(MapElement.Type.snake_horizontal); + case MapElement.Type.snake_turn_ru:goto case(MapElement.Type.snake_horizontal); + case MapElement.Type.snake_vertical:goto case(MapElement.Type.snake_horizontal); + case MapElement.Type.snake_horizontal: + foreach(ivec2 loc; data.snakes[i].parts) + { + destroy_location.x = loc.x * 16; + destroy_location.y = loc.y * 16; + snake.element(MapElement(MapElement.Type.empty, EntityID()),loc); + launcher.manager.addEntity(snake.snake_destroy_particle); + foreach(j;0..10) + { + destroy_location.x = loc.x * 16 + randomf() * 8 - 4; + destroy_location.y = loc.y * 16 + randomf() * 8 - 4; + destroy_vector.velocity = vec2(randomf(),randomf())*0.4-0.2; + snake.element(MapElement(MapElement.Type.empty, EntityID()),loc); + launcher.manager.addEntity(snake.snake_destroy_particle); + } + + } + destroy_location.x = new_location.x * 16; + destroy_location.y = new_location.y * 16; + snake.element(MapElement(MapElement.Type.empty, EntityID()),new_location); + launcher.manager.addEntity(snake.snake_destroy_particle); launcher.manager.removeEntity(data.entities[i].id); break; + case MapElement.Type.wall:break; + //launcher.manager.removeEntity(data.entities[i].id); + //break; case MapElement.Type.empty: moveSnake(data.snakes[i], new_location); - snake.element(MapElement(MapElement.Type.snake, data.entities[i].id),data.location[i].location); + final switch(data.movement[i].direction) + { + case CMovement.Direction.up: + snake.element(MapElement(MapElement.Type.snake_head_up, data.entities[i].id),data.location[i].location); + break; + case CMovement.Direction.right: + snake.element(MapElement(MapElement.Type.snake_head_right, data.entities[i].id),data.location[i].location); + break; + case CMovement.Direction.down: + snake.element(MapElement(MapElement.Type.snake_head_down, data.entities[i].id),data.location[i].location); + break; + case CMovement.Direction.left: + snake.element(MapElement(MapElement.Type.snake_head_left, data.entities[i].id),data.location[i].location); + break; + } + if(data.snakes[i].parts.length > 1) + { + MapElement.Type elem_type = snakePart(data.snakes[i].parts[$-1],data.location[i],data.snakes[i].parts[$-2]); + snake.element(MapElement(elem_type, data.entities[i].id),data.snakes[i].parts[$-1]); + elem_type = snakeTail(data.snakes[i].parts[1], data.snakes[i].parts[0]); + snake.element(MapElement(elem_type, data.entities[i].id),data.snakes[i].parts[0]); + } + else if(data.snakes[i].parts.length == 1) + { + MapElement.Type elem_type = snakeTail(data.location[i], data.snakes[i].parts[0]); + snake.element(MapElement(elem_type, data.entities[i].id),data.snakes[i].parts[0]); + } break; case MapElement.Type.apple: launcher.manager.removeEntity(snake.element(data.location[i].location).id); - data.snakes[i].parts.add(new_location); - snake.element(MapElement(MapElement.Type.snake, data.entities[i].id),new_location); - snake.element(MapElement(MapElement.Type.snake, data.entities[i].id),data.location[i].location); + if(data.snakes[i].parts.length < 100)data.snakes[i].parts.add(new_location); + + if(data.snakes[i].parts.length > 1) + { + MapElement.Type elem_type = snakePart(data.snakes[i].parts[$-1],data.location[i],data.snakes[i].parts[$-2]); + snake.element(MapElement(elem_type, data.entities[i].id),data.snakes[i].parts[$-1]); + } + else if(data.snakes[i].parts.length == 1) + { + MapElement.Type elem_type = snakeTail(data.location[i], new_location); + snake.element(MapElement(elem_type, data.entities[i].id),new_location); + } + final switch(data.movement[i].direction) + { + case CMovement.Direction.up: + snake.element(MapElement(MapElement.Type.snake_head_up, data.entities[i].id),data.location[i].location); + break; + case CMovement.Direction.right: + snake.element(MapElement(MapElement.Type.snake_head_right, data.entities[i].id),data.location[i].location); + break; + case CMovement.Direction.down: + snake.element(MapElement(MapElement.Type.snake_head_down, data.entities[i].id),data.location[i].location); + break; + case CMovement.Direction.left: + snake.element(MapElement(MapElement.Type.snake_head_left, data.entities[i].id),data.location[i].location); + break; + } snake.addApple(); break; } @@ -455,19 +736,31 @@ void snakeStart() launcher.manager.registerComponent!CSnake; launcher.manager.registerComponent!CApple; launcher.manager.registerComponent!CParticle; + launcher.manager.registerComponent!CParticleVector; launcher.manager.registerComponent!CMovement; launcher.manager.registerComponent!CInput; + launcher.manager.registerComponent!CAnimation; launcher.manager.registerSystem!MoveSystem(0,"fixed"); launcher.manager.registerSystem!InputSystem(-100); launcher.manager.registerSystem!FixSnakeDirectionSystem(-1,"fixed"); launcher.manager.registerSystem!AppleSystem(-1,"fixed"); + launcher.manager.registerSystem!AnimationRenderSystem(100); + launcher.manager.registerSystem!AnimationSystem(-1); + launcher.manager.registerSystem!ParticleSystem(-1); + launcher.manager.registerSystem!ParticleMovementSystem(-1); launcher.manager.endRegister(); launcher.gui_manager.addSystem(MoveSystem.system_id,"Move System"); launcher.gui_manager.addSystem(InputSystem.system_id,"Input System"); launcher.gui_manager.addSystem(FixSnakeDirectionSystem.system_id,"Fix Direction System"); + launcher.gui_manager.addSystem(AnimationRenderSystem.system_id,"Animation Render System"); + launcher.gui_manager.addSystem(AnimationSystem.system_id,"Animation System"); + launcher.gui_manager.addSystem(ParticleSystem.system_id,"Particle Life System"); + launcher.gui_manager.addSystem(ParticleMovementSystem.system_id,"Particle Movement System"); + + snake.snake_destroy_particle_frames = Mallocator.makeArray([vec4(64,144,16,16)*px,vec4(80,144,16,16)*px,vec4(96,144,16,16)*px,vec4(112,144,16,16)*px].staticArray); { ushort[4] components = [CILocation.component_id, CSnake.component_id, CMovement.component_id, CInput.component_id]; @@ -477,14 +770,26 @@ void snakeStart() launcher.manager.addEntity(snake.snake_tmpl); } + { + snake.snake_destroy_particle = launcher.manager.allocateTemplate([CLocation.component_id, CParticle.component_id, CParticleVector.component_id, CAnimation.component_id].staticArray); + CAnimation* canim = snake.snake_destroy_particle.getComponent!CAnimation; + canim.frames = snake.snake_destroy_particle_frames; + CParticle* particle = snake.snake_destroy_particle.getComponent!CParticle; + particle.life = 400; + } + { ushort[2] components = [CILocation.component_id, CApple.component_id]; snake.apple_tmpl = launcher.manager.allocateTemplate(components); snake.addApple(); } - + launcher.gui_manager.addTemplate(snake.snake_tmpl, "Snake"); launcher.gui_manager.addTemplate(snake.apple_tmpl, "Apple"); + launcher.gui_manager.addTemplate(snake.snake_destroy_particle, "Particle"); + + MoveSystem* move_system = launcher.manager.getSystem!MoveSystem(); + move_system.setTemplates(); /*foreach(i; 0..10) foreach(j; 0..10) diff --git a/demos/source/demos/space_invaders.d b/demos/source/demos/space_invaders.d index 7058b59..bddf53c 100644 --- a/demos/source/demos/space_invaders.d +++ b/demos/source/demos/space_invaders.d @@ -16,6 +16,8 @@ import ecs_utils.gfx.texture; import ecs_utils.math.vector; import ecs_utils.utils; +enum float px = 1.0/512.0; + extern(C): /*####################################################################################################################### @@ -587,6 +589,7 @@ struct InputMovementSystem const (CInput)[] input; //components are treated as required by default CLocation[] locations; + CTexture[] textures; } /** @@ -595,6 +598,7 @@ struct InputMovementSystem */ bool onBegin() { + move_vector = vec2(0,0); if(launcher.getKeyState(SDL_SCANCODE_W)) { move_vector = vec2(0,1); @@ -616,7 +620,7 @@ struct InputMovementSystem return true; } //don't call system update because no key pressed - return false; + return true; } /** @@ -627,11 +631,21 @@ struct InputMovementSystem */ void onUpdate(EntitiesData data) { + if(move_vector.x == 0) + { + foreach(i; 0..data.length) + { + data.textures[i].coords = vec4(0*px,80*px,48*px,32*px); + } + return; + } //move every entity using movement vector foreach(i; 0..data.length) { data.locations[i].x += move_vector.x * launcher.delta_time * 0.25; data.locations[i].y += move_vector.y * launcher.delta_time * 0.25; + if(move_vector.x > 0)data.textures[i].coords = vec4(48*px,80*px,48*px,32*px); + else data.textures[i].coords = vec4(0*px,80*px,48*px,32*px); } } } @@ -644,8 +658,6 @@ __gshared SpaceInvaders* space_invaders; void spaceInvadersStart() { - const float px = 1.0/512.0; - space_invaders = Mallocator.make!SpaceInvaders; space_invaders.texture.create(); @@ -690,9 +702,11 @@ void spaceInvadersStart() ushort[7] components = [CLocation.component_id, CTexture.component_id, CInput.component_id, CShip.component_id, CScale.component_id, CLaserWeapon.component_id, CShootDirection.component_id]; space_invaders.ship_tmpl = launcher.manager.allocateTemplate(components); + CScale* scale_comp = space_invaders.ship_tmpl.getComponent!CScale; + scale_comp.value = vec2(48,32); CTexture* tex_comp = space_invaders.ship_tmpl.getComponent!CTexture; tex_comp.tex = space_invaders.texture;//ship_tex; - tex_comp.coords = vec4(0*px,48*px,16*px,16*px); + tex_comp.coords = vec4(0*px,80*px,48*px,32*px); CLocation* loc_comp = space_invaders.ship_tmpl.getComponent!CLocation; loc_comp.value = vec2(64,64); CLaserWeapon* weapon = space_invaders.ship_tmpl.getComponent!CLaserWeapon; @@ -707,7 +721,7 @@ void spaceInvadersStart() CTexture* tex_comp = space_invaders.laser_tmpl.getComponent!CTexture; tex_comp.tex = space_invaders.texture;//laser_tex; - tex_comp.coords = vec4(0*px,48*px,16*px,16*px); + tex_comp.coords = vec4(0*px,24*px,2*px,8*px); CScale* scale_comp = space_invaders.laser_tmpl.getComponent!CScale; scale_comp.value = vec2(2,8); CVelocity* vel_comp = space_invaders.laser_tmpl.getComponent!CVelocity; diff --git a/demos/utils/source/ecs_utils/math/vector.d b/demos/utils/source/ecs_utils/math/vector.d index 10b4de5..4b9f3af 100644 --- a/demos/utils/source/ecs_utils/math/vector.d +++ b/demos/utils/source/ecs_utils/math/vector.d @@ -30,6 +30,11 @@ struct vec2 else static assert(0, "Operator "~op~" not implemented"); } + ivec2 opCast() + { + return ivec2(cast(int)x,cast(int)y); + } + void opOpAssign(string op)(vec2 v) { static if (op == "+") @@ -69,6 +74,15 @@ struct vec4 } float[4] data; } + + vec4 opBinary(string op)(float v) + { + static if (op == "+") return vec4(x + v, y + v, z + v, w + v); + else static if (op == "-") return vec4(x - v, y - v, z - v, w - v); + else static if (op == "*") return vec4(x * v, y * v, z * v, w * v); + else static if (op == "/") return vec4(x / v, y / v, z / v, w / v); + else static assert(0, "Operator "~op~" not implemented"); + } } struct ivec2 @@ -82,6 +96,11 @@ struct ivec2 } int[2] data; } + + vec2 opCast() + { + return vec2(x,y); + } } struct ivec4 diff --git a/source/ecs/manager.d b/source/ecs/manager.d index 1b9b959..9f5dceb 100644 --- a/source/ecs/manager.d +++ b/source/ecs/manager.d @@ -1550,10 +1550,13 @@ export struct EntityManager } /************************************************************************************************************************ - *Allocate EntityTemplate with specifed components and returns pointer to it. + *Allocate EntityTemplate from basic Template with modifications by adding and removing some components and returns pointer to it. + *Arrays of components needen't to be checked for repeated components, as function itself check if components exist in base template. * *Params: - *components_ids = array of components allocated with template + *base_tmpl = template from which components sould be copied + *components_ids = array of new components to add + *remove_components_ids = array of components to remove from base template */ export EntityTemplate* allocateTemplate(EntityTemplate* base_tmpl, ushort[] components_ids, ushort[] remove_components_ids = null) From 54a6d5dec27335f50f8c0de342991f8db7f5bc83 Mon Sep 17 00:00:00 2001 From: Dawid Masiukiewicz Date: Fri, 1 May 2020 19:26:21 +0000 Subject: [PATCH 115/217] CI and common update: -added webpage deploymnet stage -added separate build stage which build all binaries and generate documentation -added Emscripten build stage for merge to master only -added VBO batch rendering (current default, no render mode switch yet) -fixed camera positioning calculation -fixed buffer issue with WebGL -added viewport scalling (at least 300 pixels height). Pixels are scalled if screen is bigger. -center demos gameplay area -added fullpage html template for Emscripten build --- .gitignore | 2 + .gitlab-ci.yml | 87 +++-- demos/.gitignore | 2 + demos/assets/textures/atlas.png | Bin 17825 -> 24668 bytes demos/compile_wasm.py | 42 ++- demos/emscripten_multi_shell.html | 170 +++++++++ demos/emscripten_shell.html | 154 ++++++++ demos/external/sources/mmutils/thread_pool.d | 10 +- demos/source/app.d | 15 +- demos/source/demos/simple.d | 15 +- demos/source/demos/snake.d | 347 +++++++++++++++++-- demos/source/demos/space_invaders.d | 47 ++- demos/utils/source/ecs_utils/gfx/buffer.d | 6 +- demos/utils/source/ecs_utils/gfx/renderer.d | 28 +- demos/utils/source/ecs_utils/gfx/texture.d | 1 + demos/utils/source/ecs_utils/math/vector.d | 19 + dub.json | 2 +- skeleton.html | 36 ++ source/ecs/atomic.d | 11 +- source/ecs/attributes.d | 33 +- source/ecs/block_allocator.d | 21 +- source/ecs/core.d | 89 +++-- source/ecs/entity.d | 31 +- source/ecs/events.d | 10 +- source/ecs/id_manager.d | 18 +- source/ecs/manager.d | 237 +++++++------ source/ecs/std.d | 7 +- source/ecs/system.d | 47 +-- source/ecs/traits.d | 2 +- 29 files changed, 1167 insertions(+), 322 deletions(-) create mode 100644 demos/emscripten_multi_shell.html create mode 100644 demos/emscripten_shell.html create mode 100644 skeleton.html diff --git a/.gitignore b/.gitignore index 8a5c5c8..e595637 100644 --- a/.gitignore +++ b/.gitignore @@ -5,6 +5,8 @@ !README.md !./dub.json !.gitignore +!codecov.yml +!skeleton.html !meson.build !meson_options.txt !compile_wasm.py \ No newline at end of file diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index cccf254..14ba23c 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,60 +1,91 @@ -image: "registry.gitlab.com/mergul/bubel-ecs:latest" - -variables: - DOCKER_DRIVER: overlay2 - stages: - build - test - testcov + - build_emscripten + - deploy -test_compile: +build_code: stage: build + image: "registry.gitlab.com/mergul/bubel-ecs:latest" script: - - source $(/script/dlang/install.sh dmd -a) && dmd --version - - dub build -c unittest-runner -b debug --verror - - dub build -c unittest-runner -b release --verror - - dub build -c unittest-runner-betterC -b debug --verror - - dub build -c unittest-runner-betterC -b release --verror - - deactivate - - source $(/script/dlang/install.sh ldc -a) && ldc2 --version - - dub build -c unittest-runner --compiler=ldc2 -b debug --verror - - dub build -c unittest-runner --compiler=ldc2 -b release --verror - - dub build -c unittest-runner-betterC --compiler=ldc2 -b debug --verror - - dub build -c unittest-runner-betterC --compiler=ldc2 -b release --verror - - deactivate + - mkdir build + - /bin/bash /compile_ecs.sh + - cp artifacts/* build/ + - cp -r public build/ + artifacts: + expire_in: 1h + paths: + - build + rules: + - if: '$CI_MERGE_REQUEST_TARGET_BRANCH_NAME == "master"' + when: always + - when: always allow_failure: true test_dmd_debug: stage: test + image: frolvlad/alpine-glibc script: - - source $(/script/dlang/install.sh dmd -a) && dmd --version - - dub -c unittest-runner -b debug --verror + - build/dmd_debug_unittest artifacts: reports: junit: test_report.xml test_dmd: stage: test + image: frolvlad/alpine-glibc script: - - source $(/script/dlang/install.sh dmd -a) && dmd --version - - dub -c unittest-runner -b release --verror + - build/dmd_release_unittest artifacts: reports: junit: test_report.xml test_dmd_betterC: - stage: test + stage: test + image: frolvlad/alpine-glibc script: - - source $(/script/dlang/install.sh dmd -a) && dmd --version - - dub -c unittest-runner-betterC -b release --verror + - build/dmd_release_unittest_bc artifacts: reports: junit: test_report.xml + coverage_test_dmd: stage: testcov - needs: ["test_dmd_debug"] + image: "registry.gitlab.com/mergul/bubel-ecs/curl:latest" + needs: ["test_dmd_debug", "build_code"] + dependencies: + - build_code script: - mkdir reports - - source $(/script/dlang/install.sh dmd -a) && dmd --version - - dub -c unittest-runner-cov -b debug --verror + - build/dmd_unittest_cov after_script: - bash <(curl -s https://codecov.io/bash) -s reports -t 1a0c0169-a721-4085-8252-fed4755dcd8c + +emscripten: + stage: build_emscripten + image: "registry.gitlab.com/mergul/bubel-ecs/emscripten:latest" + dependencies: + - build_code + script: + - /bin/bash /build.sh + rules: + - if: '$CI_MERGE_REQUEST_TARGET_BRANCH_NAME == "master"' + when: always + artifacts: + expire_in: 1h + paths: + - wasm + +pages: + stage: deploy + image: frolvlad/alpine-glibc + script: + - mkdir public + - cp -r wasm/* public/ + - cp -r build/public/* public/ + rules: + - if: '$CI_MERGE_REQUEST_TARGET_BRANCH_NAME == "master"' + when: always + artifacts: + expire_in: 1h + paths: + - public \ No newline at end of file diff --git a/demos/.gitignore b/demos/.gitignore index 30c9e9c..1ac2a4a 100644 --- a/demos/.gitignore +++ b/demos/.gitignore @@ -12,4 +12,6 @@ !.gitignore !compile_wasm.py !cimgui.bc +!emscripten_shell.html +!emscripten_multi_shell.html .dub \ No newline at end of file diff --git a/demos/assets/textures/atlas.png b/demos/assets/textures/atlas.png index 498f34dd82959385bc9a96199c88707d782b46a0..c628969c0e7149419eb62313fb5c3274457838f3 100644 GIT binary patch literal 24668 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 literal 17825 zcmd72bx>Q;_b(c}MJq^gDDEv%99k$&f#M#D6nD3T8Wbqd;_mKFkq{^aio3fPf)ois zlXv+2?wxrv@6Nor?|uKclXE6J=j80Y_R`N<>x64*D3K7-5Q0D;5*6jw+8_`%FvJGk z!w0_3{3fq}>(l|dhF;q5e3{%lT;JO}*)VzeyV)?=_}RY)f&AtVlFedi#YsP}_(w=% zV_q?Yv3~su>tuk+#!ou8_CDVTpPS`qDrAdl`Tg`q_~7TR+Yvb5O=K1gTiCqy*<9de z(Xhnn`q0;^ETmMCVb)Ge)(!eBY@}<4QIL_sd;md~2Z#Gyrt@e+pb+ya`(yuWmmL2U z=&UUI9gM1fBluGcJhxOYv!e$A(b%c>7crQsi%Egmrfzwg9IIqaaVuv zs--9lgy0jDz6^;S`V}a!+k6ys=sUhTocdFkgHkPMOMr3Bfd8s4ECr>ly0#>=i|6Ju zUq_-eoYhSHIu;f=pNS2Xg0ODV&SHN);5uCm;W?an)LP)W$W1o-1wm6)#h{j3b#yJ4 z5GeX0j_|?nOjR{$<^Ut@-0wIc`VlNisiODtr)z8bOo=KuQrK6gKO89sR1WdMWt7-n zTv0!7jCeC|S65*kK;mV1G;ZdSL|!tUANl7ymt*`}CEDOW zPpqOvPI-&n)9N?qJck>8?pSV3b**1@b4VW5B3xQs=d4Cxq-WyD`iYoy_idxp2F~De zGleh>Gf}f*FNE{jIgjt6e^RFikA8)bXwAEcX$}WhUCh4=+TsFHhs#&}RdJe=7rL8B z8iw}juU7b$&Fl}Tlt6N}y}Z%7jy{`obz(whV}fZ;(NTpzwMRta19V&xWooWN7gv7q zon00E+yX1`i+N!lG!rzrE%^St#TD^hkRh|I;y+96kwba&&lSxX2iSa`J4UxTn-AGE zd6>wA)EYnD3gH`ql#yG_=!*=jLLx=DMdP%S*kOSJBvvJn$;%QWe_ z*i)`wBywI)M#U-&DRYMnnrSx$8SHYT8=6#_;@;2C@ItleI3Ae{v?#`mf9@wO_L1et zoI71ltFKFF*g!rqjmusPuTpj(cvBuQbzd5hKsc1KO>~8N(!3=NBJTfJ{4w|rn2F_~Rg6hNjl+x~c#F(+^^#(VsI{x_mz z?fE{Rh`Hpg+-Q$0Q*v5MR|~Q2;2+N0k~N^>_hA|Z7%78dWNQVVXMZ!rBsf(5*_u6*;ICo%I34LZTaakt~u)k-qYJ24d1KVR=W|g`(pG*9AajrGRpEW zVouGX1GZKZCwkSs^+Pef#o<6UX<8#0o^#JN1>uf&RD5USPt~*Yrk!jLKRi2#Z|XQC zbUbgrrm6k@7Qf}W(NVcNiGZGb>sy!2nU4e|@=g7-2=3mxXpg82FCy))jXN)fr{pww zzx@_6%4H)pDNxmA)MfI2@Das#hP_Lq`@ll|!0q)Td6_T|*DICW%y5u9`(HU)u?TN6 zwm)U?MW*5hu83hf&9&$`7I4cSy}WW^*7~O6&n}UZuGMBs{mc)ZX|q{kz3lo#=|F6f zI}pSBEWIN76Y+T<#Z-wwY_7mf@I?OC*pJU}TQeyAT zOv#W~n>4=N=z1m?Es^+33KW1tS6!*nEO1KGRuWk}5K;TRMZ55Hqfj5zu^_iI0j3Ry z@b!og;5l+MI((&Z(33l1pI{r2!iize;E9AW50xQa*eR#Pdj;8(RJq8|VW)jj{HuhL zn^c)dRTCgwxU%H)WmdQzKj0ji?_G#BrnNy3taAo+e14wmdGO+y_t4XtSG}AuGA-`f z-BQP$EPqN{b_G}nd>&yssvZe*Kwc*0*5^e;(pILjdKIVV`uwI0QHP|{1~YpY)3yz1GMzc6==g8tiCWUT*P5E~ zl!Oj36avLjQ|sW2`Sm47%jI;E7mrY!_-iKV7hM<^I4|VHkfI zW#&@*f&8f|1COf)O_nd`7OH9uL9ha|d|K!~Q}c?Hu~J5!#m8eVjm?#1Jp9SpyN#!R z(gYDa`>9@i>=Ps$v0*TXGO-~|#_Ce)=!pM|Fqz@X&k*1DUUu&|UNaXy4AEc#ZTmIM z^}P6}&uj6_7V81K)8{0s<&|K1eA8mWjUk4DHe=u9O8xB@-|(MA^(}XVHfAZiNQSVz z*5&=4s81ic7yMw!r##U zeB=8KtKm3f>nLPpyvL&%PbB*>1#L&Ls|h(-L|lEIEtj{Tp?TEugPY8+P^$3Q{%780 zp@arZ3+k|LwPb5SdUrqEuPz#6!%Oksl6@`cidcDnj=8OOrAVbXZI*<6gqQZ(6VK5n zj$1-!1qmby1MJMS@tT{gyyIJ+De5J%8{iOWX%V+S@@OV7VoDQT4g3Bni1W#Nn^dv1 zm)83o@${@bwz+5=%eQHv%Sc4mhtWl5S|`2y%<~T7c+w9z-H#vL%cVV|eoRT40m9QP z^|N98%=2FGX?84HtM${wc%94i_Y!Xm2YVs;J{IBkdsAKXyKX7k&!Q;2S-vX7(oYbc znz6akyiok=Ce4x*717K4ngKp*?^0#@KE1i(^{?*?Sx9#KM=zX6Tf?>X8I1xSRSHgm zxWg=HSrrM#?>Tg{YmAu@x#tJ#$2ijpKFm=(*805r&fr4yehM-TPygTazi(J9vkGTs z*{>b;=}DOdW2XGGyHmqe8Pc`o+uU}y``RARWB)#+jrv9X75&&$Z0o&74=%XL0A3xG z{+X7{awd;#0F!cZOVbYd7g*&pMNNQE~B*3PX)F|I?wa!`jlrK-yqi&HlrixeB08A z7rHDbKNA}o@HNLS|ETQpc}VxtLcWN@)!*{{T0RMmxO)4y=8~8$(8#57U&oPt+=s^` z1yj@#e|cTYX0^TJ-<_UT_FULjtyS?~G|c#n?RO`?|Mq}Y^;J1dC6f5o2K)>0QgNJ~ zNN?3Kzp2kUp^%nwS(?Y=>slpEwl@pi=yPjnQL}NDPeJpKq}jdkX|ma|oKo+x{ zO8(>C;5TB=fALb-((Lv(r(IvbE#K#fuD)QtS6i{;GCd!Bgp0={^lO9IGxmP1^@`Uo z<#WHQNBo4bduOkRy>-ghlt!$b6vgo`*EU}gRC}HXryc;9oH@70P%wGKS$cz=>mi4@ zp#T*fBauzbyk4SsZ zJWft2qKgWKEH<`rnh*0rZ+Z^HpWHkV|BT(QPaDnwMJTc(C&& zIm4AT`=By0WFjnT$a}-@uTE%8p9bTy9OK!KP0zDTwH@O6(kL^8YhQ0#c*&;2+Y;T`!-6uAr3_xCwn8 zxc||j`2Df?Yo312Jqo#s(b7+S1<=uaW)*jLa#JEwG_O9rX}Y(!8wGAB;{y&Q4h1T% zFDl(5hIrL*ftB-(S>y^zOl)el<^Jd6JM^G7@h2D02hB zAk)6m?U(4gl$B@FmqPsS{_i?zOgl^vLk{ zqu2Mozg4(zWB7Hf@`vS9g&lV?Ob8$pwzx7}#b`X;Y&nmcRp`IgruPt!UvCI|KSWb4 zpr2sNwZ6=Izp&EVxFm*!J<^ddePXcJG03sokVq+w9nkn85|PM$gq0-u5);Qy9m|4e zcX{f+di$-Ni|A|#+sx5rC3QzE7&Javwn^gVc8{2fGjM5RDdQmcx~Xsu&KRxXQ41DK zPy&)yd`mT@*C4aIk1~X*3b=CLP1(p31R{ETcVdB3)1Lqr3A|L^C=hJoK6oVZ^qb>3 z2XKknOTo}f-qqRJ#>ERH?_u-K%f_0?*WSyHNlE36mca*7DiDYXr1JWeE|C2$1tzn4 z2Ok}4B4I^EfjjN3I0O8=wL?#t+zdZF-ZY9acqI2v{H?Ckqul$k511a-tz|23j)@F( zo8Z1>+2elVseX^6*bg_{gUXcY&+vM!sE^O#gpjm!a7F2<(i^1L$l0J5YH)wJ`e^3# ztWMq+Q(D>@c?E&MTc{hI5z3Lh8x&NQJHr{FAuMo+Lnty%fS{w+M)xsjxqZ3#qA=^A zaYrwE=@*=RMei7igC>c5gnNhyBW3I1MUtgmT_lB3Ikl{`Hou8I>rBI^bV{9R6DVvb zYr9&Dd364mzzO^97E(v3Jc~&CqRdb>=4xeiQ6w}|%%V;ZyDAB^N{J?^NB|$vl*``x zz2UyFR6Q(m3oJrJiJggYDPpx3wy}r0zKYd-RzQZiy@@=JTQTHQk=S7g+m@~%1J81* zocQHuj1=t;7f)t*nVWoNazjiFIk=vevTeWB$y3?^&(%2*K`9WnX5H`}N+{NLG$k$M>0?G(!YCx`9Yyo9ukr?8ebl){!6GP?9(SKhEM%n;>z9a&YW%e(%Tb(0(#GlQ6fXjWe^ zn2bA;l_%JwN*uN$}`r=qNB5Di=f4U!^;?v8Phzab`QNb6X1qpr`z3wky+ncJ#Pi!^(0dE zj3_6t!!~M*Z%4YpDZBQ|-U{uR_<*+Ny?d9eS+(aCxDAI9OIF%y#Vxzd z-Eb#7x4l}z!n4^^uFE#Aj8k@7Q5BS?hHrr1Q9%3N$TdJ*1PhUQOwL+<#acdBUwSgQ zasRe#A;V_x>Q#}TxP2v3DfY1KRAZ_Jve&wD>!Jt41k8;1Ntq)#J06+IIuc?L!64XT zZBhl8<0*v67K-|6tioV7M)r1u&_5$;A@lW?lBY7Ef5BPLz~t$L&t==Vm2Xw5XCYDp z9LuW~aKXdlIR9t6B8744{8xXwu>48jHpGu|y%u(EQpSH90!{q3V)3b?xL+jz3b^o+{));>C53;9IV);T4y zA_Po$QQ$WEeMR(=GkN?&W_b&NI$Q5SS1nrCs-_4^UX|tK{-Hn&`(OBgzTJ{TR)rSkziGA=h7RiFr?kwPNmL3Y?&6y4b2rhHg(|0MfX#@p>Y{KLZ^qagME$+hTMY`g z$_ZjOkx%-!GW?C%WYc>$K7U;Ijh78VXo^qw*1y(EVWInZ<-+TNcr{k9sF~0fnx*YG9Nmxe2^?&eeFp1q3&Uz)#Pd zS01KzKvEA&b;;Pu?0(#=%RmiMe&a36Umbaf?cvXXn_t(Mxi}_Wqt>B~iqX{HX$5D# zI6&}6m2mBi0mRnw7X3_nOtgXj;n(C5{MXT1V~YLl4|aeSBk1-#iI&6-_~^=Lz$JvO z1)^`3P33Wm>xQcY;+GO&ov20TEmV$YIp5j_??B;Avm5TBUOIsbwpj^M(Or0~6u~VI^32|&6A>&=ud0@Q>RqiQ5c(%!xo8dpM zziM*NYUKPej-Bx!&5gv(pRN{uc1Ra2ZSu2vzwcvK9edzv0rSgRihtC#1_}kCT14l|CGnOcfxFpxLtm# zg~_rdIN$WY2zV@AQz#17e?jbEG@hn;e^_k7UlZQ%tjv8xT%~v;Bukn&SY&*7^Tu&o zY4`d>|CT@wCbcTX?lZ@;?@3x)%TDOzsYO%b!FU|rdlkX_(j#BpzZ91d&_tC9LkLT)>)v4)}X|w!en-s>Kpwv!Lg;y0XePi83+)!FN;Z8 zmvs8&$#3rn4VN^jkbzjwNpHa&IyM=TBUx~@clL}|M3rsrjH?m%;Ul-KINe1yrU`Me zXK7hC9e2T@C@8yi-FN-Du=D4hCDhUJ;35tm{rzWU7alux|82POmH%b9l%U0^FE%P= z!>#Hmwi(NVnb77};os`fa<+_iUGY5|@Ec2aocD7Y3qfl+5kji08GPuVBIs(0ZQ+q- zW~UrkMT@1#dEyP*m#V}K(Bj01YV(eMSkSPq;4^b2_hc4a0k%8?P@L7fpQuI0e+2W!Npjx?)pNB5nc@dchU|G89$ z8^6n%OpCSbY!>~&o96V4RW#ZpTv5;UOj=Up~fp zW)A~Nk&7MI)L;H-qv>ugdp7Iit$w44K3Q(lFyF~KUw&O16ls2RhL}?xDx6;)UrRn* zOOCNo!yKik8wtSY&9E!Sbp1tZyl(rpowmwLV7GlM%k=NQb7#e64$nIfk4URm&mzbW zJL4&2AqvExqxMQo+4em7M&|)Ir0#5tH!K}r)aBmV9dk+v(rfi0@|#K-O$LcsA(OXy zzCX&fulZ6b@b#YkO1b9Enp&vyLO^dr0%{D36bOqdYk%5$Iy+Qqd$qK*q_;vjdtheV zSjSvi51tDi0_t9y-KmFb=`pm}kP~a;B-2r?=eR$muNHrQ3076Y!JZ)Si$KK8@X$An z7cCK}@mq=31To~@$S1QAc)oZc)=N9sh*lo&B9kp|YDZRhSICmd-ux?H85quxq=@Mi z8A0j*Fj$lk6j@YG<}=oNZEZAu!4tz-_ulgu>gAi|Q~+lyfm_w}fc;+s$b4x=Z`p6< z{Prz9jaTCZQUg9s5`XnZeiv^WcOIVmV^$f?MEzNE}}`zPz{u=TvG+cg;`&niUTe%Kw@E5ov!x1(8CihYb7xw zkcC*hxzw1ECbg)HJm;N08QH3YJ9{6p?xe|3`$BKSFp%s*d-TGN;7<6M*rH!<0 zR1VF|NNEv$Ot0R~RSEZu=G5gi|DM;<257s*Zp4yLHiYdFXz>A)c+=G&WqQ;*LCMRe zK;}3O1gF%o-=d4EcS-8*jP}hEw(&^P+c%)(5iiI4pvan=hM$3Ijz$kI;!N-p7yAQ; ze;?QY`H)`kRS6BSMm3~#c*XZ^k%=0}@Y@za^=Ir5MEP((-tOGtB}KZQl#80Sb$!`7 zq9ob#ZGv$GMt7y9W@xU-SyFyEa<^YC9nrartm-q8{~bhx%({7Hb-XUQ0&&|f28WOA zmEU;FEJ(vYJ_fe5b#>Wt$=_@y@De0e4gklgAVS&d5Jb^?L)l9YP#YS%V={_?RuTj< zmkko4K=YY2>IP*pfj}JyUJ#I|OR8f_$Av|Evtr3T`MezgJxE z*Lu^L9oyF@xlv(QlUx2(!1|6K@*qFVRkYrlP=>^8nF9^!g%O)mHdyz+eGLC~`& z<9^43SUb)vEG$h$edpLqih3-xwI*f=R2~R=hl$|3T@i`>C5>l z(hjbU<2*Rb^t{pYl6Zkqaa{hx{zn(sO#p+u@k4@M@F?I6LzCma$hIB6R?+^uDuXl$ zH{!SmZT$B1N43v>T}G~Rxt1Uo%)TN=w|{PGRJPjhPH2k}t)TJDpgAIDI2btAyg5o? z1x5#aL;ahl5vdRHhC=Nh150aTUdsJY{yD2A5Ui}t`bZ!6dEoqpXqf>7ntTY_9+wrC zLLdTBnhbxMd{=TT-}**2TrWUwu;Nnv-C^`%>@rUaP-$9ZS)UZ8u} z{-^8GR159|{Xmnro?fB(Cb-h|Im!-r?7XpX{Q+7R?hi?NTM{e<30*%H;%*dh#sPsG zh(V~sL!nGgv97~Imk@(q&u-D5ubAR|&1qjaFNsr*!CJ5T3IFvS3r#*TsVJO&T<@A2 zhECh@rFO|#23A-LopShAF`YIn<~sjz-w%@XgJy(05Jg`Woy3aQ^{#uvmOKz$a{SFl z>jn#yjJekV%=hiO?m*jE)s{oPW3pGRt0ba(h3|yQ+%M-k{_VWH015VCAUAT=R|-Bb zdwj!h1@3!*p|%z4hOVG9*AX{PAkbjUyM?%-Q#dp@EVyP$b|dWwRj}#0`rdNl9N`Y_y;VWV8R_fU2Khb&y~Q!TcN7;iHS72gG3sZ;I{% z?uPe0$gO+hxR%Q2a8U)zT=C)-1gbk8(iLlTn$te^C+zzn@YnMeAMo7hZUIP+G(ox! zM_qIJ`ti@;pU~FJVbA6!f)Ja>Am9Sb8=3ph*zbAP4osP#$aoo3yMNV7j=Eu*I<`y*h9C0ZHJ zwDW!0>>6wBM!ivS*H-K4U-dg3%wKLp`C(_;D&uA=H;tJ~$G>u;C3LwnZB+sqqo1}c zF5q<3-Uqq-Psdy0IO_l0Ru!x2)U_x6#S4{~rQi&H_>HFxZ8s2Vs!W7sIP0Q@i%K09sG)T-|CW==_)8OQ`i@Tj z_G{k2K0;Q~Cq}kC<`*POH6iEvm%&(3tU4kTm`a`2{FQ`qdYKZQMZF1krZm}$SJLOd zh~{rP$)@#QCItq93{S9tptWGq=ro3M`T3fMHeb^Rad?43o;qE zf=69lf<)rdD1$y756YIxm!xO8%DyEj$bfF#w88W$<&JZp-J+^Ytn%R~omy z2aIX%Pk$)C&ZHqKrU>W#d$uhko5d_LDF)Yd5d_r>2MRyGJiv8< zXD=V{slIpjc7)vcuz80;q^a`8Y-c#B@yeyy#)Iwj@@%kTWf`#Amik*Q%b97{Ls)R_ zts~?XnbvOTef=R5T>(aSLlXyAs%SBPV@h3CtW6lH=|)8(@}x`hpYptLc}EVwyl`7U zGkc~hOpw!MN0V-SO93-4RAe#Zy=SvaGxjzco2M|V@gCXsJCL%H4ja$9+2okW^dvfw zD;B=}l0FlZgxNMx1mcik0?}VG$c4bX&vnvSf9E?2b)A?+4E@$g;W;BsvE$_ut>o>c z5~jZN;pYrVUm9A5xo3!DJlf2;)o=F(vvUwzk5P+Wk>)=lVv>mPGElyZOU6TjaEX)t z@T_2qw876tLDmF{ZKn>D8Gp>5PuRC8Qh|0N)69Un)8qVw5UA^D}mwshD6vL5uc7+5-YI@~k!{6sbzZ zA=yp`oVpBL#ljhAG{nDgd5wI%X49I}?wf<*xT&l>6bf%Y1A~)T*{(TIKVCnL>i4C} zx7u;RkjVy{#|pog6&1%Q=auKkr!E#f_q^^jy%uFHsoJqPzKquEtu6rlyCMd%;M;zl zqtOj8Tq7r(ufgQTv(VFGwf!{`hROEzXnHxyQ*iqD%T#$g(}-^V(#+yJ|2O`Sy|&uI zNiEHbWSh$+OlAe}5~YM`4XoUU{d zrj@HBP0rc&+I=J+)X$~ipsBIZd2xJRe|eea@?d&y9*9WvSZ<;rNno_N%6Rkvlw%;# zX<-+ch5V4lT2i_WE}j1fR%=Z$FY`6OOP}g};n%+CW2LhRMu_}T&{0-dm8;fK>xt_Q z1-3TJCmKy#cE=^Doi0Tket0QVdNim&>v# z%{jQ7IPlu+ijEW^=S<3Y)=?{g=}U{7Q<3nYeqm=LeP_nXJXm{B-DyI)d4PCXjQMgo z6w_&ZO}5fhRk{URmmfM$DGHk$U)N!`DtW&C_L;@sb<`2ZYarE&uYEk;xZF05o~M#L zK*2Z)e>~KYm&ZdQC1Ws1H2dwp*50`l^n8uyq0mKI*~0$yk@PTRqel^mq!Lbl)^I&l z9uRnHJhe7)kY!>v1tEa1jH(IPPAzWgy>N82u5T>6DmPry^VD$;`?7B~e1?umnkM~0Tuc!pW4hzztBs9B^zr#Hb>tihV;>c~oJKndxB_`Hj>)mZINRLN zP&oz)c83d7yklEbRb9;P*}%pRe0(CHA-OR#?bDmt^Hqt2Br|p1tMa6z1}Hu^QV@zu zU-UwJew7bgg*z@dtEfgTbdT&ED?3Ib5uIT@XOmSE61P#WZuimNK(5>|ejmhm=@uEh zejjTtu|j#a!~&2$@=Qa9wWPU^$1(TwQjmOay`|4cM(?bPNz*^n8AU`FDo;i2vaKT1 ze5W}jXqQoc!MrMm@%Flyu+Z8_J7<;r%vf01&%tHl$uVbEQ{<~HAimcfLU48*-26gX`&Vi!5f7 zgzTIN-DUC5wnU-%XJXb8 zS#_+qhCcrH{LV$~oyEBRq!NI{PFO&N_BoOY13EH&(bv1&ykS?F;!1+T&_<-j>iX#V9uU- zylQdG9jOf1ylRAD#KBwoq=dL2x=xTAA_<>(AhxHc+_Hv`@4TRUA^0162KKGy3jGUK zE^=XE85asA{Ka3csXp#memP9A7EuoPO0xF_l-GvqftTXr#b6Acjzr-E_%v(*YGHa! z_HAl$SlT7qi<~K=CNj&t@GU6IfQDLRpq)n)_b0T=JX?;1U_$4c zy}f+W=t;l1b_~(Va`6$yGk2RTX=uLRx;%A38e^#ly@IC>C}O$Xj)!RPrbr(6-fV;% z|DLeF+yISwLVtB%esBW=}1fqhyvDM4tVvNR)f&t2pu%X3ABwM zCh)AS;{7d>yTa*`0EIzd1l;}44DP0V za5v%q_F!_jDW2-EUZ_Z5nP`N?z`sMMFlzoO2gFH@{V1(CaR+Zq^)`S7u zGH&##JsGHD%tD18_b(-;u(6tTH-93HA{=jW{GopD)o`sDb{z#KU;zgN6os+7F|!xP zCw|0Hq&DQ?c=1EYvH3ae^-pU;q)7PcC^45n$uR`vhO1zS1sny6p50+1M{l2PPR*0l zSQ;kV2Bu{(0P`4P!=O!mMT(v_U!)!pDaSs-p;pn}Q9*E@qjx5Nsu*_1Lyx^n+5~lL zkU;=_G!maS z^B9_32;1X1OQvFSTyC?%8NTEx-07*03_PTh}eM zLfWV94J_4#ET6)vQn|zBY`gv)4#1KUMK&gd+9-$`P0DA|gXE6mo2{Sn#Po79ycUfc zj+>^g;Gtzz5kQ|b#abt|v8(JYH~1Dd#^!S!WMH?ycyH~|MI*b(M?!Hp;N#@|=@-eH zlj~0oyKWkIyyQ+%9Gp}hBOS{9!%llZM5F2sqQU7rX@1uD~18ztL zM@5{y2E)slaRwiayi*#9t+qIkSxNqwrnbi`fb?2?4;os1_4xPs4&Jfh3rW0ywDCH6 zGy;^x52UKH*V;f`XX|tPf-y5bhc&eN1IZF*zLyL7FSruCqOW{MZe71#Q8*KFizI4$ zs^yU)#aKXxCnLfRZx42W-h>f;$e~%_LCA_YR3>SJdzGwzVpO}$(_HX}o?4)xRi1cM z)b?ac?JJf~)NGH9@IIOwC01;oS9=}?J1X-Xa5&nns|Lkxo{INUx4i27_vGYK8c;8e zs@WMD?#y;7VA&*ZmyPRL=-J*)q&|h~iH`Pu)OZK8O3f4r4Go>%vj;l$T*Wm%(sSPo z^L>b8DOo>JKSM_jK<86rhIUSY0x6w8E7v1FPT*K2E42zPns)ih_2h(GI?;gX?-UMd zUys?fz=xZE@ zuNQYdMC$p|?@tCfMN)N`{_>#_lu!d5lUaI|WFHdfLR>s+g`NAauYr?r;AIRF(r>D< z8q(0bw=FlPw>JQm8~}Y+m5^VhM@UWquE;^SXl$)q%3K~mciqr{He-ojg2eKn@9dmd zIqEFR3Rudmrn>>3w0RmhxyYc;N;&!*VcBo<2Jk~$wS|^^%-zOvf^SUBvx@xk7@ESQ zO(X$;y$w7dEV22SNQJ_6b7Fa{(%SL_`z4^sA`PE~1>^NSP4X{-c27o7cT94^d0FDr z!`1Pnt-xZo2(Y-&YoYGoJ;22%q_GEXh39;0lL3t8!}@5jxt&h2u4kgY<#JxlEpBPb~??EbfjAvE!sRt%Ocq3Pl7DiLQ*@JKICkq-BUxLT@QcE*!~f8?oRy_@f#c1ZkelZ6YEZgw2FfR z(eC7_DCG#DoxP)0fRq{CTTU3)_g=^1cMTJ*zDeLzsU&#j2oNrT6g~XILpFTHNk~xH z7~no0;lxR=PTFa}gR+bEJKB_avkRxcry9%C9BK|Y3$RqlF_(>X*8h4dUzm~rM8xvB zD)slKHHG+51y_^7ZdHPFuYi$o;$A}U2KnWWaK{TEG+f>=n0Z}F0NVR23SuKvc+RU8pjXp=i~Yak0!Rt7-qofJ$?DiJgwtmyZRV%kCl?)Pba76Gig-v*UILhe z+?mipDkaI@7>G(uek|EqpK`pot3I?tNDgQ-^n;e{f1+><{ng{{oB`ruWE3*pN;B+Z z#R8NRMX@Z}w>=jY!yC6ytbPNEUD9jgtgWL(?hCV{s*R}n-cUUPXKZBPMr{E4D+tE$~W`U__ca?O*!W#0L*0yp0XJJ)wwA(zbA zMC0b90_e=G{vYp`FK$YtizcAfontbTZF(7j#-dnpiHNXHV4w`pLu3NcF$0{N`uCg5 zZ!A3TV#&NMuw-@oDSY(5Z*DI`fel9#9aJQX0cA)R$YDv)Wt*P<;L28cq)z;DZs;7~s@x%Y|hp?2u%OyapvBHyC)7vO7 zjn=dk!1iS?m(jJ%=nD#zmIjUe73^0GDakUKOi z_S}d5p!vxIP{_j&mLb?MM8~AquzD$sRl)MZ`bq-7gsxR!gzOy-%x}gE2G0}&xCrp= z%Dh@Z@suaj^R#!!_zr5-_Jjc#ltKWHj@UneW{7M0QLN2efb&kKk$||VO<({96q1+f zTEeHrpQX2Q=%SMGm<5}<0dT+1zw4taVV=vb*%9aDP*BHP*FHL2PH_Tk{F_$_xp4|I z31?hMzR`!??nLk(+V0D{x&A|z5OO!yf65a6vtHx>B^0PlVF + + + + + ECS Demo + + + + +
      emscripten
      +
      Downloading...
      +
      + +
      +
      + +
      + + +
      + +
      + + + + diff --git a/demos/emscripten_shell.html b/demos/emscripten_shell.html new file mode 100644 index 0000000..a657766 --- /dev/null +++ b/demos/emscripten_shell.html @@ -0,0 +1,154 @@ + + + + + + ECS Demo + + + + +
      emscripten
      +
      Downloading...
      +
      + +
      +
      + +
      + + +
      + +
      + + {{{ SCRIPT }}} + + diff --git a/demos/external/sources/mmutils/thread_pool.d b/demos/external/sources/mmutils/thread_pool.d index a5fbf91..374fbc1 100644 --- a/demos/external/sources/mmutils/thread_pool.d +++ b/demos/external/sources/mmutils/thread_pool.d @@ -12,6 +12,8 @@ import std.algorithm : map; version = MM_NO_LOGS; // Disable log creation //version = MM_USE_POSIX_THREADS; // Use posix threads insted of standard library, required for betterC +version (Posix)version = MM_USE_POSIX_THREADS; + version (WebAssembly) { extern(C) struct FILE @@ -374,7 +376,8 @@ version (MM_USE_POSIX_THREADS) { threadStart = dg; int ok = pthread_create(&handle, null, &threadRunFunc, cast(void*)&this); - assert(ok == 0); + if(!ok)handle = pthread_t(); + //assert(ok == 0); } void join() @@ -459,7 +462,8 @@ else version(D_BetterC) { threadStart = dg; int ok = pthread_create(&handle, null, &threadRunFunc, cast(void*)&this); - assert(ok == 0); + if(!ok)handle = pthread_t(); + //assert(ok == 0); } void join() @@ -567,7 +571,7 @@ else version(D_BetterC) threadStart = dg; handle = cast(HANDLE) _beginthreadex( null, 0, &threadRunFunc, cast(void*)&this, 0, null ); //int ok = pthread_create(&handle, null, &threadRunFunc, cast(void*)&this); - assert(handle != null); + //assert(handle != null); } void join() diff --git a/demos/source/app.d b/demos/source/app.d index 6338035..150d653 100644 --- a/demos/source/app.d +++ b/demos/source/app.d @@ -51,6 +51,7 @@ struct Launcher void function() end; void function(SDL_Event*) event; void function(vec2, Tool, int) tool; + float scalling; ivec2 window_size = ivec2(1024,768); Renderer renderer; ubyte[] keys; @@ -60,6 +61,7 @@ struct Launcher ulong timer_freq; double delta_time; uint fps; + vec2 render_position; Tool used_tool; int tool_size = 0; @@ -229,7 +231,7 @@ void mainLoop(void* arg) } if(launcher.tool && event.button.button == SDL_BUTTON_LEFT && launcher.tool_repeat == 0 && !igIsWindowHovered(ImGuiHoveredFlags_AnyWindow)) { - launcher.tool(vec2(event.button.x, launcher.window_size.y - event.button.y), launcher.used_tool, launcher.tool_size); + launcher.tool(vec2(event.button.x, launcher.window_size.y - event.button.y) * launcher.scalling - launcher.render_position, launcher.used_tool, launcher.tool_size); } } else if(event.type == SDL_MOUSEBUTTONUP) @@ -255,7 +257,7 @@ void mainLoop(void* arg) while(launcher.repeat_time > range) { launcher.repeat_time -= range; - launcher.tool(launcher.mouse.position, launcher.used_tool, launcher.tool_size); + launcher.tool((launcher.mouse.position*launcher.scalling)-launcher.render_position, launcher.used_tool, launcher.tool_size); } } @@ -525,7 +527,14 @@ void mainLoop(void* arg) } launcher.renderer.resize(launcher.window_size); - launcher.renderer.view(vec2(0,0),vec2(launcher.window_size.x,launcher.window_size.y)); + //launcher.renderer.view(vec2(0,0),vec2(launcher.window_size.x,launcher.window_size.y)); + //if(384, 768, 1152, 1536) + //576 960 1344 1728 + //float scalling; + if(launcher.window_size.y < 360)launcher.scalling = 1; + else launcher.scalling = 1.0 / ((launcher.window_size.y+120)/360); + launcher.renderer.view(launcher.render_position,vec2(launcher.window_size.x,launcher.window_size.y)*launcher.scalling); + //launcher.renderer.view(vec2(0,0),vec2(1024*launcher.window_size.x/launcher.window_size.y,768)); //glClear(GL_COLOR_BUFFER_BIT); launcher.renderer.clear(); diff --git a/demos/source/demos/simple.d b/demos/source/demos/simple.d index 36187c8..edd20c6 100644 --- a/demos/source/demos/simple.d +++ b/demos/source/demos/simple.d @@ -60,7 +60,7 @@ struct DrawSystem { foreach(i; 0..data.length) { - launcher.renderer.draw(data.textures[i].tex, data.locations[i].location, vec2(32,32), vec4(0,0,1,1), 0, 0 , 0); + launcher.renderer.draw(data.textures[i].tex, data.locations[i].location, vec2(16,16), vec4(0,0,1,1), 0, 0 , 0); //draw(renderer, data.textures[i].tex, data.locations[i], vec2(32,32), vec4(0,0,1,1)); } } @@ -81,7 +81,7 @@ struct MoveSystem foreach(i; 0..data.length) { data.locations[i].location.y = data.locations[i].location.y + 1; - if(data.locations[i].location.y > 400)data.locations[i].location.y = 0; + if(data.locations[i].location.y > 300)data.locations[i].location.y = 0; } } } @@ -119,7 +119,7 @@ void simpleStart() foreach(i; 0..10) foreach(j; 0..10) { - loc_comp.location = vec2(i*32+64,j*32+64); + loc_comp.location = vec2(i*16+64,j*16+64); launcher.manager.addEntity(simple.tmpl); } } @@ -147,6 +147,10 @@ void simpleTool(vec2 position, Tool tool, int size) { position.x += (randomf - 0.5) * size; position.y += (randomf - 0.5) * size; + if(position.x > 400)position.x -= 400; + else if(position.x < 0)position.x += 400; + if(position.y > 300)position.y -= 300; + else if(position.y < 0)position.y += 300; *location = position; } launcher.manager.addEntity(tmpl); @@ -169,17 +173,18 @@ void simpleEvent(SDL_Event* event) void spawnEntity() { CLocation* loc_comp = simple.tmpl.getComponent!CLocation; - loc_comp.location = vec2(randomf() * 600,0); + loc_comp.location = vec2(randomf() * 400,0); launcher.manager.addEntity(simple.tmpl); } bool simpleLoop() { + launcher.render_position = (vec2(launcher.window_size.x,launcher.window_size.y)*launcher.scalling - vec2(400,300)) * 0.5; + if(launcher.getKeyState(SDL_SCANCODE_SPACE)) { foreach(i;0..1)spawnEntity(); } - launcher.manager.begin(); if(launcher.multithreading) diff --git a/demos/source/demos/snake.d b/demos/source/demos/snake.d index f43c5a5..6bb8cef 100644 --- a/demos/source/demos/snake.d +++ b/demos/source/demos/snake.d @@ -17,6 +17,10 @@ import ecs_utils.gfx.texture; import ecs_utils.math.vector; import ecs_utils.utils; +import std.array : staticArray; + +enum float px = 1.0/512.0; + extern(C): struct MapElement @@ -24,9 +28,24 @@ struct MapElement enum Type { empty = 0, - snake = 1, - apple = 2, - wall = 3 + apple = 1, + wall = 2, + + snake_head_up = 5, + snake_head_down = 6, + snake_head_left = 7, + snake_head_right = 8, + snake_tail_up = 9, + snake_tail_down = 10, + snake_tail_left = 11, + snake_tail_right = 12, + snake_turn_ld = 13, + snake_turn_lu = 14, + snake_turn_rd = 15, + snake_turn_ru = 16, + snake_vertical = 17, + snake_horizontal = 18 + } Type type; EntityID id; @@ -38,8 +57,13 @@ struct Snake EntityTemplate* apple_tmpl; EntityTemplate* snake_tmpl; + EntityTemplate* snake_destroy_particle; Texture texture; + vec4[] snake_destroy_particle_frames; + vec4[] smoke_frames; + + bool move_system = true; bool draw_system = true; @@ -83,16 +107,30 @@ struct Snake void drawMap() { - const float px = 1.0/512.0; foreach(x; 0 .. map_size) { foreach(y; 0 .. map_size) { switch(element(ivec2(x,y)).type) { - case MapElement.Type.apple:launcher.renderer.draw(texture, vec2(x*32,y*32), vec2(32,32), vec4(0,32*px,16*px,16*px), 0, 0 , 0);break; - case MapElement.Type.snake:launcher.renderer.draw(texture, vec2(x*32,y*32), vec2(32,32), vec4(0,48*px,16*px,16*px), 0, 0 , 0);break; - case MapElement.Type.wall:launcher.renderer.draw(texture, vec2(x*32,y*32), vec2(32,32), vec4(0,0,1,1), 0, 0 , 0);break; + case MapElement.Type.apple:launcher.renderer.draw(texture, vec2(x*16,y*16), vec2(16,16), vec4(0,32*px,16*px,16*px), 0, 0 , 0);break; + + case MapElement.Type.snake_head_up:launcher.renderer.draw(texture, vec2(x*16,y*16), vec2(16,16), vec4(48*px,112*px,16*px,16*px), 0, 0 , 0);break; + case MapElement.Type.snake_head_down:launcher.renderer.draw(texture, vec2(x*16,y*16), vec2(16,16), vec4(48*px,144*px,16*px,16*px), 0, 0 , 0);break; + case MapElement.Type.snake_head_left:launcher.renderer.draw(texture, vec2(x*16,y*16), vec2(16,16), vec4(0,128*px,16*px,16*px), 0, 0 , 0);break; + case MapElement.Type.snake_head_right:launcher.renderer.draw(texture, vec2(x*16,y*16), vec2(16,16), vec4(32*px,128*px,16*px,16*px), 0, 0 , 0);break; + case MapElement.Type.snake_tail_up:launcher.renderer.draw(texture, vec2(x*16,y*16), vec2(16,16), vec4(16*px,112*px,16*px,16*px), 0, 0 , 0);break; + case MapElement.Type.snake_tail_down:launcher.renderer.draw(texture, vec2(x*16,y*16), vec2(16,16), vec4(0,112*px,16*px,16*px), 0, 0 , 0);break; + case MapElement.Type.snake_tail_left:launcher.renderer.draw(texture, vec2(x*16,y*16), vec2(16,16), vec4(32*px,112*px,16*px,16*px), 0, 0 , 0);break; + case MapElement.Type.snake_tail_right:launcher.renderer.draw(texture, vec2(x*16,y*16), vec2(16,16), vec4(0,144*px,16*px,16*px), 0, 0 , 0);break; + case MapElement.Type.snake_turn_ld:launcher.renderer.draw(texture, vec2(x*16,y*16), vec2(16,16), vec4(64*px,128*px,16*px,16*px), 0, 0 , 0);break; + case MapElement.Type.snake_turn_lu:launcher.renderer.draw(texture, vec2(x*16,y*16), vec2(16,16), vec4(32*px,144*px,16*px,16*px), 0, 0 , 0);break; + case MapElement.Type.snake_turn_rd:launcher.renderer.draw(texture, vec2(x*16,y*16), vec2(16,16), vec4(16*px,144*px,16*px,16*px), 0, 0 , 0);break; + case MapElement.Type.snake_turn_ru:launcher.renderer.draw(texture, vec2(x*16,y*16), vec2(16,16), vec4(64*px,112*px,16*px,16*px), 0, 0 , 0);break; + case MapElement.Type.snake_vertical:launcher.renderer.draw(texture, vec2(x*16,y*16), vec2(16,16), vec4(16*px,128*px,16*px,16*px), 0, 0 , 0);break; + case MapElement.Type.snake_horizontal:launcher.renderer.draw(texture, vec2(x*16,y*16), vec2(16,16), vec4(48*px,128*px,16*px,16*px), 0, 0 , 0);break; + + case MapElement.Type.wall:launcher.renderer.draw(texture, vec2(x*16,y*16), vec2(16,16), vec4(0,0,1,1), 0, 0 , 0);break; default:break; } } @@ -101,6 +139,19 @@ struct Snake } +struct Animation +{ + +} + +struct CAnimation +{ + mixin ECS.Component; + + vec4[] frames; + float time = 0; +} + struct CILocation { mixin ECS.Component; @@ -116,7 +167,7 @@ struct CLocation alias location this; - vec2 location; + vec2 location = vec2(0,0); } struct CSnake @@ -176,13 +227,15 @@ struct CApple struct CParticle { mixin ECS.Component; + + float life = 0; } struct CParticleVector { mixin ECS.Component; - vec2 velocity; + vec2 velocity = vec2(0,0); } struct CMovement @@ -226,10 +279,98 @@ struct AppleSystem } } +struct ParticleSystem +{ + mixin ECS.System!1; + + struct EntitiesData + { + uint length; + @readonly Entity[] entities; + @readonly CParticle[] particle; + } + + void onUpdate(EntitiesData data) + { + foreach(i;0..data.length) + { + data.particle[i].life -= launcher.delta_time; + if(data.particle[i].life < 0)launcher.manager.removeEntity(data.entities[i].id); + } + } +} + +struct ParticleMovementSystem +{ + mixin ECS.System!1; + + struct EntitiesData + { + uint length; + @readonly Entity[] entities; + @readonly CParticleVector[] movement; + CLocation[] location; + } + + void onUpdate(EntitiesData data) + { + foreach(i;0..data.length) + { + data.location[i].location -= data.movement[i].velocity; + } + } +} + + +struct AnimationSystem +{ + mixin ECS.System!1; + + struct EntitiesData + { + uint length; + CAnimation[] animation; + } + + void onUpdate(EntitiesData data) + { + foreach(i;0..data.length) + { + data.animation[i].time += launcher.delta_time * 0.01; + while(data.animation[i].time >= data.animation[i].frames.length)data.animation[i].time -= cast(float)data.animation[i].frames.length; + } + } +} + + +struct AnimationRenderSystem +{ + mixin ECS.System!1; + + struct EntitiesData + { + uint length; + @readonly CAnimation[] animation; + @readonly CLocation[] location; + } + + void onUpdate(EntitiesData data) + { + foreach(i;0..data.length) + { + launcher.renderer.draw(snake.texture, cast(vec2)cast(ivec2)data.location[i].location, vec2(16,16), data.animation[i].frames[cast(int)(data.animation[i].time)], 0, 0 , 0); + } + } +} + struct MoveSystem { mixin ECS.System!64; + EntityTemplate* destroy_template; + CLocation* destroy_location; + CParticleVector* destroy_vector; + struct EntitiesData { uint length; @@ -239,6 +380,13 @@ struct MoveSystem CILocation[] location; } + void setTemplates() + { + destroy_template = snake.snake_destroy_particle; + destroy_location = destroy_template.getComponent!CLocation; + destroy_vector = destroy_template.getComponent!CParticleVector; + } + void moveLocation(ref CILocation location, CMovement.Direction direction) { final switch(direction) @@ -276,6 +424,56 @@ struct MoveSystem else .snake.element(MapElement(),location); } + static CMovement.Direction getDirection(ivec2 p1, ivec2 p2) + { + if(p1.x - p2.x == -1)return CMovement.direction.right; + else if(p1.x - p2.x == 1)return CMovement.direction.left; + else if(p1.y - p2.y == -1)return CMovement.direction.up; + else if(p1.y - p2.y == 1)return CMovement.direction.down; + else if(p1.x - p2.x > 1)return CMovement.direction.right; + else if(p1.x - p2.x < -1)return CMovement.direction.left; + else if(p1.y - p2.y > 1)return CMovement.direction.up; + else return CMovement.direction.down; + } + + static MapElement.Type snakePart(ivec2 p1, ivec2 p2, ivec2 p3) + { + CMovement.Direction direction = getDirection(p1, p2); + CMovement.Direction direction2 = getDirection(p1, p3); + uint case_ = direction*4 + direction2; + final switch(case_) + { + case 0:return MapElement.Type.snake_horizontal; + case 1:return MapElement.Type.snake_horizontal; + case 2:return MapElement.Type.snake_turn_lu; + case 3:return MapElement.Type.snake_turn_ru; + case 4:return MapElement.Type.snake_horizontal; + case 5:return MapElement.Type.snake_horizontal; + case 6:return MapElement.Type.snake_turn_ld; + case 7:return MapElement.Type.snake_turn_rd; + case 8:return MapElement.Type.snake_turn_lu; + case 9:return MapElement.Type.snake_turn_ld; + case 10:return MapElement.Type.snake_vertical; + case 11:return MapElement.Type.snake_vertical; + case 12:return MapElement.Type.snake_turn_ru; + case 13:return MapElement.Type.snake_turn_rd; + case 14:return MapElement.Type.snake_vertical; + case 15:return MapElement.Type.snake_vertical; + } + } + + static MapElement.Type snakeTail(ivec2 p1, ivec2 p2) + { + CMovement.Direction direction = getDirection(p1, p2); + final switch(direction) + { + case CMovement.Direction.up:return MapElement.Type.snake_tail_up; + case CMovement.Direction.down:return MapElement.Type.snake_tail_down; + case CMovement.Direction.left:return MapElement.Type.snake_tail_left; + case CMovement.Direction.right:return MapElement.Type.snake_tail_right; + } + } + void onUpdate(EntitiesData data) { if(data.snakes) @@ -286,21 +484,104 @@ struct MoveSystem moveLocation(data.location[i], data.movement[i].direction); final switch(snake.element(data.location[i].location).type) { - case MapElement.Type.snake: - launcher.manager.removeEntity(data.entities[i].id); - break; - case MapElement.Type.wall: + case MapElement.Type.snake_head_up:goto case(MapElement.Type.snake_horizontal); + case MapElement.Type.snake_head_down:goto case(MapElement.Type.snake_horizontal); + case MapElement.Type.snake_head_left:goto case(MapElement.Type.snake_horizontal); + case MapElement.Type.snake_head_right:goto case(MapElement.Type.snake_horizontal); + case MapElement.Type.snake_tail_up:goto case(MapElement.Type.snake_horizontal); + case MapElement.Type.snake_tail_down:goto case(MapElement.Type.snake_horizontal); + case MapElement.Type.snake_tail_left:goto case(MapElement.Type.snake_horizontal); + case MapElement.Type.snake_tail_right:goto case(MapElement.Type.snake_horizontal); + case MapElement.Type.snake_turn_ld:goto case(MapElement.Type.snake_horizontal); + case MapElement.Type.snake_turn_lu:goto case(MapElement.Type.snake_horizontal); + case MapElement.Type.snake_turn_rd:goto case(MapElement.Type.snake_horizontal); + case MapElement.Type.snake_turn_ru:goto case(MapElement.Type.snake_horizontal); + case MapElement.Type.snake_vertical:goto case(MapElement.Type.snake_horizontal); + case MapElement.Type.snake_horizontal: + foreach(ivec2 loc; data.snakes[i].parts) + { + destroy_location.x = loc.x * 16; + destroy_location.y = loc.y * 16; + snake.element(MapElement(MapElement.Type.empty, EntityID()),loc); + launcher.manager.addEntity(snake.snake_destroy_particle); + foreach(j;0..10) + { + destroy_location.x = loc.x * 16 + randomf() * 8 - 4; + destroy_location.y = loc.y * 16 + randomf() * 8 - 4; + destroy_vector.velocity = vec2(randomf(),randomf())*0.4-0.2; + snake.element(MapElement(MapElement.Type.empty, EntityID()),loc); + launcher.manager.addEntity(snake.snake_destroy_particle); + } + + } + destroy_location.x = new_location.x * 16; + destroy_location.y = new_location.y * 16; + snake.element(MapElement(MapElement.Type.empty, EntityID()),new_location); + launcher.manager.addEntity(snake.snake_destroy_particle); launcher.manager.removeEntity(data.entities[i].id); break; + case MapElement.Type.wall:break; + //launcher.manager.removeEntity(data.entities[i].id); + //break; case MapElement.Type.empty: moveSnake(data.snakes[i], new_location); - snake.element(MapElement(MapElement.Type.snake, data.entities[i].id),data.location[i].location); + final switch(data.movement[i].direction) + { + case CMovement.Direction.up: + snake.element(MapElement(MapElement.Type.snake_head_up, data.entities[i].id),data.location[i].location); + break; + case CMovement.Direction.right: + snake.element(MapElement(MapElement.Type.snake_head_right, data.entities[i].id),data.location[i].location); + break; + case CMovement.Direction.down: + snake.element(MapElement(MapElement.Type.snake_head_down, data.entities[i].id),data.location[i].location); + break; + case CMovement.Direction.left: + snake.element(MapElement(MapElement.Type.snake_head_left, data.entities[i].id),data.location[i].location); + break; + } + if(data.snakes[i].parts.length > 1) + { + MapElement.Type elem_type = snakePart(data.snakes[i].parts[$-1],data.location[i],data.snakes[i].parts[$-2]); + snake.element(MapElement(elem_type, data.entities[i].id),data.snakes[i].parts[$-1]); + elem_type = snakeTail(data.snakes[i].parts[1], data.snakes[i].parts[0]); + snake.element(MapElement(elem_type, data.entities[i].id),data.snakes[i].parts[0]); + } + else if(data.snakes[i].parts.length == 1) + { + MapElement.Type elem_type = snakeTail(data.location[i], data.snakes[i].parts[0]); + snake.element(MapElement(elem_type, data.entities[i].id),data.snakes[i].parts[0]); + } break; case MapElement.Type.apple: launcher.manager.removeEntity(snake.element(data.location[i].location).id); - data.snakes[i].parts.add(new_location); - snake.element(MapElement(MapElement.Type.snake, data.entities[i].id),new_location); - snake.element(MapElement(MapElement.Type.snake, data.entities[i].id),data.location[i].location); + if(data.snakes[i].parts.length < 100)data.snakes[i].parts.add(new_location); + + if(data.snakes[i].parts.length > 1) + { + MapElement.Type elem_type = snakePart(data.snakes[i].parts[$-1],data.location[i],data.snakes[i].parts[$-2]); + snake.element(MapElement(elem_type, data.entities[i].id),data.snakes[i].parts[$-1]); + } + else if(data.snakes[i].parts.length == 1) + { + MapElement.Type elem_type = snakeTail(data.location[i], new_location); + snake.element(MapElement(elem_type, data.entities[i].id),new_location); + } + final switch(data.movement[i].direction) + { + case CMovement.Direction.up: + snake.element(MapElement(MapElement.Type.snake_head_up, data.entities[i].id),data.location[i].location); + break; + case CMovement.Direction.right: + snake.element(MapElement(MapElement.Type.snake_head_right, data.entities[i].id),data.location[i].location); + break; + case CMovement.Direction.down: + snake.element(MapElement(MapElement.Type.snake_head_down, data.entities[i].id),data.location[i].location); + break; + case CMovement.Direction.left: + snake.element(MapElement(MapElement.Type.snake_head_left, data.entities[i].id),data.location[i].location); + break; + } snake.addApple(); break; } @@ -455,19 +736,31 @@ void snakeStart() launcher.manager.registerComponent!CSnake; launcher.manager.registerComponent!CApple; launcher.manager.registerComponent!CParticle; + launcher.manager.registerComponent!CParticleVector; launcher.manager.registerComponent!CMovement; launcher.manager.registerComponent!CInput; + launcher.manager.registerComponent!CAnimation; launcher.manager.registerSystem!MoveSystem(0,"fixed"); launcher.manager.registerSystem!InputSystem(-100); launcher.manager.registerSystem!FixSnakeDirectionSystem(-1,"fixed"); launcher.manager.registerSystem!AppleSystem(-1,"fixed"); + launcher.manager.registerSystem!AnimationRenderSystem(100); + launcher.manager.registerSystem!AnimationSystem(-1); + launcher.manager.registerSystem!ParticleSystem(-1); + launcher.manager.registerSystem!ParticleMovementSystem(-1); launcher.manager.endRegister(); launcher.gui_manager.addSystem(MoveSystem.system_id,"Move System"); launcher.gui_manager.addSystem(InputSystem.system_id,"Input System"); launcher.gui_manager.addSystem(FixSnakeDirectionSystem.system_id,"Fix Direction System"); + launcher.gui_manager.addSystem(AnimationRenderSystem.system_id,"Animation Render System"); + launcher.gui_manager.addSystem(AnimationSystem.system_id,"Animation System"); + launcher.gui_manager.addSystem(ParticleSystem.system_id,"Particle Life System"); + launcher.gui_manager.addSystem(ParticleMovementSystem.system_id,"Particle Movement System"); + + snake.snake_destroy_particle_frames = Mallocator.makeArray([vec4(64,144,16,16)*px,vec4(80,144,16,16)*px,vec4(96,144,16,16)*px,vec4(112,144,16,16)*px].staticArray); { ushort[4] components = [CILocation.component_id, CSnake.component_id, CMovement.component_id, CInput.component_id]; @@ -477,14 +770,26 @@ void snakeStart() launcher.manager.addEntity(snake.snake_tmpl); } + { + snake.snake_destroy_particle = launcher.manager.allocateTemplate([CLocation.component_id, CParticle.component_id, CParticleVector.component_id, CAnimation.component_id].staticArray); + CAnimation* canim = snake.snake_destroy_particle.getComponent!CAnimation; + canim.frames = snake.snake_destroy_particle_frames; + CParticle* particle = snake.snake_destroy_particle.getComponent!CParticle; + particle.life = 400; + } + { ushort[2] components = [CILocation.component_id, CApple.component_id]; snake.apple_tmpl = launcher.manager.allocateTemplate(components); snake.addApple(); } - + launcher.gui_manager.addTemplate(snake.snake_tmpl, "Snake"); launcher.gui_manager.addTemplate(snake.apple_tmpl, "Apple"); + launcher.gui_manager.addTemplate(snake.snake_destroy_particle, "Particle"); + + MoveSystem* move_system = launcher.manager.getSystem!MoveSystem(); + move_system.setTemplates(); /*foreach(i; 0..10) foreach(j; 0..10) @@ -520,8 +825,8 @@ void snakeTool(vec2 position, Tool tool, int size) position.x += (randomf - 0.5) * size; position.y += (randomf - 0.5) * size; ivec2 ipos; - ipos.x = cast(int)(position.x / 32); - ipos.y = cast(int)(position.y / 32); + ipos.x = cast(int)(position.x / 16); + ipos.y = cast(int)(position.y / 16); *ilocation = ipos; if(snake.element(ipos).type != MapElement.Type.empty)return; } @@ -540,6 +845,8 @@ void snakeEvent(SDL_Event* event) bool snakeLoop() { + launcher.render_position = (vec2(launcher.window_size.x,launcher.window_size.y)*launcher.scalling - vec2(288,288)) * 0.5; + /*if(launcher.show_demo_wnd) { igSetNextWindowPos(ImVec2(800 - 260, 30), ImGuiCond_Once, ImVec2(0,0)); diff --git a/demos/source/demos/space_invaders.d b/demos/source/demos/space_invaders.d index 5473aed..bddf53c 100644 --- a/demos/source/demos/space_invaders.d +++ b/demos/source/demos/space_invaders.d @@ -16,6 +16,8 @@ import ecs_utils.gfx.texture; import ecs_utils.math.vector; import ecs_utils.utils; +enum float px = 1.0/512.0; + extern(C): /*####################################################################################################################### @@ -34,7 +36,7 @@ struct SpaceInvaders bool move_system = true; bool draw_system = true; - const vec2 map_size = vec2(600,600); + const vec2 map_size = vec2(400,300); const float cell_size = 60; } @@ -101,7 +103,7 @@ struct CScale ///use component as it value alias value this; - vec2 value = vec2(32,32); + vec2 value = vec2(16,16); } struct CTexture @@ -564,8 +566,8 @@ struct MovementSystem { foreach(i;0..data.length) { - data.locations[i].x += data.velocity[i].x * launcher.delta_time; - data.locations[i].y += data.velocity[i].y * launcher.delta_time; + data.locations[i].x += data.velocity[i].x * launcher.delta_time * 0.5; + data.locations[i].y += data.velocity[i].y * launcher.delta_time * 0.5; } } } @@ -587,6 +589,7 @@ struct InputMovementSystem const (CInput)[] input; //components are treated as required by default CLocation[] locations; + CTexture[] textures; } /** @@ -595,6 +598,7 @@ struct InputMovementSystem */ bool onBegin() { + move_vector = vec2(0,0); if(launcher.getKeyState(SDL_SCANCODE_W)) { move_vector = vec2(0,1); @@ -616,7 +620,7 @@ struct InputMovementSystem return true; } //don't call system update because no key pressed - return false; + return true; } /** @@ -627,11 +631,21 @@ struct InputMovementSystem */ void onUpdate(EntitiesData data) { + if(move_vector.x == 0) + { + foreach(i; 0..data.length) + { + data.textures[i].coords = vec4(0*px,80*px,48*px,32*px); + } + return; + } //move every entity using movement vector foreach(i; 0..data.length) { - data.locations[i].x += move_vector.x * launcher.delta_time * 0.5; - data.locations[i].y += move_vector.y * launcher.delta_time * 0.5; + data.locations[i].x += move_vector.x * launcher.delta_time * 0.25; + data.locations[i].y += move_vector.y * launcher.delta_time * 0.25; + if(move_vector.x > 0)data.textures[i].coords = vec4(48*px,80*px,48*px,32*px); + else data.textures[i].coords = vec4(0*px,80*px,48*px,32*px); } } } @@ -644,8 +658,6 @@ __gshared SpaceInvaders* space_invaders; void spaceInvadersStart() { - const float px = 1.0/512.0; - space_invaders = Mallocator.make!SpaceInvaders; space_invaders.texture.create(); @@ -690,9 +702,11 @@ void spaceInvadersStart() ushort[7] components = [CLocation.component_id, CTexture.component_id, CInput.component_id, CShip.component_id, CScale.component_id, CLaserWeapon.component_id, CShootDirection.component_id]; space_invaders.ship_tmpl = launcher.manager.allocateTemplate(components); + CScale* scale_comp = space_invaders.ship_tmpl.getComponent!CScale; + scale_comp.value = vec2(48,32); CTexture* tex_comp = space_invaders.ship_tmpl.getComponent!CTexture; tex_comp.tex = space_invaders.texture;//ship_tex; - tex_comp.coords = vec4(0*px,48*px,16*px,16*px); + tex_comp.coords = vec4(0*px,80*px,48*px,32*px); CLocation* loc_comp = space_invaders.ship_tmpl.getComponent!CLocation; loc_comp.value = vec2(64,64); CLaserWeapon* weapon = space_invaders.ship_tmpl.getComponent!CLaserWeapon; @@ -707,9 +721,9 @@ void spaceInvadersStart() CTexture* tex_comp = space_invaders.laser_tmpl.getComponent!CTexture; tex_comp.tex = space_invaders.texture;//laser_tex; - tex_comp.coords = vec4(0*px,48*px,16*px,16*px); + tex_comp.coords = vec4(0*px,24*px,2*px,8*px); CScale* scale_comp = space_invaders.laser_tmpl.getComponent!CScale; - scale_comp.value = vec2(4,16); + scale_comp.value = vec2(2,8); CVelocity* vel_comp = space_invaders.laser_tmpl.getComponent!CVelocity; vel_comp.value = vec2(0,1); } @@ -727,7 +741,7 @@ void spaceInvadersStart() tex_comp.tex = space_invaders.texture;//ship_tex; tex_comp.coords = vec4(32*px,32*px,16*px,16*px); CLocation* loc_comp = space_invaders.enemy_tmpl.getComponent!CLocation; - loc_comp.value = vec2(64,space_invaders.map_size.y - 64); + loc_comp.value = vec2(64,space_invaders.map_size.y - 16); CShootDirection* shoot_dir_comp = space_invaders.enemy_tmpl.getComponent!CShootDirection; shoot_dir_comp.direction = Direction.down; CVelocity* vel_comp = space_invaders.enemy_tmpl.getComponent!CVelocity; @@ -738,17 +752,17 @@ void spaceInvadersStart() current_entity = launcher.manager.addEntity(space_invaders.enemy_tmpl); launcher.manager.addComponents(current_entity.id,CSideMove(0)); - loc_comp.value = vec2(128,space_invaders.map_size.y - 64); + loc_comp.value = vec2(128,space_invaders.map_size.y - 16); current_entity = launcher.manager.addEntity(space_invaders.enemy_tmpl); launcher.manager.addComponents(current_entity.id,CSideMove(-1)); enemy_id = current_entity.id; //enemy_tmpl = launcher.manager.allocateTemplate(current_entity.id); - loc_comp.value = vec2(256,space_invaders.map_size.y - 64); + loc_comp.value = vec2(256,space_invaders.map_size.y - 16); launcher.manager.addEntity(space_invaders.enemy_tmpl); - loc_comp.value = vec2(0,space_invaders.map_size.y - 64); + loc_comp.value = vec2(0,space_invaders.map_size.y - 16); current_entity = launcher.manager.addEntity(space_invaders.enemy_tmpl); launcher.manager.addComponents(current_entity.id,CSideMove(0)); @@ -809,6 +823,7 @@ void spaceInvadersEvent(SDL_Event* event) bool spaceInvadersLoop() { + launcher.render_position = (vec2(launcher.window_size.x,launcher.window_size.y)*launcher.scalling - vec2(400,300)) * 0.5; /*if(launcher.show_demo_wnd) { diff --git a/demos/utils/source/ecs_utils/gfx/buffer.d b/demos/utils/source/ecs_utils/gfx/buffer.d index 1f38624..2c25324 100644 --- a/demos/utils/source/ecs_utils/gfx/buffer.d +++ b/demos/utils/source/ecs_utils/gfx/buffer.d @@ -55,10 +55,10 @@ struct Buffer glBufferStorage(GL_ARRAY_BUFFER,size*count,data, flags); }*/ - void bufferSubData(uint size, uint offset, void* data) nothrow + void bufferSubData(BindTarget target, uint size, uint offset, void* data) nothrow { - bind(BindTarget.array); - glBufferSubData(GL_ARRAY_BUFFER,offset,size,data); + bind(target); + glBufferSubData(target,offset,size,data); } void map(BindTarget target) nothrow diff --git a/demos/utils/source/ecs_utils/gfx/renderer.d b/demos/utils/source/ecs_utils/gfx/renderer.d index e064c9e..2a04c57 100644 --- a/demos/utils/source/ecs_utils/gfx/renderer.d +++ b/demos/utils/source/ecs_utils/gfx/renderer.d @@ -98,7 +98,7 @@ struct Renderer alias Technique = RenderTechnique; - __gshared Technique technique = Technique.simple; + __gshared Technique technique = Technique.vbo_batch; void* data_ptr; //import ecs_utils.core : RenderTechnique; @@ -339,6 +339,7 @@ struct Renderer //import core.stdc.string; with(this_) { + if(item_id >= MaxObjects)return; //pos += view_pos; size.x *= view_size.x; size.y *= view_size.y; @@ -470,8 +471,8 @@ struct Renderer break; case Technique.vbo_batch: //if(data_index){ - batch_vbo[0].bufferSubData(item_id*4*16,0,batch_vertices.ptr); - batch_ibo[0].bufferSubData(item_id*6*2,0,batch_indices.ptr); + batch_vbo[0].bufferSubData(Buffer.BindTarget.array,item_id*4*16,0,batch_vertices.ptr); + batch_ibo[0].bufferSubData(Buffer.BindTarget.element_array,item_id*6*2,0,batch_indices.ptr); batch_vbo[0].bind(Buffer.BindTarget.array); batch_ibo[0].bind(Buffer.BindTarget.element_array); @@ -480,8 +481,8 @@ struct Renderer glVertexAttribPointer(1,2,GL_FLOAT,false,16,cast(void*)8);//} break; case Technique.instanced_attrib_divisor: - ubos[0].bufferSubData(data_index,0,uniform_block.ptr); - ubos[0].bind(Buffer.BindTarget.array); + ubos[0].bufferSubData(Buffer.BindTarget.uniform,data_index,0,uniform_block.ptr); + ubos[0].bind(Buffer.BindTarget.uniform); glEnableVertexAttribArray(2); glEnableVertexAttribArray(3); glEnableVertexAttribArray(4); @@ -496,7 +497,7 @@ struct Renderer break; case Technique.uniform_buffer: //ubos[0].bufferData(1,64*MaxObjects,BufferUsage,null); - /*if(data_index)*/ubos[0].bufferSubData(data_index,0,uniform_block.ptr); + /*if(data_index)*/ubos[0].bufferSubData(Buffer.BindTarget.uniform,data_index,0,uniform_block.ptr); break; case Technique.uniform_buffer_indexed: ubos[0].bindRange(Buffer.BindTarget.uniform,0,0,block_max_size); @@ -581,6 +582,8 @@ struct Renderer { material_id = render_list[i].material_id; GfxConfig.materials[material_id].bind(); + float[3*4] data = [1,0,0,1,0,0,0,0,0,0,1,1]; + GfxConfig.materials[material_id].pushUniforms(data.ptr); } if(texture.data != render_list[i].texture.data) { @@ -589,17 +592,17 @@ struct Renderer } uint instance_count = 16_384; - if(i*16_384 > item_id) + if((i+1)*16_384 > item_id) { - instance_count = i*16_384 - item_id; + instance_count = item_id%16_384; } - /*glVertexAttribPointer(0,2,GL_FLOAT,false,16,cast(void*)(i*16_384*4*16)); + glVertexAttribPointer(0,2,GL_FLOAT,false,16,cast(void*)(i*16_384*4*16)); glVertexAttribPointer(1,2,GL_FLOAT,false,16,cast(void*)(i*16_384*4*16+8)); - glDrawElements(GL_TRIANGLES,instance_count*6,GL_UNSIGNED_SHORT,cast(void*)(i*16_384*6*2));*/ + glDrawElements(GL_TRIANGLES,instance_count*6,GL_UNSIGNED_SHORT,cast(void*)(i*16_384*6*2)); - glDrawElementsBaseVertex(GL_TRIANGLES,instance_count*6,GL_UNSIGNED_SHORT,cast(void*)(i*16_384*6*2),i*16_384*4); + //glDrawElementsBaseVertex(GL_TRIANGLES,instance_count*6,GL_UNSIGNED_SHORT,cast(void*)(i*16_384*6*2),i*16_384*4); } } else if(technique == Technique.ssbo_instanced || technique == Technique.instanced_attrib_divisor) @@ -794,9 +797,10 @@ struct Renderer void view(vec2 pos, vec2 size) { - view_pos = pos * size - 1; + //view_pos = pos * size - 1; view_size = vec2(2/size.x,2/size.y); sdl_transform = vec4(0,0,1.0/size.x,1.0/size.y); + view_pos = (pos - size * 0.5) * view_size; } __gshared void function(ref Renderer this_, Texture tex, vec2 pos, vec2 size, vec4 coords, float angle, uint material_id, uint mesh_id) __draw; diff --git a/demos/utils/source/ecs_utils/gfx/texture.d b/demos/utils/source/ecs_utils/gfx/texture.d index 4407123..bb4c62a 100644 --- a/demos/utils/source/ecs_utils/gfx/texture.d +++ b/demos/utils/source/ecs_utils/gfx/texture.d @@ -55,6 +55,7 @@ struct Texture data.data[0..$] = (cast(ubyte*)surf.pixels)[0..data.data.length]; glGenTextures(1, &data.gl_handle); + glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D,data.gl_handle); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); diff --git a/demos/utils/source/ecs_utils/math/vector.d b/demos/utils/source/ecs_utils/math/vector.d index 10b4de5..4b9f3af 100644 --- a/demos/utils/source/ecs_utils/math/vector.d +++ b/demos/utils/source/ecs_utils/math/vector.d @@ -30,6 +30,11 @@ struct vec2 else static assert(0, "Operator "~op~" not implemented"); } + ivec2 opCast() + { + return ivec2(cast(int)x,cast(int)y); + } + void opOpAssign(string op)(vec2 v) { static if (op == "+") @@ -69,6 +74,15 @@ struct vec4 } float[4] data; } + + vec4 opBinary(string op)(float v) + { + static if (op == "+") return vec4(x + v, y + v, z + v, w + v); + else static if (op == "-") return vec4(x - v, y - v, z - v, w - v); + else static if (op == "*") return vec4(x * v, y * v, z * v, w * v); + else static if (op == "/") return vec4(x / v, y / v, z / v, w / v); + else static assert(0, "Operator "~op~" not implemented"); + } } struct ivec2 @@ -82,6 +96,11 @@ struct ivec2 } int[2] data; } + + vec2 opCast() + { + return vec2(x,y); + } } struct ivec4 diff --git a/dub.json b/dub.json index 1709ae0..c23a4e6 100755 --- a/dub.json +++ b/dub.json @@ -5,7 +5,7 @@ ], "description": "Dynamic Entity Component System", "copyright": "Copyright © 2018-2019, Michał Masiukiewicz, Dawid Masiukiewicz", - "license": "BSD", + "license": "BSD 3-clause", "sourcePaths" : ["source\/"], "excludedSourceFiles":[ "source\/ecs\/traits.d" diff --git a/skeleton.html b/skeleton.html new file mode 100644 index 0000000..02f57a2 --- /dev/null +++ b/skeleton.html @@ -0,0 +1,36 @@ + + + + BubelECS + + + + + + + + + +
      +
      +
      +
      + +
      + + + diff --git a/source/ecs/atomic.d b/source/ecs/atomic.d index 91cc3d4..5e5f447 100644 --- a/source/ecs/atomic.d +++ b/source/ecs/atomic.d @@ -1,8 +1,11 @@ /************************************************************************************************************************ -*It's internal code. Can be used for atomics if emscripten backend will be used. -* -*This module contain atomic operations which include support for emscripten atomics functions. -*Emscripten functions are contained in API similar to druntime. +It's internal code. Can be used for atomics if emscripten backend will be used. + +This module contain atomic operations which include support for emscripten atomics functions. +Emscripten functions are contained in API similar to druntime. + +Copyright: Copyright © 2018-2019, Dawid Masiukiewicz, Michał Masiukiewicz +License: BSD 3-clause, see LICENSE file in project root folder. */ module ecs.atomic; diff --git a/source/ecs/attributes.d b/source/ecs/attributes.d index 2b24178..20d0f60 100644 --- a/source/ecs/attributes.d +++ b/source/ecs/attributes.d @@ -1,17 +1,24 @@ /************************************************************************************************************************ -*This module contain attributes used to mark components. -*Currently only two attributes are supported: -* - optional: mark component as optional for system update -* - readonly: mark component access as read only (used for multithreading) -* -*By default components are required and mutable. "const" attribute can be used insteac od readonly mark. -*ex. -*Struct EntitiesData -*{ -* Comp1[] cmp; //mutable required component -* @readonly @optional Comp2[] cmp2; //optional read only component -* @optional const (Comp3)[] cmp3; //same as cmp2 -*} +This module contain attributes used to mark components. +Currently only two attributes are supported: +$(LIST + * optional: mark component as optional for system update + * readonly: mark component access as read only (used for multithreading) +) + +By default components are required and mutable. "const" attribute can be used insteac od readonly mark. + +--- +Struct EntitiesData +{ + Comp1[] cmp; //mutable required component + @readonly @optional Comp2[] cmp2; //optional read only component + @optional const (Comp3)[] cmp3; //same as cmp2 +} +--- + +Copyright: Copyright © 2018-2019, Dawid Masiukiewicz, Michał Masiukiewicz +License: BSD 3-clause, see LICENSE file in project root folder. */ module ecs.attributes; diff --git a/source/ecs/block_allocator.d b/source/ecs/block_allocator.d index 5db4dab..d9f08ca 100644 --- a/source/ecs/block_allocator.d +++ b/source/ecs/block_allocator.d @@ -1,7 +1,10 @@ /************************************************************************************************************************ -*It's internal code. -* -*Module contain memory allocator. +It's internal code. + +Module contain memory allocator. + +Copyright: Copyright © 2018-2019, Dawid Masiukiewicz, Michał Masiukiewicz +License: BSD 3-clause, see LICENSE file in project root folder. */ module ecs.block_allocator; @@ -9,14 +12,14 @@ import ecs.manager; import ecs.std; /************************************************************************************************************************ -*Allocator allocate large blocks and return smaller blocks. When there is no more blocks then next large block is allocated. -*By default freeing memory only returns it to allocator. To free large memory chunks freeMemory function is used. -*freeMemory function return to system memory even if chunk blocks wasn't freed. +Allocator allocate large blocks and return smaller blocks. When there is no more blocks then next large block is allocated. +By default freeing memory only returns it to allocator. To free large memory chunks freeMemory function is used. +freeMemory function return to system memory even if chunk blocks wasn't freed. */ struct BlockAllocator { /************************************************************************************************************************ - *Get new block. Allocator automatically allocate next memory chunk if needed. + Get new block. Allocator automatically allocate next memory chunk if needed. */ void* getBlock() nothrow @nogc { @@ -28,7 +31,7 @@ struct BlockAllocator } /************************************************************************************************************************ - *Return block to allocator for further use. + Return block to allocator for further use. */ void freeBlock(void* block) nothrow @nogc { @@ -37,7 +40,7 @@ struct BlockAllocator } /************************************************************************************************************************ - *Free whole used memory. This function return to system all memory chunks even if not every black was freed. + Free whole used memory. This function return to system all memory chunks even if not every black was freed. */ void freeMemory() nothrow @nogc { diff --git a/source/ecs/core.d b/source/ecs/core.d index 91c9065..c346c9f 100644 --- a/source/ecs/core.d +++ b/source/ecs/core.d @@ -1,34 +1,53 @@ /************************************************************************************************************************ -*This module contain main templates for user. -*There are three structure templates (mixins) which should be added on top of structure: -* - System: make system structure -* - Component: make component structure -* - Event: make event structure -* -*ex. -*Struct System1 -*{ -* mixin!ECS.System; -*} -* -*Struct System2 -*{ -* mixin!ECS.System(16);//set number of jobs generated for system by multithreaded update -*} -* -*Struct Component1 -*{ -* mixin!ECS.Component; -*} -* -*Struct Event1 -*{ -* mixin!ECS.Event; -*} -* -*There is also template for generating list of excluded components "ExcludedComponets(T...)". -*This template takes component structure types and making list of excluded components used in "registerSystem" function. -* +This module contain main templates for user. +There are three structure templates (mixins) which should be added on top of structure: +$(LIST + * System: make system structure + * Component: make component structure + * Event: make event structure +) + +--- +Struct System1 +{ + mixin!ECS.System; +} + +Struct System2 +{ + mixin!ECS.System(16);//set number of jobs generated for system by multithreaded update +} + +Struct Component1 +{ + mixin!ECS.Component; +} + +Struct Event1 +{ + mixin!ECS.Event; +} +--- + +There is also template for generating list of excluded components "ExcludedComponets(T...)". +This template takes component structure types and making list of excluded components used in "registerSystem" function. + +--- +Struct System1 +{ + mixin!ECS.System; + + struct EntitiesData + { + ... //used components + } + + ExcludedComponets!(Comp1, Comp2); +} +--- + +Copyright: Copyright © 2018-2019, Dawid Masiukiewicz, Michał Masiukiewicz +License: BSD 3-clause, see LICENSE file in project root folder. */ module ecs.core; @@ -36,12 +55,12 @@ public import ecs.manager; public import ecs.entity; /************************************************************************************************************************ -*Main struct used as namespace for templates. +Main struct used as namespace for templates. */ static struct ECS { /************************************************************************************************************************ - *Mark structure as System. Should be added on top of structure (before any data). + Mark structure as System. Should be added on top of structure (before any data). */ mixin template System(uint jobs_count = 32) { @@ -50,7 +69,7 @@ static struct ECS } /************************************************************************************************************************ - *Mark structure as Component. Should be added on top of structure (before any data). + Mark structure as Component. Should be added on top of structure (before any data). */ mixin template Component() { @@ -58,7 +77,7 @@ static struct ECS } /************************************************************************************************************************ - *Mark structure as Event. Should be added on top of structure (before any data). + Mark structure as Event. Should be added on top of structure (before any data). */ mixin template Event() { @@ -67,7 +86,7 @@ static struct ECS } /************************************************************************************************************************ - *Make list of excluded components. This template get structure types as argument. Should be added inside System structure. + Make list of excluded components. This template get structure types as argument. Should be added inside System structure. */ mixin template ExcludedComponents(T...) { diff --git a/source/ecs/entity.d b/source/ecs/entity.d index f3a8d97..0bd2dea 100644 --- a/source/ecs/entity.d +++ b/source/ecs/entity.d @@ -1,5 +1,8 @@ /************************************************************************************************************************ -*Entity module. +Entity module. + +Copyright: Copyright © 2018-2019, Dawid Masiukiewicz, Michał Masiukiewicz +License: BSD 3-clause, see LICENSE file in project root folder. */ module ecs.entity; @@ -7,7 +10,7 @@ import ecs.system; import ecs.manager; /************************************************************************************************************************ -*Entity ID structure. Used as reference to Entity. Pointer to entity should be ever used to store entity reference! +Entity ID structure. Used as reference to Entity. Pointer to entity should be ever used to store entity reference! */ struct EntityID { @@ -18,7 +21,7 @@ struct EntityID } /************************************************************************************************************************ -*Structure of Entity. It's have only ID, but have full konwlege to get to components memory (If pointer to it is proper). +Structure of Entity. It's have only ID, but have full konwlege to get to components memory (If pointer to it is proper). */ struct Entity { @@ -26,8 +29,8 @@ struct Entity EntityID id; /************************************************************************************************************************ - *Get specified component. If component doesn't exist function retun null. Pointer is valid only before next "commit()", "begin()" or "end()" - *function is called. Returned pointer shouldn't be used to store reference to entity data. + Get specified component. If component doesn't exist function retun null. Pointer is valid only before next "commit()", "begin()" or "end()" + function is called. Returned pointer shouldn't be used to store reference to entity data. */ T* getComponent(T)() const { @@ -45,13 +48,15 @@ struct Entity } /************************************************************************************************************************ -*Entity template structure. -*Entity contain whole information needed to create new entity. Allocating EntityTemplate is considered as more expensive operation -*than adding entity. Whole components memory is stored in EntityTemplate and is copyied to newly added entity. -*If you want to place several entity with small difference in data then you should take pointer to component and change it before every -*entity addition. -*There is no restriction about number of allocated templates. Single template can be used from multiple threads, but if you -*want to changes some components data before add entity (entity position for example) it's better to use multiple templates. +Entity template structure. + +Entity contain whole information needed to create new entity. Allocating EntityTemplate is considered as more expensive operation +than adding entity. Whole components memory is stored in EntityTemplate and is copyied to newly added entity. +If you want to place several entity with small difference in data then you should take pointer to component and change it before every +entity addition. + +There is no restriction about number of allocated templates. Single template can be used from multiple threads, but if you +want to changes some components data before add entity (entity position for example) it's better to use multiple templates. */ export struct EntityTemplate { @@ -61,7 +66,7 @@ export struct EntityTemplate EntityManager.EntityInfo* info; /************************************************************************************************************************ - *Get specified component. If component doesn't exist function return null. Returned pointer is valid during EntityTemplate lifetime. + Get specified component. If component doesn't exist function return null. Returned pointer is valid during EntityTemplate lifetime. */ T* getComponent(T)() nothrow @nogc { diff --git a/source/ecs/events.d b/source/ecs/events.d index 317b2f0..ac7e185 100644 --- a/source/ecs/events.d +++ b/source/ecs/events.d @@ -34,7 +34,7 @@ package struct EventManager EventData* data = &events[Ev.event_id]; EventBlock* block = data.blocks[block_id]; - //EntityManager.EventInfo* info = &gEM.events[Ev.event_id]; + //EntityManager.EventInfo* info = &manager.events[Ev.event_id]; event.entity_id = id; if(block is null) @@ -119,15 +119,15 @@ package struct EventManager void allocateData(uint threads_count) nothrow @nogc { disposeData(); - events = Mallocator.makeArray!EventData(gEM.events.length); + events = Mallocator.makeArray!EventData(manager.events.length); foreach(i,ref event;events) { event.blocks = Mallocator.makeArray!(EventBlock*)(threads_count*2); event.first_blocks = Mallocator.makeArray!(EventBlock*)(threads_count*2); - event.data_offset = EventBlock.sizeof;//gEM.events[i]. - gEM.alignNum(event.data_offset, gEM.events[i].alignment); + event.data_offset = EventBlock.sizeof;//manager.events[i]. + manager.alignNum(event.data_offset, manager.events[i].alignment); - event.max_events = cast(ushort)((events_block_size - event.data_offset) / gEM.events[i].size); + event.max_events = cast(ushort)((events_block_size - event.data_offset) / manager.events[i].size); } } diff --git a/source/ecs/id_manager.d b/source/ecs/id_manager.d index 4f5a949..1ab8465 100644 --- a/source/ecs/id_manager.d +++ b/source/ecs/id_manager.d @@ -8,12 +8,12 @@ import ecs.atomic; import core.stdc.string : memcpy; /************************************************************************************************************************ -*IDManager is responsible for assignment and removing IDs. IDs are unique throughtout a whole duration of the program. +IDManager is responsible for assignment and removing IDs. IDs are unique throughtout a whole duration of the program. */ struct IDManager { /************************************************************************************************************************ - *Get new ID. + Get new ID. */ pragma(inline, false) EntityID getNewID() nothrow @nogc { @@ -74,7 +74,7 @@ struct IDManager } /************************************************************************************************************************ - *Release ID. + Release ID. */ void releaseID(EntityID id) nothrow @nogc { @@ -91,7 +91,7 @@ struct IDManager } /************************************************************************************************************************ - *Update pointer to entity. The purpose of this function is to ensure that pointer to entity is always correct. + Update pointer to entity. The purpose of this function is to ensure that pointer to entity is always correct. */ void update(ref Entity entity) nothrow @nogc { @@ -107,7 +107,7 @@ struct IDManager } /************************************************************************************************************************ - *Returns pointer to entity. + Returns pointer to entity. */ export Entity* getEntityPointer(EntityID id) nothrow @nogc { @@ -132,7 +132,7 @@ struct IDManager } /************************************************************************************************************************ - *Check if entity with specified ID exist. + Check if entity with specified ID exist. */ export bool isExist(EntityID id) nothrow @nogc { @@ -143,7 +143,7 @@ struct IDManager } /************************************************************************************************************************ - *Initialize manager. + Initialize manager. */ void initialize() nothrow @nogc { @@ -162,7 +162,7 @@ struct IDManager } /************************************************************************************************************************ - *Free manager memory. + Free manager memory. */ void deinitialize() @trusted @nogc nothrow { @@ -185,7 +185,7 @@ struct IDManager } /************************************************************************************************************************ - *Optimize memory. Must be called if any ID was added and some ID will be removed. + Optimize memory. Must be called if any ID was added and some ID will be removed. */ void optimize() nothrow @nogc { diff --git a/source/ecs/manager.d b/source/ecs/manager.d index 5ec5b87..aca7f53 100644 --- a/source/ecs/manager.d +++ b/source/ecs/manager.d @@ -1,5 +1,8 @@ /************************************************************************************************************************ -*Most important module. Almost every function is called from EntityManager. +Most important module. Almost every function is called from EntityManager. + +Copyright: Copyright © 2018-2019, Dawid Masiukiewicz, Michał Masiukiewicz +License: BSD 3-clause, see LICENSE file in project root folder. */ module ecs.manager; @@ -28,37 +31,38 @@ export alias gEntityManager = EntityManager.instance; alias SerializeVector = ecs.vector.Vector!ubyte; /************************************************************************************************************************ -*Entity manager is responsible for everything. -* -*Entity manager can be in three states: -* - registration: time between beginRegister() and endRegister() calls. -* - update: time between being() and end() calls. -* - default: when it's not in registration or update time -* -*Manager can be only in one state simultaneously. -* -*Manager must be initialized before use. There is global instance of EntityManager: EntityManager.instance or gEM as alias. -* -*Registration process consist of registration of passes, systems, entities and events. -* -*Pass is group of system which should be used inside one update() call. Passes are added as name (string) and can be referenced by name or id.
      -*System is structure responsible for update of specified group of entities. System consist of EntitiesData structure which contain components used -*by system and some callback. Main callback is onUpdate() which is called by update() entity manager function. Other callbacks are used as listeners for -*adding entites, tracking system lifetime and events handling.
      -*Component is basicly small fraction of data which is considered to be used as whole. In best scenario every byte of component is used when it's refered to. -*In practice sometimes it's better to join data into one component even if it's can be accessed separetly.
      -*Events are structures with data used to handle events. Event can contain for exmaple one floating point number used as damage dealt to entity.
      -*Entity is group of components. In memory entity is only ID which makes it's possible to take it's components. Components are grouped into chunks, and -*grouped by component type so entity can be fracted in big memory chunk.
      -* -*There is two types of update: -*
      - update(): function used to call update pass. -*
      - updateMT(): function used to call update pass multithreaded. This call only generates jobs which must be called by user. +Entity manager is responsible for everything. + +Entity manager can be in three states: + - registration: time between beginRegister() and endRegister() calls. + - update: time between being() and end() calls. + - default: when it's not in registration or update time + +Manager can be only in one state simultaneously. + +Manager must be initialized before use. There is global instance of EntityManager: EntityManager.instance or gEM as alias. + +Registration process consist of registration of passes, systems, entities and events. + +Pass is group of system which should be used inside one update() call. Passes are added as name (string) and can be referenced by name or id. +System is structure responsible for update of specified group of entities. System consist of EntitiesData structure which contain components used +by system and some callback. Main callback is onUpdate() which is called by update() entity manager function. Other callbacks are used as listeners for +adding entites, tracking system lifetime and events handling. + +Component is basicly small fraction of data which is considered to be used as whole. In best scenario every byte of component is used when it's refered to. +In practice sometimes it's better to join data into one component even if it's can be accessed separetly. +Events are structures with data used to handle events. Event can contain for exmaple one floating point number used as damage dealt to entity. +Entity is group of components. In memory entity is only ID which makes it's possible to take it's components. Components are grouped into chunks, and +grouped by component type so entity can be fracted in big memory chunk. + +There is two types of update: + - update(): function used to call update pass. + - updateMT(): function used to call update pass multithreaded. This call only generates jobs which must be called by user. */ export struct EntityManager { /************************************************************************************************************************ - *Initialize ECS. + Initialize ECS. */ export static void initialize(uint threads_count, uint page_size = 32768, uint block_pages_count = 128) @@ -81,7 +85,7 @@ export struct EntityManager } /************************************************************************************************************************ - *Deinitialize and destroy ECS. This function release whole memory. + Deinitialize and destroy ECS. This function release whole memory. */ export static void destroy() { @@ -154,7 +158,7 @@ export struct EntityManager } /************************************************************************************************************************ - *Begin registering process. Every register function should be called between beginRegister() and endRegister(). + Begin registering process. Every register function should be called between beginRegister() and endRegister(). */ export void beginRegister() nothrow @nogc { @@ -172,7 +176,7 @@ export struct EntityManager } /************************************************************************************************************************ - *End registering process. Every register function should be called between beginRegister() and endRegister(). + End registering process. Every register function should be called between beginRegister() and endRegister(). */ export void endRegister() { @@ -346,7 +350,7 @@ export struct EntityManager } /************************************************************************************************************************ - *Same as "void registerSystem(Sys)(int priority, int pass = 0)" but use pass name instead of id. + Same as "void registerSystem(Sys)(int priority, int pass = 0)" but use pass name instead of id. */ void registerSystem(Sys)(int priority, const(char)[] pass_name) { @@ -359,13 +363,13 @@ export struct EntityManager } /************************************************************************************************************************ - *Register new System into EntityManager. This funcion generate glue between EntityManager and System. - *Systems can be registered from external dynamic library, and can be registered after adding entities too. - *System mustn't be registered before components which system want to use, in this case functions call assertion. - * - *Params: - *priority = system priority. Priority determines order of execution of systems updates - *pass = index of UpdatePass which sholud call system update + Register new System into EntityManager. This funcion generate glue between EntityManager and System. + Systems can be registered from external dynamic library, and can be registered after adding entities too. + System mustn't be registered before components which system want to use, in this case functions call assertion. + + Params: + priority = system priority. Priority determines order of execution of systems updates + pass = index of UpdatePass which sholud call system update */ void registerSystem(Sys)(int priority, ushort pass = 0) { @@ -1084,7 +1088,7 @@ export struct EntityManager } /************************************************************************************************************************ - *Return system ECS api by id + Return system ECS api by id */ export System* getSystem(ushort id) nothrow @nogc { @@ -1094,7 +1098,7 @@ export struct EntityManager } /************************************************************************************************************************ - *Return pointer to system registered in manager + Return pointer to system registered in manager */ Sys* getSystem(Sys)() nothrow @nogc { @@ -1115,7 +1119,7 @@ export struct EntityManager } /************************************************************************************************************************ - *Register component into EntityManager. + Register component into EntityManager. */ void registerComponent(Comp)() { @@ -1230,7 +1234,7 @@ export struct EntityManager } /************************************************************************************************************************ - *Same as "void update(int pass = 0)" but use pass name instead of id. + Same as "void update(int pass = 0)" but use pass name instead of id. */ export void update(const(char)[] pass_name) nothrow @nogc { @@ -1240,7 +1244,7 @@ export struct EntityManager } /************************************************************************************************************************ - *Update systems. Should be called only between begin() and end(). + Update systems. Should be called only between begin() and end(). */ export void update(ushort pass = 0) nothrow @nogc { @@ -1268,7 +1272,7 @@ export struct EntityManager } /************************************************************************************************************************ - *Same as "void updateMT(int pass = 0)" but use pass name instead of id. + Same as "void updateMT(int pass = 0)" but use pass name instead of id. */ export void updateMT(const(char)[] pass_name) nothrow @nogc { @@ -1431,7 +1435,7 @@ export struct EntityManager }*/ /************************************************************************************************************************ - *Return size of single page (block). Every entity data block has size of page. + Return size of single page (block). Every entity data block has size of page. */ uint pageSize() { @@ -1439,8 +1443,8 @@ export struct EntityManager } /************************************************************************************************************************ - *Return number of pages in single block allocation. Library allocate defined number of pages at once and assign it's - *for entities. + Return number of pages in single block allocation. Library allocate defined number of pages at once and assign it's + for entities. */ uint pagesInBlock() { @@ -1465,11 +1469,11 @@ export struct EntityManager } /************************************************************************************************************************ - *Allocate EntityTemplate with all components from entity witch it's data and returns pointer to it. - * - *Params: - *entity_id = ID of entity from which should be created template - *fill_default = if true, components will be filled with default data, instead entity data will be taken + Allocate EntityTemplate with all components from entity witch it's data and returns pointer to it. + + Params: + entity_id = ID of entity from which should be created template + fill_default = if true, components will be filled with default data, instead entity data will be taken */ export EntityTemplate* allocateTemplate(EntityID entity_id, bool fill_default = false) { @@ -1505,10 +1509,10 @@ export struct EntityManager } /************************************************************************************************************************ - *Allocate EntityTemplate with specifed components and returns pointer to it. - * - *Params: - *components_ids = array of components allocated with template + Allocate EntityTemplate with specifed components and returns pointer to it. + + Params: + components_ids = array of components allocated with template */ export EntityTemplate* allocateTemplate(ushort[] components_ids) { @@ -1551,10 +1555,13 @@ export struct EntityManager } /************************************************************************************************************************ - *Allocate EntityTemplate with specifed components and returns pointer to it. - * - *Params: - *components_ids = array of components allocated with template + Allocate EntityTemplate from basic Template with modifications by adding and removing some components and returns pointer to it. + Arrays of components needen't to be checked for repeated components, as function itself check if components exist in base template. + + Params: + base_tmpl = template from which components sould be copied + components_ids = array of new components to add + remove_components_ids = array of components to remove from base template */ export EntityTemplate* allocateTemplate(EntityTemplate* base_tmpl, ushort[] components_ids, ushort[] remove_components_ids = null) @@ -1624,10 +1631,10 @@ export struct EntityManager } /************************************************************************************************************************ - *Returns entity type info. - * - *Params: - *ids = array of components + Returns entity type info. + + Params: + ids = array of components */ export EntityInfo* getEntityInfo(ushort[] ids) { @@ -1930,10 +1937,10 @@ export struct EntityManager } /************************************************************************************************************************ - *Returns pointer to entity. - * - *Params: - *id = ID of entity + Returns pointer to entity. + + Params: + id = ID of entity */ export Entity* getEntity(EntityID id) nothrow @nogc { @@ -1941,11 +1948,11 @@ export struct EntityManager } /************************************************************************************************************************ - *Remove components from entity by IDs. Components will be removed on end of frame. - * - *Params: - *entity_id = ID of entity - *del_ids = array of components IDs + Remove components from entity by IDs. Components will be removed on end of frame. + + Params: + entity_id = ID of entity + del_ids = array of components IDs */ export void removeComponents(EntityID entity_id, ushort[] del_ids) nothrow @nogc { @@ -2051,11 +2058,11 @@ export struct EntityManager } /************************************************************************************************************************ - *Remove coponents from entity. - * - *Params: - *Components = components types to remove - *entity_id = ID of entity + Remove coponents from entity. + + Params: + Components = components types to remove + entity_id = ID of entity */ void removeComponents(Components...)(EntityID entity_id) { @@ -2204,11 +2211,11 @@ export struct EntityManager } /************************************************************************************************************************ - *Add components to entity. Components will be added on end of frame. - * - *Params: - *entity_id = ID of entity to remove - *comps = components to add + Add components to entity. Components will be added on end of frame. + + Params: + entity_id = ID of entity to remove + comps = components to add */ void addComponents(Components...)(const EntityID entity_id, Components comps) nothrow @nogc { @@ -2239,10 +2246,10 @@ export struct EntityManager } /************************************************************************************************************************ - *Free template memory. - * - *Params: - *template_ = pointer entity template allocated by EntityManager. + Free template memory. + + Params: + template_ = pointer entity template allocated by EntityManager. */ export void freeTemplate(EntityTemplate* template_) { @@ -2251,9 +2258,9 @@ export struct EntityManager } /************************************************************************************************************************ - *Add copy of entity to system and returns pointer to it. Added copy has same data as copied entity. Returen pointer is - *valid only before one from commit(), begin() or end() will be called. To save entity to further use you should save ID - *instead of pointer. + Add copy of entity to system and returns pointer to it. Added copy has same data as copied entity. Returen pointer is + valid only before one from commit(), begin() or end() will be called. To save entity to further use you should save ID + instead of pointer. * *Params: *id = ID of entity to be copyied. @@ -2305,11 +2312,11 @@ export struct EntityManager } /************************************************************************************************************************ - *Add entity to system. Returen pointer is valid only before one from commit(), begin() or end() will be called. To save entity to further - *use you should save ID instead of pointer. - * - *Params: - *tmpl = pointer entity template allocated by EntityManager. + Add entity to system. Returen pointer is valid only before one from commit(), begin() or end() will be called. To save entity to further + use you should save ID instead of pointer. + + Params: + tmpl = pointer entity template allocated by EntityManager. */ export Entity* addEntity(EntityTemplate* tmpl) { @@ -2355,7 +2362,7 @@ export struct EntityManager } /************************************************************************************************************************ - *Return block with free space for selected EntityInfo. + Return block with free space for selected EntityInfo. */ private EntitiesBlock* findBlockWithFreeSpace(EntityInfo* info) nothrow @nogc { @@ -2383,7 +2390,7 @@ export struct EntityManager } /************************************************************************************************************************ - *Return block with free space for selected EntityInfo. Additional this function is multithread safe. + Return block with free space for selected EntityInfo. Additional this function is multithread safe. */ private EntitiesBlock* findBlockWithFreeSpaceMT(EntityInfo* info) { @@ -2427,10 +2434,10 @@ export struct EntityManager } /************************************************************************************************************************ - *Remove entity by ID. Entity will be removed on frame end. - * - *Params: - *id = id of entity to remove + Remove entity by ID. Entity will be removed on frame end. + + Params: + id = id of entity to remove */ export void removeEntity(EntityID id) { @@ -2513,10 +2520,10 @@ export struct EntityManager } /************************************************************************************************************************ - *functions return MetaData of page. - * - *Params: - *pointer = pointer to any data of entity (i.e. component data pointer) + functions return MetaData of page. + + Params: + pointer = pointer to any data of entity (i.e. component data pointer) */ export EntitiesBlock* getMetaData(const void* pointer) nothrow @nogc { @@ -2750,7 +2757,7 @@ export struct EntityManager } /************************************************************************************************************************ - *Begin of update process. Should be called before any update is called. + Begin of update process. Should be called before any update is called. */ export void begin() { @@ -2767,7 +2774,7 @@ export struct EntityManager } /************************************************************************************************************************ - *End of update process. Should be called after every update function. + End of update process. Should be called after every update function. */ export void end() { @@ -2917,7 +2924,7 @@ export struct EntityManager } /************************************************************************************************************************ - *Component info; + Component info; */ struct ComponentInfo { @@ -2961,7 +2968,7 @@ export struct EntityManager } /************************************************************************************************************************ - *Entity type info. + Entity type info. */ struct EntityInfo { @@ -3133,7 +3140,7 @@ export struct EntityManager } /************************************************************************************************************************ - *Meta data of every block of entities (contained at the begining of block). + Meta data of every block of entities (contained at the begining of block). */ struct EntitiesBlock { @@ -3180,10 +3187,10 @@ export struct EntityManager } /************************************************************************************************************************ - *Structure with data used to calling System calls. - * - *first_block, begin, end, blocks parameters are used - *to call partial info update + Structure with data used to calling System calls. + + first_block, begin, end, blocks parameters are used + to call partial info update */ struct CallData { diff --git a/source/ecs/std.d b/source/ecs/std.d index 6077ede..c027fd5 100644 --- a/source/ecs/std.d +++ b/source/ecs/std.d @@ -1,6 +1,9 @@ /************************************************************************************************************************ -*It's internal code! -*This module contain implementation of standard functionality. +It's internal code! +This module contain implementation of standard functionality. + +Copyright: Copyright © 2018-2019, Dawid Masiukiewicz, Michał Masiukiewicz +License: BSD 3-clause, see LICENSE file in project root folder. */ module ecs.std; diff --git a/source/ecs/system.d b/source/ecs/system.d index 35eb996..22a3955 100644 --- a/source/ecs/system.d +++ b/source/ecs/system.d @@ -1,5 +1,8 @@ /************************************************************************************************************************ -*System module. +System module. + +Copyright: Copyright © 2018-2019, Dawid Masiukiewicz, Michał Masiukiewicz +License: BSD 3-clause, see LICENSE file in project root folder. */ module ecs.system; @@ -7,25 +10,27 @@ import ecs.entity; import ecs.manager; /************************************************************************************************************************ -*System contain data required to proper glue EntityManager with Systems. -*System callbacks: -*
      -void onUpdate(EntitesData); -*
      -void onEnable() -*
      -void onDisable(); -*
      -bool onBegin(); -*
      -void onEnd(); -*
      -void onCreate() -*
      -void onDestroy(); -*
      -void onAddEntity(EntitesData); -*
      -void onRemoveEntity(EntitiesData); -*
      -void onChangeEntity(EntitiesData); -*
      -void handleEvent(Entity*, Event); +System contain data required to proper glue EntityManager with Systems. +System callbacks: +$(LIST + * void onUpdate(EntitesData); + * void onEnable() + * void onDisable(); + * bool onBegin(); + * void onEnd(); + * void onCreate() + * void onDestroy(); + * void onAddEntity(EntitesData); + * void onRemoveEntity(EntitiesData); + * void onChangeEntity(EntitiesData); + * void handleEvent(Entity*, Event); +) */ struct System { /************************************************************************************************************************ - *Check if system is enabled. + Check if system is enabled. */ export bool enabled() nothrow @nogc { @@ -33,7 +38,7 @@ struct System } /************************************************************************************************************************ - *Enable system. If actually it is enabled function do nothing. + Enable system. If actually it is enabled function do nothing. */ export void enable() nothrow @nogc { @@ -43,7 +48,7 @@ struct System } /************************************************************************************************************************ - *Disable system. If actually it is disabled function do nothing. + Disable system. If actually it is disabled function do nothing. */ export void disable() nothrow @nogc { @@ -53,7 +58,7 @@ struct System } /************************************************************************************************************************ - *Get system priority. + Get system priority. */ export int priority() nothrow @nogc { @@ -61,7 +66,7 @@ struct System } /************************************************************************************************************************ - *Get system priority. + Get system priority. */ export bool execute() nothrow @nogc { @@ -69,7 +74,7 @@ struct System } /************************************************************************************************************************ - *Get system priority. + Get system priority. */ export ushort id() nothrow @nogc { @@ -77,7 +82,7 @@ struct System } /************************************************************************************************************************ - *Get system name. + Get system name. */ export const(char)[] name() nothrow @nogc { diff --git a/source/ecs/traits.d b/source/ecs/traits.d index b270b06..d19259f 100644 --- a/source/ecs/traits.d +++ b/source/ecs/traits.d @@ -15,7 +15,7 @@ unittest } /************************************************************************************************************************ -* Returns index of Component/Entity array in System's EntitiesData struct + Returns index of Component/Entity array in System's EntitiesData struct */ static long getIndexOfTypeInEntitiesData(EntitiesData, Type)() { From 7bc07666d010ef9cfe7d66a8ca10fbf7362f3a28 Mon Sep 17 00:00:00 2001 From: Dawid Masiukiewicz Date: Sat, 2 May 2020 21:11:22 +0000 Subject: [PATCH 116/217] Initial release README.md --- README.md | 179 +++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 177 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index d3f6816..abc9709 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,180 @@ -# Dynamic Entity Component System +# Bubel Entity Component System [![pipeline status](https://gitlab.com/Mergul/bubel-ecs/badges/master/pipeline.svg)](https://gitlab.com/Mergul/bubel-ecs/-/commits/master) [![codecov](https://codecov.io/gl/Mergul/bubel-ecs/branch/master/graph/badge.svg?token=Unm0TJhFoW)](https://codecov.io/gl/Mergul/bubel-ecs) -Entity-Component-System implementation in D language. +BubelECS is Entity-Component-System architecture implementation in D language. +Library aims to delivery fast and flexible architecture for developing games. Library is @nogc and betterC compatible. Even Emscripten build works very well. +Important goal is to keep code without any external dependencies, i. eg. multithreading support don't contain any parallel execution +but emit jobs with delegate and array of dependencies. + +BubelECS was tested on Linux, Windows, Android and WASM. + +**Currently library is in beta stage so some significant API changes can appear.** + +## Design + +For core information about Entity-Component-System architectural pattern I recommend to read definition described at [Wikipedia](https://en.wikipedia.org/wiki/Entity_component_system). + +Main design principles are: + + * **Data oriented design** - components memory is packed into tight block so iterating over entity components is cache friendly + * **Fast and safe EntityID** - every entity is referenced by its unique ID. If entity was destroyed EntityManager will return null pointer for given EntityID. Access to entity from ID is linear operation. + * **Multithreading support** - whole library was developed with multithreading in mind. Adding components is thread-friendly so you get usable EntityID as early as possible. Operations like adding or removing components are deferred to end of frame. Dependencies between systems update are generated automatically. + * **Good logic separation** - system needs information only about components which it's use, there is no relation between systems. Systems can be compiled as multiple separate libraries and used together. + * **Easy systems ordering** - systems are ordered by single priority value. Order of execution of systems with same priority is undefined but order for different priorites are always preserved. + * **Flexible entity to system assignment** - system iterate over any entity that has chosen components. Components can be marked as optional so isn't required but can be used by system. Additionaly system can contain list of components which makes entity excluded from calculation. + * **Builtin events handling** - along with EntityManager library contain EventsManager which makes easier to communicate between multiple entities. + * **Hot-reload** - hot-reloading for systems should be as easy as possible. **Currently not achived yet (WIP!)**. + +Currently library is incredibly fast to iterate over entities and fast enought in direct access to entity component if it's needed. \ +There are some assumptions that should be considered when developing application: + + * Iterating over same components is incredibly fast so it's should be main way of making calculations. + * Using of direct access and events should be used very wisely and not too much. + * Direct component access is faster than events, because events must buffer memory and call multiple system handler callbacks. + * Components can be used to marking entities, assingment to systems and changing logic of entity in runtime. But due to memory fragmentation there sould by many of entities with same type. In other words, sometimes making to many components can lead to performence drop even if adding or removing components is fast enough. + * Systems give great opporunity to separate game logic. Systems can be enabled and disabled easly in runtime. It's can be used to enabling some debug systems if needed. Additionaly this concept makes game logic changes easier to deal with. If you develop your appliactiona wisely it should be trivial to change some core logic by changing only one system, or adding new system. Every entity can easily takes some behaviour from different entity type by adding several components. + +### Features + + * ECS architectural pattern + * Data oriented design + * Safe identifiers (EntityID) + * EntityTemplates - used to add entities, contain list of components and it's data + * Basic events handling + * Easy systems ordering + * Automatic multithreaded jobs generating + * Runtime and fast components adding and removing + * Listeners for adding and removing entity components inside systems + * Passes - systems are grouped to passes. Pass update call update callback of assigned systems. + * Calling custom callbacks for system entity groups + * betterC compatibility + * Emscripten compatibility + +### Planned + + * Worlds - every world works as separate environment. Entities don't with entities from different world. Systems and components should be registered for every world separately. + * Hot-reload support - currently only reloading systems (their functions) works and only if code changes apperas only inside functions. There is possibility to serialize every entity and system, but it's should be provided by library itself with special callbacks and helpers. Additionaly planned is system which helps with taking new EntityID from serialized identifiers. + * External dependencies - ability to provide dependencies between system which isn't related to components. + * Static components - this components will have different memory model and can be accessed only directly. It will be slower with access but don't trigger memory copy when component is added or some different entity was destroyed. It should fix problem with big components which isn't needed by systems iteration callbacks or is required rarely. + * Better EventManager - currently implementy event handling system isn't it what I wanted. I'm not sure exacly what I can improve but multithreaded event execution is one of things which I considered and it probably will work. + * More demos and examples - demo appliaction is very basic now, but in future I planned more minigames and sanbox mode (opportunity to mix many components and systems). I planed some examples to show how to use basic functionality. + * C API - this is currenly in consideration. Everything is dependent on my free time and amount of work required to create good C API. + * More smaller improvement in draft stage... + +For more information about design and usage I recommend to read [documentation](https://mergul.gitlab.io/bubel-ecs/ecs.html)**(WIP)**. + +## Build Instructions + +To build library you needs recent D compiler and optionally Emscripten (with python) to build web version. Currenlty tested are: LDC, DMD and GDC. \ +Supported build systems are DUB and Meson. + +##### DUB +```shell +#available configurations: library, dynlib, library-betterC, dynlib-betterC +dub build -c library -b release +``` + +##### Meson +```shell +#use '-DbetterC=true ' to build betterC code +meson build . #add '--buildtype=release' to build release code +cd build +ninja +``` + +##### Emscripten +```shell +python compile_wasm.py -opt +``` + +For more detailed build options please check documentation for used build system. + +## Demos + +Repository contain demo application. You can check demo [online](https://mergul.gitlab.io/bubel-ecs/ecs_demo.html) or build it form source code using DUB. \ +Online demo support multithreading and page tries to check if client support WASM multithreading or not and loads properly JS and WASM code. It was tested on Chrome, Firefox, Opera, Brave on Linux and Android. On firefox there is problem with multithreaded version so if demo don't works please try to disable shared_memory in browser flags. + +## Code example + +```d + +struct Position +{ + mixin ECS.Components; //makes struct component + float x; + float y; +} + +struct Velocity +{ + mixin ECS.Components; + //default values works + float x = 0.1; + float y = 1; +} + +struct StaticFlag +{ + mixin ECS.Components; +} + +struct UpdateSystem +{ + mixin ECS.System; //makes struct system + + ECS.ExcludedComponents!(StaticFlag); //prevents static entities from update + + struct EntitiesData + { + int length; //entities count + @readonly Entity[] entities; //entities arrays, entity contain ID only + Position[] positions; //positions array + @readonly Velocity[] velocities; //veocities array, readonly (Multithreading tag) + } + + void onUpdate(EntitiesData data) //update callback, called multiple times per frame for every entities types + { + foreach(i; 0..data.length) //iterate over entities + { + data.positions[i].x += data.velocities[i].x * dt; + data.positions[i].y += data.velocities[i].y * dt; + } + } +} + +void main() +{ + manager.beginRegister(); + //register components + manager.registerComponent!Position; + manager.registerComponent!Velocity; + manager.registerComponent!StaticFlag; + //register system with priority 0 + manager.registerSystem!UpdateSystem(0); + manager.endRegister(); + + //allocate template + EntityTemplate* tmpl = manager.allocateEmplate([Velocity.component_id, Position.component_id].staticArray); + scope (exit) manager.freeTemplate(tmpl); + + //gets pointer to template component data + Position* position = tmpl.getComponent!Position; + foreach(i; 0 .. 100) + { + position.x = i % 10; + position.y = i / 10; + manager.addEntity(tmpl); + } + + manager.begin(); //start frame + manager.update(); //update all systems, there onUpdate callbacks are called + manager.end(); //end frame +} + +``` + +## Links + +Documentation: https://mergul.gitlab.io/bubel-ecs/ecs.html \ +Online demo: https://mergul.gitlab.io/bubel-ecs/ecs_demo.html From 109775af871e05f8f7c814e380a900d341c44f20 Mon Sep 17 00:00:00 2001 From: Dawid Masiukiewicz Date: Mon, 4 May 2020 10:33:54 +0000 Subject: [PATCH 117/217] Update README.md --- README.md | 48 +++++++++++++++++++++++------------------------- 1 file changed, 23 insertions(+), 25 deletions(-) diff --git a/README.md b/README.md index abc9709..400b0a1 100644 --- a/README.md +++ b/README.md @@ -2,10 +2,9 @@ [![pipeline status](https://gitlab.com/Mergul/bubel-ecs/badges/master/pipeline.svg)](https://gitlab.com/Mergul/bubel-ecs/-/commits/master) [![codecov](https://codecov.io/gl/Mergul/bubel-ecs/branch/master/graph/badge.svg?token=Unm0TJhFoW)](https://codecov.io/gl/Mergul/bubel-ecs) -BubelECS is Entity-Component-System architecture implementation in D language. -Library aims to delivery fast and flexible architecture for developing games. Library is @nogc and betterC compatible. Even Emscripten build works very well. -Important goal is to keep code without any external dependencies, i. eg. multithreading support don't contain any parallel execution -but emit jobs with delegate and array of dependencies. +BubelECS is Entity-Component-System architectural pattern implementation in D language. +Library aims to delivery fast and flexible architecture for developing games. Library is **@nogc** and **betterC** compatible. WASM is supported thorugh Emscripten. +Project haven't any external dependencies. BubelECS was tested on Linux, Windows, Android and WASM. @@ -13,40 +12,38 @@ BubelECS was tested on Linux, Windows, Android and WASM. ## Design -For core information about Entity-Component-System architectural pattern I recommend to read definition described at [Wikipedia](https://en.wikipedia.org/wiki/Entity_component_system). +For core information about Entity-Component-System architectural pattern please read definition described at [Wikipedia](https://en.wikipedia.org/wiki/Entity_component_system). Main design principles are: * **Data oriented design** - components memory is packed into tight block so iterating over entity components is cache friendly - * **Fast and safe EntityID** - every entity is referenced by its unique ID. If entity was destroyed EntityManager will return null pointer for given EntityID. Access to entity from ID is linear operation. - * **Multithreading support** - whole library was developed with multithreading in mind. Adding components is thread-friendly so you get usable EntityID as early as possible. Operations like adding or removing components are deferred to end of frame. Dependencies between systems update are generated automatically. + * **Fast and safe EntityID** - every entity is referenced by its unique ID. Accessing by ID is safe even if entity don'y exist. Access by ID is constant time operation. + * **Multithreading support** - whole library was developed with multithreading in mind. Adding components is thread-friendly so you get usable EntityID as early as possible. Operations like adding or removing components are deferred to end of frame. Dependencies between systems parallel execution are generated automatically. * **Good logic separation** - system needs information only about components which it's use, there is no relation between systems. Systems can be compiled as multiple separate libraries and used together. - * **Easy systems ordering** - systems are ordered by single priority value. Order of execution of systems with same priority is undefined but order for different priorites are always preserved. - * **Flexible entity to system assignment** - system iterate over any entity that has chosen components. Components can be marked as optional so isn't required but can be used by system. Additionaly system can contain list of components which makes entity excluded from calculation. - * **Builtin events handling** - along with EntityManager library contain EventsManager which makes easier to communicate between multiple entities. - * **Hot-reload** - hot-reloading for systems should be as easy as possible. **Currently not achived yet (WIP!)**. + * **Flexible execution model** - system iterate over entities which meet specified conditions. Components can be marked as required, optional or excluded. Systems are exectued in specific order determined by system priority. + * **Builtin events handling** - library has builtin support for event handlig to makes easier communication between different entities. + * **Hot-reload** - hot-reloading for systems should be as easy as possible. In other words library should give functionality to support hot-reload of systems and components with minimal work. **(WIP!)**. -Currently library is incredibly fast to iterate over entities and fast enought in direct access to entity component if it's needed. \ There are some assumptions that should be considered when developing application: - * Iterating over same components is incredibly fast so it's should be main way of making calculations. - * Using of direct access and events should be used very wisely and not too much. + * Iterating over components is fastest way of access data so it's should be main way of making calculations. + * Using of direct access and events should be used very wisely and minimized. * Direct component access is faster than events, because events must buffer memory and call multiple system handler callbacks. - * Components can be used to marking entities, assingment to systems and changing logic of entity in runtime. But due to memory fragmentation there sould by many of entities with same type. In other words, sometimes making to many components can lead to performence drop even if adding or removing components is fast enough. - * Systems give great opporunity to separate game logic. Systems can be enabled and disabled easly in runtime. It's can be used to enabling some debug systems if needed. Additionaly this concept makes game logic changes easier to deal with. If you develop your appliactiona wisely it should be trivial to change some core logic by changing only one system, or adding new system. Every entity can easily takes some behaviour from different entity type by adding several components. + * Components can be used to marking entities, assingment to systems and changing logic of entity in runtime. Using too much component based marking can lead to memory fragmentation and performence drop. + * Systems give great opporunity to separate game logic. Systems can be enabled and disabled easly in runtime. It's can be used to enabling some debug systems if needed. Additionaly this concept makes game logic changes easier to deal with. If you develop your application wisely it should be trivial to change some core logic by changing only several systems or adding some new systems. Every entity can easily takes some behaviour from different entity type by adding several components. ### Features * ECS architectural pattern * Data oriented design * Safe identifiers (EntityID) - * EntityTemplates - used to add entities, contain list of components and it's data + * EntityTemplates * Basic events handling * Easy systems ordering * Automatic multithreaded jobs generating * Runtime and fast components adding and removing * Listeners for adding and removing entity components inside systems - * Passes - systems are grouped to passes. Pass update call update callback of assigned systems. + * Update passes * Calling custom callbacks for system entity groups * betterC compatibility * Emscripten compatibility @@ -54,15 +51,16 @@ There are some assumptions that should be considered when developing application ### Planned * Worlds - every world works as separate environment. Entities don't with entities from different world. Systems and components should be registered for every world separately. - * Hot-reload support - currently only reloading systems (their functions) works and only if code changes apperas only inside functions. There is possibility to serialize every entity and system, but it's should be provided by library itself with special callbacks and helpers. Additionaly planned is system which helps with taking new EntityID from serialized identifiers. + * Hot-reload support - currently only reloading systems (their functions) works. There is possibility to serialize every entity and system, but it's should be provided by library itself with special callbacks and helpers. Additionaly planned is system which helps with taking new EntityID from serialized identifiers. * External dependencies - ability to provide dependencies between system which isn't related to components. - * Static components - this components will have different memory model and can be accessed only directly. It will be slower with access but don't trigger memory copy when component is added or some different entity was destroyed. It should fix problem with big components which isn't needed by systems iteration callbacks or is required rarely. - * Better EventManager - currently implementy event handling system isn't it what I wanted. I'm not sure exacly what I can improve but multithreaded event execution is one of things which I considered and it probably will work. - * More demos and examples - demo appliaction is very basic now, but in future I planned more minigames and sanbox mode (opportunity to mix many components and systems). I planed some examples to show how to use basic functionality. - * C API - this is currenly in consideration. Everything is dependent on my free time and amount of work required to create good C API. - * More smaller improvement in draft stage... + * Static components - this components will have different memory model and can be accessed only directly. It will be slower to access but won't trigger memory copy when component is added. It should fix problem with big components which isn't needed by systems iteration callbacks or is required rarely. + * Better EventManager - there are several optimization and improvements that can be added in the future. + * More demos and examples - demo appliaction is very basic now, but in future more minigames and sanbox mode (opportunity to mix many components and systems) are planned. + * C API - in highly depends on amount of work required. Makes possible to use library from different languages. + * GPU compute - idea in draft stage. Special components and systems whose data wolud be on GPU memory. + * More smaller improvements... -For more information about design and usage I recommend to read [documentation](https://mergul.gitlab.io/bubel-ecs/ecs.html)**(WIP)**. +For more information about design and usage feel free to read [documentation](https://mergul.gitlab.io/bubel-ecs/ecs.html)**(WIP)** and [WIKI](https://gitlab.com/Mergul/bubel-ecs/-/wikis/home). ## Build Instructions From 167ad5437ab6b5e49ab14ea33ef8ab3a064a05d3 Mon Sep 17 00:00:00 2001 From: Mergul Date: Mon, 4 May 2020 16:17:40 +0200 Subject: [PATCH 118/217] CI changes --- .gitlab-ci.yml | 32 ++++++++++++++++++++------------ 1 file changed, 20 insertions(+), 12 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 14ba23c..1710e4a 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -9,25 +9,18 @@ build_code: stage: build image: "registry.gitlab.com/mergul/bubel-ecs:latest" script: - - mkdir build - /bin/bash /compile_ecs.sh - - cp artifacts/* build/ - - cp -r public build/ artifacts: expire_in: 1h paths: - - build - rules: - - if: '$CI_MERGE_REQUEST_TARGET_BRANCH_NAME == "master"' - when: always - - when: always + - binaries allow_failure: true test_dmd_debug: stage: test image: frolvlad/alpine-glibc script: - - build/dmd_debug_unittest + - binaries/dmd_debug_unittest artifacts: reports: junit: test_report.xml @@ -35,7 +28,7 @@ test_dmd: stage: test image: frolvlad/alpine-glibc script: - - build/dmd_release_unittest + - binaries/dmd_release_unittest artifacts: reports: junit: test_report.xml @@ -43,7 +36,7 @@ test_dmd_betterC: stage: test image: frolvlad/alpine-glibc script: - - build/dmd_release_unittest_bc + - binaries/dmd_release_unittest_bc artifacts: reports: junit: test_report.xml @@ -56,10 +49,25 @@ coverage_test_dmd: - build_code script: - mkdir reports - - build/dmd_unittest_cov + - binaries/dmd_unittest_cov after_script: - bash <(curl -s https://codecov.io/bash) -s reports -t 1a0c0169-a721-4085-8252-fed4755dcd8c +build_wasm: + stage: build + image: "registry.gitlab.com/mergul/bubel-ecs:latest" + script: + - /bin/bash /compile_wasm.sh + - /bin/bash /gen_doc.sh + artifacts: + expire_in: 1h + paths: + - build + rules: + - if: '$CI_MERGE_REQUEST_TARGET_BRANCH_NAME == "master"' + when: always + allow_failure: true + emscripten: stage: build_emscripten image: "registry.gitlab.com/mergul/bubel-ecs/emscripten:latest" From 5411e97cb1b65a0f4dac8544b83ec5e1147f8c5a Mon Sep 17 00:00:00 2001 From: Mergul Date: Tue, 5 May 2020 16:56:51 +0200 Subject: [PATCH 119/217] Move ECS to Bubel module --- .gitlab-ci.yml | 4 +++ README.md | 5 ++++ demos/external/sources/mmutils/thread_pool.d | 4 +-- demos/source/app.d | 6 ++-- demos/source/demos/bullet_madnes.d | 10 +++---- demos/source/demos/chipmunk2d.d | 10 +++---- demos/source/demos/events.d | 10 +++---- demos/source/demos/flag_component.d | 10 +++---- demos/source/demos/physics.d | 10 +++---- demos/source/demos/simple.d | 10 +++---- demos/source/demos/snake.d | 12 ++++---- demos/source/demos/space_invaders.d | 10 +++---- demos/source/game_core/job_updater.d | 8 +++--- demos/source/gui/manager.d | 8 +++--- demos/source/gui/system.d | 2 +- demos/source/gui/template_.d | 2 +- demos/utils/source/ecs_utils/gfx/buffer.d | 2 +- demos/utils/source/ecs_utils/gfx/config.d | 4 +-- demos/utils/source/ecs_utils/gfx/material.d | 2 +- demos/utils/source/ecs_utils/gfx/mesh.d | 2 +- demos/utils/source/ecs_utils/gfx/renderer.d | 2 +- demos/utils/source/ecs_utils/gfx/shader.d | 2 +- demos/utils/source/ecs_utils/gfx/texture.d | 2 +- demos/utils/source/ecs_utils/gfx/vertex.d | 2 +- meson.build | 30 ++++++++++---------- source/{ => bubel}/ecs/atomic.d | 2 +- source/{ => bubel}/ecs/attributes.d | 2 +- source/{ => bubel}/ecs/block_allocator.d | 6 ++-- source/{ => bubel}/ecs/core.d | 6 ++-- source/{ => bubel}/ecs/entity.d | 6 ++-- source/{ => bubel}/ecs/events.d | 10 +++---- source/{ => bubel}/ecs/hash_map.d | 6 ++-- source/{ => bubel}/ecs/id_manager.d | 10 +++---- source/{ => bubel}/ecs/manager.d | 26 ++++++++--------- source/bubel/ecs/package.d | 10 +++++++ source/{ => bubel}/ecs/simple_vector.d | 4 +-- source/{ => bubel}/ecs/std.d | 2 +- source/{ => bubel}/ecs/system.d | 6 ++-- source/{ => bubel}/ecs/traits.d | 2 +- source/{ => bubel}/ecs/vector.d | 4 +-- source/ecs/package.d | 10 ------- tests/basic.d | 8 +++--- tests/id_manager.d | 4 +-- tests/runner.d | 6 ++-- tests/tests.d | 14 ++++----- tests/vector.d | 4 +-- 46 files changed, 163 insertions(+), 154 deletions(-) rename source/{ => bubel}/ecs/atomic.d (99%) rename source/{ => bubel}/ecs/attributes.d (97%) rename source/{ => bubel}/ecs/block_allocator.d (97%) rename source/{ => bubel}/ecs/core.d (96%) rename source/{ => bubel}/ecs/entity.d (97%) rename source/{ => bubel}/ecs/events.d (97%) rename source/{ => bubel}/ecs/hash_map.d (98%) rename source/{ => bubel}/ecs/id_manager.d (98%) rename source/{ => bubel}/ecs/manager.d (99%) create mode 100644 source/bubel/ecs/package.d rename source/{ => bubel}/ecs/simple_vector.d (95%) rename source/{ => bubel}/ecs/std.d (99%) rename source/{ => bubel}/ecs/system.d (98%) rename source/{ => bubel}/ecs/traits.d (97%) rename source/{ => bubel}/ecs/vector.d (99%) delete mode 100644 source/ecs/package.d diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 1710e4a..a2d26ff 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,3 +1,7 @@ +default: + artifacts: + expire_in: 1 day + stages: - build - test diff --git a/README.md b/README.md index 400b0a1..b223f72 100644 --- a/README.md +++ b/README.md @@ -86,6 +86,11 @@ ninja python compile_wasm.py -opt ``` +##### Documentation +```shell +adrdox -i source/bubel/ecs/ -o docs/ -s skeleton.html +``` + For more detailed build options please check documentation for used build system. ## Demos diff --git a/demos/external/sources/mmutils/thread_pool.d b/demos/external/sources/mmutils/thread_pool.d index 374fbc1..161eb22 100644 --- a/demos/external/sources/mmutils/thread_pool.d +++ b/demos/external/sources/mmutils/thread_pool.d @@ -1,6 +1,6 @@ module mmutils.thread_pool; -import ecs.atomic; +import bubel.ecs.atomic; //import core.stdc.stdio; //import core.stdc.stdlib : free, malloc, realloc; @@ -32,7 +32,7 @@ else version (D_BetterC) { - import ecs.std; + import bubel.ecs.std; extern (C) __gshared int _d_eh_personality(int, int, size_t, void*, void*) { return 0; diff --git a/demos/source/app.d b/demos/source/app.d index 150d653..acdc385 100644 --- a/demos/source/app.d +++ b/demos/source/app.d @@ -6,9 +6,9 @@ import cimgui.cimgui; import game_core.job_updater; -import ecs.manager; -import ecs.core; -import ecs.std; +import bubel.ecs.manager; +import bubel.ecs.core; +import bubel.ecs.std; import ecs_utils.gfx.renderer; import ecs_utils.imgui_bind; diff --git a/demos/source/demos/bullet_madnes.d b/demos/source/demos/bullet_madnes.d index 0996e2e..420d6a3 100644 --- a/demos/source/demos/bullet_madnes.d +++ b/demos/source/demos/bullet_madnes.d @@ -6,11 +6,11 @@ import bindbc.sdl; import cimgui.cimgui; -import ecs.attributes; -import ecs.core; -import ecs.entity; -import ecs.manager; -import ecs.std; +import bubel.ecs.attributes; +import bubel.ecs.core; +import bubel.ecs.entity; +import bubel.ecs.manager; +import bubel.ecs.std; import ecs_utils.gfx.texture; import ecs_utils.math.vector; diff --git a/demos/source/demos/chipmunk2d.d b/demos/source/demos/chipmunk2d.d index 25b9c66..96e5fa6 100644 --- a/demos/source/demos/chipmunk2d.d +++ b/demos/source/demos/chipmunk2d.d @@ -6,11 +6,11 @@ import bindbc.sdl; import cimgui.cimgui; -import ecs.attributes; -import ecs.core; -import ecs.entity; -import ecs.manager; -import ecs.std; +import bubel.ecs.attributes; +import bubel.ecs.core; +import bubel.ecs.entity; +import bubel.ecs.manager; +import bubel.ecs.std; import ecs_utils.gfx.texture; import ecs_utils.math.vector; diff --git a/demos/source/demos/events.d b/demos/source/demos/events.d index 620ff4d..6215160 100644 --- a/demos/source/demos/events.d +++ b/demos/source/demos/events.d @@ -6,11 +6,11 @@ import bindbc.sdl; import cimgui.cimgui; -import ecs.attributes; -import ecs.core; -import ecs.entity; -import ecs.manager; -import ecs.std; +import bubel.ecs.attributes; +import bubel.ecs.core; +import bubel.ecs.entity; +import bubel.ecs.manager; +import bubel.ecs.std; import ecs_utils.gfx.texture; import ecs_utils.math.vector; diff --git a/demos/source/demos/flag_component.d b/demos/source/demos/flag_component.d index a1863b9..392164e 100644 --- a/demos/source/demos/flag_component.d +++ b/demos/source/demos/flag_component.d @@ -6,11 +6,11 @@ import bindbc.sdl; import cimgui.cimgui; -import ecs.attributes; -import ecs.core; -import ecs.entity; -import ecs.manager; -import ecs.std; +import bubel.ecs.attributes; +import bubel.ecs.core; +import bubel.ecs.entity; +import bubel.ecs.manager; +import bubel.ecs.std; import ecs_utils.gfx.texture; import ecs_utils.math.vector; diff --git a/demos/source/demos/physics.d b/demos/source/demos/physics.d index 6e9ba4a..5fccc0b 100644 --- a/demos/source/demos/physics.d +++ b/demos/source/demos/physics.d @@ -6,11 +6,11 @@ import bindbc.sdl; import cimgui.cimgui; -import ecs.attributes; -import ecs.core; -import ecs.entity; -import ecs.manager; -import ecs.std; +import bubel.ecs.attributes; +import bubel.ecs.core; +import bubel.ecs.entity; +import bubel.ecs.manager; +import bubel.ecs.std; import ecs_utils.gfx.texture; import ecs_utils.math.vector; diff --git a/demos/source/demos/simple.d b/demos/source/demos/simple.d index edd20c6..89fe801 100644 --- a/demos/source/demos/simple.d +++ b/demos/source/demos/simple.d @@ -6,11 +6,11 @@ import bindbc.sdl; import cimgui.cimgui; -import ecs.attributes; -import ecs.core; -import ecs.entity; -import ecs.manager; -import ecs.std; +import bubel.ecs.attributes; +import bubel.ecs.core; +import bubel.ecs.entity; +import bubel.ecs.manager; +import bubel.ecs.std; import ecs_utils.gfx.texture; import ecs_utils.math.vector; diff --git a/demos/source/demos/snake.d b/demos/source/demos/snake.d index 6bb8cef..c4123ba 100644 --- a/demos/source/demos/snake.d +++ b/demos/source/demos/snake.d @@ -6,12 +6,12 @@ import bindbc.sdl; import cimgui.cimgui; -import ecs.attributes; -import ecs.core; -import ecs.entity; -import ecs.manager; -import ecs.std; -import ecs.vector; +import bubel.ecs.attributes; +import bubel.ecs.core; +import bubel.ecs.entity; +import bubel.ecs.manager; +import bubel.ecs.std; +import bubel.ecs.vector; import ecs_utils.gfx.texture; import ecs_utils.math.vector; diff --git a/demos/source/demos/space_invaders.d b/demos/source/demos/space_invaders.d index bddf53c..92c4e15 100644 --- a/demos/source/demos/space_invaders.d +++ b/demos/source/demos/space_invaders.d @@ -6,11 +6,11 @@ import bindbc.sdl; import cimgui.cimgui; -import ecs.attributes; -import ecs.core; -import ecs.entity; -import ecs.manager; -import ecs.std; +import bubel.ecs.attributes; +import bubel.ecs.core; +import bubel.ecs.entity; +import bubel.ecs.manager; +import bubel.ecs.std; import ecs_utils.gfx.texture; import ecs_utils.math.vector; diff --git a/demos/source/game_core/job_updater.d b/demos/source/game_core/job_updater.d index 46cd609..6c20a83 100644 --- a/demos/source/game_core/job_updater.d +++ b/demos/source/game_core/job_updater.d @@ -1,13 +1,13 @@ module game_core.job_updater; -import ecs.std; -import ecs.vector; -import ecs.atomic; +import bubel.ecs.std; +import bubel.ecs.vector; +import bubel.ecs.atomic; import ecs_utils.utils; //import core.time; -import ecs.manager; +import bubel.ecs.manager; import mmutils.thread_pool; version(LDC) diff --git a/demos/source/gui/manager.d b/demos/source/gui/manager.d index 8a46a92..185fcd1 100644 --- a/demos/source/gui/manager.d +++ b/demos/source/gui/manager.d @@ -4,10 +4,10 @@ import app; import cimgui.cimgui; -import ecs.std; -import ecs.system; -import ecs.vector; -import ecs.entity; +import bubel.ecs.std; +import bubel.ecs.system; +import bubel.ecs.vector; +import bubel.ecs.entity; import gui.system; import gui.template_; diff --git a/demos/source/gui/system.d b/demos/source/gui/system.d index bbee409..112bed3 100644 --- a/demos/source/gui/system.d +++ b/demos/source/gui/system.d @@ -1,6 +1,6 @@ module gui.system; -import ecs.system; +import bubel.ecs.system; struct SystemGUI { diff --git a/demos/source/gui/template_.d b/demos/source/gui/template_.d index 2aa1833..4d3de11 100644 --- a/demos/source/gui/template_.d +++ b/demos/source/gui/template_.d @@ -1,6 +1,6 @@ module gui.template_; -import ecs.entity; +import bubel.ecs.entity; struct TemplateGUI { diff --git a/demos/utils/source/ecs_utils/gfx/buffer.d b/demos/utils/source/ecs_utils/gfx/buffer.d index 2c25324..b11cb85 100644 --- a/demos/utils/source/ecs_utils/gfx/buffer.d +++ b/demos/utils/source/ecs_utils/gfx/buffer.d @@ -1,6 +1,6 @@ module ecs_utils.gfx.buffer; -import ecs.std; +import bubel.ecs.std; import glad.gl.gl; import glad.gl.gles2; diff --git a/demos/utils/source/ecs_utils/gfx/config.d b/demos/utils/source/ecs_utils/gfx/config.d index de5528a..0683647 100644 --- a/demos/utils/source/ecs_utils/gfx/config.d +++ b/demos/utils/source/ecs_utils/gfx/config.d @@ -2,7 +2,7 @@ module ecs_utils.gfx.config; import bindbc.sdl; -import ecs.std; +import bubel.ecs.std; import ecs_utils.gfx.material; import ecs_utils.gfx.mesh; @@ -18,7 +18,7 @@ enum LayerType sorted } -import ecs.vector; +import bubel.ecs.vector; static struct GfxConfig { diff --git a/demos/utils/source/ecs_utils/gfx/material.d b/demos/utils/source/ecs_utils/gfx/material.d index b697992..fbd88b9 100644 --- a/demos/utils/source/ecs_utils/gfx/material.d +++ b/demos/utils/source/ecs_utils/gfx/material.d @@ -2,7 +2,7 @@ module ecs_utils.gfx.material; import bindbc.sdl; -import ecs.std; +import bubel.ecs.std; import ecs_utils.gfx.shader; diff --git a/demos/utils/source/ecs_utils/gfx/mesh.d b/demos/utils/source/ecs_utils/gfx/mesh.d index 346226f..20d5855 100644 --- a/demos/utils/source/ecs_utils/gfx/mesh.d +++ b/demos/utils/source/ecs_utils/gfx/mesh.d @@ -2,7 +2,7 @@ module ecs_utils.gfx.mesh; import bindbc.sdl; -import ecs.std; +import bubel.ecs.std; import ecs_utils.gfx.buffer; diff --git a/demos/utils/source/ecs_utils/gfx/renderer.d b/demos/utils/source/ecs_utils/gfx/renderer.d index 2a04c57..d56b5c8 100644 --- a/demos/utils/source/ecs_utils/gfx/renderer.d +++ b/demos/utils/source/ecs_utils/gfx/renderer.d @@ -2,7 +2,7 @@ module ecs_utils.gfx.renderer; import bindbc.sdl; -import ecs.std; +import bubel.ecs.std; //import ecs_utils.core : Backend; import ecs_utils.gfx.buffer; diff --git a/demos/utils/source/ecs_utils/gfx/shader.d b/demos/utils/source/ecs_utils/gfx/shader.d index 7749013..5e24d9a 100644 --- a/demos/utils/source/ecs_utils/gfx/shader.d +++ b/demos/utils/source/ecs_utils/gfx/shader.d @@ -2,7 +2,7 @@ module ecs_utils.gfx.shader; import bindbc.sdl; -import ecs.std; +import bubel.ecs.std; import glad.gl.gl; diff --git a/demos/utils/source/ecs_utils/gfx/texture.d b/demos/utils/source/ecs_utils/gfx/texture.d index bb4c62a..05e2fd9 100644 --- a/demos/utils/source/ecs_utils/gfx/texture.d +++ b/demos/utils/source/ecs_utils/gfx/texture.d @@ -2,7 +2,7 @@ module ecs_utils.gfx.texture; import bindbc.sdl; -import ecs.std; +import bubel.ecs.std; import ecs_utils.math.vector; diff --git a/demos/utils/source/ecs_utils/gfx/vertex.d b/demos/utils/source/ecs_utils/gfx/vertex.d index 1d11fdd..b63803c 100644 --- a/demos/utils/source/ecs_utils/gfx/vertex.d +++ b/demos/utils/source/ecs_utils/gfx/vertex.d @@ -1,6 +1,6 @@ module ecs_utils.gfx.vertex; -import ecs.std; +import bubel.ecs.std; struct Vertex { diff --git a/meson.build b/meson.build index 3317d5c..c31b93a 100644 --- a/meson.build +++ b/meson.build @@ -1,21 +1,21 @@ project('DECS', 'd') src = [ - 'source/ecs/atomic.d', - 'source/ecs/attributes.d', - 'source/ecs/block_allocator.d', - 'source/ecs/core.d', - 'source/ecs/entity.d', - 'source/ecs/events.d', - 'source/ecs/hash_map.d', - 'source/ecs/id_manager.d', - 'source/ecs/manager.d', - 'source/ecs/package.d', - 'source/ecs/simple_vector.d', - 'source/ecs/std.d', - 'source/ecs/system.d', - 'source/ecs/traits.d', - 'source/ecs/vector.d' + 'source/bubel/ecs/atomic.d', + 'source/bubel/ecs/attributes.d', + 'source/bubel/ecs/block_allocator.d', + 'source/bubel/ecs/core.d', + 'source/bubel/ecs/entity.d', + 'source/bubel/ecs/events.d', + 'source/bubel/ecs/hash_map.d', + 'source/bubel/ecs/id_manager.d', + 'source/bubel/ecs/manager.d', + 'source/bubel/ecs/package.d', + 'source/bubel/ecs/simple_vector.d', + 'source/bubel/ecs/std.d', + 'source/bubel/ecs/system.d', + 'source/bubel/ecs/traits.d', + 'source/bubel/ecs/vector.d' ] tests_src = [ diff --git a/source/ecs/atomic.d b/source/bubel/ecs/atomic.d similarity index 99% rename from source/ecs/atomic.d rename to source/bubel/ecs/atomic.d index 5e5f447..9155c8f 100644 --- a/source/ecs/atomic.d +++ b/source/bubel/ecs/atomic.d @@ -7,7 +7,7 @@ Emscripten functions are contained in API similar to druntime. Copyright: Copyright © 2018-2019, Dawid Masiukiewicz, Michał Masiukiewicz License: BSD 3-clause, see LICENSE file in project root folder. */ -module ecs.atomic; +module bubel.ecs.atomic; version(Emscripten)version = ECSEmscripten; diff --git a/source/ecs/attributes.d b/source/bubel/ecs/attributes.d similarity index 97% rename from source/ecs/attributes.d rename to source/bubel/ecs/attributes.d index 20d0f60..2bc0aec 100644 --- a/source/ecs/attributes.d +++ b/source/bubel/ecs/attributes.d @@ -20,7 +20,7 @@ Struct EntitiesData Copyright: Copyright © 2018-2019, Dawid Masiukiewicz, Michał Masiukiewicz License: BSD 3-clause, see LICENSE file in project root folder. */ -module ecs.attributes; +module bubel.ecs.attributes; ///Used to mark optional components for system. enum optional = "optional"; diff --git a/source/ecs/block_allocator.d b/source/bubel/ecs/block_allocator.d similarity index 97% rename from source/ecs/block_allocator.d rename to source/bubel/ecs/block_allocator.d index d9f08ca..740b762 100644 --- a/source/ecs/block_allocator.d +++ b/source/bubel/ecs/block_allocator.d @@ -6,10 +6,10 @@ Module contain memory allocator. Copyright: Copyright © 2018-2019, Dawid Masiukiewicz, Michał Masiukiewicz License: BSD 3-clause, see LICENSE file in project root folder. */ -module ecs.block_allocator; +module bubel.ecs.block_allocator; -import ecs.manager; -import ecs.std; +import bubel.ecs.manager; +import bubel.ecs.std; /************************************************************************************************************************ Allocator allocate large blocks and return smaller blocks. When there is no more blocks then next large block is allocated. diff --git a/source/ecs/core.d b/source/bubel/ecs/core.d similarity index 96% rename from source/ecs/core.d rename to source/bubel/ecs/core.d index c346c9f..ccdf3e2 100644 --- a/source/ecs/core.d +++ b/source/bubel/ecs/core.d @@ -49,10 +49,10 @@ Struct System1 Copyright: Copyright © 2018-2019, Dawid Masiukiewicz, Michał Masiukiewicz License: BSD 3-clause, see LICENSE file in project root folder. */ -module ecs.core; +module bubel.ecs.core; -public import ecs.manager; -public import ecs.entity; +public import bubel.ecs.manager; +public import bubel.ecs.entity; /************************************************************************************************************************ Main struct used as namespace for templates. diff --git a/source/ecs/entity.d b/source/bubel/ecs/entity.d similarity index 97% rename from source/ecs/entity.d rename to source/bubel/ecs/entity.d index 0bd2dea..441f412 100644 --- a/source/ecs/entity.d +++ b/source/bubel/ecs/entity.d @@ -4,10 +4,10 @@ Entity module. Copyright: Copyright © 2018-2019, Dawid Masiukiewicz, Michał Masiukiewicz License: BSD 3-clause, see LICENSE file in project root folder. */ -module ecs.entity; +module bubel.ecs.entity; -import ecs.system; -import ecs.manager; +import bubel.ecs.system; +import bubel.ecs.manager; /************************************************************************************************************************ Entity ID structure. Used as reference to Entity. Pointer to entity should be ever used to store entity reference! diff --git a/source/ecs/events.d b/source/bubel/ecs/events.d similarity index 97% rename from source/ecs/events.d rename to source/bubel/ecs/events.d index ac7e185..772d5b5 100644 --- a/source/ecs/events.d +++ b/source/bubel/ecs/events.d @@ -1,9 +1,9 @@ -module ecs.events; +module bubel.ecs.events; -import ecs.block_allocator; -import ecs.entity; -import ecs.manager; -import ecs.std; +import bubel.ecs.block_allocator; +import bubel.ecs.entity; +import bubel.ecs.manager; +import bubel.ecs.std; import std.algorithm.comparison : max; diff --git a/source/ecs/hash_map.d b/source/bubel/ecs/hash_map.d similarity index 98% rename from source/ecs/hash_map.d rename to source/bubel/ecs/hash_map.d index 5a8b253..1f7a1f8 100755 --- a/source/ecs/hash_map.d +++ b/source/bubel/ecs/hash_map.d @@ -1,9 +1,9 @@ -module ecs.hash_map; +module bubel.ecs.hash_map; import std.traits; -import ecs.vector; -import ecs.traits; +import bubel.ecs.vector; +import bubel.ecs.traits; enum doNotInline = "version(DigitalMars)pragma(inline,false);version(LDC)pragma(LDC_never_inline);"; diff --git a/source/ecs/id_manager.d b/source/bubel/ecs/id_manager.d similarity index 98% rename from source/ecs/id_manager.d rename to source/bubel/ecs/id_manager.d index 1ab8465..c8eadec 100644 --- a/source/ecs/id_manager.d +++ b/source/bubel/ecs/id_manager.d @@ -1,10 +1,10 @@ -module ecs.id_manager; +module bubel.ecs.id_manager; -import ecs.entity; -import ecs.std; -import ecs.vector; +import bubel.ecs.entity; +import bubel.ecs.std; +import bubel.ecs.vector; -import ecs.atomic; +import bubel.ecs.atomic; import core.stdc.string : memcpy; /************************************************************************************************************************ diff --git a/source/ecs/manager.d b/source/bubel/ecs/manager.d similarity index 99% rename from source/ecs/manager.d rename to source/bubel/ecs/manager.d index aca7f53..be4f37a 100644 --- a/source/ecs/manager.d +++ b/source/bubel/ecs/manager.d @@ -4,7 +4,7 @@ Most important module. Almost every function is called from EntityManager. Copyright: Copyright © 2018-2019, Dawid Masiukiewicz, Michał Masiukiewicz License: BSD 3-clause, see LICENSE file in project root folder. */ -module ecs.manager; +module bubel.ecs.manager; import std.algorithm : max; import std.conv : to; @@ -14,21 +14,21 @@ import std.traits; //import core.stdc.stdlib : qsort; //import core.stdc.string; -import ecs.system; //not ordered as forward reference bug workaround -import ecs.block_allocator; -import ecs.entity; -import ecs.events; -import ecs.hash_map; -import ecs.id_manager; -import ecs.simple_vector; -import ecs.std; -import ecs.traits; -import ecs.vector; -import ecs.atomic; +import bubel.ecs.system; //not ordered as forward reference bug workaround +import bubel.ecs.block_allocator; +import bubel.ecs.entity; +import bubel.ecs.events; +import bubel.ecs.hash_map; +import bubel.ecs.id_manager; +import bubel.ecs.simple_vector; +import bubel.ecs.std; +import bubel.ecs.traits; +import bubel.ecs.vector; +import bubel.ecs.atomic; export alias gEM = EntityManager.instance; export alias gEntityManager = EntityManager.instance; -alias SerializeVector = ecs.vector.Vector!ubyte; +alias SerializeVector = bubel.ecs.vector.Vector!ubyte; /************************************************************************************************************************ Entity manager is responsible for everything. diff --git a/source/bubel/ecs/package.d b/source/bubel/ecs/package.d new file mode 100644 index 0000000..ee3f62b --- /dev/null +++ b/source/bubel/ecs/package.d @@ -0,0 +1,10 @@ +module ecs; + +public import bubel.ecs.core; +public import bubel.ecs.entity; +public import bubel.ecs.manager; +public import bubel.ecs.system; + +import bubel.ecs.events; +import bubel.ecs.id_manager; +import bubel.ecs.std; \ No newline at end of file diff --git a/source/ecs/simple_vector.d b/source/bubel/ecs/simple_vector.d similarity index 95% rename from source/ecs/simple_vector.d rename to source/bubel/ecs/simple_vector.d index 175c015..28d4707 100644 --- a/source/ecs/simple_vector.d +++ b/source/bubel/ecs/simple_vector.d @@ -1,6 +1,6 @@ -module ecs.simple_vector; +module bubel.ecs.simple_vector; -import ecs.std; +import bubel.ecs.std; //import core.stdc.string; diff --git a/source/ecs/std.d b/source/bubel/ecs/std.d similarity index 99% rename from source/ecs/std.d rename to source/bubel/ecs/std.d index c027fd5..4cec197 100644 --- a/source/ecs/std.d +++ b/source/bubel/ecs/std.d @@ -5,7 +5,7 @@ This module contain implementation of standard functionality. Copyright: Copyright © 2018-2019, Dawid Masiukiewicz, Michał Masiukiewicz License: BSD 3-clause, see LICENSE file in project root folder. */ -module ecs.std; +module bubel.ecs.std; version(Emscripten)version = ECSEmscripten; diff --git a/source/ecs/system.d b/source/bubel/ecs/system.d similarity index 98% rename from source/ecs/system.d rename to source/bubel/ecs/system.d index 22a3955..6452e6c 100644 --- a/source/ecs/system.d +++ b/source/bubel/ecs/system.d @@ -4,10 +4,10 @@ System module. Copyright: Copyright © 2018-2019, Dawid Masiukiewicz, Michał Masiukiewicz License: BSD 3-clause, see LICENSE file in project root folder. */ -module ecs.system; +module bubel.ecs.system; -import ecs.entity; -import ecs.manager; +import bubel.ecs.entity; +import bubel.ecs.manager; /************************************************************************************************************************ System contain data required to proper glue EntityManager with Systems. diff --git a/source/ecs/traits.d b/source/bubel/ecs/traits.d similarity index 97% rename from source/ecs/traits.d rename to source/bubel/ecs/traits.d index d19259f..7043b2e 100644 --- a/source/ecs/traits.d +++ b/source/bubel/ecs/traits.d @@ -1,4 +1,4 @@ -module ecs.traits; +module bubel.ecs.traits; import std.traits; diff --git a/source/ecs/vector.d b/source/bubel/ecs/vector.d similarity index 99% rename from source/ecs/vector.d rename to source/bubel/ecs/vector.d index 84ecc51..3334be2 100644 --- a/source/ecs/vector.d +++ b/source/bubel/ecs/vector.d @@ -1,8 +1,8 @@ -module ecs.vector; +module bubel.ecs.vector; import core.bitop; //import core.stdc.stdlib : free, malloc; -import ecs.std; +import bubel.ecs.std; //import core.stdc.string : memcpy, memset; //import std.algorithm : swap; import std.conv : emplace; diff --git a/source/ecs/package.d b/source/ecs/package.d deleted file mode 100644 index eda440d..0000000 --- a/source/ecs/package.d +++ /dev/null @@ -1,10 +0,0 @@ -module ecs; - -public import ecs.core; -public import ecs.entity; -public import ecs.manager; -public import ecs.system; - -import ecs.events; -import ecs.id_manager; -import ecs.std; \ No newline at end of file diff --git a/tests/basic.d b/tests/basic.d index f3f2832..653575f 100644 --- a/tests/basic.d +++ b/tests/basic.d @@ -1,9 +1,9 @@ module tests.basic; -import ecs.core; -import ecs.manager; -import ecs.system; -import ecs.attributes; +import bubel.ecs.core; +import bubel.ecs.manager; +import bubel.ecs.system; +import bubel.ecs.attributes; import std.array : staticArray; diff --git a/tests/id_manager.d b/tests/id_manager.d index afaafe5..b0f97d5 100644 --- a/tests/id_manager.d +++ b/tests/id_manager.d @@ -1,7 +1,7 @@ module tests.id_manager; -import ecs.id_manager; -import ecs.entity; +import bubel.ecs.id_manager; +import bubel.ecs.entity; unittest { diff --git a/tests/runner.d b/tests/runner.d index 5eaf99b..7b8f6b5 100644 --- a/tests/runner.d +++ b/tests/runner.d @@ -5,9 +5,9 @@ import core.stdc.stdio; import core.stdc.string; import core.sys.posix.setjmp; -import ecs.vector; -import ecs.simple_vector; -import ecs.std; +import bubel.ecs.vector; +import bubel.ecs.simple_vector; +import bubel.ecs.std; enum int ASSERTED = 123; enum string OUT_FILE = "test_report.xml"; diff --git a/tests/tests.d b/tests/tests.d index ea554d1..d923116 100644 --- a/tests/tests.d +++ b/tests/tests.d @@ -3,12 +3,12 @@ module tests.tests; import std.experimental.allocator; import std.experimental.allocator.mallocator;*/ -import ecs.entity; -import ecs.events; -import ecs.manager; -import ecs.system; -import ecs.attributes; -import ecs.core; +import bubel.ecs.entity; +import bubel.ecs.events; +import bubel.ecs.manager; +import bubel.ecs.system; +import bubel.ecs.attributes; +import bubel.ecs.core; version (WebAssembly) { @@ -714,7 +714,7 @@ else: //foreach(i; 0..1_000_000)gEM.removeEntity(gEM.addEntity(tmpl).id); - import ecs.std; + import bubel.ecs.std; EntityID[] idss = Mallocator.makeArray!EntityID(5000); //[5000] //scope(exit)Mallocator.dispose(idss); diff --git a/tests/vector.d b/tests/vector.d index 4b2ad5b..d733f0f 100644 --- a/tests/vector.d +++ b/tests/vector.d @@ -1,7 +1,7 @@ module tests.vector; -import ecs.simple_vector; -//import ecs.vector; +import bubel.ecs.simple_vector; +//import bubel.ecs.vector; @("simple-vector") unittest From 46aba822d0a3024d7177261b18844e130a2ff65a Mon Sep 17 00:00:00 2001 From: Mergul Date: Wed, 6 May 2020 10:55:40 +0200 Subject: [PATCH 120/217] Improved documentation and removed some old code --- source/bubel/ecs/id_manager.d | 27 --------------------------- source/bubel/ecs/simple_vector.d | 8 ++++++++ source/bubel/ecs/system.d | 26 +++++++++++++------------- 3 files changed, 21 insertions(+), 40 deletions(-) diff --git a/source/bubel/ecs/id_manager.d b/source/bubel/ecs/id_manager.d index c8eadec..4c3a2c3 100644 --- a/source/bubel/ecs/id_manager.d +++ b/source/bubel/ecs/id_manager.d @@ -17,10 +17,6 @@ struct IDManager */ pragma(inline, false) EntityID getNewID() nothrow @nogc { - //uint current = m_next_id; - //uint next;// = m_ids_array[m_next_id].next_id; -//begin: - //if (current == uint.max)//> m_last_id) int current = m_stack_top.atomicOp!"-="(1) + 1; if(current < 0) { @@ -48,29 +44,11 @@ struct IDManager return id; } - - //current += 1; uint index = m_free_stack[current]; EntityID id; id.id = index; id.counter = m_ids_array[index].counter; - //current = m_ids_array[index].next_id; return id; - - /*next = m_ids_array[current].next_id; - if(cas(&m_next_id,current,next)) - { - EntityID id; - id.id = current; - id.counter = m_ids_array[current].counter; - m_next_id = m_ids_array[current].next_id; - return id; - } - else - { - current = next; - goto begin; - }*/ } /************************************************************************************************************************ @@ -82,9 +60,7 @@ struct IDManager if (data.counter != id.counter) return; data.counter++; - //data.next_id = m_next_id; data.entity = null; - ///m_next_id = id.id; m_stack_top.atomicOp!"+="(1); m_free_stack[m_stack_top] = id.id; @@ -241,13 +217,10 @@ struct IDManager private: Mutex* add_mutex; - //shared uint m_next_id = 0; - //shared uint m_last_id = 0; Data[] m_ids_array = null; uint m_blocks_count = 0; Block[] m_blocks; - //shared int m_stack_top = -1; uint[] m_free_stack = null; align(64) shared uint m_last_id = 0; diff --git a/source/bubel/ecs/simple_vector.d b/source/bubel/ecs/simple_vector.d index 28d4707..1de026e 100644 --- a/source/bubel/ecs/simple_vector.d +++ b/source/bubel/ecs/simple_vector.d @@ -4,11 +4,16 @@ import bubel.ecs.std; //import core.stdc.string; +/************************************************************************************************************************ +Vector for byte data. Simpler than standard template-based implementation designed for better performance. \ +Rellocates 1024 elements at once instead of doubling size. +*/ struct SimpleVector { @disable this(this); + ///Add element to vector void add(ubyte el) nothrow @nogc { while(used >= data.length) @@ -19,6 +24,7 @@ struct SimpleVector data[used++] = el; } + ///Add array of elements to vector void add(ubyte[] el) nothrow @nogc { while(used + el.length >= data.length) @@ -30,6 +36,7 @@ struct SimpleVector used += el.length; } + ///Return vector length size_t length() nothrow @nogc { return used; @@ -55,6 +62,7 @@ struct SimpleVector return used; } + ///set vector length to 0 void clear() nothrow @nogc { used = 0; diff --git a/source/bubel/ecs/system.d b/source/bubel/ecs/system.d index 6452e6c..7343831 100644 --- a/source/bubel/ecs/system.d +++ b/source/bubel/ecs/system.d @@ -14,16 +14,16 @@ System contain data required to proper glue EntityManager with Systems. System callbacks: $(LIST * void onUpdate(EntitesData); - * void onEnable() - * void onDisable(); - * bool onBegin(); - * void onEnd(); - * void onCreate() - * void onDestroy(); - * void onAddEntity(EntitesData); - * void onRemoveEntity(EntitiesData); - * void onChangeEntity(EntitiesData); - * void handleEvent(Entity*, Event); + * void onEnable() - called inside system.enable() function + * void onDisable() - called inside system.disable() function + * bool onBegin() - called inside manager.begin() + * void onEnd() - called inside manager.end() + * void onCreate() - called after registration inside registerSystem function + * void onDestroy() - called during re-registration and inside manager destructor + * void onAddEntity(EntitesData) - called for every entity which are assigned to system (by adding new entity or changing its components) + * void onRemoveEntity(EntitiesData) - called for every entity removed from system update process + * void onChangeEntity(EntitiesData) - called for every entity which components are changed but it was previously assigned to system + * void handleEvent(Entity*, Event) - called for every event supported by system ) */ struct System @@ -66,15 +66,15 @@ struct System } /************************************************************************************************************************ - Get system priority. + Get if system will be executed during current frame. Should be checked after manager.begin(). Its value is setted as result of manager.onBegin() callback. */ - export bool execute() nothrow @nogc + export bool willExecute() nothrow @nogc { return m_execute; } /************************************************************************************************************************ - Get system priority. + Get system id. */ export ushort id() nothrow @nogc { From 4bd5a37b5d51be1d9ed088c6461d0f2ab369c3e9 Mon Sep 17 00:00:00 2001 From: Mergul Date: Thu, 7 May 2020 14:07:07 +0200 Subject: [PATCH 121/217] Demo update and start counting tests times -Fixed performance issue with multithreading and rendering -start making better shaders (by using many macros) -speed up rendeing when maximum objects count was reached -remove map rendering form Snake demo, and render entities by themself -start adding depth and color rendering parameters -added properly names to jobs (for debugging purpses) -starts adding multithreaded rendering -added some math to vectors -changes execute() to willExecute(). Probably should have different name. --- demos/assets/shaders/base.fp | 45 ++- demos/assets/shaders/base.vp | 57 +++- demos/external/sources/mmutils/thread_pool.d | 26 +- demos/source/app.d | 2 +- demos/source/demos/simple.d | 1 + demos/source/demos/snake.d | 319 ++++++++++--------- demos/source/demos/space_invaders.d | 11 +- demos/source/game_core/job_updater.d | 7 +- demos/utils/source/ecs_utils/gfx/renderer.d | 66 +++- demos/utils/source/ecs_utils/math/vector.d | 9 + source/bubel/ecs/manager.d | 4 +- tests/runner.d | 14 + tests/time.d | 66 ++++ 13 files changed, 429 insertions(+), 198 deletions(-) create mode 100644 tests/time.d diff --git a/demos/assets/shaders/base.fp b/demos/assets/shaders/base.fp index 043fa58..ca38c30 100644 --- a/demos/assets/shaders/base.fp +++ b/demos/assets/shaders/base.fp @@ -3,6 +3,31 @@ precision mediump float; precision lowp sampler2D; precision lowp samplerCube; + +#ifdef GLES + #define TEX(x,y) texture2D(x,y) + #if __VERSION__ >290 + #define M_IN in mediump + #define L_IN in lowp + #else + #define M_IN varying mediump + #define L_IN varying lowp + #endif +#else + #define TEX(x,y) texture(x,y) + #if __VERSION__ > 320 + #define M_IN in + #define L_IN in + #else + #define M_IN varying + #define L_IN varying + #endif +#endif + + +M_IN vec2 uv; +M_IN vec4 color; +/* #ifdef GLES #if __VERSION__ >290 in mediump vec2 uv; @@ -15,7 +40,7 @@ precision lowp samplerCube; #else varying vec2 uv; #endif -#endif +#endif*/ //layout(binding = 0)uniform sampler2D tex; @@ -23,20 +48,8 @@ uniform sampler2D tex; //layout(location = 0) out vec4 outColor; -void main() { - - #ifdef GLES - #if __VERSION__ >290 - gl_FragColor = texture(tex,uv); - #else - gl_FragColor = texture2D(tex,uv); - #endif - #else - #if __VERSION__ > 320 - gl_FragColor = texture(tex,uv); - #else - gl_FragColor = texture2D(tex,uv); - #endif - #endif +void main() +{ + gl_FragColor = TEX(tex,uv);// * color; if(gl_FragColor.a < 0.01)discard; } diff --git a/demos/assets/shaders/base.vp b/demos/assets/shaders/base.vp index 42ed4a7..d2d1af8 100644 --- a/demos/assets/shaders/base.vp +++ b/demos/assets/shaders/base.vp @@ -2,12 +2,37 @@ precision highp float; precision highp int; precision lowp sampler2D; precision lowp samplerCube; - #ifdef GLES #if __VERSION__ >290 - layout(location = 0) uniform vec4 matrix_1; - layout(location = 1) uniform vec4 matrix_2; - layout(location = 2) uniform vec4 uv_transform; + #define LOC(x) layout(location = x) + #define ATT in + #define M_OUT out mediump + #define L_OUT out lowp + #else + #define LOC(x) + #define ATT attribute + #define M_OUT varying mediump + #define L_OUT varying lowp + #endif +#else + #if __VERSION__ > 320 + #define LOC(x) layout(location = x) + #define ATT in + #define M_OUT out + #define L_OUT out + #else + #define LOC(x) + #define ATT attribute + #define M_OUT varying + #define L_OUT varying + #endif +#endif +/* +#ifdef GLES + #if __VERSION__ >290 + uniform vec4 matrix_1; + uniform vec4 matrix_2; + uniform vec4 uv_transform; layout(location = 0) in vec2 positions; layout(location = 1) in vec2 tex_coords; @@ -43,13 +68,35 @@ precision lowp samplerCube; varying vec2 uv; #endif +#endif*/ + + + +M_OUT vec2 uv; +L_OUT vec4 color; + +LOC(0) ATT vec2 positions; +LOC(1) ATT vec2 tex_coords; + +#ifdef VBO_BATCH + LOC(2) ATT float depth; + LOC(3) ATT vec4 vcolor; +#else + uniform vec4 matrix_1; + uniform vec4 matrix_2; + uniform vec4 uv_transform; + uniform vec4 vcolor; + + float depth = matrix_2.z; #endif void main() { vec3 position = mat3(matrix_1.x,matrix_1.y,0,matrix_1.z,matrix_1.w,0,matrix_2.xy,1) * vec3(positions,1.0); + position.z = depth; uv = tex_coords * uv_transform.zw + uv_transform.xy; - + color = vcolor; + gl_Position = vec4(position.xy,0,1.0); } diff --git a/demos/external/sources/mmutils/thread_pool.d b/demos/external/sources/mmutils/thread_pool.d index 161eb22..20491ef 100644 --- a/demos/external/sources/mmutils/thread_pool.d +++ b/demos/external/sources/mmutils/thread_pool.d @@ -9,7 +9,7 @@ import bubel.ecs.atomic; //import std.stdio; import std.algorithm : map; -version = MM_NO_LOGS; // Disable log creation +//version = MM_NO_LOGS; // Disable log creation //version = MM_USE_POSIX_THREADS; // Use posix threads insted of standard library, required for betterC version (Posix)version = MM_USE_POSIX_THREADS; @@ -1141,17 +1141,19 @@ public: foreach (ref log; logs) { - size += log.name.length; // size of name + size += log.name.length + 1; // size of name } char* buffer = cast(char*) malloc(size); foreach (ref log; logs) { - + char[100] name_buffer; + name_buffer[0 .. log.name.length] = log.name; + name_buffer[log.name.length] = 0; size_t charWritten = snprintf(buffer + used, size - used, `{"name":"%s", "pid":1, "tid":%lld, "ph":"X", "ts":%lld, "dur":%lld }, %s`, - log.name.ptr, threadData.threadId + 1, log.time, log.duration, "\n".ptr); + name_buffer.ptr, threadData.threadId + 1, log.time, log.duration, "\n".ptr); used += charWritten; } @@ -1447,7 +1449,21 @@ private void threadFunc(ThreadData* threadData) if (data is null) { // Thread does not have own job and can not steal it, so wait for a job - bool ok = threadData.semaphore.timedWait(1_000 + !acceptJobs * 10_000); + int tryWait = 0; + //bool ok = threadData.semaphore.timedWait(1_000 + !acceptJobs * 10_000); + bool ok = true; + while(!threadData.semaphore.tryWait()) + { + tryWait++; + if(tryWait>5000) + { + ok = false; + break; + } + static foreach(i;0..10)instructionPause(); + } + if(!ok)ok = threadData.semaphore.timedWait(1_000 + !acceptJobs * 10_000); + if (ok) { diff --git a/demos/source/app.d b/demos/source/app.d index acdc385..27c706d 100644 --- a/demos/source/app.d +++ b/demos/source/app.d @@ -253,7 +253,7 @@ void mainLoop(void* arg) if(launcher.tool && launcher.tool_repeat != 0 && launcher.mouse.left && !igIsWindowHovered(ImGuiHoveredFlags_AnyWindow) && !igIsWindowFocused(ImGuiFocusedFlags_AnyWindow)) { float range = 500.0 / cast(float)launcher.tool_repeat; - launcher.repeat_time += launcher.delta_time; + launcher.repeat_time += launcher.delta_time*100; while(launcher.repeat_time > range) { launcher.repeat_time -= range; diff --git a/demos/source/demos/simple.d b/demos/source/demos/simple.d index 89fe801..8d6b0f2 100644 --- a/demos/source/demos/simple.d +++ b/demos/source/demos/simple.d @@ -58,6 +58,7 @@ struct DrawSystem void onUpdate(EntitiesData data) { + if(launcher.renderer.item_id >= launcher.renderer.MaxObjects)return;//simple leave loop if max visible objects count was reached foreach(i; 0..data.length) { launcher.renderer.draw(data.textures[i].tex, data.locations[i].location, vec2(16,16), vec4(0,0,1,1), 0, 0 , 0); diff --git a/demos/source/demos/snake.d b/demos/source/demos/snake.d index c4123ba..2606fd9 100644 --- a/demos/source/demos/snake.d +++ b/demos/source/demos/snake.d @@ -30,8 +30,9 @@ struct MapElement empty = 0, apple = 1, wall = 2, + snake = 3, - snake_head_up = 5, + /* snake_head_up = 5, snake_head_down = 6, snake_head_left = 7, snake_head_right = 8, @@ -44,13 +45,31 @@ struct MapElement snake_turn_rd = 15, snake_turn_ru = 16, snake_vertical = 17, - snake_horizontal = 18 + snake_horizontal = 18*/ } Type type; EntityID id; } +enum SnakePart : ubyte +{ + head_up = 0, + head_down = 1, + head_left = 2, + head_right = 3, + tail_up = 4, + tail_down = 5, + tail_left = 6, + tail_right = 7, + turn_ld = 8, + turn_lu = 9, + turn_rd = 10, + turn_ru = 11, + vertical = 12, + horizontal = 13 +} + struct Snake { __gshared const (char)* tips = "Use \"WASD\" keys to move."; @@ -104,39 +123,6 @@ struct Snake *location = random_pos; Entity* apple = launcher.manager.addEntity(apple_tmpl); } - - void drawMap() - { - foreach(x; 0 .. map_size) - { - foreach(y; 0 .. map_size) - { - switch(element(ivec2(x,y)).type) - { - case MapElement.Type.apple:launcher.renderer.draw(texture, vec2(x*16,y*16), vec2(16,16), vec4(0,32*px,16*px,16*px), 0, 0 , 0);break; - - case MapElement.Type.snake_head_up:launcher.renderer.draw(texture, vec2(x*16,y*16), vec2(16,16), vec4(48*px,112*px,16*px,16*px), 0, 0 , 0);break; - case MapElement.Type.snake_head_down:launcher.renderer.draw(texture, vec2(x*16,y*16), vec2(16,16), vec4(48*px,144*px,16*px,16*px), 0, 0 , 0);break; - case MapElement.Type.snake_head_left:launcher.renderer.draw(texture, vec2(x*16,y*16), vec2(16,16), vec4(0,128*px,16*px,16*px), 0, 0 , 0);break; - case MapElement.Type.snake_head_right:launcher.renderer.draw(texture, vec2(x*16,y*16), vec2(16,16), vec4(32*px,128*px,16*px,16*px), 0, 0 , 0);break; - case MapElement.Type.snake_tail_up:launcher.renderer.draw(texture, vec2(x*16,y*16), vec2(16,16), vec4(16*px,112*px,16*px,16*px), 0, 0 , 0);break; - case MapElement.Type.snake_tail_down:launcher.renderer.draw(texture, vec2(x*16,y*16), vec2(16,16), vec4(0,112*px,16*px,16*px), 0, 0 , 0);break; - case MapElement.Type.snake_tail_left:launcher.renderer.draw(texture, vec2(x*16,y*16), vec2(16,16), vec4(32*px,112*px,16*px,16*px), 0, 0 , 0);break; - case MapElement.Type.snake_tail_right:launcher.renderer.draw(texture, vec2(x*16,y*16), vec2(16,16), vec4(0,144*px,16*px,16*px), 0, 0 , 0);break; - case MapElement.Type.snake_turn_ld:launcher.renderer.draw(texture, vec2(x*16,y*16), vec2(16,16), vec4(64*px,128*px,16*px,16*px), 0, 0 , 0);break; - case MapElement.Type.snake_turn_lu:launcher.renderer.draw(texture, vec2(x*16,y*16), vec2(16,16), vec4(32*px,144*px,16*px,16*px), 0, 0 , 0);break; - case MapElement.Type.snake_turn_rd:launcher.renderer.draw(texture, vec2(x*16,y*16), vec2(16,16), vec4(16*px,144*px,16*px,16*px), 0, 0 , 0);break; - case MapElement.Type.snake_turn_ru:launcher.renderer.draw(texture, vec2(x*16,y*16), vec2(16,16), vec4(64*px,112*px,16*px,16*px), 0, 0 , 0);break; - case MapElement.Type.snake_vertical:launcher.renderer.draw(texture, vec2(x*16,y*16), vec2(16,16), vec4(16*px,128*px,16*px,16*px), 0, 0 , 0);break; - case MapElement.Type.snake_horizontal:launcher.renderer.draw(texture, vec2(x*16,y*16), vec2(16,16), vec4(48*px,128*px,16*px,16*px), 0, 0 , 0);break; - - case MapElement.Type.wall:launcher.renderer.draw(texture, vec2(x*16,y*16), vec2(16,16), vec4(0,0,1,1), 0, 0 , 0);break; - default:break; - } - } - } - } - } struct Animation @@ -184,6 +170,7 @@ struct CSnake mixin ECS.Component; + struct Parts { uint length = 0; @@ -217,6 +204,7 @@ struct CSnake } Parts parts; + CMovement.Direction direction; } struct CApple @@ -424,81 +412,19 @@ struct MoveSystem else .snake.element(MapElement(),location); } - static CMovement.Direction getDirection(ivec2 p1, ivec2 p2) - { - if(p1.x - p2.x == -1)return CMovement.direction.right; - else if(p1.x - p2.x == 1)return CMovement.direction.left; - else if(p1.y - p2.y == -1)return CMovement.direction.up; - else if(p1.y - p2.y == 1)return CMovement.direction.down; - else if(p1.x - p2.x > 1)return CMovement.direction.right; - else if(p1.x - p2.x < -1)return CMovement.direction.left; - else if(p1.y - p2.y > 1)return CMovement.direction.up; - else return CMovement.direction.down; - } - - static MapElement.Type snakePart(ivec2 p1, ivec2 p2, ivec2 p3) - { - CMovement.Direction direction = getDirection(p1, p2); - CMovement.Direction direction2 = getDirection(p1, p3); - uint case_ = direction*4 + direction2; - final switch(case_) - { - case 0:return MapElement.Type.snake_horizontal; - case 1:return MapElement.Type.snake_horizontal; - case 2:return MapElement.Type.snake_turn_lu; - case 3:return MapElement.Type.snake_turn_ru; - case 4:return MapElement.Type.snake_horizontal; - case 5:return MapElement.Type.snake_horizontal; - case 6:return MapElement.Type.snake_turn_ld; - case 7:return MapElement.Type.snake_turn_rd; - case 8:return MapElement.Type.snake_turn_lu; - case 9:return MapElement.Type.snake_turn_ld; - case 10:return MapElement.Type.snake_vertical; - case 11:return MapElement.Type.snake_vertical; - case 12:return MapElement.Type.snake_turn_ru; - case 13:return MapElement.Type.snake_turn_rd; - case 14:return MapElement.Type.snake_vertical; - case 15:return MapElement.Type.snake_vertical; - } - } - - static MapElement.Type snakeTail(ivec2 p1, ivec2 p2) - { - CMovement.Direction direction = getDirection(p1, p2); - final switch(direction) - { - case CMovement.Direction.up:return MapElement.Type.snake_tail_up; - case CMovement.Direction.down:return MapElement.Type.snake_tail_down; - case CMovement.Direction.left:return MapElement.Type.snake_tail_left; - case CMovement.Direction.right:return MapElement.Type.snake_tail_right; - } - } - void onUpdate(EntitiesData data) { if(data.snakes) { foreach(i; 0..data.length) { + data.snakes[i].direction = data.movement[i].direction; ivec2 new_location = data.location[i]; moveLocation(data.location[i], data.movement[i].direction); final switch(snake.element(data.location[i].location).type) { - case MapElement.Type.snake_head_up:goto case(MapElement.Type.snake_horizontal); - case MapElement.Type.snake_head_down:goto case(MapElement.Type.snake_horizontal); - case MapElement.Type.snake_head_left:goto case(MapElement.Type.snake_horizontal); - case MapElement.Type.snake_head_right:goto case(MapElement.Type.snake_horizontal); - case MapElement.Type.snake_tail_up:goto case(MapElement.Type.snake_horizontal); - case MapElement.Type.snake_tail_down:goto case(MapElement.Type.snake_horizontal); - case MapElement.Type.snake_tail_left:goto case(MapElement.Type.snake_horizontal); - case MapElement.Type.snake_tail_right:goto case(MapElement.Type.snake_horizontal); - case MapElement.Type.snake_turn_ld:goto case(MapElement.Type.snake_horizontal); - case MapElement.Type.snake_turn_lu:goto case(MapElement.Type.snake_horizontal); - case MapElement.Type.snake_turn_rd:goto case(MapElement.Type.snake_horizontal); - case MapElement.Type.snake_turn_ru:goto case(MapElement.Type.snake_horizontal); - case MapElement.Type.snake_vertical:goto case(MapElement.Type.snake_horizontal); - case MapElement.Type.snake_horizontal: - foreach(ivec2 loc; data.snakes[i].parts) + case MapElement.Type.snake: + foreach(loc; data.snakes[i].parts) { destroy_location.x = loc.x * 16; destroy_location.y = loc.y * 16; @@ -520,37 +446,20 @@ struct MoveSystem launcher.manager.addEntity(snake.snake_destroy_particle); launcher.manager.removeEntity(data.entities[i].id); break; + case MapElement.Type.wall:break; - //launcher.manager.removeEntity(data.entities[i].id); - //break; + case MapElement.Type.empty: moveSnake(data.snakes[i], new_location); - final switch(data.movement[i].direction) - { - case CMovement.Direction.up: - snake.element(MapElement(MapElement.Type.snake_head_up, data.entities[i].id),data.location[i].location); - break; - case CMovement.Direction.right: - snake.element(MapElement(MapElement.Type.snake_head_right, data.entities[i].id),data.location[i].location); - break; - case CMovement.Direction.down: - snake.element(MapElement(MapElement.Type.snake_head_down, data.entities[i].id),data.location[i].location); - break; - case CMovement.Direction.left: - snake.element(MapElement(MapElement.Type.snake_head_left, data.entities[i].id),data.location[i].location); - break; - } + snake.element(MapElement(MapElement.Type.snake, data.entities[i].id),data.location[i].location); if(data.snakes[i].parts.length > 1) { - MapElement.Type elem_type = snakePart(data.snakes[i].parts[$-1],data.location[i],data.snakes[i].parts[$-2]); - snake.element(MapElement(elem_type, data.entities[i].id),data.snakes[i].parts[$-1]); - elem_type = snakeTail(data.snakes[i].parts[1], data.snakes[i].parts[0]); - snake.element(MapElement(elem_type, data.entities[i].id),data.snakes[i].parts[0]); + snake.element(MapElement(MapElement.Type.snake, data.entities[i].id),data.snakes[i].parts[$-1]); + snake.element(MapElement(MapElement.Type.snake, data.entities[i].id),data.snakes[i].parts[0]); } else if(data.snakes[i].parts.length == 1) { - MapElement.Type elem_type = snakeTail(data.location[i], data.snakes[i].parts[0]); - snake.element(MapElement(elem_type, data.entities[i].id),data.snakes[i].parts[0]); + snake.element(MapElement(MapElement.Type.snake, data.entities[i].id),data.snakes[i].parts[0]); } break; case MapElement.Type.apple: @@ -559,29 +468,13 @@ struct MoveSystem if(data.snakes[i].parts.length > 1) { - MapElement.Type elem_type = snakePart(data.snakes[i].parts[$-1],data.location[i],data.snakes[i].parts[$-2]); - snake.element(MapElement(elem_type, data.entities[i].id),data.snakes[i].parts[$-1]); + snake.element(MapElement(MapElement.Type.snake, data.entities[i].id),data.snakes[i].parts[$-1]); } else if(data.snakes[i].parts.length == 1) { - MapElement.Type elem_type = snakeTail(data.location[i], new_location); - snake.element(MapElement(elem_type, data.entities[i].id),new_location); - } - final switch(data.movement[i].direction) - { - case CMovement.Direction.up: - snake.element(MapElement(MapElement.Type.snake_head_up, data.entities[i].id),data.location[i].location); - break; - case CMovement.Direction.right: - snake.element(MapElement(MapElement.Type.snake_head_right, data.entities[i].id),data.location[i].location); - break; - case CMovement.Direction.down: - snake.element(MapElement(MapElement.Type.snake_head_down, data.entities[i].id),data.location[i].location); - break; - case CMovement.Direction.left: - snake.element(MapElement(MapElement.Type.snake_head_left, data.entities[i].id),data.location[i].location); - break; + snake.element(MapElement(MapElement.Type.snake, data.entities[i].id),new_location); } + snake.element(MapElement(MapElement.Type.snake, data.entities[i].id),data.location[i].location); snake.addApple(); break; } @@ -593,10 +486,10 @@ struct MoveSystem { final switch(data.movement[i].direction) { - case CMovement.Direction.down:data.location[i].location.y -= 1;break; - case CMovement.Direction.up:data.location[i].location.y += 1;break; - case CMovement.Direction.left:data.location[i].location.x -= 1;break; - case CMovement.Direction.right:data.location[i].location.x += 1;break; + case CMovement.Direction.down:data.location[i].y -= 1;break; + case CMovement.Direction.up:data.location[i].y += 1;break; + case CMovement.Direction.left:data.location[i].x -= 1;break; + case CMovement.Direction.right:data.location[i].x += 1;break; } } } @@ -699,6 +592,132 @@ struct FixSnakeDirectionSystem } } +struct DrawAppleSystem +{ + mixin ECS.System!1; + + struct EntitiesData + { + uint length; + @readonly CILocation[] location; + const (CApple)[] apple; + } + + void onUpdate(EntitiesData data) + { + foreach(i; 0..data.location.length) + { + launcher.renderer.draw(snake.texture, vec2(data.location[i].x*16,data.location[i].y*16), vec2(16,16), vec4(0,32*px,16*px,16*px), 0, 0 , 0); + } + } +} + +struct DrawSnakeSystem +{ + mixin ECS.System!1; + + struct EntitiesData + { + uint length; + @readonly CILocation[] location; + const (CSnake)[] snake; + } + + static CMovement.Direction getDirection(ivec2 p1, ivec2 p2) + { + if(p1.x - p2.x == -1)return CMovement.direction.right; + else if(p1.x - p2.x == 1)return CMovement.direction.left; + else if(p1.y - p2.y == -1)return CMovement.direction.up; + else if(p1.y - p2.y == 1)return CMovement.direction.down; + else if(p1.x - p2.x > 1)return CMovement.direction.right; + else if(p1.x - p2.x < -1)return CMovement.direction.left; + else if(p1.y - p2.y > 1)return CMovement.direction.up; + else return CMovement.direction.down; + } + + static SnakePart snakePart(ivec2 p1, ivec2 p2, ivec2 p3) + { + CMovement.Direction direction = getDirection(p1, p2); + CMovement.Direction direction2 = getDirection(p1, p3); + uint case_ = direction*4 + direction2; + final switch(case_) + { + case 0:return SnakePart.horizontal; + case 1:return SnakePart.horizontal; + case 2:return SnakePart.turn_lu; + case 3:return SnakePart.turn_ru; + case 4:return SnakePart.horizontal; + case 5:return SnakePart.horizontal; + case 6:return SnakePart.turn_ld; + case 7:return SnakePart.turn_rd; + case 8:return SnakePart.turn_lu; + case 9:return SnakePart.turn_ld; + case 10:return SnakePart.vertical; + case 11:return SnakePart.vertical; + case 12:return SnakePart.turn_ru; + case 13:return SnakePart.turn_rd; + case 14:return SnakePart.vertical; + case 15:return SnakePart.vertical; + } + } + + static SnakePart snakeTail(ivec2 p1, ivec2 p2) + { + CMovement.Direction direction = getDirection(p1, p2); + final switch(direction) + { + case CMovement.Direction.up:return SnakePart.tail_up; + case CMovement.Direction.down:return SnakePart.tail_down; + case CMovement.Direction.left:return SnakePart.tail_left; + case CMovement.Direction.right:return SnakePart.tail_right; + } + } + + static void drawElement(ivec2 loc, SnakePart part) + { + final switch(cast(ubyte)part) + { + case SnakePart.tail_up:launcher.renderer.draw(.snake.texture, cast(vec2)loc, vec2(16,16), vec4(16,112,16,16)*px, 0, 0, 0);break; + case SnakePart.tail_down:launcher.renderer.draw(.snake.texture, cast(vec2)loc, vec2(16,16), vec4(0,112,16,16)*px, 0, 0, 0);break; + case SnakePart.tail_left:launcher.renderer.draw(.snake.texture, cast(vec2)loc, vec2(16,16), vec4(32,112,16,16)*px, 0, 0, 0);break; + case SnakePart.tail_right:launcher.renderer.draw(.snake.texture, cast(vec2)loc, vec2(16,16), vec4(0,144,16,16)*px, 0, 0, 0);break; + case SnakePart.turn_ld:launcher.renderer.draw(.snake.texture, cast(vec2)loc, vec2(16,16), vec4(64,128,16,16)*px, 0, 0, 0);break; + case SnakePart.turn_lu:launcher.renderer.draw(.snake.texture, cast(vec2)loc, vec2(16,16), vec4(32,144,16,16)*px, 0, 0, 0);break; + case SnakePart.turn_rd:launcher.renderer.draw(.snake.texture, cast(vec2)loc, vec2(16,16), vec4(16,144,16,16)*px, 0, 0, 0);break; + case SnakePart.turn_ru:launcher.renderer.draw(.snake.texture, cast(vec2)loc, vec2(16,16), vec4(64,112,16,16)*px, 0, 0, 0);break; + case SnakePart.vertical:launcher.renderer.draw(.snake.texture, cast(vec2)loc, vec2(16,16), vec4(16,128,16,16)*px, 0, 0, 0);break; + case SnakePart.horizontal:launcher.renderer.draw(.snake.texture, cast(vec2)loc, vec2(16,16), vec4(48,128,16,16)*px, 0, 0, 0);break; + } + } + + void onUpdate(EntitiesData data) + { + foreach(i; 0..data.length) + { + const (CSnake)* snake = &data.snake[i]; + scope vec2 loc = cast(vec2)(data.location[i].location * 16); + final switch(snake.direction) + { + case CMovement.Direction.up:launcher.renderer.draw(.snake.texture, vec2(data.location[i].x*16,data.location[i].y*16), vec2(16,16), vec4(48,112,16,16)*px, 0, 0 , 0);break; + case CMovement.Direction.down:launcher.renderer.draw(.snake.texture, vec2(data.location[i].x*16,data.location[i].y*16), vec2(16,16), vec4(48,144,16,16)*px, 0, 0 , 0);break; + case CMovement.Direction.left:launcher.renderer.draw(.snake.texture, vec2(data.location[i].x*16,data.location[i].y*16), vec2(16,16), vec4(0,128,16,16)*px, 0, 0 , 0);break; + case CMovement.Direction.right:launcher.renderer.draw(.snake.texture, vec2(data.location[i].x*16,data.location[i].y*16), vec2(16,16), vec4(32,128,16,16)*px, 0, 0 , 0);break; + } + if(snake.parts.length >1) + { + foreach(j;1..snake.parts.length - 1)drawElement(snake.parts[j]*16, snakePart(snake.parts[j], snake.parts[j+1], snake.parts[j-1])); + drawElement(snake.parts[$-1]*16, snakePart(snake.parts[$-1], data.location[i], snake.parts[$-2])); + drawElement(snake.parts[0]*16, snakeTail(snake.parts[1], snake.parts[0])); + } + else if(snake.parts.length == 1) + { + drawElement(snake.parts[0]*16, snakeTail(data.location[i], snake.parts[0])); + } + + } + } +} + struct CleanSystem { mixin ECS.System!64; @@ -749,6 +768,8 @@ void snakeStart() launcher.manager.registerSystem!AnimationSystem(-1); launcher.manager.registerSystem!ParticleSystem(-1); launcher.manager.registerSystem!ParticleMovementSystem(-1); + launcher.manager.registerSystem!DrawAppleSystem(99); + launcher.manager.registerSystem!DrawSnakeSystem(101); launcher.manager.endRegister(); @@ -766,7 +787,7 @@ void snakeStart() ushort[4] components = [CILocation.component_id, CSnake.component_id, CMovement.component_id, CInput.component_id]; snake.snake_tmpl = launcher.manager.allocateTemplate(components); CILocation* loc_comp = snake.snake_tmpl.getComponent!CILocation; - loc_comp.location = ivec2(2,2); + *loc_comp = ivec2(2,2); launcher.manager.addEntity(snake.snake_tmpl); } @@ -794,7 +815,7 @@ void snakeStart() /*foreach(i; 0..10) foreach(j; 0..10) { - loc_comp.location = vec2(i*32+64,j*32+64); + loc_compation = vec2(i*32+64,j*32+64); launcher.manager.addEntity(simple.tmpl); }*/ } @@ -878,7 +899,7 @@ bool snakeLoop() launcher.manager.end(); - snake.drawMap(); + //snake.drawMap(); return true; } \ No newline at end of file diff --git a/demos/source/demos/space_invaders.d b/demos/source/demos/space_invaders.d index 92c4e15..6d86113 100644 --- a/demos/source/demos/space_invaders.d +++ b/demos/source/demos/space_invaders.d @@ -179,6 +179,13 @@ struct CSideMove byte group = -1; } +struct CDepth +{ + mixin ECS.Component; + + short depth; +} + /*####################################################################################################################### ------------------------------------------------ Events ------------------------------------------------------------------ #######################################################################################################################*/ @@ -620,7 +627,7 @@ struct InputMovementSystem return true; } //don't call system update because no key pressed - return true; + return false; } /** @@ -637,7 +644,7 @@ struct InputMovementSystem { data.textures[i].coords = vec4(0*px,80*px,48*px,32*px); } - return; + //return; } //move every entity using movement vector foreach(i; 0..data.length) diff --git a/demos/source/game_core/job_updater.d b/demos/source/game_core/job_updater.d index 6c20a83..47d2423 100644 --- a/demos/source/game_core/job_updater.d +++ b/demos/source/game_core/job_updater.d @@ -63,6 +63,7 @@ struct ECSJobUpdater JobData[1024] jobs; JobCaller[1024] callers; uint count = 0; + string name; void dependantOn(Group* dependency) { @@ -89,7 +90,7 @@ struct ECSJobUpdater void add(JobCaller caller) { callers[count] = caller; - jobs[count] = JobData(&callers[count].callJob,"hmm"); + jobs[count] = JobData(&callers[count].callJob,name); count++; } } @@ -216,6 +217,8 @@ struct ECSJobUpdater return; } + jobs[group.id].name = cast(string)group.caller.system.name; + foreach(ref job;group.jobs) { uint index = 0; @@ -233,7 +236,7 @@ struct ECSJobUpdater foreach(dep;group.dependencies) { - if(jobs[dep.id].count && dep.caller.system.execute && dep.caller.system.enabled)jobs[group.id].dependantOn(&jobs[dep.id]); + if(jobs[dep.id].count && dep.caller.system.willExecute && dep.caller.system.enabled)jobs[group.id].dependantOn(&jobs[dep.id]); else deps--; } diff --git a/demos/utils/source/ecs_utils/gfx/renderer.d b/demos/utils/source/ecs_utils/gfx/renderer.d index d56b5c8..8735d98 100644 --- a/demos/utils/source/ecs_utils/gfx/renderer.d +++ b/demos/utils/source/ecs_utils/gfx/renderer.d @@ -9,6 +9,9 @@ import ecs_utils.gfx.buffer; import ecs_utils.gfx.texture; import ecs_utils.math.vector; +import bubel.ecs.block_allocator; +import bubel.ecs.vector; + import glad.gl.gl; version = ver1; @@ -41,9 +44,10 @@ enum RenderTechnique struct Renderer { //static SDL_Renderer* main_sdl_renderer; + BlockAllocator allocator; enum MaxObjects = 1024 * 64 * 4; - enum BufferUsage = GL_STATIC_DRAW; + enum BufferUsage = GL_DYNAMIC_DRAW; //SDL_Window* sdl_window; //SDL_Renderer* sdl_renderer; @@ -53,8 +57,35 @@ struct Renderer vec2 view_pos = vec2(-1,-1); vec2 view_size = vec2(1,1); + const uint batch_size = 16_384; //uint[2] time_queries; + struct VertexBlock + { + float[] batch_vertices; + ushort[] batch_indices; + void* memory; + uint itmes = 0; + } + + VertexBlock getBlock() + { + VertexBlock block; + block.memory = allocator.getBlock(); + block.batch_vertices = (cast(float*)block.memory)[0 .. 1]; + return block; + } + + + struct Thread + { + + Vector!VertexBlock block; + RenderData[] render_list; + } + Thread[] threads; + + Buffer[2] ubos; int block_alignment = 1; int block_max_size = 16384; @@ -253,6 +284,8 @@ struct Renderer SDL_Log("Uniform block alignment: %u",block_alignment); SDL_Log("Uniform block max size: %u",block_max_size); SDL_Log("Data offset: %u",data_offset); + + allocator = BlockAllocator(1245184, 32); } } @@ -261,12 +294,13 @@ struct Renderer } - void draw(Texture tex, vec2 pos, vec2 size, vec4 coords, float angle = 0, uint material_id = 0, uint mesh_id = 0) + void draw(Texture tex, vec2 pos, vec2 size, vec4 coords, short depth = 0, uint color = uint.max, float angle = 0, uint material_id = 0, uint mesh_id = 0, uint thread_id = 0) { - __draw(this,tex,pos,size,coords,angle,material_id,mesh_id); + if(item_id >= MaxObjects)return; + __draw(this,tex,pos,size,coords,depth,color,angle,material_id,mesh_id,thread_id); } - private static void __draw_sdl(ref Renderer this_, Texture tex, vec2 pos, vec2 size, vec4 coords, float angle, uint material_id, uint mesh_id) + private static void __draw_sdl(ref Renderer this_, Texture tex, vec2 pos, vec2 size, vec4 coords, short depth, uint color, float angle, uint material_id, uint mesh_id, uint thread_id) { /*with(this_) { @@ -286,7 +320,7 @@ struct Renderer }*/ } - private static void __draw_gl(ref Renderer this_, Texture tex, vec2 pos, vec2 size, vec4 coords, float angle, uint material_id, uint mesh_id) + private static void __draw_gl(ref Renderer this_, Texture tex, vec2 pos, vec2 size, vec4 coords, short depth, uint color, float angle, uint material_id, uint mesh_id, uint thread_id) { //import core.stdc.string; with(this_) @@ -333,13 +367,13 @@ struct Renderer } } - private static void __draw_gl_vbo_batch(ref Renderer this_, Texture tex, vec2 pos, vec2 size, vec4 coords, float angle, uint material_id, uint mesh_id) + private static void __draw_gl_vbo_batch(ref Renderer this_, Texture tex, vec2 pos, vec2 size, vec4 coords, short depth, uint color, float angle, uint material_id, uint mesh_id, uint thread_id = 0) { import ecs_utils.gfx.config; //import core.stdc.string; with(this_) { - if(item_id >= MaxObjects)return; + //if(item_id >= MaxObjects)return; //pos += view_pos; size.x *= view_size.x; size.y *= view_size.y; @@ -400,7 +434,7 @@ struct Renderer batch_vertices[item_id*16+14] = GfxConfig.meshes[mesh_id].vertices[14] * coords.z + coords.x; batch_vertices[item_id*16+15] = GfxConfig.meshes[mesh_id].vertices[15] * coords.w + coords.y; - uint ind_id = item_id % 16_384; + uint ind_id = item_id % batch_size; batch_indices[item_id*6] = cast(ushort)(GfxConfig.meshes[mesh_id].indices[0] + ind_id*4); batch_indices[item_id*6+1] = cast(ushort)(GfxConfig.meshes[mesh_id].indices[1] + ind_id*4); @@ -575,7 +609,7 @@ struct Renderer //glBeginQuery(GL_TIME_ELAPSED, time_queries[0]); if(technique == Technique.vbo_batch) { - uint items = item_id/16_384+1; + uint items = item_id/batch_size+1; foreach(i; 0..items) { if(material_id != render_list[i].material_id) @@ -591,16 +625,16 @@ struct Renderer render_list[i].texture.bind(); } - uint instance_count = 16_384; - if((i+1)*16_384 > item_id) + uint instance_count = batch_size; + if((i+1)*batch_size > item_id) { - instance_count = item_id%16_384; + instance_count = item_id%batch_size; } - glVertexAttribPointer(0,2,GL_FLOAT,false,16,cast(void*)(i*16_384*4*16)); - glVertexAttribPointer(1,2,GL_FLOAT,false,16,cast(void*)(i*16_384*4*16+8)); + glVertexAttribPointer(0,2,GL_FLOAT,false,16,cast(void*)(i*batch_size*4*16)); + glVertexAttribPointer(1,2,GL_FLOAT,false,16,cast(void*)(i*batch_size*4*16+8)); - glDrawElements(GL_TRIANGLES,instance_count*6,GL_UNSIGNED_SHORT,cast(void*)(i*16_384*6*2)); + glDrawElements(GL_TRIANGLES,instance_count*6,GL_UNSIGNED_SHORT,cast(void*)(i*batch_size*6*2)); //glDrawElementsBaseVertex(GL_TRIANGLES,instance_count*6,GL_UNSIGNED_SHORT,cast(void*)(i*16_384*6*2),i*16_384*4); } @@ -803,7 +837,7 @@ struct Renderer view_pos = (pos - size * 0.5) * view_size; } - __gshared void function(ref Renderer this_, Texture tex, vec2 pos, vec2 size, vec4 coords, float angle, uint material_id, uint mesh_id) __draw; + __gshared void function(ref Renderer this_, Texture tex, vec2 pos, vec2 size, vec4 coords, short depth, uint color, float angle, uint material_id, uint mesh_id, uint thread_id) __draw; __gshared void function(ref Renderer this_) __present; __gshared void function(ref Renderer this_) __clear; __gshared void function(ref Renderer this_) __initialize; diff --git a/demos/utils/source/ecs_utils/math/vector.d b/demos/utils/source/ecs_utils/math/vector.d index 4b9f3af..a74b6db 100644 --- a/demos/utils/source/ecs_utils/math/vector.d +++ b/demos/utils/source/ecs_utils/math/vector.d @@ -97,6 +97,15 @@ struct ivec2 int[2] data; } + ivec2 opBinary(string op, T)(T v) + { + static if (op == "+") return ivec2(x + v, y + v); + else static if (op == "-") return ivec2(x - v, y - v); + else static if (op == "*") return ivec2(x * v, y * v); + else static if (op == "/") return ivec2(x / v, y / v); + else static assert(0, "Operator "~op~" not implemented"); + } + vec2 opCast() { return vec2(x,y); diff --git a/source/bubel/ecs/manager.d b/source/bubel/ecs/manager.d index be4f37a..1b896db 100644 --- a/source/bubel/ecs/manager.d +++ b/source/bubel/ecs/manager.d @@ -1253,7 +1253,7 @@ export struct EntityManager foreach (caller; passes[pass].system_callers) { System* sys = &systems[caller.system_id]; - if (sys.enabled && sys.execute) + if (sys.enabled && sys.willExecute) { if (sys.m_empty) { @@ -1293,7 +1293,7 @@ export struct EntityManager foreach (caller; passes[pass].system_callers) { System* sys = &systems[caller.system_id]; - if (sys.enabled && sys.execute) + if (sys.enabled && sys.willExecute) { uint job_id = 0; void nextJob() diff --git a/tests/runner.d b/tests/runner.d index 7b8f6b5..4aa9bcb 100644 --- a/tests/runner.d +++ b/tests/runner.d @@ -9,6 +9,8 @@ import bubel.ecs.vector; import bubel.ecs.simple_vector; import bubel.ecs.std; +import tests.time; + enum int ASSERTED = 123; enum string OUT_FILE = "test_report.xml"; @@ -95,6 +97,8 @@ struct TestRunner(Args...) write(test.name); write("\" classname=\""); write(suite.name); + write("\" time=\""); + write(cast(double)test.time*0.000001); write("\">"); if (test.msg) { @@ -189,8 +193,10 @@ struct TestRunner(Args...) } else { + long time = Time.getUSecTime(); unittest_(); test.passed = true; + test.time = cast(int)(Time.getUSecTime() - time); } } else @@ -281,6 +287,14 @@ struct TestRunner(Args...) junit.add(cast(ubyte[]) txt); } + void write(double num) + { + ubyte[40] buffer; + int len; + len = sprintf(cast(char*) buffer.ptr, "%2.8lf", num); + junit.add(buffer[0 .. len]); + } + void write(uint num) { ubyte[20] buffer; diff --git a/tests/time.d b/tests/time.d new file mode 100644 index 0000000..e91b76e --- /dev/null +++ b/tests/time.d @@ -0,0 +1,66 @@ +module tests.time; + + +version (WebAssembly) +{ + alias int time_t; + alias int clockid_t; + enum CLOCK_REALTIME = 0; + + struct timespec + { + time_t tv_sec; + int tv_nsec; + } + + extern (C) int clock_gettime(clockid_t, timespec*) @nogc nothrow @system; + + struct Time + { + static long getUSecTime() + { + time_t time; + timespec spec; + + clock_gettime(CLOCK_REALTIME, &spec); + + //time = spec.tv_sec; + return spec.tv_sec * 1000_000 + spec.tv_nsec / 1000; //time / 1000_000; + } + } +} +else version (Windows) +{ + import core.stdc.stdio : printf; + import core.sys.windows.windows; + + struct Time + { + static long getUSecTime() + { + LARGE_INTEGER time, freq; + QueryPerformanceFrequency(&freq); + QueryPerformanceCounter(&time); + return time.QuadPart / (freq.QuadPart / 1000_000); + } + } +} +else version (Posix) +{ + import core.stdc.stdio : printf; + import core.sys.posix.time; + + struct Time + { + static long getUSecTime() + { + time_t time; + timespec spec; + + clock_gettime(CLOCK_REALTIME, &spec); + + //time = spec.tv_sec; + return spec.tv_sec * 1000_000 + spec.tv_nsec / 1000; //time / 1000_000; + } + } +} \ No newline at end of file From f6e7af10148d7fb47ac7b58f44f6551c6b46640b Mon Sep 17 00:00:00 2001 From: Mergul Date: Thu, 7 May 2020 21:58:34 +0200 Subject: [PATCH 122/217] Some preformance tests and added EntityMeta structure --- source/bubel/ecs/entity.d | 22 +++++ tests/access_perf.d | 128 +++++++++++++++++++++++++++ tests/perf.d | 178 ++++++++++++++++++++++++++++++++++++++ tests/runner.d | 77 ++++++++++++----- 4 files changed, 385 insertions(+), 20 deletions(-) create mode 100644 tests/access_perf.d create mode 100644 tests/perf.d diff --git a/source/bubel/ecs/entity.d b/source/bubel/ecs/entity.d index 441f412..10720a2 100644 --- a/source/bubel/ecs/entity.d +++ b/source/bubel/ecs/entity.d @@ -45,6 +45,28 @@ struct Entity uint ind = cast(uint)((cast(void*)&this - block.dataBegin()) / EntityID.sizeof()); return cast(T*)(cast(void*)block + info.deltas[T.component_id] + ind * T.sizeof); } + + EntityMeta getMeta() + { + EntityMeta meta; + meta.block = gEM.getMetaData(&this); + static if (EntityID.sizeof == 8) + meta.index = cast(ushort)((cast(void*)&this - meta.block.dataBegin()) >> 3); + else + meta.index = cast(ushort)((cast(void*)&this - meta.block.dataBegin()) / EntityID.sizeof()); + return meta; + } +} + +struct EntityMeta +{ + EntityManager.EntitiesBlock* block; + ushort index; + + T* getComponent(T)() const + { + return cast(T*)(cast(void*)block + block.type_info.deltas[T.component_id] + index * T.sizeof); + } } /************************************************************************************************************************ diff --git a/tests/access_perf.d b/tests/access_perf.d new file mode 100644 index 0000000..141a2e6 --- /dev/null +++ b/tests/access_perf.d @@ -0,0 +1,128 @@ +module tests.access_perf; + +import tests.runner; + +import bubel.ecs.core; +import bubel.ecs.manager; +import bubel.ecs.entity; + +import std.array : staticArray; + +import core.stdc.stdio; + +struct CLong +{ + mixin ECS.Component; + + alias value this; + + long value = 10; +} + +struct CInt +{ + mixin ECS.Component; + + alias value this; + + int value = 10; +} + +struct CUInt +{ + mixin ECS.Component; + + alias value this; + + uint value = 12; +} + +struct CBig +{ + mixin ECS.Component; + uint[32] data; +} + +EntityTemplate* tmpl; + +void beforeEveryTest() +{ + gEM.initialize(0); + + gEM.beginRegister(); + + gEM.registerComponent!CLong; + gEM.registerComponent!CInt; + gEM.registerComponent!CUInt; + gEM.registerComponent!CBig; + + gEM.endRegister(); + + tmpl = gEM.allocateTemplate([CLong.component_id, CInt.component_id, CUInt.component_id, CBig.component_id].staticArray); + foreach(i; 0 .. 100_000)gEM.addEntity(tmpl); +} + +void afterEveryTest() +{ + if(tmpl)gEM.freeTemplate(tmpl); + tmpl = null; + gEM.destroy(); +} + +@("DirectAccess100k1comp") +unittest +{ + foreach(i;0..25000) + { + Entity* entity = gEM.getEntity(EntityID(i*4+1,0)); + CUInt* comp1 = entity.getComponent!CUInt; + comp1.value = 4; + } +} + +@("DirectAccess100k4comp") +unittest +{ + foreach(i;0..25000) + { + Entity* entity = gEM.getEntity(EntityID(i*4+1,0)); + CUInt* comp1 = entity.getComponent!CUInt; + comp1.value = 4; + CInt* comp2 = entity.getComponent!CInt; + comp2.value = 3; + CLong* comp3 = entity.getComponent!CLong; + comp3.value = 1; + CBig* comp4 = entity.getComponent!CBig; + comp4.data[0] = 2; + } +} + +@("DirectAccess100k1compWithMeta") +unittest +{ + foreach(i;0..25000) + { + Entity* entity = gEM.getEntity(EntityID(i*4+1,0)); + EntityMeta meta = entity.getMeta(); + CUInt* comp1 = meta.getComponent!CUInt; + comp1.value = 4; + } +} + +@("DirectAccess100k4compWithMeta") +unittest +{ + foreach(i;0..25000) + { + Entity* entity = gEM.getEntity(EntityID(i*4+1,0)); + EntityMeta meta = entity.getMeta(); + CUInt* comp1 = meta.getComponent!CUInt; + comp1.value = 4; + CInt* comp2 = meta.getComponent!CInt; + comp2.value = 3; + CLong* comp3 = meta.getComponent!CLong; + comp3.value = 1; + CBig* comp4 = meta.getComponent!CBig; + comp4.data[0] = 2; + } +} \ No newline at end of file diff --git a/tests/perf.d b/tests/perf.d new file mode 100644 index 0000000..135dc54 --- /dev/null +++ b/tests/perf.d @@ -0,0 +1,178 @@ +module tests.perf; + +import tests.runner; + +import bubel.ecs.core; +import bubel.ecs.manager; +import bubel.ecs.entity; + +import std.array : staticArray; + +import core.stdc.stdio; + +struct CLong +{ + mixin ECS.Component; + + alias value this; + + long value = 10; +} + +struct CShort +{ + mixin ECS.Component; + + alias value this; + + short value = 12; +} + +struct CInt +{ + mixin ECS.Component; + + alias value this; + + int value = 10; +} + +struct CUInt +{ + mixin ECS.Component; + + alias value this; + + uint value = 12; +} + +struct CBig +{ + mixin ECS.Component; + uint[32] data; +} + +EntityTemplate* tmpl; + +void beforeEveryTest() +{ + gEM.initialize(0); + + gEM.beginRegister(); + + gEM.registerComponent!CLong; + gEM.registerComponent!CShort; + gEM.registerComponent!CInt; + gEM.registerComponent!CUInt; + gEM.registerComponent!CBig; + + gEM.endRegister(); + tmpl = null; +} + +void afterEveryTest() +{ + if(tmpl)gEM.freeTemplate(tmpl); + tmpl = null; + gEM.destroy(); +} + +void smallTmpl() +{ + tmpl = gEM.allocateTemplate([CShort.component_id].staticArray); +} + +void bigTmpl() +{ + tmpl = gEM.allocateTemplate([CBig.component_id].staticArray); +} + +void multiSmallTmpl() +{ + tmpl = gEM.allocateTemplate([CShort.component_id, CLong.component_id, CInt.component_id, CUInt.component_id].staticArray); +} + +void multiBigTmpl() +{ + tmpl = gEM.allocateTemplate([CLong.component_id, CInt.component_id, CUInt.component_id, CBig.component_id].staticArray); +} + +@("AddEntities100k1comp2b") @(before, &smallTmpl) +unittest +{ + foreach(i; 0..100_000)gEM.addEntity(tmpl); +} + +@("AddEntities100k1comp128b") @(before, &bigTmpl) +unittest +{ + foreach(i; 0..100_000)gEM.addEntity(tmpl); +} + +@("AddEntities100k4comp18b") @(before, &multiSmallTmpl) +unittest +{ + foreach(i; 0..100_000)gEM.addEntity(tmpl); +} + +@("AddEntities100k4comp144b") @(before, &multiBigTmpl) +unittest +{ + foreach(i; 0..100_000)gEM.addEntity(tmpl); +} + +void allocDealloc100k() +{ + foreach(i; 0..100_000)gEM.addEntity(tmpl); + gEM.commit(); + foreach(i; 0..100_000)gEM.removeEntity(EntityID(i + 1,0)); + gEM.commit(); +} + +void smallTmplPreAlloc() +{ + tmpl = gEM.allocateTemplate([CShort.component_id].staticArray); + allocDealloc100k(); +} + +void bigTmplPreAlloc() +{ + tmpl = gEM.allocateTemplate([CBig.component_id].staticArray); + allocDealloc100k(); +} + +void multiSmallTmplPreAlloc() +{ + tmpl = gEM.allocateTemplate([CShort.component_id, CLong.component_id, CInt.component_id, CUInt.component_id].staticArray); + allocDealloc100k(); +} + +void multiBigTmplPreAlloc() +{ + tmpl = gEM.allocateTemplate([CLong.component_id, CInt.component_id, CUInt.component_id, CBig.component_id].staticArray); + allocDealloc100k(); +} + +@("AddEntities100k1comp2bPreAlloc") @(before, &smallTmplPreAlloc) +unittest +{ + foreach(i; 0..100_000)gEM.addEntity(tmpl); +} + +@("AddEntities100k1comp128bPreAlloc") @(before, &bigTmplPreAlloc) +unittest +{ + foreach(i; 0..100_000)gEM.addEntity(tmpl); +} + +@("AddEntities100k4comp18bPreAlloc") @(before, &multiSmallTmplPreAlloc) +unittest +{ + foreach(i; 0..100_000)gEM.addEntity(tmpl); +} + +@("AddEntities100k4comp144bPreAlloc") @(before, &multiBigTmplPreAlloc) +unittest +{ + foreach(i; 0..100_000)gEM.addEntity(tmpl); +} \ No newline at end of file diff --git a/tests/runner.d b/tests/runner.d index 4aa9bcb..f299664 100644 --- a/tests/runner.d +++ b/tests/runner.d @@ -9,8 +9,19 @@ import bubel.ecs.vector; import bubel.ecs.simple_vector; import bubel.ecs.std; +import std.traits; + import tests.time; +version (LDC) +{ + import ldc.attributes; +} +else +{ + enum optStrategy = 0; +} + enum int ASSERTED = 123; enum string OUT_FILE = "test_report.xml"; @@ -124,42 +135,65 @@ struct TestRunner(Args...) write(""); } + @(optStrategy,"none") void runTests(string[] include = null, string[] exclude = null) { foreach (i, module_; Args) { TestSuite* suite = &suites[i]; suite.name = module_.stringof; + + void function() before; + void function() after; + foreach (index, unittest_; __traits(getUnitTests, module_)) { enum attributes = __traits(getAttributes, unittest_); + static if (attributes.length != 0) { - if (include.length > 0) + foreach(attr_id, attr; attributes) { - bool matched = false; - foreach (str; include) + static if(isFunctionPointer!(attr)){} + else static if(attr == "_tr_before") { - if (match(str, attributes[0])) - { - matched = true; - break; - } + static assert(attr_id+1 < attributes.length); + enum attr2 = attributes[attr_id + 1]; + //static assert(__traits(hasMember, module_, attr2)); + //alias func = __traits(getMember, module_, attr2); + //attr2(); + before = attr2; + //static assert(is(typeof(__traits(getMember, module_, attr2)) == void function())); } - - foreach (str; exclude) + else { - if (match(str, attributes[0])) + if (include.length > 0) { - matched = false; - break; - } - } + bool matched = false; + foreach (str; include) + { + if (match(str, attr)) + { + matched = true; + break; + } + } - if (!matched) - { - suite.skipped++; - continue; + foreach (str; exclude) + { + if (match(str, attr)) + { + matched = false; + break; + } + } + + if (!matched) + { + suite.skipped++; + continue; + } + } } } } @@ -178,6 +212,7 @@ struct TestRunner(Args...) static if (__traits(hasMember, module_, "beforeEveryTest")) module_.beforeEveryTest(); + if(before)before(); version(D_BetterC) { @@ -318,6 +353,8 @@ version (notBetterC) version (D_Coverage) extern (C) void dmd_coverDestPath(string path); } +enum before = "_tr_before"; + void extractStrings(ref Vector!string container, string str) { uint s = 0; @@ -383,7 +420,7 @@ extern (C) int main(int argc, char** args) } } - TestRunner!(tests.runner, tests.id_manager, tests.vector, tests.basic) runner; + TestRunner!(tests.id_manager, tests.vector, tests.basic, tests.perf, tests.access_perf) runner; runner.runTests(include[], exclude[]); From c94510a487f3c85ce216b28a88602158aa4f3381 Mon Sep 17 00:00:00 2001 From: Mergul Date: Sat, 9 May 2020 19:41:00 +0200 Subject: [PATCH 123/217] Improved Demo and multithreading rendering: -added support for multithreaded rendering (fast) -improved shaders -added support for rendering depth -added rendering color support -improved DeptThreadPool (dynamics setting number of tryWait counts before TryWait. Low cpu usage with high responivity) -added possibility to change number of threads --- demos/assets/shaders/base.fp | 2 +- demos/assets/shaders/base.vp | 14 +- demos/external/sources/mmutils/thread_pool.d | 6 +- demos/source/app.d | 23 +- demos/source/demos/simple.d | 8 +- demos/source/demos/snake.d | 30 +- demos/source/demos/space_invaders.d | 24 +- demos/utils/source/ecs_utils/gfx/renderer.d | 309 ++++++++++++++----- 8 files changed, 311 insertions(+), 105 deletions(-) diff --git a/demos/assets/shaders/base.fp b/demos/assets/shaders/base.fp index ca38c30..d86e92e 100644 --- a/demos/assets/shaders/base.fp +++ b/demos/assets/shaders/base.fp @@ -50,6 +50,6 @@ uniform sampler2D tex; void main() { - gl_FragColor = TEX(tex,uv);// * color; + gl_FragColor = TEX(tex,uv) * color; if(gl_FragColor.a < 0.01)discard; } diff --git a/demos/assets/shaders/base.vp b/demos/assets/shaders/base.vp index d2d1af8..7be086b 100644 --- a/demos/assets/shaders/base.vp +++ b/demos/assets/shaders/base.vp @@ -70,7 +70,7 @@ precision lowp samplerCube; #endif #endif*/ - +#define VBO_BATCH 1 M_OUT vec2 uv; L_OUT vec4 color; @@ -91,12 +91,16 @@ LOC(1) ATT vec2 tex_coords; #endif void main() { + #ifdef VBO_BATCH + vec3 position = vec3(positions*4,1.0); + uv = tex_coords; + #else + vec3 position = mat3(matrix_1.x,matrix_1.y,0,matrix_1.z,matrix_1.w,0,matrix_2.xy,1) * vec3(positions,1.0); + uv = tex_coords * uv_transform.zw + uv_transform.xy; + #endif - vec3 position = mat3(matrix_1.x,matrix_1.y,0,matrix_1.z,matrix_1.w,0,matrix_2.xy,1) * vec3(positions,1.0); - position.z = depth; - uv = tex_coords * uv_transform.zw + uv_transform.xy; color = vcolor; - gl_Position = vec4(position.xy,0,1.0); + gl_Position = vec4(position.xy,depth,1.0); } diff --git a/demos/external/sources/mmutils/thread_pool.d b/demos/external/sources/mmutils/thread_pool.d index 20491ef..143960c 100644 --- a/demos/external/sources/mmutils/thread_pool.d +++ b/demos/external/sources/mmutils/thread_pool.d @@ -9,13 +9,14 @@ import bubel.ecs.atomic; //import std.stdio; import std.algorithm : map; -//version = MM_NO_LOGS; // Disable log creation +version = MM_NO_LOGS; // Disable log creation //version = MM_USE_POSIX_THREADS; // Use posix threads insted of standard library, required for betterC version (Posix)version = MM_USE_POSIX_THREADS; version (WebAssembly) { + version = MM_NO_LOGS; extern(C) struct FILE { @@ -799,6 +800,7 @@ struct ThreadPool alias FlushLogsDelegaste = void delegate(ThreadData* threadData, JobLog[] logs); /// Type of delegate to flush logs FlushLogsDelegaste onFlushLogs; /// User custom delegate to flush logs, if overriden defaultFlushLogs will be used. Can be sset after initialize() call int logsCacheNum; /// Number of log cache entries. Should be set before setThreadsNum is called + int tryWaitCount = 2000; ///Number of times which tryWait are called before timedWait call. Higher value sets better response but takes CPU time even if there are no jobs. private: ThreadData*[gMaxThreadsNum] threadsData; /// Data for threads align(64) shared int threadsNum; /// Number of threads currentlu accepting jobs @@ -1455,7 +1457,7 @@ private void threadFunc(ThreadData* threadData) while(!threadData.semaphore.tryWait()) { tryWait++; - if(tryWait>5000) + if(tryWait>threadPool.tryWaitCount) { ok = false; break; diff --git a/demos/source/app.d b/demos/source/app.d index 27c706d..af4b331 100644 --- a/demos/source/app.d +++ b/demos/source/app.d @@ -58,6 +58,7 @@ struct Launcher uint style = 3; uint entities_count; bool multithreading; + int threads; ulong timer_freq; double delta_time; uint fps; @@ -253,13 +254,12 @@ void mainLoop(void* arg) if(launcher.tool && launcher.tool_repeat != 0 && launcher.mouse.left && !igIsWindowHovered(ImGuiHoveredFlags_AnyWindow) && !igIsWindowFocused(ImGuiFocusedFlags_AnyWindow)) { float range = 500.0 / cast(float)launcher.tool_repeat; - launcher.repeat_time += launcher.delta_time*100; + launcher.repeat_time += launcher.delta_time; while(launcher.repeat_time > range) { launcher.repeat_time -= range; launcher.tool((launcher.mouse.position*launcher.scalling)-launcher.render_position, launcher.used_tool, launcher.tool_size); } - } version(WebAssembly) @@ -317,6 +317,14 @@ void mainLoop(void* arg) { launcher.multithreading = !launcher.multithreading; } + igSetNextItemWidth(0); + igLabelText("Threads:",null); + igSameLine(0,4); + if(igSliderInt("##Threads",&launcher.threads, 1, 12, null))//"Multithreading", null, launcher.multithreading, true)) + { + launcher.job_updater.pool.setThreadsNum(launcher.threads); + //launcher.threads = !launcher.multithreading; + } if(igBeginMenu("Show",true)) { if(igMenuItemBool("Statistics",null,launcher.show_stat_wnd,true)) @@ -539,11 +547,14 @@ void mainLoop(void* arg) launcher.renderer.clear(); double loop_time = launcher.getTime(); + launcher.job_updater.pool.tryWaitCount = 5000; if(launcher.loop && !launcher.loop()) { quit(); *cast(bool*)arg = false; } + launcher.job_updater.pool.tryWaitCount = 10; + loop_time = launcher.getTime() - loop_time; double draw_time = launcher.getTime(); @@ -785,7 +796,15 @@ void loadGFX() GfxConfig.materials[0].compile(); GfxConfig.materials[0].bindAttribLocation("positions",0); GfxConfig.materials[0].bindAttribLocation("tex_coords",1); + GfxConfig.materials[0].bindAttribLocation("depth",2); + GfxConfig.materials[0].bindAttribLocation("vcolor",3); GfxConfig.materials[0].link(); + + /* import std.stdio; + writeln("positions ",glGetAttribLocation(GfxConfig.materials[0].data.modules[0].gl_handle,"positions")); + writeln("tex_coords ",glGetAttribLocation(GfxConfig.materials[0].data.modules[0].gl_handle,"tex_coords")); + writeln("depth ",glGetAttribLocation(GfxConfig.materials[0].data.modules[0].gl_handle,"depth")); + writeln("vcolor ",glGetAttribLocation(GfxConfig.materials[0].data.modules[0].gl_handle,"vcolor"));*/ GfxConfig.materials[0].data.uniforms = Mallocator.makeArray!(Material.Uniform)(3); GfxConfig.materials[0].data.uniforms[0] = Material.Uniform(Material.Type.float4, GfxConfig.materials[0].getLocation("matrix_1"), 0); diff --git a/demos/source/demos/simple.d b/demos/source/demos/simple.d index 8d6b0f2..686f9be 100644 --- a/demos/source/demos/simple.d +++ b/demos/source/demos/simple.d @@ -47,23 +47,25 @@ struct CTexture struct DrawSystem { - mixin ECS.System!1; + mixin ECS.System!32; struct EntitiesData { uint length; + uint thread_id; @readonly CTexture[] textures; @readonly CLocation[] locations; } void onUpdate(EntitiesData data) { - if(launcher.renderer.item_id >= launcher.renderer.MaxObjects)return;//simple leave loop if max visible objects count was reached + if(launcher.renderer.prepared_items >= launcher.renderer.MaxObjects)return;//simple leave loop if max visible objects count was reached foreach(i; 0..data.length) { - launcher.renderer.draw(data.textures[i].tex, data.locations[i].location, vec2(16,16), vec4(0,0,1,1), 0, 0 , 0); + launcher.renderer.draw(data.textures[i].tex, data.locations[i].location, vec2(16,16), vec4(0,0,1,1), cast(ushort)(data.locations[i].y*64+data.locations[i].x), uint.max, 0, 0, 0, data.thread_id); //draw(renderer, data.textures[i].tex, data.locations[i], vec2(32,32), vec4(0,0,1,1)); } + if(data.thread_id == 0)launcher.renderer.pushData(); } } diff --git a/demos/source/demos/snake.d b/demos/source/demos/snake.d index 2606fd9..94f2654 100644 --- a/demos/source/demos/snake.d +++ b/demos/source/demos/snake.d @@ -607,7 +607,7 @@ struct DrawAppleSystem { foreach(i; 0..data.location.length) { - launcher.renderer.draw(snake.texture, vec2(data.location[i].x*16,data.location[i].y*16), vec2(16,16), vec4(0,32*px,16*px,16*px), 0, 0 , 0); + launcher.renderer.draw(snake.texture, vec2(data.location[i].x*16,data.location[i].y*16), vec2(16,16), vec4(0,32*px,16*px,16*px), 0, uint.max, 0); } } } @@ -677,16 +677,16 @@ struct DrawSnakeSystem { final switch(cast(ubyte)part) { - case SnakePart.tail_up:launcher.renderer.draw(.snake.texture, cast(vec2)loc, vec2(16,16), vec4(16,112,16,16)*px, 0, 0, 0);break; - case SnakePart.tail_down:launcher.renderer.draw(.snake.texture, cast(vec2)loc, vec2(16,16), vec4(0,112,16,16)*px, 0, 0, 0);break; - case SnakePart.tail_left:launcher.renderer.draw(.snake.texture, cast(vec2)loc, vec2(16,16), vec4(32,112,16,16)*px, 0, 0, 0);break; - case SnakePart.tail_right:launcher.renderer.draw(.snake.texture, cast(vec2)loc, vec2(16,16), vec4(0,144,16,16)*px, 0, 0, 0);break; - case SnakePart.turn_ld:launcher.renderer.draw(.snake.texture, cast(vec2)loc, vec2(16,16), vec4(64,128,16,16)*px, 0, 0, 0);break; - case SnakePart.turn_lu:launcher.renderer.draw(.snake.texture, cast(vec2)loc, vec2(16,16), vec4(32,144,16,16)*px, 0, 0, 0);break; - case SnakePart.turn_rd:launcher.renderer.draw(.snake.texture, cast(vec2)loc, vec2(16,16), vec4(16,144,16,16)*px, 0, 0, 0);break; - case SnakePart.turn_ru:launcher.renderer.draw(.snake.texture, cast(vec2)loc, vec2(16,16), vec4(64,112,16,16)*px, 0, 0, 0);break; - case SnakePart.vertical:launcher.renderer.draw(.snake.texture, cast(vec2)loc, vec2(16,16), vec4(16,128,16,16)*px, 0, 0, 0);break; - case SnakePart.horizontal:launcher.renderer.draw(.snake.texture, cast(vec2)loc, vec2(16,16), vec4(48,128,16,16)*px, 0, 0, 0);break; + case SnakePart.tail_up:launcher.renderer.draw(.snake.texture, cast(vec2)loc, vec2(16,16), vec4(16,112,16,16)*px, 0, uint.max, 0);break; + case SnakePart.tail_down:launcher.renderer.draw(.snake.texture, cast(vec2)loc, vec2(16,16), vec4(0,112,16,16)*px, 0, uint.max, 0);break; + case SnakePart.tail_left:launcher.renderer.draw(.snake.texture, cast(vec2)loc, vec2(16,16), vec4(32,112,16,16)*px, 0, uint.max, 0);break; + case SnakePart.tail_right:launcher.renderer.draw(.snake.texture, cast(vec2)loc, vec2(16,16), vec4(0,144,16,16)*px, 0, uint.max, 0);break; + case SnakePart.turn_ld:launcher.renderer.draw(.snake.texture, cast(vec2)loc, vec2(16,16), vec4(64,128,16,16)*px, 0, uint.max, 0);break; + case SnakePart.turn_lu:launcher.renderer.draw(.snake.texture, cast(vec2)loc, vec2(16,16), vec4(32,144,16,16)*px, 0, uint.max, 0);break; + case SnakePart.turn_rd:launcher.renderer.draw(.snake.texture, cast(vec2)loc, vec2(16,16), vec4(16,144,16,16)*px, 0, uint.max, 0);break; + case SnakePart.turn_ru:launcher.renderer.draw(.snake.texture, cast(vec2)loc, vec2(16,16), vec4(64,112,16,16)*px, 0, uint.max, 0);break; + case SnakePart.vertical:launcher.renderer.draw(.snake.texture, cast(vec2)loc, vec2(16,16), vec4(16,128,16,16)*px, 0, uint.max, 0);break; + case SnakePart.horizontal:launcher.renderer.draw(.snake.texture, cast(vec2)loc, vec2(16,16), vec4(48,128,16,16)*px, 0, uint.max, 0);break; } } @@ -698,10 +698,10 @@ struct DrawSnakeSystem scope vec2 loc = cast(vec2)(data.location[i].location * 16); final switch(snake.direction) { - case CMovement.Direction.up:launcher.renderer.draw(.snake.texture, vec2(data.location[i].x*16,data.location[i].y*16), vec2(16,16), vec4(48,112,16,16)*px, 0, 0 , 0);break; - case CMovement.Direction.down:launcher.renderer.draw(.snake.texture, vec2(data.location[i].x*16,data.location[i].y*16), vec2(16,16), vec4(48,144,16,16)*px, 0, 0 , 0);break; - case CMovement.Direction.left:launcher.renderer.draw(.snake.texture, vec2(data.location[i].x*16,data.location[i].y*16), vec2(16,16), vec4(0,128,16,16)*px, 0, 0 , 0);break; - case CMovement.Direction.right:launcher.renderer.draw(.snake.texture, vec2(data.location[i].x*16,data.location[i].y*16), vec2(16,16), vec4(32,128,16,16)*px, 0, 0 , 0);break; + case CMovement.Direction.up:launcher.renderer.draw(.snake.texture, vec2(data.location[i].x*16,data.location[i].y*16), vec2(16,16), vec4(48,112,16,16)*px, 0, uint.max, 0);break; + case CMovement.Direction.down:launcher.renderer.draw(.snake.texture, vec2(data.location[i].x*16,data.location[i].y*16), vec2(16,16), vec4(48,144,16,16)*px, 0, uint.max, 0);break; + case CMovement.Direction.left:launcher.renderer.draw(.snake.texture, vec2(data.location[i].x*16,data.location[i].y*16), vec2(16,16), vec4(0,128,16,16)*px, 0, uint.max, 0);break; + case CMovement.Direction.right:launcher.renderer.draw(.snake.texture, vec2(data.location[i].x*16,data.location[i].y*16), vec2(16,16), vec4(32,128,16,16)*px, 0, uint.max, 0);break; } if(snake.parts.length >1) { diff --git a/demos/source/demos/space_invaders.d b/demos/source/demos/space_invaders.d index 6d86113..30891c8 100644 --- a/demos/source/demos/space_invaders.d +++ b/demos/source/demos/space_invaders.d @@ -183,6 +183,8 @@ struct CDepth { mixin ECS.Component; + alias depth this; + short depth; } @@ -208,23 +210,33 @@ struct EChangeDirection struct DrawSystem { - mixin ECS.System!1; + mixin ECS.System!32; struct EntitiesData { uint length; + uint thread_id; @readonly CTexture[] textures; @readonly CLocation[] locations; @readonly CScale[] scale; + @readonly @optional CDepth[] depth; } void onUpdate(EntitiesData data) { - foreach(i; 0..data.length) - { - launcher.renderer.draw(data.textures[i].tex, data.locations[i].value, data.scale[i], data.textures[i].coords, 0, 0 , 0); - //draw(renderer, data.textures[i].tex, data.locations[i], vec2(32,32), vec4(0,0,1,1)); - } + if(!data.depth) + foreach(i; 0..data.length) + { + launcher.renderer.draw(data.textures[i].tex, data.locations[i].value, data.scale[i], data.textures[i].coords, cast(short)data.locations[i].y, uint.max, 0, 0, 0, data.thread_id); + //draw(renderer, data.textures[i].tex, data.locations[i], vec2(32,32), vec4(0,0,1,1)); + } + else + foreach(i; 0..data.length) + { + launcher.renderer.draw(data.textures[i].tex, data.locations[i].value, data.scale[i], data.textures[i].coords, cast(short)(data.depth[i] * 64 + data.locations[i].y), uint.max, 0, 0, 0, data.thread_id); + //draw(renderer, data.textures[i].tex, data.locations[i], vec2(32,32), vec4(0,0,1,1)); + } + if(data.thread_id == 0)launcher.renderer.pushData(); } } diff --git a/demos/utils/source/ecs_utils/gfx/renderer.d b/demos/utils/source/ecs_utils/gfx/renderer.d index 8735d98..ba42cf6 100644 --- a/demos/utils/source/ecs_utils/gfx/renderer.d +++ b/demos/utils/source/ecs_utils/gfx/renderer.d @@ -11,8 +11,8 @@ import ecs_utils.math.vector; import bubel.ecs.block_allocator; import bubel.ecs.vector; - -import glad.gl.gl; +version(WebAssembly)import glad.gl.gles2; +else import glad.gl.gl; version = ver1; /*version(ver5)version = vv2; @@ -57,31 +57,105 @@ struct Renderer vec2 view_pos = vec2(-1,-1); vec2 view_size = vec2(1,1); - const uint batch_size = 16_384; + enum block_size = 2^^16; + enum batch_size = block_size/68;//963;//16_384; //uint[2] time_queries; struct VertexBlock { - float[] batch_vertices; + enum max_items = batch_size;//963; + byte[] batch_vertices; ushort[] batch_indices; void* memory; - uint itmes = 0; + uint items = 0; } + Mutex* get_block_mutex; + Mutex* block_stack_mutex; + VertexBlock getBlock() { VertexBlock block; + get_block_mutex.lock(); block.memory = allocator.getBlock(); - block.batch_vertices = (cast(float*)block.memory)[0 .. 1]; + get_block_mutex.unlock(); + block.batch_vertices = (cast(byte*)block.memory)[0 .. VertexBlock.max_items * 4 * 14]; + block.batch_indices = (cast(ushort*)block.memory)[VertexBlock.max_items * 4 * 7 .. VertexBlock.max_items * (4 * 7 + 6)]; return block; } + Vector!VertexBlock blocks; + uint current_block = 0; + uint render_blocks = 0; + + void pushBlock(VertexBlock block) + { + block_stack_mutex.lock(); + prepared_items += block.items; + blocks.add(block); + render_blocks++; + block_stack_mutex.unlock(); + } + + bool isRemainingBlocks() + { + if(render_blocks <= current_block)return false; + return true; + } + + VertexBlock fetchBlock() + { + block_stack_mutex.lock(); + VertexBlock block = blocks[current_block]; + current_block++; + block_stack_mutex.unlock(); + return block; + } + + void freeBlocks() + { + block_stack_mutex.lock(); + render_blocks = 0; + current_block = 0; + foreach(VertexBlock block; blocks) + { + allocator.freeBlock(block.memory); + } + blocks.clear; + prepared_items=0; + draw_list.clear(); + block_stack_mutex.unlock(); + } + + void pushData() + { + //if(!isRemainingBlocks())return; + while(isRemainingBlocks()) + { + VertexBlock block = fetchBlock(); + uint items = block.items; + if(items + item_id >= MaxObjects)items = MaxObjects - item_id; + batch_vbo[0].bufferSubData(Buffer.BindTarget.array,items*4*14,item_id*4*14,block.batch_vertices.ptr); + batch_ibo[0].bufferSubData(Buffer.BindTarget.element_array,items*2*6,item_id*2*6,block.batch_indices.ptr); + draw_list.add(DrawCall(item_id,items)); + item_id += items; + } + } + + void pushThreadsBlocks() + { + foreach(i, ref Thread thread; threads) + { + pushBlock(thread.block); + thread.block = getBlock(); + } + } struct Thread { - - Vector!VertexBlock block; + //Vector!VertexBlock block; RenderData[] render_list; + VertexBlock block; } Thread[] threads; @@ -102,7 +176,7 @@ struct Renderer Buffer[2] batch_vbo; Buffer[2] batch_ibo; - float[] batch_vertices; + ubyte[] batch_vertices; ushort[] batch_indices; Buffer indirect_buffer; @@ -121,8 +195,17 @@ struct Renderer uint mesh_id; } + struct DrawCall + { + uint start; + uint count; + } + + Vector!DrawCall draw_list; + RenderData[] render_list; uint item_id; + uint prepared_items; uint[] multi_count; uint[] multi_offset; @@ -140,6 +223,18 @@ struct Renderer { //this.technique = __ecs_used_technique; __initialize(this); + + get_block_mutex = Mallocator.make!Mutex(); + block_stack_mutex = Mallocator.make!Mutex(); + get_block_mutex.initialize(); + block_stack_mutex.initialize(); + + + threads = Mallocator.makeArray!Thread(12); + foreach(ref Thread thread;threads) + { + thread.block = getBlock(); + } } private static void __initialize_gl(ref Renderer this_) @@ -172,16 +267,16 @@ struct Renderer case Technique.vbo_batch: batch_vbo[0].create(); batch_ibo[0].create(); - batch_vbo[0].bufferData(Buffer.BindTarget.array,16,4*MaxObjects,BufferUsage,null); + batch_vbo[0].bufferData(Buffer.BindTarget.array,14,4*MaxObjects,BufferUsage,null); batch_ibo[0].bufferData(Buffer.BindTarget.element_array,2,6*MaxObjects,BufferUsage,null); batch_vbo[1].create(); batch_ibo[1].create(); - batch_vbo[1].bufferData(Buffer.BindTarget.array,16,4*MaxObjects,BufferUsage,null); + batch_vbo[1].bufferData(Buffer.BindTarget.array,14,4*MaxObjects,BufferUsage,null); batch_ibo[1].bufferData(Buffer.BindTarget.element_array,2,6*MaxObjects,BufferUsage,null); - batch_vertices = Mallocator.makeArray!float(16*MaxObjects); - batch_indices = Mallocator.makeArray!ushort(6*MaxObjects); + //batch_vertices = Mallocator.makeArray!ubyte(14*4*MaxObjects); + //batch_indices = Mallocator.makeArray!ushort(6*MaxObjects); break; case Technique.instanced_attrib_divisor: goto case(Technique.uniform_buffer_indexed); @@ -285,7 +380,7 @@ struct Renderer SDL_Log("Uniform block max size: %u",block_max_size); SDL_Log("Data offset: %u",data_offset); - allocator = BlockAllocator(1245184, 32); + allocator = BlockAllocator(block_size, 32); } } @@ -296,7 +391,7 @@ struct Renderer void draw(Texture tex, vec2 pos, vec2 size, vec4 coords, short depth = 0, uint color = uint.max, float angle = 0, uint material_id = 0, uint mesh_id = 0, uint thread_id = 0) { - if(item_id >= MaxObjects)return; + if(prepared_items >= MaxObjects)return; __draw(this,tex,pos,size,coords,depth,color,angle,material_id,mesh_id,thread_id); } @@ -364,12 +459,14 @@ struct Renderer data_index += data_offset; item_id++; + prepared_items++; } } private static void __draw_gl_vbo_batch(ref Renderer this_, Texture tex, vec2 pos, vec2 size, vec4 coords, short depth, uint color, float angle, uint material_id, uint mesh_id, uint thread_id = 0) { import ecs_utils.gfx.config; + short[3] mem = [depth, *cast(short*)&color, *(cast(short*)&color + 1)]; //import core.stdc.string; with(this_) { @@ -389,16 +486,37 @@ struct Renderer memcpy(ptr+16,pos.data.ptr,8); memcpy(ptr+32,coords.data.ptr,16);*/ + short[] verts = cast(short[])threads[thread_id].block.batch_vertices; + uint item_id = threads[thread_id].block.items; + if(angle == 0) { - batch_vertices[item_id*16] = GfxConfig.meshes[mesh_id].vertices[0] * size.x + pos.x; - batch_vertices[item_id*16+1] = GfxConfig.meshes[mesh_id].vertices[1] * size.y + pos.y; - batch_vertices[item_id*16+4] = GfxConfig.meshes[mesh_id].vertices[4] * size.x + pos.x; - batch_vertices[item_id*16+5] = GfxConfig.meshes[mesh_id].vertices[5] * size.y + pos.y; - batch_vertices[item_id*16+8] = GfxConfig.meshes[mesh_id].vertices[8] * size.x + pos.x; - batch_vertices[item_id*16+9] = GfxConfig.meshes[mesh_id].vertices[9] * size.y + pos.y; - batch_vertices[item_id*16+12] = GfxConfig.meshes[mesh_id].vertices[12] * size.x + pos.x; - batch_vertices[item_id*16+13] = GfxConfig.meshes[mesh_id].vertices[13] * size.y + pos.y; + verts[item_id*28] = cast(short)((GfxConfig.meshes[mesh_id].vertices[0] * size.x + pos.x) * 8191); + verts[item_id*28+1] = cast(short)((GfxConfig.meshes[mesh_id].vertices[1] * size.y + pos.y) * 8191); + verts[item_id*28+2] = cast(short)((GfxConfig.meshes[mesh_id].vertices[2] * coords.z + coords.x)*32767); + verts[item_id*28+3] = cast(short)((GfxConfig.meshes[mesh_id].vertices[3] * coords.w + coords.y)*32767); + memcpy(verts.ptr+item_id*28+4,mem.ptr,6); + + + verts[item_id*28+7] = cast(short)((GfxConfig.meshes[mesh_id].vertices[4] * size.x + pos.x) * 8191); + verts[item_id*28+8] = cast(short)((GfxConfig.meshes[mesh_id].vertices[5] * size.y + pos.y) * 8191); + verts[item_id*28+9] = cast(short)((GfxConfig.meshes[mesh_id].vertices[6] * coords.z + coords.x)*32767); + verts[item_id*28+10] = cast(short)((GfxConfig.meshes[mesh_id].vertices[7] * coords.w + coords.y)*32767); + memcpy(verts.ptr+item_id*28+11,mem.ptr,6); + + + verts[item_id*28+14] = cast(short)((GfxConfig.meshes[mesh_id].vertices[8] * size.x + pos.x) * 8191); + verts[item_id*28+15] = cast(short)((GfxConfig.meshes[mesh_id].vertices[9] * size.y + pos.y) * 8191); + verts[item_id*28+16] = cast(short)((GfxConfig.meshes[mesh_id].vertices[10] * coords.z + coords.x)*32767); + verts[item_id*28+17] = cast(short)((GfxConfig.meshes[mesh_id].vertices[11] * coords.w + coords.y)*32767); + memcpy(verts.ptr+item_id*28+18,mem.ptr,6); + + + verts[item_id*28+21] = cast(short)((GfxConfig.meshes[mesh_id].vertices[12] * size.x + pos.x) * 8191); + verts[item_id*28+22] = cast(short)((GfxConfig.meshes[mesh_id].vertices[13] * size.y + pos.y) * 8191); + verts[item_id*28+23] = cast(short)((GfxConfig.meshes[mesh_id].vertices[14] * coords.z + coords.x)*32767); + verts[item_id*28+24] = cast(short)((GfxConfig.meshes[mesh_id].vertices[15] * coords.w + coords.y)*32767); + memcpy(verts.ptr+item_id*28+25,mem.ptr,6); } else { @@ -406,50 +524,72 @@ struct Renderer float sinn = sinf(angle); float coss = cosf(angle); - /*batch_vertices[item_id*16] = GfxConfig.meshes[mesh_id].vertices[0] * size.x; - batch_vertices[item_id*16+1] = GfxConfig.meshes[mesh_id].vertices[1] * size.y; - batch_vertices[item_id*16+4] = GfxConfig.meshes[mesh_id].vertices[4] * size.x; - batch_vertices[item_id*16+5] = GfxConfig.meshes[mesh_id].vertices[5] * size.y; - batch_vertices[item_id*16+8] = GfxConfig.meshes[mesh_id].vertices[8] * size.x; - batch_vertices[item_id*16+9] = GfxConfig.meshes[mesh_id].vertices[9] * size.y; - batch_vertices[item_id*16+12] = GfxConfig.meshes[mesh_id].vertices[12] * size.x; - batch_vertices[item_id*16+13] = GfxConfig.meshes[mesh_id].vertices[13] * size.y;*/ + /*batch_vertices[item_id*28] = GfxConfig.meshes[mesh_id].vertices[0] * size.x; + batch_vertices[item_id*28+1] = GfxConfig.meshes[mesh_id].vertices[1] * size.y; + batch_vertices[item_id*28+4] = GfxConfig.meshes[mesh_id].vertices[4] * size.x; + batch_vertices[item_id*28+5] = GfxConfig.meshes[mesh_id].vertices[5] * size.y; + batch_vertices[item_id*28+8] = GfxConfig.meshes[mesh_id].vertices[8] * size.x; + batch_vertices[item_id*28+9] = GfxConfig.meshes[mesh_id].vertices[9] * size.y; + batch_vertices[item_id*28+12] = GfxConfig.meshes[mesh_id].vertices[12] * size.x; + batch_vertices[item_id*28+13] = GfxConfig.meshes[mesh_id].vertices[13] * size.y;*/ - batch_vertices[item_id*16] = (GfxConfig.meshes[mesh_id].vertices[0] * coss + GfxConfig.meshes[mesh_id].vertices[1] * sinn) * size.x + pos.x; - batch_vertices[item_id*16+1] = (GfxConfig.meshes[mesh_id].vertices[1] * coss - GfxConfig.meshes[mesh_id].vertices[0] * sinn) * size.y + pos.y; - batch_vertices[item_id*16+4] = (GfxConfig.meshes[mesh_id].vertices[4] * coss + GfxConfig.meshes[mesh_id].vertices[5] * sinn) * size.x + pos.x; - batch_vertices[item_id*16+5] = (GfxConfig.meshes[mesh_id].vertices[5] * coss - GfxConfig.meshes[mesh_id].vertices[4] * sinn) * size.y + pos.y; - batch_vertices[item_id*16+8] = (GfxConfig.meshes[mesh_id].vertices[8] * coss + GfxConfig.meshes[mesh_id].vertices[9] * sinn) * size.x + pos.x; - batch_vertices[item_id*16+9] = (GfxConfig.meshes[mesh_id].vertices[9] * coss - GfxConfig.meshes[mesh_id].vertices[8] * sinn) * size.y + pos.y; - batch_vertices[item_id*16+12] = (GfxConfig.meshes[mesh_id].vertices[12] * coss + GfxConfig.meshes[mesh_id].vertices[13] * sinn) * size.x + pos.x; - batch_vertices[item_id*16+13] = (GfxConfig.meshes[mesh_id].vertices[13] * coss - GfxConfig.meshes[mesh_id].vertices[12] * sinn) * size.y + pos.y; + verts[item_id*28] = cast(short)(((GfxConfig.meshes[mesh_id].vertices[0] * coss + GfxConfig.meshes[mesh_id].vertices[1] * sinn) * size.x + pos.x) * 8191); + verts[item_id*28+1] = cast(short)(((GfxConfig.meshes[mesh_id].vertices[1] * coss - GfxConfig.meshes[mesh_id].vertices[0] * sinn) * size.y + pos.y) * 8191); + verts[item_id*28+7] = cast(short)(((GfxConfig.meshes[mesh_id].vertices[4] * coss + GfxConfig.meshes[mesh_id].vertices[5] * sinn) * size.x + pos.x) * 8191); + verts[item_id*28+8] = cast(short)(((GfxConfig.meshes[mesh_id].vertices[5] * coss - GfxConfig.meshes[mesh_id].vertices[4] * sinn) * size.y + pos.y) * 8191); + verts[item_id*28+14] = cast(short)(((GfxConfig.meshes[mesh_id].vertices[8] * coss + GfxConfig.meshes[mesh_id].vertices[9] * sinn) * size.x + pos.x) * 8191); + verts[item_id*28+15] = cast(short)(((GfxConfig.meshes[mesh_id].vertices[9] * coss - GfxConfig.meshes[mesh_id].vertices[8] * sinn) * size.y + pos.y) * 8191); + verts[item_id*28+21] = cast(short)(((GfxConfig.meshes[mesh_id].vertices[12] * coss + GfxConfig.meshes[mesh_id].vertices[13] * sinn) * size.x + pos.x) * 8191); + verts[item_id*28+22] = cast(short)(((GfxConfig.meshes[mesh_id].vertices[13] * coss - GfxConfig.meshes[mesh_id].vertices[12] * sinn) * size.y + pos.y) * 8191); } - batch_vertices[item_id*16+2] = GfxConfig.meshes[mesh_id].vertices[2] * coords.z + coords.x; - batch_vertices[item_id*16+3] = GfxConfig.meshes[mesh_id].vertices[3] * coords.w + coords.y; - batch_vertices[item_id*16+6] = GfxConfig.meshes[mesh_id].vertices[6] * coords.z + coords.x; - batch_vertices[item_id*16+7] = GfxConfig.meshes[mesh_id].vertices[7] * coords.w + coords.y; - batch_vertices[item_id*16+10] = GfxConfig.meshes[mesh_id].vertices[10] * coords.z + coords.x; - batch_vertices[item_id*16+11] = GfxConfig.meshes[mesh_id].vertices[11] * coords.w + coords.y; - batch_vertices[item_id*16+14] = GfxConfig.meshes[mesh_id].vertices[14] * coords.z + coords.x; - batch_vertices[item_id*16+15] = GfxConfig.meshes[mesh_id].vertices[15] * coords.w + coords.y; + /*verts[item_id*28+2] = cast(short)((GfxConfig.meshes[mesh_id].vertices[2] * coords.z + coords.x)*32767); + verts[item_id*28+3] = cast(short)((GfxConfig.meshes[mesh_id].vertices[3] * coords.w + coords.y)*32767); + verts[item_id*28+9] = cast(short)((GfxConfig.meshes[mesh_id].vertices[6] * coords.z + coords.x)*32767); + verts[item_id*28+10] = cast(short)((GfxConfig.meshes[mesh_id].vertices[7] * coords.w + coords.y)*32767); + verts[item_id*28+16] = cast(short)((GfxConfig.meshes[mesh_id].vertices[10] * coords.z + coords.x)*32767); + verts[item_id*28+17] = cast(short)((GfxConfig.meshes[mesh_id].vertices[11] * coords.w + coords.y)*32767); + verts[item_id*28+23] = cast(short)((GfxConfig.meshes[mesh_id].vertices[14] * coords.z + coords.x)*32767); + verts[item_id*28+24] = cast(short)((GfxConfig.meshes[mesh_id].vertices[15] * coords.w + coords.y)*32767);*/ - uint ind_id = item_id % batch_size; + /*verts[item_id*28+4] = depth; + verts[item_id*28+11] = depth; + verts[item_id*28+18] = depth; + verts[item_id*28+25] = depth; - batch_indices[item_id*6] = cast(ushort)(GfxConfig.meshes[mesh_id].indices[0] + ind_id*4); - batch_indices[item_id*6+1] = cast(ushort)(GfxConfig.meshes[mesh_id].indices[1] + ind_id*4); - batch_indices[item_id*6+2] = cast(ushort)(GfxConfig.meshes[mesh_id].indices[2] + ind_id*4); - batch_indices[item_id*6+3] = cast(ushort)(GfxConfig.meshes[mesh_id].indices[3] + ind_id*4); - batch_indices[item_id*6+4] = cast(ushort)(GfxConfig.meshes[mesh_id].indices[4] + ind_id*4); - batch_indices[item_id*6+5] = cast(ushort)(GfxConfig.meshes[mesh_id].indices[5] + ind_id*4); + *cast(uint*)&verts[item_id*28+5] = color; + *cast(uint*)&verts[item_id*28+12] = color; + *cast(uint*)&verts[item_id*28+19] = color; + *cast(uint*)&verts[item_id*28+26] = color; + + memcpy(verts.ptr+item_id*28+4,mem.ptr,6); + memcpy(verts.ptr+item_id*28+11,mem.ptr,6); + memcpy(verts.ptr+item_id*28+18,mem.ptr,6); + memcpy(verts.ptr+item_id*28+25,mem.ptr,6);*/ + + uint ind_id = (item_id % batch_size)*4; + + ushort[] indices = threads[thread_id].block.batch_indices; + + indices[item_id*6] = cast(ushort)(GfxConfig.meshes[mesh_id].indices[0] + ind_id); + indices[item_id*6+1] = cast(ushort)(GfxConfig.meshes[mesh_id].indices[1] + ind_id); + indices[item_id*6+2] = cast(ushort)(GfxConfig.meshes[mesh_id].indices[2] + ind_id); + indices[item_id*6+3] = cast(ushort)(GfxConfig.meshes[mesh_id].indices[3] + ind_id); + indices[item_id*6+4] = cast(ushort)(GfxConfig.meshes[mesh_id].indices[4] + ind_id); + indices[item_id*6+5] = cast(ushort)(GfxConfig.meshes[mesh_id].indices[5] + ind_id); //render_list[item_id] = RenderData(tex,material_id,mesh_id); - render_list[item_id].texture = tex; - render_list[item_id].material_id = material_id; - render_list[item_id].mesh_id = mesh_id; + //render_list[item_id].texture = tex; + //render_list[item_id].material_id = material_id; + //render_list[item_id].mesh_id = mesh_id; //data_index += 1;//data_offset; - item_id++; + threads[thread_id].block.items++; + if(threads[thread_id].block.items >= VertexBlock.max_items) + { + pushBlock(threads[thread_id].block); + threads[thread_id].block = getBlock(); + } } } @@ -467,9 +607,22 @@ struct Renderer { glClearColor(0,0,0,0); glViewport(0,0,this_.resolution.x,this_.resolution.y); - glClear(GL_COLOR_BUFFER_BIT);// | GL_DEPTH_BUFFER_BIT); - glDisable(GL_DEPTH_TEST); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + //glDisable(GL_DEPTH_TEST); + glEnable(GL_DEPTH_TEST); glDisable(GL_CULL_FACE); + glDepthFunc(GL_LESS); + + version(WebAssembly) + { + glDepthRangef(0,1); + } + else + { + glDepthRange(0,1); + } + //glDepthRange(0,1); + //glClearDepth(1); } void present() @@ -484,6 +637,10 @@ struct Renderer private static void __present_gl(ref Renderer this_) { + + this_.pushThreadsBlocks(); + this_.pushData(); + glViewport(0,0,this_.resolution.x,this_.resolution.y); //glEnable(GL_ALPHA_TEST); //glAlphaFunc(GL_GREATER, 0.01); @@ -505,14 +662,17 @@ struct Renderer break; case Technique.vbo_batch: //if(data_index){ - batch_vbo[0].bufferSubData(Buffer.BindTarget.array,item_id*4*16,0,batch_vertices.ptr); - batch_ibo[0].bufferSubData(Buffer.BindTarget.element_array,item_id*6*2,0,batch_indices.ptr); + //batch_vbo[0].bufferSubData(Buffer.BindTarget.array,item_id*4*14,0,batch_vertices.ptr); + //batch_ibo[0].bufferSubData(Buffer.BindTarget.element_array,item_id*6*2,0,batch_indices.ptr); batch_vbo[0].bind(Buffer.BindTarget.array); batch_ibo[0].bind(Buffer.BindTarget.element_array); - glVertexAttribPointer(0,2,GL_FLOAT,false,16,null); - glVertexAttribPointer(1,2,GL_FLOAT,false,16,cast(void*)8);//} + //glVertexAttribPointer(0,2,GL_SHORT,true,14,null); + //glVertexAttribPointer(1,2,GL_SHORT,true,14,cast(void*)4);//} + glEnableVertexAttribArray(2); + glEnableVertexAttribArray(3); + //glVertexAttribPointer(2,1,GL_SHORT,true,14,cast(void*)6);//} break; case Technique.instanced_attrib_divisor: ubos[0].bufferSubData(Buffer.BindTarget.uniform,data_index,0,uniform_block.ptr); @@ -609,8 +769,8 @@ struct Renderer //glBeginQuery(GL_TIME_ELAPSED, time_queries[0]); if(technique == Technique.vbo_batch) { - uint items = item_id/batch_size+1; - foreach(i; 0..items) + //uint items = item_id/batch_size+1; + foreach(i; 0..draw_list.length) { if(material_id != render_list[i].material_id) { @@ -625,16 +785,20 @@ struct Renderer render_list[i].texture.bind(); } - uint instance_count = batch_size; + /*uint instance_count = batch_size; if((i+1)*batch_size > item_id) { instance_count = item_id%batch_size; - } + }*/ - glVertexAttribPointer(0,2,GL_FLOAT,false,16,cast(void*)(i*batch_size*4*16)); - glVertexAttribPointer(1,2,GL_FLOAT,false,16,cast(void*)(i*batch_size*4*16+8)); + // glVertexAttribPointer(0,2,GL_FLOAT,false,16,cast(void*)(i*batch_size*4*16)); + // glVertexAttribPointer(1,2,GL_FLOAT,false,16,cast(void*)(i*batch_size*4*16+8)); + glVertexAttribPointer(0,2,GL_SHORT,true,14,cast(void*)(draw_list[i].start*4*14)); + glVertexAttribPointer(1,2,GL_SHORT,true,14,cast(void*)(draw_list[i].start*4*14+4)); + glVertexAttribPointer(2,1,GL_SHORT,true,14,cast(void*)(draw_list[i].start*4*14+8)); + glVertexAttribPointer(3,4,GL_UNSIGNED_BYTE,true,14,cast(void*)(draw_list[i].start*4*14+10)); - glDrawElements(GL_TRIANGLES,instance_count*6,GL_UNSIGNED_SHORT,cast(void*)(i*batch_size*6*2)); + glDrawElements(GL_TRIANGLES,draw_list[i].count*6,GL_UNSIGNED_SHORT,cast(void*)(draw_list[i].start*6*2)); //glDrawElementsBaseVertex(GL_TRIANGLES,instance_count*6,GL_UNSIGNED_SHORT,cast(void*)(i*16_384*6*2),i*16_384*4); } @@ -817,6 +981,9 @@ struct Renderer } glDisableVertexAttribArray(0); glDisableVertexAttribArray(1); + glDisableVertexAttribArray(2); + glDisableVertexAttribArray(3); + this_.freeBlocks(); /*glUseProgram(0); glBindBuffer(GL_ARRAY_BUFFER, 0); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);*/ From b19fbb15288555ea94db39ea4e9504e933a8011f Mon Sep 17 00:00:00 2001 From: Mergul Date: Tue, 12 May 2020 12:30:21 +0200 Subject: [PATCH 124/217] Fixed shader compilation on WebAssembly --- demos/assets/shaders/base.vp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/demos/assets/shaders/base.vp b/demos/assets/shaders/base.vp index 7be086b..2777a24 100644 --- a/demos/assets/shaders/base.vp +++ b/demos/assets/shaders/base.vp @@ -92,10 +92,10 @@ LOC(1) ATT vec2 tex_coords; void main() { #ifdef VBO_BATCH - vec3 position = vec3(positions*4,1.0); + vec3 position = vec3(positions*4.0,1.0); uv = tex_coords; #else - vec3 position = mat3(matrix_1.x,matrix_1.y,0,matrix_1.z,matrix_1.w,0,matrix_2.xy,1) * vec3(positions,1.0); + vec3 position = mat3(matrix_1.x,matrix_1.y,0,matrix_1.z,matrix_1.w,0,matrix_2.xy,1.0) * vec3(positions,1.0); uv = tex_coords * uv_transform.zw + uv_transform.xy; #endif From 5e884352ba05c0bcbe2bf1db8429f5e9c11d247d Mon Sep 17 00:00:00 2001 From: Mergul Date: Tue, 12 May 2020 17:28:31 +0200 Subject: [PATCH 125/217] Add support for external depencencies --- source/bubel/ecs/core.d | 16 +++ source/bubel/ecs/manager.d | 143 ++++++++++++++++++- source/bubel/ecs/system.d | 3 + source/bubel/ecs/vector.d | 8 +- tests/basic.d | 275 +++++++++++++++++++++++++++++++++++++ 5 files changed, 440 insertions(+), 5 deletions(-) diff --git a/source/bubel/ecs/core.d b/source/bubel/ecs/core.d index ccdf3e2..0487665 100644 --- a/source/bubel/ecs/core.d +++ b/source/bubel/ecs/core.d @@ -92,4 +92,20 @@ static struct ECS { alias ExcludedComponents = T; } + + /************************************************************************************************************************ + Make list of readonly ependencies. This template get strings as arguments. Should be added inside System structure. + */ + mixin template ReadOnlyDependencies(T...) + { + alias ReadOnlyDependencies = T; + } + + /************************************************************************************************************************ + Make list of writable ependencies. This template get strings as arguments. Should be added inside System structure. + */ + mixin template WritableDependencies(T...) + { + alias WritableDependencies = T; + } } \ No newline at end of file diff --git a/source/bubel/ecs/manager.d b/source/bubel/ecs/manager.d index 1b896db..c1eb62a 100644 --- a/source/bubel/ecs/manager.d +++ b/source/bubel/ecs/manager.d @@ -452,6 +452,8 @@ export struct EntityManager uint excluded = 1; uint optional = 1; uint req = 1; + uint readonly_dep = 1; + uint writable_dep = 1; } static ComponentsCounts getComponentsCounts()() @@ -532,7 +534,22 @@ export struct EntityManager { components_counts.excluded++; } + } + } + static if (__traits(hasMember, Sys, "ReadOnlyDependencies")) + { + foreach (str; Sys.ReadOnlyDependencies) + { + components_counts.readonly_dep++; + } + } + + static if (__traits(hasMember, Sys, "WritableDependencies")) + { + foreach (str; Sys.WritableDependencies) + { + components_counts.writable_dep++; } } @@ -568,6 +585,16 @@ export struct EntityManager return m_req[0 .. m_req_counter]; } + CompInfo[] readonlyDeps() + { + return m_readonly_dep[0 .. m_readonly_dep_counter]; + } + + CompInfo[] writableDeps() + { + return m_writable_dep[0 .. m_writable_dep_counter]; + } + void addReadonly(CompInfo info) { m_readonly[m_readonly_counter++] = info; @@ -593,17 +620,31 @@ export struct EntityManager m_req[m_req_counter++] = info; } + void addReadonlyDep(CompInfo info) + { + m_readonly_dep[m_readonly_dep_counter++] = info; + } + + void addWritableDep(CompInfo info) + { + m_writable_dep[m_writable_dep_counter++] = info; + } + CompInfo[counts.readonly] m_readonly; CompInfo[counts.mutable] m_mutable; CompInfo[counts.excluded] m_excluded; CompInfo[counts.optional] m_optional; CompInfo[counts.req] m_req; + CompInfo[counts.readonly_dep] m_readonly_dep; + CompInfo[counts.writable_dep] m_writable_dep; uint m_readonly_counter; uint m_mutable_counter; uint m_excluded_counter; uint m_optional_counter; uint m_req_counter; + uint m_readonly_dep_counter; + uint m_writable_dep_counter; string entites_array; } @@ -616,6 +657,8 @@ export struct EntityManager size_t excluded = components_info.excluded.length; size_t read_only = components_info.readonly.length; size_t modified = components_info.mutable.length; + size_t read_only_deps = components_info.readonlyDeps.length; + size_t writable_deps = components_info.writableDeps.length; if (req > 0) system.m_components = Mallocator.makeArray!ushort(req); @@ -627,6 +670,10 @@ export struct EntityManager system.m_read_only_components = Mallocator.makeArray!ushort(read_only); if (modified > 0) system.m_modified_components = Mallocator.makeArray!ushort(modified); + if (read_only_deps > 0) + system.m_readonly_dependencies = Mallocator.makeArray!ushort(read_only_deps); + if (writable_deps > 0) + system.m_writable_dependencies = Mallocator.makeArray!ushort(writable_deps); } @@ -714,6 +761,22 @@ export struct EntityManager } } + static if (__traits(hasMember, Sys, "ReadOnlyDependencies")) + { + foreach (str; Sys.ReadOnlyDependencies) + { + components_info.addReadonlyDep(CompInfo(str, str)); + } + } + + static if (__traits(hasMember, Sys, "WritableDependencies")) + { + foreach (str; Sys.WritableDependencies) + { + components_info.addWritableDep(CompInfo(str, str)); + } + } + return components_info; } @@ -809,7 +872,6 @@ export struct EntityManager ~ "\" due to non existing component \"" ~ comp_info.type ~ "\"."); system.m_modified_components[iii] = comp; } - } static void fillInputData(ref Sys.EntitiesData input_data, EntityInfo* info, @@ -1059,6 +1121,32 @@ export struct EntityManager genCompList(system, components_map); + foreach (iii, comp_info; components_info.readonlyDeps) + { + ushort comp = external_dependencies_map.get(cast(const (char)[]) comp_info.type, ushort.max); + version (D_BetterC) + assert(comp != ushort.max, + "Can't register system \"" ~ Sys.stringof + ~ "\" due to non existing dependency."); + else + assert(comp != ushort.max, "Can't register system \"" ~ Sys.stringof + ~ "\" due to non existing dependency \"" ~ comp_info.type ~ "\"."); + system.m_readonly_dependencies[iii] = comp; + } + + foreach (iii, comp_info; components_info.writableDeps) + { + ushort comp = external_dependencies_map.get(cast(char[]) comp_info.type, ushort.max); + version (D_BetterC) + assert(comp != ushort.max, + "Can't register system \"" ~ Sys.stringof + ~ "\" due to non existing dependency."); + else + assert(comp != ushort.max, "Can't register system \"" ~ Sys.stringof + ~ "\" due to non existing dependency \"" ~ comp_info.type ~ "\"."); + system.m_writable_dependencies[iii] = comp; + } + ushort sys_id = systems_map.get(cast(char[]) Sys.stringof, ushort.max); if (sys_id < systems.length) { @@ -1118,6 +1206,11 @@ export struct EntityManager return cast(ushort)(passes.length - 1); } + export void registerDependency(const(char)[] name) + { + return external_dependencies_map.add(name, cast(ushort)external_dependencies_map.length); + } + /************************************************************************************************************************ Register component into EntityManager. */ @@ -2820,10 +2913,45 @@ export struct EntityManager foreach (caller; pass.system_callers) { index = 0; + ///gets systems which are excluding each other out_for: foreach (caller2; pass.system_callers) { if (caller is caller2) continue; + + ///check for external dependencies + foreach (cmp; caller.system.m_readonly_dependencies) + { + foreach (cmp2; caller2.system.m_writable_dependencies) + { + if (cmp == cmp2) + { + exclusion[index++] = caller2; + continue out_for; + } + } + } + foreach (cmp; caller.system.m_writable_dependencies) + { + foreach (cmp2; caller2.system.m_readonly_dependencies) + { + if (cmp == cmp2) + { + exclusion[index++] = caller2; + continue out_for; + } + } + foreach (cmp2; caller2.system.m_writable_dependencies) + { + if (cmp == cmp2) + { + exclusion[index++] = caller2; + continue out_for; + } + } + } + + ///check for component dependencies foreach (cmp; caller.system.m_read_only_components) { foreach (cmp2; caller2.system.m_modified_components) @@ -2923,6 +3051,18 @@ export struct EntityManager } } + const (UpdatePass)* getPass(const (char)[] name) + { + ushort id = getPassID(name); + if(id == ushort.max)return null; + return passes[id]; + } + + ushort getPassID(const (char)[] name) + { + return passes_map.get(name, ushort.max); + } + /************************************************************************************************************************ Component info; */ @@ -3350,6 +3490,7 @@ export struct EntityManager HashMap!(char[], ushort) components_map; HashMap!(const(char)[], ushort) events_map; HashMap!(const(char)[], ushort) passes_map; + HashMap!(const(char)[], ushort) external_dependencies_map; Vector!System systems; Vector!ComponentInfo components; Vector!EventInfo events; diff --git a/source/bubel/ecs/system.d b/source/bubel/ecs/system.d index 7343831..5bf750b 100644 --- a/source/bubel/ecs/system.d +++ b/source/bubel/ecs/system.d @@ -129,6 +129,9 @@ package: ushort[] m_read_only_components; ushort[] m_modified_components; + ushort[] m_readonly_dependencies; + ushort[] m_writable_dependencies; + EntityManager.SystemCaller* m_any_system_caller; EventCaller[] m_event_callers; diff --git a/source/bubel/ecs/vector.d b/source/bubel/ecs/vector.d index 3334be2..413bbce 100644 --- a/source/bubel/ecs/vector.d +++ b/source/bubel/ecs/vector.d @@ -62,11 +62,11 @@ public: used = 0; } - export bool empty() { + export bool empty() const { return (used == 0); } - export size_t length() { + export size_t length() const { return used; } @@ -197,9 +197,9 @@ public: assert(ok, "There is no such an element in vector"); } - export ref T opIndex(size_t elemNum) { + export ref T opIndex(size_t elemNum) const { //debug assert(elemNum < used, "Range violation [index]"); - return array.ptr[elemNum]; + return *cast(T*)&array.ptr[elemNum]; } export auto opSlice() { diff --git a/tests/basic.d b/tests/basic.d index 653575f..10d79b8 100644 --- a/tests/basic.d +++ b/tests/basic.d @@ -1220,4 +1220,279 @@ unittest assert(*entity2.getComponent!CInt == 13); gEM.end(); +} + +@("SystemDependencies") +unittest +{ + struct TestSystem + { + mixin ECS.System; + + struct EntitiesData + { + uint length; + @readonly CInt[] int_; + } + + void onUpdate(EntitiesData entities) + { + + } + } + + struct TestSystem2 + { + mixin ECS.System; + + struct EntitiesData + { + uint length; + CInt[] int_; + } + + void onUpdate(EntitiesData entities) + { + + } + } + + struct TestSystem3 + { + mixin ECS.System; + + struct EntitiesData + { + uint length; + @readonly CInt[] int_; + } + + void onUpdate(EntitiesData entities) + { + + } + } + + struct TestSystem4 + { + mixin ECS.System; + + struct EntitiesData + { + uint length; + CInt[] int_; + CLong[] long_; + } + + void onUpdate(EntitiesData entities) + { + + } + } + + struct TestSystem5 + { + mixin ECS.System; + + struct EntitiesData + { + uint length; + @readonly CLong[] int_; + } + + void onUpdate(EntitiesData entities) + { + + } + } + + void func1(TestSystem.EntitiesData entities) + { + foreach(i;0 .. entities.length) + { + entities.int_[i] += entities.int_[i] / 2; + } + } + + void func2(TestSystem.EntitiesData entities) + { + foreach(i;0 .. entities.length) + { + entities.int_[i] += 8; + } + } + + gEM.beginRegister(); + + gEM.registerSystem!TestSystem(0); + gEM.registerSystem!TestSystem2(1); + gEM.registerSystem!TestSystem3(2); + gEM.registerSystem!TestSystem4(3); + gEM.registerSystem!TestSystem5(4); + + gEM.endRegister(); + + const (EntityManager.UpdatePass)* pass = gEM.getPass("update"); + assert(pass != null); + assert(pass.system_callers.length == 5); + assert(pass.system_callers[0].system_id == TestSystem.system_id); + assert(pass.system_callers[1].system_id == TestSystem2.system_id); + assert(pass.system_callers[2].system_id == TestSystem3.system_id); + assert(pass.system_callers[3].system_id == TestSystem4.system_id); + assert(pass.system_callers[4].system_id == TestSystem5.system_id); + assert(pass.system_callers[0].dependencies.length == 0); + assert(pass.system_callers[1].dependencies.length == 1); + assert(pass.system_callers[2].dependencies.length == 1); + assert(pass.system_callers[3].dependencies.length == 3); + assert(pass.system_callers[4].dependencies.length == 1); + assert(pass.system_callers[1].dependencies[0].system_id == TestSystem.system_id); + assert(pass.system_callers[2].dependencies[0].system_id == TestSystem2.system_id); + assert(pass.system_callers[3].dependencies[0].system_id == TestSystem.system_id); + assert(pass.system_callers[3].dependencies[1].system_id == TestSystem2.system_id); + assert(pass.system_callers[3].dependencies[2].system_id == TestSystem3.system_id); + assert(pass.system_callers[4].dependencies[0].system_id == TestSystem4.system_id); +} + +@("ExternalSystemDependencies") +unittest +{ + enum TestDependency = "TestDepencency"; + + struct TestSystem + { + mixin ECS.System; + + mixin ECS.ReadOnlyDependencies!(TestDependency); + + struct EntitiesData + { + uint length; + @readonly CInt[] int_; + } + + void onUpdate(EntitiesData entities) + { + + } + } + + struct TestSystem2 + { + mixin ECS.System; + + mixin ECS.WritableDependencies!(TestDependency); + + struct EntitiesData + { + uint length; + @readonly CInt[] int_; + } + + void onUpdate(EntitiesData entities) + { + + } + } + + struct TestSystem3 + { + mixin ECS.System; + + mixin ECS.ReadOnlyDependencies!(TestDependency); + + struct EntitiesData + { + uint thread_id; + } + + void onUpdate(EntitiesData entities) + { + + } + } + + struct TestSystem4 + { + mixin ECS.System; + + mixin ECS.WritableDependencies!(TestDependency); + + struct EntitiesData + { + uint length; + @readonly CInt[] int_; + } + + void onUpdate(EntitiesData entities) + { + + } + } + + struct TestSystem5 + { + mixin ECS.System; + + mixin ECS.ReadOnlyDependencies!(TestDependency); + + struct EntitiesData + { + uint length; + @readonly CLong[] int_; + } + + void onUpdate(EntitiesData entities) + { + + } + } + + void func1(TestSystem.EntitiesData entities) + { + foreach(i;0 .. entities.length) + { + entities.int_[i] += entities.int_[i] / 2; + } + } + + void func2(TestSystem.EntitiesData entities) + { + foreach(i;0 .. entities.length) + { + entities.int_[i] += 8; + } + } + + gEM.beginRegister(); + + gEM.registerDependency(TestDependency); + + gEM.registerSystem!TestSystem(0); + gEM.registerSystem!TestSystem2(1); + gEM.registerSystem!TestSystem3(2); + gEM.registerSystem!TestSystem4(3); + gEM.registerSystem!TestSystem5(4); + + gEM.endRegister(); + + const (EntityManager.UpdatePass)* pass = gEM.getPass("update"); + assert(pass != null); + assert(pass.system_callers.length == 5); + assert(pass.system_callers[0].system_id == TestSystem.system_id); + assert(pass.system_callers[1].system_id == TestSystem2.system_id); + assert(pass.system_callers[2].system_id == TestSystem3.system_id); + assert(pass.system_callers[3].system_id == TestSystem4.system_id); + assert(pass.system_callers[4].system_id == TestSystem5.system_id); + assert(pass.system_callers[0].dependencies.length == 0); + assert(pass.system_callers[1].dependencies.length == 1); + assert(pass.system_callers[2].dependencies.length == 1); + assert(pass.system_callers[3].dependencies.length == 3); + assert(pass.system_callers[4].dependencies.length == 2); + assert(pass.system_callers[1].dependencies[0].system_id == TestSystem.system_id); + assert(pass.system_callers[2].dependencies[0].system_id == TestSystem2.system_id); + assert(pass.system_callers[3].dependencies[0].system_id == TestSystem.system_id); + assert(pass.system_callers[3].dependencies[1].system_id == TestSystem2.system_id); + assert(pass.system_callers[3].dependencies[2].system_id == TestSystem3.system_id); + assert(pass.system_callers[4].dependencies[0].system_id == TestSystem2.system_id); + assert(pass.system_callers[4].dependencies[1].system_id == TestSystem4.system_id); } \ No newline at end of file From 1b925b7ab190be050012262d2dffcd03188b662a Mon Sep 17 00:00:00 2001 From: Mergul Date: Tue, 12 May 2020 17:30:57 +0200 Subject: [PATCH 126/217] Change component name from "modified" to "writable" --- source/bubel/ecs/manager.d | 18 +++++++++--------- source/bubel/ecs/system.d | 2 +- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/source/bubel/ecs/manager.d b/source/bubel/ecs/manager.d index c1eb62a..15d1f6e 100644 --- a/source/bubel/ecs/manager.d +++ b/source/bubel/ecs/manager.d @@ -104,8 +104,8 @@ export struct EntityManager Mallocator.dispose(system.jobs); if (system.m_read_only_components) Mallocator.dispose(system.m_read_only_components); - if (system.m_modified_components) - Mallocator.dispose(system.m_modified_components); + if (system.m_writable_components) + Mallocator.dispose(system.m_writable_components); if (system.m_components) Mallocator.dispose(system.m_components); if (system.m_excluded_components) @@ -656,7 +656,7 @@ export struct EntityManager size_t opt = components_info.optional.length; size_t excluded = components_info.excluded.length; size_t read_only = components_info.readonly.length; - size_t modified = components_info.mutable.length; + size_t writable = components_info.mutable.length; size_t read_only_deps = components_info.readonlyDeps.length; size_t writable_deps = components_info.writableDeps.length; @@ -668,8 +668,8 @@ export struct EntityManager system.m_excluded_components = Mallocator.makeArray!ushort(excluded); if (read_only > 0) system.m_read_only_components = Mallocator.makeArray!ushort(read_only); - if (modified > 0) - system.m_modified_components = Mallocator.makeArray!ushort(modified); + if (writable > 0) + system.m_writable_components = Mallocator.makeArray!ushort(writable); if (read_only_deps > 0) system.m_readonly_dependencies = Mallocator.makeArray!ushort(read_only_deps); if (writable_deps > 0) @@ -870,7 +870,7 @@ export struct EntityManager else assert(comp != ushort.max, "Can't register system \"" ~ Sys.stringof ~ "\" due to non existing component \"" ~ comp_info.type ~ "\"."); - system.m_modified_components[iii] = comp; + system.m_writable_components[iii] = comp; } } @@ -2954,7 +2954,7 @@ export struct EntityManager ///check for component dependencies foreach (cmp; caller.system.m_read_only_components) { - foreach (cmp2; caller2.system.m_modified_components) + foreach (cmp2; caller2.system.m_writable_components) { if (cmp == cmp2) { @@ -2963,7 +2963,7 @@ export struct EntityManager } } } - foreach (cmp; caller.system.m_modified_components) + foreach (cmp; caller.system.m_writable_components) { foreach (cmp2; caller2.system.m_read_only_components) { @@ -2973,7 +2973,7 @@ export struct EntityManager continue out_for; } } - foreach (cmp2; caller2.system.m_modified_components) + foreach (cmp2; caller2.system.m_writable_components) { if (cmp == cmp2) { diff --git a/source/bubel/ecs/system.d b/source/bubel/ecs/system.d index 5bf750b..7bcaf01 100644 --- a/source/bubel/ecs/system.d +++ b/source/bubel/ecs/system.d @@ -127,7 +127,7 @@ package: //System*[] m_dependencies; ushort[] m_read_only_components; - ushort[] m_modified_components; + ushort[] m_writable_components; ushort[] m_readonly_dependencies; ushort[] m_writable_dependencies; From 9580ee9af9fd40b32651488e3882843f306fff7e Mon Sep 17 00:00:00 2001 From: Mergul Date: Tue, 12 May 2020 18:21:25 +0200 Subject: [PATCH 127/217] Add bullets collision system to SpaceInvaders demo --- demos/source/demos/space_invaders.d | 252 ++++++++++++++++++++++++++-- 1 file changed, 236 insertions(+), 16 deletions(-) diff --git a/demos/source/demos/space_invaders.d b/demos/source/demos/space_invaders.d index 30891c8..004a3eb 100644 --- a/demos/source/demos/space_invaders.d +++ b/demos/source/demos/space_invaders.d @@ -16,10 +16,14 @@ import ecs_utils.gfx.texture; import ecs_utils.math.vector; import ecs_utils.utils; +import std.array : staticArray; + enum float px = 1.0/512.0; extern(C): +enum ShootGridDependency = "ShootGridDependency"; + /*####################################################################################################################### ------------------------------------------------ Types ------------------------------------------------------------------ #######################################################################################################################*/ @@ -33,11 +37,18 @@ struct SpaceInvaders EntityTemplate* laser_tmpl; Texture texture; + ShootGrid* shoot_grid; + bool move_system = true; bool draw_system = true; const vec2 map_size = vec2(400,300); const float cell_size = 60; + + ~this() @nogc nothrow + { + if(shoot_grid)Mallocator.dispose(shoot_grid); + } } struct SceneGrid @@ -147,7 +158,7 @@ struct CGuild { mixin ECS.Component; - int guild; + byte guild; } struct CLaser @@ -188,6 +199,11 @@ struct CDepth short depth; } +struct CShootGrid +{ + mixin ECS.Component; +} + /*####################################################################################################################### ------------------------------------------------ Events ------------------------------------------------------------------ #######################################################################################################################*/ @@ -208,6 +224,158 @@ struct EChangeDirection ------------------------------------------------ Systems ------------------------------------------------------------------ #######################################################################################################################*/ +struct ShootGrid +{ + + ~this() @nogc nothrow + { + if(nodes)Mallocator.dispose(nodes); + if(masks)Mallocator.dispose(masks); + } + + struct Node + { + alias entity this; + + EntityID entity; + } + + void create(ivec2 nodes_count, vec2 node_size) + { + this.size = nodes_count; + this.node_size = node_size; + inv_node_size = vec2(1.0/node_size.x, 1.0/node_size.y); + nodes = Mallocator.makeArray!Node(nodes_count.x * nodes_count.y); + masks = Mallocator.makeArray!ubyte(nodes.length); + } + + void mark(EntityID id, vec2 beg, vec2 end, byte mask) + { + ivec2 ibeg = cast(ivec2)(beg * inv_node_size); + ivec2 iend = cast(ivec2)((end * inv_node_size) + 0.5); + if(ibeg.x < 0)ibeg.x = 0; + if(ibeg.y < 0)ibeg.y = 0; + if(iend.x > size.x)iend.x = size.x; + if(iend.y > size.y)iend.y = size.y; + foreach(i; ibeg.y .. iend.y) + { + foreach(j; ibeg.x .. iend.x) + { + nodes[i * size.x + j] = id; + masks[i * size.x +j] = mask; + } + } + } + + void clear() + { + size_t size = nodes.length * EntityID.sizeof; + memset(nodes.ptr, 0, size); + memset(masks.ptr, 0, masks.length); + } + + bool test(out EntityID id, vec2 beg, vec2 end) + { + ivec2 ibeg = cast(ivec2)(beg * inv_node_size); + ivec2 iend = cast(ivec2)((end * inv_node_size) + 0.5); + if(ibeg.x < 0)ibeg.x = 0; + if(ibeg.y < 0)ibeg.y = 0; + if(iend.x > size.x)iend.x = size.x; + if(iend.y > size.y)iend.y = size.y; + foreach(i; ibeg.y .. iend.y) + { + foreach(j; ibeg.x .. iend.x) + { + if(nodes[i * size.x + j].id != 0) + { + id = nodes[i * size.x + j]; + return true; + } + } + } + return false; + } + + bool test(out EntityID id, vec2 pos, ubyte mask) + { + ivec2 ipos = cast(ivec2)(pos * inv_node_size - 0.5); + if(ipos.x < 0)ipos.x = 0; + if(ipos.y < 0)ipos.y = 0; + if(ipos.x >= size.x)ipos.x = size.x - 1; + if(ipos.y >= size.y)ipos.y = size.y - 1; + size_t index = ipos.y * size.x + ipos.x; + if((masks[index] & mask) == 0)return false; + if(nodes[index].id != 0) + { + id = nodes[index]; + return true; + } + return false; + } + + vec2 inv_node_size; + ivec2 size; + vec2 node_size; + Node[] nodes; + ubyte[] masks; +} + +struct ShootGridCleaner +{ + mixin ECS.System!1; + + struct EntitiesData + { + + } + + void onUpdate(EntitiesData data) + { + if(space_invaders.shoot_grid)space_invaders.shoot_grid.clear(); + } +} + +struct ShootGridManager +{ + mixin ECS.System!32; + + mixin ECS.WritableDependencies!(ShootGridDependency); + + struct EntitiesData + { + uint length; + uint thread_id; + const (Entity)[] entity; + @readonly CLocation[] locations; + @readonly CScale[] scale; + @readonly CShootGrid[] grid_flag; + @readonly CGuild[] guild; + } + + ShootGrid* grid; + + void onCreate() + { + grid = space_invaders.shoot_grid; + } + + bool onBegin() + { + if(!grid)return false; + //grid.clear(); + return true; + } + + void onUpdate(EntitiesData data) + { + foreach(i; 0..data.length) + { + vec2 half_scale = data.scale[i] * 0.5; + grid.mark(data.entity[i].id, data.locations[i] - half_scale, data.locations[i] + half_scale, cast(ubyte)(1 << data.guild[i].guild)); + } + } +} + struct DrawSystem { mixin ECS.System!32; @@ -260,10 +428,11 @@ struct LaserShootingSystem mixin ECS.System!32; bool shoot = false; - float[10] laser_shoot_times = [2000,1500,1000,700,500,300,100,50,10,1]; + static float[10] laser_shoot_times = [2000,1500,1000,700,500,300,100,50,10,1]; CLocation* laser_location; CVelocity* laser_velocity; + CGuild* laser_guild; struct EntitiesData { @@ -272,6 +441,7 @@ struct LaserShootingSystem @readonly CShootDirection[] shoot_direction; @readonly @optional CAutoShoot[] auto_shoot; @readonly CLocation[] location; + @readonly CGuild[] guild; CLaserWeapon[] laser; } @@ -285,6 +455,7 @@ struct LaserShootingSystem { laser_location = space_invaders.laser_tmpl.getComponent!CLocation; laser_velocity = space_invaders.laser_tmpl.getComponent!CVelocity; + laser_guild = space_invaders.laser_tmpl.getComponent!CGuild; if(launcher.getKeyState(SDL_SCANCODE_SPACE)) { shoot = true; @@ -307,6 +478,7 @@ struct LaserShootingSystem laser.shoot_time -= laser_shoot_times[laser.level - 1]; laser_location.value = data.location[i]; laser_velocity.value = vec2(randomf()*0.5-0.25,data.shoot_direction[i].direction == Direction.up ? 1.0 : -1.0); + laser_guild.guild = data.guild[i].guild; launcher.manager.addEntity(space_invaders.laser_tmpl); } } @@ -324,6 +496,36 @@ struct LaserShootingSystem } } +struct LaserCollisionSystem +{ + mixin ECS.System!32; + + mixin ECS.ReadOnlyDependencies!(ShootGridDependency); + + struct EntitiesData + { + ///variable named "length" contain entites count + uint length; + const (Entity)[] entity; + @readonly CLocation[] location; + @readonly CLaser[] laser; + @readonly CGuild[] guild; + } + + void onUpdate(EntitiesData data) + { + EntityID id; + foreach(i; 0..data.length) + { + if(space_invaders.shoot_grid.test(id, data.location[i], cast(ubyte)(~(1 << data.guild[i].guild)))) + { + launcher.manager.removeEntity(data.entity[i].id); + } + } + } + +} + struct ChangeDirectionSystem { mixin ECS.System!32; @@ -591,6 +793,8 @@ struct MovementSystem } } +import core.stdc.math; + /** *System is responsible for movement of objects with CInput component. *In this example every entity has same speed when using movement system. @@ -620,22 +824,24 @@ struct InputMovementSystem move_vector = vec2(0,0); if(launcher.getKeyState(SDL_SCANCODE_W)) { - move_vector = vec2(0,1); - return true; + move_vector += vec2(0,1); } else if(launcher.getKeyState(SDL_SCANCODE_S)) { - move_vector = vec2(0,-1); - return true; + move_vector += vec2(0,-1); } - else if(launcher.getKeyState(SDL_SCANCODE_A)) + if(launcher.getKeyState(SDL_SCANCODE_A)) { - move_vector = vec2(-1,0); - return true; + move_vector += vec2(-1,0); } else if(launcher.getKeyState(SDL_SCANCODE_D)) { - move_vector = vec2(1,0); + move_vector += vec2(1,0); + } + + if(move_vector.x != 0 ||move_vector.y != 0) + { + move_vector = move_vector / sqrtf(move_vector.x * move_vector.x + move_vector.y * move_vector.y); return true; } //don't call system update because no key pressed @@ -682,6 +888,9 @@ void spaceInvadersStart() space_invaders.texture.create(); space_invaders.texture.load("assets/textures/atlas.png"); + space_invaders.shoot_grid = Mallocator.make!ShootGrid; + space_invaders.shoot_grid.create(ivec2(80,60), vec2(5,5)); + launcher.manager.beginRegister(); launcher.manager.registerComponent!CLocation; @@ -696,16 +905,22 @@ void spaceInvadersStart() launcher.manager.registerComponent!CVelocity; launcher.manager.registerComponent!CLaser; launcher.manager.registerComponent!CSideMove; + launcher.manager.registerComponent!CDepth; + launcher.manager.registerComponent!CShootGrid; + launcher.manager.registerComponent!CGuild; launcher.manager.registerEvent!EChangeDirection; //launcher.manager.registerSystem!MoveSystem(0); launcher.manager.registerSystem!DrawSystem(100); launcher.manager.registerSystem!InputMovementSystem(-100); + launcher.manager.registerSystem!MovementSystem(-99); + launcher.manager.registerSystem!ClampPositionSystem(-90); launcher.manager.registerSystem!LaserShootingSystem(0); - launcher.manager.registerSystem!MovementSystem(0); - launcher.manager.registerSystem!ClampPositionSystem(1); launcher.manager.registerSystem!ChangeDirectionSystem(0); + launcher.manager.registerSystem!LaserCollisionSystem(-70); + launcher.manager.registerSystem!ShootGridManager(-80); + launcher.manager.registerSystem!ShootGridCleaner(-101); launcher.manager.endRegister(); @@ -718,7 +933,7 @@ void spaceInvadersStart() //launcher.manager.getSystem(CleanSystem.system_id).disable(); { - ushort[7] components = [CLocation.component_id, CTexture.component_id, CInput.component_id, CShip.component_id, CScale.component_id, CLaserWeapon.component_id, CShootDirection.component_id]; + ushort[9] components = [CLocation.component_id, CTexture.component_id, CInput.component_id, CShip.component_id, CScale.component_id, CLaserWeapon.component_id, CShootDirection.component_id, CShootGrid.component_id, CGuild.component_id]; space_invaders.ship_tmpl = launcher.manager.allocateTemplate(components); CScale* scale_comp = space_invaders.ship_tmpl.getComponent!CScale; @@ -735,7 +950,7 @@ void spaceInvadersStart() } { - ushort[5] components = [CLocation.component_id, CTexture.component_id, CVelocity.component_id, CScale.component_id, CLaser.component_id]; + ushort[6] components = [CLocation.component_id, CTexture.component_id, CVelocity.component_id, CScale.component_id, CLaser.component_id, CGuild.component_id]; space_invaders.laser_tmpl = launcher.manager.allocateTemplate(components); CTexture* tex_comp = space_invaders.laser_tmpl.getComponent!CTexture; @@ -753,7 +968,7 @@ void spaceInvadersStart() EntityID grouped_id; { - ushort[8] components = [CVelocity.component_id, CAutoShoot.component_id, CLocation.component_id, CTexture.component_id, CScale.component_id, CLaserWeapon.component_id, CEnemy.component_id, CShootDirection.component_id];//, CVelocity.component_id]; + ushort[10] components = [CVelocity.component_id, CAutoShoot.component_id, CLocation.component_id, CTexture.component_id, CScale.component_id, CLaserWeapon.component_id, CEnemy.component_id, CShootDirection.component_id, CShootGrid.component_id, CGuild.component_id]; space_invaders.enemy_tmpl = launcher.manager.allocateTemplate(components); CTexture* tex_comp = space_invaders.enemy_tmpl.getComponent!CTexture; @@ -765,6 +980,7 @@ void spaceInvadersStart() shoot_dir_comp.direction = Direction.down; CVelocity* vel_comp = space_invaders.enemy_tmpl.getComponent!CVelocity; vel_comp.value = vec2(0.1,0); + space_invaders.enemy_tmpl.getComponent!CGuild().guild = 1; Entity* current_entity; @@ -802,7 +1018,6 @@ void spaceInvadersStart() void spaceInvadersEnd() { - launcher.manager.getSystem(DrawSystem.system_id).disable(); launcher.manager.getSystem(InputMovementSystem.system_id).disable(); launcher.manager.getSystem(LaserShootingSystem.system_id).disable(); @@ -827,6 +1042,11 @@ void spaceInvadersTool(vec2 position, Tool tool, int size) position.y += (randomf - 0.5) * size; *location = position; } + CLaserWeapon* laser_weapon = tmpl.getComponent!CLaserWeapon; + if(laser_weapon) + { + laser_weapon.shoot_time = randomf * LaserShootingSystem.laser_shoot_times[laser_weapon.level - 1]; + } launcher.manager.addEntity(tmpl); } break; From dd491302afa388e86e7ad5b2a4a5af502a28431b Mon Sep 17 00:00:00 2001 From: Mergul Date: Wed, 13 May 2020 15:31:26 +0200 Subject: [PATCH 128/217] Fixed system reregistration issue and added funtion to allocate EntityTEmplate as copy of different teamplte --- source/bubel/ecs/manager.d | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/source/bubel/ecs/manager.d b/source/bubel/ecs/manager.d index 15d1f6e..c6b02a1 100644 --- a/source/bubel/ecs/manager.d +++ b/source/bubel/ecs/manager.d @@ -1150,17 +1150,22 @@ export struct EntityManager ushort sys_id = systems_map.get(cast(char[]) Sys.stringof, ushort.max); if (sys_id < systems.length) { - system.enable(); + systems[sys_id].disable(); + if(systems[sys_id].m_destroy)(cast(void function(void*)) systems[sys_id].m_destroy)(systems[sys_id].m_system_pointer); if (system.m_create) (cast(void function(void*)) system.m_create)(system.m_system_pointer); + system.enable(); + system.m_id = sys_id; + system.m_name = systems[sys_id].m_name; systems[sys_id] = system; } else { system.m_name = Mallocator.makeArray(cast(char[]) Sys.stringof); + systems_map.add(system.m_name, cast(ushort) systems.length); system.m_id = cast(ushort)(systems.length); @@ -1723,6 +1728,20 @@ export struct EntityManager return temp; } + /************************************************************************************************************************ + Allocate EntityTemplate copy. + + Params: + copy_tmpl = template which should be copied + */ + export EntityTemplate* allocateTemplate(EntityTemplate* copy_tmpl) + { + EntityTemplate* tmpl = Mallocator.make!EntityTemplate; + tmpl.info = copy_tmpl.info; + tmpl.entity_data = Mallocator.makeArray(copy_tmpl.entity_data); + return tmpl; + } + /************************************************************************************************************************ Returns entity type info. @@ -2344,7 +2363,7 @@ export struct EntityManager Params: template_ = pointer entity template allocated by EntityManager. */ - export void freeTemplate(EntityTemplate* template_) + export void freeTemplate(EntityTemplate* template_) @nogc nothrow { Mallocator.dispose(template_.entity_data); Mallocator.dispose(template_); From 3647fa4b867ff7b4a0c0ecf5829c8b7bd23bb369 Mon Sep 17 00:00:00 2001 From: Mergul Date: Wed, 13 May 2020 15:34:24 +0200 Subject: [PATCH 129/217] Demos update -added functionality to detect host CPU threads count -fixed some memory leaks -now textures free memory corectly -added support for up to 32 threads --- demos/external/sources/mmutils/thread_pool.d | 40 ++++++++++++++++++++ demos/source/app.d | 34 ++++++++++++++--- demos/source/demos/snake.d | 16 ++++++-- demos/source/demos/space_invaders.d | 17 ++++++--- demos/utils/source/ecs_utils/gfx/renderer.d | 2 +- demos/utils/source/ecs_utils/gfx/texture.d | 5 ++- 6 files changed, 98 insertions(+), 16 deletions(-) diff --git a/demos/external/sources/mmutils/thread_pool.d b/demos/external/sources/mmutils/thread_pool.d index 143960c..48d2932 100644 --- a/demos/external/sources/mmutils/thread_pool.d +++ b/demos/external/sources/mmutils/thread_pool.d @@ -810,6 +810,46 @@ private: JobData[4] resumeJobs; /// Dummu jobs to resume some thread public: + + static int getCPUCoresCount() + { + version(Windows) + { + import core.sys.windows.winbase : SYSTEM_INFO, GetSystemInfo; + SYSTEM_INFO sysinfo; + GetSystemInfo(&sysinfo); + return sysinfo.dwNumberOfProcessors; + } + else version (linux) + { + version(D_BetterC) + { + import core.sys.posix.unistd : _SC_NPROCESSORS_ONLN, sysconf; + return cast(int)sysconf(_SC_NPROCESSORS_ONLN); + } + else + { + import core.sys.linux.sched : CPU_COUNT, cpu_set_t, sched_getaffinity; + import core.sys.posix.unistd : _SC_NPROCESSORS_ONLN, sysconf; + + cpu_set_t set = void; + if (sched_getaffinity(0, cpu_set_t.sizeof, &set) == 0) + { + int count = CPU_COUNT(&set); + if (count > 0) + return cast(uint) count; + } + return cast(int)sysconf(_SC_NPROCESSORS_ONLN); + } + } + else version(Posix) + { + import core.sys.posix.unistd; + return cast(int)sysconf(_SC_NPROCESSORS_ONLN); + } + else return -1; + } + int jobsDoneCount() { int sum; diff --git a/demos/source/app.d b/demos/source/app.d index af4b331..10fc80e 100644 --- a/demos/source/app.d +++ b/demos/source/app.d @@ -58,7 +58,7 @@ struct Launcher uint style = 3; uint entities_count; bool multithreading; - int threads; + int threads = 1; ulong timer_freq; double delta_time; uint fps; @@ -103,6 +103,14 @@ struct Launcher manager.update("clean"); manager.end(); + foreach(system; manager.systems) + { + if(system.id != CountSystem.system_id && system.id != CleanSystem.system_id)system.disable(); + } + + /*launcher.manager.getSystem(CountSystem.system_id).enable(); + launcher.manager.getSystem(CleanSystem.system_id).enable();//*/ + if(start)start(); this.loop = loop; this.end = end; @@ -316,11 +324,19 @@ void mainLoop(void* arg) if(igMenuItemBool("Multithreading", null, launcher.multithreading, true)) { launcher.multithreading = !launcher.multithreading; + if(launcher.multithreading) + { + launcher.job_updater.pool.setThreadsNum(launcher.threads); + } + else + { + launcher.job_updater.pool.setThreadsNum(1); + } } igSetNextItemWidth(0); igLabelText("Threads:",null); igSameLine(0,4); - if(igSliderInt("##Threads",&launcher.threads, 1, 12, null))//"Multithreading", null, launcher.multithreading, true)) + if(igSliderInt("##Threads",&launcher.threads, 1, 32, null))//"Multithreading", null, launcher.multithreading, true)) { launcher.job_updater.pool.setThreadsNum(launcher.threads); //launcher.threads = !launcher.multithreading; @@ -547,13 +563,13 @@ void mainLoop(void* arg) launcher.renderer.clear(); double loop_time = launcher.getTime(); - launcher.job_updater.pool.tryWaitCount = 5000; + launcher.job_updater.pool.tryWaitCount = 10000; if(launcher.loop && !launcher.loop()) { quit(); *cast(bool*)arg = false; } - launcher.job_updater.pool.tryWaitCount = 10; + launcher.job_updater.pool.tryWaitCount = 0; loop_time = launcher.getTime() - loop_time; @@ -697,10 +713,10 @@ int main(int argc, char** argv) setStyle(3); - launcher.job_updater = Mallocator.make!ECSJobUpdater(12); + launcher.job_updater = Mallocator.make!ECSJobUpdater(1); //launcher.job_updater.onCreate(); - EntityManager.initialize(12); + EntityManager.initialize(32); launcher.manager = EntityManager.instance; //launcher.manager.m_thread_id_func = &launcher.job_updater.getThreadID; @@ -720,6 +736,10 @@ int main(int argc, char** argv) launcher.renderer.initialize(); + import mmutils.thread_pool : ThreadPool; + launcher.threads = ThreadPool.getCPUCoresCount(); + if(launcher.threads < 2)launcher.threads = 2; + launcher.gui_manager = Mallocator.make!GUIManager(); { @@ -752,6 +772,8 @@ int main(int argc, char** argv) } } + EntityManager.destroy(); + return 0; } diff --git a/demos/source/demos/snake.d b/demos/source/demos/snake.d index 94f2654..ecaefd3 100644 --- a/demos/source/demos/snake.d +++ b/demos/source/demos/snake.d @@ -90,6 +90,16 @@ struct Snake MapElement[map_size * map_size] map; + ~this() @nogc nothrow + { + if(snake_destroy_particle_frames)Mallocator.dispose(snake_destroy_particle_frames); + if(smoke_frames)Mallocator.dispose(smoke_frames); + if(apple_tmpl)launcher.manager.freeTemplate(apple_tmpl); + if(snake_tmpl)launcher.manager.freeTemplate(snake_tmpl); + if(snake_destroy_particle)launcher.manager.freeTemplate(snake_destroy_particle); + texture.destory(); + } + MapElement element(ivec2 pos) { uint index = pos.x + pos.y * map_size; @@ -805,9 +815,9 @@ void snakeStart() snake.addApple(); } - launcher.gui_manager.addTemplate(snake.snake_tmpl, "Snake"); - launcher.gui_manager.addTemplate(snake.apple_tmpl, "Apple"); - launcher.gui_manager.addTemplate(snake.snake_destroy_particle, "Particle"); + launcher.gui_manager.addTemplate(launcher.manager.allocateTemplate(snake.snake_tmpl), "Snake"); + launcher.gui_manager.addTemplate(launcher.manager.allocateTemplate(snake.apple_tmpl), "Apple"); + launcher.gui_manager.addTemplate(launcher.manager.allocateTemplate(snake.snake_destroy_particle), "Particle"); MoveSystem* move_system = launcher.manager.getSystem!MoveSystem(); move_system.setTemplates(); diff --git a/demos/source/demos/space_invaders.d b/demos/source/demos/space_invaders.d index 004a3eb..b6fe80d 100644 --- a/demos/source/demos/space_invaders.d +++ b/demos/source/demos/space_invaders.d @@ -48,6 +48,10 @@ struct SpaceInvaders ~this() @nogc nothrow { if(shoot_grid)Mallocator.dispose(shoot_grid); + launcher.manager.freeTemplate(enemy_tmpl); + launcher.manager.freeTemplate(ship_tmpl); + launcher.manager.freeTemplate(laser_tmpl); + texture.destory(); } } @@ -337,7 +341,7 @@ struct ShootGridCleaner struct ShootGridManager { - mixin ECS.System!32; + mixin ECS.System!128; mixin ECS.WritableDependencies!(ShootGridDependency); @@ -793,7 +797,7 @@ struct MovementSystem } } -import core.stdc.math; +extern(C) float sqrtf(float x) @nogc nothrow @system; /** *System is responsible for movement of objects with CInput component. @@ -893,6 +897,8 @@ void spaceInvadersStart() launcher.manager.beginRegister(); + launcher.manager.registerDependency(ShootGridDependency); + launcher.manager.registerComponent!CLocation; launcher.manager.registerComponent!CTexture; launcher.manager.registerComponent!CInput; @@ -1009,10 +1015,10 @@ void spaceInvadersStart() enemy_tmpl = launcher.manager.allocateTemplate(enemy_id); grouped_tmpl = launcher.manager.allocateTemplate(grouped_id); - launcher.gui_manager.addTemplate(space_invaders.ship_tmpl,"Ship"); + launcher.gui_manager.addTemplate(launcher.manager.allocateTemplate(space_invaders.ship_tmpl),"Ship"); launcher.gui_manager.addTemplate(enemy_tmpl,"Enemy"); launcher.gui_manager.addTemplate(grouped_tmpl,"Grouped enemy"); - launcher.gui_manager.addTemplate(space_invaders.laser_tmpl,"Laser"); + launcher.gui_manager.addTemplate(launcher.manager.allocateTemplate(space_invaders.laser_tmpl),"Laser"); } @@ -1023,8 +1029,9 @@ void spaceInvadersEnd() launcher.manager.getSystem(LaserShootingSystem.system_id).disable(); launcher.manager.getSystem(MovementSystem.system_id).disable(); launcher.manager.getSystem(ClampPositionSystem.system_id).disable(); + launcher.manager.getSystem(ShootGridCleaner.system_id).disable(); - launcher.manager.freeTemplate(space_invaders.enemy_tmpl); + //launcher.manager.freeTemplate(space_invaders.enemy_tmpl); Mallocator.dispose(space_invaders); } diff --git a/demos/utils/source/ecs_utils/gfx/renderer.d b/demos/utils/source/ecs_utils/gfx/renderer.d index ba42cf6..206364f 100644 --- a/demos/utils/source/ecs_utils/gfx/renderer.d +++ b/demos/utils/source/ecs_utils/gfx/renderer.d @@ -230,7 +230,7 @@ struct Renderer block_stack_mutex.initialize(); - threads = Mallocator.makeArray!Thread(12); + threads = Mallocator.makeArray!Thread(32); foreach(ref Thread thread;threads) { thread.block = getBlock(); diff --git a/demos/utils/source/ecs_utils/gfx/texture.d b/demos/utils/source/ecs_utils/gfx/texture.d index 05e2fd9..d4e2089 100644 --- a/demos/utils/source/ecs_utils/gfx/texture.d +++ b/demos/utils/source/ecs_utils/gfx/texture.d @@ -54,6 +54,8 @@ struct Texture data.data = Mallocator.makeArray!ubyte(surf.w*surf.h*surf.format.BytesPerPixel); data.data[0..$] = (cast(ubyte*)surf.pixels)[0..data.data.length]; + SDL_FreeSurface(surf); + glGenTextures(1, &data.gl_handle); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D,data.gl_handle); @@ -78,11 +80,12 @@ struct Texture glBindTexture(GL_TEXTURE_2D, data.gl_handle); } - void destory() + void destory() @nogc nothrow { if(data) { glDeleteTextures(1, &data.gl_handle); + if(data.data)Mallocator.dispose(data.data); Mallocator.dispose(data); data = null; } From d257a6c9f83acc660ddff5383b4ce45730663702 Mon Sep 17 00:00:00 2001 From: Mergul Date: Wed, 13 May 2020 16:24:32 +0200 Subject: [PATCH 130/217] Updated codecov.yml --- codecov.yml | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/codecov.yml b/codecov.yml index a6afdbc..f3e0d9b 100644 --- a/codecov.yml +++ b/codecov.yml @@ -1,3 +1,12 @@ ignore: - "tests/*" - - "**/traits*" \ No newline at end of file + - "**/traits*" + +coverage: + status: + project: + default: + threshold: 5 + patch: + default: + threshold: 5 \ No newline at end of file From c29ace661bde8b132248c44d810a716de741c608 Mon Sep 17 00:00:00 2001 From: Mergul Date: Wed, 13 May 2020 21:27:09 +0200 Subject: [PATCH 131/217] Added laser collision response to SpaceInvaders --- demos/assets/shaders/base.vp | 2 +- demos/source/demos/simple.d | 2 +- demos/source/demos/snake.d | 32 +++---- demos/source/demos/space_invaders.d | 124 +++++++++++++++++++++++++--- 4 files changed, 131 insertions(+), 29 deletions(-) diff --git a/demos/assets/shaders/base.vp b/demos/assets/shaders/base.vp index 2777a24..b054d8e 100644 --- a/demos/assets/shaders/base.vp +++ b/demos/assets/shaders/base.vp @@ -99,7 +99,7 @@ void main() { uv = tex_coords * uv_transform.zw + uv_transform.xy; #endif - color = vcolor; + color = vcolor * 2; gl_Position = vec4(position.xy,depth,1.0); diff --git a/demos/source/demos/simple.d b/demos/source/demos/simple.d index 686f9be..1668323 100644 --- a/demos/source/demos/simple.d +++ b/demos/source/demos/simple.d @@ -62,7 +62,7 @@ struct DrawSystem if(launcher.renderer.prepared_items >= launcher.renderer.MaxObjects)return;//simple leave loop if max visible objects count was reached foreach(i; 0..data.length) { - launcher.renderer.draw(data.textures[i].tex, data.locations[i].location, vec2(16,16), vec4(0,0,1,1), cast(ushort)(data.locations[i].y*64+data.locations[i].x), uint.max, 0, 0, 0, data.thread_id); + launcher.renderer.draw(data.textures[i].tex, data.locations[i].location, vec2(16,16), vec4(0,0,1,1), cast(ushort)(data.locations[i].y*64+data.locations[i].x), 0x80808080, 0, 0, 0, data.thread_id); //draw(renderer, data.textures[i].tex, data.locations[i], vec2(32,32), vec4(0,0,1,1)); } if(data.thread_id == 0)launcher.renderer.pushData(); diff --git a/demos/source/demos/snake.d b/demos/source/demos/snake.d index ecaefd3..244e5ec 100644 --- a/demos/source/demos/snake.d +++ b/demos/source/demos/snake.d @@ -356,7 +356,7 @@ struct AnimationRenderSystem { foreach(i;0..data.length) { - launcher.renderer.draw(snake.texture, cast(vec2)cast(ivec2)data.location[i].location, vec2(16,16), data.animation[i].frames[cast(int)(data.animation[i].time)], 0, 0 , 0); + launcher.renderer.draw(snake.texture, cast(vec2)cast(ivec2)data.location[i].location, vec2(16,16), data.animation[i].frames[cast(int)(data.animation[i].time)], -1, 0x80808080); } } } @@ -617,7 +617,7 @@ struct DrawAppleSystem { foreach(i; 0..data.location.length) { - launcher.renderer.draw(snake.texture, vec2(data.location[i].x*16,data.location[i].y*16), vec2(16,16), vec4(0,32*px,16*px,16*px), 0, uint.max, 0); + launcher.renderer.draw(snake.texture, vec2(data.location[i].x*16,data.location[i].y*16), vec2(16,16), vec4(0,32*px,16*px,16*px), 0, 0x80808080, 0); } } } @@ -687,16 +687,16 @@ struct DrawSnakeSystem { final switch(cast(ubyte)part) { - case SnakePart.tail_up:launcher.renderer.draw(.snake.texture, cast(vec2)loc, vec2(16,16), vec4(16,112,16,16)*px, 0, uint.max, 0);break; - case SnakePart.tail_down:launcher.renderer.draw(.snake.texture, cast(vec2)loc, vec2(16,16), vec4(0,112,16,16)*px, 0, uint.max, 0);break; - case SnakePart.tail_left:launcher.renderer.draw(.snake.texture, cast(vec2)loc, vec2(16,16), vec4(32,112,16,16)*px, 0, uint.max, 0);break; - case SnakePart.tail_right:launcher.renderer.draw(.snake.texture, cast(vec2)loc, vec2(16,16), vec4(0,144,16,16)*px, 0, uint.max, 0);break; - case SnakePart.turn_ld:launcher.renderer.draw(.snake.texture, cast(vec2)loc, vec2(16,16), vec4(64,128,16,16)*px, 0, uint.max, 0);break; - case SnakePart.turn_lu:launcher.renderer.draw(.snake.texture, cast(vec2)loc, vec2(16,16), vec4(32,144,16,16)*px, 0, uint.max, 0);break; - case SnakePart.turn_rd:launcher.renderer.draw(.snake.texture, cast(vec2)loc, vec2(16,16), vec4(16,144,16,16)*px, 0, uint.max, 0);break; - case SnakePart.turn_ru:launcher.renderer.draw(.snake.texture, cast(vec2)loc, vec2(16,16), vec4(64,112,16,16)*px, 0, uint.max, 0);break; - case SnakePart.vertical:launcher.renderer.draw(.snake.texture, cast(vec2)loc, vec2(16,16), vec4(16,128,16,16)*px, 0, uint.max, 0);break; - case SnakePart.horizontal:launcher.renderer.draw(.snake.texture, cast(vec2)loc, vec2(16,16), vec4(48,128,16,16)*px, 0, uint.max, 0);break; + case SnakePart.tail_up:launcher.renderer.draw(.snake.texture, cast(vec2)loc, vec2(16,16), vec4(16,112,16,16)*px, 0, 0x80808080, 0);break; + case SnakePart.tail_down:launcher.renderer.draw(.snake.texture, cast(vec2)loc, vec2(16,16), vec4(0,112,16,16)*px, 0, 0x80808080, 0);break; + case SnakePart.tail_left:launcher.renderer.draw(.snake.texture, cast(vec2)loc, vec2(16,16), vec4(32,112,16,16)*px, 0, 0x80808080, 0);break; + case SnakePart.tail_right:launcher.renderer.draw(.snake.texture, cast(vec2)loc, vec2(16,16), vec4(0,144,16,16)*px, 0, 0x80808080, 0);break; + case SnakePart.turn_ld:launcher.renderer.draw(.snake.texture, cast(vec2)loc, vec2(16,16), vec4(64,128,16,16)*px, 0, 0x80808080, 0);break; + case SnakePart.turn_lu:launcher.renderer.draw(.snake.texture, cast(vec2)loc, vec2(16,16), vec4(32,144,16,16)*px, 0, 0x80808080, 0);break; + case SnakePart.turn_rd:launcher.renderer.draw(.snake.texture, cast(vec2)loc, vec2(16,16), vec4(16,144,16,16)*px, 0, 0x80808080, 0);break; + case SnakePart.turn_ru:launcher.renderer.draw(.snake.texture, cast(vec2)loc, vec2(16,16), vec4(64,112,16,16)*px, 0, 0x80808080, 0);break; + case SnakePart.vertical:launcher.renderer.draw(.snake.texture, cast(vec2)loc, vec2(16,16), vec4(16,128,16,16)*px, 0, 0x80808080, 0);break; + case SnakePart.horizontal:launcher.renderer.draw(.snake.texture, cast(vec2)loc, vec2(16,16), vec4(48,128,16,16)*px, 0, 0x80808080, 0);break; } } @@ -708,10 +708,10 @@ struct DrawSnakeSystem scope vec2 loc = cast(vec2)(data.location[i].location * 16); final switch(snake.direction) { - case CMovement.Direction.up:launcher.renderer.draw(.snake.texture, vec2(data.location[i].x*16,data.location[i].y*16), vec2(16,16), vec4(48,112,16,16)*px, 0, uint.max, 0);break; - case CMovement.Direction.down:launcher.renderer.draw(.snake.texture, vec2(data.location[i].x*16,data.location[i].y*16), vec2(16,16), vec4(48,144,16,16)*px, 0, uint.max, 0);break; - case CMovement.Direction.left:launcher.renderer.draw(.snake.texture, vec2(data.location[i].x*16,data.location[i].y*16), vec2(16,16), vec4(0,128,16,16)*px, 0, uint.max, 0);break; - case CMovement.Direction.right:launcher.renderer.draw(.snake.texture, vec2(data.location[i].x*16,data.location[i].y*16), vec2(16,16), vec4(32,128,16,16)*px, 0, uint.max, 0);break; + case CMovement.Direction.up:launcher.renderer.draw(.snake.texture, vec2(data.location[i].x*16,data.location[i].y*16), vec2(16,16), vec4(48,112,16,16)*px, 0, 0x80808080, 0);break; + case CMovement.Direction.down:launcher.renderer.draw(.snake.texture, vec2(data.location[i].x*16,data.location[i].y*16), vec2(16,16), vec4(48,144,16,16)*px, 0, 0x80808080, 0);break; + case CMovement.Direction.left:launcher.renderer.draw(.snake.texture, vec2(data.location[i].x*16,data.location[i].y*16), vec2(16,16), vec4(0,128,16,16)*px, 0, 0x80808080, 0);break; + case CMovement.Direction.right:launcher.renderer.draw(.snake.texture, vec2(data.location[i].x*16,data.location[i].y*16), vec2(16,16), vec4(32,128,16,16)*px, 0, 0x80808080, 0);break; } if(snake.parts.length >1) { diff --git a/demos/source/demos/space_invaders.d b/demos/source/demos/space_invaders.d index b6fe80d..f4e2848 100644 --- a/demos/source/demos/space_invaders.d +++ b/demos/source/demos/space_invaders.d @@ -208,6 +208,24 @@ struct CShootGrid mixin ECS.Component; } +struct CHitPoints +{ + mixin ECS.Component; + + alias value this; + + int value = 10; +} + +struct CHitMark +{ + mixin ECS.Component; + + alias value this; + + ubyte value = 0; +} + /*####################################################################################################################### ------------------------------------------------ Events ------------------------------------------------------------------ #######################################################################################################################*/ @@ -224,6 +242,18 @@ struct EChangeDirection Direction direction; } +struct EDamage +{ + mixin ECS.Event; + + this(uint damage) + { + this.damage = damage; + } + + uint damage = 0; +} + /*####################################################################################################################### ------------------------------------------------ Systems ------------------------------------------------------------------ #######################################################################################################################*/ @@ -392,22 +422,47 @@ struct DrawSystem @readonly CLocation[] locations; @readonly CScale[] scale; @readonly @optional CDepth[] depth; + @readonly @optional CHitMark[] hit_mark; } void onUpdate(EntitiesData data) { if(!data.depth) - foreach(i; 0..data.length) + { + if(data.hit_mark) { - launcher.renderer.draw(data.textures[i].tex, data.locations[i].value, data.scale[i], data.textures[i].coords, cast(short)data.locations[i].y, uint.max, 0, 0, 0, data.thread_id); - //draw(renderer, data.textures[i].tex, data.locations[i], vec2(32,32), vec4(0,0,1,1)); + foreach(i; 0..data.length) + { + uint color = 0x80808080 + 0x01010101 * data.hit_mark[i]; + launcher.renderer.draw(data.textures[i].tex, data.locations[i].value, data.scale[i], data.textures[i].coords, cast(short)data.locations[i].y, color, 0, 0, 0, data.thread_id); + } } + else + { + foreach(i; 0..data.length) + { + launcher.renderer.draw(data.textures[i].tex, data.locations[i].value, data.scale[i], data.textures[i].coords, cast(short)data.locations[i].y, 0x80808080, 0, 0, 0, data.thread_id); + } + } + } else - foreach(i; 0..data.length) + { + if(data.hit_mark) { - launcher.renderer.draw(data.textures[i].tex, data.locations[i].value, data.scale[i], data.textures[i].coords, cast(short)(data.depth[i] * 64 + data.locations[i].y), uint.max, 0, 0, 0, data.thread_id); - //draw(renderer, data.textures[i].tex, data.locations[i], vec2(32,32), vec4(0,0,1,1)); + foreach(i; 0..data.length) + { + uint color = 0x80808080 + 0x01010101 * data.hit_mark[i]; + launcher.renderer.draw(data.textures[i].tex, data.locations[i].value, data.scale[i], data.textures[i].coords, cast(short)(data.depth[i] * 64 + data.locations[i].y), color, 0, 0, 0, data.thread_id); + } } + else + { + foreach(i; 0..data.length) + { + launcher.renderer.draw(data.textures[i].tex, data.locations[i].value, data.scale[i], data.textures[i].coords, cast(short)(data.depth[i] * 64 + data.locations[i].y), 0x80808080, 0, 0, 0, data.thread_id); + } + } + } if(data.thread_id == 0)launcher.renderer.pushData(); } } @@ -432,7 +487,7 @@ struct LaserShootingSystem mixin ECS.System!32; bool shoot = false; - static float[10] laser_shoot_times = [2000,1500,1000,700,500,300,100,50,10,1]; + static float[22] laser_shoot_times = [2000,1500,1000,700,500,350,250,170,130,80,50,25,15,10,5,2.5,2,1,0.8,0.5,0.3,0.1]; CLocation* laser_location; CVelocity* laser_velocity; @@ -523,6 +578,7 @@ struct LaserCollisionSystem { if(space_invaders.shoot_grid.test(id, data.location[i], cast(ubyte)(~(1 << data.guild[i].guild)))) { + launcher.manager.sendEvent(id, EDamage(1)); launcher.manager.removeEntity(data.entity[i].id); } } @@ -666,7 +722,7 @@ struct ChangeDirectionSystem } } - void handleEvent(Entity* entity, EChangeDirection event) + /*void handleEvent(Entity* entity, EChangeDirection event) { CSideMove* side_move = entity.getComponent!CSideMove; if(side_move && side_move.group != -1) @@ -691,6 +747,46 @@ struct ChangeDirectionSystem if(velocity.value.x < 0)velocity.value.x = -velocity.value.x; break; } + }*/ +} + +struct HitMarkingSystem +{ + mixin ECS.System!16; + + struct EntitiesData + { + uint length; + CHitMark[] mark; + } + + void onUpdate(EntitiesData data) + { + foreach(i;0..data.length) + { + //if(data.mark[i] < 10)data.mark[i] = 0; + //else data.mark[i] -= 1; + data.mark[i] = cast(ubyte)(data.mark[i] * 0.9); + } + } +} + +struct HitPointsSystem +{ + mixin ECS.System; + + struct EntitiesData + { + CHitPoints[] hp; + } + + void handleEvent(Entity* entity, EDamage event) + { + CHitPoints* hp = entity.getComponent!CHitPoints; + *hp -= event.damage; + if(*hp < 0)launcher.manager.removeEntity(entity.id); + CHitMark* hit_mark = entity.getComponent!CHitMark; + if(hit_mark)hit_mark.value = 127; } } @@ -914,8 +1010,11 @@ void spaceInvadersStart() launcher.manager.registerComponent!CDepth; launcher.manager.registerComponent!CShootGrid; launcher.manager.registerComponent!CGuild; + launcher.manager.registerComponent!CHitPoints; + launcher.manager.registerComponent!CHitMark; launcher.manager.registerEvent!EChangeDirection; + launcher.manager.registerEvent!EDamage; //launcher.manager.registerSystem!MoveSystem(0); launcher.manager.registerSystem!DrawSystem(100); @@ -927,6 +1026,8 @@ void spaceInvadersStart() launcher.manager.registerSystem!LaserCollisionSystem(-70); launcher.manager.registerSystem!ShootGridManager(-80); launcher.manager.registerSystem!ShootGridCleaner(-101); + launcher.manager.registerSystem!HitPointsSystem(0); + launcher.manager.registerSystem!HitMarkingSystem(-100); launcher.manager.endRegister(); @@ -939,7 +1040,7 @@ void spaceInvadersStart() //launcher.manager.getSystem(CleanSystem.system_id).disable(); { - ushort[9] components = [CLocation.component_id, CTexture.component_id, CInput.component_id, CShip.component_id, CScale.component_id, CLaserWeapon.component_id, CShootDirection.component_id, CShootGrid.component_id, CGuild.component_id]; + ushort[11] components = [CHitMark.component_id, CHitPoints.component_id, CLocation.component_id, CTexture.component_id, CInput.component_id, CShip.component_id, CScale.component_id, CLaserWeapon.component_id, CShootDirection.component_id, CShootGrid.component_id, CGuild.component_id]; space_invaders.ship_tmpl = launcher.manager.allocateTemplate(components); CScale* scale_comp = space_invaders.ship_tmpl.getComponent!CScale; @@ -950,7 +1051,8 @@ void spaceInvadersStart() CLocation* loc_comp = space_invaders.ship_tmpl.getComponent!CLocation; loc_comp.value = vec2(64,64); CLaserWeapon* weapon = space_invaders.ship_tmpl.getComponent!CLaserWeapon; - weapon.level = 10; + weapon.level = 22; + space_invaders.ship_tmpl.getComponent!CHitPoints().value = 1000; launcher.manager.addEntity(space_invaders.ship_tmpl); } @@ -974,7 +1076,7 @@ void spaceInvadersStart() EntityID grouped_id; { - ushort[10] components = [CVelocity.component_id, CAutoShoot.component_id, CLocation.component_id, CTexture.component_id, CScale.component_id, CLaserWeapon.component_id, CEnemy.component_id, CShootDirection.component_id, CShootGrid.component_id, CGuild.component_id]; + ushort[12] components = [CHitMark.component_id, CHitPoints.component_id, CVelocity.component_id, CAutoShoot.component_id, CLocation.component_id, CTexture.component_id, CScale.component_id, CLaserWeapon.component_id, CEnemy.component_id, CShootDirection.component_id, CShootGrid.component_id, CGuild.component_id]; space_invaders.enemy_tmpl = launcher.manager.allocateTemplate(components); CTexture* tex_comp = space_invaders.enemy_tmpl.getComponent!CTexture; From d26c940b80608ab64cbd18413ae1b71f05c08c15 Mon Sep 17 00:00:00 2001 From: Mergul Date: Wed, 13 May 2020 21:30:56 +0200 Subject: [PATCH 132/217] Fixed shader compilation on GLES --- demos/assets/shaders/base.vp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/demos/assets/shaders/base.vp b/demos/assets/shaders/base.vp index b054d8e..6c4c183 100644 --- a/demos/assets/shaders/base.vp +++ b/demos/assets/shaders/base.vp @@ -99,7 +99,7 @@ void main() { uv = tex_coords * uv_transform.zw + uv_transform.xy; #endif - color = vcolor * 2; + color = vcolor * 2.0; gl_Position = vec4(position.xy,depth,1.0); From f731b4cedb1f9f6b408a555312a18eed7bcae3ee Mon Sep 17 00:00:00 2001 From: Mergul Date: Wed, 13 May 2020 21:51:38 +0200 Subject: [PATCH 133/217] Added Upgrade bonuses to SpaceInvaders demo --- demos/source/demos/space_invaders.d | 82 ++++++++++++++++++++++++++++- 1 file changed, 80 insertions(+), 2 deletions(-) diff --git a/demos/source/demos/space_invaders.d b/demos/source/demos/space_invaders.d index f4e2848..1c5b3e4 100644 --- a/demos/source/demos/space_invaders.d +++ b/demos/source/demos/space_invaders.d @@ -226,6 +226,11 @@ struct CHitMark ubyte value = 0; } +struct CUpgrade +{ + mixin ECS.Component; +} + /*####################################################################################################################### ------------------------------------------------ Events ------------------------------------------------------------------ #######################################################################################################################*/ @@ -242,6 +247,11 @@ struct EChangeDirection Direction direction; } +struct EUpgrade +{ + mixin ECS.Event; +} + struct EDamage { mixin ECS.Event; @@ -487,7 +497,7 @@ struct LaserShootingSystem mixin ECS.System!32; bool shoot = false; - static float[22] laser_shoot_times = [2000,1500,1000,700,500,350,250,170,130,80,50,25,15,10,5,2.5,2,1,0.8,0.5,0.3,0.1]; + static float[18] laser_shoot_times = [500,400,300,200,100,50,25,10,5,2,1,0.8,0.6,0.5,0.4,0.3,0.2,0.1]; CLocation* laser_location; CVelocity* laser_velocity; @@ -583,7 +593,55 @@ struct LaserCollisionSystem } } } +} +struct UpgradeCollisionSystem +{ + mixin ECS.System!32; + + mixin ECS.ReadOnlyDependencies!(ShootGridDependency); + + struct EntitiesData + { + ///variable named "length" contain entites count + uint length; + const (Entity)[] entity; + @readonly CLocation[] location; + @readonly CUpgrade[] upgrade; + } + + void onUpdate(EntitiesData data) + { + EntityID id; + foreach(i; 0..data.length) + { + if(space_invaders.shoot_grid.test(id, data.location[i], cast(ubyte)(0xFF))) + { + launcher.manager.sendEvent(id, EUpgrade()); + launcher.manager.removeEntity(data.entity[i].id); + } + } + } +} + +struct UpgradeSystem +{ + mixin ECS.System; + + struct EntitiesData + { + const (Entity)[] entity; + @readonly CShip[] ship; + } + + void handleEvent(Entity* entity, EUpgrade event) + { + CLaserWeapon* laser = entity.getComponent!CLaserWeapon; + if(laser) + { + if(laser.level < LaserShootingSystem.laser_shoot_times.length)laser.level++; + } + } } struct ChangeDirectionSystem @@ -893,6 +951,7 @@ struct MovementSystem } } + extern(C) float sqrtf(float x) @nogc nothrow @system; /** @@ -1012,9 +1071,11 @@ void spaceInvadersStart() launcher.manager.registerComponent!CGuild; launcher.manager.registerComponent!CHitPoints; launcher.manager.registerComponent!CHitMark; + launcher.manager.registerComponent!CUpgrade; launcher.manager.registerEvent!EChangeDirection; launcher.manager.registerEvent!EDamage; + launcher.manager.registerEvent!EUpgrade; //launcher.manager.registerSystem!MoveSystem(0); launcher.manager.registerSystem!DrawSystem(100); @@ -1028,6 +1089,8 @@ void spaceInvadersStart() launcher.manager.registerSystem!ShootGridCleaner(-101); launcher.manager.registerSystem!HitPointsSystem(0); launcher.manager.registerSystem!HitMarkingSystem(-100); + launcher.manager.registerSystem!UpgradeCollisionSystem(-70); + launcher.manager.registerSystem!UpgradeSystem(-100); launcher.manager.endRegister(); @@ -1051,7 +1114,7 @@ void spaceInvadersStart() CLocation* loc_comp = space_invaders.ship_tmpl.getComponent!CLocation; loc_comp.value = vec2(64,64); CLaserWeapon* weapon = space_invaders.ship_tmpl.getComponent!CLaserWeapon; - weapon.level = 22; + weapon.level = 1; space_invaders.ship_tmpl.getComponent!CHitPoints().value = 1000; launcher.manager.addEntity(space_invaders.ship_tmpl); @@ -1112,6 +1175,18 @@ void spaceInvadersStart() grouped_id = current_entity.id; //grouped_tmpl = launcher.manager.allocateTemplate(current_entity.id); } + + EntityTemplate* upgrade_tmpl; + + { + upgrade_tmpl = launcher.manager.allocateTemplate([CVelocity.component_id, CLocation.component_id, CTexture.component_id, CScale.component_id, CUpgrade.component_id].staticArray); + CTexture* tex_comp = upgrade_tmpl.getComponent!CTexture; + tex_comp.tex = space_invaders.texture;//ship_tex; + tex_comp.coords = vec4(0*px,32*px,16*px,16*px); + CVelocity* vel_comp = upgrade_tmpl.getComponent!CVelocity; + vel_comp.value = vec2(0,-0.1); + } + launcher.manager.commit(); enemy_tmpl = launcher.manager.allocateTemplate(enemy_id); @@ -1121,6 +1196,7 @@ void spaceInvadersStart() launcher.gui_manager.addTemplate(enemy_tmpl,"Enemy"); launcher.gui_manager.addTemplate(grouped_tmpl,"Grouped enemy"); launcher.gui_manager.addTemplate(launcher.manager.allocateTemplate(space_invaders.laser_tmpl),"Laser"); + launcher.gui_manager.addTemplate(upgrade_tmpl,"Upgrade"); } @@ -1149,6 +1225,8 @@ void spaceInvadersTool(vec2 position, Tool tool, int size) { position.x += (randomf - 0.5) * size; position.y += (randomf - 0.5) * size; + if(position.y < 16)position.y = 16; + else if(position.y > 299)position.y = 299; *location = position; } CLaserWeapon* laser_weapon = tmpl.getComponent!CLaserWeapon; From 9589a5cb2d051e18f32039daad4077150b72870f Mon Sep 17 00:00:00 2001 From: Mergul Date: Thu, 14 May 2020 22:18:57 +0200 Subject: [PATCH 134/217] FIxed GDC compilation (basic betterC WIP) and some improvements -fixed issue with adding/removing entities inside events handling -fixed EntityMeta.getComponent() (added check if component_id is valid) -added function hasComponent to entity to check if component exists --- demos/external/sources/mmutils/thread_pool.d | 7 +- demos/source/demos/snake.d | 2 +- demos/utils/source/ecs_utils/utils.d | 14 +- dub.json | 14 +- source/bubel/ecs/entity.d | 18 ++ source/bubel/ecs/manager.d | 164 ++++++++++--------- source/bubel/ecs/std.d | 8 + source/bubel/ecs/vector.d | 14 +- tests/access_perf.d | 9 +- tests/basic.d | 9 +- tests/perf.d | 9 +- 11 files changed, 174 insertions(+), 94 deletions(-) diff --git a/demos/external/sources/mmutils/thread_pool.d b/demos/external/sources/mmutils/thread_pool.d index 48d2932..52136d4 100644 --- a/demos/external/sources/mmutils/thread_pool.d +++ b/demos/external/sources/mmutils/thread_pool.d @@ -182,6 +182,12 @@ void instructionPause() __builtin_ia32_pause(); } + else version(GNU) + { + import gcc.builtins; + + __builtin_ia32_pause(); + } else version (DigitalMars) { asm @@ -189,7 +195,6 @@ void instructionPause() rep; nop; } - } else { diff --git a/demos/source/demos/snake.d b/demos/source/demos/snake.d index 244e5ec..3c62ef6 100644 --- a/demos/source/demos/snake.d +++ b/demos/source/demos/snake.d @@ -17,7 +17,7 @@ import ecs_utils.gfx.texture; import ecs_utils.math.vector; import ecs_utils.utils; -import std.array : staticArray; +//import std.array : staticArray; enum float px = 1.0/512.0; diff --git a/demos/utils/source/ecs_utils/utils.d b/demos/utils/source/ecs_utils/utils.d index 4c143fd..8ce5cd1 100644 --- a/demos/utils/source/ecs_utils/utils.d +++ b/demos/utils/source/ecs_utils/utils.d @@ -21,7 +21,19 @@ float randomRangef(float min, float max) return rand()%4096; }*/ -extern(C) int printf(scope const char* format, ...) @nogc nothrow @system; +version(GNU) +{ + public import core.stdc.stdio : printf; + pragma(inline, true) T[n] staticArray(T, size_t n)(auto ref T[n] a) + { + return a; + } +} +else +{ + extern(C) int printf(scope const char* format, ...) @nogc nothrow @system; + public import std.array : staticArray; +} extern(C) int rand(); version(D_BetterC) diff --git a/dub.json b/dub.json index c23a4e6..01cf85c 100755 --- a/dub.json +++ b/dub.json @@ -74,6 +74,9 @@ "dflags": [ "-betterC", "-defaultlib=" + ], + "dflags-gdc": [ + "-fno-druntime" ] }, { @@ -88,9 +91,7 @@ ], "dflags-gdc": [ "-fno-druntime", - "-fvisibility=hidden" - ], - "lflags-gdc": [ + "-fvisibility=hidden", "-lpthread" ] }, @@ -105,9 +106,7 @@ "-betterC" ], "dflags-gdc": [ - "-fno-druntime" - ], - "lflags-gdc": [ + "-fno-druntime", "-lpthread" ] }, @@ -118,6 +117,9 @@ "-betterC", "-unittest" ], + "dflags-gdc": [ + "-fno-druntime" + ], "sourcePaths": ["source/","tests/"], "mainSourceFile":"tests/runner.d", "excludedSourceFiles":[ diff --git a/source/bubel/ecs/entity.d b/source/bubel/ecs/entity.d index 10720a2..1e98ff2 100644 --- a/source/bubel/ecs/entity.d +++ b/source/bubel/ecs/entity.d @@ -46,6 +46,14 @@ struct Entity return cast(T*)(cast(void*)block + info.deltas[T.component_id] + ind * T.sizeof); } + bool hasComponent(ushort component_id) + { + EntityManager.EntitiesBlock* block = gEM.getMetaData(&this); + EntityManager.EntityInfo* info = block.type_info; + if (component_id >= info.deltas.length || info.deltas[component_id] == 0)return false; + return true; + } + EntityMeta getMeta() { EntityMeta meta; @@ -65,8 +73,18 @@ struct EntityMeta T* getComponent(T)() const { + const (EntityManager.EntityInfo)* info = block.type_info; + if (T.component_id >= info.deltas.length || info.deltas[T.component_id] == 0) + return null; return cast(T*)(cast(void*)block + block.type_info.deltas[T.component_id] + index * T.sizeof); } + + bool hasComponent(ushort component_id) + { + EntityManager.EntityInfo* info = block.type_info; + if (component_id >= info.deltas.length || info.deltas[component_id] == 0)return false; + return true; + } } /************************************************************************************************************************ diff --git a/source/bubel/ecs/manager.d b/source/bubel/ecs/manager.d index c6b02a1..7b6a983 100644 --- a/source/bubel/ecs/manager.d +++ b/source/bubel/ecs/manager.d @@ -126,7 +126,7 @@ export struct EntityManager //if(info.components)Mallocator.dispose(info.components); Mallocator.dispose(info); - } //*/ + } foreach (UpdatePass* pass; passes) { @@ -472,50 +472,52 @@ export struct EntityManager if (member == "length" || member == "thread_id" || is(MemberType == Entity[]) || is(MemberType == const(Entity)[])) { - continue; + //continue; } - - string name; - static if (isArray!MemberType) - { // Workaround. This code is never called with: not an array type, but compiler prints an error - name = Unqual!(ForeachType!MemberType).stringof; - } - - bool is_optional; - bool is_read_only; - - if (is(CopyConstness!(ForeachType!(MemberType), int) == const(int))) + else { - is_read_only = true; - } - - foreach (att; __traits(getAttributes, __traits(getMember, - Sys.EntitiesData, member))) - { - if (att == "optional") - { - is_optional = true; + string name; + static if (isArray!MemberType) + { // Workaround. This code is never called with: not an array type, but compiler prints an error + name = Unqual!(ForeachType!MemberType).stringof; } - if (att == "readonly") + + bool is_optional; + bool is_read_only; + + if (is(CopyConstness!(ForeachType!(MemberType), int) == const(int))) { is_read_only = true; } - } - if (is_read_only) - { - components_counts.readonly++; - } - else - { - components_counts.mutable++; - } - if (is_optional) - { - components_counts.optional++; - } - else - { - components_counts.req++; + + foreach (att; __traits(getAttributes, __traits(getMember, + Sys.EntitiesData, member))) + { + if (att == "optional") + { + is_optional = true; + } + if (att == "readonly") + { + is_read_only = true; + } + } + if (is_read_only) + { + components_counts.readonly++; + } + else + { + components_counts.mutable++; + } + if (is_optional) + { + components_counts.optional++; + } + else + { + components_counts.req++; + } } } @@ -695,50 +697,52 @@ export struct EntityManager { if (is(MemberType == Entity[]) || is(MemberType == const(Entity)[])) components_info.entites_array = member; - continue; + //continue; } - - string name; - static if (isArray!MemberType) - { // Workaround. This code is never called with: not an array type, but compiler prints an error - name = Unqual!(ForeachType!MemberType).stringof; - } - - bool is_optional; - bool is_read_only; - - if (is(CopyConstness!(ForeachType!(MemberType), int) == const(int))) + else { - is_read_only = true; - } - - foreach (att; __traits(getAttributes, __traits(getMember, - Sys.EntitiesData, member))) - { - if (att == "optional") - { - is_optional = true; + string name; + static if (isArray!MemberType) + { // Workaround. This code is never called with: not an array type, but compiler prints an error + name = Unqual!(ForeachType!MemberType).stringof; } - if (att == "readonly") + + bool is_optional; + bool is_read_only; + + if (is(CopyConstness!(ForeachType!(MemberType), int) == const(int))) { is_read_only = true; } - } - if (is_read_only) - { - components_info.addReadonly(CompInfo(member, name)); - } - else - { - components_info.addMutable(CompInfo(member, name)); - } - if (is_optional) - { - components_info.addOptional(CompInfo(member, name)); - } - else - { - components_info.addReq(CompInfo(member, name)); + + foreach (att; __traits(getAttributes, __traits(getMember, + Sys.EntitiesData, member))) + { + if (att == "optional") + { + is_optional = true; + } + if (att == "readonly") + { + is_read_only = true; + } + } + if (is_read_only) + { + components_info.addReadonly(CompInfo(member, name)); + } + else + { + components_info.addMutable(CompInfo(member, name)); + } + if (is_optional) + { + components_info.addOptional(CompInfo(member, name)); + } + else + { + components_info.addReq(CompInfo(member, name)); + } } } @@ -874,7 +878,7 @@ export struct EntityManager } } - static void fillInputData(ref Sys.EntitiesData input_data, EntityInfo* info, + static void fillInputData()(ref Sys.EntitiesData input_data, EntityInfo* info, EntitiesBlock* block, uint offset, uint entities_count, System* system) { //enum ComponentsIndices components_info = getComponentsInfo(); @@ -2863,7 +2867,11 @@ export struct EntityManager id_manager.optimize(); updateBlocks(); changeEntities(); + updateEvents(); + + id_manager.optimize(); + updateBlocks(); removeEntities(); event_manager.clearEvents(); } diff --git a/source/bubel/ecs/std.d b/source/bubel/ecs/std.d index 4cec197..6658639 100644 --- a/source/bubel/ecs/std.d +++ b/source/bubel/ecs/std.d @@ -113,6 +113,14 @@ else version(D_BetterC) alloca_pos += length; return ret; } + + version(GNU) + { + extern(C) void __gdc_personality_v0() + { + + } + } } else { diff --git a/source/bubel/ecs/vector.d b/source/bubel/ecs/vector.d index 413bbce..1ec8a93 100644 --- a/source/bubel/ecs/vector.d +++ b/source/bubel/ecs/vector.d @@ -55,7 +55,8 @@ public: /*foreach (ref el; array[0 .. used]) { destroy(el); }*/ - freeData(cast(void[]) array); + //freeData(cast(void[]) array); + freeData((cast(void*)array.ptr)[0 .. array.length * T.sizeof]); gVectorsDestroyed++; } array = null; @@ -78,7 +79,9 @@ public: } } else { foreach (ref el; array[newLength .. used]) { - destroy(el); + //destroy(el); + static if(__traits(hasMember, T, "__xdtor"))el.__xdtor(); + else static if(__traits(hasMember, T, "__dtor"))el.__dtor(); } } used = newLength; @@ -122,7 +125,8 @@ public: T* memory = cast(T*) malloc(newSize); memcpy(cast(void*) memory, cast(void*) oldArray.ptr, oldSize); array = memory[0 .. newNumOfElements]; - return cast(void[]) oldArray; + //return cast(void[]) oldArray; + return (cast(void*)oldArray.ptr)[0 .. oldArray.length * T.sizeof]; } export Vector!T copy()() { @@ -169,7 +173,9 @@ public: } export void remove(size_t elemNum) { - destroy(array[elemNum]); + //destroy(array[elemNum]); + static if(__traits(hasMember, T, "__xdtor"))array[elemNum].__xdtor(); + else static if(__traits(hasMember, T, "__dtor"))array[elemNum].__dtor(); //swap(array[elemNum], array[used - 1]); array[elemNum] = array[used - 1]; used--; diff --git a/tests/access_perf.d b/tests/access_perf.d index 141a2e6..36da0c0 100644 --- a/tests/access_perf.d +++ b/tests/access_perf.d @@ -6,7 +6,14 @@ import bubel.ecs.core; import bubel.ecs.manager; import bubel.ecs.entity; -import std.array : staticArray; +version(GNU) +{ + pragma(inline, true) T[n] staticArray(T, size_t n)(auto ref T[n] a) + { + return a; + } +} +else import std.array : staticArray; import core.stdc.stdio; diff --git a/tests/basic.d b/tests/basic.d index 10d79b8..3bf2814 100644 --- a/tests/basic.d +++ b/tests/basic.d @@ -5,7 +5,14 @@ import bubel.ecs.manager; import bubel.ecs.system; import bubel.ecs.attributes; -import std.array : staticArray; +version(GNU) +{ + pragma(inline, true) T[n] staticArray(T, size_t n)(auto ref T[n] a) + { + return a; + } +} +else import std.array : staticArray; struct CInt { diff --git a/tests/perf.d b/tests/perf.d index 135dc54..b6a2692 100644 --- a/tests/perf.d +++ b/tests/perf.d @@ -6,7 +6,14 @@ import bubel.ecs.core; import bubel.ecs.manager; import bubel.ecs.entity; -import std.array : staticArray; +version(GNU) +{ + pragma(inline, true) T[n] staticArray(T, size_t n)(auto ref T[n] a) + { + return a; + } +} +else import std.array : staticArray; import core.stdc.stdio; From 6c3c803d1ea1e2c4f5916efd7da06fb27595382e Mon Sep 17 00:00:00 2001 From: Mergul Date: Thu, 14 May 2020 22:20:41 +0200 Subject: [PATCH 135/217] SpaceShip demo update -fixed issue with firing lasers in multithreaded mode -fix: enies can't grab upgrade anymore -there is a change that enemy drop bonus upon death --- demos/source/demos/space_invaders.d | 124 ++++++++++++++++++++++++---- 1 file changed, 109 insertions(+), 15 deletions(-) diff --git a/demos/source/demos/space_invaders.d b/demos/source/demos/space_invaders.d index 1c5b3e4..bef65fe 100644 --- a/demos/source/demos/space_invaders.d +++ b/demos/source/demos/space_invaders.d @@ -16,7 +16,7 @@ import ecs_utils.gfx.texture; import ecs_utils.math.vector; import ecs_utils.utils; -import std.array : staticArray; +//import std.array : staticArray; enum float px = 1.0/512.0; @@ -252,6 +252,11 @@ struct EUpgrade mixin ECS.Event; } +struct EDeath +{ + mixin ECS.Event; +} + struct EDamage { mixin ECS.Event; @@ -499,32 +504,72 @@ struct LaserShootingSystem bool shoot = false; static float[18] laser_shoot_times = [500,400,300,200,100,50,25,10,5,2,1,0.8,0.6,0.5,0.4,0.3,0.2,0.1]; - CLocation* laser_location; + /*CLocation* laser_location; CVelocity* laser_velocity; - CGuild* laser_guild; + CGuild* laser_guild;*/ struct EntitiesData { ///variable named "length" contain entites count uint length; + ///variable named "length" contain thread identifier + uint thread_id; @readonly CShootDirection[] shoot_direction; @readonly @optional CAutoShoot[] auto_shoot; @readonly CLocation[] location; @readonly CGuild[] guild; CLaserWeapon[] laser; } + + struct ThreadData + { + EntityTemplate* laser_tmpl; + CLocation* laser_location; + CVelocity* laser_velocity; + CGuild* laser_guild; + } + + ThreadData[] threads; ///Called inside "registerSystem" function - /*void onCreate() + void onCreate() { - laser_location = space_invaders.laser_tmpl.getComponent!CLocation; - }*/ + threads = Mallocator.makeArray!ThreadData(32); + threads[0].laser_tmpl = launcher.manager.allocateTemplate([CLocation.component_id, CTexture.component_id, CVelocity.component_id, CScale.component_id, CLaser.component_id, CGuild.component_id].staticArray); + + CTexture* tex_comp = threads[0].laser_tmpl.getComponent!CTexture; + tex_comp.tex = space_invaders.texture;//laser_tex; + tex_comp.coords = vec4(0*px,24*px,2*px,8*px); + CScale* scale_comp = threads[0].laser_tmpl.getComponent!CScale; + scale_comp.value = vec2(2,8); + threads[0].laser_location = threads[0].laser_tmpl.getComponent!CLocation; + threads[0].laser_velocity = threads[0].laser_tmpl.getComponent!CVelocity; + threads[0].laser_guild = threads[0].laser_tmpl.getComponent!CGuild; + + foreach(ref ThreadData thread;threads[1..$]) + { + thread.laser_tmpl = launcher.manager.allocateTemplate(threads[0].laser_tmpl); + thread.laser_location = thread.laser_tmpl.getComponent!CLocation; + thread.laser_velocity = thread.laser_tmpl.getComponent!CVelocity; + thread.laser_guild = thread.laser_tmpl.getComponent!CGuild; + } + //laser_location = space_invaders.laser_tmpl.getComponent!CLocation; + } + + void onDestroy() + { + foreach(ref ThreadData thread;threads[1..$]) + { + launcher.manager.freeTemplate(thread.laser_tmpl); + } + Mallocator.dispose(threads); + } bool onBegin() { - laser_location = space_invaders.laser_tmpl.getComponent!CLocation; + /*laser_location = space_invaders.laser_tmpl.getComponent!CLocation; laser_velocity = space_invaders.laser_tmpl.getComponent!CVelocity; - laser_guild = space_invaders.laser_tmpl.getComponent!CGuild; + laser_guild = space_invaders.laser_tmpl.getComponent!CGuild;*/ if(launcher.getKeyState(SDL_SCANCODE_SPACE)) { shoot = true; @@ -535,6 +580,7 @@ struct LaserShootingSystem void onUpdate(EntitiesData data) { + ThreadData* thread = &threads[data.thread_id]; //conditional branch for whole entities block if(shoot || data.auto_shoot) { @@ -545,10 +591,10 @@ struct LaserShootingSystem while(laser.shoot_time > laser_shoot_times[laser.level - 1]) { laser.shoot_time -= laser_shoot_times[laser.level - 1]; - laser_location.value = data.location[i]; - laser_velocity.value = vec2(randomf()*0.5-0.25,data.shoot_direction[i].direction == Direction.up ? 1.0 : -1.0); - laser_guild.guild = data.guild[i].guild; - launcher.manager.addEntity(space_invaders.laser_tmpl); + thread.laser_location.value = data.location[i]; + thread.laser_velocity.value = vec2(randomf()*0.5-0.25,data.shoot_direction[i].direction == Direction.up ? 1.0 : -1.0); + thread.laser_guild.guild = data.guild[i].guild; + launcher.manager.addEntity(thread.laser_tmpl); } } } @@ -617,8 +663,12 @@ struct UpgradeCollisionSystem { if(space_invaders.shoot_grid.test(id, data.location[i], cast(ubyte)(0xFF))) { - launcher.manager.sendEvent(id, EUpgrade()); - launcher.manager.removeEntity(data.entity[i].id); + Entity* entity = launcher.manager.getEntity(id); + if(entity.hasComponent(CShip.component_id)) + { + launcher.manager.sendEvent(id, EUpgrade()); + launcher.manager.removeEntity(data.entity[i].id); + } } } } @@ -676,6 +726,7 @@ struct ChangeDirectionSystem if(direction != cast(Direction)-1)//return true; { has_changes = true; +INFO: Uniform block alig break; } } @@ -833,19 +884,61 @@ struct HitPointsSystem { mixin ECS.System; + EntityTemplate* upgrade_tmpl; + CLocation* upgrade_location; + struct EntitiesData { CHitPoints[] hp; } + void onCreate() + { + upgrade_tmpl = launcher.manager.allocateTemplate([CVelocity.component_id, CLocation.component_id, CTexture.component_id, CScale.component_id, CUpgrade.component_id].staticArray); + CTexture* tex_comp = upgrade_tmpl.getComponent!CTexture; + tex_comp.tex = space_invaders.texture;//ship_tex; + tex_comp.coords = vec4(0*px,32*px,16*px,16*px); + CVelocity* vel_comp = upgrade_tmpl.getComponent!CVelocity; + vel_comp.value = vec2(0,-0.1); + upgrade_location = upgrade_tmpl.getComponent!CLocation; + } + + void onDestroy() + { + launcher.manager.freeTemplate(upgrade_tmpl); + } + void handleEvent(Entity* entity, EDamage event) { CHitPoints* hp = entity.getComponent!CHitPoints; + if(*hp < 0)return; *hp -= event.damage; - if(*hp < 0)launcher.manager.removeEntity(entity.id); + if(*hp < 0) + { + launcher.manager.sendEvent(entity.id, EDeath()); + //launcher.manager.removeEntity(entity.id); + } CHitMark* hit_mark = entity.getComponent!CHitMark; if(hit_mark)hit_mark.value = 127; } + + void handleEvent(Entity* entity, EDeath event) + { + CEnemy* enemy = entity.getComponent!CEnemy; + if(enemy) + { + if(randomRange(0, 1000) < 5) + { + CLocation* location = entity.getComponent!CLocation; + if(location) + { + *upgrade_location = *location; + launcher.manager.addEntity(upgrade_tmpl); + } + } + } + launcher.manager.removeEntity(entity.id); + } } struct ClampPositionSystem @@ -1076,6 +1169,7 @@ void spaceInvadersStart() launcher.manager.registerEvent!EChangeDirection; launcher.manager.registerEvent!EDamage; launcher.manager.registerEvent!EUpgrade; + launcher.manager.registerEvent!EDeath; //launcher.manager.registerSystem!MoveSystem(0); launcher.manager.registerSystem!DrawSystem(100); From 0b924ae77c8084d39b360f90b688a8461a04d043 Mon Sep 17 00:00:00 2001 From: Mergul Date: Tue, 19 May 2020 20:27:18 +0200 Subject: [PATCH 136/217] Demos update (SpaceInvaders demo) -added new sprites -added new functions to vectors -fixed rendering rotated sprites -small performance improvement and some bug fixes -added animations support -bullets get initial velocity from parent -added partiles for fire from gun and explosion of enemies --- demos/assets/textures/atlas.png | Bin 24668 -> 35204 bytes demos/dub.json | 3 + demos/source/app.d | 4 +- demos/source/demos/snake.d | 2 +- demos/source/demos/space_invaders.d | 362 ++++++++++++++++++-- demos/utils/source/ecs_utils/gfx/renderer.d | 18 + demos/utils/source/ecs_utils/math/vector.d | 56 +++ 7 files changed, 411 insertions(+), 34 deletions(-) diff --git a/demos/assets/textures/atlas.png b/demos/assets/textures/atlas.png index c628969c0e7149419eb62313fb5c3274457838f3..1e269e513e42c5dc797f568af05816d2562995f0 100644 GIT binary patch literal 35204 zcmXt91z6l%lnw4~#oZ}xMF)5Hwn&S+yUbw4-3k;bRvcQ~-HR4?DemsD(|>pKC6mm{ zH%YFYd+vRi2z6CC3{(A31&Fp=*n)nrlIiojXN5*nRGMI*&T1U|M)Yq~!5gV;VU`bnZYRISq92 zS!-&25nc0iSh;$nKZ-+Gd<<`U3F=5LFPUL@@Aa0sw0_J|=_ix(lGtQ<6}I2<-eE`2 zKuN^A!X)~E-5H~r-&Gx5#@jkBmzOR9Vn23uj5II{qM12ezymjJ+HpHrKkrlP#Gg^b zYsx*}`Mrg^Z%6N@Y`@b)JZ_EKVg|LhrtO+;Ml#Dov);^P}@cOM%kntX`xY zu}ko`-JZlgG9@7eZ#C<}Co&$F$v-sDiBYe^DjB}33-Ygd+T3z~+BQUqyib;L9^Z1E zw1#RWaemeN{rZFGQK1GA4*;_bdVc0% zE?4^+gAgldEcKgZ&4yJxV(goqH~9MNUVz~#9KnfUI=a6W9siI{hO|mVB2~O>&=+Z? zrUC`Tg4x=1GnVw(Khk(khn;*Z<4q++bI$6C%G1lg5;L=rhFA(U#otGhkbrDU>gr2p zY^w6Nbz#Y8Gx)=nz8gg8+Lziay6e|}p2;XlcPACSMkkq574|r6i|Z0aqKzX&+{KFh z&3nmKGsf?}c;w19Y?-2?_o3PDn$Kg=`_Dj&{Yw2Kg&by~+i=N7ZT^6&_?D)vz?#dU zy?|Fzl~l;mbYd6mv)wzl9`o_S0*`j=zWgCoI!H9LXG zDecFwIkJ&2lF*NO93SB%i8v?cQWr%c!_4VH>#|zE-CC`T`I7Bgh0-V9nWYDzigK-! zi7X4R*m@<9A|+kHYT~`@lIl-;!YaO-ShxB7R4;yG$F@T{i}(DKbaJ-axJA+FOG8m6 z#>b{96{1G6X6?_vGc$MI$Nm2Efj9V~IJw>71P)fj9fwF2891HMZ6O~MqBGZVi>N3{ zc30YEi}x>*9PVWzO=obqaaa}`U%ft>Wh%w?9QN;G|IM6M)}pS>7lR-(%`GA<#Iz`a z)J^A(`Wdde!qbUOL%2e}ia)qOSzx+7M$RvQ*T?HIOiqu{p#^^P%hVlC~-gCM}}S z{c?pwDPy{ho8lomS!l{DMV%4QYL)-3-7X~pIc$6R%!;CC52j{g4;)8qmbS3cEpWTrmHgY@HJHEo#w8PwsDk_DZ|D+`)i~*At`=6-+Iw^ zX?b}D=WwHfo+;uTcGncidiD~BE8lCDrDQkQcv_^}`SRT5zg!|E6TG}+UQ#Y0s!qh* zJz`I~A^ix#1sL4!Q)25gW~1~NZ7GRJ{y+~`%+Vd zvwMk{QzG++%CY+3nxI>Odji)p&M6#gwxHCS?}8?-V$|4QJ<)=)+A4{UC3{BX2#U z@#mxvQWTb8!O<5`Oe07b?k330$hsuLSLpz?m0lSNP{gR+@l5{>+K zsj9z|-H$o;E`<4CDi5u&ov~OGCFmbwpNnY)E8lm}*;|%471{NIke)&50Z%uK-_WRP z+~_c-*%bDP9Z*p158~vh6IiN-2yXYiPRPbtaHgU+NN_GmEfSuJTvMa~* zDZICe@dinmSnH%0PBg(&KawEo%jHPlEYMT=`>mz=J73WF5Qw_uNr%<)%JJn&BJP_h zhpUODGno0ZtbPU8Du!bW_kA!s+$Tr9A!Np+H492Zxmp!ez|%xM_`#@Q!TT*9E0rXo z2F4=b{o>o|H`QU7OwxkcrAbM*2#fm;+>#xxpJlxQwe%}j3pwEx9BS7?vhmAid>}J` zjS%LsPRtqWbsiEiQWzzP0%XA2^d{?acrZ}jcR~Q4c62^O#(0lUdawI?fTn5et#T%z z@($6#VfSz-^CWVb7iz;G)%x6F_hUELe*Puf=vQtx#cl?I-Sbi5nU||e(1Cl{G4efV zK&{XHN0O5QYN9$Qnn!{E**T#^Uh5&`bq}H_!@{bHXti?k>6Ua}1pinxNJO)oY1Dz} zJmCvk0~%-Gr_X6ZRF~-tEyWrs@71lFZDhFvb9nNaHqj0?BtKvI^((&SobrN(s_pfW z573!Kfxh`_vP7q^HmA6Pq%+p0*@e=P)2%B6E#z)@&89pH+4^ z(H-|F3>32wn;G+(huE7j3)Q5M_u#X0tujX>H#a`0m`5GH;>~%C5^8AKBRE)jmm^2! zvZIlGl8;S}@bj*f+8~)zNH%i+lsI&vj18my7lnqh_ZI#SK1NueFl`S((U?_&j_e;C zTgxYDPlhTxf%NbuqT@_I=(=B)Q(Z#4X)Gk z=RwW@5EclaURf+)Wx&g&dA7QZ@Rj&rj97vHmgPJ8Q-T1@`z_{3qYVPO9%PEqHleh= zTn7o_*1s@sb7M7d@8CQvb#)|c7>39uR;ajfJqfJ(Q_!!;zOvm*0sZ`zwzN(mK3@LF0xZ2b(`k$@?ej#dvI{RGd@|518)PE;OAkW`U^^w-ZXcL9Dl zsEsgjcns}zCTJRMO%QGeGmRiR(r(WdjGbu01k*4s{$WAQ;9WvO3KAAV@3uL&Os|~L zxI-4F?jBN29-`Z?kVav&3y{=0FJA6zHih|w+8$rwc6X2#3Kk7q-I9()-CW5V&r}VL zH!ww1{@BcQx>wpck`Qe<$z`OwM%u4YrsaLZ4e0@NspDCDqLQ+Ic&}lZ7IYx%wd*4I z=oW2V9L{B&`9Hs-9uTjDwQdMYPb&4E8ppqGjKHkf%Hv~`M@vWv7%4+Ej~4_!odudU zLc-%Uaa^!`ni`}mJqa6$cy2_Ihsk|+anS}nJp$n079MLl&FQB4<~B`$<=;dG{Uk-) z35V|%E?6ID9K*PmOggM_|HK~w7au2nm^b#W<|-m%56&_1=Qso&7Z6<@#*}v9c!+@= z8e(3M5~27e16n^}CBfJg@h?j}fWv6na;cYFqhl+Q0;=c+QI$_x-w8&}pNqhi4L-PXp$$04e}?yJ zLUQi;F2#Xl6Y5Kx!-dP98DVNd)0w_b96!iBcWW^%fYth|O#G|C7kvblChAW3!i}Sy zL5z1Wa^1G_8}Q~BA#Y1leNPzpfSHO;Pzs*T!Uf*tHN7*UE~N_3;`l)Vp+; zF_Xbhb|E~C#~;3$Uqz+?A2y!0QBN_W&%Qb+L#VIv98Dl&Uw!f0L!+pqyb`3MA@?UZ z7R_dw^87Ls>jZ-`yo%15p@lMM3*32b8k;TZYC-^EWDbIiAMM!6ZJHlC9o$Hv zj(Jz!%B@_u0|-a?=u8^#Zb$a~Ej8}ez2Rf0D_upRW9a@eqhl*Fv-G4^t^Q~%3RMf$ z-|z7hL&1F4ZExjm9#aXE<$wCrU-NC14uLU|{7y>pIiS#P>b_maxib4hn}{gxs<3XRuix?@Vw zn1UmQ5=-(~<6GK64tJd&nHqh{C@dwuMgPT&q~w)WeuwfL41tY-cbv|svCZf!45~e{ z!!TF7)o{I-C9|a_cUMTr;&4&(YSZL7Nv!1bjV7}>`XnGQi!6a0@rK;d!5rl;Y?U(y zO^iDx8E$i!eo8MBxi>q@+NWBzA3M_o$P0o~@$r|<)S(f4a2t16cahikZ@@32tzyWk z@OySUkLV!k`WsE8J`t`)qhGT9Th8Y&l^0(sKIxR_98tm40%L5ko3rHKOFS zXQi>PJ~-5H>rGaG>!{OW&K23Bb(aX3NUTNVv~`cel>eGHXWtWLxeM%{;5vj3;1}K@ zo4r$P3XdXP)9t3Gn; zFSL`!V5#9KYRW|s=OpZqMDGn+-X2d-bbjMrEV<>*iAjCcg<=wfw__hdQ@xkR9^;XE zxb&_#cahwy=Cr0%+zp19H&6x}rwq23Ge7^s8p4?zDB?K5FYMqh3ESbMg*t5-TL9=B zRlPE*VzP4yh0E>9Jgosr!|sNR0)@od-Q#p&MI?A^2+Q4utONwk5aUH-LGjd(7<%|3 z1US6?>Vrpqb~P=NEc}Ey)V~s_Py2V5%Kne0_T7VeW|u)&Ln)oIVKkghIVfh=a$%;y zJ|s{3Sez^aqWpqi&grtbu!yqR-zC_GY7XJuZtu8jSz(i6H=^~fNA`_lPKt(di^5Zd zx8YZ&F2!`ZO<;c&AHk6mo_|B$c&^g?YL&UcEBi6pu(tBUG2Tjy~RV8&SE!E?Iwi zNpywT1y9(QLj`iJw4-~YgM?~wiYoYws(foW8dQ|`v9nWC(GDwC^7M;B$}Tl6^?P|Y zn+{qNocFY&s60KD9D>6ahgNj-eqex98rvze^&+f_@pn>QMq~7th{0ckFB#%=-*b!Q zz@Q)|$p^kE-wON&u85cZNLaP@*AVT?A4XPc;FrP!cFSB6d6uHUBGRBQ13J`&l?ZF8 z2rbxU?OZ6B#8<@3$tl@w~cY)uL)Z3j)F6Ptnbtu zZ#ygq)HFHd>y*^SGF&pMp1j4J|FR$0>MUYU!C8cfW@VTh<)}Kn;_paI8}|Jo#s!`8 z*Ke+n1ClEknx}XflV`~>WUdF80OEFE9DFhoNeqdom#=_TuaoR9sorXPVZ#@3dzm%R zYQrRwJkr&76!jf8<%OwdCT(~$WDQr|a3S)YQ!K2A9SQ7Df_oBu&gmYP_CmwB`ZC^k zvz&_X(~81*arJ0OkV4&Dt&%Qf%M8}{<)k!|esVL}s3r8zGhe2~S0^7tCr$$cu&#V_ z*Wmn5&W)#yjR%>y7~Ka|CH?g1h8| zUKaDp^t%x~y`S4-Qur+pv}m(wVv93W?-+!|6qog4I5{Cl?=btWY^`J+w>|q7Ev#VyIxgNT1rKkb zZBN9{N^;VG34jYArdCrBLq|}Y$pKdBFeT+{Z^B;8A4k}M7PtpU4UB_>)=T>ywPug_Q{l`u{1z>sr zkCrSZ@~Vmog3hl07Op*Y`s%0wDUIB<${q-O1}fORTKC*9X>}|Hgn!u&u@gsi2p9af zAR-9ybvtq>`k)NWBF`UtNQR1A->=kNeZI)CgWZXNVIC(~gIO2vLuSh`X9(69o6RzE z`1bFI(-r_>9MVrBm_W|;vxor;!x!P&hKBs@3M3c+f#LiPN6vx)5(#G57T7;7<$=*= z;*k;hG+Mu`EF;{Weev=Bo^ZGG@D0kQc;Vu=n`W;3iz%ban;Q=Y*nb!29s=OIFHVn- zkAvUetEU=UA+orb?$8h{OXLoewJ+P{-zmdq%$iQY2*u3HW}=+In||peiZraMf2O5B z(4&2^`RQdu4Dsl$fgyt~*65wIaUzoSVt%5rg1x6(sJ))!z7YxUM8WslX-OEQ`~}a> zbxX&8`$-+8i?-uR)8T;97T9v1+y&+g2&U)7VGz!FhBEv#r6#ySgR!2T6wd^DXBetU zKZq~@PXm#F3!&M(CnQq0B59Y*W=5oWl3RKph*N7w+vujB**m^el%>*g+Jf5VobnUE zzv3&ZyL=6s{d^k5DI~zqdtRLmIAWj8evGZh5-6_ZJ-o;dhMft@fM}~{(wlt80V+`6 zA!Es6)l-QDi@@d1!D4c(W62#dg1l9448DBF2Xh_h-UgV(IYBV}50hoUE<-zA;V*yFM9}nR;YtPcslJiF5LC7I&7czr(jG~KP4)%X~Z@+;~ z4DeUBAz!AwVgl>)XJ}r*oqNUlQ{$@{BcI?+R$HjIBEy>f_-IZsEsPmhPs)kaai8xh zG3zG5oNSm=$av=~!~pvHPN0*B&{znDbMNyCY)>CNnf+nf!)|aF@|APmI0f1l`EMq^ zT(^;HtRrWx;%UTzUK?utOLxoT=6M`t#y|Z(?Oo?lTififci=;HXe*k z+}PCv`eUZN(OfIGDv&lXV0S)py;qyV=q!4zVFphh{ceUqWa%Elj^xBrPhxsFx-b3$ zs=|4^=E1RQBOK%lCk|_e%oF6|^$Lv&{iJY2o`4z_`P~axU9sf#>xA6;&E2O#ff0DU zDy`RX1%#KR;@m$+65JbV4|WR=`8kZ*F+t+kUnX-?dc|K>y$B(}!CSVrz~-MzOk?Hn zEm}8#^Dt1CQT^<#`w9TZF5cq+Q27gh`X|BK>vbee^Q?xnGRX&iESK9B=jHYfE^)~!4+1x{}srWHxg^G^4P{U!M`d)gy7^w ztnXp3PABO{Br!$kVPfHHu)<5A*VQ=GyWB%%_o<-Wc`7{1bS62Z90I??i|DBW;=~cX}|Kj}+ixmm=-VLTzyXUq?I7OZ#1{;v+6R1#0% zdcTw03YC8_#C60C;8Rw3vS*bO%APjPk!qZL}3V6=g!P3km-?T^Ku!^giIvkDSu>rY_ZIt-t1PMr(x9 zh6Dj2(L{u-N5`p%@q!T^zr5GJ%i+YLsY1)|c$8n3wvh68U^Shg8p$tfLXjaz8T`3Z zz~*~VOMHej9dlH$f?Xo_GT_>+LEC8w|L<8aFhI}s7{x|j?^>4xY-U&Mi}Fa}B4Kp6Ea+Gt;&$EG4T{zH zhO&-=kt5F3W|aRG!OFoiubIYp_Vsk{Hm`OtgA-PqAR1A0nWZu+?j>ar1u&IO8-zEi zn%lIp{gIqyk`FEn4E%?X#-wln&_?M9v0vTp)FY*XiH)BR;sqVO0p@oMW6#*H{r@=; z)lEu6%b%z^0XiesX>Y%g(ISd8@cOkG$#z*=Djy8UZZX^Ms^d){Tm&4@6)3>INE^{n5ic zll1{Z$i3sJPQFjo+nG>@z*hX}l8CJ<5XWQi1#X1wb6cwr4b`VGXwE8CA?iS}w>CF$k7qm2OM&#@{B6WUN2DpHFKlT&jR}{ec z*`MUNrn{1tkMj*Vc5&1Pql8gdx4OFA>PCHcO0eIR+9wmjR}I`(eSYeC3V;ux97XY# zte85_6tNL!eSQ7S4Wh~6Y(;mTOjLM@HS6NX&SEl+aDVDtUK0DMaY*Akl?VbWR)dg= z4-G|6fl=)1Qo{pmlKk5ZwY9~oIPo^BA>ooG8YYvj>1+$a+S?RWK8X_6%xjenNaeaw zo7YChR9)~BIIlAV_Y>9#3txfspQJ$xzg?IwmTsIP;|p*$)`7KE>!>EbK55zg zFTOwK-m&hzYb0nNmPy2x$>S&-2PO=fk+Xw8=;#SeZ~t-GFB^TUiWUtHt>FcvG)~S- z<(MCgMXJ#2{c4oa+uDJ0T{M!o`kv#PK_lR7(J)7;+iUw>(m9j`?75RzPm4!A?1&AK z6~K+c78}4p;V{SUfs*u?(!oke(1F)#a&jgH>PTC|t_+Of;3rork;PcG*BKVW9#nB- zsee8-ZwVCOVSKj~1wWJwP$dT_Xs)a?}72th3$TKkEF+W%=~ z8iJa!blgQ0rg*+dD)h}el9F+BPxeyJe{W^KcP}Yw(yNwSrv4*7QQr>7l*X&6>^Aiq z8cjk-B}%RtHe!%+Gjj1ADaL#2^))pP@dRsMHaPW<+7PIkn|-sGenmuSy50868nr)Z z!vQ8^>G|fwIGC82u{h>{m>BBD2UAdVSVP`C>XmG0V^UKQ56k8Y_5>NuI~$gAD78EC z5Dsi1OiwR5bj-tA0A?vH>JnILA|gn;w7c}vJJ5|U;+WA z^WvVc9PCK)`|W74Bj!e{Z7BfA)Gvpy!}8g_XeD8bi6iH z(%-EADiQsK$rZ$dkfZONoGQIpCK5M4OWF;n6x0;&3=iNh!){)oP$t{zbqqkaThoHf ztN8PL9Bm+g-2bTTHv0D!k`{C_L4lX0lpoV$?`AF*6TT4ZM{9nio|jl`_n<@ zHu0Q73(UNEp!@slhL^=z4(`%80{`YGjuuQ1!&iZxzx*ZgnXuw%o&3RHu<|s#=u#e-#iYZkc2toVp6SzGG*&^qhKsQ(%iTo^1J7j zOMlGMD?y_&^!Le&%H#tUp7GF{Q4 zoI|Nya-&9E;+=+{qebXZhFM;w^76vVo!J(AF$xe*^-_)k{Jp$iAO?=S;F~+uK7aT; zupj|B9}g5mE9---1;; zyhtB3$jpNVZhVoXaH{WP%{IqoGaaa?5DX3CX#$+73D4nxKA}2=MOI-FLf6Q}O z@Ir{@!f&8#Ceei~B=ILylk0*Gh>$ID(!#!7Cus#iBdpE?ZzS6M<+L~Gu&z4#Sa0&@S~i#vuT&OF-%0l0RntE0Kj!VH z!uP<3v%(lbd9=z~a;f@fE+pt80FVVE!tt==u6k0)9}#ph1MK_2 zTnTxc!a$J$(*Y2ajmF6}09byNXf9nfo3Wlvasj+}pqN0r3ZP9E*FTK4ywS}`h|O3x zDV})#PPUDW2h_J_H8K2K^=Te>xQ7-XUN@9T+M-B4hEHR`|C0SO;DjzrM+%3HE=xzP z)R6rgs#K~KNlp$2;(<9If%${s3FUe}J65BD$c`bWQ4UtpYx`XMGmi1Z@qgX3eHZoL zT#@LEQ?KxB|I;-h#8jVZ0RY{2mA1RnYt(FKCRO%OqT?)Zcap9Zr%hc$YoV~e6dWHl zV^+l+-Qt3$YIl$zn{M5gs-$H$aI}2m$-z(_-AD?EZHn`hw|kFrrPFwqgYr%5B!$#9 zOfBKb;=;eGTw5;R;0vR;{L9pD;M7+D7`10ZA*b^@+y(XHsDU*3oSdpdZBa+>jczTo zZM&r#BU#t%nvJTq`edMUkx{t7w&C>{_A_f1IuPVPd8!%d{nRq$ZsWyfTvD!FnQu~M z+JR-^RxaB+ukFJk1Q^4akGAa7is-1C=it1+bL5N!W=+S}@Hql>fj2L281GkAW z%zDaO#4C1mGgOkD)F>>RAdT5OJjC;S{WB!v zNA*-Umx{~svNfRBqbo$*;^`l`nyp$}Uq9FkmkdIv|5FQ5&g6mv&bG5fna6BCuOaaL~)J*aovj{@d z$|$Uf9&AC`^Q1d49}2O%e>b(eDwcM&uzf?P40CjRxe0BZ{A$*!OWD>C4;PRjS*2Q`u1CduY}lu z6ZhlDqhg1WP=2>@_gOLExY!I!+4>MZVf`Lde5UnskU0mm--ZgT;f!#=oLvycTc+a& zK(Fy>*Y-5{La$t(ek(@eD*F2+zxouS~2QS^xsV}C4jQZ^+N(Fe}I$TC0t*aZ7KAWOi)6a4*q z@T6+}8`P1n!tghsL+v3uGc&Uu2X3Rv|CiL>(Y2)IudYKZ=-fs0%e3?>n~)0H;Iu-@ z)NN8ni=@Y#7Nbu0^m%D#1}xzSp$fJY@z{%4x_9{NDpVQCG*^!&ZKOr9dZA;*FrV%@ z92cTYR*DKX!K?dxa1TwrxsD@3MISjANJW(Op1Jd zPI@&<1W5(n`OMVop-dfs`{3u6MKDe~G~<4pJmW%t+d4fT13s~lg_fzdt{%8i4! zz7hiu-xbeB#;pQNe8e4oqiyuJVi(zb-mS1kR40vL@bc5{m3e!3c-XU=uPnW?CQ|&= zW_;Wq7%b!*eGOw2+4acc50Zi3K>Q0lqdZ zX1m4#r7&7V^Ck^ZYu+Tn*O#uL(r_P~a}mSZTAc6jCf`ih{%e|kQGs^vT1kEyw+T=o z#xb-}K-Zmv2qxy*?*$Wx#+>2H)dc<3F8G2a^I_?eFngn_oy>pp7f^ne<8nfW6#Cke zF-VZX$4TUpMVsR^0t4aBj8!zgt6u8Jv-Y@)!i)65>*s>d)#-2WK%(p%PwKKfljT}h zQLz>6Miw9LkuXr}S=+PaO!bBU93_Jfet4PdC?9}^`}%@#Dr#nZj(~R4i0`FyHe9*>a@eU{B)m88o%-qXx!eO) zhLNG!-wB-+4%8=3AmrHO z;*Hn8#<74R_UetlTEo>=l~_>5?%_)T9l%f^LWMe{9KZTEgo#5e*omGZ0+qm$CK&S3 zpL>ORpNwxG`uX+WexBA}n_!6$0{)4yHW7JHIyqGrgxWr^6@^;G{1!}=TjCiv5O~b- zENh|y03w&`qmnPRWheyB{GlBWJA6(att@tnK41Sk(Q2K$Eto~YaAC|*_`L5X$+DMx z=;jljX`66fDb$8I?sv}^0X9a|dY+D)*SZZLhUVAFmlD_B(A;)`8p&phY9}_m9$`ZF zpW|OVQYLnhfXiJSr}JHC-e^bcEJNugn~Y-UEDlp)?IemOfoU^pKG8_iah3r!EJY=5 z!t(OgfB(+K-`rty#MHPloZseo{Eq1xrzvj4u39=b8c+>>9fN8MQ7D5 z5Bjqm28|q-tNgISUnR)9Jb8X6-n(+NcP)j7W37J)4f?6Ti!*;Wge!@dz`qs56NW`^ zTQBi?DS?Ofr=(6)v8d&bXcX;RJ{yb;;*y6^%7f;;OC|a$8^UVfj9U%^ zkbFu}w&-{Jj0LA7;wV+EPq_RmUL2`!-?N;bw%j^QT#56c^KSjKwN8oB{*nCe4GOZy*62&bG-(e6P;;DHWzv&b?L^Z5ri2^E*#&;kFziE z{N051jk(IXfkc$>@Tgs{(a(fb>GR^0Z1FO$EjMKNMat80A>C24SyxvMn_!X;%5Jk^V_`SUR0^gkB*!6_mPhdahy7DifgLaAZOUgk z`K1h25W08I3<-2rHq?fW87%|Jy! zJ);WQ4>3IEWAiv!_Ex4GG=BXhX76Lj{7{tel+xhHu;-
      -U`yoWDlL!y69I7g$; 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 diff --git a/demos/dub.json b/demos/dub.json index 43d248c..1c1fe65 100644 --- a/demos/dub.json +++ b/demos/dub.json @@ -18,6 +18,9 @@ "libs-windows-x86_64": ["libs/windows/x64/SDL2","libs/windows/x64/SDL2_Image","libs/windows/x64/cimgui"], "libs-linux-x86_64": ["cimgui","SDL2","SDL2_image"], "lflags-linux-x86_64": ["-rpath=libs/linux/x64/","-Llibs/linux/x64/"], + "dflags-ldc" : [ + "--ffast-math" + ], "configurations" : [ { "name" : "default", diff --git a/demos/source/app.d b/demos/source/app.d index 10fc80e..3af24b5 100644 --- a/demos/source/app.d +++ b/demos/source/app.d @@ -262,7 +262,7 @@ void mainLoop(void* arg) if(launcher.tool && launcher.tool_repeat != 0 && launcher.mouse.left && !igIsWindowHovered(ImGuiHoveredFlags_AnyWindow) && !igIsWindowFocused(ImGuiFocusedFlags_AnyWindow)) { float range = 500.0 / cast(float)launcher.tool_repeat; - launcher.repeat_time += launcher.delta_time; + launcher.repeat_time += launcher.delta_time * 100; while(launcher.repeat_time > range) { launcher.repeat_time -= range; @@ -716,7 +716,7 @@ int main(int argc, char** argv) launcher.job_updater = Mallocator.make!ECSJobUpdater(1); //launcher.job_updater.onCreate(); - EntityManager.initialize(32); + EntityManager.initialize(32, 1<<16); launcher.manager = EntityManager.instance; //launcher.manager.m_thread_id_func = &launcher.job_updater.getThreadID; diff --git a/demos/source/demos/snake.d b/demos/source/demos/snake.d index 3c62ef6..50f7729 100644 --- a/demos/source/demos/snake.d +++ b/demos/source/demos/snake.d @@ -285,7 +285,7 @@ struct ParticleSystem { uint length; @readonly Entity[] entities; - @readonly CParticle[] particle; + CParticle[] particle; } void onUpdate(EntitiesData data) diff --git a/demos/source/demos/space_invaders.d b/demos/source/demos/space_invaders.d index bef65fe..56d891d 100644 --- a/demos/source/demos/space_invaders.d +++ b/demos/source/demos/space_invaders.d @@ -16,6 +16,8 @@ import ecs_utils.gfx.texture; import ecs_utils.math.vector; import ecs_utils.utils; +import std.math : PI; + //import std.array : staticArray; enum float px = 1.0/512.0; @@ -121,6 +123,16 @@ struct CScale vec2 value = vec2(16,16); } +struct CRotation +{ + mixin ECS.Component; + + ///use component as it value + alias value this; + + float value = 0; +} + struct CTexture { mixin ECS.Component; @@ -176,6 +188,17 @@ struct CLaserWeapon { mixin ECS.Component; + static struct Level + { + float reload_time; + float dispersion; + } + + __gshared Level[12] levels = [Level(4000,0),Level(4000,0.1), + Level(500,0),Level(350,0),Level(250,0.02),Level(175,0.03),Level(110,0.04), + Level(80,0.05),Level(50,0.08),Level(20,0.1),Level(10,0.12),Level(2,0.14)]; + + ubyte level = 1; float shoot_time = 0; } @@ -208,13 +231,30 @@ struct CShootGrid mixin ECS.Component; } +struct CTargetPartent +{ + mixin ECS.Component; + + EntityID parent; + vec2 rel_pos; +} + struct CHitPoints { mixin ECS.Component; alias value this; - int value = 10; + int value = 3; +} + +struct CMaxHitPoints +{ + mixin ECS.Component; + + alias value this; + + int value = 3; } struct CHitMark @@ -229,6 +269,47 @@ struct CHitMark struct CUpgrade { mixin ECS.Component; + + alias value this; + + enum Upgrade : ubyte + { + hit_points, + regeneration, + laser + } + + Upgrade value; +} + +struct CAnimation +{ + mixin ECS.Component; + + vec4[] frames; + float time = 0; + float speed = 1; +} + +struct CAnimationLooped +{ + mixin ECS.Component; +} + +struct CDamping +{ + mixin ECS.Component; + + alias value this; + + byte value = 0; +} + +struct CParticle +{ + mixin ECS.Component; + + float life = 0; } /*####################################################################################################################### @@ -436,6 +517,7 @@ struct DrawSystem @readonly CTexture[] textures; @readonly CLocation[] locations; @readonly CScale[] scale; + @readonly @optional CRotation[] rotation; @readonly @optional CDepth[] depth; @readonly @optional CHitMark[] hit_mark; } @@ -452,6 +534,13 @@ struct DrawSystem launcher.renderer.draw(data.textures[i].tex, data.locations[i].value, data.scale[i], data.textures[i].coords, cast(short)data.locations[i].y, color, 0, 0, 0, data.thread_id); } } + else if(data.rotation) + { + foreach(i; 0..data.length) + { + launcher.renderer.draw(data.textures[i].tex, data.locations[i].value, data.scale[i], data.textures[i].coords, cast(short)data.locations[i].y, 0x80808080, data.rotation[i], 0, 0, data.thread_id); + } + } else { foreach(i; 0..data.length) @@ -463,18 +552,36 @@ struct DrawSystem else { if(data.hit_mark) + { + if(data.rotation) + { + foreach(i; 0..data.length) + { + uint color = 0x80808080 + 0x01010101 * data.hit_mark[i]; + launcher.renderer.draw(data.textures[i].tex, data.locations[i].value, data.scale[i], data.textures[i].coords, cast(short)(data.depth[i] * 4 + data.locations[i].y), color, data.rotation[i], 0, 0, data.thread_id); + } + } + else + { + foreach(i; 0..data.length) + { + uint color = 0x80808080 + 0x01010101 * data.hit_mark[i]; + launcher.renderer.draw(data.textures[i].tex, data.locations[i].value, data.scale[i], data.textures[i].coords, cast(short)(data.depth[i] * 4 + data.locations[i].y), color, 0, 0, 0, data.thread_id); + } + } + } + else if(data.rotation) { foreach(i; 0..data.length) { - uint color = 0x80808080 + 0x01010101 * data.hit_mark[i]; - launcher.renderer.draw(data.textures[i].tex, data.locations[i].value, data.scale[i], data.textures[i].coords, cast(short)(data.depth[i] * 64 + data.locations[i].y), color, 0, 0, 0, data.thread_id); + launcher.renderer.draw(data.textures[i].tex, data.locations[i].value, data.scale[i], data.textures[i].coords, cast(short)(data.depth[i] * 4 + data.locations[i].y), 0x80808080, data.rotation[i], 0, 0, data.thread_id); } } else { foreach(i; 0..data.length) { - launcher.renderer.draw(data.textures[i].tex, data.locations[i].value, data.scale[i], data.textures[i].coords, cast(short)(data.depth[i] * 64 + data.locations[i].y), 0x80808080, 0, 0, 0, data.thread_id); + launcher.renderer.draw(data.textures[i].tex, data.locations[i].value, data.scale[i], data.textures[i].coords, cast(short)(data.depth[i] * 4 + data.locations[i].y), 0x80808080, 0, 0, 0, data.thread_id); } } } @@ -502,12 +609,19 @@ struct LaserShootingSystem mixin ECS.System!32; bool shoot = false; - static float[18] laser_shoot_times = [500,400,300,200,100,50,25,10,5,2,1,0.8,0.6,0.5,0.4,0.3,0.2,0.1]; + //static float[18] laser_shoot_times = [500,400,300,200,100,50,25,10,5,2,1,0.8,0.6,0.5,0.4,0.3,0.2,0.1]; + //static float[18] laser_shoot_disp = [0,0,0,0,0.05,0.06,0.08,0.1,0.14,0.18,0.2,0.25,0.26,0.27,0.28,0.29,0.3,0.4]; + + __gshared vec4[] fire_frames = [vec4(96,64,8,16)*px,vec4(104,64,8,16)*px,vec4(112,64,8,16)*px,vec4(120,64,8,16)*px,vec4(128,64,8,16)*px, + vec4(136,64,8,16)*px,vec4(144,64,8,16)*px,vec4(152,64,8,16)*px,vec4(160,64,8,16)*px]; + + // __gshared vec4[] fire_frames = [vec4(0,160,8,16)*px,vec4(16,160,16,16)*px,vec4(32,160,16,16)*px,vec4(48,160,16,16)*px,vec4(64,160,16,16)*px, + // vec4(80,160,16,16)*px,vec4(96,160,16,16)*px,vec4(112,160,16,16)*px]; /*CLocation* laser_location; CVelocity* laser_velocity; CGuild* laser_guild;*/ - + struct EntitiesData { ///variable named "length" contain entites count @@ -518,6 +632,7 @@ struct LaserShootingSystem @readonly @optional CAutoShoot[] auto_shoot; @readonly CLocation[] location; @readonly CGuild[] guild; + @optional @readonly CVelocity[] velocity; CLaserWeapon[] laser; } @@ -527,6 +642,11 @@ struct LaserShootingSystem CLocation* laser_location; CVelocity* laser_velocity; CGuild* laser_guild; + + EntityTemplate* fire_tmpl; + CLocation* fire_location; + CVelocity* fire_velocity; + CRotation* fire_rotation; } ThreadData[] threads; @@ -535,7 +655,10 @@ struct LaserShootingSystem void onCreate() { threads = Mallocator.makeArray!ThreadData(32); - threads[0].laser_tmpl = launcher.manager.allocateTemplate([CLocation.component_id, CTexture.component_id, CVelocity.component_id, CScale.component_id, CLaser.component_id, CGuild.component_id].staticArray); + threads[0].laser_tmpl = launcher.manager.allocateTemplate( + [CLocation.component_id, CTexture.component_id, CVelocity.component_id, + CScale.component_id, CLaser.component_id, CGuild.component_id].staticArray + ); CTexture* tex_comp = threads[0].laser_tmpl.getComponent!CTexture; tex_comp.tex = space_invaders.texture;//laser_tex; @@ -546,12 +669,33 @@ struct LaserShootingSystem threads[0].laser_velocity = threads[0].laser_tmpl.getComponent!CVelocity; threads[0].laser_guild = threads[0].laser_tmpl.getComponent!CGuild; + threads[0].fire_tmpl = launcher.manager.allocateTemplate( + [CLocation.component_id, CTexture.component_id, CScale.component_id, + CAnimation.component_id, CParticle.component_id, CRotation.component_id, + CVelocity.component_id, CDamping.component_id].staticArray + ); + + tex_comp = threads[0].fire_tmpl.getComponent!CTexture; + tex_comp.tex = space_invaders.texture;//laser_tex; + tex_comp.coords = vec4(96*px,64*px,8*px,16*px); + scale_comp = threads[0].fire_tmpl.getComponent!CScale; + scale_comp.value = vec2(8,16); + threads[0].fire_location = threads[0].fire_tmpl.getComponent!CLocation; + threads[0].fire_rotation = threads[0].fire_tmpl.getComponent!CRotation; + threads[0].fire_velocity = threads[0].fire_tmpl.getComponent!CVelocity; + threads[0].fire_tmpl.getComponent!(CParticle).life = 300; + *threads[0].fire_tmpl.getComponent!(CAnimation) = CAnimation(fire_frames, 0, 3); + foreach(ref ThreadData thread;threads[1..$]) { thread.laser_tmpl = launcher.manager.allocateTemplate(threads[0].laser_tmpl); thread.laser_location = thread.laser_tmpl.getComponent!CLocation; thread.laser_velocity = thread.laser_tmpl.getComponent!CVelocity; thread.laser_guild = thread.laser_tmpl.getComponent!CGuild; + thread.fire_tmpl = launcher.manager.allocateTemplate(threads[0].fire_tmpl); + thread.fire_location = thread.fire_tmpl.getComponent!CLocation; + thread.fire_rotation = thread.fire_tmpl.getComponent!CRotation; + thread.fire_velocity = thread.fire_tmpl.getComponent!CVelocity; } //laser_location = space_invaders.laser_tmpl.getComponent!CLocation; } @@ -588,13 +732,34 @@ struct LaserShootingSystem { CLaserWeapon* laser = &data.laser[i]; laser.shoot_time += launcher.delta_time; - while(laser.shoot_time > laser_shoot_times[laser.level - 1]) + while(laser.shoot_time > CLaserWeapon.levels[laser.level - 1].reload_time) { - laser.shoot_time -= laser_shoot_times[laser.level - 1]; + laser.shoot_time -= CLaserWeapon.levels[laser.level - 1].reload_time; thread.laser_location.value = data.location[i]; - thread.laser_velocity.value = vec2(randomf()*0.5-0.25,data.shoot_direction[i].direction == Direction.up ? 1.0 : -1.0); + thread.laser_velocity.value = vec2((randomf()*2-1) * CLaserWeapon.levels[laser.level - 1].dispersion,data.shoot_direction[i].direction == Direction.up ? 1.0 : -1.0); thread.laser_guild.guild = data.guild[i].guild; + + if(data.velocity) + { + thread.fire_velocity.value = data.velocity[i]; + //thread.laser_velocity.value += data.velocity[i] * 0.5; + } + else thread.fire_velocity.value = vec2(0,0); + launcher.manager.addEntity(thread.laser_tmpl); + + thread.fire_location.value = data.location[i]; + if(data.shoot_direction[i].direction == Direction.down) + { + thread.fire_rotation.value = PI; + thread.fire_location.value.y -= 16; + } + else + { + thread.fire_rotation.value = 0; + thread.fire_location.value.y += 24; + } + launcher.manager.addEntity(thread.fire_tmpl); } } } @@ -604,13 +769,47 @@ struct LaserShootingSystem { CLaserWeapon* laser = &data.laser[i]; laser.shoot_time += launcher.delta_time; - if(laser.shoot_time > laser_shoot_times[laser.level - 1])laser.shoot_time = laser_shoot_times[laser.level - 1]; + if(laser.shoot_time > CLaserWeapon.levels[laser.level - 1].reload_time)laser.shoot_time = CLaserWeapon.levels[laser.level - 1].reload_time; } } } } +struct DampingSystem +{ + mixin ECS.System!32; + + struct EntitiesData + { + uint length; + const (Entity)[] entity; + @readonly CDamping[] damping; + CVelocity[] velocity; + } + + float[10] damp = 0; + + bool onBegin() + { + import core.stdc.math : powf; + foreach(i;0..10) + { + damp[i] = powf((0.98 - cast(float)i * 0.02),launcher.delta_time*0.1); + } + + return true; + } + + void onUpdate(EntitiesData data) + { + foreach(i; 0..data.length) + { + data.velocity[i] = data.velocity[i] * damp[data.damping[i]]; + } + } +} + struct LaserCollisionSystem { mixin ECS.System!32; @@ -689,7 +888,7 @@ struct UpgradeSystem CLaserWeapon* laser = entity.getComponent!CLaserWeapon; if(laser) { - if(laser.level < LaserShootingSystem.laser_shoot_times.length)laser.level++; + if(laser.level < CLaserWeapon.levels.length)laser.level++; } } } @@ -884,9 +1083,15 @@ struct HitPointsSystem { mixin ECS.System; + __gshared vec4[] upgrade_laser_frames = [vec4(96,80,16,16)*px,vec4(112,80,16,16)*px,vec4(128,80,16,16)*px,vec4(144,80,16,16)*px,vec4(128,80,16,16)*px,vec4(112,80,16,16)*px]; + __gshared vec4[] explosion_laser_frames = [vec4(80,128,16,16)*px,vec4(96,128,16,16)*px,vec4(112,128,16,16)*px,vec4(128,128,16,16)*px,vec4(144,128,16,16)*px,vec4(160,128,16,16)*px,vec4(176,128,16,16)*px,vec4(192,128,16,16)*px,vec4(208,128,16,16)*px]; + EntityTemplate* upgrade_tmpl; CLocation* upgrade_location; + EntityTemplate* explosion_tmpl; + CLocation* explosion_location; + struct EntitiesData { CHitPoints[] hp; @@ -894,13 +1099,21 @@ struct HitPointsSystem void onCreate() { - upgrade_tmpl = launcher.manager.allocateTemplate([CVelocity.component_id, CLocation.component_id, CTexture.component_id, CScale.component_id, CUpgrade.component_id].staticArray); + upgrade_tmpl = launcher.manager.allocateTemplate([CVelocity.component_id, CLocation.component_id, CTexture.component_id, CScale.component_id, CUpgrade.component_id, CAnimation.component_id, CAnimationLooped.component_id].staticArray); CTexture* tex_comp = upgrade_tmpl.getComponent!CTexture; tex_comp.tex = space_invaders.texture;//ship_tex; tex_comp.coords = vec4(0*px,32*px,16*px,16*px); + *upgrade_tmpl.getComponent!CAnimation = CAnimation(upgrade_laser_frames, 0, 1); CVelocity* vel_comp = upgrade_tmpl.getComponent!CVelocity; vel_comp.value = vec2(0,-0.1); upgrade_location = upgrade_tmpl.getComponent!CLocation; + + explosion_tmpl = launcher.manager.allocateTemplate([CDepth.component_id, CParticle.component_id, CLocation.component_id, CTexture.component_id, CScale.component_id, CAnimation.component_id].staticArray); + explosion_tmpl.getComponent!(CTexture).tex = space_invaders.texture; + *explosion_tmpl.getComponent!CAnimation = CAnimation(explosion_laser_frames, 0, 1.333); + explosion_tmpl.getComponent!(CParticle).life = 600; + *explosion_tmpl.getComponent!CDepth = -1; + explosion_location = explosion_tmpl.getComponent!CLocation; } void onDestroy() @@ -911,9 +1124,9 @@ struct HitPointsSystem void handleEvent(Entity* entity, EDamage event) { CHitPoints* hp = entity.getComponent!CHitPoints; - if(*hp < 0)return; + if(*hp <= 0)return; *hp -= event.damage; - if(*hp < 0) + if(*hp <= 0) { launcher.manager.sendEvent(entity.id, EDeath()); //launcher.manager.removeEntity(entity.id); @@ -927,14 +1140,16 @@ struct HitPointsSystem CEnemy* enemy = entity.getComponent!CEnemy; if(enemy) { - if(randomRange(0, 1000) < 5) + CLocation* location = entity.getComponent!CLocation; + if(location) { - CLocation* location = entity.getComponent!CLocation; - if(location) + if(randomRange(0, 1000) < 5) { *upgrade_location = *location; launcher.manager.addEntity(upgrade_tmpl); } + *explosion_location = *location; + launcher.manager.addEntity(explosion_tmpl); } } launcher.manager.removeEntity(entity.id); @@ -1031,7 +1246,7 @@ struct MovementSystem //@optional const (CLaser)[] laser; const (Entity)[] entities; - @optional CSideMove[] side_move; + //@optional CSideMove[] side_move; } void onUpdate(EntitiesData data) @@ -1044,6 +1259,63 @@ struct MovementSystem } } +struct AnimationSystem +{ + mixin ECS.System!32; + + struct EntitiesData + { + uint length; + CAnimation[] animation; + CTexture[] texture; + @optional @readonly CAnimationLooped[] looped; + } + + void onUpdate(EntitiesData data) + { + float dt = launcher.delta_time * 0.01; + if(data.looped) + { + foreach(i;0..data.length) + { + data.animation[i].time += dt * data.animation[i].speed; + while(data.animation[i].time >= data.animation[i].frames.length)data.animation[i].time -= cast(float)data.animation[i].frames.length; + data.texture[i].coords = data.animation[i].frames[cast(int)(data.animation[i].time)]; + } + } + else + { + foreach(i;0..data.length) + { + data.animation[i].time += dt * data.animation[i].speed; + if(data.animation[i].time >= data.animation[i].frames.length)data.animation[i].time = data.animation[i].frames.length - 0.1; + data.texture[i].coords = data.animation[i].frames[cast(int)(data.animation[i].time)]; + } + } + + } +} + +struct ParticleSystem +{ + mixin ECS.System!32; + + struct EntitiesData + { + uint length; + @readonly Entity[] entitiy; + CParticle[] particle; + } + + void onUpdate(EntitiesData data) + { + foreach(i;0..data.length) + { + data.particle[i].life -= launcher.delta_time; + if(data.particle[i].life < 0)launcher.manager.removeEntity(data.entitiy[i].id); + } + } +} extern(C) float sqrtf(float x) @nogc nothrow @system; @@ -1063,7 +1335,8 @@ struct InputMovementSystem //read only components can be marked with @readonly attribute or with const expression instead const (CInput)[] input; //components are treated as required by default - CLocation[] locations; + //CLocation[] locations; + CVelocity[] velocity; CTexture[] textures; } @@ -1108,22 +1381,33 @@ struct InputMovementSystem */ void onUpdate(EntitiesData data) { - if(move_vector.x == 0) + /*if(move_vector.x == 0) { foreach(i; 0..data.length) { data.textures[i].coords = vec4(0*px,80*px,48*px,32*px); } //return; - } + }*/ //move every entity using movement vector + //if(move_vector.x != 0 || move_vector.y != 0) foreach(i; 0..data.length) { - data.locations[i].x += move_vector.x * launcher.delta_time * 0.25; - data.locations[i].y += move_vector.y * launcher.delta_time * 0.25; - if(move_vector.x > 0)data.textures[i].coords = vec4(48*px,80*px,48*px,32*px); - else data.textures[i].coords = vec4(0*px,80*px,48*px,32*px); + data.velocity[i] += move_vector * launcher.delta_time * 0.005; + if(data.velocity[i].x > 0.5)data.velocity[i].x = 0.5; + else if(data.velocity[i].x < -0.5)data.velocity[i].x = -0.5; + if(data.velocity[i].y > 0.5)data.velocity[i].y = 0.5; + else if(data.velocity[i].y < -0.5)data.velocity[i].y = -0.5; + //data.locations[i].x += move_vector.x * launcher.delta_time * 0.25; + //data.locations[i].y += move_vector.y * launcher.delta_time * 0.25; + //if(move_vector.x > 0)data.textures[i].coords = vec4(48*px,80*px,48*px,32*px); + //else data.textures[i].coords = vec4(0*px,80*px,48*px,32*px); } + /*else + foreach(i; 0..data.length) + { + data.velocity[i] = vec2(0,0); + }*/ } } @@ -1165,6 +1449,12 @@ void spaceInvadersStart() launcher.manager.registerComponent!CHitPoints; launcher.manager.registerComponent!CHitMark; launcher.manager.registerComponent!CUpgrade; + launcher.manager.registerComponent!CParticle; + launcher.manager.registerComponent!CMaxHitPoints; + launcher.manager.registerComponent!CAnimation; + launcher.manager.registerComponent!CRotation; + launcher.manager.registerComponent!CAnimationLooped; + launcher.manager.registerComponent!CDamping; launcher.manager.registerEvent!EChangeDirection; launcher.manager.registerEvent!EDamage; @@ -1185,6 +1475,9 @@ void spaceInvadersStart() launcher.manager.registerSystem!HitMarkingSystem(-100); launcher.manager.registerSystem!UpgradeCollisionSystem(-70); launcher.manager.registerSystem!UpgradeSystem(-100); + launcher.manager.registerSystem!ParticleSystem(-100); + launcher.manager.registerSystem!AnimationSystem(-100); + launcher.manager.registerSystem!DampingSystem(-101); launcher.manager.endRegister(); @@ -1197,8 +1490,13 @@ void spaceInvadersStart() //launcher.manager.getSystem(CleanSystem.system_id).disable(); { - ushort[11] components = [CHitMark.component_id, CHitPoints.component_id, CLocation.component_id, CTexture.component_id, CInput.component_id, CShip.component_id, CScale.component_id, CLaserWeapon.component_id, CShootDirection.component_id, CShootGrid.component_id, CGuild.component_id]; - space_invaders.ship_tmpl = launcher.manager.allocateTemplate(components); + space_invaders.ship_tmpl = launcher.manager.allocateTemplate( + [CVelocity.component_id, CHitMark.component_id, CHitPoints.component_id, + CLocation.component_id, CTexture.component_id, CInput.component_id, + CShip.component_id, CScale.component_id, CLaserWeapon.component_id, + CShootDirection.component_id, CShootGrid.component_id, CGuild.component_id, + CDamping.component_id].staticArray + ); CScale* scale_comp = space_invaders.ship_tmpl.getComponent!CScale; scale_comp.value = vec2(48,32); @@ -1208,8 +1506,9 @@ void spaceInvadersStart() CLocation* loc_comp = space_invaders.ship_tmpl.getComponent!CLocation; loc_comp.value = vec2(64,64); CLaserWeapon* weapon = space_invaders.ship_tmpl.getComponent!CLaserWeapon; - weapon.level = 1; + weapon.level = 3; space_invaders.ship_tmpl.getComponent!CHitPoints().value = 1000; + space_invaders.ship_tmpl.getComponent!CDamping().value = 7; launcher.manager.addEntity(space_invaders.ship_tmpl); } @@ -1273,12 +1572,13 @@ void spaceInvadersStart() EntityTemplate* upgrade_tmpl; { - upgrade_tmpl = launcher.manager.allocateTemplate([CVelocity.component_id, CLocation.component_id, CTexture.component_id, CScale.component_id, CUpgrade.component_id].staticArray); + upgrade_tmpl = launcher.manager.allocateTemplate([CVelocity.component_id, CLocation.component_id, CTexture.component_id, CScale.component_id, CUpgrade.component_id, CAnimationLooped.component_id, CAnimation.component_id].staticArray); CTexture* tex_comp = upgrade_tmpl.getComponent!CTexture; tex_comp.tex = space_invaders.texture;//ship_tex; tex_comp.coords = vec4(0*px,32*px,16*px,16*px); CVelocity* vel_comp = upgrade_tmpl.getComponent!CVelocity; vel_comp.value = vec2(0,-0.1); + *upgrade_tmpl.getComponent!CAnimation = CAnimation(HitPointsSystem.upgrade_laser_frames, 0, 0.75); } launcher.manager.commit(); @@ -1326,7 +1626,7 @@ void spaceInvadersTool(vec2 position, Tool tool, int size) CLaserWeapon* laser_weapon = tmpl.getComponent!CLaserWeapon; if(laser_weapon) { - laser_weapon.shoot_time = randomf * LaserShootingSystem.laser_shoot_times[laser_weapon.level - 1]; + laser_weapon.shoot_time = randomf * CLaserWeapon.levels[laser_weapon.level - 1].reload_time; } launcher.manager.addEntity(tmpl); } diff --git a/demos/utils/source/ecs_utils/gfx/renderer.d b/demos/utils/source/ecs_utils/gfx/renderer.d index 206364f..95f8aa6 100644 --- a/demos/utils/source/ecs_utils/gfx/renderer.d +++ b/demos/utils/source/ecs_utils/gfx/renderer.d @@ -535,12 +535,30 @@ struct Renderer verts[item_id*28] = cast(short)(((GfxConfig.meshes[mesh_id].vertices[0] * coss + GfxConfig.meshes[mesh_id].vertices[1] * sinn) * size.x + pos.x) * 8191); verts[item_id*28+1] = cast(short)(((GfxConfig.meshes[mesh_id].vertices[1] * coss - GfxConfig.meshes[mesh_id].vertices[0] * sinn) * size.y + pos.y) * 8191); + verts[item_id*28+2] = cast(short)((GfxConfig.meshes[mesh_id].vertices[2] * coords.z + coords.x)*32767); + verts[item_id*28+3] = cast(short)((GfxConfig.meshes[mesh_id].vertices[3] * coords.w + coords.y)*32767); + memcpy(verts.ptr+item_id*28+4,mem.ptr,6); + + verts[item_id*28+7] = cast(short)(((GfxConfig.meshes[mesh_id].vertices[4] * coss + GfxConfig.meshes[mesh_id].vertices[5] * sinn) * size.x + pos.x) * 8191); verts[item_id*28+8] = cast(short)(((GfxConfig.meshes[mesh_id].vertices[5] * coss - GfxConfig.meshes[mesh_id].vertices[4] * sinn) * size.y + pos.y) * 8191); + verts[item_id*28+9] = cast(short)((GfxConfig.meshes[mesh_id].vertices[6] * coords.z + coords.x)*32767); + verts[item_id*28+10] = cast(short)((GfxConfig.meshes[mesh_id].vertices[7] * coords.w + coords.y)*32767); + memcpy(verts.ptr+item_id*28+11,mem.ptr,6); + + verts[item_id*28+14] = cast(short)(((GfxConfig.meshes[mesh_id].vertices[8] * coss + GfxConfig.meshes[mesh_id].vertices[9] * sinn) * size.x + pos.x) * 8191); verts[item_id*28+15] = cast(short)(((GfxConfig.meshes[mesh_id].vertices[9] * coss - GfxConfig.meshes[mesh_id].vertices[8] * sinn) * size.y + pos.y) * 8191); + verts[item_id*28+16] = cast(short)((GfxConfig.meshes[mesh_id].vertices[10] * coords.z + coords.x)*32767); + verts[item_id*28+17] = cast(short)((GfxConfig.meshes[mesh_id].vertices[11] * coords.w + coords.y)*32767); + memcpy(verts.ptr+item_id*28+18,mem.ptr,6); + + verts[item_id*28+21] = cast(short)(((GfxConfig.meshes[mesh_id].vertices[12] * coss + GfxConfig.meshes[mesh_id].vertices[13] * sinn) * size.x + pos.x) * 8191); verts[item_id*28+22] = cast(short)(((GfxConfig.meshes[mesh_id].vertices[13] * coss - GfxConfig.meshes[mesh_id].vertices[12] * sinn) * size.y + pos.y) * 8191); + verts[item_id*28+23] = cast(short)((GfxConfig.meshes[mesh_id].vertices[14] * coords.z + coords.x)*32767); + verts[item_id*28+24] = cast(short)((GfxConfig.meshes[mesh_id].vertices[15] * coords.w + coords.y)*32767); + memcpy(verts.ptr+item_id*28+25,mem.ptr,6); } /*verts[item_id*28+2] = cast(short)((GfxConfig.meshes[mesh_id].vertices[2] * coords.z + coords.x)*32767); diff --git a/demos/utils/source/ecs_utils/math/vector.d b/demos/utils/source/ecs_utils/math/vector.d index a74b6db..a8f14f8 100644 --- a/demos/utils/source/ecs_utils/math/vector.d +++ b/demos/utils/source/ecs_utils/math/vector.d @@ -2,6 +2,18 @@ module ecs_utils.math.vector; struct vec2 { + this(float v) @nogc nothrow + { + x = v; + y = v; + } + + this(float x, float y) @nogc nothrow + { + this.x = x; + this.y = y; + } + union { struct @@ -75,6 +87,22 @@ struct vec4 float[4] data; } + this(float v) @nogc nothrow + { + x = v; + y = v; + z = v; + w = v; + } + + this(float x, float y, float z, float w) @nogc nothrow + { + this.x = x; + this.y = y; + this.z = z; + this.w = w; + } + vec4 opBinary(string op)(float v) { static if (op == "+") return vec4(x + v, y + v, z + v, w + v); @@ -96,6 +124,18 @@ struct ivec2 } int[2] data; } + + this(int v) @nogc nothrow + { + x = v; + y = v; + } + + this(int x, int y) @nogc nothrow + { + this.x = x; + this.y = y; + } ivec2 opBinary(string op, T)(T v) { @@ -125,4 +165,20 @@ struct ivec4 } int[4] data; } + + this(int v) @nogc nothrow + { + x = v; + y = v; + z = v; + w = v; + } + + this(int x, int y, int z, int w) @nogc nothrow + { + this.x = x; + this.y = y; + this.z = z; + this.w = w; + } } \ No newline at end of file From abc4d0c509765bf3d3f66cf1ad466f95bafa81ec Mon Sep 17 00:00:00 2001 From: Mergul Date: Fri, 22 May 2020 15:40:53 +0200 Subject: [PATCH 137/217] Modified codecov.yml --- codecov.yml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/codecov.yml b/codecov.yml index f3e0d9b..5672706 100644 --- a/codecov.yml +++ b/codecov.yml @@ -7,6 +7,4 @@ coverage: project: default: threshold: 5 - patch: - default: - threshold: 5 \ No newline at end of file + patch: off \ No newline at end of file From d89df28f85309bdd5ccad7ffed828973b6636c6c Mon Sep 17 00:00:00 2001 From: Mergul Date: Fri, 22 May 2020 15:41:28 +0200 Subject: [PATCH 138/217] Fixed rendering of rotated entities --- demos/utils/source/ecs_utils/gfx/renderer.d | 28 ++++++++++++--------- 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/demos/utils/source/ecs_utils/gfx/renderer.d b/demos/utils/source/ecs_utils/gfx/renderer.d index 95f8aa6..1b46eaf 100644 --- a/demos/utils/source/ecs_utils/gfx/renderer.d +++ b/demos/utils/source/ecs_utils/gfx/renderer.d @@ -472,8 +472,7 @@ struct Renderer { //if(item_id >= MaxObjects)return; //pos += view_pos; - size.x *= view_size.x; - size.y *= view_size.y; + pos.x = pos.x * view_size.x + view_pos.x; pos.y = pos.y * view_size.y + view_pos.y;//*/ @@ -491,6 +490,9 @@ struct Renderer if(angle == 0) { + size.x *= view_size.x; + size.y *= view_size.y; + verts[item_id*28] = cast(short)((GfxConfig.meshes[mesh_id].vertices[0] * size.x + pos.x) * 8191); verts[item_id*28+1] = cast(short)((GfxConfig.meshes[mesh_id].vertices[1] * size.y + pos.y) * 8191); verts[item_id*28+2] = cast(short)((GfxConfig.meshes[mesh_id].vertices[2] * coords.z + coords.x)*32767); @@ -521,8 +523,10 @@ struct Renderer else { //import core.stdc.math; - float sinn = sinf(angle); - float coss = cosf(angle); + float sinx = sinf(angle) * size.x * view_size.y; + float cosx = cosf(angle) * size.x * view_size.x; + float siny = sinf(angle) * size.y * view_size.x; + float cosy = cosf(angle) * size.y * view_size.y; /*batch_vertices[item_id*28] = GfxConfig.meshes[mesh_id].vertices[0] * size.x; batch_vertices[item_id*28+1] = GfxConfig.meshes[mesh_id].vertices[1] * size.y; @@ -533,29 +537,29 @@ struct Renderer batch_vertices[item_id*28+12] = GfxConfig.meshes[mesh_id].vertices[12] * size.x; batch_vertices[item_id*28+13] = GfxConfig.meshes[mesh_id].vertices[13] * size.y;*/ - verts[item_id*28] = cast(short)(((GfxConfig.meshes[mesh_id].vertices[0] * coss + GfxConfig.meshes[mesh_id].vertices[1] * sinn) * size.x + pos.x) * 8191); - verts[item_id*28+1] = cast(short)(((GfxConfig.meshes[mesh_id].vertices[1] * coss - GfxConfig.meshes[mesh_id].vertices[0] * sinn) * size.y + pos.y) * 8191); + verts[item_id*28] = cast(short)(((GfxConfig.meshes[mesh_id].vertices[0] * cosx + GfxConfig.meshes[mesh_id].vertices[1] * siny) + pos.x) * 8191); + verts[item_id*28+1] = cast(short)(((GfxConfig.meshes[mesh_id].vertices[1] * cosy - GfxConfig.meshes[mesh_id].vertices[0] * sinx) + pos.y) * 8191); verts[item_id*28+2] = cast(short)((GfxConfig.meshes[mesh_id].vertices[2] * coords.z + coords.x)*32767); verts[item_id*28+3] = cast(short)((GfxConfig.meshes[mesh_id].vertices[3] * coords.w + coords.y)*32767); memcpy(verts.ptr+item_id*28+4,mem.ptr,6); - verts[item_id*28+7] = cast(short)(((GfxConfig.meshes[mesh_id].vertices[4] * coss + GfxConfig.meshes[mesh_id].vertices[5] * sinn) * size.x + pos.x) * 8191); - verts[item_id*28+8] = cast(short)(((GfxConfig.meshes[mesh_id].vertices[5] * coss - GfxConfig.meshes[mesh_id].vertices[4] * sinn) * size.y + pos.y) * 8191); + verts[item_id*28+7] = cast(short)(((GfxConfig.meshes[mesh_id].vertices[4] * cosx + GfxConfig.meshes[mesh_id].vertices[5] * siny) + pos.x) * 8191); + verts[item_id*28+8] = cast(short)(((GfxConfig.meshes[mesh_id].vertices[5] * cosy - GfxConfig.meshes[mesh_id].vertices[4] * sinx) + pos.y) * 8191); verts[item_id*28+9] = cast(short)((GfxConfig.meshes[mesh_id].vertices[6] * coords.z + coords.x)*32767); verts[item_id*28+10] = cast(short)((GfxConfig.meshes[mesh_id].vertices[7] * coords.w + coords.y)*32767); memcpy(verts.ptr+item_id*28+11,mem.ptr,6); - verts[item_id*28+14] = cast(short)(((GfxConfig.meshes[mesh_id].vertices[8] * coss + GfxConfig.meshes[mesh_id].vertices[9] * sinn) * size.x + pos.x) * 8191); - verts[item_id*28+15] = cast(short)(((GfxConfig.meshes[mesh_id].vertices[9] * coss - GfxConfig.meshes[mesh_id].vertices[8] * sinn) * size.y + pos.y) * 8191); + verts[item_id*28+14] = cast(short)(((GfxConfig.meshes[mesh_id].vertices[8] * cosx + GfxConfig.meshes[mesh_id].vertices[9] * siny) + pos.x) * 8191); + verts[item_id*28+15] = cast(short)(((GfxConfig.meshes[mesh_id].vertices[9] * cosy - GfxConfig.meshes[mesh_id].vertices[8] * sinx) + pos.y) * 8191); verts[item_id*28+16] = cast(short)((GfxConfig.meshes[mesh_id].vertices[10] * coords.z + coords.x)*32767); verts[item_id*28+17] = cast(short)((GfxConfig.meshes[mesh_id].vertices[11] * coords.w + coords.y)*32767); memcpy(verts.ptr+item_id*28+18,mem.ptr,6); - verts[item_id*28+21] = cast(short)(((GfxConfig.meshes[mesh_id].vertices[12] * coss + GfxConfig.meshes[mesh_id].vertices[13] * sinn) * size.x + pos.x) * 8191); - verts[item_id*28+22] = cast(short)(((GfxConfig.meshes[mesh_id].vertices[13] * coss - GfxConfig.meshes[mesh_id].vertices[12] * sinn) * size.y + pos.y) * 8191); + verts[item_id*28+21] = cast(short)(((GfxConfig.meshes[mesh_id].vertices[12] * cosx + GfxConfig.meshes[mesh_id].vertices[13] * siny) + pos.x) * 8191); + verts[item_id*28+22] = cast(short)(((GfxConfig.meshes[mesh_id].vertices[13] * cosy - GfxConfig.meshes[mesh_id].vertices[12] * sinx) + pos.y) * 8191); verts[item_id*28+23] = cast(short)((GfxConfig.meshes[mesh_id].vertices[14] * coords.z + coords.x)*32767); verts[item_id*28+24] = cast(short)((GfxConfig.meshes[mesh_id].vertices[15] * coords.w + coords.y)*32767); memcpy(verts.ptr+item_id*28+25,mem.ptr,6); From 43f8755a39da1d795a01dc916365973ffeef4f26 Mon Sep 17 00:00:00 2001 From: Mergul Date: Fri, 22 May 2020 15:44:31 +0200 Subject: [PATCH 139/217] Fixed ECS bug related to adding/removing entities inside onAdd/onRemove entity callback Now whole committing process is called in specific order: - UpdateBlocks - ChangeEntities - RemoveEntities - HandleEvents Whole process is repeated until there will be no more changes to commit --- source/bubel/ecs/manager.d | 178 +++++++++++++++++++++++++------------ 1 file changed, 123 insertions(+), 55 deletions(-) diff --git a/source/bubel/ecs/manager.d b/source/bubel/ecs/manager.d index 7b6a983..dc3b9f5 100644 --- a/source/bubel/ecs/manager.d +++ b/source/bubel/ecs/manager.d @@ -2074,10 +2074,10 @@ export struct EntityManager { ThreadData* data = &threads[threadID]; uint num = cast(uint) del_ids.length; - data.change_entities_list.add(0); - data.change_entities_list.add((cast(ubyte*)&entity_id)[0 .. EntityID.sizeof]); - data.change_entities_list.add((cast(ubyte*)&num)[0 .. uint.sizeof]); - data.change_entities_list.add((cast(ubyte*) del_ids.ptr)[0 .. num * 2]); + data.changeEntitiesList.add(0); + data.changeEntitiesList.add((cast(ubyte*)&entity_id)[0 .. EntityID.sizeof]); + data.changeEntitiesList.add((cast(ubyte*)&num)[0 .. uint.sizeof]); + data.changeEntitiesList.add((cast(ubyte*) del_ids.ptr)[0 .. num * 2]); } private void __removeComponents(EntityID entity_id, ushort[] del_ids) @@ -2349,13 +2349,13 @@ export struct EntityManager } ThreadData* data = &threads[threadID]; - data.change_entities_list.add(cast(ubyte) 1u); - data.change_entities_list.add((cast(ubyte*)&entity_id)[0 .. EntityID.sizeof]); - data.change_entities_list.add((cast(ubyte*)&num)[0 .. uint.sizeof]); - data.change_entities_list.add(cast(ubyte[]) new_ids); + data.changeEntitiesList.add(cast(ubyte) 1u); + data.changeEntitiesList.add((cast(ubyte*)&entity_id)[0 .. EntityID.sizeof]); + data.changeEntitiesList.add((cast(ubyte*)&num)[0 .. uint.sizeof]); + data.changeEntitiesList.add(cast(ubyte[]) new_ids); static foreach (i, comp; comps) { - data.change_entities_list.add((cast(ubyte*)&comp)[0 .. comp.sizeof]); + data.changeEntitiesList.add((cast(ubyte*)&comp)[0 .. comp.sizeof]); } //__addComponents(entity_id, new_ids, pointers); @@ -2416,7 +2416,7 @@ export struct EntityManager } if (new_index == 1) - threads[threadID].blocks_to_update.add(new_block); + threads[threadID].blockToUpdate.add(new_block); Entity* new_entity = cast(Entity*) start; //add_mutex.lock_nothrow(); @@ -2466,7 +2466,7 @@ export struct EntityManager } if (index == 1) - threads[threadID].blocks_to_update.add(block); + threads[threadID].blockToUpdate.add(block); Entity* entity = cast(Entity*) start; //add_mutex.lock_nothrow(); @@ -2557,7 +2557,7 @@ export struct EntityManager */ export void removeEntity(EntityID id) { - threads[threadID].entities_to_remove.add(id); + threads[threadID].entitesToRemove.add(id); } private void __removeEntity(EntityID id) nothrow @nogc @@ -2646,47 +2646,51 @@ export struct EntityManager return cast(EntitiesBlock*)(cast(size_t) pointer & (~cast(size_t)(m_page_size - 1))); } - private void changeEntities() + private bool changeEntities() { - foreach (ref thread; threads) + bool has_work = false; + //foreach (ref ThreadData thread; threads)thread.swapToChange(); + foreach (ref ThreadData thread; threads) { uint index = 0; - uint len = cast(uint) thread.change_entities_list.length; + uint len = cast(uint) thread.changeEntitiesListPrev.length; + if(len)has_work = true; void*[32] pointers; // = (cast(void**) alloca(num * (void*).sizeof))[0 .. num]; while (index < len) { - if (!thread.change_entities_list[index++]) + if (!thread.changeEntitiesListPrev[index++]) { - EntityID id = *cast(EntityID*)&thread.change_entities_list[index]; + EntityID id = *cast(EntityID*)&thread.changeEntitiesListPrev[index]; index += EntityID.sizeof; - uint num = *cast(uint*)&thread.change_entities_list[index]; + uint num = *cast(uint*)&thread.changeEntitiesListPrev[index]; index += uint.sizeof; ushort[] ids; // = (cast(ushort*) alloca(num * ushort.sizeof))[0 .. num]; - ids = (cast(ushort*)&thread.change_entities_list[index])[0 .. num]; + ids = (cast(ushort*)&thread.changeEntitiesListPrev[index])[0 .. num]; index += ushort.sizeof * num; __removeComponents(id, ids); } else { - EntityID id = *cast(EntityID*)&thread.change_entities_list[index]; + EntityID id = *cast(EntityID*)&thread.changeEntitiesListPrev[index]; index += EntityID.sizeof; - uint num = *cast(uint*)&thread.change_entities_list[index]; + uint num = *cast(uint*)&thread.changeEntitiesListPrev[index]; index += uint.sizeof; ushort[] ids; // = (cast(ushort*) alloca(num * ushort.sizeof))[0 .. num]; - ids = (cast(ushort*)&thread.change_entities_list[index])[0 .. num]; + ids = (cast(ushort*)&thread.changeEntitiesListPrev[index])[0 .. num]; index += ushort.sizeof * num; //void*[] pointers = (cast(void**) alloca(num * (void*).sizeof))[0 .. num]; foreach (i; 0 .. num) { - pointers[i] = &thread.change_entities_list[index]; + pointers[i] = &thread.changeEntitiesListPrev[index]; index += components[ids[i]].size; } __addComponents(id, ids, pointers[0 .. num]); } } - thread.change_entities_list.clear(); + thread.changeEntitiesListPrev.clear(); } + return has_work; } private void callAddEntityListeners(EntityInfo* info, EntitiesBlock* block, int begin, int end) @nogc nothrow @@ -2767,11 +2771,15 @@ export struct EntityManager (cast(void function(ref ListenerCallData) nothrow @nogc) system.m_change_entity)(data); } - private void updateBlocks() + private bool updateBlocks() { - foreach (ref thread; threads) + bool has_work = false; + //foreach (ref ThreadData thread; threads)thread.swapToUpdate(); + foreach (ref ThreadData thread; threads) { - foreach (block; thread.blocks_to_update) + //thread.swapToUpdate(); + if(thread.blockToUpdatePrev.length)has_work = true; + foreach (block; thread.blockToUpdatePrev) { EntityInfo* info = block.type_info; ushort entities_count = block.entities_count; @@ -2786,30 +2794,35 @@ export struct EntityManager { callAddEntityListeners(info, block, entities_count, block.entities_count); } - } - thread.blocks_to_update.clear(); + thread.blockToUpdatePrev.clear(); } + return has_work; } - private void removeEntities() nothrow @nogc + private bool removeEntities() nothrow @nogc { - foreach (i, ref thread; threads) + bool has_work = false; + //foreach (ref ThreadData thread; threads)thread.swapToRemove(); + foreach (ref ThreadData thread; threads) { - foreach (id; thread.entities_to_remove) + if(thread.entitiesToRemovePrev.length)has_work = true; + foreach (id; thread.entitiesToRemovePrev) { __removeEntity(id); } - thread.entities_to_remove.clear(); + thread.entitiesToRemovePrev.clear(); } + return has_work; } - private void updateEvents() nothrow @nogc + private bool updateEvents() nothrow @nogc { - bool empty = true; - while (1) - { - event_manager.swapCurrent(); + bool has_work = false; + // bool empty = true; + //while (1) + //{ + //event_manager.swapCurrent(); uint current_index; if (event_manager.current_index == 0) current_index = cast(uint) threads.length; @@ -2821,8 +2834,11 @@ export struct EntityManager .. current_index + threads.length]) { EventManager.EventBlock* block = first_block; - if (block) - empty = false; + if (block)has_work = true; + // { + // has_work = true; + // //empty = false; + // } while (block) { EventCallData call_data; @@ -2856,23 +2872,37 @@ export struct EntityManager } } } - if (empty) - break; - empty = true; + // if (empty) + // break; + // empty = true; + //} + return has_work; + } + + private void swapData() nothrow @nogc + { + event_manager.swapCurrent(); + foreach(ref ThreadData thread; threads) + { + thread.swapData(); } } export void commit() { - id_manager.optimize(); - updateBlocks(); - changeEntities(); - - updateEvents(); + bool has_work = true; + while(has_work) + { + swapData(); - id_manager.optimize(); - updateBlocks(); - removeEntities(); + has_work = false; + id_manager.optimize(); + has_work |= updateBlocks(); + has_work |= changeEntities(); + has_work |= removeEntities(); + + has_work |= updateEvents(); + } event_manager.clearEvents(); } @@ -3445,10 +3475,48 @@ export struct EntityManager struct ThreadData { - Vector!EntityID entities_to_remove; - //Vector!ubyte change_entities_list; - SimpleVector change_entities_list; - Vector!(EntitiesBlock*) blocks_to_update; + ref Vector!EntityID entitesToRemove() @nogc nothrow + { + return entities_to_remove[data_index]; + } + + ref SimpleVector changeEntitiesList() @nogc nothrow + { + return change_entities_list[data_index]; + } + + ref Vector!(EntitiesBlock*) blockToUpdate() @nogc nothrow + { + return blocks_to_update[data_index]; + } + + ref Vector!EntityID entitiesToRemovePrev() @nogc nothrow + { + return entities_to_remove[1 - data_index]; + } + + ref SimpleVector changeEntitiesListPrev() @nogc nothrow + { + return change_entities_list[1 - data_index]; + } + + ref Vector!(EntitiesBlock*) blockToUpdatePrev() @nogc nothrow + { + return blocks_to_update[1 - data_index]; + } + + private: + + void swapData() @nogc nothrow + { + data_index = cast(ubyte)(1 - data_index); + } + + Vector!EntityID[2] entities_to_remove; + SimpleVector[2] change_entities_list; + Vector!(EntitiesBlock*)[2] blocks_to_update; + + ubyte data_index = 0; } export struct UpdatePass From bfc0da47e495e7d7e62910d8a95b3c115d01c65b Mon Sep 17 00:00:00 2001 From: Mergul Date: Fri, 22 May 2020 15:58:35 +0200 Subject: [PATCH 140/217] SpaceShip demo updage -Update sprites texture atlas -added support for separate collider and graphical scale -weapon now can be located on specific sprite relative position -SpaceShip has two lasers which are separate entities -added following parent system -added Boss -parent destroy children after being destroyed -added towers (Tower consist of 3 entities, parent take damage and one is weapon) - added targeting system which rotate entity to target --- demos/assets/textures/atlas.png | Bin 35204 -> 41948 bytes demos/source/demos/space_invaders.d | 869 ++++++++++++++++++++++++---- 2 files changed, 772 insertions(+), 97 deletions(-) diff --git a/demos/assets/textures/atlas.png b/demos/assets/textures/atlas.png index 1e269e513e42c5dc797f568af05816d2562995f0..a799eb7706feddc336f6f1e6e75f780dcbea5467 100644 GIT binary patch literal 41948 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 literal 35204 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

      -U`yoWDlL!y69I7g$; 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 space_invaders.map_size.x) + { + if(data.side_move[i].group == -1) + { + if(data.velocity[i].x > 0)data.velocity[i].x = -data.velocity[i].x; + } + else + { + groups_directions[data.side_move[i].group] = Direction.left; + } + } + } + } else { foreach(i;0..data.length) @@ -1024,38 +1472,9 @@ INFO: Uniform block alig groups_directions[data.side_move[i].group] = Direction.left; } } - //if(data.locations[i].y < 0) data.locations[i].y = 0; - //else if(data.locations[i].y > space_invaders.map_size.y)data.locations[i].y = space_invaders.map_size.y; } } } - - /*void handleEvent(Entity* entity, EChangeDirection event) - { - CSideMove* side_move = entity.getComponent!CSideMove; - if(side_move && side_move.group != -1) - { - groups_directions[side_move.group] = event.direction; - return; - } - //Entity* entity = launcher.manager.getEntity(event.entity_id); - CVelocity* velocity = entity.getComponent!CVelocity; - final switch(event.direction) - { - case Direction.up: - if(velocity.value.y > 0)velocity.value.y = -velocity.value.y; - break; - case Direction.down: - if(velocity.value.y < 0)velocity.value.y = -velocity.value.y; - break; - case Direction.left: - if(velocity.value.x > 0)velocity.value.x = -velocity.value.x; - break; - case Direction.right: - if(velocity.value.x < 0)velocity.value.x = -velocity.value.x; - break; - } - }*/ } struct HitMarkingSystem @@ -1101,7 +1520,7 @@ struct HitPointsSystem { upgrade_tmpl = launcher.manager.allocateTemplate([CVelocity.component_id, CLocation.component_id, CTexture.component_id, CScale.component_id, CUpgrade.component_id, CAnimation.component_id, CAnimationLooped.component_id].staticArray); CTexture* tex_comp = upgrade_tmpl.getComponent!CTexture; - tex_comp.tex = space_invaders.texture;//ship_tex; + //tex_comp.tex = space_invaders.texture;//ship_tex; tex_comp.coords = vec4(0*px,32*px,16*px,16*px); *upgrade_tmpl.getComponent!CAnimation = CAnimation(upgrade_laser_frames, 0, 1); CVelocity* vel_comp = upgrade_tmpl.getComponent!CVelocity; @@ -1109,7 +1528,7 @@ struct HitPointsSystem upgrade_location = upgrade_tmpl.getComponent!CLocation; explosion_tmpl = launcher.manager.allocateTemplate([CDepth.component_id, CParticle.component_id, CLocation.component_id, CTexture.component_id, CScale.component_id, CAnimation.component_id].staticArray); - explosion_tmpl.getComponent!(CTexture).tex = space_invaders.texture; + //explosion_tmpl.getComponent!(CTexture).tex = space_invaders.texture; *explosion_tmpl.getComponent!CAnimation = CAnimation(explosion_laser_frames, 0, 1.333); explosion_tmpl.getComponent!(CParticle).life = 600; *explosion_tmpl.getComponent!CDepth = -1; @@ -1156,6 +1575,47 @@ struct HitPointsSystem } } +struct ChildDestroySystem +{ + mixin ECS.System; + + struct EntitiesData + { + CTargetPartent[] parent; + } + + void handleEvent(Entity* entity, EDeath event) + { + CTargetPartent* parent = entity.getComponent!CTargetPartent; + if(parent) + { + launcher.manager.sendEvent(parent.parent, EDestroyedChild(entity.id)); + } + } +} + +struct PartsDestroySystem +{ + mixin ECS.System; + + struct EntitiesData + { + CInit[] init; + CChildren[] children; + CParts[] parts; + } + + void handleEvent(Entity* entity, EDestroyedChild event) + { + CParts* parts = entity.getComponent!CParts; + parts.count--; + if(parts.count == 0) + { + launcher.manager.addComponents(entity.id, CHitPoints(100), CShootGrid()); + } + } +} + struct ClampPositionSystem { mixin ECS.System!32; @@ -1168,7 +1628,10 @@ struct ClampPositionSystem //components are treated as required by default CLocation[] locations; + @optional @readonly CColliderScale[] collider_scale; + @optional @readonly CScale[] scale; @optional const (CLaser)[] laser; + @optional const (CUpgrade)[] upgrade; //@optional CVelocity[] velocity; //@optional const (CSideMove)[] side_move; } @@ -1177,7 +1640,7 @@ struct ClampPositionSystem void onUpdate(EntitiesData data) { - if(data.laser) + if(data.laser || data.upgrade) { foreach(i;0..data.length) { @@ -1219,6 +1682,28 @@ struct ClampPositionSystem else if(data.locations[i].y > space_invaders.map_size.y)data.locations[i].y = space_invaders.map_size.y; } }*/ + else if(data.collider_scale) + { + foreach(i;0..data.length) + { + vec2 hscale = data.collider_scale[i] * 0.5; + if(data.locations[i].x - hscale.x < 0)data.locations[i].x = hscale.x; + else if(data.locations[i].x + hscale.x > space_invaders.map_size.x)data.locations[i].x = space_invaders.map_size.x - hscale.x; + if(data.locations[i].y - hscale.y < 0)data.locations[i].y = hscale.y; + else if(data.locations[i].y + hscale.y > space_invaders.map_size.y)data.locations[i].y = space_invaders.map_size.y - hscale.y; + } + } + else if(data.scale) + { + foreach(i;0..data.length) + { + vec2 hscale = data.scale[i] * 0.5; + if(data.locations[i].x - hscale.x < 0)data.locations[i].x = hscale.x; + else if(data.locations[i].x + hscale.x > space_invaders.map_size.x)data.locations[i].x = space_invaders.map_size.x - hscale.x; + if(data.locations[i].y - hscale.y < 0)data.locations[i].y = hscale.y; + else if(data.locations[i].y + hscale.y > space_invaders.map_size.y)data.locations[i].y = space_invaders.map_size.y - hscale.y; + } + } else { foreach(i;0..data.length) @@ -1317,7 +1802,116 @@ struct ParticleSystem } } +struct RotateToTargetSystem +{ + mixin ECS.System!32; + + struct EntitiesData + { + int length; + @readonly CTarget[] target; + @readonly CLocation[] location; + CRotation[] rotation; + } + + void onUpdate(EntitiesData data) + { + foreach(i;0..data.length) + { + Entity* target = launcher.manager.getEntity(data.target[i].target); + if(target) + { + CLocation* target_loc = target.getComponent!CLocation; + if(target_loc) + { + vec2 rel_pos = target_loc.value - data.location[i]; + float length = sqrtf(rel_pos.x*rel_pos.x + rel_pos.y*rel_pos.y); + if(rel_pos.x > 0)data.rotation[i] = acosf(rel_pos.y/length); + else data.rotation[i] = 2 * PI - acosf(rel_pos.y/length); + + } + } + //CLocation* target_loc = + //vec2 rel_pos = d + //data.rotation = 0; + } + } +} + +struct ShipTargetSystem +{ + mixin ECS.System!32; + + struct EntitiesData + { + int length; + @readonly CTargetPlayerShip[] target_player; + CTarget[] target; + } + + EntityID player_ship; + + void iterateShips(CShipIterator.EntitiesData data) + { + player_ship = data.entity[0].id; + } + + void onAddEntity(EntitiesData data) + { + foreach(i;0..data.length) + { + data.target[i].target = player_ship; + } + } + + bool onBegin() + { + Entity* ship = launcher.manager.getEntity(player_ship); + if(ship is null) + { + launcher.manager.callEntitiesFunction!CShipIterator(&iterateShips); + ship = launcher.manager.getEntity(player_ship); + if(ship is null)return false; + return true; + } + return false; + } + + void onUpdate(EntitiesData data) + { + foreach(i;0..data.length) + { + data.target[i].target = player_ship; + } + } +} + +struct CShipIterator +{ + mixin ECS.System!1; + + struct EntitiesData + { + @readonly Entity[] entity; + @readonly CShip[] ship; + } + + bool onBegin() + { + return false; + } + + void onUpdate(EntitiesData data) + { + + } +} + extern(C) float sqrtf(float x) @nogc nothrow @system; +extern(C) float acosf(float x) @nogc nothrow @system; +extern(C) float sinf(float x) @nogc nothrow @system; +extern(C) float cosf(float x) @nogc nothrow @system; +extern(C) float powf(float x, float y) @nogc nothrow @system; /** *System is responsible for movement of objects with CInput component. @@ -1455,11 +2049,23 @@ void spaceInvadersStart() launcher.manager.registerComponent!CRotation; launcher.manager.registerComponent!CAnimationLooped; launcher.manager.registerComponent!CDamping; + launcher.manager.registerComponent!CTargetPartent; + launcher.manager.registerComponent!CTarget; + launcher.manager.registerComponent!CTargetPlayerShip; + launcher.manager.registerComponent!CChildren; + launcher.manager.registerComponent!CWeaponLocation; + launcher.manager.registerComponent!CInit; + launcher.manager.registerComponent!CBoss; + launcher.manager.registerComponent!CParts; + launcher.manager.registerComponent!CColliderScale; + launcher.manager.registerComponent!CParticleEmitter; + launcher.manager.registerComponent!CParticleEmitterTime; launcher.manager.registerEvent!EChangeDirection; launcher.manager.registerEvent!EDamage; launcher.manager.registerEvent!EUpgrade; launcher.manager.registerEvent!EDeath; + launcher.manager.registerEvent!EDestroyedChild; //launcher.manager.registerSystem!MoveSystem(0); launcher.manager.registerSystem!DrawSystem(100); @@ -1478,7 +2084,16 @@ void spaceInvadersStart() launcher.manager.registerSystem!ParticleSystem(-100); launcher.manager.registerSystem!AnimationSystem(-100); launcher.manager.registerSystem!DampingSystem(-101); - + launcher.manager.registerSystem!MoveToParentTargetSystem(99); + launcher.manager.registerSystem!ParentOwnerSystem(-101); + launcher.manager.registerSystem!ShipWeaponSystem(-100); + + launcher.manager.registerSystem!RotateToTargetSystem(-100); + launcher.manager.registerSystem!ShipTargetSystem(-110); + launcher.manager.registerSystem!CShipIterator(-100); + launcher.manager.registerSystem!PartsDestroySystem(-80); + launcher.manager.registerSystem!ChildDestroySystem(-110); + launcher.manager.endRegister(); launcher.gui_manager.addSystem(DrawSystem.system_id,"Draw System"); @@ -1487,28 +2102,38 @@ void spaceInvadersStart() launcher.gui_manager.addSystem(MovementSystem.system_id,"Movement System"); launcher.gui_manager.addSystem(ClampPositionSystem.system_id,"Clamp Position System"); launcher.gui_manager.addSystem(ChangeDirectionSystem.system_id,"Change Direction System"); + launcher.gui_manager.addSystem(LaserCollisionSystem.system_id,"Draw System"); + launcher.gui_manager.addSystem(ShootGridManager.system_id,"Shoot Grid Manager"); + launcher.gui_manager.addSystem(ShootGridCleaner.system_id,"Shoot Grid Cleaner"); + launcher.gui_manager.addSystem(HitPointsSystem.system_id,"Hit Points System"); + launcher.gui_manager.addSystem(HitMarkingSystem.system_id,"Hit Matking System"); + launcher.gui_manager.addSystem(UpgradeCollisionSystem.system_id,"Upgrade Collision System"); + launcher.gui_manager.addSystem(UpgradeSystem.system_id,"Upgrade System"); + launcher.gui_manager.addSystem(ParticleSystem.system_id,"Particle System"); + launcher.gui_manager.addSystem(AnimationSystem.system_id,"Animation System"); + launcher.gui_manager.addSystem(DampingSystem.system_id,"Damping System"); + launcher.gui_manager.addSystem(MoveToParentTargetSystem.system_id,"Move To Target System"); + launcher.gui_manager.addSystem(ParentOwnerSystem.system_id,"Parent Owner System System"); + launcher.gui_manager.addSystem(ShipWeaponSystem.system_id,"Ship Weapon System"); //launcher.manager.getSystem(CleanSystem.system_id).disable(); { space_invaders.ship_tmpl = launcher.manager.allocateTemplate( [CVelocity.component_id, CHitMark.component_id, CHitPoints.component_id, CLocation.component_id, CTexture.component_id, CInput.component_id, - CShip.component_id, CScale.component_id, CLaserWeapon.component_id, + CShip.component_id, CScale.component_id, CColliderScale.component_id, CShootDirection.component_id, CShootGrid.component_id, CGuild.component_id, - CDamping.component_id].staticArray + CDamping.component_id, CChildren.component_id, CInit.component_id].staticArray ); - - CScale* scale_comp = space_invaders.ship_tmpl.getComponent!CScale; - scale_comp.value = vec2(48,32); - CTexture* tex_comp = space_invaders.ship_tmpl.getComponent!CTexture; - tex_comp.tex = space_invaders.texture;//ship_tex; - tex_comp.coords = vec4(0*px,80*px,48*px,32*px); - CLocation* loc_comp = space_invaders.ship_tmpl.getComponent!CLocation; - loc_comp.value = vec2(64,64); - CLaserWeapon* weapon = space_invaders.ship_tmpl.getComponent!CLaserWeapon; - weapon.level = 3; + //CLaserWeapon* weapon = space_invaders.ship_tmpl.getComponent!CLaserWeapon; + //weapon.level = 3; + space_invaders.ship_tmpl.getComponent!CTexture().coords = vec4(0*px,80*px,48*px,32*px); + space_invaders.ship_tmpl.getComponent!CScale().value = vec2(48,32); + space_invaders.ship_tmpl.getComponent!CLocation().value = vec2(64,64); space_invaders.ship_tmpl.getComponent!CHitPoints().value = 1000; space_invaders.ship_tmpl.getComponent!CDamping().value = 7; + space_invaders.ship_tmpl.getComponent!CInit().type = CInit.Type.space_ship; + space_invaders.ship_tmpl.getComponent!CColliderScale().value = vec2(26,24); launcher.manager.addEntity(space_invaders.ship_tmpl); } @@ -1518,7 +2143,7 @@ void spaceInvadersStart() space_invaders.laser_tmpl = launcher.manager.allocateTemplate(components); CTexture* tex_comp = space_invaders.laser_tmpl.getComponent!CTexture; - tex_comp.tex = space_invaders.texture;//laser_tex; + //tex_comp.tex = 0;//space_invaders.texture;//laser_tex; tex_comp.coords = vec4(0*px,24*px,2*px,8*px); CScale* scale_comp = space_invaders.laser_tmpl.getComponent!CScale; scale_comp.value = vec2(2,8); @@ -1528,15 +2153,63 @@ void spaceInvadersStart() EntityTemplate* enemy_tmpl; EntityTemplate* grouped_tmpl; + EntityTemplate* tower_tmpl; + EntityTemplate* boss_tmpl; + //EntityTemplate* tower_weapon_tmpl; EntityID enemy_id; EntityID grouped_id; { - ushort[12] components = [CHitMark.component_id, CHitPoints.component_id, CVelocity.component_id, CAutoShoot.component_id, CLocation.component_id, CTexture.component_id, CScale.component_id, CLaserWeapon.component_id, CEnemy.component_id, CShootDirection.component_id, CShootGrid.component_id, CGuild.component_id]; - space_invaders.enemy_tmpl = launcher.manager.allocateTemplate(components); + boss_tmpl = launcher.manager.allocateTemplate( + [CHitMark.component_id, CParts.component_id, CLocation.component_id, + CTexture.component_id, CScale.component_id, CEnemy.component_id, + CBoss.component_id, CGuild.component_id, CInit.component_id, + CChildren.component_id, CSideMove.component_id, CVelocity.component_id, + CDepth.component_id].staticArray + ); + + CTexture* tex_comp = boss_tmpl.getComponent!CTexture; + //tex_comp.tex = space_invaders.texture;//ship_tex; + tex_comp.coords = vec4(128*px,0*px,96*px,48*px); + CLocation* loc_comp = boss_tmpl.getComponent!CLocation; + loc_comp.value = vec2(64,space_invaders.map_size.y - 16); + boss_tmpl.getComponent!CGuild().guild = 1; + boss_tmpl.getComponent!CInit().type = CInit.Type.boss; + boss_tmpl.getComponent!CScale().value = vec2(96,48); + boss_tmpl.getComponent!CDepth().depth = -1; + boss_tmpl.getComponent!CParts().count = 4; + boss_tmpl.getComponent!CVelocity().value = vec2(0.05,0); + } + + { + tower_tmpl = launcher.manager.allocateTemplate( + [CHitMark.component_id, CHitPoints.component_id, CLocation.component_id, + CTexture.component_id, CScale.component_id, CEnemy.component_id, + CShootGrid.component_id, CGuild.component_id, CInit.component_id, + CChildren.component_id].staticArray + ); + + CTexture* tex_comp = tower_tmpl.getComponent!CTexture; + //tex_comp.tex = space_invaders.texture;//ship_tex; + tex_comp.coords = vec4(96*px,96*px,16*px,16*px); + CLocation* loc_comp = tower_tmpl.getComponent!CLocation; + loc_comp.value = vec2(64,space_invaders.map_size.y - 16); + tower_tmpl.getComponent!CGuild().guild = 1; + tower_tmpl.getComponent!CInit().type = CInit.Type.tower; + tower_tmpl.getComponent!CHitPoints().value = 10; + } + + { + space_invaders.enemy_tmpl = launcher.manager.allocateTemplate( + [CWeaponLocation.component_id, CHitMark.component_id, CHitPoints.component_id, + CVelocity.component_id, CAutoShoot.component_id, CLocation.component_id, + CTexture.component_id, CScale.component_id, CLaserWeapon.component_id, + CEnemy.component_id, CShootDirection.component_id, CShootGrid.component_id, + CGuild.component_id].staticArray + ); CTexture* tex_comp = space_invaders.enemy_tmpl.getComponent!CTexture; - tex_comp.tex = space_invaders.texture;//ship_tex; + //tex_comp.tex = space_invaders.texture;//ship_tex; tex_comp.coords = vec4(32*px,32*px,16*px,16*px); CLocation* loc_comp = space_invaders.enemy_tmpl.getComponent!CLocation; loc_comp.value = vec2(64,space_invaders.map_size.y - 16); @@ -1545,6 +2218,7 @@ void spaceInvadersStart() CVelocity* vel_comp = space_invaders.enemy_tmpl.getComponent!CVelocity; vel_comp.value = vec2(0.1,0); space_invaders.enemy_tmpl.getComponent!CGuild().guild = 1; + space_invaders.enemy_tmpl.getComponent!CWeaponLocation().rel_pos = vec2(0,-15); Entity* current_entity; @@ -1568,13 +2242,13 @@ void spaceInvadersStart() grouped_id = current_entity.id; //grouped_tmpl = launcher.manager.allocateTemplate(current_entity.id); } - + EntityTemplate* upgrade_tmpl; { upgrade_tmpl = launcher.manager.allocateTemplate([CVelocity.component_id, CLocation.component_id, CTexture.component_id, CScale.component_id, CUpgrade.component_id, CAnimationLooped.component_id, CAnimation.component_id].staticArray); CTexture* tex_comp = upgrade_tmpl.getComponent!CTexture; - tex_comp.tex = space_invaders.texture;//ship_tex; + //tex_comp.tex = space_invaders.texture;//ship_tex; tex_comp.coords = vec4(0*px,32*px,16*px,16*px); CVelocity* vel_comp = upgrade_tmpl.getComponent!CVelocity; vel_comp.value = vec2(0,-0.1); @@ -1586,22 +2260,23 @@ void spaceInvadersStart() enemy_tmpl = launcher.manager.allocateTemplate(enemy_id); grouped_tmpl = launcher.manager.allocateTemplate(grouped_id); - launcher.gui_manager.addTemplate(launcher.manager.allocateTemplate(space_invaders.ship_tmpl),"Ship"); launcher.gui_manager.addTemplate(enemy_tmpl,"Enemy"); launcher.gui_manager.addTemplate(grouped_tmpl,"Grouped enemy"); + launcher.gui_manager.addTemplate(launcher.manager.allocateTemplate(space_invaders.ship_tmpl),"Ship"); launcher.gui_manager.addTemplate(launcher.manager.allocateTemplate(space_invaders.laser_tmpl),"Laser"); launcher.gui_manager.addTemplate(upgrade_tmpl,"Upgrade"); - + launcher.gui_manager.addTemplate(tower_tmpl,"Tower"); + launcher.gui_manager.addTemplate(boss_tmpl,"Boss"); } void spaceInvadersEnd() { - launcher.manager.getSystem(DrawSystem.system_id).disable(); + /*launcher.manager.getSystem(DrawSystem.system_id).disable(); launcher.manager.getSystem(InputMovementSystem.system_id).disable(); launcher.manager.getSystem(LaserShootingSystem.system_id).disable(); launcher.manager.getSystem(MovementSystem.system_id).disable(); launcher.manager.getSystem(ClampPositionSystem.system_id).disable(); - launcher.manager.getSystem(ShootGridCleaner.system_id).disable(); + launcher.manager.getSystem(ShootGridCleaner.system_id).disable();*/ //launcher.manager.freeTemplate(space_invaders.enemy_tmpl); Mallocator.dispose(space_invaders); From 233f4abd47a89dccc4f86289dfedebf117f045aa Mon Sep 17 00:00:00 2001 From: Mergul Date: Sat, 23 May 2020 10:53:36 +0200 Subject: [PATCH 141/217] Added job_id parameter to EntitiesData (index of currently executing job) --- source/bubel/ecs/manager.d | 28 ++++++++++++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/source/bubel/ecs/manager.d b/source/bubel/ecs/manager.d index dc3b9f5..d5892bb 100644 --- a/source/bubel/ecs/manager.d +++ b/source/bubel/ecs/manager.d @@ -469,7 +469,7 @@ export struct EntityManager foreach (member; __traits(allMembers, Sys.EntitiesData)) { alias MemberType = typeof(__traits(getMember, Sys.EntitiesData, member)); - if (member == "length" || member == "thread_id" + if (member == "length" || member == "thread_id" || member == "job_id" || is(MemberType == Entity[]) || is(MemberType == const(Entity)[])) { //continue; @@ -692,7 +692,7 @@ export struct EntityManager foreach (member; __traits(allMembers, Sys.EntitiesData)) { alias MemberType = typeof(__traits(getMember, Sys.EntitiesData, member)); - if (member == "length" || member == "thread_id" + if (member == "length" || member == "thread_id" || member == "job_id" || is(MemberType == Entity[]) || is(MemberType == const(Entity)[])) { if (is(MemberType == Entity[]) || is(MemberType == const(Entity)[])) @@ -809,6 +809,13 @@ export struct EntityManager static assert(MemberType.sizeof > 1, "EntitiesData 'thread_id' member can't be byte or ubyte."); } + else static if (member == "job_id") + { + static assert(isIntegral!(MemberType), + "EntitiesData 'job_id' member must be integral type."); + static assert(MemberType.sizeof > 1, + "EntitiesData 'job_id' member can't be byte or ubyte."); + } else static if (!(isArray!(MemberType))) static assert(0, "EntitiesData members should be arrays of elements!"); } @@ -1009,6 +1016,12 @@ export struct EntityManager .thread_id; } + static if (hasMember!(Sys.EntitiesData, "job_id")) + { + input_data.job_id = cast(typeof(input_data.job_id)) data + .job_id; + } + //s.onUpdate(input_data); (cast(typeof(&__traits(getOverloads, s, "onUpdate")[OnUpdateOverloadNum])) data.update_delegate)(input_data); @@ -1037,6 +1050,12 @@ export struct EntityManager input_data.thread_id = cast(typeof(input_data.thread_id)) data.thread_id; } + static if (hasMember!(Sys.EntitiesData, "job_id")) + { + input_data.job_id = cast(typeof(input_data.job_id)) data + .job_id; + } + (cast(typeof(&__traits(getOverloads, s, "onUpdate")[OnUpdateOverloadNum])) data.update_delegate)(input_data); } @@ -1406,6 +1425,7 @@ export struct EntityManager memcpy(callers.ptr, &tmp_datas[0], CallData.sizeof * tmp_datas.length); tmp_datas.clear(); sys.jobs[job_id].callers = callers; + sys.jobs[job_id].id = job_id; job_id++; } @@ -3415,6 +3435,8 @@ export struct EntityManager ushort end; ///current thread index uint thread_id; + //current job index + uint job_id; } struct ListenerCallData @@ -3428,6 +3450,7 @@ export struct EntityManager struct Job { CallData[] callers; + uint id; export void execute() nothrow @nogc { @@ -3435,6 +3458,7 @@ export struct EntityManager foreach (ref caller; callers) { caller.thread_id = EntityManager.instance.threadID(); + caller.job_id = id; caller.update(); } } From 3d98b0ee5eeac61a71cff1015e4d8cc59a652761 Mon Sep 17 00:00:00 2001 From: Mergul Date: Sat, 23 May 2020 10:55:31 +0200 Subject: [PATCH 142/217] Demos update -fixed critical bug with demos switching -change multithreaded rendering method (now draw order is keeped even witch multithreading there is no popping) -added particle emitter components and systems (WIP) -bullets (laser) now sending EBullet event insead of EDamage which gives possibility to not destroy bullet if shooted entity is already killed --- demos/source/app.d | 6 +- demos/source/demos/simple.d | 6 +- demos/source/demos/space_invaders.d | 319 +++++++++++++++----- demos/utils/source/ecs_utils/gfx/renderer.d | 40 ++- 4 files changed, 284 insertions(+), 87 deletions(-) diff --git a/demos/source/app.d b/demos/source/app.d index 3af24b5..9017f8d 100644 --- a/demos/source/app.d +++ b/demos/source/app.d @@ -103,7 +103,7 @@ struct Launcher manager.update("clean"); manager.end(); - foreach(system; manager.systems) + foreach(ref system; manager.systems) { if(system.id != CountSystem.system_id && system.id != CleanSystem.system_id)system.disable(); } @@ -744,7 +744,9 @@ int main(int argc, char** argv) { import demos.simple; - launcher.switchDemo(&simpleStart,&simpleLoop,&simpleEnd,&simpleEvent,&simpleTool,Simple.tips); + import demos.space_invaders; + launcher.switchDemo(&spaceInvadersStart,&spaceInvadersLoop,&spaceInvadersEnd,&spaceInvadersEvent,&spaceInvadersTool,SpaceInvaders.tips); + // launcher.switchDemo(&simpleStart,&simpleLoop,&simpleEnd,&simpleEvent,&simpleTool,Simple.tips); } int key_num; diff --git a/demos/source/demos/simple.d b/demos/source/demos/simple.d index 1668323..5e82d27 100644 --- a/demos/source/demos/simple.d +++ b/demos/source/demos/simple.d @@ -53,6 +53,7 @@ struct DrawSystem { uint length; uint thread_id; + uint job_id; @readonly CTexture[] textures; @readonly CLocation[] locations; } @@ -62,10 +63,11 @@ struct DrawSystem if(launcher.renderer.prepared_items >= launcher.renderer.MaxObjects)return;//simple leave loop if max visible objects count was reached foreach(i; 0..data.length) { - launcher.renderer.draw(data.textures[i].tex, data.locations[i].location, vec2(16,16), vec4(0,0,1,1), cast(ushort)(data.locations[i].y*64+data.locations[i].x), 0x80808080, 0, 0, 0, data.thread_id); + launcher.renderer.draw(data.textures[i].tex, data.locations[i].location, vec2(16,16), vec4(0,0,1,1), cast(ushort)(data.locations[i].y), 0x80808080, 0, 0, 0, data.job_id); + // launcher.renderer.draw(data.textures[i].tex, data.locations[i].location, vec2(16,16), vec4(0,0,1,1), 0, 0x80808080, 0, 0, 0, data.job_id); //draw(renderer, data.textures[i].tex, data.locations[i], vec2(32,32), vec4(0,0,1,1)); } - if(data.thread_id == 0)launcher.renderer.pushData(); + //if(data.thread_id == 0)launcher.renderer.pushData(); } } diff --git a/demos/source/demos/space_invaders.d b/demos/source/demos/space_invaders.d index f61df5c..c047d25 100644 --- a/demos/source/demos/space_invaders.d +++ b/demos/source/demos/space_invaders.d @@ -196,10 +196,10 @@ struct CLaser { mixin ECS.Component; - float damage = 1.0f; + int damage = 1; } -struct CLaserWeapon +struct CWeapon { mixin ECS.Component; @@ -207,15 +207,25 @@ struct CLaserWeapon { float reload_time; float dispersion; + int damage; } __gshared Level[12] levels = [Level(4000,0),Level(4000,0.1), Level(500,0),Level(350,0),Level(250,0.02),Level(175,0.03),Level(110,0.04), Level(80,0.05),Level(50,0.08),Level(20,0.1),Level(10,0.12),Level(2,0.14)]; + enum Type : ubyte + { + laser, + enemy_laser, + blaster, + canon, + plasma + } - ubyte level = 1; float shoot_time = 0; + Type type; + ubyte level = 1; } struct CWeaponLocation @@ -253,7 +263,7 @@ struct CShootGrid mixin ECS.Component; } -struct CTargetPartent +struct CTargetParent { mixin ECS.Component; @@ -386,6 +396,10 @@ struct CParticleEmitter vec2 range; vec2 time_range; + ///due to multithreading there should be separate template for every thread. + ///It can be array of tempaltes or (like in this demo) simply index of template; + uint tmpl_id; + //EntityTemplate* tmpl; } ///Due to perfarmance reason emitter time and attributes are divided into seprate components. @@ -397,6 +411,11 @@ struct CParticleEmitterTime float time; } +struct CShootWaveUponDeath +{ + mixin ECS.Component; +} + /*####################################################################################################################### ------------------------------------------------ Events ------------------------------------------------------------------ #######################################################################################################################*/ @@ -435,6 +454,20 @@ struct EDamage uint damage = 0; } +struct EBulletHit +{ + mixin ECS.Event; + + this(EntityID id, uint damage) + { + this.id = id; + this.damage = damage; + } + + EntityID id; + uint damage; +} + struct EDestroyedChild { mixin ECS.Event; @@ -652,9 +685,9 @@ struct ShipWeaponSystem CChildren* children = entity.getComponent!CChildren; if(children is null || children.childern.length != 0)return; EntityID[3] weapons; - laser1_tmpl.getComponent!CTargetPartent().parent = entity.id; - laser2_tmpl.getComponent!CTargetPartent().parent = entity.id; - main_weapon_tmpl.getComponent!CTargetPartent().parent = entity.id; + laser1_tmpl.getComponent!CTargetParent().parent = entity.id; + laser2_tmpl.getComponent!CTargetParent().parent = entity.id; + main_weapon_tmpl.getComponent!CTargetParent().parent = entity.id; weapons[0] = launcher.manager.addEntity(laser1_tmpl).id; weapons[1] = launcher.manager.addEntity(laser2_tmpl).id; weapons[2] = launcher.manager.addEntity(main_weapon_tmpl).id; @@ -663,13 +696,13 @@ struct ShipWeaponSystem void create() { - laser1_tmpl = launcher.manager.allocateTemplate([CLaserWeapon.component_id, CLocation.component_id, CShootDirection.component_id, CTargetPartent.component_id, CGuild.component_id, CVelocity.component_id].staticArray); - main_weapon_tmpl = launcher.manager.allocateTemplate([CLocation.component_id, CShootDirection.component_id, CTargetPartent.component_id, CGuild.component_id, CVelocity.component_id].staticArray); - *laser1_tmpl.getComponent!CLaserWeapon = CLaserWeapon(3,0.0); - laser1_tmpl.getComponent!CTargetPartent().rel_pos = vec2(10,13); - main_weapon_tmpl.getComponent!CTargetPartent().rel_pos = vec2(0,4); + laser1_tmpl = launcher.manager.allocateTemplate([CWeapon.component_id, CLocation.component_id, CShootDirection.component_id, CTargetParent.component_id, CGuild.component_id, CVelocity.component_id].staticArray); + main_weapon_tmpl = launcher.manager.allocateTemplate([CLocation.component_id, CShootDirection.component_id, CTargetParent.component_id, CGuild.component_id, CVelocity.component_id].staticArray); + *laser1_tmpl.getComponent!CWeapon = CWeapon(0,CWeapon.Type.laser,3); + laser1_tmpl.getComponent!CTargetParent().rel_pos = vec2(10,13); + main_weapon_tmpl.getComponent!CTargetParent().rel_pos = vec2(0,4); laser2_tmpl = launcher.manager.allocateTemplate(laser1_tmpl); - laser2_tmpl.getComponent!CTargetPartent().rel_pos = vec2(-10,13); + laser2_tmpl.getComponent!CTargetParent().rel_pos = vec2(-10,13); } ~this() @@ -691,10 +724,10 @@ struct ShipWeaponSystem if(children is null || children.childern.length != 0)return; CDepth* depth = entity.getComponent!CDepth; EntityID[2] weapons; - weapon_tmpl.getComponent!CTargetPartent().parent = entity.id; + weapon_tmpl.getComponent!CTargetParent().parent = entity.id; if(depth)weapon_tmpl.getComponent!CDepth().depth = cast(short)(depth.depth - 1); else weapon_tmpl.getComponent!CDepth().depth = -1; - top_tmpl.getComponent!CTargetPartent().parent = entity.id; + top_tmpl.getComponent!CTargetParent().parent = entity.id; if(depth)top_tmpl.getComponent!CDepth().depth = cast(short)(depth.depth - 2); else top_tmpl.getComponent!CDepth().depth = -2; @@ -706,24 +739,24 @@ struct ShipWeaponSystem void create() { weapon_tmpl = launcher.manager.allocateTemplate( - [CLaserWeapon.component_id, CLocation.component_id, CShootDirection.component_id, - CTargetPartent.component_id, CGuild.component_id, CVelocity.component_id, + [CWeapon.component_id, CLocation.component_id, CShootDirection.component_id, + CTargetParent.component_id, CGuild.component_id, CVelocity.component_id, CAutoShoot.component_id, CTarget.component_id, CTargetPlayerShip.component_id, CRotation.component_id, CScale.component_id, CTexture.component_id, CDepth.component_id, CWeaponLocation.component_id].staticArray); - *weapon_tmpl.getComponent!CLaserWeapon = CLaserWeapon(3,0.0); - weapon_tmpl.getComponent!CTargetPartent().rel_pos = vec2(0,0); + *weapon_tmpl.getComponent!CWeapon = CWeapon(0,CWeapon.Type.laser,3); + weapon_tmpl.getComponent!CTargetParent().rel_pos = vec2(0,0); weapon_tmpl.getComponent!CGuild().guild = 1; weapon_tmpl.getComponent!CScale().value = vec2(4,16); - weapon_tmpl.getComponent!CLaserWeapon().level = 1; + weapon_tmpl.getComponent!CWeapon().level = 1; weapon_tmpl.getComponent!CDepth().depth = -1; weapon_tmpl.getComponent!CTexture().coords = vec4(136,96,4,16)*px; weapon_tmpl.getComponent!CWeaponLocation().rel_pos = vec2(0,12); top_tmpl = launcher.manager.allocateTemplate( - [CLocation.component_id, CTargetPartent.component_id, CScale.component_id, + [CLocation.component_id, CTargetParent.component_id, CScale.component_id, CTexture.component_id, CDepth.component_id].staticArray); - top_tmpl.getComponent!CTargetPartent().rel_pos = vec2(0,1); + top_tmpl.getComponent!CTargetParent().rel_pos = vec2(0,1); top_tmpl.getComponent!CScale().value = vec2(10,11); top_tmpl.getComponent!CDepth().depth = -2; top_tmpl.getComponent!CTexture().coords = vec4(112,96,10,11)*px; @@ -751,10 +784,10 @@ struct ShipWeaponSystem CParts* parts = entity.getComponent!CParts; if(parts)parts.count = 4; EntityID[4] towers; - tower1_tmpl.getComponent!CTargetPartent().parent = entity.id; - tower2_tmpl.getComponent!CTargetPartent().parent = entity.id; - tower3_tmpl.getComponent!CTargetPartent().parent = entity.id; - tower4_tmpl.getComponent!CTargetPartent().parent = entity.id; + tower1_tmpl.getComponent!CTargetParent().parent = entity.id; + tower2_tmpl.getComponent!CTargetParent().parent = entity.id; + tower3_tmpl.getComponent!CTargetParent().parent = entity.id; + tower4_tmpl.getComponent!CTargetParent().parent = entity.id; towers[0] = launcher.manager.addEntity(tower1_tmpl).id; towers[1] = launcher.manager.addEntity(tower2_tmpl).id; towers[2] = launcher.manager.addEntity(tower3_tmpl).id; @@ -768,7 +801,7 @@ struct ShipWeaponSystem [CHitMark.component_id, CHitPoints.component_id, CLocation.component_id, CTexture.component_id, CScale.component_id, CEnemy.component_id, CShootGrid.component_id, CGuild.component_id, CInit.component_id, - CChildren.component_id, CDepth.component_id, CTargetPartent.component_id].staticArray + CChildren.component_id, CDepth.component_id, CTargetParent.component_id].staticArray ); CTexture* tex_comp = tower1_tmpl.getComponent!CTexture; @@ -779,17 +812,19 @@ struct ShipWeaponSystem tower1_tmpl.getComponent!CGuild().guild = 1; tower1_tmpl.getComponent!CInit().type = CInit.Type.tower; tower1_tmpl.getComponent!CHitPoints().value = 10; - tower1_tmpl.getComponent!CDepth().depth = -5; - tower1_tmpl.getComponent!CTargetPartent().rel_pos = vec2(-33,2); + tower1_tmpl.getComponent!CDepth().depth = -2; + tower1_tmpl.getComponent!CTargetParent().rel_pos = vec2(-33,2); tower2_tmpl = launcher.manager.allocateTemplate(tower1_tmpl); - tower2_tmpl.getComponent!CTargetPartent().rel_pos = vec2(33,2); + tower2_tmpl.getComponent!CTargetParent().rel_pos = vec2(33,2); tower3_tmpl = launcher.manager.allocateTemplate(tower1_tmpl); - tower3_tmpl.getComponent!CTargetPartent().rel_pos = vec2(-39,-15); + tower3_tmpl.getComponent!CDepth().depth = 0; + tower3_tmpl.getComponent!CTargetParent().rel_pos = vec2(-40,-15); tower4_tmpl = launcher.manager.allocateTemplate(tower1_tmpl); - tower4_tmpl.getComponent!CTargetPartent().rel_pos = vec2(39,-15); + tower4_tmpl.getComponent!CDepth().depth = 0; + tower4_tmpl.getComponent!CTargetParent().rel_pos = vec2(40,-15); } ~this() @@ -810,13 +845,13 @@ struct ShipWeaponSystem ship.create(); tower.create(); boss.create(); - /*ship.laser1_tmpl = launcher.manager.allocateTemplate([CLaserWeapon.component_id, CLocation.component_id, CShootDirection.component_id, CTargetPartent.component_id, CGuild.component_id, CVelocity.component_id].staticArray); - ship.main_weapon_tmpl = launcher.manager.allocateTemplate([CLocation.component_id, CShootDirection.component_id, CTargetPartent.component_id, CGuild.component_id, CVelocity.component_id].staticArray); - *ship.laser1_tmpl.getComponent!CLaserWeapon = CLaserWeapon(3,0.0); - ship.laser1_tmpl.getComponent!CTargetPartent().rel_pos = vec2(10,13); - ship.main_weapon_tmpl.getComponent!CTargetPartent().rel_pos = vec2(0,4); + /*ship.laser1_tmpl = launcher.manager.allocateTemplate([CWeapon.component_id, CLocation.component_id, CShootDirection.component_id, CTargetParent.component_id, CGuild.component_id, CVelocity.component_id].staticArray); + ship.main_weapon_tmpl = launcher.manager.allocateTemplate([CLocation.component_id, CShootDirection.component_id, CTargetParent.component_id, CGuild.component_id, CVelocity.component_id].staticArray); + *ship.laser1_tmpl.getComponent!CWeapon = CWeapon(3,0.0); + ship.laser1_tmpl.getComponent!CTargetParent().rel_pos = vec2(10,13); + ship.main_weapon_tmpl.getComponent!CTargetParent().rel_pos = vec2(0,4); ship.laser2_tmpl = launcher.manager.allocateTemplate(ship.laser1_tmpl); - ship.laser2_tmpl.getComponent!CTargetPartent().rel_pos = vec2(-10,13);*/ + ship.laser2_tmpl.getComponent!CTargetParent().rel_pos = vec2(-10,13);*/ } void onDestroy() @@ -832,9 +867,9 @@ struct ShipWeaponSystem { /*if(data.children[i].childern.length != 0)continue; EntityID[3] weapons; - laser1_tmpl.getComponent!CTargetPartent().parent = data.entity[i].id; - laser2_tmpl.getComponent!CTargetPartent().parent = data.entity[i].id; - main_weapon_tmpl.getComponent!CTargetPartent().parent = data.entity[i].id; + laser1_tmpl.getComponent!CTargetParent().parent = data.entity[i].id; + laser2_tmpl.getComponent!CTargetParent().parent = data.entity[i].id; + main_weapon_tmpl.getComponent!CTargetParent().parent = data.entity[i].id; weapons[0] = launcher.manager.addEntity(laser1_tmpl).id; weapons[1] = launcher.manager.addEntity(laser2_tmpl).id; weapons[2] = launcher.manager.addEntity(main_weapon_tmpl).id; @@ -859,7 +894,7 @@ struct MoveToParentTargetSystem int length; CLocation[] location; @optional CVelocity[] velocity; - @readonly CTargetPartent[] target; + @readonly CTargetParent[] target; } void onUpdate(EntitiesData data) @@ -908,6 +943,7 @@ struct DrawSystem { uint length; uint thread_id; + uint job_id; @readonly CTexture[] textures; @readonly CLocation[] locations; @readonly CScale[] scale; @@ -925,24 +961,24 @@ struct DrawSystem foreach(i; 0..data.length) { uint color = 0x80808080 + 0x01010101 * data.hit_mark[i]; - short depth = cast(short)(data.locations[i].y*8 + data.locations[i].x); - launcher.renderer.draw(space_invaders.texture, data.locations[i].value, data.scale[i], data.textures[i].coords, depth, color, 0, 0, 0, data.thread_id); + short depth = cast(short)(data.locations[i].y); + launcher.renderer.draw(space_invaders.texture, data.locations[i].value, data.scale[i], data.textures[i].coords, depth, color, 0, 0, 0, data.job_id); } } else if(data.rotation) { foreach(i; 0..data.length) { - short depth = cast(short)(data.locations[i].y*8 + data.locations[i].x); - launcher.renderer.draw(space_invaders.texture, data.locations[i].value, data.scale[i], data.textures[i].coords, depth, 0x80808080, data.rotation[i], 0, 0, data.thread_id); + short depth = cast(short)(data.locations[i].y); + launcher.renderer.draw(space_invaders.texture, data.locations[i].value, data.scale[i], data.textures[i].coords, depth, 0x80808080, data.rotation[i], 0, 0, data.job_id); } } else { foreach(i; 0..data.length) { - short depth = cast(short)(data.locations[i].y*8 + data.locations[i].x); - launcher.renderer.draw(space_invaders.texture, data.locations[i].value, data.scale[i], data.textures[i].coords, depth, 0x80808080, 0, 0, 0, data.thread_id); + short depth = cast(short)(data.locations[i].y); + launcher.renderer.draw(space_invaders.texture, data.locations[i].value, data.scale[i], data.textures[i].coords, depth, 0x80808080, 0, 0, 0, data.job_id); } } } @@ -955,8 +991,8 @@ struct DrawSystem foreach(i; 0..data.length) { uint color = 0x80808080 + 0x01010101 * data.hit_mark[i]; - short depth = cast(short)(data.depth[i] * 16 + data.locations[i].y*8 + data.locations[i].x); - launcher.renderer.draw(space_invaders.texture, data.locations[i].value, data.scale[i], data.textures[i].coords, depth, color, data.rotation[i], 0, 0, data.thread_id); + short depth = cast(short)(data.depth[i] * 8 + data.locations[i].y); + launcher.renderer.draw(space_invaders.texture, data.locations[i].value, data.scale[i], data.textures[i].coords, depth, color, data.rotation[i], 0, 0, data.job_id); } } else @@ -964,8 +1000,8 @@ struct DrawSystem foreach(i; 0..data.length) { uint color = 0x80808080 + 0x01010101 * data.hit_mark[i]; - short depth = cast(short)(data.depth[i] * 16 + data.locations[i].y*8 + data.locations[i].x); - launcher.renderer.draw(space_invaders.texture, data.locations[i].value, data.scale[i], data.textures[i].coords, depth, color, 0, 0, 0, data.thread_id); + short depth = cast(short)(data.depth[i] * 8 + data.locations[i].y); + launcher.renderer.draw(space_invaders.texture, data.locations[i].value, data.scale[i], data.textures[i].coords, depth, color, 0, 0, 0, data.job_id); } } } @@ -973,20 +1009,20 @@ struct DrawSystem { foreach(i; 0..data.length) { - short depth = cast(short)(data.depth[i] * 16 + data.locations[i].y*8 + data.locations[i].x); - launcher.renderer.draw(space_invaders.texture, data.locations[i].value, data.scale[i], data.textures[i].coords, depth, 0x80808080, data.rotation[i], 0, 0, data.thread_id); + short depth = cast(short)(data.depth[i] * 8 + data.locations[i].y); + launcher.renderer.draw(space_invaders.texture, data.locations[i].value, data.scale[i], data.textures[i].coords, depth, 0x80808080, data.rotation[i], 0, 0, data.job_id); } } else { foreach(i; 0..data.length) { - short depth = cast(short)(data.depth[i] * 16 + data.locations[i].y*8 + data.locations[i].x); - launcher.renderer.draw(space_invaders.texture, data.locations[i].value, data.scale[i], data.textures[i].coords, depth, 0x80808080, 0, 0, 0, data.thread_id); + short depth = cast(short)(data.depth[i] * 8 + data.locations[i].y); + launcher.renderer.draw(space_invaders.texture, data.locations[i].value, data.scale[i], data.textures[i].coords, depth, 0x80808080, 0, 0, 0, data.job_id); } } } - if(data.thread_id == 0)launcher.renderer.pushData(); + //if(data.thread_id == 0)launcher.renderer.pushData(); } } @@ -1029,7 +1065,7 @@ struct LaserShootingSystem uint length; ///variable named "length" contain thread identifier uint thread_id; - CLaserWeapon[] laser; + CWeapon[] laser; @readonly CLocation[] location; @readonly CGuild[] guild; @@ -1134,14 +1170,14 @@ struct LaserShootingSystem { foreach(i;0..data.length) { - CLaserWeapon* laser = &data.laser[i]; + CWeapon* laser = &data.laser[i]; laser.shoot_time += launcher.delta_time; - while(laser.shoot_time > CLaserWeapon.levels[laser.level - 1].reload_time) + while(laser.shoot_time > CWeapon.levels[laser.level - 1].reload_time) { - laser.shoot_time -= CLaserWeapon.levels[laser.level - 1].reload_time; + laser.shoot_time -= CWeapon.levels[laser.level - 1].reload_time; thread.laser_location.value = data.location[i]; - thread.laser_velocity.value = vec2((randomf()*2-1) * CLaserWeapon.levels[laser.level - 1].dispersion,1);//data.shoot_direction[i].direction == Direction.up ? 1.0 : -1.0); + thread.laser_velocity.value = vec2((randomf()*2-1) * CWeapon.levels[laser.level - 1].dispersion,1);//data.shoot_direction[i].direction == Direction.up ? 1.0 : -1.0); if(data.shoot_direction && data.shoot_direction[i].direction == Direction.down)thread.laser_velocity.y = -1; thread.laser_guild.guild = data.guild[i].guild; @@ -1197,9 +1233,9 @@ struct LaserShootingSystem { foreach(i;0..data.length) { - CLaserWeapon* laser = &data.laser[i]; + CWeapon* laser = &data.laser[i]; laser.shoot_time += launcher.delta_time; - if(laser.shoot_time > CLaserWeapon.levels[laser.level - 1].reload_time)laser.shoot_time = CLaserWeapon.levels[laser.level - 1].reload_time; + if(laser.shoot_time > CWeapon.levels[laser.level - 1].reload_time)laser.shoot_time = CWeapon.levels[laser.level - 1].reload_time; } } @@ -1262,8 +1298,83 @@ struct LaserCollisionSystem { if(space_invaders.shoot_grid.test(id, data.location[i], cast(ubyte)(~(1 << data.guild[i].guild)))) { - launcher.manager.sendEvent(id, EDamage(1)); - launcher.manager.removeEntity(data.entity[i].id); + launcher.manager.sendEvent(id, EBulletHit(data.entity[i].id,1)); + //launcher.manager.removeEntity(data.entity[i].id); + } + } + } +} + +struct ParticleEmittingSystem +{ + mixin ECS.System!32; + + struct EntitiesData + { + uint length; + uint thread_id; + CParticleEmitterTime[] emit_time; + @readonly CLocation[] location; + @readonly CParticleEmitter[] emitter; + + @optional @readonly CVelocity[] velocity; + } + + struct Thread + { + EntityTemplate*[1] templates; + } + + Thread[] threads; + + void onCreate() + { + threads = Mallocator.makeArray!Thread(32); + + threads[0].templates[0] = launcher.manager.allocateTemplate( + [CLocation.component_id, CTexture.component_id, CScale.component_id, + CAnimation.component_id, CParticle.component_id, CRotation.component_id, + CVelocity.component_id, CDamping.component_id].staticArray); + + foreach(ref thread;threads[1 .. $]) + { + thread.templates[0] = launcher.manager.allocateTemplate(threads[0].templates[0]); + } + } + + void onDestroy() + { + foreach(ref thread;threads[1 .. $]) + { + foreach(tmpl; thread.templates) + { + launcher.manager.freeTemplate(tmpl); + } + } + Mallocator.dispose(threads); + } + + void onUpdate(EntitiesData data) + { + Thread* thread = &threads[data.thread_id]; + foreach(i;0..data.length) + { + data.emit_time[i].time -= launcher.delta_time; + while(data.emit_time[i].time < 0) + { + CParticleEmitter* emitter = &data.emitter[i]; + data.emit_time[i].time += emitter.time_range.x + randomf() * emitter.time_range.y; + + EntityTemplate* tmpl = thread.templates[emitter.tmpl_id]; + CLocation* location = tmpl.getComponent!CLocation; + if(location)location.value = data.location[i]; + + if(data.velocity) + { + CVelocity* velocity = tmpl.getComponent!CVelocity; + if(velocity)velocity.value = data.velocity[i]; + } + launcher.manager.addEntity(tmpl); } } } @@ -1314,10 +1425,10 @@ struct UpgradeSystem void handleEvent(Entity* entity, EUpgrade event) { - CLaserWeapon* laser = entity.getComponent!CLaserWeapon; + CWeapon* laser = entity.getComponent!CWeapon; if(laser) { - if(laser.level < CLaserWeapon.levels.length)laser.level++; + if(laser.level < CWeapon.levels.length)laser.level++; } CShip* ship = entity.getComponent!CShip; if(ship) @@ -1553,6 +1664,21 @@ struct HitPointsSystem CHitMark* hit_mark = entity.getComponent!CHitMark; if(hit_mark)hit_mark.value = 127; } + + void handleEvent(Entity* entity, EBulletHit event) + { + CHitPoints* hp = entity.getComponent!CHitPoints; + if(*hp <= 0)return; + launcher.manager.removeEntity(event.id); + *hp -= event.damage; + if(*hp <= 0) + { + launcher.manager.sendEvent(entity.id, EDeath()); + //launcher.manager.removeEntity(entity.id); + } + CHitMark* hit_mark = entity.getComponent!CHitMark; + if(hit_mark)hit_mark.value = 127; + } void handleEvent(Entity* entity, EDeath event) { @@ -1581,12 +1707,12 @@ struct ChildDestroySystem struct EntitiesData { - CTargetPartent[] parent; + CTargetParent[] parent; } void handleEvent(Entity* entity, EDeath event) { - CTargetPartent* parent = entity.getComponent!CTargetPartent; + CTargetParent* parent = entity.getComponent!CTargetParent; if(parent) { launcher.manager.sendEvent(parent.parent, EDestroyedChild(entity.id)); @@ -1605,13 +1731,50 @@ struct PartsDestroySystem CParts[] parts; } + EntityTemplate* flashes_emitter; + + void onCreate() + { + flashes_emitter = launcher.manager.allocateTemplate( + [ + CVelocity.component_id, CLocation.component_id, CParticleEmitter.component_id, + CParticleEmitterTime.component_id, CTargetParent.component_id + ].staticArray); + *flashes_emitter.getComponent!CParticleEmitter() = CParticleEmitter(vec2(0,0), vec2(400,400), 0); + } + void handleEvent(Entity* entity, EDestroyedChild event) { CParts* parts = entity.getComponent!CParts; parts.count--; + + CInit* init = entity.getComponent!CInit; + if(init.type == CInit.Type.boss) + { + CChildren* children = entity.getComponent!CChildren; + foreach(EntityID child; children.childern) + { + if(child == event.id) + { + Entity* child_entity = launcher.manager.getEntity(child); + if(child_entity) + { + CTargetParent* target_parent = child_entity.getComponent!CTargetParent; + + *flashes_emitter.getComponent!CTargetParent() = *target_parent; + launcher.manager.addEntity(flashes_emitter); + } + break; + } + } + } + if(parts.count == 0) { - launcher.manager.addComponents(entity.id, CHitPoints(100), CShootGrid()); + if(init.type == CInit.Type.boss) + { + launcher.manager.addComponents(entity.id, CHitPoints(100), CShootGrid()); + } } } } @@ -2033,7 +2196,7 @@ void spaceInvadersStart() launcher.manager.registerComponent!CScale; launcher.manager.registerComponent!CShootDirection; launcher.manager.registerComponent!CAutoShoot; - launcher.manager.registerComponent!CLaserWeapon; + launcher.manager.registerComponent!CWeapon; launcher.manager.registerComponent!CVelocity; launcher.manager.registerComponent!CLaser; launcher.manager.registerComponent!CSideMove; @@ -2049,7 +2212,7 @@ void spaceInvadersStart() launcher.manager.registerComponent!CRotation; launcher.manager.registerComponent!CAnimationLooped; launcher.manager.registerComponent!CDamping; - launcher.manager.registerComponent!CTargetPartent; + launcher.manager.registerComponent!CTargetParent; launcher.manager.registerComponent!CTarget; launcher.manager.registerComponent!CTargetPlayerShip; launcher.manager.registerComponent!CChildren; @@ -2066,6 +2229,7 @@ void spaceInvadersStart() launcher.manager.registerEvent!EUpgrade; launcher.manager.registerEvent!EDeath; launcher.manager.registerEvent!EDestroyedChild; + launcher.manager.registerEvent!EBulletHit; //launcher.manager.registerSystem!MoveSystem(0); launcher.manager.registerSystem!DrawSystem(100); @@ -2087,6 +2251,7 @@ void spaceInvadersStart() launcher.manager.registerSystem!MoveToParentTargetSystem(99); launcher.manager.registerSystem!ParentOwnerSystem(-101); launcher.manager.registerSystem!ShipWeaponSystem(-100); + launcher.manager.registerSystem!ParticleEmittingSystem(-100); launcher.manager.registerSystem!RotateToTargetSystem(-100); launcher.manager.registerSystem!ShipTargetSystem(-110); @@ -2125,7 +2290,7 @@ void spaceInvadersStart() CShootDirection.component_id, CShootGrid.component_id, CGuild.component_id, CDamping.component_id, CChildren.component_id, CInit.component_id].staticArray ); - //CLaserWeapon* weapon = space_invaders.ship_tmpl.getComponent!CLaserWeapon; + //CWeapon* weapon = space_invaders.ship_tmpl.getComponent!CWeapon; //weapon.level = 3; space_invaders.ship_tmpl.getComponent!CTexture().coords = vec4(0*px,80*px,48*px,32*px); space_invaders.ship_tmpl.getComponent!CScale().value = vec2(48,32); @@ -2203,7 +2368,7 @@ void spaceInvadersStart() space_invaders.enemy_tmpl = launcher.manager.allocateTemplate( [CWeaponLocation.component_id, CHitMark.component_id, CHitPoints.component_id, CVelocity.component_id, CAutoShoot.component_id, CLocation.component_id, - CTexture.component_id, CScale.component_id, CLaserWeapon.component_id, + CTexture.component_id, CScale.component_id, CWeapon.component_id, CEnemy.component_id, CShootDirection.component_id, CShootGrid.component_id, CGuild.component_id].staticArray ); @@ -2298,10 +2463,10 @@ void spaceInvadersTool(vec2 position, Tool tool, int size) else if(position.y > 299)position.y = 299; *location = position; } - CLaserWeapon* laser_weapon = tmpl.getComponent!CLaserWeapon; + CWeapon* laser_weapon = tmpl.getComponent!CWeapon; if(laser_weapon) { - laser_weapon.shoot_time = randomf * CLaserWeapon.levels[laser_weapon.level - 1].reload_time; + laser_weapon.shoot_time = randomf * CWeapon.levels[laser_weapon.level - 1].reload_time; } launcher.manager.addEntity(tmpl); } diff --git a/demos/utils/source/ecs_utils/gfx/renderer.d b/demos/utils/source/ecs_utils/gfx/renderer.d index 1b46eaf..fcd6a88 100644 --- a/demos/utils/source/ecs_utils/gfx/renderer.d +++ b/demos/utils/source/ecs_utils/gfx/renderer.d @@ -114,7 +114,7 @@ struct Renderer void freeBlocks() { - block_stack_mutex.lock(); + /*block_stack_mutex.lock(); render_blocks = 0; current_block = 0; foreach(VertexBlock block; blocks) @@ -124,13 +124,38 @@ struct Renderer blocks.clear; prepared_items=0; draw_list.clear(); - block_stack_mutex.unlock(); + block_stack_mutex.unlock();*/ + foreach(ref Thread thread; threads) + { + foreach(VertexBlock block; thread.blocks) + { + allocator.freeBlock(block.memory); + } + thread.blocks.clear(); + } + render_blocks = 0; + current_block = 0; + prepared_items = 0; + draw_list.clear(); } void pushData() { + foreach(ref Thread thread; threads) + { + foreach(VertexBlock block; thread.blocks) + { + uint items = block.items; + if(items + item_id >= MaxObjects)items = MaxObjects - item_id; + batch_vbo[0].bufferSubData(Buffer.BindTarget.array,items*4*14,item_id*4*14,block.batch_vertices.ptr); + batch_ibo[0].bufferSubData(Buffer.BindTarget.element_array,items*2*6,item_id*2*6,block.batch_indices.ptr); + draw_list.add(DrawCall(item_id,items)); + item_id += items; + } + //thread.blocks.clear(); + } //if(!isRemainingBlocks())return; - while(isRemainingBlocks()) + /* while(isRemainingBlocks()) { VertexBlock block = fetchBlock(); uint items = block.items; @@ -139,14 +164,15 @@ struct Renderer batch_ibo[0].bufferSubData(Buffer.BindTarget.element_array,items*2*6,item_id*2*6,block.batch_indices.ptr); draw_list.add(DrawCall(item_id,items)); item_id += items; - } + }*/ } void pushThreadsBlocks() { foreach(i, ref Thread thread; threads) { - pushBlock(thread.block); + //pushBlock(thread.block); + thread.blocks.add(thread.block); thread.block = getBlock(); } } @@ -156,6 +182,7 @@ struct Renderer //Vector!VertexBlock block; RenderData[] render_list; VertexBlock block; + Vector!VertexBlock blocks; } Thread[] threads; @@ -609,7 +636,8 @@ struct Renderer threads[thread_id].block.items++; if(threads[thread_id].block.items >= VertexBlock.max_items) { - pushBlock(threads[thread_id].block); + //pushBlock(threads[thread_id].block); + threads[thread_id].blocks.add(threads[thread_id].block); threads[thread_id].block = getBlock(); } } From 15cd57dbcb10cf2a5e843ba728c3cfde4bd082ca Mon Sep 17 00:00:00 2001 From: Mergul Date: Sun, 24 May 2020 21:57:48 +0200 Subject: [PATCH 143/217] Basic update, multithreading emplate support, fixed -Added possibility to add entity form template + components to replace template data -basic tests for new functionality -small performance improvement for events -added ComponentRef structure which contain data pointer and component ID -now events are called before entities removing --- source/bubel/ecs/block_allocator.d | 1 + source/bubel/ecs/core.d | 5 ++ source/bubel/ecs/entity.d | 11 +++ source/bubel/ecs/events.d | 10 +-- source/bubel/ecs/manager.d | 120 +++++++++++++++++++++++++---- tests/basic.d | 10 ++- 6 files changed, 137 insertions(+), 20 deletions(-) diff --git a/source/bubel/ecs/block_allocator.d b/source/bubel/ecs/block_allocator.d index 740b762..5a2d02c 100644 --- a/source/bubel/ecs/block_allocator.d +++ b/source/bubel/ecs/block_allocator.d @@ -62,6 +62,7 @@ private: { next_block = cast(void*) Mallocator.alignAlloc( block_size * blocks_in_allocation, block_size); + if(next_block is null)assert(0); if(pointers is null)pointers = Mallocator.make!BlockPointers; if(pointers.numberof >= 32) diff --git a/source/bubel/ecs/core.d b/source/bubel/ecs/core.d index 0487665..4a90928 100644 --- a/source/bubel/ecs/core.d +++ b/source/bubel/ecs/core.d @@ -74,6 +74,11 @@ static struct ECS mixin template Component() { __gshared ushort component_id = ushort.max; + + ComponentRef ref_() @nogc nothrow + { + return ComponentRef(&this,component_id); + } } /************************************************************************************************************************ diff --git a/source/bubel/ecs/entity.d b/source/bubel/ecs/entity.d index 1e98ff2..f24ddf3 100644 --- a/source/bubel/ecs/entity.d +++ b/source/bubel/ecs/entity.d @@ -114,3 +114,14 @@ export struct EntityTemplate return cast(T*)(entity_data.ptr + info.tmpl_deltas[T.component_id]); } } + +/************************************************************************************************************************ +ComponentRef contain component ID and pointer to it. It used to add component data to entity. +*/ +export struct ComponentRef +{ + ///pointer to component + void* ptr; + ///component index + ushort component_id; +} diff --git a/source/bubel/ecs/events.d b/source/bubel/ecs/events.d index 772d5b5..25b864d 100644 --- a/source/bubel/ecs/events.d +++ b/source/bubel/ecs/events.d @@ -40,10 +40,9 @@ package struct EventManager if(block is null) { event_block_alloc_mutex.lock(); - scope (exit) - event_block_alloc_mutex.unlock(); - block = cast(EventBlock*) allocator.getBlock(); + event_block_alloc_mutex.unlock(); + *block = EventBlock(); data.first_blocks[block_id] = block; data.blocks[block_id] = block; @@ -52,10 +51,9 @@ package struct EventManager if(block.count >= data.max_events) { event_block_alloc_mutex.lock(); - scope (exit) - event_block_alloc_mutex.unlock(); - EventBlock* new_block = cast(EventBlock*) allocator.getBlock(); + event_block_alloc_mutex.unlock(); + *new_block = EventBlock(); block.next = new_block; block = new_block; diff --git a/source/bubel/ecs/manager.d b/source/bubel/ecs/manager.d index d5892bb..3ac16e8 100644 --- a/source/bubel/ecs/manager.d +++ b/source/bubel/ecs/manager.d @@ -2356,12 +2356,7 @@ export struct EntityManager void addComponents(Components...)(const EntityID entity_id, Components comps) nothrow @nogc { const uint num = Components.length; - //Entity* entity = id_manager.getEntityPointer(entity_id); - //EntitiesBlock* block = getMetaData(entity); - //EntityInfo* info = block.type_info; - /*ushort[] ids = (cast(ushort*) alloca(ushort.sizeof * (info.components.length + num)))[0 - .. info.components.length + num];*/ - ushort[num] new_ids; + /*ushort[num] new_ids; static foreach (i, comp; Components) { @@ -2376,9 +2371,39 @@ export struct EntityManager static foreach (i, comp; comps) { data.changeEntitiesList.add((cast(ubyte*)&comp)[0 .. comp.sizeof]); - } + }*/ //__addComponents(entity_id, new_ids, pointers); + + ComponentRef[num] _comps; + static foreach(i, comp; comps) + { + _comps[i] = comp.ref_; + } + addComponents(entity_id, _comps); + + } + + export void addComponents(const EntityID entity_id, ComponentRef[] comps) nothrow @nogc + { + uint num = cast(uint)comps.length; + ThreadData* data = &threads[threadID]; + data.changeEntitiesList.add(cast(ubyte) 1u); + data.changeEntitiesList.add((cast(ubyte*)&entity_id)[0 .. EntityID.sizeof]); + data.changeEntitiesList.add((cast(ubyte*)&num)[0 .. uint.sizeof]); + foreach(ref_; comps) + { + data.changeEntitiesList.add((cast(ubyte*)&ref_.component_id)[0 .. ushort.sizeof]); + } + foreach(ref_; comps) + { + data.changeEntitiesList.add((cast(ubyte*)ref_.ptr)[0 .. components[ref_.component_id].size]); + } + /*data.changeEntitiesList.add(cast(ubyte[]) new_ids); + static foreach (i, comp; comps) + { + data.changeEntitiesList.add((cast(ubyte*)&comp)[0 .. comp.sizeof]); + }*/ } /************************************************************************************************************************ @@ -2455,6 +2480,58 @@ export struct EntityManager tmpl = pointer entity template allocated by EntityManager. */ export Entity* addEntity(EntityTemplate* tmpl) + { + /*EntityInfo* info = tmpl.info; + + ushort index = 0; + EntitiesBlock* block; + do + { + block = findBlockWithFreeSpaceMT(info); + index = block.added_count.atomicOp!"+="(1); + } + while (block.entities_count + index > info.max_entities); + + uint id = (block.entities_count + index - 1); //block.added_count); + + void* data_begin = block.dataBegin(); + void* start = data_begin + EntityID.sizeof * id; + + foreach (comp; info.components) + { + memcpy(cast(void*) block + info.deltas[comp] + components[comp].size * id, + tmpl.entity_data.ptr + info.tmpl_deltas[comp], components[comp].size); + + if (components[comp].create_callback) + { + components[comp].create_callback( + cast(void*) block + info.deltas[comp] + id * components[comp].size); + } + + } + + if (index == 1) + threads[threadID].blockToUpdate.add(block); + + Entity* entity = cast(Entity*) start; + //add_mutex.lock_nothrow(); + entity.id = id_manager.getNewID(); + //add_mutex.unlock_nothrow(); + id_manager.update(*entity); //entity.updateID(); + + return entity;*/ + return addEntity(tmpl, null); + } + + /************************************************************************************************************************ + Add entity to system. Returen pointer is valid only before one from commit(), begin() or end() will be called. To save entity to further + use you should save ID instead of pointer. + + Params: + tmpl = pointer entity template allocated by EntityManager. + replacement = list of components references to used. Memory form list replace data from template inside new entity. Should be used only for data which vary between most entities (like 3D position etc.) + */ + export Entity* addEntity(EntityTemplate* tmpl, ComponentRef[] replacement) { EntityInfo* info = tmpl.info; @@ -2472,17 +2549,34 @@ export struct EntityManager void* data_begin = block.dataBegin(); void* start = data_begin + EntityID.sizeof * id; + foreach (comp; info.components) + { + uint size = components[comp].size; + memcpy(cast(void*) block + info.deltas[comp] + size * id, + tmpl.entity_data.ptr + info.tmpl_deltas[comp], size); + } + + foreach(comp; replacement) + { + if(comp.component_id < info.deltas.length) + { + ushort delta = info.deltas[comp.component_id]; + if(delta != ushort.max) + { + uint size = components[comp.component_id].size; + memcpy(cast(void*) block + delta + size * id, + comp.ptr, size); + } + } + } + foreach (i, comp; info.components) { - memcpy(cast(void*) block + info.deltas[comp] + components[comp].size * id, - tmpl.entity_data.ptr + info.tmpl_deltas[comp], components[comp].size); - if (components[comp].create_callback) { components[comp].create_callback( cast(void*) block + info.deltas[comp] + id * components[comp].size); } - } if (index == 1) @@ -2916,12 +3010,12 @@ export struct EntityManager swapData(); has_work = false; + has_work |= updateEvents(); + id_manager.optimize(); has_work |= updateBlocks(); has_work |= changeEntities(); has_work |= removeEntities(); - - has_work |= updateEvents(); } event_manager.clearEvents(); } diff --git a/tests/basic.d b/tests/basic.d index 3bf2814..ab9acec 100644 --- a/tests/basic.d +++ b/tests/basic.d @@ -153,6 +153,14 @@ unittest assert(entity2.getComponent!CFloat); assert(*entity2.getComponent!CInt == 2); assert(*entity2.getComponent!CFloat == 2.0); + + CInt cint = CInt(10); + CLong clong; + Entity* entity3 = gEM.addEntity(tmpl_, [cint.ref_, clong.ref_].staticArray); + assert(entity3.getComponent!CInt); + assert(entity3.getComponent!CFloat); + assert(*entity3.getComponent!CInt == 10); + assert(*entity3.getComponent!CFloat == 2.0); } //allocate templates @@ -1142,7 +1150,7 @@ unittest entity = gEM.getEntity(id); assert(*entity.getComponent!CLong == 66); - assert(*entity.getComponent!CInt == 36); + assert(*entity.getComponent!CInt == 2);//36); //test for multiple event blocks long result = *entity.getComponent!CLong; From 6929f5a7487a1c96239d03c256456f2952dab448 Mon Sep 17 00:00:00 2001 From: Mergul Date: Wed, 27 May 2020 17:03:44 +0200 Subject: [PATCH 144/217] Mostly bugfix update + empty components support and remove EntityID from Event structure -empty components now take no memory, so flag components is now far better -added test for critical bug -fixed critical bug with adding/removing entities form inside events -fixed small bug with TestRunner -improve basic tests -fixed betterC compilation on DMD -remove EntityID form Event structure -added "return" attribute to some functions -moved some code from Tempalte side to actual implementation -fixed bug with EntityTemplate copying -commented out some possibliy unused code -use code formatter --- source/bubel/ecs/atomic.d | 125 +++++++---- source/bubel/ecs/attributes.d | 2 +- source/bubel/ecs/block_allocator.d | 21 +- source/bubel/ecs/core.d | 9 +- source/bubel/ecs/entity.d | 11 +- source/bubel/ecs/events.d | 63 +++--- source/bubel/ecs/hash_map.d | 186 ++++++++++------ source/bubel/ecs/id_manager.d | 54 +++-- source/bubel/ecs/manager.d | 330 ++++++++++++++++------------- source/bubel/ecs/package.d | 2 +- source/bubel/ecs/simple_vector.d | 40 ++-- source/bubel/ecs/std.d | 215 +++++++++++-------- source/bubel/ecs/vector.d | 173 ++++++++++----- tests/basic.d | 153 ++++++++----- tests/bugs.d | 142 +++++++++++++ tests/runner.d | 6 +- 16 files changed, 988 insertions(+), 544 deletions(-) create mode 100644 tests/bugs.d diff --git a/source/bubel/ecs/atomic.d b/source/bubel/ecs/atomic.d index 9155c8f..8ea43df 100644 --- a/source/bubel/ecs/atomic.d +++ b/source/bubel/ecs/atomic.d @@ -9,9 +9,9 @@ License: BSD 3-clause, see LICENSE file in project root folder. */ module bubel.ecs.atomic; -version(Emscripten)version = ECSEmscripten; +version (Emscripten) version = ECSEmscripten; -version(ECSEmscripten) +version (ECSEmscripten) { import std.traits; @@ -24,74 +24,109 @@ version(ECSEmscripten) seq } - extern(C) ubyte emscripten_atomic_cas_u8(void *addr, ubyte oldVal, ubyte newVal) @nogc nothrow pure; - extern(C) ushort emscripten_atomic_cas_u16(void *addr, ushort oldVal, ushort newVal) @nogc nothrow pure; - extern(C) uint emscripten_atomic_cas_u32(void *addr, uint oldVal, uint newVal) @nogc nothrow pure; + extern (C) ubyte emscripten_atomic_cas_u8(void* addr, ubyte oldVal, ubyte newVal) @nogc nothrow pure; + extern (C) ushort emscripten_atomic_cas_u16(void* addr, ushort oldVal, ushort newVal) @nogc nothrow pure; + extern (C) uint emscripten_atomic_cas_u32(void* addr, uint oldVal, uint newVal) @nogc nothrow pure; - extern(C) ubyte emscripten_atomic_load_u8(const void *addr) @nogc nothrow pure; - extern(C) ushort emscripten_atomic_load_u16(const void *addr) @nogc nothrow pure; - extern(C) uint emscripten_atomic_load_u32(const void *addr) @nogc nothrow pure; + extern (C) ubyte emscripten_atomic_load_u8(const void* addr) @nogc nothrow pure; + extern (C) ushort emscripten_atomic_load_u16(const void* addr) @nogc nothrow pure; + extern (C) uint emscripten_atomic_load_u32(const void* addr) @nogc nothrow pure; - extern(C) ubyte emscripten_atomic_store_u8(void *addr, ubyte val) @nogc nothrow pure; - extern(C) ushort emscripten_atomic_store_u16(void *addr, ushort val) @nogc nothrow pure; - extern(C) uint emscripten_atomic_store_u32(void *addr, uint val) @nogc nothrow pure; + extern (C) ubyte emscripten_atomic_store_u8(void* addr, ubyte val) @nogc nothrow pure; + extern (C) ushort emscripten_atomic_store_u16(void* addr, ushort val) @nogc nothrow pure; + extern (C) uint emscripten_atomic_store_u32(void* addr, uint val) @nogc nothrow pure; - extern(C) ubyte emscripten_atomic_add_u8(void *addr, ubyte val) @nogc nothrow pure; - extern(C) ushort emscripten_atomic_add_u16(void *addr, ushort val) @nogc nothrow pure; - extern(C) uint emscripten_atomic_add_u32(void *addr, uint val) @nogc nothrow pure; + extern (C) ubyte emscripten_atomic_add_u8(void* addr, ubyte val) @nogc nothrow pure; + extern (C) ushort emscripten_atomic_add_u16(void* addr, ushort val) @nogc nothrow pure; + extern (C) uint emscripten_atomic_add_u32(void* addr, uint val) @nogc nothrow pure; - extern(C) ubyte emscripten_atomic_sub_u8(void *addr, ubyte val) @nogc nothrow pure; - extern(C) ushort emscripten_atomic_sub_u16(void *addr, ushort val) @nogc nothrow pure; - extern(C) uint emscripten_atomic_sub_u32(void *addr, uint val) @nogc nothrow pure; + extern (C) ubyte emscripten_atomic_sub_u8(void* addr, ubyte val) @nogc nothrow pure; + extern (C) ushort emscripten_atomic_sub_u16(void* addr, ushort val) @nogc nothrow pure; + extern (C) uint emscripten_atomic_sub_u32(void* addr, uint val) @nogc nothrow pure; public pure nothrow @nogc Unqual!T atomicOp(string op, T, V1)(ref shared T val, V1 mod) { - static if(op == "+=") + static if (op == "+=") { - static if(is(T == byte) || is(T == ubyte))return cast(Unqual!T)(emscripten_atomic_add_u8(cast(void*)&val, cast(Unqual!T)mod) + 1); - else static if(is(T == short) || is(T == ushort))return cast(Unqual!T)(emscripten_atomic_add_u16(cast(void*)&val, cast(Unqual!T)mod) + 1); - else static if(is(T == int) || is(T == uint))return cast(Unqual!T)(emscripten_atomic_add_u32(cast(void*)&val, cast(Unqual!T)mod) + 1); - else static assert(0); + static if (is(T == byte) || is(T == ubyte)) + return cast(Unqual!T)(emscripten_atomic_add_u8(cast(void*)&val, + cast(Unqual!T) mod) + 1); + else static if (is(T == short) || is(T == ushort)) + return cast(Unqual!T)(emscripten_atomic_add_u16(cast(void*)&val, + cast(Unqual!T) mod) + 1); + else static if (is(T == int) || is(T == uint)) + return cast(Unqual!T)(emscripten_atomic_add_u32(cast(void*)&val, + cast(Unqual!T) mod) + 1); + else + static assert(0); } - else static if(op == "-=") + else static if (op == "-=") { - static if(is(T == byte) || is(T == ubyte))return cast(Unqual!T)(emscripten_atomic_sub_u8(cast(void*)&val, cast(Unqual!T)mod) - 1); - else static if(is(T == short) || is(T == ushort))return cast(Unqual!T)(emscripten_atomic_sub_u16(cast(void*)&val, cast(Unqual!T)mod) - 1); - else static if(is(T == int) || is(T == uint))return cast(Unqual!T)(emscripten_atomic_sub_u32(cast(void*)&val, cast(Unqual!T)mod) - 1); - else static assert(0); + static if (is(T == byte) || is(T == ubyte)) + return cast(Unqual!T)(emscripten_atomic_sub_u8(cast(void*)&val, + cast(Unqual!T) mod) - 1); + else static if (is(T == short) || is(T == ushort)) + return cast(Unqual!T)(emscripten_atomic_sub_u16(cast(void*)&val, + cast(Unqual!T) mod) - 1); + else static if (is(T == int) || is(T == uint)) + return cast(Unqual!T)(emscripten_atomic_sub_u32(cast(void*)&val, + cast(Unqual!T) mod) - 1); + else + static assert(0); } } - public pure nothrow @nogc @trusted void atomicStore(MemoryOrder ms = MemoryOrder.seq, T, V)(ref T val, V newval) + public pure nothrow @nogc @trusted void atomicStore(MemoryOrder ms = MemoryOrder.seq, T, V)(ref T val, + V newval) { alias UT = Unqual!T; - static if(is(UT == bool) || is(UT == byte) || is(UT == ubyte))emscripten_atomic_store_u8(cast(void*)&val, cast(UT)newval); - else static if(is(UT == short) || is(UT == ushort))emscripten_atomic_store_u16(cast(void*)&val, cast(UT)newval); - else static if(is(UT == int) || is(UT == uint))emscripten_atomic_store_u32(cast(void*)&val, cast(UT)newval); - else static assert(0); + static if (is(UT == bool) || is(UT == byte) || is(UT == ubyte)) + emscripten_atomic_store_u8(cast(void*)&val, cast(UT) newval); + else static if (is(UT == short) || is(UT == ushort)) + emscripten_atomic_store_u16(cast(void*)&val, cast(UT) newval); + else static if (is(UT == int) || is(UT == uint)) + emscripten_atomic_store_u32(cast(void*)&val, cast(UT) newval); + else + static assert(0); } - public pure nothrow @nogc @trusted T atomicLoad(MemoryOrder ms = MemoryOrder.seq, T)(ref const T val) + public pure nothrow @nogc @trusted T atomicLoad(MemoryOrder ms = MemoryOrder.seq, T)( + ref const T val) { alias UT = Unqual!T; - static if(is(UT == bool))return emscripten_atomic_load_u8(cast(const void*)&val) != 0; - else static if(is(UT == byte) || is(UT == ubyte))return emscripten_atomic_load_u8(cast(const void*)&val); - else static if(is(UT == short) || is(UT == ushort))return emscripten_atomic_load_u16(cast(const void*)&val); - else static if(is(UT == int) || is(UT == uint))return emscripten_atomic_load_u32(cast(const void*)&val); - else static assert(0); + static if (is(UT == bool)) + return emscripten_atomic_load_u8(cast(const void*)&val) != 0; + else static if (is(UT == byte) || is(UT == ubyte)) + return emscripten_atomic_load_u8(cast(const void*)&val); + else static if (is(UT == short) || is(UT == ushort)) + return emscripten_atomic_load_u16(cast(const void*)&val); + else static if (is(UT == int) || is(UT == uint)) + return emscripten_atomic_load_u32(cast(const void*)&val); + else + static assert(0); } - public pure nothrow @nogc @trusted bool cas(MemoryOrder succ = MemoryOrder.seq, MemoryOrder fail = MemoryOrder.seq, T, V1, V2)(T* here, V1 ifThis, V2 writeThis) + public pure nothrow @nogc @trusted bool cas(MemoryOrder succ = MemoryOrder.seq, + MemoryOrder fail = MemoryOrder.seq, T, V1, V2)(T* here, V1 ifThis, V2 writeThis) { alias UT = Unqual!T; - static if(is(UT == bool))return emscripten_atomic_cas_u8(cast(void*)here, cast(Unqual!T)ifThis, cast(Unqual!T)writeThis) == ifThis; - else static if(is(UT == byte) || is(UT == ubyte))return emscripten_atomic_cas_u8(cast(void*)here, cast(Unqual!T)ifThis, cast(Unqual!T)writeThis) == ifThis; - else static if(is(UT == short) || is(UT == ushort))return emscripten_atomic_cas_u16(cast(void*)here, cast(Unqual!T)ifThis, cast(Unqual!T)writeThis) == ifThis; - else static if(is(UT == int) || is(UT == uint))return emscripten_atomic_cas_u32(cast(void*)here, cast(Unqual!T)ifThis, cast(Unqual!T)writeThis) == ifThis; - else static assert(0); + static if (is(UT == bool)) + return emscripten_atomic_cas_u8(cast(void*) here, + cast(Unqual!T) ifThis, cast(Unqual!T) writeThis) == ifThis; + else static if (is(UT == byte) || is(UT == ubyte)) + return emscripten_atomic_cas_u8(cast(void*) here, + cast(Unqual!T) ifThis, cast(Unqual!T) writeThis) == ifThis; + else static if (is(UT == short) || is(UT == ushort)) + return emscripten_atomic_cas_u16(cast(void*) here, + cast(Unqual!T) ifThis, cast(Unqual!T) writeThis) == ifThis; + else static if (is(UT == int) || is(UT == uint)) + return emscripten_atomic_cas_u32(cast(void*) here, + cast(Unqual!T) ifThis, cast(Unqual!T) writeThis) == ifThis; + else + static assert(0); } } else { public import core.atomic; -} \ No newline at end of file +} diff --git a/source/bubel/ecs/attributes.d b/source/bubel/ecs/attributes.d index 2bc0aec..d094aad 100644 --- a/source/bubel/ecs/attributes.d +++ b/source/bubel/ecs/attributes.d @@ -25,4 +25,4 @@ module bubel.ecs.attributes; ///Used to mark optional components for system. enum optional = "optional"; ///Used to mark readonly components for system. "const" can be used insted. -enum readonly = "readonly"; \ No newline at end of file +enum readonly = "readonly"; diff --git a/source/bubel/ecs/block_allocator.d b/source/bubel/ecs/block_allocator.d index 5a2d02c..d3070c4 100644 --- a/source/bubel/ecs/block_allocator.d +++ b/source/bubel/ecs/block_allocator.d @@ -35,7 +35,7 @@ struct BlockAllocator */ void freeBlock(void* block) nothrow @nogc { - *cast(void**)block = next_block; + *cast(void**) block = next_block; next_block = block; } @@ -44,9 +44,9 @@ struct BlockAllocator */ void freeMemory() nothrow @nogc { - while(pointers) + while (pointers) { - foreach(i;0..pointers.numberof) + foreach (i; 0 .. pointers.numberof) { Mallocator.alignDispose(pointers.blocks[i]); } @@ -60,12 +60,14 @@ private: void allocBlock() nothrow @nogc { - next_block = cast(void*) Mallocator.alignAlloc( - block_size * blocks_in_allocation, block_size); - if(next_block is null)assert(0); + next_block = cast(void*) Mallocator.alignAlloc(block_size * blocks_in_allocation, + block_size); + if (next_block is null) + assert(0); - if(pointers is null)pointers = Mallocator.make!BlockPointers; - if(pointers.numberof >= 32) + if (pointers is null) + pointers = Mallocator.make!BlockPointers; + if (pointers.numberof >= 32) { BlockPointers* new_pointers = Mallocator.make!BlockPointers; new_pointers.next_pointers = pointers; @@ -78,8 +80,7 @@ private: void** pointer = cast(void**)(next_block + i * block_size); *pointer = next_block + (i + 1) * block_size; } - void** pointer = cast(void**)( - next_block + (blocks_in_allocation - 1) * block_size); + void** pointer = cast(void**)(next_block + (blocks_in_allocation - 1) * block_size); *pointer = null; } diff --git a/source/bubel/ecs/core.d b/source/bubel/ecs/core.d index 4a90928..c032d21 100644 --- a/source/bubel/ecs/core.d +++ b/source/bubel/ecs/core.d @@ -75,19 +75,18 @@ static struct ECS { __gshared ushort component_id = ushort.max; - ComponentRef ref_() @nogc nothrow + ComponentRef ref_() @nogc nothrow return { - return ComponentRef(&this,component_id); + return ComponentRef(&this, component_id); } } /************************************************************************************************************************ Mark structure as Event. Should be added on top of structure (before any data). */ - mixin template Event() + mixin template Event() { __gshared ushort event_id = ushort.max; - EntityID entity_id; } /************************************************************************************************************************ @@ -113,4 +112,4 @@ static struct ECS { alias WritableDependencies = T; } -} \ No newline at end of file +} diff --git a/source/bubel/ecs/entity.d b/source/bubel/ecs/entity.d index f24ddf3..6a64d50 100644 --- a/source/bubel/ecs/entity.d +++ b/source/bubel/ecs/entity.d @@ -39,11 +39,7 @@ struct Entity if (T.component_id >= info.deltas.length || info.deltas[T.component_id] == 0) return null; - static if (EntityID.sizeof == 8) - uint ind = cast(uint)((cast(void*)&this - block.dataBegin()) >> 3); - else - uint ind = cast(uint)((cast(void*)&this - block.dataBegin()) / EntityID.sizeof()); - return cast(T*)(cast(void*)block + info.deltas[T.component_id] + ind * T.sizeof); + return cast(T*)(cast(void*)block + info.deltas[T.component_id] + block.entityIndex(&this) * T.sizeof); } bool hasComponent(ushort component_id) @@ -58,10 +54,7 @@ struct Entity { EntityMeta meta; meta.block = gEM.getMetaData(&this); - static if (EntityID.sizeof == 8) - meta.index = cast(ushort)((cast(void*)&this - meta.block.dataBegin()) >> 3); - else - meta.index = cast(ushort)((cast(void*)&this - meta.block.dataBegin()) / EntityID.sizeof()); + meta.index = meta.block.entityIndex(&this); return meta; } } diff --git a/source/bubel/ecs/events.d b/source/bubel/ecs/events.d index 25b864d..64e0c79 100644 --- a/source/bubel/ecs/events.d +++ b/source/bubel/ecs/events.d @@ -20,7 +20,7 @@ package struct EventManager void destroy() nothrow @nogc { - if(event_block_alloc_mutex) + if (event_block_alloc_mutex) { event_block_alloc_mutex.destroy(); Mallocator.dispose(event_block_alloc_mutex); @@ -30,14 +30,14 @@ package struct EventManager export void sendEvent(Ev)(EntityID id, Ev event, uint thread_id = 0) nothrow @nogc { - uint block_id = current_index+thread_id; + uint block_id = current_index + thread_id; EventData* data = &events[Ev.event_id]; EventBlock* block = data.blocks[block_id]; //EntityManager.EventInfo* info = &manager.events[Ev.event_id]; - event.entity_id = id; + //event.entity_id = id; - if(block is null) + if (block is null) { event_block_alloc_mutex.lock(); block = cast(EventBlock*) allocator.getBlock(); @@ -48,35 +48,42 @@ package struct EventManager data.blocks[block_id] = block; } - if(block.count >= data.max_events) + if (block.count >= data.max_events) { event_block_alloc_mutex.lock(); EventBlock* new_block = cast(EventBlock*) allocator.getBlock(); event_block_alloc_mutex.unlock(); - + *new_block = EventBlock(); block.next = new_block; block = new_block; data.blocks[block_id] = block; } - Ev* event_array = cast(Ev*)(cast(void*)block + data.data_offset); - event_array[block.count] = event; + uint size = Ev.sizeof + EntityID.sizeof; + void* ptr = cast(void*) block + data.data_offset + block.count * size; + *cast(EntityID*)ptr = id; + *cast(Ev*)(ptr + EntityID.sizeof) = event; + //Ev* event_array = cast(Ev*)(cast(void*) block + data.data_offset); + //event_array[block.count] = event; block.count++; } void swapCurrent() nothrow @nogc { - uint threads_count = cast(uint)manager.threads.length; - if(current_index == 0)current_index = threads_count; - else current_index = 0; + uint threads_count = cast(uint) manager.threads.length; + if (current_index == 0) + current_index = threads_count; + else + current_index = 0; - foreach(ref event;events) + foreach (ref event; events) { - foreach(ref first_block; event.first_blocks[current_index .. current_index + threads_count]) + foreach (ref first_block; event.first_blocks[current_index + .. current_index + threads_count]) { EventBlock* block = first_block; - while(block) + while (block) { EventBlock* to_dispose = block; block = block.next; @@ -84,7 +91,7 @@ package struct EventManager } first_block = null; } - foreach(ref block; event.blocks[current_index .. current_index + threads_count]) + foreach (ref block; event.blocks[current_index .. current_index + threads_count]) { block = null; } @@ -94,12 +101,12 @@ package struct EventManager void clearEvents() nothrow @nogc { //uint threads_count = cast(uint)manager.threads.length; - foreach(ref event;events) + foreach (ref event; events) { - foreach(ref first_block; event.first_blocks) + foreach (ref first_block; event.first_blocks) { EventBlock* block = first_block; - while(block) + while (block) { EventBlock* to_dispose = block; block = block.next; @@ -107,7 +114,7 @@ package struct EventManager } first_block = null; } - foreach(ref block; event.blocks) + foreach (ref block; event.blocks) { block = null; } @@ -118,23 +125,25 @@ package struct EventManager { disposeData(); events = Mallocator.makeArray!EventData(manager.events.length); - foreach(i,ref event;events) + foreach (i, ref event; events) { - event.blocks = Mallocator.makeArray!(EventBlock*)(threads_count*2); - event.first_blocks = Mallocator.makeArray!(EventBlock*)(threads_count*2); - event.data_offset = EventBlock.sizeof;//manager.events[i]. + event.blocks = Mallocator.makeArray!(EventBlock*)(threads_count * 2); + event.first_blocks = Mallocator.makeArray!(EventBlock*)(threads_count * 2); + event.data_offset = EventBlock.sizeof; //manager.events[i]. manager.alignNum(event.data_offset, manager.events[i].alignment); - event.max_events = cast(ushort)((events_block_size - event.data_offset) / manager.events[i].size); + uint size = manager.events[i].size + EntityID.sizeof; + event.max_events = cast(ushort)( + (events_block_size - event.data_offset) / size); } } private void disposeData() nothrow @nogc { clearEvents(); - if(events) + if (events) { - foreach(ref event;events) + foreach (ref event; events) { Mallocator.dispose(event.blocks); Mallocator.dispose(event.first_blocks); @@ -166,7 +175,7 @@ package struct EventManager ushort max_events; EventBlock*[] blocks; EventBlock*[] first_blocks; - + //EventBlock*[] current_blocks; } diff --git a/source/bubel/ecs/hash_map.d b/source/bubel/ecs/hash_map.d index 1f7a1f8..6ae6a79 100755 --- a/source/bubel/ecs/hash_map.d +++ b/source/bubel/ecs/hash_map.d @@ -11,36 +11,44 @@ private enum HASH_EMPTY = 0; private enum HASH_DELETED = 0x1; private enum HASH_FILLED_MARK = ulong(1) << 8 * ulong.sizeof - 1; -export ulong defaultHashFunc(T)(auto ref T t) nothrow @nogc { - static if (isIntegral!(T)) { +export ulong defaultHashFunc(T)(auto ref T t) nothrow @nogc +{ + static if (isIntegral!(T)) + { return hashInt(t); - } else { - return 0;//hashInt(t.hashOf); // hashOf is not giving proper distribution between H1 and H2 hash parts + } + else + { + return 0; //hashInt(t.hashOf); // hashOf is not giving proper distribution between H1 and H2 hash parts } } // Can turn bad hash function to good one -export ulong hashInt(ulong x) nothrow @nogc @safe { +export ulong hashInt(ulong x) nothrow @nogc @safe +{ x = (x ^ (x >> 30)) * 0xbf58476d1ce4e5b9; x = (x ^ (x >> 27)) * 0x94d049bb133111eb; x = x ^ (x >> 31); return x; } -struct HashMap(KeyPar, ValuePar, alias hashFunc = defaultHashFunc) { +struct HashMap(KeyPar, ValuePar, alias hashFunc = defaultHashFunc) +{ alias Key = KeyPar; alias Value = ValuePar; - nothrow: +nothrow: enum rehashFactor = 0.75; enum size_t getIndexEmptyValue = size_t.max; - static struct KeyVal { + static struct KeyVal + { Key key; Value value; } - static struct Bucket { + static struct Bucket + { ulong hash; KeyVal keyValue; } @@ -49,58 +57,74 @@ struct HashMap(KeyPar, ValuePar, alias hashFunc = defaultHashFunc) { size_t length; // Used to compute loadFactor size_t markerdDeleted; - export void clear() { + export void clear() + { elements.clear(); length = 0; markerdDeleted = 0; } - export void reset() { + export void reset() + { elements.reset(); length = 0; markerdDeleted = 0; } - export bool isIn(ref Key el) { + export bool isIn(ref Key el) + { return getIndex(el) != getIndexEmptyValue; } - export bool isIn(Key el) { + export bool isIn(Key el) + { return getIndex(el) != getIndexEmptyValue; } - export Value* getPtr()(auto ref Key k) { + export Value* getPtr()(auto ref Key k) + { size_t index = getIndex(k); - if (index == getIndexEmptyValue) { + if (index == getIndexEmptyValue) + { return null; - } else { + } + else + { return &elements[index].keyValue.value; } } - export ref Value get()(auto ref Key k) { + export ref Value get()(auto ref Key k) + { size_t index = getIndex(k); assert(index != getIndexEmptyValue); return elements[index].keyValue.value; } deprecated("Use get with second parameter.") export auto ref Value getDefault()( - auto ref Key k, auto ref Value defaultValue) { + auto ref Key k, auto ref Value defaultValue) + { return get(k, defaultValue); } - export auto ref Value get()(auto ref Key k, auto ref Value defaultValue) { + export auto ref Value get()(auto ref Key k, auto ref Value defaultValue) + { size_t index = getIndex(k); - if (index == getIndexEmptyValue) { + if (index == getIndexEmptyValue) + { return defaultValue; - } else { + } + else + { return elements[index].keyValue.value; } } - export ref Value getInsertDefault()(auto ref Key k, auto ref Value defaultValue) { + export ref Value getInsertDefault()(auto ref Key k, auto ref Value defaultValue) + { size_t index = getIndex(k); - if (index == getIndexEmptyValue) { + if (index == getIndexEmptyValue) + { add(k, defaultValue); } index = getIndex(k); @@ -109,9 +133,11 @@ struct HashMap(KeyPar, ValuePar, alias hashFunc = defaultHashFunc) { } - export bool tryRemove(Key el) { + export bool tryRemove(Key el) + { size_t index = getIndex(el); - if (index == getIndexEmptyValue) { + if (index == getIndexEmptyValue) + { return false; } length--; @@ -120,28 +146,34 @@ struct HashMap(KeyPar, ValuePar, alias hashFunc = defaultHashFunc) { return true; } - export void remove(Key el) { + export void remove(Key el) + { bool ok = tryRemove(el); assert(ok); } - export ref Value opIndex()(auto ref Key key) { + export ref Value opIndex()(auto ref Key key) + { return get(key); } - export void opIndexAssign()(auto ref Value value, auto ref Key key) { + export void opIndexAssign()(auto ref Value value, auto ref Key key) + { add(key, value); } - export void add()(auto ref Key key, auto ref Value value) { + export void add()(auto ref Key key, auto ref Value value) + { size_t index = getIndex(key); - if (index != getIndexEmptyValue) { + if (index != getIndexEmptyValue) + { elements[index].keyValue.value = value; return; } if (getLoadFactor(length + 1) > rehashFactor - || getLoadFactor(length + markerdDeleted) > rehashFactor) { + || getLoadFactor(length + markerdDeleted) > rehashFactor) + { rehash(); } length++; @@ -150,10 +182,13 @@ struct HashMap(KeyPar, ValuePar, alias hashFunc = defaultHashFunc) { immutable size_t rotateMask = elements.length - 1; index = hash & rotateMask; // Starting point - while (true) { + while (true) + { Bucket* gr = &elements[index]; - if ((gr.hash & HASH_FILLED_MARK) == 0) { - if (gr.hash == HASH_DELETED) { + if ((gr.hash & HASH_FILLED_MARK) == 0) + { + if (gr.hash == HASH_DELETED) + { markerdDeleted--; } gr.hash = hash; @@ -171,15 +206,18 @@ struct HashMap(KeyPar, ValuePar, alias hashFunc = defaultHashFunc) { //int numA; //int numB; - export size_t getIndex(Key el) { + export size_t getIndex(Key el) + { return getIndex(el); } - export size_t getIndex(ref Key el) { + export size_t getIndex(ref Key el) + { mixin(doNotInline); immutable size_t groupsLength = elements.length; - if (groupsLength == 0) { + if (groupsLength == 0) + { return getIndexEmptyValue; } @@ -188,13 +226,16 @@ struct HashMap(KeyPar, ValuePar, alias hashFunc = defaultHashFunc) { size_t index = hash & rotateMask; // Starting point //numA++; - while (true) { + while (true) + { //numB++; Bucket* gr = &elements[index]; - if (gr.hash == hash && gr.keyValue.key == el) { + if (gr.hash == hash && gr.keyValue.key == el) + { return index; } - if (gr.hash == HASH_EMPTY) { + if (gr.hash == HASH_EMPTY) + { return getIndexEmptyValue; } @@ -204,21 +245,26 @@ struct HashMap(KeyPar, ValuePar, alias hashFunc = defaultHashFunc) { } - export float getLoadFactor(size_t forElementsNum) { - if (elements.length == 0) { + export float getLoadFactor(size_t forElementsNum) + { + if (elements.length == 0) + { return 1; } return cast(float) forElementsNum / (elements.length); } - export void rehash()() { + export void rehash()() + { mixin(doNotInline); // Get all elements Vector!KeyVal allElements; allElements.reserve(elements.length); - foreach (ref Bucket el; elements) { - if ((el.hash & HASH_FILLED_MARK) == 0) { + foreach (ref Bucket el; elements) + { + if ((el.hash & HASH_FILLED_MARK) == 0) + { el.hash = HASH_EMPTY; continue; } @@ -227,12 +273,14 @@ struct HashMap(KeyPar, ValuePar, alias hashFunc = defaultHashFunc) { } - if (getLoadFactor(length + 1) > rehashFactor) { // Reallocate + if (getLoadFactor(length + 1) > rehashFactor) + { // Reallocate elements.length = (elements.length ? elements.length : 4) << 1; // Power of two, initially 8 elements } // Insert elements - foreach (i, ref el; allElements) { + foreach (i, ref el; allElements) + { add(el.key, el.value); } length = allElements.length; @@ -240,19 +288,29 @@ struct HashMap(KeyPar, ValuePar, alias hashFunc = defaultHashFunc) { } // foreach support - export int opApply(DG)(scope DG dg) { + export int opApply(DG)(scope DG dg) + { int result; - foreach (ref Bucket gr; elements) { - if ((gr.hash & HASH_FILLED_MARK) == 0) { + foreach (ref Bucket gr; elements) + { + if ((gr.hash & HASH_FILLED_MARK) == 0) + { continue; } - static if (isForeachDelegateWithTypes!(DG, Key)) { + static if (isForeachDelegateWithTypes!(DG, Key)) + { result = dg(gr.keyValue.key); - } else static if (isForeachDelegateWithTypes!(DG, Value)) { + } + else static if (isForeachDelegateWithTypes!(DG, Value)) + { result = dg(gr.keyValue.value); - } else static if (isForeachDelegateWithTypes!(DG, Key, Value)) { + } + else static if (isForeachDelegateWithTypes!(DG, Key, Value)) + { result = dg(gr.keyValue.key, gr.keyValue.value); - } else { + } + else + { static assert(0); } if (result) @@ -263,9 +321,11 @@ struct HashMap(KeyPar, ValuePar, alias hashFunc = defaultHashFunc) { return result; } - export int byKey(scope int delegate(Key k) nothrow dg) { + export int byKey(scope int delegate(Key k) nothrow dg) + { int result; - foreach (ref Key k; this) { + foreach (ref Key k; this) + { result = dg(k); if (result) break; @@ -273,9 +333,11 @@ struct HashMap(KeyPar, ValuePar, alias hashFunc = defaultHashFunc) { return result; } - export int byValue(scope int delegate(ref Value k) nothrow dg) { + export int byValue(scope int delegate(ref Value k) nothrow dg) + { int result; - foreach (ref Value v; this) { + foreach (ref Value v; this) + { result = dg(v); if (result) break; @@ -283,13 +345,15 @@ struct HashMap(KeyPar, ValuePar, alias hashFunc = defaultHashFunc) { return result; } - export int byKeyValue(scope int delegate(ref Key k, ref Value v) nothrow dg) { + export int byKeyValue(scope int delegate(ref Key k, ref Value v) nothrow dg) + { int result; - foreach (ref Key k, ref Value v; this) { + foreach (ref Key k, ref Value v; this) + { result = dg(k, v); if (result) break; } return result; } -} \ No newline at end of file +} diff --git a/source/bubel/ecs/id_manager.d b/source/bubel/ecs/id_manager.d index 4c3a2c3..084a947 100644 --- a/source/bubel/ecs/id_manager.d +++ b/source/bubel/ecs/id_manager.d @@ -18,7 +18,7 @@ struct IDManager pragma(inline, false) EntityID getNewID() nothrow @nogc { int current = m_stack_top.atomicOp!"-="(1) + 1; - if(current < 0) + if (current < 0) { uint add_id = m_last_id.atomicOp!"+="(1) - 1; @@ -29,7 +29,7 @@ struct IDManager if (block_id >= m_blocks_count) { add_mutex.lock(); - if(block_id >= m_blocks_count) + if (block_id >= m_blocks_count) { m_blocks[m_blocks_count].alloc(); m_blocks_count++; @@ -112,9 +112,11 @@ struct IDManager */ export bool isExist(EntityID id) nothrow @nogc { - if(id.id >= m_ids_array.length)return false; + if (id.id >= m_ids_array.length) + return false; Data* data = &m_ids_array[id.id]; - if(data.entity is null)return false; + if (data.entity is null) + return false; return data.counter == id.counter; } @@ -126,7 +128,8 @@ struct IDManager m_ids_array = Mallocator.makeArray!Data(65536); m_free_stack = Mallocator.makeArray!uint(65536); m_blocks = Mallocator.makeArray!Block(64); - foreach(ref block;m_blocks)block = Block(); + foreach (ref block; m_blocks) + block = Block(); m_blocks_count = 1; m_blocks[0].alloc(); @@ -142,20 +145,23 @@ struct IDManager */ void deinitialize() @trusted @nogc nothrow { - if(m_ids_array)Mallocator.dispose(m_ids_array); - if(m_free_stack)Mallocator.dispose(m_free_stack); - if(m_blocks) + if (m_ids_array) + Mallocator.dispose(m_ids_array); + if (m_free_stack) + Mallocator.dispose(m_free_stack); + if (m_blocks) { - foreach(ref block;m_blocks) + foreach (ref block; m_blocks) { - if(block.data)block.free(); + if (block.data) + block.free(); } Mallocator.dispose(m_blocks); } - if(add_mutex) + if (add_mutex) { add_mutex.destroy(); - Mallocator.dispose(add_mutex);//cast(void*)add_mutex); //workaround for compiler bug + Mallocator.dispose(add_mutex); //cast(void*)add_mutex); //workaround for compiler bug add_mutex = null; } } @@ -165,27 +171,31 @@ struct IDManager */ void optimize() nothrow @nogc { - if(m_stack_top < -1)m_stack_top = -1; - if(m_last_id > m_ids_array.length) + if (m_stack_top < -1) + m_stack_top = -1; + if (m_last_id > m_ids_array.length) { - uint begin = cast(uint)m_ids_array.length; + uint begin = cast(uint) m_ids_array.length; Data[] new_array = Mallocator.makeArray!Data(begin + (m_blocks_count << 16)); memcpy(new_array.ptr, m_ids_array.ptr, m_ids_array.length * Data.sizeof); Mallocator.dispose(m_ids_array); m_ids_array = new_array; uint[] new_stack = Mallocator.makeArray!uint(m_ids_array.length); - memcpy(new_stack.ptr,m_free_stack.ptr,m_free_stack.length * uint.sizeof); + memcpy(new_stack.ptr, m_free_stack.ptr, m_free_stack.length * uint.sizeof); Mallocator.dispose(m_free_stack); m_free_stack = new_stack; - foreach(block;m_blocks[0..m_blocks_count-1]) + foreach (block; m_blocks[0 .. m_blocks_count - 1]) { - memcpy(cast(void*)m_ids_array.ptr + begin * Data.sizeof, block.data.ptr, 65536 * Data.sizeof); + memcpy(cast(void*) m_ids_array.ptr + begin * Data.sizeof, + block.data.ptr, 65536 * Data.sizeof); begin += 65536; } - memcpy(cast(void*)m_ids_array.ptr + begin * Data.sizeof, m_blocks[m_blocks_count-1].data.ptr, (m_last_id - begin) * Data.sizeof); - foreach(ref block;m_blocks[1..m_blocks_count])block.free(); + memcpy(cast(void*) m_ids_array.ptr + begin * Data.sizeof, + m_blocks[m_blocks_count - 1].data.ptr, (m_last_id - begin) * Data.sizeof); + foreach (ref block; m_blocks[1 .. m_blocks_count]) + block.free(); m_blocks_count = 1; } } @@ -217,12 +227,12 @@ struct IDManager private: Mutex* add_mutex; - + Data[] m_ids_array = null; uint m_blocks_count = 0; Block[] m_blocks; uint[] m_free_stack = null; - + align(64) shared uint m_last_id = 0; align(64) shared int m_stack_top = -1; } diff --git a/source/bubel/ecs/manager.d b/source/bubel/ecs/manager.d index 3ac16e8..cf3712d 100644 --- a/source/bubel/ecs/manager.d +++ b/source/bubel/ecs/manager.d @@ -126,7 +126,7 @@ export struct EntityManager //if(info.components)Mallocator.dispose(info.components); Mallocator.dispose(info); - } + } foreach (UpdatePass* pass; passes) { @@ -402,7 +402,7 @@ export struct EntityManager Sys* data_system = cast(Sys*) data.system_pointer; Type* event = cast(Type*) data.event; - data_system.handleEvent(gEM.getEntity(event.entity_id), *event); + data_system.handleEvent(data.entity, *event); } void setEventCallers(Sys)(ref System system) @@ -474,7 +474,7 @@ export struct EntityManager { //continue; } - else + else { string name; static if (isArray!MemberType) @@ -1018,8 +1018,7 @@ export struct EntityManager static if (hasMember!(Sys.EntitiesData, "job_id")) { - input_data.job_id = cast(typeof(input_data.job_id)) data - .job_id; + input_data.job_id = cast(typeof(input_data.job_id)) data.job_id; } //s.onUpdate(input_data); @@ -1052,8 +1051,7 @@ export struct EntityManager static if (hasMember!(Sys.EntitiesData, "job_id")) { - input_data.job_id = cast(typeof(input_data.job_id)) data - .job_id; + input_data.job_id = cast(typeof(input_data.job_id)) data.job_id; } (cast(typeof(&__traits(getOverloads, s, @@ -1146,7 +1144,8 @@ export struct EntityManager foreach (iii, comp_info; components_info.readonlyDeps) { - ushort comp = external_dependencies_map.get(cast(const (char)[]) comp_info.type, ushort.max); + ushort comp = external_dependencies_map.get(cast(const(char)[]) comp_info.type, + ushort.max); version (D_BetterC) assert(comp != ushort.max, "Can't register system \"" ~ Sys.stringof @@ -1156,7 +1155,7 @@ export struct EntityManager ~ "\" due to non existing dependency \"" ~ comp_info.type ~ "\"."); system.m_readonly_dependencies[iii] = comp; } - + foreach (iii, comp_info; components_info.writableDeps) { ushort comp = external_dependencies_map.get(cast(char[]) comp_info.type, ushort.max); @@ -1174,7 +1173,9 @@ export struct EntityManager if (sys_id < systems.length) { systems[sys_id].disable(); - if(systems[sys_id].m_destroy)(cast(void function(void*)) systems[sys_id].m_destroy)(systems[sys_id].m_system_pointer); + if (systems[sys_id].m_destroy) + (cast(void function(void*)) systems[sys_id].m_destroy)( + systems[sys_id].m_system_pointer); if (system.m_create) (cast(void function(void*)) system.m_create)(system.m_system_pointer); @@ -1236,7 +1237,7 @@ export struct EntityManager export void registerDependency(const(char)[] name) { - return external_dependencies_map.add(name, cast(ushort)external_dependencies_map.length); + return external_dependencies_map.add(name, cast(ushort) external_dependencies_map.length); } /************************************************************************************************************************ @@ -1274,7 +1275,10 @@ export struct EntityManager info.create_callback = &callCreate; } - info.size = Comp.sizeof; + static if (Comp.sizeof == 1 && Fields!(Comp).length == 0) + info.size = 0; + else + info.size = Comp.sizeof; info.alignment = Comp.alignof; //8; info.init_data = Mallocator.makeArray!ubyte(Comp.sizeof); *cast(Comp*) info.init_data.ptr = Comp.init; // = Comp(); @@ -1340,7 +1344,9 @@ export struct EntityManager "Can't call function with system which hasn't EntitesData structure."); static assert(__traits(hasMember, Sys, "onUpdate"), "Can't call function with system which hasn't onUpdate function callback."); - static assert(is(SetFunctionAttributes!(T,functionLinkage!(s.onUpdate), functionAttributes!(s.onUpdate)) == typeof(&s.onUpdate)), "Function must match system update function."); + static assert(is(SetFunctionAttributes!(T, functionLinkage!(s.onUpdate), + functionAttributes!(s.onUpdate)) == typeof(&s.onUpdate)), + "Function must match system update function."); static assert(__traits(hasMember, Sys, "system_id"), "Sys must be system type."); System* system = getSystem(Sys.system_id); @@ -1612,6 +1618,8 @@ export struct EntityManager //fill components with default data foreach (comp; info.components) { + if (components[comp].size == 0) + continue; memcpy(temp.entity_data.ptr + info.tmpl_deltas[comp], components[comp].init_data.ptr, components[comp].size); } @@ -1621,6 +1629,8 @@ export struct EntityManager ushort index = block.entityIndex(entity); foreach (comp; info.components) { + if (components[comp].size == 0) + continue; memcpy(cast(void*) temp.entity_data.ptr + info.tmpl_deltas[comp], cast(void*) block + info.deltas[comp] + components[comp].size * index, components[comp].size); @@ -1669,6 +1679,8 @@ export struct EntityManager //fill components with default data foreach (comp; info.components) { + if (components[comp].size == 0) + continue; memcpy(temp.entity_data.ptr + info.tmpl_deltas[comp], components[comp].init_data.ptr, components[comp].size); } @@ -1736,14 +1748,19 @@ export struct EntityManager //fill components with default data and copy from base template foreach (comp; info.components) { - if (comp < base_tmpl.info.deltas.length && base_tmpl.info.deltas[comp] != ushort.max) //copy data from base component - { + if (comp < base_tmpl.info.tmpl_deltas.length + && base_tmpl.info.tmpl_deltas[comp] != ushort.max) //copy data from base component + { + if (components[comp].size == 0) + continue; memcpy(temp.entity_data.ptr + info.tmpl_deltas[comp], base_tmpl.entity_data.ptr + base_tmpl.info.tmpl_deltas[comp], components[comp].size); } else //fill with default data { + if (components[comp].size == 0) + continue; memcpy(temp.entity_data.ptr + info.tmpl_deltas[comp], components[comp].init_data.ptr, components[comp].size); } @@ -1833,8 +1850,8 @@ export struct EntityManager } info.comp_add_info = Mallocator.makeArray!(EntityInfo*)(instance.components.length); - info.comp_rem_info = Mallocator.makeArray!(EntityInfo*)(instance.components.length, - info); + //info.comp_rem_info = Mallocator.makeArray!(EntityInfo*)(instance.components.length); + info.comp_rem_info = Mallocator.makeArray!(EntityInfo*)(info.deltas.length); foreach (comp; info.components) { @@ -1894,11 +1911,11 @@ export struct EntityManager } add_len++; //move elements after new listener - if(add_len < tmp_add.length) - for (int k = add_len; k > j; k--) - { - tmp_add[k] = tmp_add[k - 1]; - } + if (add_len < tmp_add.length) + for (int k = add_len; k > j; k--) + { + tmp_add[k] = tmp_add[k - 1]; + } //assign listener tmp_add[j] = cast(ushort) i; } @@ -1914,11 +1931,11 @@ export struct EntityManager } rem_len++; //move elements after new listener - if(rem_len < tmp_add.length) - for (int k = rem_len; k > j; k--) - { - tmp_rem[k] = tmp_rem[k - 1]; - } + if (rem_len < tmp_add.length) + for (int k = rem_len; k > j; k--) + { + tmp_rem[k] = tmp_rem[k - 1]; + } //assign listener tmp_rem[j] = cast(ushort) i; } @@ -1934,11 +1951,11 @@ export struct EntityManager } ch_len++; //move elements after new listener - if(ch_len < tmp_add.length) - for (int k = ch_len; k > j; k--) - { - tmp_ch[k] = tmp_ch[k - 1]; - } + if (ch_len < tmp_add.length) + for (int k = ch_len; k > j; k--) + { + tmp_ch[k] = tmp_ch[k - 1]; + } //assign listener tmp_ch[j] = cast(ushort) i; } @@ -2160,6 +2177,8 @@ export struct EntityManager foreach (comp; new_info.components) { uint comp_size = components[comp].size; + if (comp_size == 0) + continue; memcpy(cast(void*) new_block + new_info.deltas[comp] + new_block.entities_count * comp_size, cast(void*) block + info.deltas[comp] + ind * comp_size, comp_size); } @@ -2296,24 +2315,29 @@ export struct EntityManager foreach (id; new_info.components) //ids[0 .. len]) { - void* dst = cast(void*) new_block + new_info.deltas[id] + ( - new_block.entities_count) * components[id].size; uint size = components[id].size; + void* dst = void; + if (size != 0) + dst = cast(void*) new_block + new_info.deltas[id] + (new_block.entities_count) + * size; if (k >= new_ids.length) { - memcpy(dst, cast(void*) block + info.deltas[id] + ind * size, size); + if (size != 0) + memcpy(dst, cast(void*) block + info.deltas[id] + ind * size, size); j++; } else if (j >= info.components.length || id == new_ids[k]) { - memcpy(dst, data_pointers[k], size); + if (size != 0) + memcpy(dst, data_pointers[k], size); k++; } else { assert(id != new_ids[0]); - memcpy(dst, cast(void*) block + info.deltas[id] + ind * size, size); + if (size != 0) + memcpy(dst, cast(void*) block + info.deltas[id] + ind * size, size); j++; } } @@ -2376,28 +2400,30 @@ export struct EntityManager //__addComponents(entity_id, new_ids, pointers); ComponentRef[num] _comps; - static foreach(i, comp; comps) + static foreach (i, comp; comps) { _comps[i] = comp.ref_; } addComponents(entity_id, _comps); - + } export void addComponents(const EntityID entity_id, ComponentRef[] comps) nothrow @nogc { - uint num = cast(uint)comps.length; + uint num = cast(uint) comps.length; ThreadData* data = &threads[threadID]; data.changeEntitiesList.add(cast(ubyte) 1u); data.changeEntitiesList.add((cast(ubyte*)&entity_id)[0 .. EntityID.sizeof]); data.changeEntitiesList.add((cast(ubyte*)&num)[0 .. uint.sizeof]); - foreach(ref_; comps) + foreach (ref_; comps) { data.changeEntitiesList.add((cast(ubyte*)&ref_.component_id)[0 .. ushort.sizeof]); } - foreach(ref_; comps) + foreach (ref_; comps) { - data.changeEntitiesList.add((cast(ubyte*)ref_.ptr)[0 .. components[ref_.component_id].size]); + if (components[ref_.component_id].size != 0) + data.changeEntitiesList.add( + (cast(ubyte*) ref_.ptr)[0 .. components[ref_.component_id].size]); } /*data.changeEntitiesList.add(cast(ubyte[]) new_ids); static foreach (i, comp; comps) @@ -2449,14 +2475,15 @@ export struct EntityManager foreach (i, comp; info.components) { - memcpy(cast(void*) new_block + info.deltas[comp] + components[comp].size * new_id, - cast(void*) block + info.deltas[comp] + components[comp].size * index, - components[comp].size); + ushort size = components[comp].size; + if (size != 0) + memcpy(cast(void*) new_block + info.deltas[comp] + size * new_id, + cast(void*) block + info.deltas[comp] + size * index, size); if (components[comp].create_callback) { - components[comp].create_callback(cast( - void*) block + info.deltas[comp] + new_id * components[comp].size); + components[comp].create_callback( + cast(void*) block + info.deltas[comp] + new_id * size); } } @@ -2552,20 +2579,21 @@ export struct EntityManager foreach (comp; info.components) { uint size = components[comp].size; - memcpy(cast(void*) block + info.deltas[comp] + size * id, - tmpl.entity_data.ptr + info.tmpl_deltas[comp], size); + if (size != 0) + memcpy(cast(void*) block + info.deltas[comp] + size * id, + tmpl.entity_data.ptr + info.tmpl_deltas[comp], size); } - foreach(comp; replacement) + foreach (comp; replacement) { - if(comp.component_id < info.deltas.length) + if (comp.component_id < info.deltas.length) { ushort delta = info.deltas[comp.component_id]; - if(delta != ushort.max) + if (delta != ushort.max) { uint size = components[comp.component_id].size; - memcpy(cast(void*) block + delta + size * id, - comp.ptr, size); + if (size != 0) + memcpy(cast(void*) block + delta + size * id, comp.ptr, size); } } } @@ -2678,8 +2706,10 @@ export struct EntityManager { //get entity and block meta data pointers Entity* entity = id_manager.getEntityPointer(id); + if (entity is null) return; //return if entity doesn't exist + EntitiesBlock* block = getMetaData(entity); EntityInfo* info = block.type_info; @@ -2700,6 +2730,9 @@ export struct EntityManager { EntityInfo* info = block.type_info; + if (info.last_block.added_count) + updateBlock(info.last_block); + info.last_block.entities_count--; uint pos = block.entityIndex(entity); @@ -2720,9 +2753,11 @@ export struct EntityManager { foreach (comp; info.components) { + uint size = components[comp].size; + if (size == 0) + continue; void* src = cast(void*) info.last_block + info.deltas[comp]; void* dst = cast(void*) block + info.deltas[comp]; - uint size = components[comp].size; memcpy(dst + pos * size, src + info.last_block.entities_count * size, size); } @@ -2768,7 +2803,8 @@ export struct EntityManager { uint index = 0; uint len = cast(uint) thread.changeEntitiesListPrev.length; - if(len)has_work = true; + if (len) + has_work = true; void*[32] pointers; // = (cast(void**) alloca(num * (void*).sizeof))[0 .. num]; while (index < len) { @@ -2798,7 +2834,7 @@ export struct EntityManager pointers[i] = &thread.changeEntitiesListPrev[index]; index += components[ids[i]].size; } - + __addComponents(id, ids, pointers[0 .. num]); } } @@ -2885,6 +2921,23 @@ export struct EntityManager (cast(void function(ref ListenerCallData) nothrow @nogc) system.m_change_entity)(data); } + private void updateBlock(EntitiesBlock* block) @nogc nothrow + { + EntityInfo* info = block.type_info; + ushort entities_count = block.entities_count; + block.entities_count += block.added_count; + if (block.entities_count > block.type_info.max_entities) + { + block.entities_count = block.type_info.max_entities; + } + block.added_count.atomicStore(cast(ushort) 0); + + if (info.add_listeners) + { + callAddEntityListeners(info, block, entities_count, block.entities_count); + } + } + private bool updateBlocks() { bool has_work = false; @@ -2892,22 +2945,11 @@ export struct EntityManager foreach (ref ThreadData thread; threads) { //thread.swapToUpdate(); - if(thread.blockToUpdatePrev.length)has_work = true; + if (thread.blockToUpdatePrev.length) + has_work = true; foreach (block; thread.blockToUpdatePrev) { - EntityInfo* info = block.type_info; - ushort entities_count = block.entities_count; - block.entities_count += block.added_count; - if (block.entities_count > block.type_info.max_entities) - { - block.entities_count = block.type_info.max_entities; - } - block.added_count.atomicStore(cast(ushort) 0); - - if (info.add_listeners) - { - callAddEntityListeners(info, block, entities_count, block.entities_count); - } + updateBlock(block); } thread.blockToUpdatePrev.clear(); } @@ -2920,7 +2962,8 @@ export struct EntityManager //foreach (ref ThreadData thread; threads)thread.swapToRemove(); foreach (ref ThreadData thread; threads) { - if(thread.entitiesToRemovePrev.length)has_work = true; + if (thread.entitiesToRemovePrev.length) + has_work = true; foreach (id; thread.entitiesToRemovePrev) { __removeEntity(id); @@ -2936,59 +2979,60 @@ export struct EntityManager // bool empty = true; //while (1) //{ - //event_manager.swapCurrent(); - uint current_index; - if (event_manager.current_index == 0) - current_index = cast(uint) threads.length; - else - current_index = 0; - foreach (i, event; event_manager.events) + //event_manager.swapCurrent(); + uint current_index; + if (event_manager.current_index == 0) + current_index = cast(uint) threads.length; + else + current_index = 0; + foreach (i, event; event_manager.events) + { + foreach (first_block; event.first_blocks[current_index .. current_index + threads + .length]) { - foreach (first_block; event.first_blocks[current_index - .. current_index + threads.length]) + EventManager.EventBlock* block = first_block; + if (block) + has_work = true; + // { + // has_work = true; + // //empty = false; + // } + while (block) { - EventManager.EventBlock* block = first_block; - if (block)has_work = true; - // { - // has_work = true; - // //empty = false; - // } - while (block) + EventCallData call_data; + void* event_pointer = cast(void*) block + event.data_offset; + foreach (j; 0 .. block.count) { - EventCallData call_data; - void* event_pointer = cast(void*) block + event.data_offset; - foreach (j; 0 .. block.count) + call_data.event = event_pointer + EntityID.sizeof; + EntityID entity_id = *cast(EntityID*)(event_pointer); + Entity* entity = id_manager.getEntityPointer(entity_id); + if (entity) { - call_data.event = event_pointer; - EntityID entity_id = *cast(EntityID*) event_pointer; - Entity* entity = id_manager.getEntityPointer(entity_id); - if (entity) - { - call_data.block = getMetaData(entity); - call_data.id = call_data.block.entityIndex(entity); + call_data.block = getMetaData(entity); + call_data.id = call_data.block.entityIndex(entity); + call_data.entity = entity; - foreach (caller; events[i].callers) - { - if ( - call_data.block.type_info.systems[caller.system.m_id] - == false) - continue; - call_data.system_pointer = caller.system.m_system_pointer; - (cast(void function( - ref EventCallData) nothrow @nogc) caller.callback)( - call_data); - } + foreach (caller; events[i].callers) + { + if (call_data.block.type_info.systems[caller.system.m_id] == false + || !caller.system.enabled || !caller.system.willExecute) + continue; + call_data.system_pointer = caller.system.m_system_pointer; + (cast(void function(ref EventCallData) nothrow @nogc) caller + .callback)(call_data); } - if(events[i].destroy_callback)events[i].destroy_callback(event_pointer); - event_pointer += events[i].size; } - block = block.next; + if (events[i].destroy_callback) + events[i].destroy_callback(event_pointer); + event_pointer += events[i].size + EntityID.sizeof; } + block = block.next; } } - // if (empty) - // break; - // empty = true; + } + // if (empty) + // break; + // empty = true; //} return has_work; } @@ -2996,7 +3040,7 @@ export struct EntityManager private void swapData() nothrow @nogc { event_manager.swapCurrent(); - foreach(ref ThreadData thread; threads) + foreach (ref ThreadData thread; threads) { thread.swapData(); } @@ -3005,13 +3049,13 @@ export struct EntityManager export void commit() { bool has_work = true; - while(has_work) - { + while (has_work) + { swapData(); has_work = false; has_work |= updateEvents(); - + id_manager.optimize(); has_work |= updateBlocks(); has_work |= changeEntities(); @@ -3222,14 +3266,15 @@ export struct EntityManager } } - const (UpdatePass)* getPass(const (char)[] name) + const(UpdatePass)* getPass(const(char)[] name) { ushort id = getPassID(name); - if(id == ushort.max)return null; + if (id == ushort.max) + return null; return passes[id]; } - ushort getPassID(const (char)[] name) + ushort getPassID(const(char)[] name) { return passes_map.get(name, ushort.max); } @@ -3267,6 +3312,7 @@ export struct EntityManager EntitiesBlock* block; void* system_pointer; void* event; + Entity* entity; ushort id; } @@ -3357,9 +3403,9 @@ export struct EntityManager return new_info; } - EntityInfo* getNewInfoRemove(ushort id) + EntityInfo* getNewInfoRemove(ushort id) return { - if (comp_rem_info.length <= id) + /*if (comp_rem_info.length <= id) { EntityInfo*[] new_infos = Mallocator.makeArray!(EntityInfo*)( instance.components.length, &this); @@ -3371,7 +3417,7 @@ export struct EntityManager Mallocator.dispose(comp_rem_info); } comp_rem_info = new_infos; - } + }*/ if (comp_rem_info[id]) return comp_rem_info[id]; @@ -3386,8 +3432,9 @@ export struct EntityManager ids[len++] = comp; } } - if (len == components.length) - return &this; + assert(len != components.length); + //if (len == components.length) + // return &this; assert(len == components.length - 1); @@ -3455,23 +3502,14 @@ export struct EntityManager */ struct EntitiesBlock { - ///return distance (in bytes) from begin of block to data - ///TODO: probably to remove. It's used by old code if I remeber correctly. - /*export uint dataDelta() nothrow @nogc pure - { - ushort dif = EntitiesBlock.sizeof; - alignNum(dif, type_info.alignment); - return dif; - }*/ - ///return pointer to first element in block - export void* dataBegin() nothrow @nogc pure + export void* dataBegin() nothrow @nogc pure return { ushort dif = EntitiesBlock.sizeof; return cast(void*)&this + dif; } - export ushort entityIndex(Entity* entity) nothrow @nogc pure + export ushort entityIndex(const(Entity)* entity) nothrow @nogc pure { static if (EntityID.sizeof == 8) return cast(ushort)((cast(void*) entity - dataBegin()) >> 3); @@ -3593,32 +3631,32 @@ export struct EntityManager struct ThreadData { - ref Vector!EntityID entitesToRemove() @nogc nothrow + ref Vector!EntityID entitesToRemove() @nogc nothrow return { return entities_to_remove[data_index]; } - ref SimpleVector changeEntitiesList() @nogc nothrow + ref SimpleVector changeEntitiesList() @nogc nothrow return { return change_entities_list[data_index]; } - ref Vector!(EntitiesBlock*) blockToUpdate() @nogc nothrow + ref Vector!(EntitiesBlock*) blockToUpdate() @nogc nothrow return { return blocks_to_update[data_index]; } - - ref Vector!EntityID entitiesToRemovePrev() @nogc nothrow + + ref Vector!EntityID entitiesToRemovePrev() @nogc nothrow return { return entities_to_remove[1 - data_index]; } - ref SimpleVector changeEntitiesListPrev() @nogc nothrow + ref SimpleVector changeEntitiesListPrev() @nogc nothrow return { return change_entities_list[1 - data_index]; } - ref Vector!(EntitiesBlock*) blockToUpdatePrev() @nogc nothrow + ref Vector!(EntitiesBlock*) blockToUpdatePrev() @nogc nothrow return { return blocks_to_update[1 - data_index]; } diff --git a/source/bubel/ecs/package.d b/source/bubel/ecs/package.d index ee3f62b..51da325 100644 --- a/source/bubel/ecs/package.d +++ b/source/bubel/ecs/package.d @@ -7,4 +7,4 @@ public import bubel.ecs.system; import bubel.ecs.events; import bubel.ecs.id_manager; -import bubel.ecs.std; \ No newline at end of file +import bubel.ecs.std; diff --git a/source/bubel/ecs/simple_vector.d b/source/bubel/ecs/simple_vector.d index 1de026e..bb4b610 100644 --- a/source/bubel/ecs/simple_vector.d +++ b/source/bubel/ecs/simple_vector.d @@ -16,10 +16,12 @@ struct SimpleVector ///Add element to vector void add(ubyte el) nothrow @nogc { - while(used >= data.length) + while (used >= data.length) { - if(data is null)data = Mallocator.makeArray!ubyte(1024); - else data = Mallocator.expandArray(data,data.length); + if (data is null) + data = Mallocator.makeArray!ubyte(1024); + else + data = Mallocator.expandArray(data, data.length); } data[used++] = el; } @@ -27,10 +29,12 @@ struct SimpleVector ///Add array of elements to vector void add(ubyte[] el) nothrow @nogc { - while(used + el.length >= data.length) + while (used + el.length >= data.length) { - if(data is null)data = Mallocator.makeArray!ubyte(1024); - else data = Mallocator.expandArray(data,data.length); + if (data is null) + data = Mallocator.makeArray!ubyte(1024); + else + data = Mallocator.expandArray(data, data.length); } memcpy(data.ptr + used, el.ptr, el.length); used += el.length; @@ -44,23 +48,23 @@ struct SimpleVector export ref ubyte opIndex(size_t pos) nothrow @nogc { - return data[pos]; - } + return data[pos]; + } - export ubyte[] opSlice() nothrow @nogc + export ubyte[] opSlice() nothrow @nogc { - return data[0 .. used]; - } + return data[0 .. used]; + } - export ubyte[] opSlice(size_t x, size_t y) nothrow @nogc + export ubyte[] opSlice(size_t x, size_t y) nothrow @nogc { - return data[x .. y]; - } + return data[x .. y]; + } - export size_t opDollar() nothrow @nogc + export size_t opDollar() nothrow @nogc { - return used; - } + return used; + } ///set vector length to 0 void clear() nothrow @nogc @@ -70,4 +74,4 @@ struct SimpleVector ubyte[] data = null; size_t used = 0; -} \ No newline at end of file +} diff --git a/source/bubel/ecs/std.d b/source/bubel/ecs/std.d index 6658639..a7dd846 100644 --- a/source/bubel/ecs/std.d +++ b/source/bubel/ecs/std.d @@ -7,45 +7,50 @@ License: BSD 3-clause, see LICENSE file in project root folder. */ module bubel.ecs.std; -version(Emscripten)version = ECSEmscripten; +version (Emscripten) version = ECSEmscripten; import std.traits; -version(ECSEmscripten) +version (ECSEmscripten) { - extern(C) struct pthread_mutex_t - { - union - { - int[6] __i; - void[6] *__p; + extern (C) struct pthread_mutex_t + { + union + { + int[6] __i; + void[6]* __p; } - } - - extern(C) struct pthread_mutexattr_t - { - uint __attr; } - extern(C) int memcmp (const void *s1, const void *s2, size_t size); - extern(C) void exit (int status) nothrow @nogc; - extern(C) void __assert(const(char)* msg, const(char)* file, uint line) { exit(-20);} - extern(C) void free(void*) @nogc nothrow @system; - extern(C) void* malloc(size_t size) @nogc nothrow @system; - extern(C) void* realloc(void*, size_t size) @nogc nothrow @system; - extern(C) void* memcpy(return void*, scope const void*, size_t size) @nogc nothrow @system; - extern(C) void* memset(void*, int val, size_t size) @nogc nothrow @system; - extern(C) int posix_memalign(void**, size_t, size_t) @nogc nothrow @system; - extern(C) void qsort(void* base, size_t num, size_t size, int function(const void*,const void*) compar) @nogc nothrow @system; + extern (C) struct pthread_mutexattr_t + { + uint __attr; + } - extern(C) int pthread_mutex_lock(pthread_mutex_t *mutex) @nogc nothrow; - extern(C) int pthread_mutex_trylock(pthread_mutex_t *mutex) @nogc nothrow; - extern(C) int pthread_mutex_unlock(pthread_mutex_t *mutex) @nogc nothrow; - extern(C) void pthread_mutexattr_settype(pthread_mutexattr_t *attr, int type) @nogc nothrow; - extern(C) void pthread_mutexattr_destroy(pthread_mutexattr_t *attr) @nogc nothrow; - extern(C) int pthread_mutexattr_init(pthread_mutexattr_t *attr) @nogc nothrow; - extern(C) int pthread_mutex_destroy(pthread_mutex_t *mutex) @nogc nothrow; - extern(C) int pthread_mutex_init(pthread_mutex_t* mutex, const pthread_mutexattr_t* attr) @nogc nothrow; + extern (C) int memcmp(const void* s1, const void* s2, size_t size); + extern (C) void exit(int status) nothrow @nogc; + extern (C) void __assert(const(char)* msg, const(char)* file, uint line) + { + exit(-20); + } + + extern (C) void free(void*) @nogc nothrow @system; + extern (C) void* malloc(size_t size) @nogc nothrow @system; + extern (C) void* realloc(void*, size_t size) @nogc nothrow @system; + extern (C) void* memcpy(return void*, scope const void*, size_t size) @nogc nothrow @system; + extern (C) void* memset(void*, int val, size_t size) @nogc nothrow @system; + extern (C) int posix_memalign(void**, size_t, size_t) @nogc nothrow @system; + extern (C) void qsort(void* base, size_t num, size_t size, + int function(const void*, const void*) compar) @nogc nothrow @system; + + extern (C) int pthread_mutex_lock(pthread_mutex_t* mutex) @nogc nothrow; + extern (C) int pthread_mutex_trylock(pthread_mutex_t* mutex) @nogc nothrow; + extern (C) int pthread_mutex_unlock(pthread_mutex_t* mutex) @nogc nothrow; + extern (C) void pthread_mutexattr_settype(pthread_mutexattr_t* attr, int type) @nogc nothrow; + extern (C) void pthread_mutexattr_destroy(pthread_mutexattr_t* attr) @nogc nothrow; + extern (C) int pthread_mutexattr_init(pthread_mutexattr_t* attr) @nogc nothrow; + extern (C) int pthread_mutex_destroy(pthread_mutex_t* mutex) @nogc nothrow; + extern (C) int pthread_mutex_init(pthread_mutex_t* mutex, const pthread_mutexattr_t* attr) @nogc nothrow; } else @@ -55,23 +60,24 @@ else public import core.stdc.stdlib : qsort; } -version(ECSEmscripten) +version (ECSEmscripten) { } else version (Windows) { import core.sys.windows.windows; - extern(Windows) void* _aligned_malloc(size_t size,size_t alignment) @nogc nothrow @system; - extern(Windows) void _aligned_free(void* ptr) @nogc nothrow @system; - - version(LDC) + + extern (Windows) void* _aligned_malloc(size_t size, size_t alignment) @nogc nothrow @system; + extern (Windows) void _aligned_free(void* ptr) @nogc nothrow @system; + + version (LDC) { /*extern(Windows) void* __alloca(size_t size) @nogc nothrow @system; alias alloca = __alloca;*/ - extern(Windows) void ___chkstk_ms() @nogc nothrow @system; - - extern(Windows) void __chkstk() + extern (Windows) void ___chkstk_ms() @nogc nothrow @system; + + extern (Windows) void __chkstk() { ___chkstk_ms(); } @@ -80,17 +86,18 @@ else version (Windows) else version (Posix) { import core.sys.posix.pthread; - import core.sys.posix.stdlib; + import core.sys.posix.stdlib : posix_memalign; } -version(ECSEmscripten) +version (ECSEmscripten) { - private const uint max_alloca = 10000; + private const uint max_alloca = 10000; private __gshared byte[max_alloca] alloca_array; private __gshared uint alloca_pos = 0; - export extern(C) void* alloca(size_t length) @nogc nothrow + export extern (C) void* alloca(size_t length) @nogc nothrow { - if(alloca_pos + length > max_alloca)alloca_pos = 0; + if (alloca_pos + length > max_alloca) + alloca_pos = 0; void* ret = &alloca_array[alloca_pos]; alloca_pos += length; return ret; @@ -101,28 +108,44 @@ version(ECSEmscripten) return null; }*/ } -else version(D_BetterC) +else version (D_BetterC) { - private const uint max_alloca = 10000; + private const uint max_alloca = 10000; private __gshared byte[max_alloca] alloca_array; private uint alloca_pos = 0; - export extern(C) void* alloca(size_t length) @nogc nothrow + export extern (C) void* __alloca(size_t length) @nogc nothrow { - if(alloca_pos + length > max_alloca)alloca_pos = 0; + if (alloca_pos + length > max_alloca) + alloca_pos = 0; void* ret = &alloca_array[alloca_pos]; alloca_pos += length; return ret; } - version(GNU) + alias alloca = __alloca; + + version (DigitalMars) { - extern(C) void __gdc_personality_v0() + export extern (C) float* _memsetFloat(float* p, float value, size_t count) @nogc nothrow + { + float* pstart = p; + float* ptop; + + for (ptop = &p[count]; p < ptop; p++) + *p = value; + return pstart; + } + } + + version (GNU) + { + extern (C) void __gdc_personality_v0() { } } } -else +else { public import core.stdc.stdlib : alloca; } @@ -131,13 +154,13 @@ static struct Mallocator { static T[] makeArray(T)(size_t length) nothrow @nogc { - T[] ret = (cast(T*)malloc(T.sizeof * length))[0 .. length]; + T[] ret = (cast(T*) malloc(T.sizeof * length))[0 .. length]; - static if(__traits(isPOD, T)) + static if (__traits(isPOD, T)) { static immutable T init = T.init; - - foreach(i;0..ret.length) + + foreach (i; 0 .. ret.length) { memcpy(&ret[i], &init, T.sizeof); } @@ -145,7 +168,8 @@ static struct Mallocator else { static import std.conv; - foreach(i;0..ret.length) + + foreach (i; 0 .. ret.length) { std.conv.emplace(&ret[i]); } @@ -155,78 +179,94 @@ static struct Mallocator static T[] makeArray(T)(size_t length, T initializer) nothrow @nogc { - T[] ret = (cast(T*)malloc(T.sizeof * length))[0 .. length]; - foreach(ref v; ret)v = initializer; + T[] ret = (cast(T*) malloc(T.sizeof * length))[0 .. length]; + foreach (ref v; ret) + v = initializer; return ret; } static T[] expandArray(T)(T[] array, size_t length) nothrow @nogc { size_t new_length = array.length + length; - return (cast(T*)realloc(array.ptr, T.sizeof * new_length))[0 .. new_length]; + return (cast(T*) realloc(array.ptr, T.sizeof * new_length))[0 .. new_length]; } static T[] makeArray(T)(T[] array) nothrow @nogc { - T[] ret = (cast(T*)malloc(T.sizeof * array.length))[0 .. array.length];//Mallocator.makeArray!(T)(array.length); - foreach(i, ref v;ret)v = array[i]; + T[] ret = (cast(T*) malloc(T.sizeof * array.length))[0 .. array.length]; //Mallocator.makeArray!(T)(array.length); + foreach (i, ref v; ret) + v = array[i]; return ret; } - static T* make(T, Args...)(Args args) + static T* make(T, Args...)(Args args) { - T* ret = cast(T*)malloc(T.sizeof); + T* ret = cast(T*) malloc(T.sizeof); static import std.conv; - static if(__traits(isPOD, T)) + + static if (__traits(isPOD, T)) { static immutable T init = T.init; memcpy(ret, &init, T.sizeof); } - else static if(is(T == struct))std.conv.emplace(ret, args); + else static if (is(T == struct)) + std.conv.emplace(ret, args); return ret; } static void* alignAlloc(size_t length, size_t alignment) nothrow @nogc { void* ret; - version(Posix)posix_memalign(&ret, alignment, length);//ret = aligned_alloc(alignment, length); - else version(Windows)ret = _aligned_malloc(length, alignment); - else version(ECSEmscripten)posix_memalign(&ret, alignment, length);//malloc(length); - else static assert(0, "Unimplemented platform!"); + version (Posix) + posix_memalign(&ret, alignment, length); //ret = aligned_alloc(alignment, length); + else version (Windows) + ret = _aligned_malloc(length, alignment); + else version (ECSEmscripten) + posix_memalign(&ret, alignment, length); //malloc(length); + else + static assert(0, "Unimplemented platform!"); return ret; } static void dispose(T)(T object) nothrow @nogc { - static if(__traits(hasMember, T, "__xdtor"))object.__xdtor(); - else static if(__traits(hasMember, T, "__dtor"))object.__dtor(); - free(cast(void*)object); + static if (__traits(hasMember, T, "__xdtor")) + object.__xdtor(); + else static if (__traits(hasMember, T, "__dtor")) + object.__dtor(); + free(cast(void*) object); } static void alignDispose(T)(T object) { - static if(__traits(hasMember, T, "__xdtor"))object.__xdtor(); - else static if(__traits(hasMember, T, "__dtor"))object.__dtor(); - version(Posix)free(cast(void*)object); - else version(Windows)_aligned_free(cast(void*)object); - else version(ECSEmscripten)free(cast(void*)object); - else static assert(0, "Unimplemented platform!"); + static if (__traits(hasMember, T, "__xdtor")) + object.__xdtor(); + else static if (__traits(hasMember, T, "__dtor")) + object.__dtor(); + version (Posix) + free(cast(void*) object); + else version (Windows) + _aligned_free(cast(void*) object); + else version (ECSEmscripten) + free(cast(void*) object); + else + static assert(0, "Unimplemented platform!"); } } struct Mutex { - version(ECSEmscripten) + version (ECSEmscripten) { void initialize() nothrow @nogc { pthread_mutexattr_t attr = void; //pthread_mutexattr_init(&attr); - + //pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); - pthread_mutex_init(cast(pthread_mutex_t*) &m_handle, &attr); + pthread_mutex_init(cast(pthread_mutex_t*)&m_handle, &attr); //pthread_mutexattr_destroy(&attr); } @@ -257,7 +297,7 @@ struct Mutex { void initialize() nothrow @nogc { - InitializeCriticalSection(cast(CRITICAL_SECTION*) &m_handle); + InitializeCriticalSection(cast(CRITICAL_SECTION*)&m_handle); } void destroy() nothrow @nogc @@ -280,7 +320,7 @@ struct Mutex return TryEnterCriticalSection(&m_handle) != 0; } - CRITICAL_SECTION m_handle; + CRITICAL_SECTION m_handle; } else version (Posix) { @@ -289,9 +329,9 @@ struct Mutex pthread_mutexattr_t attr = void; pthread_mutexattr_init(&attr); - + pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); - pthread_mutex_init(cast(pthread_mutex_t*) &m_handle, &attr); + pthread_mutex_init(cast(pthread_mutex_t*)&m_handle, &attr); pthread_mutexattr_destroy(&attr); } @@ -318,5 +358,6 @@ struct Mutex private pthread_mutex_t m_handle; } - else static assert(0, "unsupported platform!"); -} \ No newline at end of file + else + static assert(0, "unsupported platform!"); +} diff --git a/source/bubel/ecs/vector.d b/source/bubel/ecs/vector.d index 1ec8a93..ca6cd6c 100644 --- a/source/bubel/ecs/vector.d +++ b/source/bubel/ecs/vector.d @@ -1,30 +1,36 @@ module bubel.ecs.vector; import core.bitop; + //import core.stdc.stdlib : free, malloc; import bubel.ecs.std; + //import core.stdc.string : memcpy, memset; //import std.algorithm : swap; import std.conv : emplace; import std.traits : hasMember, isCopyable, TemplateOf, Unqual; -export @nogc @safe nothrow pure size_t nextPow2(size_t num) { +export @nogc @safe nothrow pure size_t nextPow2(size_t num) +{ return 1 << bsr(num) + 1; } export __gshared size_t gVectorsCreated = 0; export __gshared size_t gVectorsDestroyed = 0; -struct Vector(T) { +struct Vector(T) +{ T[] array; size_t used; public: - export this()(T t) { + export this()(T t) + { add(t); } - export this(X)(X[] t) if (is(Unqual!X == Unqual!T)) { + export this(X)(X[] t) if (is(Unqual!X == Unqual!T)) + { add(t); } @@ -42,79 +48,101 @@ public: @disable this(this); - export ~this() { + export ~this() + { clear(); } - export void clear() { + export void clear() + { removeAll(); } - export void removeAll() { - if (array !is null) { + export void removeAll() + { + if (array !is null) + { /*foreach (ref el; array[0 .. used]) { destroy(el); }*/ //freeData(cast(void[]) array); - freeData((cast(void*)array.ptr)[0 .. array.length * T.sizeof]); + freeData((cast(void*) array.ptr)[0 .. array.length * T.sizeof]); gVectorsDestroyed++; } array = null; used = 0; } - export bool empty() const { + export bool empty() const + { return (used == 0); } - export size_t length() const { + export size_t length() const + { return used; } - export void length(size_t newLength) { - if (newLength > used) { + export void length(size_t newLength) + { + if (newLength > used) + { reserve(newLength); - foreach (ref el; array[used .. newLength]) { + foreach (ref el; array[used .. newLength]) + { emplace(&el); } - } else { - foreach (ref el; array[newLength .. used]) { + } + else + { + foreach (ref el; array[newLength .. used]) + { //destroy(el); - static if(__traits(hasMember, T, "__xdtor"))el.__xdtor(); - else static if(__traits(hasMember, T, "__dtor"))el.__dtor(); + static if (__traits(hasMember, T, "__xdtor")) + el.__xdtor(); + else static if (__traits(hasMember, T, "__dtor")) + el.__dtor(); } } used = newLength; } - export void reset() { + export void reset() + { used = 0; } - export void reserve(size_t numElements) { - if (numElements > array.length) { + export void reserve(size_t numElements) + { + if (numElements > array.length) + { extend(numElements); } } - export size_t capacity() { + export size_t capacity() + { return array.length - used; } - export void extend(size_t newNumOfElements) { + export void extend(size_t newNumOfElements) + { auto oldArray = manualExtend(array, newNumOfElements); - if (oldArray !is null) { + if (oldArray !is null) + { freeData(oldArray); } } - export @nogc void freeData(void[] data) { + export @nogc void freeData(void[] data) + { // 0x0F probably invalid value for pointers and other types memset(data.ptr, 0x0F, data.length); // Makes bugs show up xD free(data.ptr); } - export static void[] manualExtend(ref T[] array, size_t newNumOfElements = 0) { + export static void[] manualExtend(ref T[] array, size_t newNumOfElements = 0) + { if (newNumOfElements == 0) newNumOfElements = 2; if (array.length == 0) @@ -126,22 +154,26 @@ public: memcpy(cast(void*) memory, cast(void*) oldArray.ptr, oldSize); array = memory[0 .. newNumOfElements]; //return cast(void[]) oldArray; - return (cast(void*)oldArray.ptr)[0 .. oldArray.length * T.sizeof]; + return (cast(void*) oldArray.ptr)[0 .. oldArray.length * T.sizeof]; } - export Vector!T copy()() { + export Vector!T copy()() + { Vector!T duplicate; duplicate.reserve(used); duplicate ~= array[0 .. used]; return duplicate; } - export bool canAddWithoutRealloc(uint elemNum = 1) { + export bool canAddWithoutRealloc(uint elemNum = 1) + { return used + elemNum <= array.length; } - export void add()(T t) { - if (used >= array.length) { + export void add()(T t) + { + if (used >= array.length) + { extend(nextPow2(used + 1)); } emplace(&array[used], t); @@ -149,48 +181,62 @@ public: } /// Add element at given position moving others - export void add()(T t, size_t pos) { + export void add()(T t, size_t pos) + { assert(pos <= used); - if (used >= array.length) { + if (used >= array.length) + { extend(array.length * 2); } - foreach_reverse (size_t i; pos .. used) { + foreach_reverse (size_t i; pos .. used) + { //swap(array[i + 1], array[i]); - array[i+1] = array[i]; + array[i + 1] = array[i]; } emplace(&array[pos], t); used++; } - export void add(X)(X[] t) if (is(Unqual!X == Unqual!T)) { - if (used + t.length > array.length) { + export void add(X)(X[] t) if (is(Unqual!X == Unqual!T)) + { + if (used + t.length > array.length) + { extend(nextPow2(used + t.length)); } - foreach (i; 0 .. t.length) { + foreach (i; 0 .. t.length) + { emplace(&array[used + i], t[i]); } used += t.length; } - export void remove(size_t elemNum) { + export void remove(size_t elemNum) + { //destroy(array[elemNum]); - static if(__traits(hasMember, T, "__xdtor"))array[elemNum].__xdtor(); - else static if(__traits(hasMember, T, "__dtor"))array[elemNum].__dtor(); + static if (__traits(hasMember, T, "__xdtor")) + array[elemNum].__xdtor(); + else static if (__traits(hasMember, T, "__dtor")) + array[elemNum].__dtor(); //swap(array[elemNum], array[used - 1]); array[elemNum] = array[used - 1]; used--; } - export void removeStable()(size_t elemNum) { + export void removeStable()(size_t elemNum) + { used--; - foreach (i; 0 .. used) { + foreach (i; 0 .. used) + { array[i] = array[i + 1]; } } - export bool tryRemoveElement()(T elem) { - foreach (i, ref el; array[0 .. used]) { - if (el == elem) { + export bool tryRemoveElement()(T elem) + { + foreach (i, ref el; array[0 .. used]) + { + if (el == elem) + { remove(i); return true; } @@ -198,55 +244,66 @@ public: return false; } - export void removeElement()(T elem) { + export void removeElement()(T elem) + { bool ok = tryRemoveElement(elem); assert(ok, "There is no such an element in vector"); } - export ref T opIndex(size_t elemNum) const { + export ref T opIndex(size_t elemNum) const + { //debug assert(elemNum < used, "Range violation [index]"); return *cast(T*)&array.ptr[elemNum]; } - export auto opSlice() { + export auto opSlice() + { return array.ptr[0 .. used]; } - export T[] opSlice(size_t x, size_t y) { + export T[] opSlice(size_t x, size_t y) + { assert(y <= used); return array.ptr[x .. y]; } - export size_t opDollar() { + export size_t opDollar() + { return used; } - export void opAssign(X)(X[] slice) { + export void opAssign(X)(X[] slice) + { reset(); this ~= slice; } - export void opOpAssign(string op)(T obj) { + export void opOpAssign(string op)(T obj) + { //static assert(op == "~"); add(obj); } - export void opOpAssign(string op, X)(X[] obj) { + export void opOpAssign(string op, X)(X[] obj) + { //static assert(op == "~"); add(obj); } - export void opIndexAssign()(T obj, size_t elemNum) { + export void opIndexAssign()(T obj, size_t elemNum) + { assert(elemNum < used, "Range viloation"); array[elemNum] = obj; } - export void opSliceAssign()(T[] obj, size_t a, size_t b) { + export void opSliceAssign()(T[] obj, size_t a, size_t b) + { assert(b <= used && a <= b, "Range viloation"); array.ptr[a .. b] = obj; } - export bool opEquals()(auto ref const Vector!(T) r) const { + export bool opEquals()(auto ref const Vector!(T) r) const + { return used == r.used && array.ptr[0 .. used] == r.array.ptr[0 .. r.used]; } -} \ No newline at end of file +} diff --git a/tests/basic.d b/tests/basic.d index ab9acec..b8e1d2c 100644 --- a/tests/basic.d +++ b/tests/basic.d @@ -68,6 +68,11 @@ struct CUnregistered short value = 12; } +struct CFlag +{ + mixin ECS.Component; +} + struct LongAddSystem { mixin ECS.System; @@ -110,6 +115,7 @@ struct EmptySystem void beforeEveryTest() { + CUnregistered.component_id = ushort.max; gEM.initialize(0); gEM.beginRegister(); @@ -119,6 +125,7 @@ void beforeEveryTest() gEM.registerComponent!CDouble; gEM.registerComponent!CLong; gEM.registerComponent!CShort; + gEM.registerComponent!CFlag; gEM.endRegister(); } @@ -131,11 +138,12 @@ void afterEveryTest() @("AddEntity") unittest { - ushort[2] ids = [CInt.component_id, CFloat.component_id]; - EntityTemplate* tmpl_ = gEM.allocateTemplate(ids); - assert(tmpl_.info.components.length == 2); + EntityTemplate* tmpl_ = gEM.allocateTemplate([CInt.component_id, CFloat.component_id, CFlag.component_id].staticArray); + assert(tmpl_.info.components.length == 3); + assert(tmpl_.info.size == (CInt.sizeof + CFloat.sizeof + EntityID.sizeof)); assert(tmpl_.getComponent!CInt); assert(tmpl_.getComponent!CFloat); + assert(tmpl_.getComponent!CFlag); assert(!tmpl_.getComponent!CLong); assert(!tmpl_.getComponent!CUnregistered); assert(*tmpl_.getComponent!CInt == 1); @@ -154,13 +162,66 @@ unittest assert(*entity2.getComponent!CInt == 2); assert(*entity2.getComponent!CFloat == 2.0); - CInt cint = CInt(10); - CLong clong; - Entity* entity3 = gEM.addEntity(tmpl_, [cint.ref_, clong.ref_].staticArray); + //CInt cint = CInt(10); + //CLong clong; + //Entity* entity3 = gEM.addEntity(tmpl_, [cint.ref_, clong.ref_].staticArray); + Entity* entity3 = gEM.addEntity(tmpl_, [CInt(10).ref_, CLong().ref_, CFlag().ref_].staticArray); + EntityID id = entity3.id; assert(entity3.getComponent!CInt); assert(entity3.getComponent!CFloat); assert(*entity3.getComponent!CInt == 10); assert(*entity3.getComponent!CFloat == 2.0); + + gEM.addComponents(entity3.id, [CFlag().ref_,CShort(2).ref_]); + gEM.commit(); + entity3 = gEM.getEntity(id); + assert(entity3.getComponent!CInt); + assert(entity3.getComponent!CFloat); + assert(entity3.getComponent!CFlag); + assert(entity3.getComponent!CShort); + assert(*entity3.getComponent!CInt == 10); + assert(*entity3.getComponent!CFloat == 2.0); + assert(*entity3.getComponent!CShort == 2); + + gEM.removeComponents(entity3.id, [CFlag().component_id,CShort(2).component_id]); + gEM.commit(); + entity3 = gEM.getEntity(id); + assert(entity3.getComponent!CInt); + assert(entity3.getComponent!CFloat); + assert(!entity3.getComponent!CFlag); + assert(!entity3.getComponent!CShort); + assert(*entity3.getComponent!CInt == 10); + assert(*entity3.getComponent!CFloat == 2.0); + + gEM.addComponents(entity3.id, [CFlag().ref_,CShort(2).ref_]); + gEM.removeComponents(entity3.id, [CUnregistered.component_id]); + gEM.commit(); + entity3 = gEM.getEntity(id); + assert(entity3.getComponent!CInt); + assert(entity3.getComponent!CFloat); + assert(entity3.getComponent!CFlag); + assert(entity3.getComponent!CShort); + assert(*entity3.getComponent!CInt == 10); + assert(*entity3.getComponent!CFloat == 2.0); + assert(*entity3.getComponent!CShort == 2); + + gEM.beginRegister(); + + gEM.registerComponent!CUnregistered; + + gEM.endRegister(); + + gEM.addComponents(entity3.id, [CUnregistered(4).ref_]); + gEM.commit(); + entity3 = gEM.getEntity(id); + assert(entity3.getComponent!CUnregistered); + assert(*entity3.getComponent!CUnregistered == 4); + + gEM.removeComponents(entity3.id, [CUnregistered.component_id]); + gEM.commit(); + entity3 = gEM.getEntity(id); + assert(!entity3.getComponent!CUnregistered); + } //allocate templates @@ -171,32 +232,48 @@ unittest ushort[2] ids = [CInt.component_id, CFloat.component_id]; EntityTemplate* tmpl_ = gEM.allocateTemplate(ids); EntityTemplate* tmpl_d = gEM.allocateTemplate([CFloat.component_id, CInt.component_id, CFloat.component_id].staticArray); + EntityTemplate* tmpl_cp = gEM.allocateTemplate(tmpl_); assert(tmpl_d.info == tmpl_.info); + assert(tmpl_cp.info == tmpl_cp.info); assert(tmpl_.info.components.length == 2); assert(tmpl_.getComponent!CInt); assert(tmpl_.getComponent!CFloat); assert(*tmpl_.getComponent!CInt == 1); assert(*tmpl_.getComponent!CFloat == 2.0); + assert(tmpl_cp.getComponent!CFloat); + assert(tmpl_cp.getComponent!CInt); + assert(tmpl_.getComponent!CInt != tmpl_cp.getComponent!CInt); + assert(tmpl_.getComponent!CFloat != tmpl_cp.getComponent!CFloat); + assert(*tmpl_.getComponent!CInt == *tmpl_cp.getComponent!CInt); + assert(*tmpl_.getComponent!CFloat == *tmpl_cp.getComponent!CFloat); *tmpl_.getComponent!CInt = 4; *tmpl_.getComponent!CFloat = 5.0; - //allocate template from template with additional component - ushort[1] ids2 = [CDouble.component_id]; + //allocate template from template with additional components + ushort[2] ids2 = [CDouble.component_id,CFlag.component_id]; EntityTemplate* tmpl_2 = gEM.allocateTemplate(tmpl_, ids2); - assert(tmpl_2.info.components.length == 3); + assert(tmpl_2.info.components.length == 4); assert(tmpl_2.getComponent!CInt); assert(tmpl_2.getComponent!CFloat); assert(tmpl_2.getComponent!CDouble); + assert(tmpl_2.getComponent!CFlag); assert(*tmpl_2.getComponent!CInt == 4); assert(*tmpl_2.getComponent!CFloat == 5.0); assert(*tmpl_2.getComponent!CDouble == 3.0); + assert(tmpl_.info.blocksCount() == 0); + Entity* entity = gEM.addEntity(tmpl_); - gEM.addComponents(entity.id, CDouble(8.0)); + gEM.addComponents(entity.id, CFloat(100)); + gEM.addComponents(entity.id, CDouble(8.0), CFloat(100)); + + assert(tmpl_.info.blocksCount() == 1); //apply entity changes gEM.commit(); + assert(tmpl_.info.blocksCount() == 0); + //allocate template as entity copy EntityTemplate* tmpl_3 = gEM.allocateTemplate(entity.id); assert(tmpl_3.info.components.length == 3); @@ -217,18 +294,20 @@ unittest assert(*tmpl_4.getComponent!CFloat == 2.0); assert(*tmpl_4.getComponent!CDouble == 3.0); - //allocate template from template with two additional component - ushort[2] ids3 = [CDouble.component_id, CLong.component_id]; - EntityTemplate* tmpl_5 = gEM.allocateTemplate(tmpl_, ids3); - assert(tmpl_5.info.components.length == 4); + //allocate template from template with three additional component + ushort[3] ids3 = [CDouble.component_id, CLong.component_id, CShort.component_id]; + EntityTemplate* tmpl_5 = gEM.allocateTemplate(tmpl_2, ids3); + assert(tmpl_5.info.components.length == 6); assert(tmpl_5.getComponent!CInt); assert(tmpl_5.getComponent!CFloat); assert(tmpl_5.getComponent!CDouble); assert(tmpl_5.getComponent!CLong); + assert(tmpl_5.getComponent!CShort); assert(*tmpl_5.getComponent!CInt == 4); assert(*tmpl_5.getComponent!CFloat == 5.0); assert(*tmpl_5.getComponent!CDouble == 3.0); assert(*tmpl_5.getComponent!CLong == 10); + assert(*tmpl_5.getComponent!CShort == 12); //allocate template from template without one component ushort[1] rem_ids = [CFloat.component_id]; @@ -239,7 +318,7 @@ unittest //allocate template from template without one component and two additional EntityTemplate* tmpl_7 = gEM.allocateTemplate(tmpl_, ids3, rem_ids); - assert(tmpl_7.info.components.length == 3); + assert(tmpl_7.info.components.length == 4); assert(tmpl_7.getComponent!CInt); assert(tmpl_7.getComponent!CDouble); assert(tmpl_7.getComponent!CLong); @@ -496,6 +575,10 @@ unittest gEM.endRegister(); + assert(gEM.getPass("custom")); + assert(!gEM.getPass("custommm")); + + LongAddSystem* system = gEM.getSystem!LongAddSystem; assert(system !is null); assert(system.updates_count == 0); @@ -1131,9 +1214,9 @@ unittest assert(*entity2.getComponent!CShort == 12); gEM.sendEvent(id,ETest()); - gEM.sendEvent(id,ETest2(id,10)); + gEM.sendEvent(id,ETest2(10)); gEM.sendEvent(id2,ETest()); - gEM.sendEvent(id2,ETest2(id2,12)); + gEM.sendEvent(id2,ETest2(12)); gEM.commit(); assert(ETest2.destory == 2); @@ -1144,7 +1227,7 @@ unittest gEM.addComponents(id, CInt(2), CShort(1)); gEM.sendEvent(id,ETest()); - gEM.sendEvent(id,ETest2(id,2)); + gEM.sendEvent(id,ETest2(2)); gEM.commit(); assert(ETest2.destory == 3); @@ -1157,7 +1240,7 @@ unittest foreach(i;0..10000) { gEM.sendEvent(id,ETest()); - gEM.sendEvent(id,ETest2(id,4)); + gEM.sendEvent(id,ETest2(4)); result += 16; result += 8; } @@ -1321,22 +1404,6 @@ unittest } } - void func1(TestSystem.EntitiesData entities) - { - foreach(i;0 .. entities.length) - { - entities.int_[i] += entities.int_[i] / 2; - } - } - - void func2(TestSystem.EntitiesData entities) - { - foreach(i;0 .. entities.length) - { - entities.int_[i] += 8; - } - } - gEM.beginRegister(); gEM.registerSystem!TestSystem(0); @@ -1462,22 +1529,6 @@ unittest } } - void func1(TestSystem.EntitiesData entities) - { - foreach(i;0 .. entities.length) - { - entities.int_[i] += entities.int_[i] / 2; - } - } - - void func2(TestSystem.EntitiesData entities) - { - foreach(i;0 .. entities.length) - { - entities.int_[i] += 8; - } - } - gEM.beginRegister(); gEM.registerDependency(TestDependency); diff --git a/tests/bugs.d b/tests/bugs.d new file mode 100644 index 0000000..49e3b12 --- /dev/null +++ b/tests/bugs.d @@ -0,0 +1,142 @@ +module tests.bugs; + +import tests.basic; + +import bubel.ecs.core; +import bubel.ecs.manager; +import bubel.ecs.system; +import bubel.ecs.attributes; + +version(GNU) +{ + pragma(inline, true) T[n] staticArray(T, size_t n)(auto ref T[n] a) + { + return a; + } +} +else import std.array : staticArray; + +@("Bug0001") +unittest +{ + struct Event1 + { + mixin ECS.Event; + + EntityID id; + } + + struct Event2 + { + mixin ECS.Event; + } + + struct System1 + { + mixin ECS.System; + + struct EntitiesData + { + CInt[] int_; + } + + EntityTemplate* tmpl; + EntityID id; + + void onCreate() + { + tmpl = gEM.allocateTemplate([CInt.component_id, CLong.component_id].staticArray); + } + + void onDestroy() + { + gEM.freeTemplate(tmpl); + } + + void handleEvent(Entity* entity, Event1 event) + { + gEM.removeEntity(event.id); + gEM.sendEvent(entity.id,Event2()); + } + + void handleEvent(Entity* entity, Event2 event) + { + id = gEM.addEntity(tmpl,[CInt(2).ref_, CLong(8).ref_].staticArray).id; + } + } + + struct System2 + { + mixin ECS.System; + + struct EntitiesData + { + Entity[] entity; + } + + ///check if every entity was removed correctly + void onUpdate(EntitiesData data) + { + assert(0); + } + } + + struct System3 + { + mixin ECS.System; + + struct EntitiesData + { + uint length; + Entity[] entity; + } + + ///remove every entity + void onUpdate(EntitiesData data) + { + foreach(i;0..data.length)gEM.removeEntity(data.entity[i].id); + } + } + + gEM.initialize(0); + + gEM.beginRegister(); + + gEM.registerComponent!CInt; + gEM.registerComponent!CFloat; + gEM.registerComponent!CDouble; + gEM.registerComponent!CLong; + gEM.registerComponent!CShort; + gEM.registerComponent!CFlag; + + gEM.registerEvent!Event1; + gEM.registerEvent!Event2; + + gEM.registerSystem!System1(0); + gEM.registerSystem!System2(-200); + gEM.registerSystem!System3(-200); + + gEM.endRegister(); + + EntityTemplate* tmpl = gEM.allocateTemplate([CInt.component_id, CLong.component_id].staticArray); + EntityID id = gEM.addEntity(tmpl,[CLong(10).ref_, CInt(6).ref_].staticArray).id; + EntityID id2 = gEM.addEntity(tmpl,[CInt(4).ref_].staticArray).id; + gEM.freeTemplate(tmpl); + gEM.commit(); + + gEM.sendEvent(id2, Event1(id)); + + gEM.getSystem(System2.system_id).disable(); + + gEM.begin(); + gEM.update(); + gEM.end(); + + gEM.getSystem(System2.system_id).enable(); + + gEM.begin(); + gEM.update(); + gEM.end(); + + gEM.destroy(); +} \ No newline at end of file diff --git a/tests/runner.d b/tests/runner.d index f299664..b14dafe 100644 --- a/tests/runner.d +++ b/tests/runner.d @@ -210,7 +210,7 @@ struct TestRunner(Args...) else test.name = attributes[0]; - static if (__traits(hasMember, module_, "beforeEveryTest")) + static if (__traits(hasMember, module_, "beforeEveryTest") && __traits(compiles, module_.beforeEveryTest())) module_.beforeEveryTest(); if(before)before(); @@ -256,7 +256,7 @@ struct TestRunner(Args...) else suite.failed++; suite.tests ~= test; - static if (__traits(hasMember, module_, "afterEveryTest")) + static if (__traits(hasMember, module_, "afterEveryTest") && __traits(compiles, module_.beforeEveryTest())) module_.afterEveryTest(); } passed += suite.passed; @@ -420,7 +420,7 @@ extern (C) int main(int argc, char** args) } } - TestRunner!(tests.id_manager, tests.vector, tests.basic, tests.perf, tests.access_perf) runner; + TestRunner!(tests.id_manager, tests.vector, tests.basic, tests.perf, tests.access_perf, tests.bugs) runner; runner.runTests(include[], exclude[]); From 2f827a94db33c34445044a11056580f3c85563a5 Mon Sep 17 00:00:00 2001 From: Mergul Date: Wed, 27 May 2020 18:22:55 +0200 Subject: [PATCH 145/217] Fixed betterC compilation --- tests/basic.d | 12 ++++++------ tests/bugs.d | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/tests/basic.d b/tests/basic.d index b8e1d2c..aefdc7e 100644 --- a/tests/basic.d +++ b/tests/basic.d @@ -172,7 +172,7 @@ unittest assert(*entity3.getComponent!CInt == 10); assert(*entity3.getComponent!CFloat == 2.0); - gEM.addComponents(entity3.id, [CFlag().ref_,CShort(2).ref_]); + gEM.addComponents(entity3.id, [CFlag().ref_,CShort(2).ref_].staticArray); gEM.commit(); entity3 = gEM.getEntity(id); assert(entity3.getComponent!CInt); @@ -183,7 +183,7 @@ unittest assert(*entity3.getComponent!CFloat == 2.0); assert(*entity3.getComponent!CShort == 2); - gEM.removeComponents(entity3.id, [CFlag().component_id,CShort(2).component_id]); + gEM.removeComponents(entity3.id, [CFlag().component_id,CShort(2).component_id].staticArray); gEM.commit(); entity3 = gEM.getEntity(id); assert(entity3.getComponent!CInt); @@ -193,8 +193,8 @@ unittest assert(*entity3.getComponent!CInt == 10); assert(*entity3.getComponent!CFloat == 2.0); - gEM.addComponents(entity3.id, [CFlag().ref_,CShort(2).ref_]); - gEM.removeComponents(entity3.id, [CUnregistered.component_id]); + gEM.addComponents(entity3.id, [CFlag().ref_,CShort(2).ref_].staticArray); + gEM.removeComponents(entity3.id, [CUnregistered.component_id].staticArray); gEM.commit(); entity3 = gEM.getEntity(id); assert(entity3.getComponent!CInt); @@ -211,13 +211,13 @@ unittest gEM.endRegister(); - gEM.addComponents(entity3.id, [CUnregistered(4).ref_]); + gEM.addComponents(entity3.id, [CUnregistered(4).ref_].staticArray); gEM.commit(); entity3 = gEM.getEntity(id); assert(entity3.getComponent!CUnregistered); assert(*entity3.getComponent!CUnregistered == 4); - gEM.removeComponents(entity3.id, [CUnregistered.component_id]); + gEM.removeComponents(entity3.id, [CUnregistered.component_id].staticArray); gEM.commit(); entity3 = gEM.getEntity(id); assert(!entity3.getComponent!CUnregistered); diff --git a/tests/bugs.d b/tests/bugs.d index 49e3b12..4c4153a 100644 --- a/tests/bugs.d +++ b/tests/bugs.d @@ -61,7 +61,7 @@ unittest void handleEvent(Entity* entity, Event2 event) { - id = gEM.addEntity(tmpl,[CInt(2).ref_, CLong(8).ref_].staticArray).id; + id = gEM.addEntity(tmpl).id; } } From f964d7bf85e4dafd15b63d85cb6a1812ca243956 Mon Sep 17 00:00:00 2001 From: Mergul Date: Wed, 27 May 2020 19:46:11 +0200 Subject: [PATCH 146/217] Added more tests -added Vector test -added HashMap test -added EntityMeta test -added default hashing function to hashmap --- source/bubel/ecs/hash_map.d | 13 ++++++++- source/bubel/ecs/vector.d | 4 +-- tests/basic.d | 22 +++++++++++++-- tests/map.d | 53 +++++++++++++++++++++++++++++++++++++ tests/runner.d | 2 +- tests/vector.d | 46 +++++++++++++++++++++++++++++++- 6 files changed, 133 insertions(+), 7 deletions(-) create mode 100644 tests/map.d diff --git a/source/bubel/ecs/hash_map.d b/source/bubel/ecs/hash_map.d index 6ae6a79..764374c 100755 --- a/source/bubel/ecs/hash_map.d +++ b/source/bubel/ecs/hash_map.d @@ -19,10 +19,21 @@ export ulong defaultHashFunc(T)(auto ref T t) nothrow @nogc } else { - return 0; //hashInt(t.hashOf); // hashOf is not giving proper distribution between H1 and H2 hash parts + static if(isArray!T)return hashInt(hash((cast(byte*)t.ptr)[0 .. t.length * ForeachType!(T).sizeof])); + else return hashInt(hash((cast(byte*)&t)[0 .. T.sizeof])); //hashInt(t.hashOf); // hashOf is not giving proper distribution between H1 and H2 hash parts } } +ulong hash(byte[] array) nothrow @nogc +{ + ulong hash = 0; + + foreach(c;array) + hash = c + (hash << 6) + (hash << 16) - hash; + + return hash; +} + // Can turn bad hash function to good one export ulong hashInt(ulong x) nothrow @nogc @safe { diff --git a/source/bubel/ecs/vector.d b/source/bubel/ecs/vector.d index ca6cd6c..019673b 100644 --- a/source/bubel/ecs/vector.d +++ b/source/bubel/ecs/vector.d @@ -165,10 +165,10 @@ public: return duplicate; } - export bool canAddWithoutRealloc(uint elemNum = 1) + /*export bool canAddWithoutRealloc(uint elemNum = 1) { return used + elemNum <= array.length; - } + }*/ export void add()(T t) { diff --git a/tests/basic.d b/tests/basic.d index aefdc7e..5046dff 100644 --- a/tests/basic.d +++ b/tests/basic.d @@ -135,6 +135,24 @@ void afterEveryTest() gEM.destroy(); } +@("EntityMeta") +unittest +{ + EntityTemplate* tmpl_ = gEM.allocateTemplate([CInt.component_id, CFloat.component_id, CFlag.component_id].staticArray); + Entity* entity = gEM.addEntity(tmpl_); + EntityMeta meta = entity.getMeta(); + assert(meta.hasComponent(CInt.component_id)); + assert(meta.getComponent!CInt); + assert(meta.hasComponent(CFloat.component_id)); + assert(meta.getComponent!CFloat); + assert(!meta.getComponent!CLong); + assert(!meta.hasComponent(CLong.component_id)); + assert(!meta.getComponent!CUnregistered); + assert(!meta.hasComponent(CUnregistered.component_id)); + assert(*meta.getComponent!CInt == 1); + assert(*meta.getComponent!CFloat == 2.0); +} + @("AddEntity") unittest { @@ -167,8 +185,8 @@ unittest //Entity* entity3 = gEM.addEntity(tmpl_, [cint.ref_, clong.ref_].staticArray); Entity* entity3 = gEM.addEntity(tmpl_, [CInt(10).ref_, CLong().ref_, CFlag().ref_].staticArray); EntityID id = entity3.id; - assert(entity3.getComponent!CInt); - assert(entity3.getComponent!CFloat); + assert(entity3.hasComponent(CInt.component_id)); + assert(entity3.hasComponent(CFloat.component_id)); assert(*entity3.getComponent!CInt == 10); assert(*entity3.getComponent!CFloat == 2.0); diff --git a/tests/map.d b/tests/map.d new file mode 100644 index 0000000..a82985b --- /dev/null +++ b/tests/map.d @@ -0,0 +1,53 @@ +module tests.map; + +import bubel.ecs.hash_map; + +version(GNU) +{ + pragma(inline, true) T[n] staticArray(T, size_t n)(auto ref T[n] a) + { + return a; + } +} +else import std.array : staticArray; + +@("HashMap") +unittest +{ + HashMap!(string, int) map; + + assert(map.length == 0); + map.add("asd",1); + assert(map.length == 1); + map.clear(); + assert(map.length == 0); + map.add("asd",1); + assert(map.length == 1); + map.reset(); + assert(map.length == 0); + + map.add("asd",1); + string asd = "asd"; + assert(map.isIn("asd")); + assert(map.isIn(asd)); + assert(!map.isIn("asdf")); + map.tryRemove("asdf"); + map.tryRemove("asd"); + assert(map.length == 0); + map.add("asdf",1); + map.add("asd",2); + assert(map["asd"] == 2); + assert(map["asdf"] == 1); + assert(map.length == 2); + map.tryRemove("asdf"); + assert(map.length == 1); + map.remove("asd"); + assert(map.length == 0); + + map.add("asd",1); + map.add("asdwwghe",6); + foreach(k,v;&map.byKeyValue) + { + assert(map[k] == v); + } +} \ No newline at end of file diff --git a/tests/runner.d b/tests/runner.d index b14dafe..7e3dd07 100644 --- a/tests/runner.d +++ b/tests/runner.d @@ -420,7 +420,7 @@ extern (C) int main(int argc, char** args) } } - TestRunner!(tests.id_manager, tests.vector, tests.basic, tests.perf, tests.access_perf, tests.bugs) runner; + TestRunner!(tests.id_manager, tests.vector, tests.basic, tests.perf, tests.access_perf, tests.bugs, tests.map) runner; runner.runTests(include[], exclude[]); diff --git a/tests/vector.d b/tests/vector.d index d733f0f..1756518 100644 --- a/tests/vector.d +++ b/tests/vector.d @@ -1,7 +1,16 @@ module tests.vector; import bubel.ecs.simple_vector; -//import bubel.ecs.vector; +import bubel.ecs.vector; + +version(GNU) +{ + pragma(inline, true) T[n] staticArray(T, size_t n)(auto ref T[n] a) + { + return a; + } +} +else import std.array : staticArray; @("simple-vector") unittest @@ -33,3 +42,38 @@ unittest assert(vector2[1023] == 'a'); assert(vector2[1024] == 'b'); } + +@("Vector") +unittest +{ + struct G + { + int a; + } + + Vector!G vector; + assert(vector.empty()); + vector.add(G(1)); + assert(!vector.empty()); + vector.clear(); + assert(vector.empty()); + vector.add(G(1)); + assert(!vector.empty()); + vector.reset(); + assert(vector.empty()); + + vector.add(G(1)); + vector.add([G(2),G(5)].staticArray); + assert(vector.length == 3); + assert(vector.capacity == 1); + + Vector!G vector2; + vector2.add([G(1),G(2),G(5)].staticArray); + assert(vector == vector2); + vector2.remove(1); + assert(vector != vector2); + assert(vector2.length == 2); + assert(vector2[1] == G(5)); + vector2.add(G(2),1); + assert(vector == vector2); +} From 3719cdaee0f28a610ef59078f775b3c7f3951cb8 Mon Sep 17 00:00:00 2001 From: Mergul Date: Thu, 28 May 2020 09:39:17 +0200 Subject: [PATCH 147/217] Some small fixes --- source/bubel/ecs/id_manager.d | 1 + source/bubel/ecs/manager.d | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/source/bubel/ecs/id_manager.d b/source/bubel/ecs/id_manager.d index 084a947..aaeef30 100644 --- a/source/bubel/ecs/id_manager.d +++ b/source/bubel/ecs/id_manager.d @@ -56,6 +56,7 @@ struct IDManager */ void releaseID(EntityID id) nothrow @nogc { + optimize(); Data* data = &m_ids_array[id.id]; if (data.counter != id.counter) return; diff --git a/source/bubel/ecs/manager.d b/source/bubel/ecs/manager.d index cf3712d..a8954e0 100644 --- a/source/bubel/ecs/manager.d +++ b/source/bubel/ecs/manager.d @@ -2923,6 +2923,7 @@ export struct EntityManager private void updateBlock(EntitiesBlock* block) @nogc nothrow { + if(block.added_count == 0)return; EntityInfo* info = block.type_info; ushort entities_count = block.entities_count; block.entities_count += block.added_count; @@ -3056,7 +3057,7 @@ export struct EntityManager has_work = false; has_work |= updateEvents(); - id_manager.optimize(); + //id_manager.optimize(); has_work |= updateBlocks(); has_work |= changeEntities(); has_work |= removeEntities(); From 7a0ddf7494b94e26b828a77e18dd115a85c6efb4 Mon Sep 17 00:00:00 2001 From: Mergul Date: Thu, 28 May 2020 15:53:05 +0200 Subject: [PATCH 148/217] Bugfix update -fixed critical bug with adding entities -fixed small bug with adding entity with replacement components which entity hasn't -added multiple asserts to faster bug detection in future --- source/bubel/ecs/manager.d | 136 +++++++++++++++++++++++++------------ 1 file changed, 93 insertions(+), 43 deletions(-) diff --git a/source/bubel/ecs/manager.d b/source/bubel/ecs/manager.d index a8954e0..0982531 100644 --- a/source/bubel/ecs/manager.d +++ b/source/bubel/ecs/manager.d @@ -2154,6 +2154,8 @@ export struct EntityManager return;*/ EntitiesBlock* new_block = findBlockWithFreeSpace(new_info); + updateEntityInfoBlocks(new_info); + assert(new_block.added_count == 0); void* start = new_block.dataBegin() + new_block.entities_count * EntityID.sizeof; @@ -2183,6 +2185,10 @@ export struct EntityManager cast(void*) block + info.deltas[comp] + ind * comp_size, comp_size); } + new_block.entities_count++; + if (new_block != new_info.update_block) + new_info.update_block = new_block; + if (new_info.add_listeners) { foreach (listener; new_info.add_listeners) @@ -2190,7 +2196,7 @@ export struct EntityManager if (!info.systems[listener]) { callAddEntityListener(&systems[listener], new_info, new_block, - new_block.entities_count, new_block.entities_count + 1); + new_block.entities_count - 1, new_block.entities_count); } } } @@ -2202,13 +2208,11 @@ export struct EntityManager if (info.systems[listener]) { callChangeEntityListener(&systems[listener], new_info, new_block, - new_block.entities_count, new_block.entities_count + 1, del_ids); + new_block.entities_count - 1, new_block.entities_count, del_ids); } } } - new_block.entities_count++; - removeEntityNoID(entity, block); } @@ -2291,12 +2295,14 @@ export struct EntityManager //EntityInfo* new_info = getEntityInfo(ids[0 .. len]); EntitiesBlock* new_block = findBlockWithFreeSpace(new_info); + updateEntityInfoBlocks(new_info); + assert(new_block.added_count == 0); void* start = new_block.dataBegin() + new_block.entities_count * EntityID.sizeof; Entity* new_entity = cast(Entity*) start; new_entity.id = entity.id; - id_manager.update(*new_entity); //new_entity.updateID(); + id_manager.update(*new_entity); uint j = 0; uint k = 0; @@ -2342,6 +2348,10 @@ export struct EntityManager } } + new_block.entities_count++; + if (new_block != new_info.update_block) + new_info.update_block = new_block; + if (new_info.add_listeners) { foreach (listener; new_info.add_listeners) @@ -2349,7 +2359,7 @@ export struct EntityManager if (!info.systems[listener]) { callAddEntityListener(&systems[listener], new_info, new_block, - new_block.entities_count, new_block.entities_count + 1); + new_block.entities_count - 1, new_block.entities_count); } } } @@ -2361,12 +2371,11 @@ export struct EntityManager if (info.systems[listener]) { callChangeEntityListener(&systems[listener], new_info, new_block, - new_block.entities_count, new_block.entities_count + 1, new_ids); + new_block.entities_count - 1, new_block.entities_count, new_ids); } } } - new_block.entities_count++; removeEntityNoID(entity, block); } @@ -2487,14 +2496,12 @@ export struct EntityManager } } - if (new_index == 1) - threads[threadID].blockToUpdate.add(new_block); + if (new_index == 1 && info.update_block == block) + threads[threadID].infosToUpdate.add(info); Entity* new_entity = cast(Entity*) start; - //add_mutex.lock_nothrow(); new_entity.id = id_manager.getNewID(); - //add_mutex.unlock_nothrow(); - id_manager.update(*new_entity); //new_entity.updateID(); + id_manager.update(*new_entity); return new_entity; } @@ -2538,12 +2545,10 @@ export struct EntityManager } if (index == 1) - threads[threadID].blockToUpdate.add(block); + threads[threadID].infosToUpdate.add(block); Entity* entity = cast(Entity*) start; - //add_mutex.lock_nothrow(); entity.id = id_manager.getNewID(); - //add_mutex.unlock_nothrow(); id_manager.update(*entity); //entity.updateID(); return entity;*/ @@ -2589,7 +2594,7 @@ export struct EntityManager if (comp.component_id < info.deltas.length) { ushort delta = info.deltas[comp.component_id]; - if (delta != ushort.max) + if (delta != 0) { uint size = components[comp.component_id].size; if (size != 0) @@ -2607,14 +2612,12 @@ export struct EntityManager } } - if (index == 1) - threads[threadID].blockToUpdate.add(block); + if (index == 1 && info.update_block == block) + threads[threadID].infosToUpdate.add(info); Entity* entity = cast(Entity*) start; - //add_mutex.lock_nothrow(); entity.id = id_manager.getNewID(); - //add_mutex.unlock_nothrow(); - id_manager.update(*entity); //entity.updateID(); + id_manager.update(*entity); return entity; } @@ -2633,6 +2636,7 @@ export struct EntityManager block.id = 0; info.first_block = block; info.last_block = block; + info.update_block = block; } else if (block.entities_count >= info.max_entities) { @@ -2643,6 +2647,12 @@ export struct EntityManager new_block.id = cast(ushort)(block.id + 1); block = new_block; info.last_block = block; + ///make sure that update_block point to unfilled block + if (info.update_block.entities_count == info.max_entities) + { + assert(!info.update_block.added_count); + info.update_block = block; + } } return block; } @@ -2668,8 +2678,9 @@ export struct EntityManager block.id = 0; info.first_block = block; info.last_block = block; + info.update_block = block; } - else if (block.entities_count + block.added_count > info.max_entities) + else if (block.entities_count + block.added_count >= info.max_entities) { EntitiesBlock* last_block = info.last_block; @@ -2687,6 +2698,12 @@ export struct EntityManager new_block.id = cast(ushort)(block.id + 1); block = new_block; info.last_block = block; + ///make sure that update_block point to unfilled block + if (info.update_block.entities_count == info.max_entities) + { + assert(!info.update_block.added_count); + info.update_block = block; + } } return block; } @@ -2730,8 +2747,10 @@ export struct EntityManager { EntityInfo* info = block.type_info; - if (info.last_block.added_count) - updateBlock(info.last_block); + updateEntityInfoBlocks(info); + + assert(info.last_block.added_count == 0); + assert(info.last_block.entities_count > 0); info.last_block.entities_count--; @@ -2764,12 +2783,13 @@ export struct EntityManager block = info.last_block; entity.id = *cast(EntityID*)(block.dataBegin() + block.entities_count * EntityID.sizeof); - id_manager.update(*entity); //entity.updateID(); + id_manager.update(*entity); } block = info.last_block; if (block.entities_count == 0) { + assert(info.update_block is block); info.last_block = block.prev_block; if (info.first_block is block) { @@ -2778,7 +2798,9 @@ export struct EntityManager if (block.prev_block) { block.prev_block.next_block = null; - block.prev_block.added_count = 0; + info.update_block = block.prev_block; + assert(block.prev_block.added_count == 0); + //block.prev_block.added_count.atomicStore(cast(ushort)0); } allocator.freeBlock(block); } @@ -2852,7 +2874,7 @@ export struct EntityManager } } - private void callAddEntityListener(System* system, EntityInfo* info, + private static void callAddEntityListener(System* system, EntityInfo* info, EntitiesBlock* block, int begin, int end) @nogc nothrow { ListenerCallData data; @@ -2873,8 +2895,8 @@ export struct EntityManager } } - private void callRemoveEntityListener(System* system, EntityInfo* info, - EntitiesBlock* block, int begin, int end) @nogc nothrow + private static void callRemoveEntityListener(System* system, + EntityInfo* info, EntitiesBlock* block, int begin, int end) @nogc nothrow { ListenerCallData data; data.system = system; @@ -2921,9 +2943,34 @@ export struct EntityManager (cast(void function(ref ListenerCallData) nothrow @nogc) system.m_change_entity)(data); } + private void updateEntityInfoBlocks(EntityInfo* info) nothrow @nogc + { + while (info.last_block.added_count) + { + EntitiesBlock* block = info.update_block; + assert(block !is null); + if (block.entities_count == info.max_entities) + { + assert(!block.added_count); + block = block.next_block; + } + assert(!block.prev_block || !block.prev_block.added_count); + info.update_block = info.last_block; + + while (block) + { + assert(block.added_count.atomicLoad() > 0); + updateBlock(block); + block = block.next_block; + } + } + assert(info.last_block is info.update_block); + } + private void updateBlock(EntitiesBlock* block) @nogc nothrow { - if(block.added_count == 0)return; + //if(block.added_count == 0)return; + assert(block.added_count != 0); EntityInfo* info = block.type_info; ushort entities_count = block.entities_count; block.entities_count += block.added_count; @@ -2942,17 +2989,15 @@ export struct EntityManager private bool updateBlocks() { bool has_work = false; - //foreach (ref ThreadData thread; threads)thread.swapToUpdate(); foreach (ref ThreadData thread; threads) { - //thread.swapToUpdate(); - if (thread.blockToUpdatePrev.length) + if (thread.infosToUpdatePrev.length) has_work = true; - foreach (block; thread.blockToUpdatePrev) + foreach (info; thread.infosToUpdatePrev) { - updateBlock(block); + updateEntityInfoBlocks(info); } - thread.blockToUpdatePrev.clear(); + thread.infosToUpdatePrev.clear(); } return has_work; } @@ -3055,6 +3100,9 @@ export struct EntityManager swapData(); has_work = false; + // has_work |= updateBlocks(); + // has_work |= changeEntities(); + // has_work |= removeEntities(); has_work |= updateEvents(); //id_manager.optimize(); @@ -3477,7 +3525,7 @@ export struct EntityManager EntityInfo*[] comp_rem_info; ///alignment of whole entity - ushort alignment; //unused in linear-layout + ushort alignment; //unused in linear-layout TODO: to remove ///size of entity (with alignment respect) ushort size; ///max number of entities in block @@ -3496,6 +3544,8 @@ export struct EntityManager EntitiesBlock* first_block; ///pointer to last block EntitiesBlock* last_block; + ///pointer to last updated block + EntitiesBlock* update_block; } /************************************************************************************************************************ @@ -3642,9 +3692,9 @@ export struct EntityManager return change_entities_list[data_index]; } - ref Vector!(EntitiesBlock*) blockToUpdate() @nogc nothrow return + ref Vector!(EntityInfo*) infosToUpdate() @nogc nothrow return { - return blocks_to_update[data_index]; + return infos_to_update[data_index]; } ref Vector!EntityID entitiesToRemovePrev() @nogc nothrow return @@ -3657,9 +3707,9 @@ export struct EntityManager return change_entities_list[1 - data_index]; } - ref Vector!(EntitiesBlock*) blockToUpdatePrev() @nogc nothrow return + ref Vector!(EntityInfo*) infosToUpdatePrev() @nogc nothrow return { - return blocks_to_update[1 - data_index]; + return infos_to_update[1 - data_index]; } private: @@ -3671,7 +3721,7 @@ export struct EntityManager Vector!EntityID[2] entities_to_remove; SimpleVector[2] change_entities_list; - Vector!(EntitiesBlock*)[2] blocks_to_update; + Vector!(EntityInfo*)[2] infos_to_update; ubyte data_index = 0; } From 9af1cee60b3ce3bf07f3e06876749de3257d6224 Mon Sep 17 00:00:00 2001 From: Mergul Date: Thu, 28 May 2020 16:11:27 +0200 Subject: [PATCH 149/217] SpaceShip demo update -added wave shooted upon death of boss tower -cleanup code a little bit -moved to new entityAdding method -fixed bug with changeing demos --- demos/source/app.d | 9 +- demos/source/demos/chipmunk2d.d | 19 - demos/source/demos/events.d | 19 - demos/source/demos/flag_component.d | 19 - demos/source/demos/simple.d | 2 +- demos/source/demos/snake.d | 47 +-- demos/source/demos/space_invaders.d | 549 +++++++++++++++++----------- demos/source/gui/manager.d | 1 + 8 files changed, 368 insertions(+), 297 deletions(-) delete mode 100644 demos/source/demos/chipmunk2d.d delete mode 100644 demos/source/demos/events.d delete mode 100644 demos/source/demos/flag_component.d diff --git a/demos/source/app.d b/demos/source/app.d index 9017f8d..ede93b5 100644 --- a/demos/source/app.d +++ b/demos/source/app.d @@ -96,6 +96,7 @@ struct Launcher void switchDemo(void function() start, bool function() loop, void function() end, void function(SDL_Event*) event, void function(vec2, Tool, int) tool, const (char)* tips) { gui_manager.clear(); + //launcher.ent if(this.end)this.end(); @@ -262,7 +263,7 @@ void mainLoop(void* arg) if(launcher.tool && launcher.tool_repeat != 0 && launcher.mouse.left && !igIsWindowHovered(ImGuiHoveredFlags_AnyWindow) && !igIsWindowFocused(ImGuiFocusedFlags_AnyWindow)) { float range = 500.0 / cast(float)launcher.tool_repeat; - launcher.repeat_time += launcher.delta_time * 100; + launcher.repeat_time += launcher.delta_time; while(launcher.repeat_time > range) { launcher.repeat_time -= range; @@ -463,7 +464,7 @@ void mainLoop(void* arg) if(launcher.show_demo_wnd) { igSetNextWindowPos(ImVec2(launcher.window_size.x - 260, 30), ImGuiCond_Once, ImVec2(0,0)); - igSetNextWindowSize(ImVec2(250, 250), ImGuiCond_Once); + igSetNextWindowSize(ImVec2(250, 500), ImGuiCond_Once); if(igBegin("Demo",&launcher.show_demo_wnd,0)) { ImDrawList* draw_list = igGetWindowDrawList(); @@ -745,8 +746,8 @@ int main(int argc, char** argv) { import demos.simple; import demos.space_invaders; - launcher.switchDemo(&spaceInvadersStart,&spaceInvadersLoop,&spaceInvadersEnd,&spaceInvadersEvent,&spaceInvadersTool,SpaceInvaders.tips); - // launcher.switchDemo(&simpleStart,&simpleLoop,&simpleEnd,&simpleEvent,&simpleTool,Simple.tips); + // launcher.switchDemo(&spaceInvadersStart,&spaceInvadersLoop,&spaceInvadersEnd,&spaceInvadersEvent,&spaceInvadersTool,SpaceInvaders.tips); + launcher.switchDemo(&simpleStart,&simpleLoop,&simpleEnd,&simpleEvent,&simpleTool,Simple.tips); } int key_num; diff --git a/demos/source/demos/chipmunk2d.d b/demos/source/demos/chipmunk2d.d deleted file mode 100644 index 96e5fa6..0000000 --- a/demos/source/demos/chipmunk2d.d +++ /dev/null @@ -1,19 +0,0 @@ -module demos.chipmunk2d; - -import app; - -import bindbc.sdl; - -import cimgui.cimgui; - -import bubel.ecs.attributes; -import bubel.ecs.core; -import bubel.ecs.entity; -import bubel.ecs.manager; -import bubel.ecs.std; - -import ecs_utils.gfx.texture; -import ecs_utils.math.vector; -import ecs_utils.utils; - -extern(C): \ No newline at end of file diff --git a/demos/source/demos/events.d b/demos/source/demos/events.d deleted file mode 100644 index 6215160..0000000 --- a/demos/source/demos/events.d +++ /dev/null @@ -1,19 +0,0 @@ -module demos.events; - -import app; - -import bindbc.sdl; - -import cimgui.cimgui; - -import bubel.ecs.attributes; -import bubel.ecs.core; -import bubel.ecs.entity; -import bubel.ecs.manager; -import bubel.ecs.std; - -import ecs_utils.gfx.texture; -import ecs_utils.math.vector; -import ecs_utils.utils; - -extern(C): \ No newline at end of file diff --git a/demos/source/demos/flag_component.d b/demos/source/demos/flag_component.d deleted file mode 100644 index 392164e..0000000 --- a/demos/source/demos/flag_component.d +++ /dev/null @@ -1,19 +0,0 @@ -module demos.flag_component; - -import app; - -import bindbc.sdl; - -import cimgui.cimgui; - -import bubel.ecs.attributes; -import bubel.ecs.core; -import bubel.ecs.entity; -import bubel.ecs.manager; -import bubel.ecs.std; - -import ecs_utils.gfx.texture; -import ecs_utils.math.vector; -import ecs_utils.utils; - -extern(C): \ No newline at end of file diff --git a/demos/source/demos/simple.d b/demos/source/demos/simple.d index 5e82d27..313cc00 100644 --- a/demos/source/demos/simple.d +++ b/demos/source/demos/simple.d @@ -52,7 +52,7 @@ struct DrawSystem struct EntitiesData { uint length; - uint thread_id; + //uint thread_id; uint job_id; @readonly CTexture[] textures; @readonly CLocation[] locations; diff --git a/demos/source/demos/snake.d b/demos/source/demos/snake.d index 50f7729..01e9a36 100644 --- a/demos/source/demos/snake.d +++ b/demos/source/demos/snake.d @@ -129,9 +129,10 @@ struct Snake } if(base_pos.x == random_pos.x && base_pos.y == random_pos.y)return; } - CILocation* location = apple_tmpl.getComponent!CILocation; - *location = random_pos; - Entity* apple = launcher.manager.addEntity(apple_tmpl); + //CILocation* location = apple_tmpl.getComponent!CILocation; + //*location = random_pos; + //Entity* apple = + launcher.manager.addEntity(apple_tmpl,[CILocation(random_pos).ref_].staticArray); } } @@ -366,8 +367,8 @@ struct MoveSystem mixin ECS.System!64; EntityTemplate* destroy_template; - CLocation* destroy_location; - CParticleVector* destroy_vector; + //CLocation* destroy_location; + //CParticleVector* destroy_vector; struct EntitiesData { @@ -381,8 +382,8 @@ struct MoveSystem void setTemplates() { destroy_template = snake.snake_destroy_particle; - destroy_location = destroy_template.getComponent!CLocation; - destroy_vector = destroy_template.getComponent!CParticleVector; + //destroy_location = destroy_template.getComponent!CLocation; + //destroy_vector = destroy_template.getComponent!CParticleVector; } void moveLocation(ref CILocation location, CMovement.Direction direction) @@ -436,24 +437,26 @@ struct MoveSystem case MapElement.Type.snake: foreach(loc; data.snakes[i].parts) { - destroy_location.x = loc.x * 16; - destroy_location.y = loc.y * 16; + //destroy_location.x = loc.x * 16; + //destroy_location.y = loc.y * 16; snake.element(MapElement(MapElement.Type.empty, EntityID()),loc); - launcher.manager.addEntity(snake.snake_destroy_particle); + launcher.manager.addEntity(snake.snake_destroy_particle,[CLocation(cast(vec2)(loc * 16)).ref_].staticArray); + + CLocation destroy_location; foreach(j;0..10) { destroy_location.x = loc.x * 16 + randomf() * 8 - 4; destroy_location.y = loc.y * 16 + randomf() * 8 - 4; - destroy_vector.velocity = vec2(randomf(),randomf())*0.4-0.2; + //destroy_vector.velocity = vec2(randomf(),randomf())*0.4-0.2; snake.element(MapElement(MapElement.Type.empty, EntityID()),loc); - launcher.manager.addEntity(snake.snake_destroy_particle); + launcher.manager.addEntity(snake.snake_destroy_particle, [destroy_location.ref_, CParticleVector(vec2(randomf(),randomf())*0.4-0.2).ref_].staticArray); } } - destroy_location.x = new_location.x * 16; - destroy_location.y = new_location.y * 16; + //destroy_location.x = new_location.x * 16; + //destroy_location.y = new_location.y * 16; snake.element(MapElement(MapElement.Type.empty, EntityID()),new_location); - launcher.manager.addEntity(snake.snake_destroy_particle); + launcher.manager.addEntity(snake.snake_destroy_particle,[CLocation(cast(vec2)(new_location * 16)).ref_].staticArray); launcher.manager.removeEntity(data.entities[i].id); break; @@ -796,9 +799,9 @@ void snakeStart() { ushort[4] components = [CILocation.component_id, CSnake.component_id, CMovement.component_id, CInput.component_id]; snake.snake_tmpl = launcher.manager.allocateTemplate(components); - CILocation* loc_comp = snake.snake_tmpl.getComponent!CILocation; - *loc_comp = ivec2(2,2); - launcher.manager.addEntity(snake.snake_tmpl); + //CILocation* loc_comp = snake.snake_tmpl.getComponent!CILocation; + //*loc_comp = ivec2(2,2); + launcher.manager.addEntity(snake.snake_tmpl,[CILocation(ivec2(2,2)).ref_].staticArray); } { @@ -846,15 +849,15 @@ void snakeTool(vec2 position, Tool tool, int size) CLocation* location = tmpl.getComponent!CLocation; if(location) { - position.x += (randomf - 0.5) * size; - position.y += (randomf - 0.5) * size; + position.x += (randomf() - 0.5) * size; + position.y += (randomf() - 0.5) * size; *location = position; } CILocation* ilocation = tmpl.getComponent!CILocation; if(ilocation) { - position.x += (randomf - 0.5) * size; - position.y += (randomf - 0.5) * size; + position.x += (randomf() - 0.5) * size; + position.y += (randomf() - 0.5) * size; ivec2 ipos; ipos.x = cast(int)(position.x / 16); ipos.y = cast(int)(position.y / 16); diff --git a/demos/source/demos/space_invaders.d b/demos/source/demos/space_invaders.d index c047d25..5615f0d 100644 --- a/demos/source/demos/space_invaders.d +++ b/demos/source/demos/space_invaders.d @@ -40,6 +40,7 @@ struct SpaceInvaders EntityTemplate* enemy_tmpl; EntityTemplate* ship_tmpl; EntityTemplate* laser_tmpl; + EntityTemplate*[5] bullet_tmpl; Texture texture; ShootGrid* shoot_grid; @@ -55,9 +56,13 @@ struct SpaceInvaders ~this() @nogc nothrow { if(shoot_grid)Mallocator.dispose(shoot_grid); - launcher.manager.freeTemplate(enemy_tmpl); - launcher.manager.freeTemplate(ship_tmpl); - launcher.manager.freeTemplate(laser_tmpl); + if(enemy_tmpl)launcher.manager.freeTemplate(enemy_tmpl); + if(ship_tmpl)launcher.manager.freeTemplate(ship_tmpl); + if(laser_tmpl)launcher.manager.freeTemplate(laser_tmpl); + foreach (EntityTemplate* tmpl; bullet_tmpl) + { + if(tmpl)launcher.manager.freeTemplate(tmpl); + } texture.destory(); } } @@ -115,7 +120,7 @@ struct CLocation alias value this; - vec2 value; + vec2 value = vec2(0); } struct CScale @@ -192,7 +197,7 @@ struct CGuild byte guild; } -struct CLaser +struct CBullet { mixin ECS.Component; @@ -408,12 +413,35 @@ struct CParticleEmitterTime { mixin ECS.Component; - float time; + float time = 0; } +///You can create separate component for every kind of spawned entities but it's not practial due to archetype fragmentation. +///Second approach can be commented code. It's gives good flexibility inchoosing entity, but it limits to one entity. +///Instead of entity it can be array of templates which is good solution, but if possibilities is known at time of game development it +///can be simply index/enum for type of spawn. Bad thing about this solution is problem witch merging multiple spawning types during +///gameplay, i.e. giving buff which cast firebols upon death. +struct CSpawnUponDeath +{ + mixin ECS.Component; + + enum Type + { + flashes_emitter, + } + + //EntityID parent; + //EntityTemplate* tmpl; + Type type; +} + +///This component can be replaced by "CSpawnUponDeath" but I want to gives possibility to add this component to every entity +///during gameplay. End application works exacly the same way for every demo so I can't use different way as adding component. struct CShootWaveUponDeath { mixin ECS.Component; + + CWeapon.Type bullet_type; } /*####################################################################################################################### @@ -604,7 +632,7 @@ struct ShootGridManager struct EntitiesData { uint length; - uint thread_id; + //uint thread_id; const (Entity)[] entity; @readonly CLocation[] locations; @readonly CShootGrid[] grid_flag; @@ -748,7 +776,8 @@ struct ShipWeaponSystem weapon_tmpl.getComponent!CTargetParent().rel_pos = vec2(0,0); weapon_tmpl.getComponent!CGuild().guild = 1; weapon_tmpl.getComponent!CScale().value = vec2(4,16); - weapon_tmpl.getComponent!CWeapon().level = 1; + //weapon_tmpl.getComponent!CWeapon().level = 1; + *weapon_tmpl.getComponent!CWeapon() = CWeapon(0,CWeapon.Type.canon,1); weapon_tmpl.getComponent!CDepth().depth = -1; weapon_tmpl.getComponent!CTexture().coords = vec4(136,96,4,16)*px; weapon_tmpl.getComponent!CWeaponLocation().rel_pos = vec2(0,12); @@ -801,7 +830,8 @@ struct ShipWeaponSystem [CHitMark.component_id, CHitPoints.component_id, CLocation.component_id, CTexture.component_id, CScale.component_id, CEnemy.component_id, CShootGrid.component_id, CGuild.component_id, CInit.component_id, - CChildren.component_id, CDepth.component_id, CTargetParent.component_id].staticArray + CChildren.component_id, CDepth.component_id, CTargetParent.component_id, + CSpawnUponDeath.component_id, CShootWaveUponDeath.component_id].staticArray ); CTexture* tex_comp = tower1_tmpl.getComponent!CTexture; @@ -813,6 +843,7 @@ struct ShipWeaponSystem tower1_tmpl.getComponent!CInit().type = CInit.Type.tower; tower1_tmpl.getComponent!CHitPoints().value = 10; tower1_tmpl.getComponent!CDepth().depth = -2; + tower1_tmpl.getComponent!CShootWaveUponDeath().bullet_type = CWeapon.Type.canon; tower1_tmpl.getComponent!CTargetParent().rel_pos = vec2(-33,2); tower2_tmpl = launcher.manager.allocateTemplate(tower1_tmpl); @@ -865,22 +896,12 @@ struct ShipWeaponSystem { foreach(i; 0..data.length) { - /*if(data.children[i].childern.length != 0)continue; - EntityID[3] weapons; - laser1_tmpl.getComponent!CTargetParent().parent = data.entity[i].id; - laser2_tmpl.getComponent!CTargetParent().parent = data.entity[i].id; - main_weapon_tmpl.getComponent!CTargetParent().parent = data.entity[i].id; - weapons[0] = launcher.manager.addEntity(laser1_tmpl).id; - weapons[1] = launcher.manager.addEntity(laser2_tmpl).id; - weapons[2] = launcher.manager.addEntity(main_weapon_tmpl).id; - data.children[i].childern = Mallocator.makeArray(weapons);*/ final switch(data.init[i].type) { case CInit.Type.space_ship:ship.add(&data.entity[i]);break; case CInit.Type.tower:tower.add(&data.entity[i]);break; case CInit.Type.boss:boss.add(&data.entity[i]);break; } - } } } @@ -942,7 +963,7 @@ struct DrawSystem struct EntitiesData { uint length; - uint thread_id; + //uint thread_id; uint job_id; @readonly CTexture[] textures; @readonly CLocation[] locations; @@ -1046,8 +1067,6 @@ struct LaserShootingSystem mixin ECS.System!32; bool shoot = false; - //static float[18] laser_shoot_times = [500,400,300,200,100,50,25,10,5,2,1,0.8,0.6,0.5,0.4,0.3,0.2,0.1]; - //static float[18] laser_shoot_disp = [0,0,0,0,0.05,0.06,0.08,0.1,0.14,0.18,0.2,0.25,0.26,0.27,0.28,0.29,0.3,0.4]; __gshared vec4[] fire_frames = [vec4(96,64,8,16)*px,vec4(104,64,8,16)*px,vec4(112,64,8,16)*px,vec4(120,64,8,16)*px,vec4(128,64,8,16)*px, vec4(136,64,8,16)*px,vec4(144,64,8,16)*px,vec4(152,64,8,16)*px,vec4(160,64,8,16)*px]; @@ -1055,16 +1074,10 @@ struct LaserShootingSystem // __gshared vec4[] fire_frames = [vec4(0,160,8,16)*px,vec4(16,160,16,16)*px,vec4(32,160,16,16)*px,vec4(48,160,16,16)*px,vec4(64,160,16,16)*px, // vec4(80,160,16,16)*px,vec4(96,160,16,16)*px,vec4(112,160,16,16)*px]; - /*CLocation* laser_location; - CVelocity* laser_velocity; - CGuild* laser_guild;*/ - struct EntitiesData { ///variable named "length" contain entites count uint length; - ///variable named "length" contain thread identifier - uint thread_id; CWeapon[] laser; @readonly CLocation[] location; @readonly CGuild[] guild; @@ -1076,77 +1089,53 @@ struct LaserShootingSystem @optional @readonly CRotation[] rotation; } - struct ThreadData - { - EntityTemplate* laser_tmpl; - CLocation* laser_location; - CVelocity* laser_velocity; - CGuild* laser_guild; + //EntityTemplate* laser_tmpl; + EntityTemplate* fire_tmpl; - EntityTemplate* fire_tmpl; - CLocation* fire_location; - CVelocity* fire_velocity; - CRotation* fire_rotation; - } - - ThreadData[] threads; + //EntityTemplate*[5] bullet_tmpl; ///Called inside "registerSystem" function void onCreate() { - threads = Mallocator.makeArray!ThreadData(32); - threads[0].laser_tmpl = launcher.manager.allocateTemplate( + /*bullet_tmpl[0] = launcher.manager.allocateTemplate( [CLocation.component_id, CTexture.component_id, CVelocity.component_id, - CScale.component_id, CLaser.component_id, CGuild.component_id].staticArray + CScale.component_id, CBullet.component_id, CGuild.component_id].staticArray ); + bullet_tmpl[0].getComponent!CTexture().coords = vec4(0,24,2,8)*px; + bullet_tmpl[0].getComponent!CScale().value = vec2(2,8); - CTexture* tex_comp = threads[0].laser_tmpl.getComponent!CTexture; - //tex_comp.tex = space_invaders.texture;//laser_tex; - tex_comp.coords = vec4(0*px,24*px,2*px,8*px); - CScale* scale_comp = threads[0].laser_tmpl.getComponent!CScale; - scale_comp.value = vec2(2,8); - threads[0].laser_location = threads[0].laser_tmpl.getComponent!CLocation; - threads[0].laser_velocity = threads[0].laser_tmpl.getComponent!CVelocity; - threads[0].laser_guild = threads[0].laser_tmpl.getComponent!CGuild; + bullet_tmpl[1] = launcher.manager.allocateTemplate(bullet_tmpl[0]); + bullet_tmpl[2] = launcher.manager.allocateTemplate(bullet_tmpl[0]); + bullet_tmpl[2].getComponent!CTexture().coords = vec4(64,32,8,16)*px; + bullet_tmpl[2].getComponent!CScale().value = vec2(8,16); + bullet_tmpl[3] = launcher.manager.allocateTemplate(bullet_tmpl[0]); + bullet_tmpl[3].getComponent!CTexture().coords = vec4(56,32,2,2)*px; + bullet_tmpl[3].getComponent!CScale().value = vec2(2,2); + // bullet_tmpl[3].getComponent!CTexture().coords = vec4(48,32,8,8)*px; + // bullet_tmpl[3].getComponent!CScale().value = vec2(8,8); + bullet_tmpl[4] = launcher.manager.allocateTemplate(bullet_tmpl[0]);*/ - threads[0].fire_tmpl = launcher.manager.allocateTemplate( + + fire_tmpl = launcher.manager.allocateTemplate( [CLocation.component_id, CTexture.component_id, CScale.component_id, CAnimation.component_id, CParticle.component_id, CRotation.component_id, CVelocity.component_id, CDamping.component_id].staticArray ); - tex_comp = threads[0].fire_tmpl.getComponent!CTexture; - //tex_comp.tex = space_invaders.texture;//laser_tex; - tex_comp.coords = vec4(96*px,64*px,8*px,16*px); - scale_comp = threads[0].fire_tmpl.getComponent!CScale; - scale_comp.value = vec2(8,16); - threads[0].fire_location = threads[0].fire_tmpl.getComponent!CLocation; - threads[0].fire_rotation = threads[0].fire_tmpl.getComponent!CRotation; - threads[0].fire_velocity = threads[0].fire_tmpl.getComponent!CVelocity; - threads[0].fire_tmpl.getComponent!(CParticle).life = 300; - *threads[0].fire_tmpl.getComponent!(CAnimation) = CAnimation(fire_frames, 0, 3); - - foreach(ref ThreadData thread;threads[1..$]) - { - thread.laser_tmpl = launcher.manager.allocateTemplate(threads[0].laser_tmpl); - thread.laser_location = thread.laser_tmpl.getComponent!CLocation; - thread.laser_velocity = thread.laser_tmpl.getComponent!CVelocity; - thread.laser_guild = thread.laser_tmpl.getComponent!CGuild; - thread.fire_tmpl = launcher.manager.allocateTemplate(threads[0].fire_tmpl); - thread.fire_location = thread.fire_tmpl.getComponent!CLocation; - thread.fire_rotation = thread.fire_tmpl.getComponent!CRotation; - thread.fire_velocity = thread.fire_tmpl.getComponent!CVelocity; - } - //laser_location = space_invaders.laser_tmpl.getComponent!CLocation; + fire_tmpl.getComponent!CTexture().coords = vec4(96,64,8,16)*px; + fire_tmpl.getComponent!CScale().value = vec2(8,16); + fire_tmpl.getComponent!(CParticle).life = 300; + *fire_tmpl.getComponent!(CAnimation) = CAnimation(fire_frames, 0, 3); } void onDestroy() { - foreach(ref ThreadData thread;threads[1..$]) + //launcher.manager.freeTemplate(laser_tmpl); + /*foreach (EntityTemplate* tmpl; bullet_tmpl) { - launcher.manager.freeTemplate(thread.laser_tmpl); - } - Mallocator.dispose(threads); + launcher.manager.freeTemplate(tmpl); + }*/ + launcher.manager.freeTemplate(fire_tmpl); } bool onBegin() @@ -1164,7 +1153,6 @@ struct LaserShootingSystem void onUpdate(EntitiesData data) { - ThreadData* thread = &threads[data.thread_id]; //conditional branch for whole entities block if(shoot || data.auto_shoot) { @@ -1174,58 +1162,65 @@ struct LaserShootingSystem laser.shoot_time += launcher.delta_time; while(laser.shoot_time > CWeapon.levels[laser.level - 1].reload_time) { + CVelocity laser_velocity; + CGuild laser_guild; + CLocation laser_location; + CVelocity fire_velocity; + CLocation fire_location; + CRotation fire_rotation; + laser.shoot_time -= CWeapon.levels[laser.level - 1].reload_time; - thread.laser_location.value = data.location[i]; + laser_location.value = data.location[i]; - thread.laser_velocity.value = vec2((randomf()*2-1) * CWeapon.levels[laser.level - 1].dispersion,1);//data.shoot_direction[i].direction == Direction.up ? 1.0 : -1.0); - if(data.shoot_direction && data.shoot_direction[i].direction == Direction.down)thread.laser_velocity.y = -1; + laser_velocity.value = vec2((randomf()*2-1) * CWeapon.levels[laser.level - 1].dispersion,1);//data.shoot_direction[i].direction == Direction.up ? 1.0 : -1.0); + if(data.shoot_direction && data.shoot_direction[i].direction == Direction.down)laser_velocity.y = -1; - thread.laser_guild.guild = data.guild[i].guild; + laser_guild.guild = data.guild[i].guild; - if(laser.level < 3)thread.laser_velocity.value = thread.laser_velocity.value * 0.4f; + if(laser.level < 3)laser_velocity.value = laser_velocity.value * 0.4f; if(data.velocity) { - thread.fire_velocity.value = data.velocity[i]; - //thread.laser_velocity.value += data.velocity[i] * 0.5; + fire_velocity.value = data.velocity[i]; + //laser_velocity.value += data.velocity[i] * 0.5; } - else thread.fire_velocity.value = vec2(0,0); + else fire_velocity.value = vec2(0,0); - thread.fire_location.value = data.location[i]; + fire_location.value = data.location[i]; if(data.shoot_direction[i].direction == Direction.down) { - thread.fire_rotation.value = PI; - //thread.fire_location.value.y -= 16; + fire_rotation.value = PI; + //fire_location.value.y -= 16; } else { - thread.fire_rotation.value = 0; - //thread.fire_location.value.y += 24; + fire_rotation.value = 0; + //fire_location.value.y += 24; } if(data.rotation) { float sinn = sinf(data.rotation[i]); float coss = cosf(data.rotation[i]); - float x = thread.laser_velocity.y*sinn + thread.laser_velocity.x*coss; - float y = thread.laser_velocity.y*coss + thread.laser_velocity.x*sinn; - thread.laser_velocity.value = vec2(x,y); - thread.fire_rotation.value = data.rotation[i]; + float x = laser_velocity.y*sinn + laser_velocity.x*coss; + float y = laser_velocity.y*coss + laser_velocity.x*sinn; + laser_velocity.value = vec2(x,y); + fire_rotation.value = data.rotation[i]; if(data.weapon_location) { vec2 rel_pos = vec2(data.weapon_location[i].rel_pos.y*sinn+data.weapon_location[i].rel_pos.x*coss, data.weapon_location[i].rel_pos.y*coss+data.weapon_location[i].rel_pos.x*sinn); - thread.laser_location.value += rel_pos; - thread.fire_location.value += rel_pos; + laser_location.value += rel_pos; + fire_location.value += rel_pos; } } else if(data.weapon_location) { - thread.laser_location.value += data.weapon_location[i].rel_pos; - thread.fire_location.value += data.weapon_location[i].rel_pos; + laser_location.value += data.weapon_location[i].rel_pos; + fire_location.value += data.weapon_location[i].rel_pos; } - launcher.manager.addEntity(thread.laser_tmpl); - launcher.manager.addEntity(thread.fire_tmpl); + launcher.manager.addEntity(space_invaders.bullet_tmpl[data.laser[i].type],[laser_velocity.ref_, laser_guild.ref_, laser_location.ref_].staticArray); + launcher.manager.addEntity(fire_tmpl,[fire_location.ref_, fire_rotation.ref_, fire_velocity.ref_].staticArray); } } } @@ -1287,7 +1282,7 @@ struct LaserCollisionSystem uint length; const (Entity)[] entity; @readonly CLocation[] location; - @readonly CLaser[] laser; + @readonly CBullet[] laser; @readonly CGuild[] guild; } @@ -1312,69 +1307,63 @@ struct ParticleEmittingSystem struct EntitiesData { uint length; - uint thread_id; + //uint thread_id; CParticleEmitterTime[] emit_time; @readonly CLocation[] location; @readonly CParticleEmitter[] emitter; @optional @readonly CVelocity[] velocity; + @optional @readonly CDepth[] depth; } + + __gshared vec4[] flashes = [vec4(224,0,16,16)*px,vec4(240,0,16,16)*px,vec4(256,0,16,16)*px,vec4(272,0,16,16)*px,vec4(288,0,16,16)*px, + vec4(304,0,16,16)*px,vec4(320,0,16,16)*px]; - struct Thread - { - EntityTemplate*[1] templates; - } - - Thread[] threads; + EntityTemplate*[1] templates; void onCreate() { - threads = Mallocator.makeArray!Thread(32); - - threads[0].templates[0] = launcher.manager.allocateTemplate( + templates[0] = launcher.manager.allocateTemplate( [CLocation.component_id, CTexture.component_id, CScale.component_id, CAnimation.component_id, CParticle.component_id, CRotation.component_id, - CVelocity.component_id, CDamping.component_id].staticArray); - - foreach(ref thread;threads[1 .. $]) - { - thread.templates[0] = launcher.manager.allocateTemplate(threads[0].templates[0]); - } + CVelocity.component_id, CDamping.component_id, CDepth.component_id].staticArray); + *templates[0].getComponent!CAnimation() = CAnimation(flashes,0,2); + *templates[0].getComponent!CParticle() = CParticle(350); + //*templates[0].getComponent!CDepth() = CDepth(-3); } void onDestroy() { - foreach(ref thread;threads[1 .. $]) + foreach(tmpl; templates) { - foreach(tmpl; thread.templates) - { - launcher.manager.freeTemplate(tmpl); - } - } - Mallocator.dispose(threads); + launcher.manager.freeTemplate(tmpl); + } } void onUpdate(EntitiesData data) { - Thread* thread = &threads[data.thread_id]; foreach(i;0..data.length) { data.emit_time[i].time -= launcher.delta_time; while(data.emit_time[i].time < 0) { + CVelocity velocity; + CDepth depth; + CParticleEmitter* emitter = &data.emitter[i]; data.emit_time[i].time += emitter.time_range.x + randomf() * emitter.time_range.y; - EntityTemplate* tmpl = thread.templates[emitter.tmpl_id]; - CLocation* location = tmpl.getComponent!CLocation; - if(location)location.value = data.location[i]; - if(data.velocity) { - CVelocity* velocity = tmpl.getComponent!CVelocity; - if(velocity)velocity.value = data.velocity[i]; + velocity.value = data.velocity[i]; } - launcher.manager.addEntity(tmpl); + + if(data.depth) + { + depth.depth = data.depth[i]; + } + + launcher.manager.addEntity(templates[0],[data.location[i].ref_,velocity.ref_,depth.ref_].staticArray); } } } @@ -1617,10 +1606,7 @@ struct HitPointsSystem __gshared vec4[] explosion_laser_frames = [vec4(80,128,16,16)*px,vec4(96,128,16,16)*px,vec4(112,128,16,16)*px,vec4(128,128,16,16)*px,vec4(144,128,16,16)*px,vec4(160,128,16,16)*px,vec4(176,128,16,16)*px,vec4(192,128,16,16)*px,vec4(208,128,16,16)*px]; EntityTemplate* upgrade_tmpl; - CLocation* upgrade_location; - EntityTemplate* explosion_tmpl; - CLocation* explosion_location; struct EntitiesData { @@ -1629,29 +1615,31 @@ struct HitPointsSystem void onCreate() { - upgrade_tmpl = launcher.manager.allocateTemplate([CVelocity.component_id, CLocation.component_id, CTexture.component_id, CScale.component_id, CUpgrade.component_id, CAnimation.component_id, CAnimationLooped.component_id].staticArray); - CTexture* tex_comp = upgrade_tmpl.getComponent!CTexture; + upgrade_tmpl = launcher.manager.allocateTemplate( + [CVelocity.component_id, CLocation.component_id, CTexture.component_id, + CScale.component_id, CUpgrade.component_id, CAnimation.component_id, + CAnimationLooped.component_id].staticArray); //tex_comp.tex = space_invaders.texture;//ship_tex; - tex_comp.coords = vec4(0*px,32*px,16*px,16*px); + upgrade_tmpl.getComponent!CTexture().coords = vec4(0*px,32*px,16*px,16*px); *upgrade_tmpl.getComponent!CAnimation = CAnimation(upgrade_laser_frames, 0, 1); - CVelocity* vel_comp = upgrade_tmpl.getComponent!CVelocity; - vel_comp.value = vec2(0,-0.1); - upgrade_location = upgrade_tmpl.getComponent!CLocation; + upgrade_tmpl.getComponent!CVelocity().value = vec2(0,-0.1); - explosion_tmpl = launcher.manager.allocateTemplate([CDepth.component_id, CParticle.component_id, CLocation.component_id, CTexture.component_id, CScale.component_id, CAnimation.component_id].staticArray); + explosion_tmpl = launcher.manager.allocateTemplate( + [CDepth.component_id, CParticle.component_id, CLocation.component_id, + CTexture.component_id, CScale.component_id, CAnimation.component_id].staticArray); //explosion_tmpl.getComponent!(CTexture).tex = space_invaders.texture; *explosion_tmpl.getComponent!CAnimation = CAnimation(explosion_laser_frames, 0, 1.333); explosion_tmpl.getComponent!(CParticle).life = 600; *explosion_tmpl.getComponent!CDepth = -1; - explosion_location = explosion_tmpl.getComponent!CLocation; } void onDestroy() { launcher.manager.freeTemplate(upgrade_tmpl); + launcher.manager.freeTemplate(explosion_tmpl); } - void handleEvent(Entity* entity, EDamage event) + /*void handleEvent(Entity* entity, EDamage event) { CHitPoints* hp = entity.getComponent!CHitPoints; if(*hp <= 0)return; @@ -1663,7 +1651,7 @@ struct HitPointsSystem } CHitMark* hit_mark = entity.getComponent!CHitMark; if(hit_mark)hit_mark.value = 127; - } + }*/ void handleEvent(Entity* entity, EBulletHit event) { @@ -1690,11 +1678,9 @@ struct HitPointsSystem { if(randomRange(0, 1000) < 5) { - *upgrade_location = *location; - launcher.manager.addEntity(upgrade_tmpl); + launcher.manager.addEntity(upgrade_tmpl,[location.ref_].staticArray); } - *explosion_location = *location; - launcher.manager.addEntity(explosion_tmpl); + launcher.manager.addEntity(explosion_tmpl,[location.ref_].staticArray); } } launcher.manager.removeEntity(entity.id); @@ -1720,6 +1706,55 @@ struct ChildDestroySystem } } +struct ShootWaveSystem +{ + mixin ECS.System; + + struct EntitiesData + { + CLocation[] location; + CShootWaveUponDeath[] shoot_wave; + } + + vec2[] dirs; + + void onCreate() + { + enum count = 24; + dirs = Mallocator.makeArray!vec2(count); + float step = 2 * PI / cast(float)count; + foreach(i;0..count) + { + float angle = step * i; + dirs[i] = vec2(sinf(angle),cosf(angle)) * 0.2; + } + } + + void onDestroy() + { + Mallocator.dispose(dirs); + } + + void handleEvent(Entity* entity, EDeath event) + { + + CShootWaveUponDeath* wave = entity.getComponent!CShootWaveUponDeath; + CLocation* location = entity.getComponent!CLocation; + CGuild* guild = entity.getComponent!CGuild; + + //LaserShootingSystem.bullet_tmpl + EntityTemplate* tmpl = space_invaders.bullet_tmpl[wave.bullet_type]; + foreach(dir;dirs) + { + if(guild)launcher.manager.addEntity(tmpl,[location.ref_,guild.ref_,CVelocity(dir).ref_].staticArray); + else launcher.manager.addEntity(tmpl,[location.ref_,CVelocity(dir).ref_].staticArray); + } + //launcher.manager.addEntity(tmpl);//,[location.ref_].staticArray); + + //launcher.manager.addEntity(space_invaders.bullet_tmpl[0]); + } +} + struct PartsDestroySystem { mixin ECS.System; @@ -1738,9 +1773,14 @@ struct PartsDestroySystem flashes_emitter = launcher.manager.allocateTemplate( [ CVelocity.component_id, CLocation.component_id, CParticleEmitter.component_id, - CParticleEmitterTime.component_id, CTargetParent.component_id + CParticleEmitterTime.component_id, CTargetParent.component_id, CDepth.component_id ].staticArray); - *flashes_emitter.getComponent!CParticleEmitter() = CParticleEmitter(vec2(0,0), vec2(400,400), 0); + *flashes_emitter.getComponent!CParticleEmitter() = CParticleEmitter(vec2(0,0), vec2(800,1600), 0); + } + + void onDestroy() + { + launcher.manager.freeTemplate(flashes_emitter); } void handleEvent(Entity* entity, EDestroyedChild event) @@ -1752,17 +1792,24 @@ struct PartsDestroySystem if(init.type == CInit.Type.boss) { CChildren* children = entity.getComponent!CChildren; - foreach(EntityID child; children.childern) + foreach(ref EntityID child; children.childern) { if(child == event.id) { Entity* child_entity = launcher.manager.getEntity(child); if(child_entity) { + CLocation location; CTargetParent* target_parent = child_entity.getComponent!CTargetParent; + CDepth* target_depth = child_entity.getComponent!CDepth; + CLocation* target_location = child_entity.getComponent!CLocation; + //CVelocity* velocity = child_entity.getComponent!CTargetParent; + + if(target_location)location = *target_location; *flashes_emitter.getComponent!CTargetParent() = *target_parent; - launcher.manager.addEntity(flashes_emitter); + if(target_depth)child = launcher.manager.addEntity(flashes_emitter, [target_depth.ref_, location.ref_].staticArray).id; + else child = launcher.manager.addEntity(flashes_emitter, [location.ref_].staticArray).id; } break; } @@ -1793,7 +1840,7 @@ struct ClampPositionSystem @optional @readonly CColliderScale[] collider_scale; @optional @readonly CScale[] scale; - @optional const (CLaser)[] laser; + @optional const (CBullet)[] laser; @optional const (CUpgrade)[] upgrade; //@optional CVelocity[] velocity; //@optional const (CSideMove)[] side_move; @@ -1891,7 +1938,7 @@ struct MovementSystem const (CVelocity)[] velocity; //components are treated as required by default CLocation[] locations; - //@optional const (CLaser)[] laser; + //@optional const (CBullet)[] laser; const (Entity)[] entities; //@optional CSideMove[] side_move; @@ -1927,8 +1974,10 @@ struct AnimationSystem foreach(i;0..data.length) { data.animation[i].time += dt * data.animation[i].speed; - while(data.animation[i].time >= data.animation[i].frames.length)data.animation[i].time -= cast(float)data.animation[i].frames.length; - data.texture[i].coords = data.animation[i].frames[cast(int)(data.animation[i].time)]; + while(cast(uint)data.animation[i].time >= data.animation[i].frames.length)data.animation[i].time -= cast(float)data.animation[i].frames.length; + if(cast(uint)(data.animation[i].time) >= data.animation[i].frames.length)assert(0); + uint index = cast(uint)(data.animation[i].time); + if(index < data.animation[i].frames.length)data.texture[i].coords = data.animation[i].frames[index]; } } else @@ -1936,8 +1985,9 @@ struct AnimationSystem foreach(i;0..data.length) { data.animation[i].time += dt * data.animation[i].speed; - if(data.animation[i].time >= data.animation[i].frames.length)data.animation[i].time = data.animation[i].frames.length - 0.1; - data.texture[i].coords = data.animation[i].frames[cast(int)(data.animation[i].time)]; + if(cast(uint)data.animation[i].time >= data.animation[i].frames.length)data.animation[i].time = data.animation[i].frames.length - 0.9; + uint index = cast(uint)(data.animation[i].time); + if(index < data.animation[i].frames.length)data.texture[i].coords = data.animation[i].frames[index]; } } @@ -2070,6 +2120,66 @@ struct CShipIterator } } +/*struct SpawnUponDeathSystem +{ + mixin ECS.System; + + struct EntitiesData + { + @readonly CSpawnUponDeath[] spawn; + @optional CTargetParent[] parent; + } + + EntityTemplate* flashes_emitter; + + void onCreate() + { + flashes_emitter = launcher.manager.allocateTemplate( + [ + CVelocity.component_id, CLocation.component_id, CParticleEmitter.component_id, + CParticleEmitterTime.component_id, CTargetParent.component_id + ].staticArray); + *flashes_emitter.getComponent!CParticleEmitter() = CParticleEmitter(vec2(0,0), vec2(400,400), 0); + } + + void onDestroy() + { + launcher.manager.freeTemplate(flashes_emitter); + } + + void onRemoveEntity(EntitiesData data) + { + //CSpawnUponDeath[] spawn = + switch(data.spawn[0].type) + { + case CSpawnUponDeath.Type.flashes_emitter: + if(data.parent) + { + /*Entity* parent_entity = launcher.manager.getEntity(data.parent[0].parent); + CChildren* children = entity.getComponent!CChildren; + foreach(ref EntityID child; children.childern) + { + if(child == event.id) + { + Entity* child_entity = launcher.manager.getEntity(child); + if(child_entity) + { + *flashes_emitter.getComponent!CTargetParent = data.parent[0]; + launcher.manager.addEntity(flashes_emitter); + //child = launcher.manager.addEntity(flashes_emitter); + } + break; + } + } + } + break; + default:break; + } + } + + //void handleEvent(Entity* entity, ) +}//*/ + extern(C) float sqrtf(float x) @nogc nothrow @system; extern(C) float acosf(float x) @nogc nothrow @system; extern(C) float sinf(float x) @nogc nothrow @system; @@ -2198,7 +2308,7 @@ void spaceInvadersStart() launcher.manager.registerComponent!CAutoShoot; launcher.manager.registerComponent!CWeapon; launcher.manager.registerComponent!CVelocity; - launcher.manager.registerComponent!CLaser; + launcher.manager.registerComponent!CBullet; launcher.manager.registerComponent!CSideMove; launcher.manager.registerComponent!CDepth; launcher.manager.registerComponent!CShootGrid; @@ -2223,6 +2333,8 @@ void spaceInvadersStart() launcher.manager.registerComponent!CColliderScale; launcher.manager.registerComponent!CParticleEmitter; launcher.manager.registerComponent!CParticleEmitterTime; + launcher.manager.registerComponent!CSpawnUponDeath; + launcher.manager.registerComponent!CShootWaveUponDeath; launcher.manager.registerEvent!EChangeDirection; launcher.manager.registerEvent!EDamage; @@ -2248,16 +2360,17 @@ void spaceInvadersStart() launcher.manager.registerSystem!ParticleSystem(-100); launcher.manager.registerSystem!AnimationSystem(-100); launcher.manager.registerSystem!DampingSystem(-101); - launcher.manager.registerSystem!MoveToParentTargetSystem(99); + launcher.manager.registerSystem!MoveToParentTargetSystem(-98); launcher.manager.registerSystem!ParentOwnerSystem(-101); launcher.manager.registerSystem!ShipWeaponSystem(-100); - launcher.manager.registerSystem!ParticleEmittingSystem(-100); - + launcher.manager.registerSystem!ParticleEmittingSystem(-95); launcher.manager.registerSystem!RotateToTargetSystem(-100); launcher.manager.registerSystem!ShipTargetSystem(-110); launcher.manager.registerSystem!CShipIterator(-100); launcher.manager.registerSystem!PartsDestroySystem(-80); launcher.manager.registerSystem!ChildDestroySystem(-110); + launcher.manager.registerSystem!ShootWaveSystem(-100); + //launcher.manager.registerSystem!SpawnUponDeathSystem(-110); launcher.manager.endRegister(); @@ -2267,19 +2380,26 @@ void spaceInvadersStart() launcher.gui_manager.addSystem(MovementSystem.system_id,"Movement System"); launcher.gui_manager.addSystem(ClampPositionSystem.system_id,"Clamp Position System"); launcher.gui_manager.addSystem(ChangeDirectionSystem.system_id,"Change Direction System"); - launcher.gui_manager.addSystem(LaserCollisionSystem.system_id,"Draw System"); + launcher.gui_manager.addSystem(LaserCollisionSystem.system_id,"Laser Collision System"); launcher.gui_manager.addSystem(ShootGridManager.system_id,"Shoot Grid Manager"); launcher.gui_manager.addSystem(ShootGridCleaner.system_id,"Shoot Grid Cleaner"); launcher.gui_manager.addSystem(HitPointsSystem.system_id,"Hit Points System"); - launcher.gui_manager.addSystem(HitMarkingSystem.system_id,"Hit Matking System"); + launcher.gui_manager.addSystem(HitMarkingSystem.system_id,"Hit Marking System"); launcher.gui_manager.addSystem(UpgradeCollisionSystem.system_id,"Upgrade Collision System"); launcher.gui_manager.addSystem(UpgradeSystem.system_id,"Upgrade System"); launcher.gui_manager.addSystem(ParticleSystem.system_id,"Particle System"); launcher.gui_manager.addSystem(AnimationSystem.system_id,"Animation System"); launcher.gui_manager.addSystem(DampingSystem.system_id,"Damping System"); launcher.gui_manager.addSystem(MoveToParentTargetSystem.system_id,"Move To Target System"); - launcher.gui_manager.addSystem(ParentOwnerSystem.system_id,"Parent Owner System System"); + launcher.gui_manager.addSystem(ParentOwnerSystem.system_id,"Parent Owner System"); launcher.gui_manager.addSystem(ShipWeaponSystem.system_id,"Ship Weapon System"); + launcher.gui_manager.addSystem(ParticleEmittingSystem.system_id,"Particle Emitting System"); + launcher.gui_manager.addSystem(RotateToTargetSystem.system_id,"Rotate To Target System"); + launcher.gui_manager.addSystem(ShipTargetSystem.system_id,"Ship Target System"); + launcher.gui_manager.addSystem(PartsDestroySystem.system_id,"Parts Destroy System"); + launcher.gui_manager.addSystem(ChildDestroySystem.system_id,"Child Destroy System"); + launcher.gui_manager.addSystem(ShootWaveSystem.system_id,"Shoot Wave System"); + //launcher.gui_manager.addSystem(SpawnUponDeathSystem.system_id,"Child Destroy System"); //launcher.manager.getSystem(CleanSystem.system_id).disable(); { @@ -2290,30 +2410,23 @@ void spaceInvadersStart() CShootDirection.component_id, CShootGrid.component_id, CGuild.component_id, CDamping.component_id, CChildren.component_id, CInit.component_id].staticArray ); - //CWeapon* weapon = space_invaders.ship_tmpl.getComponent!CWeapon; - //weapon.level = 3; - space_invaders.ship_tmpl.getComponent!CTexture().coords = vec4(0*px,80*px,48*px,32*px); + space_invaders.ship_tmpl.getComponent!CTexture().coords = vec4(0,80,48,32)*px; space_invaders.ship_tmpl.getComponent!CScale().value = vec2(48,32); - space_invaders.ship_tmpl.getComponent!CLocation().value = vec2(64,64); space_invaders.ship_tmpl.getComponent!CHitPoints().value = 1000; space_invaders.ship_tmpl.getComponent!CDamping().value = 7; space_invaders.ship_tmpl.getComponent!CInit().type = CInit.Type.space_ship; space_invaders.ship_tmpl.getComponent!CColliderScale().value = vec2(26,24); - launcher.manager.addEntity(space_invaders.ship_tmpl); + launcher.manager.addEntity(space_invaders.ship_tmpl,[CLocation(vec2(64,64)).ref_].staticArray); } { - ushort[6] components = [CLocation.component_id, CTexture.component_id, CVelocity.component_id, CScale.component_id, CLaser.component_id, CGuild.component_id]; + ushort[6] components = [CLocation.component_id, CTexture.component_id, CVelocity.component_id, CScale.component_id, CBullet.component_id, CGuild.component_id]; space_invaders.laser_tmpl = launcher.manager.allocateTemplate(components); - CTexture* tex_comp = space_invaders.laser_tmpl.getComponent!CTexture; - //tex_comp.tex = 0;//space_invaders.texture;//laser_tex; - tex_comp.coords = vec4(0*px,24*px,2*px,8*px); - CScale* scale_comp = space_invaders.laser_tmpl.getComponent!CScale; - scale_comp.value = vec2(2,8); - CVelocity* vel_comp = space_invaders.laser_tmpl.getComponent!CVelocity; - vel_comp.value = vec2(0,1); + space_invaders.laser_tmpl.getComponent!CTexture().coords = vec4(0,24,2,8)*px; + space_invaders.laser_tmpl.getComponent!CScale().value = vec2(2,8); + space_invaders.laser_tmpl.getComponent!CVelocity().value = vec2(0,1); } EntityTemplate* enemy_tmpl; @@ -2333,11 +2446,12 @@ void spaceInvadersStart() CDepth.component_id].staticArray ); - CTexture* tex_comp = boss_tmpl.getComponent!CTexture; + //CTexture* tex_comp = boss_tmpl.getComponent!CTexture; //tex_comp.tex = space_invaders.texture;//ship_tex; - tex_comp.coords = vec4(128*px,0*px,96*px,48*px); - CLocation* loc_comp = boss_tmpl.getComponent!CLocation; - loc_comp.value = vec2(64,space_invaders.map_size.y - 16); + //tex_comp.coords = vec4(128*px,0*px,96*px,48*px); + //CLocation* loc_comp = boss_tmpl.getComponent!CLocation; + //loc_comp.value = vec2(64,space_invaders.map_size.y - 16); + boss_tmpl.getComponent!CTexture().coords = vec4(128,0,96,48)*px; boss_tmpl.getComponent!CGuild().guild = 1; boss_tmpl.getComponent!CInit().type = CInit.Type.boss; boss_tmpl.getComponent!CScale().value = vec2(96,48); @@ -2354,11 +2468,7 @@ void spaceInvadersStart() CChildren.component_id].staticArray ); - CTexture* tex_comp = tower_tmpl.getComponent!CTexture; - //tex_comp.tex = space_invaders.texture;//ship_tex; - tex_comp.coords = vec4(96*px,96*px,16*px,16*px); - CLocation* loc_comp = tower_tmpl.getComponent!CLocation; - loc_comp.value = vec2(64,space_invaders.map_size.y - 16); + tower_tmpl.getComponent!CTexture().coords = vec4(96,96,16,16)*px; tower_tmpl.getComponent!CGuild().guild = 1; tower_tmpl.getComponent!CInit().type = CInit.Type.tower; tower_tmpl.getComponent!CHitPoints().value = 10; @@ -2373,35 +2483,29 @@ void spaceInvadersStart() CGuild.component_id].staticArray ); - CTexture* tex_comp = space_invaders.enemy_tmpl.getComponent!CTexture; - //tex_comp.tex = space_invaders.texture;//ship_tex; - tex_comp.coords = vec4(32*px,32*px,16*px,16*px); - CLocation* loc_comp = space_invaders.enemy_tmpl.getComponent!CLocation; - loc_comp.value = vec2(64,space_invaders.map_size.y - 16); - CShootDirection* shoot_dir_comp = space_invaders.enemy_tmpl.getComponent!CShootDirection; - shoot_dir_comp.direction = Direction.down; - CVelocity* vel_comp = space_invaders.enemy_tmpl.getComponent!CVelocity; - vel_comp.value = vec2(0.1,0); + space_invaders.enemy_tmpl.getComponent!CTexture().coords = vec4(32,32,16,16)*px; + space_invaders.enemy_tmpl.getComponent!CShootDirection().direction = Direction.down; + space_invaders.enemy_tmpl.getComponent!CVelocity().value = vec2(0.1,0); space_invaders.enemy_tmpl.getComponent!CGuild().guild = 1; space_invaders.enemy_tmpl.getComponent!CWeaponLocation().rel_pos = vec2(0,-15); Entity* current_entity; - current_entity = launcher.manager.addEntity(space_invaders.enemy_tmpl); + current_entity = launcher.manager.addEntity(space_invaders.enemy_tmpl,[CLocation(vec2(32,space_invaders.map_size.y - 16)).ref_].staticArray); launcher.manager.addComponents(current_entity.id,CSideMove(0)); - loc_comp.value = vec2(128,space_invaders.map_size.y - 16); - current_entity = launcher.manager.addEntity(space_invaders.enemy_tmpl); + //loc_comp.value = vec2(128,space_invaders.map_size.y - 16); + current_entity = launcher.manager.addEntity(space_invaders.enemy_tmpl,[CLocation(vec2(128,space_invaders.map_size.y - 16)).ref_].staticArray); launcher.manager.addComponents(current_entity.id,CSideMove(-1)); enemy_id = current_entity.id; //enemy_tmpl = launcher.manager.allocateTemplate(current_entity.id); - loc_comp.value = vec2(256,space_invaders.map_size.y - 16); - launcher.manager.addEntity(space_invaders.enemy_tmpl); + //loc_comp.value = vec2(256,space_invaders.map_size.y - 16); + launcher.manager.addEntity(space_invaders.enemy_tmpl,[CLocation(vec2(256,space_invaders.map_size.y - 16)).ref_].staticArray); - loc_comp.value = vec2(0,space_invaders.map_size.y - 16); - current_entity = launcher.manager.addEntity(space_invaders.enemy_tmpl); + //loc_comp.value = vec2(0,space_invaders.map_size.y - 16); + current_entity = launcher.manager.addEntity(space_invaders.enemy_tmpl,[CLocation(vec2(0,space_invaders.map_size.y - 16)).ref_].staticArray); launcher.manager.addComponents(current_entity.id,CSideMove(0)); grouped_id = current_entity.id; @@ -2412,11 +2516,8 @@ void spaceInvadersStart() { upgrade_tmpl = launcher.manager.allocateTemplate([CVelocity.component_id, CLocation.component_id, CTexture.component_id, CScale.component_id, CUpgrade.component_id, CAnimationLooped.component_id, CAnimation.component_id].staticArray); - CTexture* tex_comp = upgrade_tmpl.getComponent!CTexture; - //tex_comp.tex = space_invaders.texture;//ship_tex; - tex_comp.coords = vec4(0*px,32*px,16*px,16*px); - CVelocity* vel_comp = upgrade_tmpl.getComponent!CVelocity; - vel_comp.value = vec2(0,-0.1); + upgrade_tmpl.getComponent!CTexture().coords = vec4(0,32,16,16)*px; + upgrade_tmpl.getComponent!CVelocity().value = vec2(0,-0.1); *upgrade_tmpl.getComponent!CAnimation = CAnimation(HitPointsSystem.upgrade_laser_frames, 0, 0.75); } @@ -2425,6 +2526,24 @@ void spaceInvadersStart() enemy_tmpl = launcher.manager.allocateTemplate(enemy_id); grouped_tmpl = launcher.manager.allocateTemplate(grouped_id); + space_invaders.bullet_tmpl[0] = launcher.manager.allocateTemplate( + [CLocation.component_id, CTexture.component_id, CVelocity.component_id, + CScale.component_id, CBullet.component_id, CGuild.component_id].staticArray + ); + space_invaders.bullet_tmpl[0].getComponent!CTexture().coords = vec4(0,24,2,8)*px; + space_invaders.bullet_tmpl[0].getComponent!CScale().value = vec2(2,8); + + space_invaders.bullet_tmpl[1] = launcher.manager.allocateTemplate(space_invaders.bullet_tmpl[0]); + space_invaders.bullet_tmpl[2] = launcher.manager.allocateTemplate(space_invaders.bullet_tmpl[0]); + space_invaders.bullet_tmpl[2].getComponent!CTexture().coords = vec4(64,32,8,16)*px; + space_invaders.bullet_tmpl[2].getComponent!CScale().value = vec2(8,16); + space_invaders.bullet_tmpl[3] = launcher.manager.allocateTemplate(space_invaders.bullet_tmpl[0]); + space_invaders.bullet_tmpl[3].getComponent!CTexture().coords = vec4(56,32,2,2)*px; + space_invaders.bullet_tmpl[3].getComponent!CScale().value = vec2(2,2); + // bullet_tmpl[3].getComponent!CTexture().coords = vec4(48,32,8,8)*px; + // bullet_tmpl[3].getComponent!CScale().value = vec2(8,8); + space_invaders.bullet_tmpl[4] = launcher.manager.allocateTemplate(space_invaders.bullet_tmpl[0]); + launcher.gui_manager.addTemplate(enemy_tmpl,"Enemy"); launcher.gui_manager.addTemplate(grouped_tmpl,"Grouped enemy"); launcher.gui_manager.addTemplate(launcher.manager.allocateTemplate(space_invaders.ship_tmpl),"Ship"); @@ -2432,6 +2551,9 @@ void spaceInvadersStart() launcher.gui_manager.addTemplate(upgrade_tmpl,"Upgrade"); launcher.gui_manager.addTemplate(tower_tmpl,"Tower"); launcher.gui_manager.addTemplate(boss_tmpl,"Boss"); + launcher.gui_manager.addTemplate(launcher.manager.allocateTemplate(space_invaders.bullet_tmpl[3]),"Cannon bullet"); + //launcher.gui_manager.addTemplate(launcher.manager.allocateTemplate(space_invaders.bullet_tmpl[4]),"Laser"); + //launcher.gui_manager.addTemplate(launcher.manager.allocateTemplate(space_invaders.bullet_tmpl[5]),"Laser"); } void spaceInvadersEnd() @@ -2445,6 +2567,7 @@ void spaceInvadersEnd() //launcher.manager.freeTemplate(space_invaders.enemy_tmpl); Mallocator.dispose(space_invaders); + space_invaders = null; } void spaceInvadersTool(vec2 position, Tool tool, int size) diff --git a/demos/source/gui/manager.d b/demos/source/gui/manager.d index 185fcd1..4d452ad 100644 --- a/demos/source/gui/manager.d +++ b/demos/source/gui/manager.d @@ -30,6 +30,7 @@ struct GUIManager systems.clear(); templates.clear(); + selected_tempalte = 0; } EntityTemplate* getSelectedTemplate() From 2ad238841bb98048faddad9af63dd3f087b8a467 Mon Sep 17 00:00:00 2001 From: Mergul Date: Thu, 28 May 2020 16:41:58 +0200 Subject: [PATCH 150/217] Fixed .gitlab-ci.yml emscripten build --- .gitlab-ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index a2d26ff..376aead 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -76,7 +76,7 @@ emscripten: stage: build_emscripten image: "registry.gitlab.com/mergul/bubel-ecs/emscripten:latest" dependencies: - - build_code + - build_wasm script: - /bin/bash /build.sh rules: From 024356df9b0bd233eb59d7d19df37a9404a07473 Mon Sep 17 00:00:00 2001 From: Dawid Masiukiewicz Date: Thu, 28 May 2020 16:48:42 +0000 Subject: [PATCH 151/217] Common update: -added multiple new function to allocate template and add entity -updated README.md (complete initial version) -empty components now don't take memory -fixedd small bug with TestRunner -added many new tests (HashMap, Vector, EntityMeta, ...) -added default hashing function to HashMap -fixed critical bug with adding entities -fixed small bug with adding entity with remplacement components -added asserts into code to better bug detection -small performance improvement for events -added ComponentRef structure which contain data pointer and componentID -remove EntityID from Event structure -now events are handled before removing entiteis -fixed GDC compilation -fixed rendering of rotated sprites -added weapons as separate entities to space ship and others -added Tower enemy to SpaceInvaders demo -added Boss to SpaceInvaders demo (boss has four tower attached to it) -Boss towers shoot multiple bullets upon death -fixed critical bug with demos switching -fixed critical bug related to adding/removing entities form inside onAdd/onRemove entity callback -added animation support -added particles sypport and particles for firing and explostions, and more -multithreaded rendering now has same rendering order as singlethreaded -application automaticallu detect host CPU threads count -added upgrades to SPaceInvaders demo -fixed texture memory freeing -improved documentation -improved multithreaded performance -improve shader code -fixed registration issue -some additional performance improvements -added depth and colors to rendering parameters -jobs now has names corresponding to their systems -change execute() -> willExecute() -added EntityMeta structure to speedup getting fetching components form entity -improved multithreading rendering -added possibility tio change number of threads runtime -added bullets collision detection in SpaceInvaders demo -some CI changes -added VBO batch rendering (current default, no render mode switch yet) -fixed camera positioning calculation -fixed buffer issue with WebGL -added viewport scalling (at least 300 pixels height). Pixels are scalled if screen is bigger. -center demos gameplay area -added fullpage html template for Emscripten build -added many new sprites to atlas -fixed critical bug with CPU usage in multithreaded mode -snake render tile coresponding to body part -snake is destroyed after collision and emit some particles -added some functionality to vectors -fixed documentation issue in Manager.d -more minor code changes and cleanup --- .gitlab-ci.yml | 38 +- README.md | 182 +- codecov.yml | 9 +- demos/assets/shaders/base.fp | 45 +- demos/assets/shaders/base.vp | 67 +- demos/assets/textures/atlas.png | Bin 24668 -> 41948 bytes demos/dub.json | 3 + demos/external/sources/mmutils/thread_pool.d | 77 +- demos/source/app.d | 58 +- demos/source/demos/bullet_madnes.d | 10 +- demos/source/demos/chipmunk2d.d | 19 - demos/source/demos/events.d | 19 - demos/source/demos/flag_component.d | 19 - demos/source/demos/physics.d | 10 +- demos/source/demos/simple.d | 19 +- demos/source/demos/snake.d | 398 ++-- demos/source/demos/space_invaders.d | 2079 ++++++++++++++++-- demos/source/game_core/job_updater.d | 15 +- demos/source/gui/manager.d | 9 +- demos/source/gui/system.d | 2 +- demos/source/gui/template_.d | 2 +- demos/utils/source/ecs_utils/gfx/buffer.d | 2 +- demos/utils/source/ecs_utils/gfx/config.d | 4 +- demos/utils/source/ecs_utils/gfx/material.d | 2 +- demos/utils/source/ecs_utils/gfx/mesh.d | 2 +- demos/utils/source/ecs_utils/gfx/renderer.d | 405 +++- demos/utils/source/ecs_utils/gfx/shader.d | 2 +- demos/utils/source/ecs_utils/gfx/texture.d | 7 +- demos/utils/source/ecs_utils/gfx/vertex.d | 2 +- demos/utils/source/ecs_utils/math/vector.d | 65 + demos/utils/source/ecs_utils/utils.d | 14 +- dub.json | 14 +- meson.build | 30 +- source/bubel/ecs/atomic.d | 132 ++ source/{ => bubel}/ecs/attributes.d | 4 +- source/{ => bubel}/ecs/block_allocator.d | 26 +- source/{ => bubel}/ecs/core.d | 32 +- source/{ => bubel}/ecs/entity.d | 60 +- source/{ => bubel}/ecs/events.d | 81 +- source/{ => bubel}/ecs/hash_map.d | 203 +- source/{ => bubel}/ecs/id_manager.d | 92 +- source/{ => bubel}/ecs/manager.d | 1023 ++++++--- source/bubel/ecs/package.d | 10 + source/bubel/ecs/simple_vector.d | 77 + source/bubel/ecs/std.d | 363 +++ source/{ => bubel}/ecs/system.d | 37 +- source/{ => bubel}/ecs/traits.d | 2 +- source/{ => bubel}/ecs/vector.d | 183 +- source/ecs/atomic.d | 97 - source/ecs/package.d | 10 - source/ecs/simple_vector.d | 65 - source/ecs/std.d | 314 --- tests/access_perf.d | 135 ++ tests/basic.d | 403 +++- tests/bugs.d | 142 ++ tests/id_manager.d | 4 +- tests/map.d | 53 + tests/perf.d | 185 ++ tests/runner.d | 101 +- tests/tests.d | 14 +- tests/time.d | 66 + tests/vector.d | 48 +- 62 files changed, 5918 insertions(+), 1673 deletions(-) delete mode 100644 demos/source/demos/chipmunk2d.d delete mode 100644 demos/source/demos/events.d delete mode 100644 demos/source/demos/flag_component.d create mode 100644 source/bubel/ecs/atomic.d rename source/{ => bubel}/ecs/attributes.d (94%) rename source/{ => bubel}/ecs/block_allocator.d (82%) rename source/{ => bubel}/ecs/core.d (74%) rename source/{ => bubel}/ecs/entity.d (66%) rename source/{ => bubel}/ecs/events.d (67%) rename source/{ => bubel}/ecs/hash_map.d (61%) rename source/{ => bubel}/ecs/id_manager.d (75%) rename source/{ => bubel}/ecs/manager.d (79%) create mode 100644 source/bubel/ecs/package.d create mode 100644 source/bubel/ecs/simple_vector.d create mode 100644 source/bubel/ecs/std.d rename source/{ => bubel}/ecs/system.d (77%) rename source/{ => bubel}/ecs/traits.d (97%) rename source/{ => bubel}/ecs/vector.d (53%) delete mode 100644 source/ecs/atomic.d delete mode 100644 source/ecs/package.d delete mode 100644 source/ecs/simple_vector.d delete mode 100644 source/ecs/std.d create mode 100644 tests/access_perf.d create mode 100644 tests/bugs.d create mode 100644 tests/map.d create mode 100644 tests/perf.d create mode 100644 tests/time.d diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 14ba23c..376aead 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,3 +1,7 @@ +default: + artifacts: + expire_in: 1 day + stages: - build - test @@ -9,25 +13,18 @@ build_code: stage: build image: "registry.gitlab.com/mergul/bubel-ecs:latest" script: - - mkdir build - /bin/bash /compile_ecs.sh - - cp artifacts/* build/ - - cp -r public build/ artifacts: expire_in: 1h paths: - - build - rules: - - if: '$CI_MERGE_REQUEST_TARGET_BRANCH_NAME == "master"' - when: always - - when: always + - binaries allow_failure: true test_dmd_debug: stage: test image: frolvlad/alpine-glibc script: - - build/dmd_debug_unittest + - binaries/dmd_debug_unittest artifacts: reports: junit: test_report.xml @@ -35,7 +32,7 @@ test_dmd: stage: test image: frolvlad/alpine-glibc script: - - build/dmd_release_unittest + - binaries/dmd_release_unittest artifacts: reports: junit: test_report.xml @@ -43,7 +40,7 @@ test_dmd_betterC: stage: test image: frolvlad/alpine-glibc script: - - build/dmd_release_unittest_bc + - binaries/dmd_release_unittest_bc artifacts: reports: junit: test_report.xml @@ -56,15 +53,30 @@ coverage_test_dmd: - build_code script: - mkdir reports - - build/dmd_unittest_cov + - binaries/dmd_unittest_cov after_script: - bash <(curl -s https://codecov.io/bash) -s reports -t 1a0c0169-a721-4085-8252-fed4755dcd8c +build_wasm: + stage: build + image: "registry.gitlab.com/mergul/bubel-ecs:latest" + script: + - /bin/bash /compile_wasm.sh + - /bin/bash /gen_doc.sh + artifacts: + expire_in: 1h + paths: + - build + rules: + - if: '$CI_MERGE_REQUEST_TARGET_BRANCH_NAME == "master"' + when: always + allow_failure: true + emscripten: stage: build_emscripten image: "registry.gitlab.com/mergul/bubel-ecs/emscripten:latest" dependencies: - - build_code + - build_wasm script: - /bin/bash /build.sh rules: diff --git a/README.md b/README.md index d3f6816..b223f72 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,183 @@ -# Dynamic Entity Component System +# Bubel Entity Component System [![pipeline status](https://gitlab.com/Mergul/bubel-ecs/badges/master/pipeline.svg)](https://gitlab.com/Mergul/bubel-ecs/-/commits/master) [![codecov](https://codecov.io/gl/Mergul/bubel-ecs/branch/master/graph/badge.svg?token=Unm0TJhFoW)](https://codecov.io/gl/Mergul/bubel-ecs) -Entity-Component-System implementation in D language. +BubelECS is Entity-Component-System architectural pattern implementation in D language. +Library aims to delivery fast and flexible architecture for developing games. Library is **@nogc** and **betterC** compatible. WASM is supported thorugh Emscripten. +Project haven't any external dependencies. + +BubelECS was tested on Linux, Windows, Android and WASM. + +**Currently library is in beta stage so some significant API changes can appear.** + +## Design + +For core information about Entity-Component-System architectural pattern please read definition described at [Wikipedia](https://en.wikipedia.org/wiki/Entity_component_system). + +Main design principles are: + + * **Data oriented design** - components memory is packed into tight block so iterating over entity components is cache friendly + * **Fast and safe EntityID** - every entity is referenced by its unique ID. Accessing by ID is safe even if entity don'y exist. Access by ID is constant time operation. + * **Multithreading support** - whole library was developed with multithreading in mind. Adding components is thread-friendly so you get usable EntityID as early as possible. Operations like adding or removing components are deferred to end of frame. Dependencies between systems parallel execution are generated automatically. + * **Good logic separation** - system needs information only about components which it's use, there is no relation between systems. Systems can be compiled as multiple separate libraries and used together. + * **Flexible execution model** - system iterate over entities which meet specified conditions. Components can be marked as required, optional or excluded. Systems are exectued in specific order determined by system priority. + * **Builtin events handling** - library has builtin support for event handlig to makes easier communication between different entities. + * **Hot-reload** - hot-reloading for systems should be as easy as possible. In other words library should give functionality to support hot-reload of systems and components with minimal work. **(WIP!)**. + +There are some assumptions that should be considered when developing application: + + * Iterating over components is fastest way of access data so it's should be main way of making calculations. + * Using of direct access and events should be used very wisely and minimized. + * Direct component access is faster than events, because events must buffer memory and call multiple system handler callbacks. + * Components can be used to marking entities, assingment to systems and changing logic of entity in runtime. Using too much component based marking can lead to memory fragmentation and performence drop. + * Systems give great opporunity to separate game logic. Systems can be enabled and disabled easly in runtime. It's can be used to enabling some debug systems if needed. Additionaly this concept makes game logic changes easier to deal with. If you develop your application wisely it should be trivial to change some core logic by changing only several systems or adding some new systems. Every entity can easily takes some behaviour from different entity type by adding several components. + +### Features + + * ECS architectural pattern + * Data oriented design + * Safe identifiers (EntityID) + * EntityTemplates + * Basic events handling + * Easy systems ordering + * Automatic multithreaded jobs generating + * Runtime and fast components adding and removing + * Listeners for adding and removing entity components inside systems + * Update passes + * Calling custom callbacks for system entity groups + * betterC compatibility + * Emscripten compatibility + +### Planned + + * Worlds - every world works as separate environment. Entities don't with entities from different world. Systems and components should be registered for every world separately. + * Hot-reload support - currently only reloading systems (their functions) works. There is possibility to serialize every entity and system, but it's should be provided by library itself with special callbacks and helpers. Additionaly planned is system which helps with taking new EntityID from serialized identifiers. + * External dependencies - ability to provide dependencies between system which isn't related to components. + * Static components - this components will have different memory model and can be accessed only directly. It will be slower to access but won't trigger memory copy when component is added. It should fix problem with big components which isn't needed by systems iteration callbacks or is required rarely. + * Better EventManager - there are several optimization and improvements that can be added in the future. + * More demos and examples - demo appliaction is very basic now, but in future more minigames and sanbox mode (opportunity to mix many components and systems) are planned. + * C API - in highly depends on amount of work required. Makes possible to use library from different languages. + * GPU compute - idea in draft stage. Special components and systems whose data wolud be on GPU memory. + * More smaller improvements... + +For more information about design and usage feel free to read [documentation](https://mergul.gitlab.io/bubel-ecs/ecs.html)**(WIP)** and [WIKI](https://gitlab.com/Mergul/bubel-ecs/-/wikis/home). + +## Build Instructions + +To build library you needs recent D compiler and optionally Emscripten (with python) to build web version. Currenlty tested are: LDC, DMD and GDC. \ +Supported build systems are DUB and Meson. + +##### DUB +```shell +#available configurations: library, dynlib, library-betterC, dynlib-betterC +dub build -c library -b release +``` + +##### Meson +```shell +#use '-DbetterC=true ' to build betterC code +meson build . #add '--buildtype=release' to build release code +cd build +ninja +``` + +##### Emscripten +```shell +python compile_wasm.py -opt +``` + +##### Documentation +```shell +adrdox -i source/bubel/ecs/ -o docs/ -s skeleton.html +``` + +For more detailed build options please check documentation for used build system. + +## Demos + +Repository contain demo application. You can check demo [online](https://mergul.gitlab.io/bubel-ecs/ecs_demo.html) or build it form source code using DUB. \ +Online demo support multithreading and page tries to check if client support WASM multithreading or not and loads properly JS and WASM code. It was tested on Chrome, Firefox, Opera, Brave on Linux and Android. On firefox there is problem with multithreaded version so if demo don't works please try to disable shared_memory in browser flags. + +## Code example + +```d + +struct Position +{ + mixin ECS.Components; //makes struct component + float x; + float y; +} + +struct Velocity +{ + mixin ECS.Components; + //default values works + float x = 0.1; + float y = 1; +} + +struct StaticFlag +{ + mixin ECS.Components; +} + +struct UpdateSystem +{ + mixin ECS.System; //makes struct system + + ECS.ExcludedComponents!(StaticFlag); //prevents static entities from update + + struct EntitiesData + { + int length; //entities count + @readonly Entity[] entities; //entities arrays, entity contain ID only + Position[] positions; //positions array + @readonly Velocity[] velocities; //veocities array, readonly (Multithreading tag) + } + + void onUpdate(EntitiesData data) //update callback, called multiple times per frame for every entities types + { + foreach(i; 0..data.length) //iterate over entities + { + data.positions[i].x += data.velocities[i].x * dt; + data.positions[i].y += data.velocities[i].y * dt; + } + } +} + +void main() +{ + manager.beginRegister(); + //register components + manager.registerComponent!Position; + manager.registerComponent!Velocity; + manager.registerComponent!StaticFlag; + //register system with priority 0 + manager.registerSystem!UpdateSystem(0); + manager.endRegister(); + + //allocate template + EntityTemplate* tmpl = manager.allocateEmplate([Velocity.component_id, Position.component_id].staticArray); + scope (exit) manager.freeTemplate(tmpl); + + //gets pointer to template component data + Position* position = tmpl.getComponent!Position; + foreach(i; 0 .. 100) + { + position.x = i % 10; + position.y = i / 10; + manager.addEntity(tmpl); + } + + manager.begin(); //start frame + manager.update(); //update all systems, there onUpdate callbacks are called + manager.end(); //end frame +} + +``` + +## Links + +Documentation: https://mergul.gitlab.io/bubel-ecs/ecs.html \ +Online demo: https://mergul.gitlab.io/bubel-ecs/ecs_demo.html diff --git a/codecov.yml b/codecov.yml index a6afdbc..5672706 100644 --- a/codecov.yml +++ b/codecov.yml @@ -1,3 +1,10 @@ ignore: - "tests/*" - - "**/traits*" \ No newline at end of file + - "**/traits*" + +coverage: + status: + project: + default: + threshold: 5 + patch: off \ No newline at end of file diff --git a/demos/assets/shaders/base.fp b/demos/assets/shaders/base.fp index 043fa58..d86e92e 100644 --- a/demos/assets/shaders/base.fp +++ b/demos/assets/shaders/base.fp @@ -3,6 +3,31 @@ precision mediump float; precision lowp sampler2D; precision lowp samplerCube; + +#ifdef GLES + #define TEX(x,y) texture2D(x,y) + #if __VERSION__ >290 + #define M_IN in mediump + #define L_IN in lowp + #else + #define M_IN varying mediump + #define L_IN varying lowp + #endif +#else + #define TEX(x,y) texture(x,y) + #if __VERSION__ > 320 + #define M_IN in + #define L_IN in + #else + #define M_IN varying + #define L_IN varying + #endif +#endif + + +M_IN vec2 uv; +M_IN vec4 color; +/* #ifdef GLES #if __VERSION__ >290 in mediump vec2 uv; @@ -15,7 +40,7 @@ precision lowp samplerCube; #else varying vec2 uv; #endif -#endif +#endif*/ //layout(binding = 0)uniform sampler2D tex; @@ -23,20 +48,8 @@ uniform sampler2D tex; //layout(location = 0) out vec4 outColor; -void main() { - - #ifdef GLES - #if __VERSION__ >290 - gl_FragColor = texture(tex,uv); - #else - gl_FragColor = texture2D(tex,uv); - #endif - #else - #if __VERSION__ > 320 - gl_FragColor = texture(tex,uv); - #else - gl_FragColor = texture2D(tex,uv); - #endif - #endif +void main() +{ + gl_FragColor = TEX(tex,uv) * color; if(gl_FragColor.a < 0.01)discard; } diff --git a/demos/assets/shaders/base.vp b/demos/assets/shaders/base.vp index 42ed4a7..6c4c183 100644 --- a/demos/assets/shaders/base.vp +++ b/demos/assets/shaders/base.vp @@ -2,12 +2,37 @@ precision highp float; precision highp int; precision lowp sampler2D; precision lowp samplerCube; - #ifdef GLES #if __VERSION__ >290 - layout(location = 0) uniform vec4 matrix_1; - layout(location = 1) uniform vec4 matrix_2; - layout(location = 2) uniform vec4 uv_transform; + #define LOC(x) layout(location = x) + #define ATT in + #define M_OUT out mediump + #define L_OUT out lowp + #else + #define LOC(x) + #define ATT attribute + #define M_OUT varying mediump + #define L_OUT varying lowp + #endif +#else + #if __VERSION__ > 320 + #define LOC(x) layout(location = x) + #define ATT in + #define M_OUT out + #define L_OUT out + #else + #define LOC(x) + #define ATT attribute + #define M_OUT varying + #define L_OUT varying + #endif +#endif +/* +#ifdef GLES + #if __VERSION__ >290 + uniform vec4 matrix_1; + uniform vec4 matrix_2; + uniform vec4 uv_transform; layout(location = 0) in vec2 positions; layout(location = 1) in vec2 tex_coords; @@ -43,13 +68,39 @@ precision lowp samplerCube; varying vec2 uv; #endif +#endif*/ + +#define VBO_BATCH 1 + +M_OUT vec2 uv; +L_OUT vec4 color; + +LOC(0) ATT vec2 positions; +LOC(1) ATT vec2 tex_coords; + +#ifdef VBO_BATCH + LOC(2) ATT float depth; + LOC(3) ATT vec4 vcolor; +#else + uniform vec4 matrix_1; + uniform vec4 matrix_2; + uniform vec4 uv_transform; + uniform vec4 vcolor; + + float depth = matrix_2.z; #endif void main() { + #ifdef VBO_BATCH + vec3 position = vec3(positions*4.0,1.0); + uv = tex_coords; + #else + vec3 position = mat3(matrix_1.x,matrix_1.y,0,matrix_1.z,matrix_1.w,0,matrix_2.xy,1.0) * vec3(positions,1.0); + uv = tex_coords * uv_transform.zw + uv_transform.xy; + #endif - vec3 position = mat3(matrix_1.x,matrix_1.y,0,matrix_1.z,matrix_1.w,0,matrix_2.xy,1) * vec3(positions,1.0); - uv = tex_coords * uv_transform.zw + uv_transform.xy; - - gl_Position = vec4(position.xy,0,1.0); + color = vcolor * 2.0; + + gl_Position = vec4(position.xy,depth,1.0); } diff --git a/demos/assets/textures/atlas.png b/demos/assets/textures/atlas.png index c628969c0e7149419eb62313fb5c3274457838f3..a799eb7706feddc336f6f1e6e75f780dcbea5467 100644 GIT binary patch literal 41948 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 literal 24668 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 diff --git a/demos/dub.json b/demos/dub.json index 43d248c..1c1fe65 100644 --- a/demos/dub.json +++ b/demos/dub.json @@ -18,6 +18,9 @@ "libs-windows-x86_64": ["libs/windows/x64/SDL2","libs/windows/x64/SDL2_Image","libs/windows/x64/cimgui"], "libs-linux-x86_64": ["cimgui","SDL2","SDL2_image"], "lflags-linux-x86_64": ["-rpath=libs/linux/x64/","-Llibs/linux/x64/"], + "dflags-ldc" : [ + "--ffast-math" + ], "configurations" : [ { "name" : "default", diff --git a/demos/external/sources/mmutils/thread_pool.d b/demos/external/sources/mmutils/thread_pool.d index 374fbc1..52136d4 100644 --- a/demos/external/sources/mmutils/thread_pool.d +++ b/demos/external/sources/mmutils/thread_pool.d @@ -1,6 +1,6 @@ module mmutils.thread_pool; -import ecs.atomic; +import bubel.ecs.atomic; //import core.stdc.stdio; //import core.stdc.stdlib : free, malloc, realloc; @@ -16,6 +16,7 @@ version (Posix)version = MM_USE_POSIX_THREADS; version (WebAssembly) { + version = MM_NO_LOGS; extern(C) struct FILE { @@ -32,7 +33,7 @@ else version (D_BetterC) { - import ecs.std; + import bubel.ecs.std; extern (C) __gshared int _d_eh_personality(int, int, size_t, void*, void*) { return 0; @@ -181,6 +182,12 @@ void instructionPause() __builtin_ia32_pause(); } + else version(GNU) + { + import gcc.builtins; + + __builtin_ia32_pause(); + } else version (DigitalMars) { asm @@ -188,7 +195,6 @@ void instructionPause() rep; nop; } - } else { @@ -799,6 +805,7 @@ struct ThreadPool alias FlushLogsDelegaste = void delegate(ThreadData* threadData, JobLog[] logs); /// Type of delegate to flush logs FlushLogsDelegaste onFlushLogs; /// User custom delegate to flush logs, if overriden defaultFlushLogs will be used. Can be sset after initialize() call int logsCacheNum; /// Number of log cache entries. Should be set before setThreadsNum is called + int tryWaitCount = 2000; ///Number of times which tryWait are called before timedWait call. Higher value sets better response but takes CPU time even if there are no jobs. private: ThreadData*[gMaxThreadsNum] threadsData; /// Data for threads align(64) shared int threadsNum; /// Number of threads currentlu accepting jobs @@ -808,6 +815,46 @@ private: JobData[4] resumeJobs; /// Dummu jobs to resume some thread public: + + static int getCPUCoresCount() + { + version(Windows) + { + import core.sys.windows.winbase : SYSTEM_INFO, GetSystemInfo; + SYSTEM_INFO sysinfo; + GetSystemInfo(&sysinfo); + return sysinfo.dwNumberOfProcessors; + } + else version (linux) + { + version(D_BetterC) + { + import core.sys.posix.unistd : _SC_NPROCESSORS_ONLN, sysconf; + return cast(int)sysconf(_SC_NPROCESSORS_ONLN); + } + else + { + import core.sys.linux.sched : CPU_COUNT, cpu_set_t, sched_getaffinity; + import core.sys.posix.unistd : _SC_NPROCESSORS_ONLN, sysconf; + + cpu_set_t set = void; + if (sched_getaffinity(0, cpu_set_t.sizeof, &set) == 0) + { + int count = CPU_COUNT(&set); + if (count > 0) + return cast(uint) count; + } + return cast(int)sysconf(_SC_NPROCESSORS_ONLN); + } + } + else version(Posix) + { + import core.sys.posix.unistd; + return cast(int)sysconf(_SC_NPROCESSORS_ONLN); + } + else return -1; + } + int jobsDoneCount() { int sum; @@ -1141,17 +1188,19 @@ public: foreach (ref log; logs) { - size += log.name.length; // size of name + size += log.name.length + 1; // size of name } char* buffer = cast(char*) malloc(size); foreach (ref log; logs) { - + char[100] name_buffer; + name_buffer[0 .. log.name.length] = log.name; + name_buffer[log.name.length] = 0; size_t charWritten = snprintf(buffer + used, size - used, `{"name":"%s", "pid":1, "tid":%lld, "ph":"X", "ts":%lld, "dur":%lld }, %s`, - log.name.ptr, threadData.threadId + 1, log.time, log.duration, "\n".ptr); + name_buffer.ptr, threadData.threadId + 1, log.time, log.duration, "\n".ptr); used += charWritten; } @@ -1447,7 +1496,21 @@ private void threadFunc(ThreadData* threadData) if (data is null) { // Thread does not have own job and can not steal it, so wait for a job - bool ok = threadData.semaphore.timedWait(1_000 + !acceptJobs * 10_000); + int tryWait = 0; + //bool ok = threadData.semaphore.timedWait(1_000 + !acceptJobs * 10_000); + bool ok = true; + while(!threadData.semaphore.tryWait()) + { + tryWait++; + if(tryWait>threadPool.tryWaitCount) + { + ok = false; + break; + } + static foreach(i;0..10)instructionPause(); + } + if(!ok)ok = threadData.semaphore.timedWait(1_000 + !acceptJobs * 10_000); + if (ok) { diff --git a/demos/source/app.d b/demos/source/app.d index 150d653..ede93b5 100644 --- a/demos/source/app.d +++ b/demos/source/app.d @@ -6,9 +6,9 @@ import cimgui.cimgui; import game_core.job_updater; -import ecs.manager; -import ecs.core; -import ecs.std; +import bubel.ecs.manager; +import bubel.ecs.core; +import bubel.ecs.std; import ecs_utils.gfx.renderer; import ecs_utils.imgui_bind; @@ -58,6 +58,7 @@ struct Launcher uint style = 3; uint entities_count; bool multithreading; + int threads = 1; ulong timer_freq; double delta_time; uint fps; @@ -95,6 +96,7 @@ struct Launcher void switchDemo(void function() start, bool function() loop, void function() end, void function(SDL_Event*) event, void function(vec2, Tool, int) tool, const (char)* tips) { gui_manager.clear(); + //launcher.ent if(this.end)this.end(); @@ -102,6 +104,14 @@ struct Launcher manager.update("clean"); manager.end(); + foreach(ref system; manager.systems) + { + if(system.id != CountSystem.system_id && system.id != CleanSystem.system_id)system.disable(); + } + + /*launcher.manager.getSystem(CountSystem.system_id).enable(); + launcher.manager.getSystem(CleanSystem.system_id).enable();//*/ + if(start)start(); this.loop = loop; this.end = end; @@ -259,7 +269,6 @@ void mainLoop(void* arg) launcher.repeat_time -= range; launcher.tool((launcher.mouse.position*launcher.scalling)-launcher.render_position, launcher.used_tool, launcher.tool_size); } - } version(WebAssembly) @@ -316,6 +325,22 @@ void mainLoop(void* arg) if(igMenuItemBool("Multithreading", null, launcher.multithreading, true)) { launcher.multithreading = !launcher.multithreading; + if(launcher.multithreading) + { + launcher.job_updater.pool.setThreadsNum(launcher.threads); + } + else + { + launcher.job_updater.pool.setThreadsNum(1); + } + } + igSetNextItemWidth(0); + igLabelText("Threads:",null); + igSameLine(0,4); + if(igSliderInt("##Threads",&launcher.threads, 1, 32, null))//"Multithreading", null, launcher.multithreading, true)) + { + launcher.job_updater.pool.setThreadsNum(launcher.threads); + //launcher.threads = !launcher.multithreading; } if(igBeginMenu("Show",true)) { @@ -439,7 +464,7 @@ void mainLoop(void* arg) if(launcher.show_demo_wnd) { igSetNextWindowPos(ImVec2(launcher.window_size.x - 260, 30), ImGuiCond_Once, ImVec2(0,0)); - igSetNextWindowSize(ImVec2(250, 250), ImGuiCond_Once); + igSetNextWindowSize(ImVec2(250, 500), ImGuiCond_Once); if(igBegin("Demo",&launcher.show_demo_wnd,0)) { ImDrawList* draw_list = igGetWindowDrawList(); @@ -539,11 +564,14 @@ void mainLoop(void* arg) launcher.renderer.clear(); double loop_time = launcher.getTime(); + launcher.job_updater.pool.tryWaitCount = 10000; if(launcher.loop && !launcher.loop()) { quit(); *cast(bool*)arg = false; } + launcher.job_updater.pool.tryWaitCount = 0; + loop_time = launcher.getTime() - loop_time; double draw_time = launcher.getTime(); @@ -686,10 +714,10 @@ int main(int argc, char** argv) setStyle(3); - launcher.job_updater = Mallocator.make!ECSJobUpdater(12); + launcher.job_updater = Mallocator.make!ECSJobUpdater(1); //launcher.job_updater.onCreate(); - EntityManager.initialize(12); + EntityManager.initialize(32, 1<<16); launcher.manager = EntityManager.instance; //launcher.manager.m_thread_id_func = &launcher.job_updater.getThreadID; @@ -709,10 +737,16 @@ int main(int argc, char** argv) launcher.renderer.initialize(); + import mmutils.thread_pool : ThreadPool; + launcher.threads = ThreadPool.getCPUCoresCount(); + if(launcher.threads < 2)launcher.threads = 2; + launcher.gui_manager = Mallocator.make!GUIManager(); { import demos.simple; + import demos.space_invaders; + // launcher.switchDemo(&spaceInvadersStart,&spaceInvadersLoop,&spaceInvadersEnd,&spaceInvadersEvent,&spaceInvadersTool,SpaceInvaders.tips); launcher.switchDemo(&simpleStart,&simpleLoop,&simpleEnd,&simpleEvent,&simpleTool,Simple.tips); } @@ -741,6 +775,8 @@ int main(int argc, char** argv) } } + EntityManager.destroy(); + return 0; } @@ -785,7 +821,15 @@ void loadGFX() GfxConfig.materials[0].compile(); GfxConfig.materials[0].bindAttribLocation("positions",0); GfxConfig.materials[0].bindAttribLocation("tex_coords",1); + GfxConfig.materials[0].bindAttribLocation("depth",2); + GfxConfig.materials[0].bindAttribLocation("vcolor",3); GfxConfig.materials[0].link(); + + /* import std.stdio; + writeln("positions ",glGetAttribLocation(GfxConfig.materials[0].data.modules[0].gl_handle,"positions")); + writeln("tex_coords ",glGetAttribLocation(GfxConfig.materials[0].data.modules[0].gl_handle,"tex_coords")); + writeln("depth ",glGetAttribLocation(GfxConfig.materials[0].data.modules[0].gl_handle,"depth")); + writeln("vcolor ",glGetAttribLocation(GfxConfig.materials[0].data.modules[0].gl_handle,"vcolor"));*/ GfxConfig.materials[0].data.uniforms = Mallocator.makeArray!(Material.Uniform)(3); GfxConfig.materials[0].data.uniforms[0] = Material.Uniform(Material.Type.float4, GfxConfig.materials[0].getLocation("matrix_1"), 0); diff --git a/demos/source/demos/bullet_madnes.d b/demos/source/demos/bullet_madnes.d index 0996e2e..420d6a3 100644 --- a/demos/source/demos/bullet_madnes.d +++ b/demos/source/demos/bullet_madnes.d @@ -6,11 +6,11 @@ import bindbc.sdl; import cimgui.cimgui; -import ecs.attributes; -import ecs.core; -import ecs.entity; -import ecs.manager; -import ecs.std; +import bubel.ecs.attributes; +import bubel.ecs.core; +import bubel.ecs.entity; +import bubel.ecs.manager; +import bubel.ecs.std; import ecs_utils.gfx.texture; import ecs_utils.math.vector; diff --git a/demos/source/demos/chipmunk2d.d b/demos/source/demos/chipmunk2d.d deleted file mode 100644 index 25b9c66..0000000 --- a/demos/source/demos/chipmunk2d.d +++ /dev/null @@ -1,19 +0,0 @@ -module demos.chipmunk2d; - -import app; - -import bindbc.sdl; - -import cimgui.cimgui; - -import ecs.attributes; -import ecs.core; -import ecs.entity; -import ecs.manager; -import ecs.std; - -import ecs_utils.gfx.texture; -import ecs_utils.math.vector; -import ecs_utils.utils; - -extern(C): \ No newline at end of file diff --git a/demos/source/demos/events.d b/demos/source/demos/events.d deleted file mode 100644 index 620ff4d..0000000 --- a/demos/source/demos/events.d +++ /dev/null @@ -1,19 +0,0 @@ -module demos.events; - -import app; - -import bindbc.sdl; - -import cimgui.cimgui; - -import ecs.attributes; -import ecs.core; -import ecs.entity; -import ecs.manager; -import ecs.std; - -import ecs_utils.gfx.texture; -import ecs_utils.math.vector; -import ecs_utils.utils; - -extern(C): \ No newline at end of file diff --git a/demos/source/demos/flag_component.d b/demos/source/demos/flag_component.d deleted file mode 100644 index a1863b9..0000000 --- a/demos/source/demos/flag_component.d +++ /dev/null @@ -1,19 +0,0 @@ -module demos.flag_component; - -import app; - -import bindbc.sdl; - -import cimgui.cimgui; - -import ecs.attributes; -import ecs.core; -import ecs.entity; -import ecs.manager; -import ecs.std; - -import ecs_utils.gfx.texture; -import ecs_utils.math.vector; -import ecs_utils.utils; - -extern(C): \ No newline at end of file diff --git a/demos/source/demos/physics.d b/demos/source/demos/physics.d index 6e9ba4a..5fccc0b 100644 --- a/demos/source/demos/physics.d +++ b/demos/source/demos/physics.d @@ -6,11 +6,11 @@ import bindbc.sdl; import cimgui.cimgui; -import ecs.attributes; -import ecs.core; -import ecs.entity; -import ecs.manager; -import ecs.std; +import bubel.ecs.attributes; +import bubel.ecs.core; +import bubel.ecs.entity; +import bubel.ecs.manager; +import bubel.ecs.std; import ecs_utils.gfx.texture; import ecs_utils.math.vector; diff --git a/demos/source/demos/simple.d b/demos/source/demos/simple.d index edd20c6..313cc00 100644 --- a/demos/source/demos/simple.d +++ b/demos/source/demos/simple.d @@ -6,11 +6,11 @@ import bindbc.sdl; import cimgui.cimgui; -import ecs.attributes; -import ecs.core; -import ecs.entity; -import ecs.manager; -import ecs.std; +import bubel.ecs.attributes; +import bubel.ecs.core; +import bubel.ecs.entity; +import bubel.ecs.manager; +import bubel.ecs.std; import ecs_utils.gfx.texture; import ecs_utils.math.vector; @@ -47,22 +47,27 @@ struct CTexture struct DrawSystem { - mixin ECS.System!1; + mixin ECS.System!32; struct EntitiesData { uint length; + //uint thread_id; + uint job_id; @readonly CTexture[] textures; @readonly CLocation[] locations; } void onUpdate(EntitiesData data) { + if(launcher.renderer.prepared_items >= launcher.renderer.MaxObjects)return;//simple leave loop if max visible objects count was reached foreach(i; 0..data.length) { - launcher.renderer.draw(data.textures[i].tex, data.locations[i].location, vec2(16,16), vec4(0,0,1,1), 0, 0 , 0); + launcher.renderer.draw(data.textures[i].tex, data.locations[i].location, vec2(16,16), vec4(0,0,1,1), cast(ushort)(data.locations[i].y), 0x80808080, 0, 0, 0, data.job_id); + // launcher.renderer.draw(data.textures[i].tex, data.locations[i].location, vec2(16,16), vec4(0,0,1,1), 0, 0x80808080, 0, 0, 0, data.job_id); //draw(renderer, data.textures[i].tex, data.locations[i], vec2(32,32), vec4(0,0,1,1)); } + //if(data.thread_id == 0)launcher.renderer.pushData(); } } diff --git a/demos/source/demos/snake.d b/demos/source/demos/snake.d index 6bb8cef..01e9a36 100644 --- a/demos/source/demos/snake.d +++ b/demos/source/demos/snake.d @@ -6,18 +6,18 @@ import bindbc.sdl; import cimgui.cimgui; -import ecs.attributes; -import ecs.core; -import ecs.entity; -import ecs.manager; -import ecs.std; -import ecs.vector; +import bubel.ecs.attributes; +import bubel.ecs.core; +import bubel.ecs.entity; +import bubel.ecs.manager; +import bubel.ecs.std; +import bubel.ecs.vector; import ecs_utils.gfx.texture; import ecs_utils.math.vector; import ecs_utils.utils; -import std.array : staticArray; +//import std.array : staticArray; enum float px = 1.0/512.0; @@ -30,8 +30,9 @@ struct MapElement empty = 0, apple = 1, wall = 2, + snake = 3, - snake_head_up = 5, + /* snake_head_up = 5, snake_head_down = 6, snake_head_left = 7, snake_head_right = 8, @@ -44,13 +45,31 @@ struct MapElement snake_turn_rd = 15, snake_turn_ru = 16, snake_vertical = 17, - snake_horizontal = 18 + snake_horizontal = 18*/ } Type type; EntityID id; } +enum SnakePart : ubyte +{ + head_up = 0, + head_down = 1, + head_left = 2, + head_right = 3, + tail_up = 4, + tail_down = 5, + tail_left = 6, + tail_right = 7, + turn_ld = 8, + turn_lu = 9, + turn_rd = 10, + turn_ru = 11, + vertical = 12, + horizontal = 13 +} + struct Snake { __gshared const (char)* tips = "Use \"WASD\" keys to move."; @@ -71,6 +90,16 @@ struct Snake MapElement[map_size * map_size] map; + ~this() @nogc nothrow + { + if(snake_destroy_particle_frames)Mallocator.dispose(snake_destroy_particle_frames); + if(smoke_frames)Mallocator.dispose(smoke_frames); + if(apple_tmpl)launcher.manager.freeTemplate(apple_tmpl); + if(snake_tmpl)launcher.manager.freeTemplate(snake_tmpl); + if(snake_destroy_particle)launcher.manager.freeTemplate(snake_destroy_particle); + texture.destory(); + } + MapElement element(ivec2 pos) { uint index = pos.x + pos.y * map_size; @@ -100,43 +129,11 @@ struct Snake } if(base_pos.x == random_pos.x && base_pos.y == random_pos.y)return; } - CILocation* location = apple_tmpl.getComponent!CILocation; - *location = random_pos; - Entity* apple = launcher.manager.addEntity(apple_tmpl); + //CILocation* location = apple_tmpl.getComponent!CILocation; + //*location = random_pos; + //Entity* apple = + launcher.manager.addEntity(apple_tmpl,[CILocation(random_pos).ref_].staticArray); } - - void drawMap() - { - foreach(x; 0 .. map_size) - { - foreach(y; 0 .. map_size) - { - switch(element(ivec2(x,y)).type) - { - case MapElement.Type.apple:launcher.renderer.draw(texture, vec2(x*16,y*16), vec2(16,16), vec4(0,32*px,16*px,16*px), 0, 0 , 0);break; - - case MapElement.Type.snake_head_up:launcher.renderer.draw(texture, vec2(x*16,y*16), vec2(16,16), vec4(48*px,112*px,16*px,16*px), 0, 0 , 0);break; - case MapElement.Type.snake_head_down:launcher.renderer.draw(texture, vec2(x*16,y*16), vec2(16,16), vec4(48*px,144*px,16*px,16*px), 0, 0 , 0);break; - case MapElement.Type.snake_head_left:launcher.renderer.draw(texture, vec2(x*16,y*16), vec2(16,16), vec4(0,128*px,16*px,16*px), 0, 0 , 0);break; - case MapElement.Type.snake_head_right:launcher.renderer.draw(texture, vec2(x*16,y*16), vec2(16,16), vec4(32*px,128*px,16*px,16*px), 0, 0 , 0);break; - case MapElement.Type.snake_tail_up:launcher.renderer.draw(texture, vec2(x*16,y*16), vec2(16,16), vec4(16*px,112*px,16*px,16*px), 0, 0 , 0);break; - case MapElement.Type.snake_tail_down:launcher.renderer.draw(texture, vec2(x*16,y*16), vec2(16,16), vec4(0,112*px,16*px,16*px), 0, 0 , 0);break; - case MapElement.Type.snake_tail_left:launcher.renderer.draw(texture, vec2(x*16,y*16), vec2(16,16), vec4(32*px,112*px,16*px,16*px), 0, 0 , 0);break; - case MapElement.Type.snake_tail_right:launcher.renderer.draw(texture, vec2(x*16,y*16), vec2(16,16), vec4(0,144*px,16*px,16*px), 0, 0 , 0);break; - case MapElement.Type.snake_turn_ld:launcher.renderer.draw(texture, vec2(x*16,y*16), vec2(16,16), vec4(64*px,128*px,16*px,16*px), 0, 0 , 0);break; - case MapElement.Type.snake_turn_lu:launcher.renderer.draw(texture, vec2(x*16,y*16), vec2(16,16), vec4(32*px,144*px,16*px,16*px), 0, 0 , 0);break; - case MapElement.Type.snake_turn_rd:launcher.renderer.draw(texture, vec2(x*16,y*16), vec2(16,16), vec4(16*px,144*px,16*px,16*px), 0, 0 , 0);break; - case MapElement.Type.snake_turn_ru:launcher.renderer.draw(texture, vec2(x*16,y*16), vec2(16,16), vec4(64*px,112*px,16*px,16*px), 0, 0 , 0);break; - case MapElement.Type.snake_vertical:launcher.renderer.draw(texture, vec2(x*16,y*16), vec2(16,16), vec4(16*px,128*px,16*px,16*px), 0, 0 , 0);break; - case MapElement.Type.snake_horizontal:launcher.renderer.draw(texture, vec2(x*16,y*16), vec2(16,16), vec4(48*px,128*px,16*px,16*px), 0, 0 , 0);break; - - case MapElement.Type.wall:launcher.renderer.draw(texture, vec2(x*16,y*16), vec2(16,16), vec4(0,0,1,1), 0, 0 , 0);break; - default:break; - } - } - } - } - } struct Animation @@ -184,6 +181,7 @@ struct CSnake mixin ECS.Component; + struct Parts { uint length = 0; @@ -217,6 +215,7 @@ struct CSnake } Parts parts; + CMovement.Direction direction; } struct CApple @@ -287,7 +286,7 @@ struct ParticleSystem { uint length; @readonly Entity[] entities; - @readonly CParticle[] particle; + CParticle[] particle; } void onUpdate(EntitiesData data) @@ -358,7 +357,7 @@ struct AnimationRenderSystem { foreach(i;0..data.length) { - launcher.renderer.draw(snake.texture, cast(vec2)cast(ivec2)data.location[i].location, vec2(16,16), data.animation[i].frames[cast(int)(data.animation[i].time)], 0, 0 , 0); + launcher.renderer.draw(snake.texture, cast(vec2)cast(ivec2)data.location[i].location, vec2(16,16), data.animation[i].frames[cast(int)(data.animation[i].time)], -1, 0x80808080); } } } @@ -368,8 +367,8 @@ struct MoveSystem mixin ECS.System!64; EntityTemplate* destroy_template; - CLocation* destroy_location; - CParticleVector* destroy_vector; + //CLocation* destroy_location; + //CParticleVector* destroy_vector; struct EntitiesData { @@ -383,8 +382,8 @@ struct MoveSystem void setTemplates() { destroy_template = snake.snake_destroy_particle; - destroy_location = destroy_template.getComponent!CLocation; - destroy_vector = destroy_template.getComponent!CParticleVector; + //destroy_location = destroy_template.getComponent!CLocation; + //destroy_vector = destroy_template.getComponent!CParticleVector; } void moveLocation(ref CILocation location, CMovement.Direction direction) @@ -424,133 +423,56 @@ struct MoveSystem else .snake.element(MapElement(),location); } - static CMovement.Direction getDirection(ivec2 p1, ivec2 p2) - { - if(p1.x - p2.x == -1)return CMovement.direction.right; - else if(p1.x - p2.x == 1)return CMovement.direction.left; - else if(p1.y - p2.y == -1)return CMovement.direction.up; - else if(p1.y - p2.y == 1)return CMovement.direction.down; - else if(p1.x - p2.x > 1)return CMovement.direction.right; - else if(p1.x - p2.x < -1)return CMovement.direction.left; - else if(p1.y - p2.y > 1)return CMovement.direction.up; - else return CMovement.direction.down; - } - - static MapElement.Type snakePart(ivec2 p1, ivec2 p2, ivec2 p3) - { - CMovement.Direction direction = getDirection(p1, p2); - CMovement.Direction direction2 = getDirection(p1, p3); - uint case_ = direction*4 + direction2; - final switch(case_) - { - case 0:return MapElement.Type.snake_horizontal; - case 1:return MapElement.Type.snake_horizontal; - case 2:return MapElement.Type.snake_turn_lu; - case 3:return MapElement.Type.snake_turn_ru; - case 4:return MapElement.Type.snake_horizontal; - case 5:return MapElement.Type.snake_horizontal; - case 6:return MapElement.Type.snake_turn_ld; - case 7:return MapElement.Type.snake_turn_rd; - case 8:return MapElement.Type.snake_turn_lu; - case 9:return MapElement.Type.snake_turn_ld; - case 10:return MapElement.Type.snake_vertical; - case 11:return MapElement.Type.snake_vertical; - case 12:return MapElement.Type.snake_turn_ru; - case 13:return MapElement.Type.snake_turn_rd; - case 14:return MapElement.Type.snake_vertical; - case 15:return MapElement.Type.snake_vertical; - } - } - - static MapElement.Type snakeTail(ivec2 p1, ivec2 p2) - { - CMovement.Direction direction = getDirection(p1, p2); - final switch(direction) - { - case CMovement.Direction.up:return MapElement.Type.snake_tail_up; - case CMovement.Direction.down:return MapElement.Type.snake_tail_down; - case CMovement.Direction.left:return MapElement.Type.snake_tail_left; - case CMovement.Direction.right:return MapElement.Type.snake_tail_right; - } - } - void onUpdate(EntitiesData data) { if(data.snakes) { foreach(i; 0..data.length) { + data.snakes[i].direction = data.movement[i].direction; ivec2 new_location = data.location[i]; moveLocation(data.location[i], data.movement[i].direction); final switch(snake.element(data.location[i].location).type) { - case MapElement.Type.snake_head_up:goto case(MapElement.Type.snake_horizontal); - case MapElement.Type.snake_head_down:goto case(MapElement.Type.snake_horizontal); - case MapElement.Type.snake_head_left:goto case(MapElement.Type.snake_horizontal); - case MapElement.Type.snake_head_right:goto case(MapElement.Type.snake_horizontal); - case MapElement.Type.snake_tail_up:goto case(MapElement.Type.snake_horizontal); - case MapElement.Type.snake_tail_down:goto case(MapElement.Type.snake_horizontal); - case MapElement.Type.snake_tail_left:goto case(MapElement.Type.snake_horizontal); - case MapElement.Type.snake_tail_right:goto case(MapElement.Type.snake_horizontal); - case MapElement.Type.snake_turn_ld:goto case(MapElement.Type.snake_horizontal); - case MapElement.Type.snake_turn_lu:goto case(MapElement.Type.snake_horizontal); - case MapElement.Type.snake_turn_rd:goto case(MapElement.Type.snake_horizontal); - case MapElement.Type.snake_turn_ru:goto case(MapElement.Type.snake_horizontal); - case MapElement.Type.snake_vertical:goto case(MapElement.Type.snake_horizontal); - case MapElement.Type.snake_horizontal: - foreach(ivec2 loc; data.snakes[i].parts) + case MapElement.Type.snake: + foreach(loc; data.snakes[i].parts) { - destroy_location.x = loc.x * 16; - destroy_location.y = loc.y * 16; + //destroy_location.x = loc.x * 16; + //destroy_location.y = loc.y * 16; snake.element(MapElement(MapElement.Type.empty, EntityID()),loc); - launcher.manager.addEntity(snake.snake_destroy_particle); + launcher.manager.addEntity(snake.snake_destroy_particle,[CLocation(cast(vec2)(loc * 16)).ref_].staticArray); + + CLocation destroy_location; foreach(j;0..10) { destroy_location.x = loc.x * 16 + randomf() * 8 - 4; destroy_location.y = loc.y * 16 + randomf() * 8 - 4; - destroy_vector.velocity = vec2(randomf(),randomf())*0.4-0.2; + //destroy_vector.velocity = vec2(randomf(),randomf())*0.4-0.2; snake.element(MapElement(MapElement.Type.empty, EntityID()),loc); - launcher.manager.addEntity(snake.snake_destroy_particle); + launcher.manager.addEntity(snake.snake_destroy_particle, [destroy_location.ref_, CParticleVector(vec2(randomf(),randomf())*0.4-0.2).ref_].staticArray); } } - destroy_location.x = new_location.x * 16; - destroy_location.y = new_location.y * 16; + //destroy_location.x = new_location.x * 16; + //destroy_location.y = new_location.y * 16; snake.element(MapElement(MapElement.Type.empty, EntityID()),new_location); - launcher.manager.addEntity(snake.snake_destroy_particle); + launcher.manager.addEntity(snake.snake_destroy_particle,[CLocation(cast(vec2)(new_location * 16)).ref_].staticArray); launcher.manager.removeEntity(data.entities[i].id); break; + case MapElement.Type.wall:break; - //launcher.manager.removeEntity(data.entities[i].id); - //break; + case MapElement.Type.empty: moveSnake(data.snakes[i], new_location); - final switch(data.movement[i].direction) - { - case CMovement.Direction.up: - snake.element(MapElement(MapElement.Type.snake_head_up, data.entities[i].id),data.location[i].location); - break; - case CMovement.Direction.right: - snake.element(MapElement(MapElement.Type.snake_head_right, data.entities[i].id),data.location[i].location); - break; - case CMovement.Direction.down: - snake.element(MapElement(MapElement.Type.snake_head_down, data.entities[i].id),data.location[i].location); - break; - case CMovement.Direction.left: - snake.element(MapElement(MapElement.Type.snake_head_left, data.entities[i].id),data.location[i].location); - break; - } + snake.element(MapElement(MapElement.Type.snake, data.entities[i].id),data.location[i].location); if(data.snakes[i].parts.length > 1) { - MapElement.Type elem_type = snakePart(data.snakes[i].parts[$-1],data.location[i],data.snakes[i].parts[$-2]); - snake.element(MapElement(elem_type, data.entities[i].id),data.snakes[i].parts[$-1]); - elem_type = snakeTail(data.snakes[i].parts[1], data.snakes[i].parts[0]); - snake.element(MapElement(elem_type, data.entities[i].id),data.snakes[i].parts[0]); + snake.element(MapElement(MapElement.Type.snake, data.entities[i].id),data.snakes[i].parts[$-1]); + snake.element(MapElement(MapElement.Type.snake, data.entities[i].id),data.snakes[i].parts[0]); } else if(data.snakes[i].parts.length == 1) { - MapElement.Type elem_type = snakeTail(data.location[i], data.snakes[i].parts[0]); - snake.element(MapElement(elem_type, data.entities[i].id),data.snakes[i].parts[0]); + snake.element(MapElement(MapElement.Type.snake, data.entities[i].id),data.snakes[i].parts[0]); } break; case MapElement.Type.apple: @@ -559,29 +481,13 @@ struct MoveSystem if(data.snakes[i].parts.length > 1) { - MapElement.Type elem_type = snakePart(data.snakes[i].parts[$-1],data.location[i],data.snakes[i].parts[$-2]); - snake.element(MapElement(elem_type, data.entities[i].id),data.snakes[i].parts[$-1]); + snake.element(MapElement(MapElement.Type.snake, data.entities[i].id),data.snakes[i].parts[$-1]); } else if(data.snakes[i].parts.length == 1) { - MapElement.Type elem_type = snakeTail(data.location[i], new_location); - snake.element(MapElement(elem_type, data.entities[i].id),new_location); - } - final switch(data.movement[i].direction) - { - case CMovement.Direction.up: - snake.element(MapElement(MapElement.Type.snake_head_up, data.entities[i].id),data.location[i].location); - break; - case CMovement.Direction.right: - snake.element(MapElement(MapElement.Type.snake_head_right, data.entities[i].id),data.location[i].location); - break; - case CMovement.Direction.down: - snake.element(MapElement(MapElement.Type.snake_head_down, data.entities[i].id),data.location[i].location); - break; - case CMovement.Direction.left: - snake.element(MapElement(MapElement.Type.snake_head_left, data.entities[i].id),data.location[i].location); - break; + snake.element(MapElement(MapElement.Type.snake, data.entities[i].id),new_location); } + snake.element(MapElement(MapElement.Type.snake, data.entities[i].id),data.location[i].location); snake.addApple(); break; } @@ -593,10 +499,10 @@ struct MoveSystem { final switch(data.movement[i].direction) { - case CMovement.Direction.down:data.location[i].location.y -= 1;break; - case CMovement.Direction.up:data.location[i].location.y += 1;break; - case CMovement.Direction.left:data.location[i].location.x -= 1;break; - case CMovement.Direction.right:data.location[i].location.x += 1;break; + case CMovement.Direction.down:data.location[i].y -= 1;break; + case CMovement.Direction.up:data.location[i].y += 1;break; + case CMovement.Direction.left:data.location[i].x -= 1;break; + case CMovement.Direction.right:data.location[i].x += 1;break; } } } @@ -699,6 +605,132 @@ struct FixSnakeDirectionSystem } } +struct DrawAppleSystem +{ + mixin ECS.System!1; + + struct EntitiesData + { + uint length; + @readonly CILocation[] location; + const (CApple)[] apple; + } + + void onUpdate(EntitiesData data) + { + foreach(i; 0..data.location.length) + { + launcher.renderer.draw(snake.texture, vec2(data.location[i].x*16,data.location[i].y*16), vec2(16,16), vec4(0,32*px,16*px,16*px), 0, 0x80808080, 0); + } + } +} + +struct DrawSnakeSystem +{ + mixin ECS.System!1; + + struct EntitiesData + { + uint length; + @readonly CILocation[] location; + const (CSnake)[] snake; + } + + static CMovement.Direction getDirection(ivec2 p1, ivec2 p2) + { + if(p1.x - p2.x == -1)return CMovement.direction.right; + else if(p1.x - p2.x == 1)return CMovement.direction.left; + else if(p1.y - p2.y == -1)return CMovement.direction.up; + else if(p1.y - p2.y == 1)return CMovement.direction.down; + else if(p1.x - p2.x > 1)return CMovement.direction.right; + else if(p1.x - p2.x < -1)return CMovement.direction.left; + else if(p1.y - p2.y > 1)return CMovement.direction.up; + else return CMovement.direction.down; + } + + static SnakePart snakePart(ivec2 p1, ivec2 p2, ivec2 p3) + { + CMovement.Direction direction = getDirection(p1, p2); + CMovement.Direction direction2 = getDirection(p1, p3); + uint case_ = direction*4 + direction2; + final switch(case_) + { + case 0:return SnakePart.horizontal; + case 1:return SnakePart.horizontal; + case 2:return SnakePart.turn_lu; + case 3:return SnakePart.turn_ru; + case 4:return SnakePart.horizontal; + case 5:return SnakePart.horizontal; + case 6:return SnakePart.turn_ld; + case 7:return SnakePart.turn_rd; + case 8:return SnakePart.turn_lu; + case 9:return SnakePart.turn_ld; + case 10:return SnakePart.vertical; + case 11:return SnakePart.vertical; + case 12:return SnakePart.turn_ru; + case 13:return SnakePart.turn_rd; + case 14:return SnakePart.vertical; + case 15:return SnakePart.vertical; + } + } + + static SnakePart snakeTail(ivec2 p1, ivec2 p2) + { + CMovement.Direction direction = getDirection(p1, p2); + final switch(direction) + { + case CMovement.Direction.up:return SnakePart.tail_up; + case CMovement.Direction.down:return SnakePart.tail_down; + case CMovement.Direction.left:return SnakePart.tail_left; + case CMovement.Direction.right:return SnakePart.tail_right; + } + } + + static void drawElement(ivec2 loc, SnakePart part) + { + final switch(cast(ubyte)part) + { + case SnakePart.tail_up:launcher.renderer.draw(.snake.texture, cast(vec2)loc, vec2(16,16), vec4(16,112,16,16)*px, 0, 0x80808080, 0);break; + case SnakePart.tail_down:launcher.renderer.draw(.snake.texture, cast(vec2)loc, vec2(16,16), vec4(0,112,16,16)*px, 0, 0x80808080, 0);break; + case SnakePart.tail_left:launcher.renderer.draw(.snake.texture, cast(vec2)loc, vec2(16,16), vec4(32,112,16,16)*px, 0, 0x80808080, 0);break; + case SnakePart.tail_right:launcher.renderer.draw(.snake.texture, cast(vec2)loc, vec2(16,16), vec4(0,144,16,16)*px, 0, 0x80808080, 0);break; + case SnakePart.turn_ld:launcher.renderer.draw(.snake.texture, cast(vec2)loc, vec2(16,16), vec4(64,128,16,16)*px, 0, 0x80808080, 0);break; + case SnakePart.turn_lu:launcher.renderer.draw(.snake.texture, cast(vec2)loc, vec2(16,16), vec4(32,144,16,16)*px, 0, 0x80808080, 0);break; + case SnakePart.turn_rd:launcher.renderer.draw(.snake.texture, cast(vec2)loc, vec2(16,16), vec4(16,144,16,16)*px, 0, 0x80808080, 0);break; + case SnakePart.turn_ru:launcher.renderer.draw(.snake.texture, cast(vec2)loc, vec2(16,16), vec4(64,112,16,16)*px, 0, 0x80808080, 0);break; + case SnakePart.vertical:launcher.renderer.draw(.snake.texture, cast(vec2)loc, vec2(16,16), vec4(16,128,16,16)*px, 0, 0x80808080, 0);break; + case SnakePart.horizontal:launcher.renderer.draw(.snake.texture, cast(vec2)loc, vec2(16,16), vec4(48,128,16,16)*px, 0, 0x80808080, 0);break; + } + } + + void onUpdate(EntitiesData data) + { + foreach(i; 0..data.length) + { + const (CSnake)* snake = &data.snake[i]; + scope vec2 loc = cast(vec2)(data.location[i].location * 16); + final switch(snake.direction) + { + case CMovement.Direction.up:launcher.renderer.draw(.snake.texture, vec2(data.location[i].x*16,data.location[i].y*16), vec2(16,16), vec4(48,112,16,16)*px, 0, 0x80808080, 0);break; + case CMovement.Direction.down:launcher.renderer.draw(.snake.texture, vec2(data.location[i].x*16,data.location[i].y*16), vec2(16,16), vec4(48,144,16,16)*px, 0, 0x80808080, 0);break; + case CMovement.Direction.left:launcher.renderer.draw(.snake.texture, vec2(data.location[i].x*16,data.location[i].y*16), vec2(16,16), vec4(0,128,16,16)*px, 0, 0x80808080, 0);break; + case CMovement.Direction.right:launcher.renderer.draw(.snake.texture, vec2(data.location[i].x*16,data.location[i].y*16), vec2(16,16), vec4(32,128,16,16)*px, 0, 0x80808080, 0);break; + } + if(snake.parts.length >1) + { + foreach(j;1..snake.parts.length - 1)drawElement(snake.parts[j]*16, snakePart(snake.parts[j], snake.parts[j+1], snake.parts[j-1])); + drawElement(snake.parts[$-1]*16, snakePart(snake.parts[$-1], data.location[i], snake.parts[$-2])); + drawElement(snake.parts[0]*16, snakeTail(snake.parts[1], snake.parts[0])); + } + else if(snake.parts.length == 1) + { + drawElement(snake.parts[0]*16, snakeTail(data.location[i], snake.parts[0])); + } + + } + } +} + struct CleanSystem { mixin ECS.System!64; @@ -749,6 +781,8 @@ void snakeStart() launcher.manager.registerSystem!AnimationSystem(-1); launcher.manager.registerSystem!ParticleSystem(-1); launcher.manager.registerSystem!ParticleMovementSystem(-1); + launcher.manager.registerSystem!DrawAppleSystem(99); + launcher.manager.registerSystem!DrawSnakeSystem(101); launcher.manager.endRegister(); @@ -765,9 +799,9 @@ void snakeStart() { ushort[4] components = [CILocation.component_id, CSnake.component_id, CMovement.component_id, CInput.component_id]; snake.snake_tmpl = launcher.manager.allocateTemplate(components); - CILocation* loc_comp = snake.snake_tmpl.getComponent!CILocation; - loc_comp.location = ivec2(2,2); - launcher.manager.addEntity(snake.snake_tmpl); + //CILocation* loc_comp = snake.snake_tmpl.getComponent!CILocation; + //*loc_comp = ivec2(2,2); + launcher.manager.addEntity(snake.snake_tmpl,[CILocation(ivec2(2,2)).ref_].staticArray); } { @@ -784,9 +818,9 @@ void snakeStart() snake.addApple(); } - launcher.gui_manager.addTemplate(snake.snake_tmpl, "Snake"); - launcher.gui_manager.addTemplate(snake.apple_tmpl, "Apple"); - launcher.gui_manager.addTemplate(snake.snake_destroy_particle, "Particle"); + launcher.gui_manager.addTemplate(launcher.manager.allocateTemplate(snake.snake_tmpl), "Snake"); + launcher.gui_manager.addTemplate(launcher.manager.allocateTemplate(snake.apple_tmpl), "Apple"); + launcher.gui_manager.addTemplate(launcher.manager.allocateTemplate(snake.snake_destroy_particle), "Particle"); MoveSystem* move_system = launcher.manager.getSystem!MoveSystem(); move_system.setTemplates(); @@ -794,7 +828,7 @@ void snakeStart() /*foreach(i; 0..10) foreach(j; 0..10) { - loc_comp.location = vec2(i*32+64,j*32+64); + loc_compation = vec2(i*32+64,j*32+64); launcher.manager.addEntity(simple.tmpl); }*/ } @@ -815,15 +849,15 @@ void snakeTool(vec2 position, Tool tool, int size) CLocation* location = tmpl.getComponent!CLocation; if(location) { - position.x += (randomf - 0.5) * size; - position.y += (randomf - 0.5) * size; + position.x += (randomf() - 0.5) * size; + position.y += (randomf() - 0.5) * size; *location = position; } CILocation* ilocation = tmpl.getComponent!CILocation; if(ilocation) { - position.x += (randomf - 0.5) * size; - position.y += (randomf - 0.5) * size; + position.x += (randomf() - 0.5) * size; + position.y += (randomf() - 0.5) * size; ivec2 ipos; ipos.x = cast(int)(position.x / 16); ipos.y = cast(int)(position.y / 16); @@ -878,7 +912,7 @@ bool snakeLoop() launcher.manager.end(); - snake.drawMap(); + //snake.drawMap(); return true; } \ No newline at end of file diff --git a/demos/source/demos/space_invaders.d b/demos/source/demos/space_invaders.d index bddf53c..5615f0d 100644 --- a/demos/source/demos/space_invaders.d +++ b/demos/source/demos/space_invaders.d @@ -6,20 +6,29 @@ import bindbc.sdl; import cimgui.cimgui; -import ecs.attributes; -import ecs.core; -import ecs.entity; -import ecs.manager; -import ecs.std; +import bubel.ecs.attributes; +import bubel.ecs.core; +import bubel.ecs.entity; +import bubel.ecs.manager; +import bubel.ecs.std; import ecs_utils.gfx.texture; import ecs_utils.math.vector; import ecs_utils.utils; +//import std.math : PI; + +enum PI = 3.141592653589793238462643383279502884197169399375105820; + +//import std.array : staticArray; + enum float px = 1.0/512.0; + extern(C): +enum ShootGridDependency = "ShootGridDependency"; + /*####################################################################################################################### ------------------------------------------------ Types ------------------------------------------------------------------ #######################################################################################################################*/ @@ -31,13 +40,31 @@ struct SpaceInvaders EntityTemplate* enemy_tmpl; EntityTemplate* ship_tmpl; EntityTemplate* laser_tmpl; + EntityTemplate*[5] bullet_tmpl; Texture texture; + ShootGrid* shoot_grid; + bool move_system = true; bool draw_system = true; const vec2 map_size = vec2(400,300); const float cell_size = 60; + + EntityID player_ship; + + ~this() @nogc nothrow + { + if(shoot_grid)Mallocator.dispose(shoot_grid); + if(enemy_tmpl)launcher.manager.freeTemplate(enemy_tmpl); + if(ship_tmpl)launcher.manager.freeTemplate(ship_tmpl); + if(laser_tmpl)launcher.manager.freeTemplate(laser_tmpl); + foreach (EntityTemplate* tmpl; bullet_tmpl) + { + if(tmpl)launcher.manager.freeTemplate(tmpl); + } + texture.destory(); + } } struct SceneGrid @@ -93,7 +120,7 @@ struct CLocation alias value this; - vec2 value; + vec2 value = vec2(0); } struct CScale @@ -106,11 +133,31 @@ struct CScale vec2 value = vec2(16,16); } +struct CColliderScale +{ + mixin ECS.Component; + + alias value this; + + vec2 value = vec2(16,16); +} + +struct CRotation +{ + mixin ECS.Component; + + ///use component as it value + alias value this; + + float value = 0; +} + struct CTexture { mixin ECS.Component; - Texture tex; + //Texture tex; + uint id; vec4 coords = vec4(0,0,0,1); } @@ -147,22 +194,50 @@ struct CGuild { mixin ECS.Component; - int guild; + byte guild; } -struct CLaser +struct CBullet { mixin ECS.Component; - float damage = 1.0f; + int damage = 1; } -struct CLaserWeapon +struct CWeapon { mixin ECS.Component; - ubyte level = 1; + static struct Level + { + float reload_time; + float dispersion; + int damage; + } + + __gshared Level[12] levels = [Level(4000,0),Level(4000,0.1), + Level(500,0),Level(350,0),Level(250,0.02),Level(175,0.03),Level(110,0.04), + Level(80,0.05),Level(50,0.08),Level(20,0.1),Level(10,0.12),Level(2,0.14)]; + + enum Type : ubyte + { + laser, + enemy_laser, + blaster, + canon, + plasma + } + float shoot_time = 0; + Type type; + ubyte level = 1; +} + +struct CWeaponLocation +{ + mixin ECS.Component; + + vec2 rel_pos = vec2(0,0); } struct CShootDirection @@ -179,6 +254,196 @@ struct CSideMove byte group = -1; } +struct CDepth +{ + mixin ECS.Component; + + alias depth this; + + short depth; +} + +struct CShootGrid +{ + mixin ECS.Component; +} + +struct CTargetParent +{ + mixin ECS.Component; + + EntityID parent; + vec2 rel_pos; +} + + +struct CHitPoints +{ + mixin ECS.Component; + + alias value this; + + int value = 3; +} + +struct CMaxHitPoints +{ + mixin ECS.Component; + + alias value this; + + int value = 3; +} + +struct CHitMark +{ + mixin ECS.Component; + + alias value this; + + ubyte value = 0; +} + +struct CUpgrade +{ + mixin ECS.Component; + + alias value this; + + enum Upgrade : ubyte + { + hit_points, + regeneration, + laser + } + + Upgrade value; +} + +struct CAnimation +{ + mixin ECS.Component; + + vec4[] frames; + float time = 0; + float speed = 1; +} + +struct CAnimationLooped +{ + mixin ECS.Component; +} + +struct CDamping +{ + mixin ECS.Component; + + alias value this; + + byte value = 0; +} + +struct CParticle +{ + mixin ECS.Component; + + float life = 0; +} + +struct CTarget +{ + mixin ECS.Component; + + EntityID target; +} + +struct CTargetPlayerShip +{ + mixin ECS.Component; +} + +struct CChildren +{ + mixin ECS.Component; + + EntityID[] childern; +} + +struct CBoss +{ + mixin ECS.Component; +} + +struct CParts +{ + mixin ECS.Component; + + ubyte count; +} + +struct CInit +{ + mixin ECS.Component; + + enum Type + { + space_ship, + tower, + boss + } + + Type type; +} + +struct CParticleEmitter +{ + mixin ECS.Component; + + vec2 range; + vec2 time_range; + ///due to multithreading there should be separate template for every thread. + ///It can be array of tempaltes or (like in this demo) simply index of template; + uint tmpl_id; + //EntityTemplate* tmpl; +} + +///Due to perfarmance reason emitter time and attributes are divided into seprate components. +///Beyon that both components are considerd to be used together. +struct CParticleEmitterTime +{ + mixin ECS.Component; + + float time = 0; +} + +///You can create separate component for every kind of spawned entities but it's not practial due to archetype fragmentation. +///Second approach can be commented code. It's gives good flexibility inchoosing entity, but it limits to one entity. +///Instead of entity it can be array of templates which is good solution, but if possibilities is known at time of game development it +///can be simply index/enum for type of spawn. Bad thing about this solution is problem witch merging multiple spawning types during +///gameplay, i.e. giving buff which cast firebols upon death. +struct CSpawnUponDeath +{ + mixin ECS.Component; + + enum Type + { + flashes_emitter, + } + + //EntityID parent; + //EntityTemplate* tmpl; + Type type; +} + +///This component can be replaced by "CSpawnUponDeath" but I want to gives possibility to add this component to every entity +///during gameplay. End application works exacly the same way for every demo so I can't use different way as adding component. +struct CShootWaveUponDeath +{ + mixin ECS.Component; + + CWeapon.Type bullet_type; +} + /*####################################################################################################################### ------------------------------------------------ Events ------------------------------------------------------------------ #######################################################################################################################*/ @@ -195,32 +460,593 @@ struct EChangeDirection Direction direction; } +struct EUpgrade +{ + mixin ECS.Event; +} + +struct EDeath +{ + mixin ECS.Event; +} + +struct EDamage +{ + mixin ECS.Event; + + this(uint damage) + { + this.damage = damage; + } + + uint damage = 0; +} + +struct EBulletHit +{ + mixin ECS.Event; + + this(EntityID id, uint damage) + { + this.id = id; + this.damage = damage; + } + + EntityID id; + uint damage; +} + +struct EDestroyedChild +{ + mixin ECS.Event; + + this(EntityID id) + { + this.id = id; + } + + EntityID id; +} + /*####################################################################################################################### ------------------------------------------------ Systems ------------------------------------------------------------------ #######################################################################################################################*/ -struct DrawSystem +struct ShootGrid +{ + + ~this() @nogc nothrow + { + if(nodes)Mallocator.dispose(nodes); + if(masks)Mallocator.dispose(masks); + } + + struct Node + { + alias entity this; + + EntityID entity; + } + + void create(ivec2 nodes_count, vec2 node_size) + { + this.size = nodes_count; + this.node_size = node_size; + inv_node_size = vec2(1.0/node_size.x, 1.0/node_size.y); + nodes = Mallocator.makeArray!Node(nodes_count.x * nodes_count.y); + masks = Mallocator.makeArray!ubyte(nodes.length); + } + + void mark(EntityID id, vec2 beg, vec2 end, byte mask) + { + ivec2 ibeg = cast(ivec2)(beg * inv_node_size); + ivec2 iend = cast(ivec2)((end * inv_node_size) + 0.5); + if(ibeg.x < 0)ibeg.x = 0; + if(ibeg.y < 0)ibeg.y = 0; + if(iend.x > size.x)iend.x = size.x; + if(iend.y > size.y)iend.y = size.y; + foreach(i; ibeg.y .. iend.y) + { + foreach(j; ibeg.x .. iend.x) + { + nodes[i * size.x + j] = id; + masks[i * size.x +j] = mask; + } + } + } + + void clear() + { + size_t size = nodes.length * EntityID.sizeof; + memset(nodes.ptr, 0, size); + memset(masks.ptr, 0, masks.length); + } + + bool test(out EntityID id, vec2 beg, vec2 end) + { + ivec2 ibeg = cast(ivec2)(beg * inv_node_size); + ivec2 iend = cast(ivec2)((end * inv_node_size) + 0.5); + if(ibeg.x < 0)ibeg.x = 0; + if(ibeg.y < 0)ibeg.y = 0; + if(iend.x > size.x)iend.x = size.x; + if(iend.y > size.y)iend.y = size.y; + foreach(i; ibeg.y .. iend.y) + { + foreach(j; ibeg.x .. iend.x) + { + if(nodes[i * size.x + j].id != 0) + { + id = nodes[i * size.x + j]; + return true; + } + } + } + return false; + } + + bool test(out EntityID id, vec2 pos, ubyte mask) + { + ivec2 ipos = cast(ivec2)(pos * inv_node_size - 0.5); + if(ipos.x < 0)ipos.x = 0; + if(ipos.y < 0)ipos.y = 0; + if(ipos.x >= size.x)ipos.x = size.x - 1; + if(ipos.y >= size.y)ipos.y = size.y - 1; + size_t index = ipos.y * size.x + ipos.x; + if((masks[index] & mask) == 0)return false; + if(nodes[index].id != 0) + { + id = nodes[index]; + return true; + } + return false; + } + + vec2 inv_node_size; + ivec2 size; + vec2 node_size; + Node[] nodes; + ubyte[] masks; +} + +struct ShootGridCleaner { mixin ECS.System!1; struct EntitiesData { - uint length; - @readonly CTexture[] textures; - @readonly CLocation[] locations; - @readonly CScale[] scale; + } void onUpdate(EntitiesData data) { + if(space_invaders.shoot_grid)space_invaders.shoot_grid.clear(); + } +} + +struct ShootGridManager +{ + mixin ECS.System!128; + + mixin ECS.WritableDependencies!(ShootGridDependency); + + struct EntitiesData + { + uint length; + //uint thread_id; + const (Entity)[] entity; + @readonly CLocation[] locations; + @readonly CShootGrid[] grid_flag; + @readonly CGuild[] guild; + @optional @readonly CScale[] scale; + @optional @readonly CColliderScale[] collider_scale; + } + + ShootGrid* grid; + + void onCreate() + { + grid = space_invaders.shoot_grid; + } + + bool onBegin() + { + if(!grid)return false; + //grid.clear(); + return true; + } + + void onUpdate(EntitiesData data) + { + vec2[] scale; + if(data.collider_scale)scale = cast(vec2[])data.collider_scale; + else if(data.scale)scale = cast(vec2[])data.scale; + else return; foreach(i; 0..data.length) { - launcher.renderer.draw(data.textures[i].tex, data.locations[i].value, data.scale[i], data.textures[i].coords, 0, 0 , 0); - //draw(renderer, data.textures[i].tex, data.locations[i], vec2(32,32), vec4(0,0,1,1)); + vec2 half_scale = scale[i] * 0.5; + grid.mark(data.entity[i].id, data.locations[i] - half_scale, data.locations[i] + half_scale, cast(ubyte)(1 << data.guild[i].guild)); } } } +struct ParentOwnerSystem +{ + mixin ECS.System; + + struct EntitiesData + { + CChildren[] children; + } + + void onRemoveEntity(EntitiesData data) + { + //currently EntitiesData always has only one element + foreach(child; data.children[0].childern) + { + launcher.manager.removeEntity(child); + } + if(data.children[0].childern.length)Mallocator.dispose(data.children[0].childern); + } +} + +struct ShipWeaponSystem +{ + mixin ECS.System; + + struct EntitiesData + { + int length; + Entity[] entity; + CInit[] init; + //CShip[] ship; + //CChildren[] children; + } + + struct Ship + { + EntityTemplate* laser1_tmpl; + EntityTemplate* laser2_tmpl; + EntityTemplate* main_weapon_tmpl; + + void add(Entity* entity) + { + CChildren* children = entity.getComponent!CChildren; + if(children is null || children.childern.length != 0)return; + EntityID[3] weapons; + laser1_tmpl.getComponent!CTargetParent().parent = entity.id; + laser2_tmpl.getComponent!CTargetParent().parent = entity.id; + main_weapon_tmpl.getComponent!CTargetParent().parent = entity.id; + weapons[0] = launcher.manager.addEntity(laser1_tmpl).id; + weapons[1] = launcher.manager.addEntity(laser2_tmpl).id; + weapons[2] = launcher.manager.addEntity(main_weapon_tmpl).id; + children.childern = Mallocator.makeArray(weapons); + } + + void create() + { + laser1_tmpl = launcher.manager.allocateTemplate([CWeapon.component_id, CLocation.component_id, CShootDirection.component_id, CTargetParent.component_id, CGuild.component_id, CVelocity.component_id].staticArray); + main_weapon_tmpl = launcher.manager.allocateTemplate([CLocation.component_id, CShootDirection.component_id, CTargetParent.component_id, CGuild.component_id, CVelocity.component_id].staticArray); + *laser1_tmpl.getComponent!CWeapon = CWeapon(0,CWeapon.Type.laser,3); + laser1_tmpl.getComponent!CTargetParent().rel_pos = vec2(10,13); + main_weapon_tmpl.getComponent!CTargetParent().rel_pos = vec2(0,4); + laser2_tmpl = launcher.manager.allocateTemplate(laser1_tmpl); + laser2_tmpl.getComponent!CTargetParent().rel_pos = vec2(-10,13); + } + + ~this() + { + launcher.manager.freeTemplate(laser1_tmpl); + launcher.manager.freeTemplate(laser2_tmpl); + launcher.manager.freeTemplate(main_weapon_tmpl); + } + } + + struct Tower + { + EntityTemplate* weapon_tmpl; + EntityTemplate* top_tmpl; + + void add(Entity* entity) + { + CChildren* children = entity.getComponent!CChildren; + if(children is null || children.childern.length != 0)return; + CDepth* depth = entity.getComponent!CDepth; + EntityID[2] weapons; + weapon_tmpl.getComponent!CTargetParent().parent = entity.id; + if(depth)weapon_tmpl.getComponent!CDepth().depth = cast(short)(depth.depth - 1); + else weapon_tmpl.getComponent!CDepth().depth = -1; + top_tmpl.getComponent!CTargetParent().parent = entity.id; + if(depth)top_tmpl.getComponent!CDepth().depth = cast(short)(depth.depth - 2); + else top_tmpl.getComponent!CDepth().depth = -2; + + weapons[0] = launcher.manager.addEntity(weapon_tmpl).id; + weapons[1] = launcher.manager.addEntity(top_tmpl).id; + children.childern = Mallocator.makeArray(weapons); + } + + void create() + { + weapon_tmpl = launcher.manager.allocateTemplate( + [CWeapon.component_id, CLocation.component_id, CShootDirection.component_id, + CTargetParent.component_id, CGuild.component_id, CVelocity.component_id, + CAutoShoot.component_id, CTarget.component_id, CTargetPlayerShip.component_id, + CRotation.component_id, CScale.component_id, CTexture.component_id, + CDepth.component_id, CWeaponLocation.component_id].staticArray); + *weapon_tmpl.getComponent!CWeapon = CWeapon(0,CWeapon.Type.laser,3); + weapon_tmpl.getComponent!CTargetParent().rel_pos = vec2(0,0); + weapon_tmpl.getComponent!CGuild().guild = 1; + weapon_tmpl.getComponent!CScale().value = vec2(4,16); + //weapon_tmpl.getComponent!CWeapon().level = 1; + *weapon_tmpl.getComponent!CWeapon() = CWeapon(0,CWeapon.Type.canon,1); + weapon_tmpl.getComponent!CDepth().depth = -1; + weapon_tmpl.getComponent!CTexture().coords = vec4(136,96,4,16)*px; + weapon_tmpl.getComponent!CWeaponLocation().rel_pos = vec2(0,12); + + top_tmpl = launcher.manager.allocateTemplate( + [CLocation.component_id, CTargetParent.component_id, CScale.component_id, + CTexture.component_id, CDepth.component_id].staticArray); + top_tmpl.getComponent!CTargetParent().rel_pos = vec2(0,1); + top_tmpl.getComponent!CScale().value = vec2(10,11); + top_tmpl.getComponent!CDepth().depth = -2; + top_tmpl.getComponent!CTexture().coords = vec4(112,96,10,11)*px; + + } + + ~this() + { + launcher.manager.freeTemplate(weapon_tmpl); + launcher.manager.freeTemplate(top_tmpl); + } + } + + struct Boss + { + EntityTemplate* tower1_tmpl; + EntityTemplate* tower2_tmpl; + EntityTemplate* tower3_tmpl; + EntityTemplate* tower4_tmpl; + + void add(Entity* entity) + { + CChildren* children = entity.getComponent!CChildren; + if(children is null || children.childern.length != 0)return; + CParts* parts = entity.getComponent!CParts; + if(parts)parts.count = 4; + EntityID[4] towers; + tower1_tmpl.getComponent!CTargetParent().parent = entity.id; + tower2_tmpl.getComponent!CTargetParent().parent = entity.id; + tower3_tmpl.getComponent!CTargetParent().parent = entity.id; + tower4_tmpl.getComponent!CTargetParent().parent = entity.id; + towers[0] = launcher.manager.addEntity(tower1_tmpl).id; + towers[1] = launcher.manager.addEntity(tower2_tmpl).id; + towers[2] = launcher.manager.addEntity(tower3_tmpl).id; + towers[3] = launcher.manager.addEntity(tower4_tmpl).id; + children.childern = Mallocator.makeArray(towers); + } + + void create() + { + tower1_tmpl = launcher.manager.allocateTemplate( + [CHitMark.component_id, CHitPoints.component_id, CLocation.component_id, + CTexture.component_id, CScale.component_id, CEnemy.component_id, + CShootGrid.component_id, CGuild.component_id, CInit.component_id, + CChildren.component_id, CDepth.component_id, CTargetParent.component_id, + CSpawnUponDeath.component_id, CShootWaveUponDeath.component_id].staticArray + ); + + CTexture* tex_comp = tower1_tmpl.getComponent!CTexture; + //tex_comp.tex = space_invaders.texture;//ship_tex; + tex_comp.coords = vec4(96*px,96*px,16*px,16*px); + CLocation* loc_comp = tower1_tmpl.getComponent!CLocation; + loc_comp.value = vec2(64,space_invaders.map_size.y - 16); + tower1_tmpl.getComponent!CGuild().guild = 1; + tower1_tmpl.getComponent!CInit().type = CInit.Type.tower; + tower1_tmpl.getComponent!CHitPoints().value = 10; + tower1_tmpl.getComponent!CDepth().depth = -2; + tower1_tmpl.getComponent!CShootWaveUponDeath().bullet_type = CWeapon.Type.canon; + tower1_tmpl.getComponent!CTargetParent().rel_pos = vec2(-33,2); + + tower2_tmpl = launcher.manager.allocateTemplate(tower1_tmpl); + tower2_tmpl.getComponent!CTargetParent().rel_pos = vec2(33,2); + + tower3_tmpl = launcher.manager.allocateTemplate(tower1_tmpl); + tower3_tmpl.getComponent!CDepth().depth = 0; + tower3_tmpl.getComponent!CTargetParent().rel_pos = vec2(-40,-15); + + tower4_tmpl = launcher.manager.allocateTemplate(tower1_tmpl); + tower4_tmpl.getComponent!CDepth().depth = 0; + tower4_tmpl.getComponent!CTargetParent().rel_pos = vec2(40,-15); + } + + ~this() + { + launcher.manager.freeTemplate(tower1_tmpl); + launcher.manager.freeTemplate(tower2_tmpl); + launcher.manager.freeTemplate(tower3_tmpl); + launcher.manager.freeTemplate(tower4_tmpl); + } + } + + Ship ship; + Tower tower; + Boss boss; + + void onCreate() + { + ship.create(); + tower.create(); + boss.create(); + /*ship.laser1_tmpl = launcher.manager.allocateTemplate([CWeapon.component_id, CLocation.component_id, CShootDirection.component_id, CTargetParent.component_id, CGuild.component_id, CVelocity.component_id].staticArray); + ship.main_weapon_tmpl = launcher.manager.allocateTemplate([CLocation.component_id, CShootDirection.component_id, CTargetParent.component_id, CGuild.component_id, CVelocity.component_id].staticArray); + *ship.laser1_tmpl.getComponent!CWeapon = CWeapon(3,0.0); + ship.laser1_tmpl.getComponent!CTargetParent().rel_pos = vec2(10,13); + ship.main_weapon_tmpl.getComponent!CTargetParent().rel_pos = vec2(0,4); + ship.laser2_tmpl = launcher.manager.allocateTemplate(ship.laser1_tmpl); + ship.laser2_tmpl.getComponent!CTargetParent().rel_pos = vec2(-10,13);*/ + } + + void onDestroy() + { + /*launcher.manager.freeTemplate(laser1_tmpl); + launcher.manager.freeTemplate(laser2_tmpl); + launcher.manager.freeTemplate(main_weapon_tmpl);*/ + } + + void onAddEntity(EntitiesData data) + { + foreach(i; 0..data.length) + { + final switch(data.init[i].type) + { + case CInit.Type.space_ship:ship.add(&data.entity[i]);break; + case CInit.Type.tower:tower.add(&data.entity[i]);break; + case CInit.Type.boss:boss.add(&data.entity[i]);break; + } + } + } +} + +struct MoveToParentTargetSystem +{ + mixin ECS.System!32; + + struct EntitiesData + { + int length; + CLocation[] location; + @optional CVelocity[] velocity; + @readonly CTargetParent[] target; + } + + void onUpdate(EntitiesData data) + { + if(data.velocity) + { + foreach(i;0..data.length) + { + Entity* target = launcher.manager.getEntity(data.target[i].parent); + if(target) + { + CLocation* target_loc = target.getComponent!CLocation; + if(target_loc != null) + { + data.location[i] = *target_loc + data.target[i].rel_pos; + } + CVelocity* target_vel = target.getComponent!CVelocity; + if(target_vel != null) + { + data.velocity[i] = *target_vel; + } + } + } + } + else + foreach(i;0..data.length) + { + Entity* target = launcher.manager.getEntity(data.target[i].parent); + if(target) + { + CLocation* target_loc = target.getComponent!CLocation; + if(target_loc != null) + { + data.location[i] = *target_loc + data.target[i].rel_pos; + } + } + } + } +} + +struct DrawSystem +{ + mixin ECS.System!32; + + struct EntitiesData + { + uint length; + //uint thread_id; + uint job_id; + @readonly CTexture[] textures; + @readonly CLocation[] locations; + @readonly CScale[] scale; + @readonly @optional CRotation[] rotation; + @readonly @optional CDepth[] depth; + @readonly @optional CHitMark[] hit_mark; + } + + void onUpdate(EntitiesData data) + { + if(!data.depth) + { + if(data.hit_mark) + { + foreach(i; 0..data.length) + { + uint color = 0x80808080 + 0x01010101 * data.hit_mark[i]; + short depth = cast(short)(data.locations[i].y); + launcher.renderer.draw(space_invaders.texture, data.locations[i].value, data.scale[i], data.textures[i].coords, depth, color, 0, 0, 0, data.job_id); + } + } + else if(data.rotation) + { + foreach(i; 0..data.length) + { + short depth = cast(short)(data.locations[i].y); + launcher.renderer.draw(space_invaders.texture, data.locations[i].value, data.scale[i], data.textures[i].coords, depth, 0x80808080, data.rotation[i], 0, 0, data.job_id); + } + } + else + { + foreach(i; 0..data.length) + { + short depth = cast(short)(data.locations[i].y); + launcher.renderer.draw(space_invaders.texture, data.locations[i].value, data.scale[i], data.textures[i].coords, depth, 0x80808080, 0, 0, 0, data.job_id); + } + } + } + else + { + if(data.hit_mark) + { + if(data.rotation) + { + foreach(i; 0..data.length) + { + uint color = 0x80808080 + 0x01010101 * data.hit_mark[i]; + short depth = cast(short)(data.depth[i] * 8 + data.locations[i].y); + launcher.renderer.draw(space_invaders.texture, data.locations[i].value, data.scale[i], data.textures[i].coords, depth, color, data.rotation[i], 0, 0, data.job_id); + } + } + else + { + foreach(i; 0..data.length) + { + uint color = 0x80808080 + 0x01010101 * data.hit_mark[i]; + short depth = cast(short)(data.depth[i] * 8 + data.locations[i].y); + launcher.renderer.draw(space_invaders.texture, data.locations[i].value, data.scale[i], data.textures[i].coords, depth, color, 0, 0, 0, data.job_id); + } + } + } + else if(data.rotation) + { + foreach(i; 0..data.length) + { + short depth = cast(short)(data.depth[i] * 8 + data.locations[i].y); + launcher.renderer.draw(space_invaders.texture, data.locations[i].value, data.scale[i], data.textures[i].coords, depth, 0x80808080, data.rotation[i], 0, 0, data.job_id); + } + } + else + { + foreach(i; 0..data.length) + { + short depth = cast(short)(data.depth[i] * 8 + data.locations[i].y); + launcher.renderer.draw(space_invaders.texture, data.locations[i].value, data.scale[i], data.textures[i].coords, depth, 0x80808080, 0, 0, 0, data.job_id); + } + } + } + //if(data.thread_id == 0)launcher.renderer.pushData(); + } +} + struct CollisionSystem { mixin ECS.System; @@ -241,31 +1067,82 @@ struct LaserShootingSystem mixin ECS.System!32; bool shoot = false; - float[10] laser_shoot_times = [2000,1500,1000,700,500,300,100,50,10,1]; - CLocation* laser_location; - CVelocity* laser_velocity; - + __gshared vec4[] fire_frames = [vec4(96,64,8,16)*px,vec4(104,64,8,16)*px,vec4(112,64,8,16)*px,vec4(120,64,8,16)*px,vec4(128,64,8,16)*px, + vec4(136,64,8,16)*px,vec4(144,64,8,16)*px,vec4(152,64,8,16)*px,vec4(160,64,8,16)*px]; + + // __gshared vec4[] fire_frames = [vec4(0,160,8,16)*px,vec4(16,160,16,16)*px,vec4(32,160,16,16)*px,vec4(48,160,16,16)*px,vec4(64,160,16,16)*px, + // vec4(80,160,16,16)*px,vec4(96,160,16,16)*px,vec4(112,160,16,16)*px]; + struct EntitiesData { ///variable named "length" contain entites count uint length; - @readonly CShootDirection[] shoot_direction; - @readonly @optional CAutoShoot[] auto_shoot; + CWeapon[] laser; @readonly CLocation[] location; - CLaserWeapon[] laser; + @readonly CGuild[] guild; + + @optional @readonly CShootDirection[] shoot_direction; + @optional @readonly CWeaponLocation[] weapon_location; + @optional @readonly CAutoShoot[] auto_shoot; + @optional @readonly CVelocity[] velocity; + @optional @readonly CRotation[] rotation; } + + //EntityTemplate* laser_tmpl; + EntityTemplate* fire_tmpl; + + //EntityTemplate*[5] bullet_tmpl; ///Called inside "registerSystem" function - /*void onCreate() + void onCreate() { - laser_location = space_invaders.laser_tmpl.getComponent!CLocation; - }*/ + /*bullet_tmpl[0] = launcher.manager.allocateTemplate( + [CLocation.component_id, CTexture.component_id, CVelocity.component_id, + CScale.component_id, CBullet.component_id, CGuild.component_id].staticArray + ); + bullet_tmpl[0].getComponent!CTexture().coords = vec4(0,24,2,8)*px; + bullet_tmpl[0].getComponent!CScale().value = vec2(2,8); + + bullet_tmpl[1] = launcher.manager.allocateTemplate(bullet_tmpl[0]); + bullet_tmpl[2] = launcher.manager.allocateTemplate(bullet_tmpl[0]); + bullet_tmpl[2].getComponent!CTexture().coords = vec4(64,32,8,16)*px; + bullet_tmpl[2].getComponent!CScale().value = vec2(8,16); + bullet_tmpl[3] = launcher.manager.allocateTemplate(bullet_tmpl[0]); + bullet_tmpl[3].getComponent!CTexture().coords = vec4(56,32,2,2)*px; + bullet_tmpl[3].getComponent!CScale().value = vec2(2,2); + // bullet_tmpl[3].getComponent!CTexture().coords = vec4(48,32,8,8)*px; + // bullet_tmpl[3].getComponent!CScale().value = vec2(8,8); + bullet_tmpl[4] = launcher.manager.allocateTemplate(bullet_tmpl[0]);*/ + + + fire_tmpl = launcher.manager.allocateTemplate( + [CLocation.component_id, CTexture.component_id, CScale.component_id, + CAnimation.component_id, CParticle.component_id, CRotation.component_id, + CVelocity.component_id, CDamping.component_id].staticArray + ); + + fire_tmpl.getComponent!CTexture().coords = vec4(96,64,8,16)*px; + fire_tmpl.getComponent!CScale().value = vec2(8,16); + fire_tmpl.getComponent!(CParticle).life = 300; + *fire_tmpl.getComponent!(CAnimation) = CAnimation(fire_frames, 0, 3); + } + + void onDestroy() + { + //launcher.manager.freeTemplate(laser_tmpl); + /*foreach (EntityTemplate* tmpl; bullet_tmpl) + { + launcher.manager.freeTemplate(tmpl); + }*/ + launcher.manager.freeTemplate(fire_tmpl); + } bool onBegin() { - laser_location = space_invaders.laser_tmpl.getComponent!CLocation; + /*laser_location = space_invaders.laser_tmpl.getComponent!CLocation; laser_velocity = space_invaders.laser_tmpl.getComponent!CVelocity; + laser_guild = space_invaders.laser_tmpl.getComponent!CGuild;*/ if(launcher.getKeyState(SDL_SCANCODE_SPACE)) { shoot = true; @@ -281,14 +1158,69 @@ struct LaserShootingSystem { foreach(i;0..data.length) { - CLaserWeapon* laser = &data.laser[i]; + CWeapon* laser = &data.laser[i]; laser.shoot_time += launcher.delta_time; - while(laser.shoot_time > laser_shoot_times[laser.level - 1]) + while(laser.shoot_time > CWeapon.levels[laser.level - 1].reload_time) { - laser.shoot_time -= laser_shoot_times[laser.level - 1]; + CVelocity laser_velocity; + CGuild laser_guild; + CLocation laser_location; + CVelocity fire_velocity; + CLocation fire_location; + CRotation fire_rotation; + + laser.shoot_time -= CWeapon.levels[laser.level - 1].reload_time; laser_location.value = data.location[i]; - laser_velocity.value = vec2(randomf()*0.5-0.25,data.shoot_direction[i].direction == Direction.up ? 1.0 : -1.0); - launcher.manager.addEntity(space_invaders.laser_tmpl); + + laser_velocity.value = vec2((randomf()*2-1) * CWeapon.levels[laser.level - 1].dispersion,1);//data.shoot_direction[i].direction == Direction.up ? 1.0 : -1.0); + if(data.shoot_direction && data.shoot_direction[i].direction == Direction.down)laser_velocity.y = -1; + + laser_guild.guild = data.guild[i].guild; + + if(laser.level < 3)laser_velocity.value = laser_velocity.value * 0.4f; + + if(data.velocity) + { + fire_velocity.value = data.velocity[i]; + //laser_velocity.value += data.velocity[i] * 0.5; + } + else fire_velocity.value = vec2(0,0); + + fire_location.value = data.location[i]; + if(data.shoot_direction[i].direction == Direction.down) + { + fire_rotation.value = PI; + //fire_location.value.y -= 16; + } + else + { + fire_rotation.value = 0; + //fire_location.value.y += 24; + } + + if(data.rotation) + { + float sinn = sinf(data.rotation[i]); + float coss = cosf(data.rotation[i]); + float x = laser_velocity.y*sinn + laser_velocity.x*coss; + float y = laser_velocity.y*coss + laser_velocity.x*sinn; + laser_velocity.value = vec2(x,y); + fire_rotation.value = data.rotation[i]; + if(data.weapon_location) + { + vec2 rel_pos = vec2(data.weapon_location[i].rel_pos.y*sinn+data.weapon_location[i].rel_pos.x*coss, data.weapon_location[i].rel_pos.y*coss+data.weapon_location[i].rel_pos.x*sinn); + laser_location.value += rel_pos; + fire_location.value += rel_pos; + } + } + else if(data.weapon_location) + { + laser_location.value += data.weapon_location[i].rel_pos; + fire_location.value += data.weapon_location[i].rel_pos; + } + + launcher.manager.addEntity(space_invaders.bullet_tmpl[data.laser[i].type],[laser_velocity.ref_, laser_guild.ref_, laser_location.ref_].staticArray); + launcher.manager.addEntity(fire_tmpl,[fire_location.ref_, fire_rotation.ref_, fire_velocity.ref_].staticArray); } } } @@ -296,15 +1228,209 @@ struct LaserShootingSystem { foreach(i;0..data.length) { - CLaserWeapon* laser = &data.laser[i]; + CWeapon* laser = &data.laser[i]; laser.shoot_time += launcher.delta_time; - if(laser.shoot_time > laser_shoot_times[laser.level - 1])laser.shoot_time = laser_shoot_times[laser.level - 1]; + if(laser.shoot_time > CWeapon.levels[laser.level - 1].reload_time)laser.shoot_time = CWeapon.levels[laser.level - 1].reload_time; } } } } +struct DampingSystem +{ + mixin ECS.System!32; + + struct EntitiesData + { + uint length; + const (Entity)[] entity; + @readonly CDamping[] damping; + CVelocity[] velocity; + } + + float[10] damp = 0; + + bool onBegin() + { + foreach(i;0..10) + { + damp[i] = powf((0.98 - cast(float)i * 0.02),launcher.delta_time*0.1); + } + + return true; + } + + void onUpdate(EntitiesData data) + { + foreach(i; 0..data.length) + { + data.velocity[i] = data.velocity[i] * damp[data.damping[i]]; + } + } +} + +struct LaserCollisionSystem +{ + mixin ECS.System!32; + + mixin ECS.ReadOnlyDependencies!(ShootGridDependency); + + struct EntitiesData + { + ///variable named "length" contain entites count + uint length; + const (Entity)[] entity; + @readonly CLocation[] location; + @readonly CBullet[] laser; + @readonly CGuild[] guild; + } + + void onUpdate(EntitiesData data) + { + EntityID id; + foreach(i; 0..data.length) + { + if(space_invaders.shoot_grid.test(id, data.location[i], cast(ubyte)(~(1 << data.guild[i].guild)))) + { + launcher.manager.sendEvent(id, EBulletHit(data.entity[i].id,1)); + //launcher.manager.removeEntity(data.entity[i].id); + } + } + } +} + +struct ParticleEmittingSystem +{ + mixin ECS.System!32; + + struct EntitiesData + { + uint length; + //uint thread_id; + CParticleEmitterTime[] emit_time; + @readonly CLocation[] location; + @readonly CParticleEmitter[] emitter; + + @optional @readonly CVelocity[] velocity; + @optional @readonly CDepth[] depth; + } + + __gshared vec4[] flashes = [vec4(224,0,16,16)*px,vec4(240,0,16,16)*px,vec4(256,0,16,16)*px,vec4(272,0,16,16)*px,vec4(288,0,16,16)*px, + vec4(304,0,16,16)*px,vec4(320,0,16,16)*px]; + + EntityTemplate*[1] templates; + + void onCreate() + { + templates[0] = launcher.manager.allocateTemplate( + [CLocation.component_id, CTexture.component_id, CScale.component_id, + CAnimation.component_id, CParticle.component_id, CRotation.component_id, + CVelocity.component_id, CDamping.component_id, CDepth.component_id].staticArray); + *templates[0].getComponent!CAnimation() = CAnimation(flashes,0,2); + *templates[0].getComponent!CParticle() = CParticle(350); + //*templates[0].getComponent!CDepth() = CDepth(-3); + } + + void onDestroy() + { + foreach(tmpl; templates) + { + launcher.manager.freeTemplate(tmpl); + } + } + + void onUpdate(EntitiesData data) + { + foreach(i;0..data.length) + { + data.emit_time[i].time -= launcher.delta_time; + while(data.emit_time[i].time < 0) + { + CVelocity velocity; + CDepth depth; + + CParticleEmitter* emitter = &data.emitter[i]; + data.emit_time[i].time += emitter.time_range.x + randomf() * emitter.time_range.y; + + if(data.velocity) + { + velocity.value = data.velocity[i]; + } + + if(data.depth) + { + depth.depth = data.depth[i]; + } + + launcher.manager.addEntity(templates[0],[data.location[i].ref_,velocity.ref_,depth.ref_].staticArray); + } + } + } +} + +struct UpgradeCollisionSystem +{ + mixin ECS.System!32; + + mixin ECS.ReadOnlyDependencies!(ShootGridDependency); + + struct EntitiesData + { + ///variable named "length" contain entites count + uint length; + const (Entity)[] entity; + @readonly CLocation[] location; + @readonly CUpgrade[] upgrade; + } + + void onUpdate(EntitiesData data) + { + EntityID id; + foreach(i; 0..data.length) + { + if(space_invaders.shoot_grid.test(id, data.location[i], cast(ubyte)(0xFF))) + { + Entity* entity = launcher.manager.getEntity(id); + if(entity.hasComponent(CShip.component_id)) + { + launcher.manager.sendEvent(id, EUpgrade()); + launcher.manager.removeEntity(data.entity[i].id); + } + } + } + } +} + +struct UpgradeSystem +{ + mixin ECS.System; + + struct EntitiesData + { + const (Entity)[] entity; + //@readonly CShip[] ship; + } + + void handleEvent(Entity* entity, EUpgrade event) + { + CWeapon* laser = entity.getComponent!CWeapon; + if(laser) + { + if(laser.level < CWeapon.levels.length)laser.level++; + } + CShip* ship = entity.getComponent!CShip; + if(ship) + { + CChildren* children = entity.getComponent!CChildren; + foreach(child;children.childern) + { + launcher.manager.sendEvent(child,EUpgrade()); + } + } + } +} + struct ChangeDirectionSystem { mixin ECS.System!32; @@ -320,6 +1446,7 @@ struct ChangeDirectionSystem CVelocity[] velocity; const(CSideMove)[] side_move; + @optional const(CScale)[] scale; } void onCreate() @@ -330,19 +1457,6 @@ struct ChangeDirectionSystem } } - /*bool onBegin() - { - foreach(direction; groups_directions) - { - if(direction != cast(Direction)-1)//return true; - { - has_changes = true; - break; - } - } - return true; - }*/ - void onEnd() { if(has_changes) @@ -358,13 +1472,8 @@ struct ChangeDirectionSystem if(direction != cast(Direction)-1) { has_changes = true; - //direction = cast(Direction)-1; } } - /*foreach(ref direction; groups_directions) - { - direction = cast(Direction)-1; - }*/ } void onUpdate(EntitiesData data) @@ -409,6 +1518,34 @@ struct ChangeDirectionSystem } } } + else if(data.scale) + { + foreach(i;0..data.length) + { + if(data.locations[i].x - data.scale[i].x * 0.5 < 0) + { + if(data.side_move[i].group == -1) + { + if(data.velocity[i].x < 0)data.velocity[i].x = -data.velocity[i].x; + } + else + { + groups_directions[data.side_move[i].group] = Direction.right; + } + } + else if(data.locations[i].x + data.scale[i].x * 0.5 > space_invaders.map_size.x) + { + if(data.side_move[i].group == -1) + { + if(data.velocity[i].x > 0)data.velocity[i].x = -data.velocity[i].x; + } + else + { + groups_directions[data.side_move[i].group] = Direction.left; + } + } + } + } else { foreach(i;0..data.length) @@ -435,36 +1572,256 @@ struct ChangeDirectionSystem groups_directions[data.side_move[i].group] = Direction.left; } } - //if(data.locations[i].y < 0) data.locations[i].y = 0; - //else if(data.locations[i].y > space_invaders.map_size.y)data.locations[i].y = space_invaders.map_size.y; } } } +} - void handleEvent(Entity* entity, EChangeDirection event) +struct HitMarkingSystem +{ + mixin ECS.System!16; + + struct EntitiesData { - CSideMove* side_move = entity.getComponent!CSideMove; - if(side_move && side_move.group != -1) + uint length; + CHitMark[] mark; + } + + void onUpdate(EntitiesData data) + { + foreach(i;0..data.length) { - groups_directions[side_move.group] = event.direction; - return; + //if(data.mark[i] < 10)data.mark[i] = 0; + //else data.mark[i] -= 1; + data.mark[i] = cast(ubyte)(data.mark[i] * 0.9); } - //Entity* entity = launcher.manager.getEntity(event.entity_id); - CVelocity* velocity = entity.getComponent!CVelocity; - final switch(event.direction) + } +} + +struct HitPointsSystem +{ + mixin ECS.System; + + __gshared vec4[] upgrade_laser_frames = [vec4(96,80,16,16)*px,vec4(112,80,16,16)*px,vec4(128,80,16,16)*px,vec4(144,80,16,16)*px,vec4(128,80,16,16)*px,vec4(112,80,16,16)*px]; + __gshared vec4[] explosion_laser_frames = [vec4(80,128,16,16)*px,vec4(96,128,16,16)*px,vec4(112,128,16,16)*px,vec4(128,128,16,16)*px,vec4(144,128,16,16)*px,vec4(160,128,16,16)*px,vec4(176,128,16,16)*px,vec4(192,128,16,16)*px,vec4(208,128,16,16)*px]; + + EntityTemplate* upgrade_tmpl; + EntityTemplate* explosion_tmpl; + + struct EntitiesData + { + CHitPoints[] hp; + } + + void onCreate() + { + upgrade_tmpl = launcher.manager.allocateTemplate( + [CVelocity.component_id, CLocation.component_id, CTexture.component_id, + CScale.component_id, CUpgrade.component_id, CAnimation.component_id, + CAnimationLooped.component_id].staticArray); + //tex_comp.tex = space_invaders.texture;//ship_tex; + upgrade_tmpl.getComponent!CTexture().coords = vec4(0*px,32*px,16*px,16*px); + *upgrade_tmpl.getComponent!CAnimation = CAnimation(upgrade_laser_frames, 0, 1); + upgrade_tmpl.getComponent!CVelocity().value = vec2(0,-0.1); + + explosion_tmpl = launcher.manager.allocateTemplate( + [CDepth.component_id, CParticle.component_id, CLocation.component_id, + CTexture.component_id, CScale.component_id, CAnimation.component_id].staticArray); + //explosion_tmpl.getComponent!(CTexture).tex = space_invaders.texture; + *explosion_tmpl.getComponent!CAnimation = CAnimation(explosion_laser_frames, 0, 1.333); + explosion_tmpl.getComponent!(CParticle).life = 600; + *explosion_tmpl.getComponent!CDepth = -1; + } + + void onDestroy() + { + launcher.manager.freeTemplate(upgrade_tmpl); + launcher.manager.freeTemplate(explosion_tmpl); + } + + /*void handleEvent(Entity* entity, EDamage event) + { + CHitPoints* hp = entity.getComponent!CHitPoints; + if(*hp <= 0)return; + *hp -= event.damage; + if(*hp <= 0) { - case Direction.up: - if(velocity.value.y > 0)velocity.value.y = -velocity.value.y; - break; - case Direction.down: - if(velocity.value.y < 0)velocity.value.y = -velocity.value.y; - break; - case Direction.left: - if(velocity.value.x > 0)velocity.value.x = -velocity.value.x; - break; - case Direction.right: - if(velocity.value.x < 0)velocity.value.x = -velocity.value.x; - break; + launcher.manager.sendEvent(entity.id, EDeath()); + //launcher.manager.removeEntity(entity.id); + } + CHitMark* hit_mark = entity.getComponent!CHitMark; + if(hit_mark)hit_mark.value = 127; + }*/ + + void handleEvent(Entity* entity, EBulletHit event) + { + CHitPoints* hp = entity.getComponent!CHitPoints; + if(*hp <= 0)return; + launcher.manager.removeEntity(event.id); + *hp -= event.damage; + if(*hp <= 0) + { + launcher.manager.sendEvent(entity.id, EDeath()); + //launcher.manager.removeEntity(entity.id); + } + CHitMark* hit_mark = entity.getComponent!CHitMark; + if(hit_mark)hit_mark.value = 127; + } + + void handleEvent(Entity* entity, EDeath event) + { + CEnemy* enemy = entity.getComponent!CEnemy; + if(enemy) + { + CLocation* location = entity.getComponent!CLocation; + if(location) + { + if(randomRange(0, 1000) < 5) + { + launcher.manager.addEntity(upgrade_tmpl,[location.ref_].staticArray); + } + launcher.manager.addEntity(explosion_tmpl,[location.ref_].staticArray); + } + } + launcher.manager.removeEntity(entity.id); + } +} + +struct ChildDestroySystem +{ + mixin ECS.System; + + struct EntitiesData + { + CTargetParent[] parent; + } + + void handleEvent(Entity* entity, EDeath event) + { + CTargetParent* parent = entity.getComponent!CTargetParent; + if(parent) + { + launcher.manager.sendEvent(parent.parent, EDestroyedChild(entity.id)); + } + } +} + +struct ShootWaveSystem +{ + mixin ECS.System; + + struct EntitiesData + { + CLocation[] location; + CShootWaveUponDeath[] shoot_wave; + } + + vec2[] dirs; + + void onCreate() + { + enum count = 24; + dirs = Mallocator.makeArray!vec2(count); + float step = 2 * PI / cast(float)count; + foreach(i;0..count) + { + float angle = step * i; + dirs[i] = vec2(sinf(angle),cosf(angle)) * 0.2; + } + } + + void onDestroy() + { + Mallocator.dispose(dirs); + } + + void handleEvent(Entity* entity, EDeath event) + { + + CShootWaveUponDeath* wave = entity.getComponent!CShootWaveUponDeath; + CLocation* location = entity.getComponent!CLocation; + CGuild* guild = entity.getComponent!CGuild; + + //LaserShootingSystem.bullet_tmpl + EntityTemplate* tmpl = space_invaders.bullet_tmpl[wave.bullet_type]; + foreach(dir;dirs) + { + if(guild)launcher.manager.addEntity(tmpl,[location.ref_,guild.ref_,CVelocity(dir).ref_].staticArray); + else launcher.manager.addEntity(tmpl,[location.ref_,CVelocity(dir).ref_].staticArray); + } + //launcher.manager.addEntity(tmpl);//,[location.ref_].staticArray); + + //launcher.manager.addEntity(space_invaders.bullet_tmpl[0]); + } +} + +struct PartsDestroySystem +{ + mixin ECS.System; + + struct EntitiesData + { + CInit[] init; + CChildren[] children; + CParts[] parts; + } + + EntityTemplate* flashes_emitter; + + void onCreate() + { + flashes_emitter = launcher.manager.allocateTemplate( + [ + CVelocity.component_id, CLocation.component_id, CParticleEmitter.component_id, + CParticleEmitterTime.component_id, CTargetParent.component_id, CDepth.component_id + ].staticArray); + *flashes_emitter.getComponent!CParticleEmitter() = CParticleEmitter(vec2(0,0), vec2(800,1600), 0); + } + + void onDestroy() + { + launcher.manager.freeTemplate(flashes_emitter); + } + + void handleEvent(Entity* entity, EDestroyedChild event) + { + CParts* parts = entity.getComponent!CParts; + parts.count--; + + CInit* init = entity.getComponent!CInit; + if(init.type == CInit.Type.boss) + { + CChildren* children = entity.getComponent!CChildren; + foreach(ref EntityID child; children.childern) + { + if(child == event.id) + { + Entity* child_entity = launcher.manager.getEntity(child); + if(child_entity) + { + CLocation location; + CTargetParent* target_parent = child_entity.getComponent!CTargetParent; + CDepth* target_depth = child_entity.getComponent!CDepth; + CLocation* target_location = child_entity.getComponent!CLocation; + //CVelocity* velocity = child_entity.getComponent!CTargetParent; + + if(target_location)location = *target_location; + + *flashes_emitter.getComponent!CTargetParent() = *target_parent; + if(target_depth)child = launcher.manager.addEntity(flashes_emitter, [target_depth.ref_, location.ref_].staticArray).id; + else child = launcher.manager.addEntity(flashes_emitter, [location.ref_].staticArray).id; + } + break; + } + } + } + + if(parts.count == 0) + { + if(init.type == CInit.Type.boss) + { + launcher.manager.addComponents(entity.id, CHitPoints(100), CShootGrid()); + } } } } @@ -481,7 +1838,10 @@ struct ClampPositionSystem //components are treated as required by default CLocation[] locations; - @optional const (CLaser)[] laser; + @optional @readonly CColliderScale[] collider_scale; + @optional @readonly CScale[] scale; + @optional const (CBullet)[] laser; + @optional const (CUpgrade)[] upgrade; //@optional CVelocity[] velocity; //@optional const (CSideMove)[] side_move; } @@ -490,7 +1850,7 @@ struct ClampPositionSystem void onUpdate(EntitiesData data) { - if(data.laser) + if(data.laser || data.upgrade) { foreach(i;0..data.length) { @@ -532,6 +1892,28 @@ struct ClampPositionSystem else if(data.locations[i].y > space_invaders.map_size.y)data.locations[i].y = space_invaders.map_size.y; } }*/ + else if(data.collider_scale) + { + foreach(i;0..data.length) + { + vec2 hscale = data.collider_scale[i] * 0.5; + if(data.locations[i].x - hscale.x < 0)data.locations[i].x = hscale.x; + else if(data.locations[i].x + hscale.x > space_invaders.map_size.x)data.locations[i].x = space_invaders.map_size.x - hscale.x; + if(data.locations[i].y - hscale.y < 0)data.locations[i].y = hscale.y; + else if(data.locations[i].y + hscale.y > space_invaders.map_size.y)data.locations[i].y = space_invaders.map_size.y - hscale.y; + } + } + else if(data.scale) + { + foreach(i;0..data.length) + { + vec2 hscale = data.scale[i] * 0.5; + if(data.locations[i].x - hscale.x < 0)data.locations[i].x = hscale.x; + else if(data.locations[i].x + hscale.x > space_invaders.map_size.x)data.locations[i].x = space_invaders.map_size.x - hscale.x; + if(data.locations[i].y - hscale.y < 0)data.locations[i].y = hscale.y; + else if(data.locations[i].y + hscale.y > space_invaders.map_size.y)data.locations[i].y = space_invaders.map_size.y - hscale.y; + } + } else { foreach(i;0..data.length) @@ -556,10 +1938,10 @@ struct MovementSystem const (CVelocity)[] velocity; //components are treated as required by default CLocation[] locations; - //@optional const (CLaser)[] laser; + //@optional const (CBullet)[] laser; const (Entity)[] entities; - @optional CSideMove[] side_move; + //@optional CSideMove[] side_move; } void onUpdate(EntitiesData data) @@ -572,6 +1954,238 @@ struct MovementSystem } } +struct AnimationSystem +{ + mixin ECS.System!32; + + struct EntitiesData + { + uint length; + CAnimation[] animation; + CTexture[] texture; + @optional @readonly CAnimationLooped[] looped; + } + + void onUpdate(EntitiesData data) + { + float dt = launcher.delta_time * 0.01; + if(data.looped) + { + foreach(i;0..data.length) + { + data.animation[i].time += dt * data.animation[i].speed; + while(cast(uint)data.animation[i].time >= data.animation[i].frames.length)data.animation[i].time -= cast(float)data.animation[i].frames.length; + if(cast(uint)(data.animation[i].time) >= data.animation[i].frames.length)assert(0); + uint index = cast(uint)(data.animation[i].time); + if(index < data.animation[i].frames.length)data.texture[i].coords = data.animation[i].frames[index]; + } + } + else + { + foreach(i;0..data.length) + { + data.animation[i].time += dt * data.animation[i].speed; + if(cast(uint)data.animation[i].time >= data.animation[i].frames.length)data.animation[i].time = data.animation[i].frames.length - 0.9; + uint index = cast(uint)(data.animation[i].time); + if(index < data.animation[i].frames.length)data.texture[i].coords = data.animation[i].frames[index]; + } + } + + } +} + +struct ParticleSystem +{ + mixin ECS.System!32; + + struct EntitiesData + { + uint length; + @readonly Entity[] entitiy; + CParticle[] particle; + } + + void onUpdate(EntitiesData data) + { + foreach(i;0..data.length) + { + data.particle[i].life -= launcher.delta_time; + if(data.particle[i].life < 0)launcher.manager.removeEntity(data.entitiy[i].id); + } + } +} + +struct RotateToTargetSystem +{ + mixin ECS.System!32; + + struct EntitiesData + { + int length; + @readonly CTarget[] target; + @readonly CLocation[] location; + CRotation[] rotation; + } + + void onUpdate(EntitiesData data) + { + foreach(i;0..data.length) + { + Entity* target = launcher.manager.getEntity(data.target[i].target); + if(target) + { + CLocation* target_loc = target.getComponent!CLocation; + if(target_loc) + { + vec2 rel_pos = target_loc.value - data.location[i]; + float length = sqrtf(rel_pos.x*rel_pos.x + rel_pos.y*rel_pos.y); + if(rel_pos.x > 0)data.rotation[i] = acosf(rel_pos.y/length); + else data.rotation[i] = 2 * PI - acosf(rel_pos.y/length); + + } + } + //CLocation* target_loc = + //vec2 rel_pos = d + //data.rotation = 0; + } + } +} + +struct ShipTargetSystem +{ + mixin ECS.System!32; + + struct EntitiesData + { + int length; + @readonly CTargetPlayerShip[] target_player; + CTarget[] target; + } + + EntityID player_ship; + + void iterateShips(CShipIterator.EntitiesData data) + { + player_ship = data.entity[0].id; + } + + void onAddEntity(EntitiesData data) + { + foreach(i;0..data.length) + { + data.target[i].target = player_ship; + } + } + + bool onBegin() + { + Entity* ship = launcher.manager.getEntity(player_ship); + if(ship is null) + { + launcher.manager.callEntitiesFunction!CShipIterator(&iterateShips); + ship = launcher.manager.getEntity(player_ship); + if(ship is null)return false; + return true; + } + return false; + } + + void onUpdate(EntitiesData data) + { + foreach(i;0..data.length) + { + data.target[i].target = player_ship; + } + } +} + +struct CShipIterator +{ + mixin ECS.System!1; + + struct EntitiesData + { + @readonly Entity[] entity; + @readonly CShip[] ship; + } + + bool onBegin() + { + return false; + } + + void onUpdate(EntitiesData data) + { + + } +} + +/*struct SpawnUponDeathSystem +{ + mixin ECS.System; + + struct EntitiesData + { + @readonly CSpawnUponDeath[] spawn; + @optional CTargetParent[] parent; + } + + EntityTemplate* flashes_emitter; + + void onCreate() + { + flashes_emitter = launcher.manager.allocateTemplate( + [ + CVelocity.component_id, CLocation.component_id, CParticleEmitter.component_id, + CParticleEmitterTime.component_id, CTargetParent.component_id + ].staticArray); + *flashes_emitter.getComponent!CParticleEmitter() = CParticleEmitter(vec2(0,0), vec2(400,400), 0); + } + + void onDestroy() + { + launcher.manager.freeTemplate(flashes_emitter); + } + + void onRemoveEntity(EntitiesData data) + { + //CSpawnUponDeath[] spawn = + switch(data.spawn[0].type) + { + case CSpawnUponDeath.Type.flashes_emitter: + if(data.parent) + { + /*Entity* parent_entity = launcher.manager.getEntity(data.parent[0].parent); + CChildren* children = entity.getComponent!CChildren; + foreach(ref EntityID child; children.childern) + { + if(child == event.id) + { + Entity* child_entity = launcher.manager.getEntity(child); + if(child_entity) + { + *flashes_emitter.getComponent!CTargetParent = data.parent[0]; + launcher.manager.addEntity(flashes_emitter); + //child = launcher.manager.addEntity(flashes_emitter); + } + break; + } + } + } + break; + default:break; + } + } + + //void handleEvent(Entity* entity, ) +}//*/ + +extern(C) float sqrtf(float x) @nogc nothrow @system; +extern(C) float acosf(float x) @nogc nothrow @system; +extern(C) float sinf(float x) @nogc nothrow @system; +extern(C) float cosf(float x) @nogc nothrow @system; +extern(C) float powf(float x, float y) @nogc nothrow @system; + /** *System is responsible for movement of objects with CInput component. *In this example every entity has same speed when using movement system. @@ -588,7 +2202,8 @@ struct InputMovementSystem //read only components can be marked with @readonly attribute or with const expression instead const (CInput)[] input; //components are treated as required by default - CLocation[] locations; + //CLocation[] locations; + CVelocity[] velocity; CTexture[] textures; } @@ -601,26 +2216,28 @@ struct InputMovementSystem move_vector = vec2(0,0); if(launcher.getKeyState(SDL_SCANCODE_W)) { - move_vector = vec2(0,1); - return true; + move_vector += vec2(0,1); } else if(launcher.getKeyState(SDL_SCANCODE_S)) { - move_vector = vec2(0,-1); - return true; + move_vector += vec2(0,-1); } - else if(launcher.getKeyState(SDL_SCANCODE_A)) + if(launcher.getKeyState(SDL_SCANCODE_A)) { - move_vector = vec2(-1,0); - return true; + move_vector += vec2(-1,0); } else if(launcher.getKeyState(SDL_SCANCODE_D)) { - move_vector = vec2(1,0); + move_vector += vec2(1,0); + } + + if(move_vector.x != 0 ||move_vector.y != 0) + { + move_vector = move_vector / sqrtf(move_vector.x * move_vector.x + move_vector.y * move_vector.y); return true; } //don't call system update because no key pressed - return true; + return false; } /** @@ -631,22 +2248,33 @@ struct InputMovementSystem */ void onUpdate(EntitiesData data) { - if(move_vector.x == 0) + /*if(move_vector.x == 0) { foreach(i; 0..data.length) { data.textures[i].coords = vec4(0*px,80*px,48*px,32*px); } - return; - } + //return; + }*/ //move every entity using movement vector + //if(move_vector.x != 0 || move_vector.y != 0) foreach(i; 0..data.length) { - data.locations[i].x += move_vector.x * launcher.delta_time * 0.25; - data.locations[i].y += move_vector.y * launcher.delta_time * 0.25; - if(move_vector.x > 0)data.textures[i].coords = vec4(48*px,80*px,48*px,32*px); - else data.textures[i].coords = vec4(0*px,80*px,48*px,32*px); + data.velocity[i] += move_vector * launcher.delta_time * 0.005; + if(data.velocity[i].x > 0.5)data.velocity[i].x = 0.5; + else if(data.velocity[i].x < -0.5)data.velocity[i].x = -0.5; + if(data.velocity[i].y > 0.5)data.velocity[i].y = 0.5; + else if(data.velocity[i].y < -0.5)data.velocity[i].y = -0.5; + //data.locations[i].x += move_vector.x * launcher.delta_time * 0.25; + //data.locations[i].y += move_vector.y * launcher.delta_time * 0.25; + //if(move_vector.x > 0)data.textures[i].coords = vec4(48*px,80*px,48*px,32*px); + //else data.textures[i].coords = vec4(0*px,80*px,48*px,32*px); } + /*else + foreach(i; 0..data.length) + { + data.velocity[i] = vec2(0,0); + }*/ } } @@ -663,8 +2291,13 @@ void spaceInvadersStart() space_invaders.texture.create(); space_invaders.texture.load("assets/textures/atlas.png"); + space_invaders.shoot_grid = Mallocator.make!ShootGrid; + space_invaders.shoot_grid.create(ivec2(80,60), vec2(5,5)); + launcher.manager.beginRegister(); + launcher.manager.registerDependency(ShootGridDependency); + launcher.manager.registerComponent!CLocation; launcher.manager.registerComponent!CTexture; launcher.manager.registerComponent!CInput; @@ -673,21 +2306,72 @@ void spaceInvadersStart() launcher.manager.registerComponent!CScale; launcher.manager.registerComponent!CShootDirection; launcher.manager.registerComponent!CAutoShoot; - launcher.manager.registerComponent!CLaserWeapon; + launcher.manager.registerComponent!CWeapon; launcher.manager.registerComponent!CVelocity; - launcher.manager.registerComponent!CLaser; + launcher.manager.registerComponent!CBullet; launcher.manager.registerComponent!CSideMove; + launcher.manager.registerComponent!CDepth; + launcher.manager.registerComponent!CShootGrid; + launcher.manager.registerComponent!CGuild; + launcher.manager.registerComponent!CHitPoints; + launcher.manager.registerComponent!CHitMark; + launcher.manager.registerComponent!CUpgrade; + launcher.manager.registerComponent!CParticle; + launcher.manager.registerComponent!CMaxHitPoints; + launcher.manager.registerComponent!CAnimation; + launcher.manager.registerComponent!CRotation; + launcher.manager.registerComponent!CAnimationLooped; + launcher.manager.registerComponent!CDamping; + launcher.manager.registerComponent!CTargetParent; + launcher.manager.registerComponent!CTarget; + launcher.manager.registerComponent!CTargetPlayerShip; + launcher.manager.registerComponent!CChildren; + launcher.manager.registerComponent!CWeaponLocation; + launcher.manager.registerComponent!CInit; + launcher.manager.registerComponent!CBoss; + launcher.manager.registerComponent!CParts; + launcher.manager.registerComponent!CColliderScale; + launcher.manager.registerComponent!CParticleEmitter; + launcher.manager.registerComponent!CParticleEmitterTime; + launcher.manager.registerComponent!CSpawnUponDeath; + launcher.manager.registerComponent!CShootWaveUponDeath; launcher.manager.registerEvent!EChangeDirection; + launcher.manager.registerEvent!EDamage; + launcher.manager.registerEvent!EUpgrade; + launcher.manager.registerEvent!EDeath; + launcher.manager.registerEvent!EDestroyedChild; + launcher.manager.registerEvent!EBulletHit; //launcher.manager.registerSystem!MoveSystem(0); launcher.manager.registerSystem!DrawSystem(100); launcher.manager.registerSystem!InputMovementSystem(-100); + launcher.manager.registerSystem!MovementSystem(-99); + launcher.manager.registerSystem!ClampPositionSystem(-90); launcher.manager.registerSystem!LaserShootingSystem(0); - launcher.manager.registerSystem!MovementSystem(0); - launcher.manager.registerSystem!ClampPositionSystem(1); launcher.manager.registerSystem!ChangeDirectionSystem(0); - + launcher.manager.registerSystem!LaserCollisionSystem(-70); + launcher.manager.registerSystem!ShootGridManager(-80); + launcher.manager.registerSystem!ShootGridCleaner(-101); + launcher.manager.registerSystem!HitPointsSystem(0); + launcher.manager.registerSystem!HitMarkingSystem(-100); + launcher.manager.registerSystem!UpgradeCollisionSystem(-70); + launcher.manager.registerSystem!UpgradeSystem(-100); + launcher.manager.registerSystem!ParticleSystem(-100); + launcher.manager.registerSystem!AnimationSystem(-100); + launcher.manager.registerSystem!DampingSystem(-101); + launcher.manager.registerSystem!MoveToParentTargetSystem(-98); + launcher.manager.registerSystem!ParentOwnerSystem(-101); + launcher.manager.registerSystem!ShipWeaponSystem(-100); + launcher.manager.registerSystem!ParticleEmittingSystem(-95); + launcher.manager.registerSystem!RotateToTargetSystem(-100); + launcher.manager.registerSystem!ShipTargetSystem(-110); + launcher.manager.registerSystem!CShipIterator(-100); + launcher.manager.registerSystem!PartsDestroySystem(-80); + launcher.manager.registerSystem!ChildDestroySystem(-110); + launcher.manager.registerSystem!ShootWaveSystem(-100); + //launcher.manager.registerSystem!SpawnUponDeathSystem(-110); + launcher.manager.endRegister(); launcher.gui_manager.addSystem(DrawSystem.system_id,"Draw System"); @@ -696,102 +2380,194 @@ void spaceInvadersStart() launcher.gui_manager.addSystem(MovementSystem.system_id,"Movement System"); launcher.gui_manager.addSystem(ClampPositionSystem.system_id,"Clamp Position System"); launcher.gui_manager.addSystem(ChangeDirectionSystem.system_id,"Change Direction System"); + launcher.gui_manager.addSystem(LaserCollisionSystem.system_id,"Laser Collision System"); + launcher.gui_manager.addSystem(ShootGridManager.system_id,"Shoot Grid Manager"); + launcher.gui_manager.addSystem(ShootGridCleaner.system_id,"Shoot Grid Cleaner"); + launcher.gui_manager.addSystem(HitPointsSystem.system_id,"Hit Points System"); + launcher.gui_manager.addSystem(HitMarkingSystem.system_id,"Hit Marking System"); + launcher.gui_manager.addSystem(UpgradeCollisionSystem.system_id,"Upgrade Collision System"); + launcher.gui_manager.addSystem(UpgradeSystem.system_id,"Upgrade System"); + launcher.gui_manager.addSystem(ParticleSystem.system_id,"Particle System"); + launcher.gui_manager.addSystem(AnimationSystem.system_id,"Animation System"); + launcher.gui_manager.addSystem(DampingSystem.system_id,"Damping System"); + launcher.gui_manager.addSystem(MoveToParentTargetSystem.system_id,"Move To Target System"); + launcher.gui_manager.addSystem(ParentOwnerSystem.system_id,"Parent Owner System"); + launcher.gui_manager.addSystem(ShipWeaponSystem.system_id,"Ship Weapon System"); + launcher.gui_manager.addSystem(ParticleEmittingSystem.system_id,"Particle Emitting System"); + launcher.gui_manager.addSystem(RotateToTargetSystem.system_id,"Rotate To Target System"); + launcher.gui_manager.addSystem(ShipTargetSystem.system_id,"Ship Target System"); + launcher.gui_manager.addSystem(PartsDestroySystem.system_id,"Parts Destroy System"); + launcher.gui_manager.addSystem(ChildDestroySystem.system_id,"Child Destroy System"); + launcher.gui_manager.addSystem(ShootWaveSystem.system_id,"Shoot Wave System"); + //launcher.gui_manager.addSystem(SpawnUponDeathSystem.system_id,"Child Destroy System"); //launcher.manager.getSystem(CleanSystem.system_id).disable(); { - ushort[7] components = [CLocation.component_id, CTexture.component_id, CInput.component_id, CShip.component_id, CScale.component_id, CLaserWeapon.component_id, CShootDirection.component_id]; - space_invaders.ship_tmpl = launcher.manager.allocateTemplate(components); + space_invaders.ship_tmpl = launcher.manager.allocateTemplate( + [CVelocity.component_id, CHitMark.component_id, CHitPoints.component_id, + CLocation.component_id, CTexture.component_id, CInput.component_id, + CShip.component_id, CScale.component_id, CColliderScale.component_id, + CShootDirection.component_id, CShootGrid.component_id, CGuild.component_id, + CDamping.component_id, CChildren.component_id, CInit.component_id].staticArray + ); + space_invaders.ship_tmpl.getComponent!CTexture().coords = vec4(0,80,48,32)*px; + space_invaders.ship_tmpl.getComponent!CScale().value = vec2(48,32); + space_invaders.ship_tmpl.getComponent!CHitPoints().value = 1000; + space_invaders.ship_tmpl.getComponent!CDamping().value = 7; + space_invaders.ship_tmpl.getComponent!CInit().type = CInit.Type.space_ship; + space_invaders.ship_tmpl.getComponent!CColliderScale().value = vec2(26,24); - CScale* scale_comp = space_invaders.ship_tmpl.getComponent!CScale; - scale_comp.value = vec2(48,32); - CTexture* tex_comp = space_invaders.ship_tmpl.getComponent!CTexture; - tex_comp.tex = space_invaders.texture;//ship_tex; - tex_comp.coords = vec4(0*px,80*px,48*px,32*px); - CLocation* loc_comp = space_invaders.ship_tmpl.getComponent!CLocation; - loc_comp.value = vec2(64,64); - CLaserWeapon* weapon = space_invaders.ship_tmpl.getComponent!CLaserWeapon; - weapon.level = 10; - - launcher.manager.addEntity(space_invaders.ship_tmpl); + launcher.manager.addEntity(space_invaders.ship_tmpl,[CLocation(vec2(64,64)).ref_].staticArray); } { - ushort[5] components = [CLocation.component_id, CTexture.component_id, CVelocity.component_id, CScale.component_id, CLaser.component_id]; + ushort[6] components = [CLocation.component_id, CTexture.component_id, CVelocity.component_id, CScale.component_id, CBullet.component_id, CGuild.component_id]; space_invaders.laser_tmpl = launcher.manager.allocateTemplate(components); - CTexture* tex_comp = space_invaders.laser_tmpl.getComponent!CTexture; - tex_comp.tex = space_invaders.texture;//laser_tex; - tex_comp.coords = vec4(0*px,24*px,2*px,8*px); - CScale* scale_comp = space_invaders.laser_tmpl.getComponent!CScale; - scale_comp.value = vec2(2,8); - CVelocity* vel_comp = space_invaders.laser_tmpl.getComponent!CVelocity; - vel_comp.value = vec2(0,1); + space_invaders.laser_tmpl.getComponent!CTexture().coords = vec4(0,24,2,8)*px; + space_invaders.laser_tmpl.getComponent!CScale().value = vec2(2,8); + space_invaders.laser_tmpl.getComponent!CVelocity().value = vec2(0,1); } EntityTemplate* enemy_tmpl; EntityTemplate* grouped_tmpl; + EntityTemplate* tower_tmpl; + EntityTemplate* boss_tmpl; + //EntityTemplate* tower_weapon_tmpl; EntityID enemy_id; EntityID grouped_id; { - ushort[8] components = [CVelocity.component_id, CAutoShoot.component_id, CLocation.component_id, CTexture.component_id, CScale.component_id, CLaserWeapon.component_id, CEnemy.component_id, CShootDirection.component_id];//, CVelocity.component_id]; - space_invaders.enemy_tmpl = launcher.manager.allocateTemplate(components); + boss_tmpl = launcher.manager.allocateTemplate( + [CHitMark.component_id, CParts.component_id, CLocation.component_id, + CTexture.component_id, CScale.component_id, CEnemy.component_id, + CBoss.component_id, CGuild.component_id, CInit.component_id, + CChildren.component_id, CSideMove.component_id, CVelocity.component_id, + CDepth.component_id].staticArray + ); - CTexture* tex_comp = space_invaders.enemy_tmpl.getComponent!CTexture; - tex_comp.tex = space_invaders.texture;//ship_tex; - tex_comp.coords = vec4(32*px,32*px,16*px,16*px); - CLocation* loc_comp = space_invaders.enemy_tmpl.getComponent!CLocation; - loc_comp.value = vec2(64,space_invaders.map_size.y - 16); - CShootDirection* shoot_dir_comp = space_invaders.enemy_tmpl.getComponent!CShootDirection; - shoot_dir_comp.direction = Direction.down; - CVelocity* vel_comp = space_invaders.enemy_tmpl.getComponent!CVelocity; - vel_comp.value = vec2(0.1,0); + //CTexture* tex_comp = boss_tmpl.getComponent!CTexture; + //tex_comp.tex = space_invaders.texture;//ship_tex; + //tex_comp.coords = vec4(128*px,0*px,96*px,48*px); + //CLocation* loc_comp = boss_tmpl.getComponent!CLocation; + //loc_comp.value = vec2(64,space_invaders.map_size.y - 16); + boss_tmpl.getComponent!CTexture().coords = vec4(128,0,96,48)*px; + boss_tmpl.getComponent!CGuild().guild = 1; + boss_tmpl.getComponent!CInit().type = CInit.Type.boss; + boss_tmpl.getComponent!CScale().value = vec2(96,48); + boss_tmpl.getComponent!CDepth().depth = -1; + boss_tmpl.getComponent!CParts().count = 4; + boss_tmpl.getComponent!CVelocity().value = vec2(0.05,0); + } + + { + tower_tmpl = launcher.manager.allocateTemplate( + [CHitMark.component_id, CHitPoints.component_id, CLocation.component_id, + CTexture.component_id, CScale.component_id, CEnemy.component_id, + CShootGrid.component_id, CGuild.component_id, CInit.component_id, + CChildren.component_id].staticArray + ); + + tower_tmpl.getComponent!CTexture().coords = vec4(96,96,16,16)*px; + tower_tmpl.getComponent!CGuild().guild = 1; + tower_tmpl.getComponent!CInit().type = CInit.Type.tower; + tower_tmpl.getComponent!CHitPoints().value = 10; + } + + { + space_invaders.enemy_tmpl = launcher.manager.allocateTemplate( + [CWeaponLocation.component_id, CHitMark.component_id, CHitPoints.component_id, + CVelocity.component_id, CAutoShoot.component_id, CLocation.component_id, + CTexture.component_id, CScale.component_id, CWeapon.component_id, + CEnemy.component_id, CShootDirection.component_id, CShootGrid.component_id, + CGuild.component_id].staticArray + ); + + space_invaders.enemy_tmpl.getComponent!CTexture().coords = vec4(32,32,16,16)*px; + space_invaders.enemy_tmpl.getComponent!CShootDirection().direction = Direction.down; + space_invaders.enemy_tmpl.getComponent!CVelocity().value = vec2(0.1,0); + space_invaders.enemy_tmpl.getComponent!CGuild().guild = 1; + space_invaders.enemy_tmpl.getComponent!CWeaponLocation().rel_pos = vec2(0,-15); Entity* current_entity; - current_entity = launcher.manager.addEntity(space_invaders.enemy_tmpl); + current_entity = launcher.manager.addEntity(space_invaders.enemy_tmpl,[CLocation(vec2(32,space_invaders.map_size.y - 16)).ref_].staticArray); launcher.manager.addComponents(current_entity.id,CSideMove(0)); - loc_comp.value = vec2(128,space_invaders.map_size.y - 16); - current_entity = launcher.manager.addEntity(space_invaders.enemy_tmpl); + //loc_comp.value = vec2(128,space_invaders.map_size.y - 16); + current_entity = launcher.manager.addEntity(space_invaders.enemy_tmpl,[CLocation(vec2(128,space_invaders.map_size.y - 16)).ref_].staticArray); launcher.manager.addComponents(current_entity.id,CSideMove(-1)); enemy_id = current_entity.id; //enemy_tmpl = launcher.manager.allocateTemplate(current_entity.id); - loc_comp.value = vec2(256,space_invaders.map_size.y - 16); - launcher.manager.addEntity(space_invaders.enemy_tmpl); + //loc_comp.value = vec2(256,space_invaders.map_size.y - 16); + launcher.manager.addEntity(space_invaders.enemy_tmpl,[CLocation(vec2(256,space_invaders.map_size.y - 16)).ref_].staticArray); - loc_comp.value = vec2(0,space_invaders.map_size.y - 16); - current_entity = launcher.manager.addEntity(space_invaders.enemy_tmpl); + //loc_comp.value = vec2(0,space_invaders.map_size.y - 16); + current_entity = launcher.manager.addEntity(space_invaders.enemy_tmpl,[CLocation(vec2(0,space_invaders.map_size.y - 16)).ref_].staticArray); launcher.manager.addComponents(current_entity.id,CSideMove(0)); grouped_id = current_entity.id; //grouped_tmpl = launcher.manager.allocateTemplate(current_entity.id); } + + EntityTemplate* upgrade_tmpl; + + { + upgrade_tmpl = launcher.manager.allocateTemplate([CVelocity.component_id, CLocation.component_id, CTexture.component_id, CScale.component_id, CUpgrade.component_id, CAnimationLooped.component_id, CAnimation.component_id].staticArray); + upgrade_tmpl.getComponent!CTexture().coords = vec4(0,32,16,16)*px; + upgrade_tmpl.getComponent!CVelocity().value = vec2(0,-0.1); + *upgrade_tmpl.getComponent!CAnimation = CAnimation(HitPointsSystem.upgrade_laser_frames, 0, 0.75); + } + launcher.manager.commit(); enemy_tmpl = launcher.manager.allocateTemplate(enemy_id); grouped_tmpl = launcher.manager.allocateTemplate(grouped_id); - launcher.gui_manager.addTemplate(space_invaders.ship_tmpl,"Ship"); + space_invaders.bullet_tmpl[0] = launcher.manager.allocateTemplate( + [CLocation.component_id, CTexture.component_id, CVelocity.component_id, + CScale.component_id, CBullet.component_id, CGuild.component_id].staticArray + ); + space_invaders.bullet_tmpl[0].getComponent!CTexture().coords = vec4(0,24,2,8)*px; + space_invaders.bullet_tmpl[0].getComponent!CScale().value = vec2(2,8); + + space_invaders.bullet_tmpl[1] = launcher.manager.allocateTemplate(space_invaders.bullet_tmpl[0]); + space_invaders.bullet_tmpl[2] = launcher.manager.allocateTemplate(space_invaders.bullet_tmpl[0]); + space_invaders.bullet_tmpl[2].getComponent!CTexture().coords = vec4(64,32,8,16)*px; + space_invaders.bullet_tmpl[2].getComponent!CScale().value = vec2(8,16); + space_invaders.bullet_tmpl[3] = launcher.manager.allocateTemplate(space_invaders.bullet_tmpl[0]); + space_invaders.bullet_tmpl[3].getComponent!CTexture().coords = vec4(56,32,2,2)*px; + space_invaders.bullet_tmpl[3].getComponent!CScale().value = vec2(2,2); + // bullet_tmpl[3].getComponent!CTexture().coords = vec4(48,32,8,8)*px; + // bullet_tmpl[3].getComponent!CScale().value = vec2(8,8); + space_invaders.bullet_tmpl[4] = launcher.manager.allocateTemplate(space_invaders.bullet_tmpl[0]); + launcher.gui_manager.addTemplate(enemy_tmpl,"Enemy"); launcher.gui_manager.addTemplate(grouped_tmpl,"Grouped enemy"); - launcher.gui_manager.addTemplate(space_invaders.laser_tmpl,"Laser"); - + launcher.gui_manager.addTemplate(launcher.manager.allocateTemplate(space_invaders.ship_tmpl),"Ship"); + launcher.gui_manager.addTemplate(launcher.manager.allocateTemplate(space_invaders.laser_tmpl),"Laser"); + launcher.gui_manager.addTemplate(upgrade_tmpl,"Upgrade"); + launcher.gui_manager.addTemplate(tower_tmpl,"Tower"); + launcher.gui_manager.addTemplate(boss_tmpl,"Boss"); + launcher.gui_manager.addTemplate(launcher.manager.allocateTemplate(space_invaders.bullet_tmpl[3]),"Cannon bullet"); + //launcher.gui_manager.addTemplate(launcher.manager.allocateTemplate(space_invaders.bullet_tmpl[4]),"Laser"); + //launcher.gui_manager.addTemplate(launcher.manager.allocateTemplate(space_invaders.bullet_tmpl[5]),"Laser"); } void spaceInvadersEnd() { - - launcher.manager.getSystem(DrawSystem.system_id).disable(); + /*launcher.manager.getSystem(DrawSystem.system_id).disable(); launcher.manager.getSystem(InputMovementSystem.system_id).disable(); launcher.manager.getSystem(LaserShootingSystem.system_id).disable(); launcher.manager.getSystem(MovementSystem.system_id).disable(); launcher.manager.getSystem(ClampPositionSystem.system_id).disable(); + launcher.manager.getSystem(ShootGridCleaner.system_id).disable();*/ - launcher.manager.freeTemplate(space_invaders.enemy_tmpl); + //launcher.manager.freeTemplate(space_invaders.enemy_tmpl); Mallocator.dispose(space_invaders); + space_invaders = null; } void spaceInvadersTool(vec2 position, Tool tool, int size) @@ -806,8 +2582,15 @@ void spaceInvadersTool(vec2 position, Tool tool, int size) { position.x += (randomf - 0.5) * size; position.y += (randomf - 0.5) * size; + if(position.y < 16)position.y = 16; + else if(position.y > 299)position.y = 299; *location = position; } + CWeapon* laser_weapon = tmpl.getComponent!CWeapon; + if(laser_weapon) + { + laser_weapon.shoot_time = randomf * CWeapon.levels[laser_weapon.level - 1].reload_time; + } launcher.manager.addEntity(tmpl); } break; diff --git a/demos/source/game_core/job_updater.d b/demos/source/game_core/job_updater.d index 46cd609..47d2423 100644 --- a/demos/source/game_core/job_updater.d +++ b/demos/source/game_core/job_updater.d @@ -1,13 +1,13 @@ module game_core.job_updater; -import ecs.std; -import ecs.vector; -import ecs.atomic; +import bubel.ecs.std; +import bubel.ecs.vector; +import bubel.ecs.atomic; import ecs_utils.utils; //import core.time; -import ecs.manager; +import bubel.ecs.manager; import mmutils.thread_pool; version(LDC) @@ -63,6 +63,7 @@ struct ECSJobUpdater JobData[1024] jobs; JobCaller[1024] callers; uint count = 0; + string name; void dependantOn(Group* dependency) { @@ -89,7 +90,7 @@ struct ECSJobUpdater void add(JobCaller caller) { callers[count] = caller; - jobs[count] = JobData(&callers[count].callJob,"hmm"); + jobs[count] = JobData(&callers[count].callJob,name); count++; } } @@ -216,6 +217,8 @@ struct ECSJobUpdater return; } + jobs[group.id].name = cast(string)group.caller.system.name; + foreach(ref job;group.jobs) { uint index = 0; @@ -233,7 +236,7 @@ struct ECSJobUpdater foreach(dep;group.dependencies) { - if(jobs[dep.id].count && dep.caller.system.execute && dep.caller.system.enabled)jobs[group.id].dependantOn(&jobs[dep.id]); + if(jobs[dep.id].count && dep.caller.system.willExecute && dep.caller.system.enabled)jobs[group.id].dependantOn(&jobs[dep.id]); else deps--; } diff --git a/demos/source/gui/manager.d b/demos/source/gui/manager.d index 8a46a92..4d452ad 100644 --- a/demos/source/gui/manager.d +++ b/demos/source/gui/manager.d @@ -4,10 +4,10 @@ import app; import cimgui.cimgui; -import ecs.std; -import ecs.system; -import ecs.vector; -import ecs.entity; +import bubel.ecs.std; +import bubel.ecs.system; +import bubel.ecs.vector; +import bubel.ecs.entity; import gui.system; import gui.template_; @@ -30,6 +30,7 @@ struct GUIManager systems.clear(); templates.clear(); + selected_tempalte = 0; } EntityTemplate* getSelectedTemplate() diff --git a/demos/source/gui/system.d b/demos/source/gui/system.d index bbee409..112bed3 100644 --- a/demos/source/gui/system.d +++ b/demos/source/gui/system.d @@ -1,6 +1,6 @@ module gui.system; -import ecs.system; +import bubel.ecs.system; struct SystemGUI { diff --git a/demos/source/gui/template_.d b/demos/source/gui/template_.d index 2aa1833..4d3de11 100644 --- a/demos/source/gui/template_.d +++ b/demos/source/gui/template_.d @@ -1,6 +1,6 @@ module gui.template_; -import ecs.entity; +import bubel.ecs.entity; struct TemplateGUI { diff --git a/demos/utils/source/ecs_utils/gfx/buffer.d b/demos/utils/source/ecs_utils/gfx/buffer.d index 2c25324..b11cb85 100644 --- a/demos/utils/source/ecs_utils/gfx/buffer.d +++ b/demos/utils/source/ecs_utils/gfx/buffer.d @@ -1,6 +1,6 @@ module ecs_utils.gfx.buffer; -import ecs.std; +import bubel.ecs.std; import glad.gl.gl; import glad.gl.gles2; diff --git a/demos/utils/source/ecs_utils/gfx/config.d b/demos/utils/source/ecs_utils/gfx/config.d index de5528a..0683647 100644 --- a/demos/utils/source/ecs_utils/gfx/config.d +++ b/demos/utils/source/ecs_utils/gfx/config.d @@ -2,7 +2,7 @@ module ecs_utils.gfx.config; import bindbc.sdl; -import ecs.std; +import bubel.ecs.std; import ecs_utils.gfx.material; import ecs_utils.gfx.mesh; @@ -18,7 +18,7 @@ enum LayerType sorted } -import ecs.vector; +import bubel.ecs.vector; static struct GfxConfig { diff --git a/demos/utils/source/ecs_utils/gfx/material.d b/demos/utils/source/ecs_utils/gfx/material.d index b697992..fbd88b9 100644 --- a/demos/utils/source/ecs_utils/gfx/material.d +++ b/demos/utils/source/ecs_utils/gfx/material.d @@ -2,7 +2,7 @@ module ecs_utils.gfx.material; import bindbc.sdl; -import ecs.std; +import bubel.ecs.std; import ecs_utils.gfx.shader; diff --git a/demos/utils/source/ecs_utils/gfx/mesh.d b/demos/utils/source/ecs_utils/gfx/mesh.d index 346226f..20d5855 100644 --- a/demos/utils/source/ecs_utils/gfx/mesh.d +++ b/demos/utils/source/ecs_utils/gfx/mesh.d @@ -2,7 +2,7 @@ module ecs_utils.gfx.mesh; import bindbc.sdl; -import ecs.std; +import bubel.ecs.std; import ecs_utils.gfx.buffer; diff --git a/demos/utils/source/ecs_utils/gfx/renderer.d b/demos/utils/source/ecs_utils/gfx/renderer.d index 2a04c57..fcd6a88 100644 --- a/demos/utils/source/ecs_utils/gfx/renderer.d +++ b/demos/utils/source/ecs_utils/gfx/renderer.d @@ -2,14 +2,17 @@ module ecs_utils.gfx.renderer; import bindbc.sdl; -import ecs.std; +import bubel.ecs.std; //import ecs_utils.core : Backend; import ecs_utils.gfx.buffer; import ecs_utils.gfx.texture; import ecs_utils.math.vector; -import glad.gl.gl; +import bubel.ecs.block_allocator; +import bubel.ecs.vector; +version(WebAssembly)import glad.gl.gles2; +else import glad.gl.gl; version = ver1; /*version(ver5)version = vv2; @@ -41,9 +44,10 @@ enum RenderTechnique struct Renderer { //static SDL_Renderer* main_sdl_renderer; + BlockAllocator allocator; enum MaxObjects = 1024 * 64 * 4; - enum BufferUsage = GL_STATIC_DRAW; + enum BufferUsage = GL_DYNAMIC_DRAW; //SDL_Window* sdl_window; //SDL_Renderer* sdl_renderer; @@ -53,8 +57,136 @@ struct Renderer vec2 view_pos = vec2(-1,-1); vec2 view_size = vec2(1,1); + enum block_size = 2^^16; + enum batch_size = block_size/68;//963;//16_384; //uint[2] time_queries; + struct VertexBlock + { + enum max_items = batch_size;//963; + byte[] batch_vertices; + ushort[] batch_indices; + void* memory; + uint items = 0; + } + + Mutex* get_block_mutex; + Mutex* block_stack_mutex; + + VertexBlock getBlock() + { + VertexBlock block; + get_block_mutex.lock(); + block.memory = allocator.getBlock(); + get_block_mutex.unlock(); + block.batch_vertices = (cast(byte*)block.memory)[0 .. VertexBlock.max_items * 4 * 14]; + block.batch_indices = (cast(ushort*)block.memory)[VertexBlock.max_items * 4 * 7 .. VertexBlock.max_items * (4 * 7 + 6)]; + return block; + } + + Vector!VertexBlock blocks; + uint current_block = 0; + uint render_blocks = 0; + + void pushBlock(VertexBlock block) + { + block_stack_mutex.lock(); + prepared_items += block.items; + blocks.add(block); + render_blocks++; + block_stack_mutex.unlock(); + } + + bool isRemainingBlocks() + { + if(render_blocks <= current_block)return false; + return true; + } + + VertexBlock fetchBlock() + { + block_stack_mutex.lock(); + VertexBlock block = blocks[current_block]; + current_block++; + block_stack_mutex.unlock(); + return block; + } + + void freeBlocks() + { + /*block_stack_mutex.lock(); + render_blocks = 0; + current_block = 0; + foreach(VertexBlock block; blocks) + { + allocator.freeBlock(block.memory); + } + blocks.clear; + prepared_items=0; + draw_list.clear(); + block_stack_mutex.unlock();*/ + foreach(ref Thread thread; threads) + { + foreach(VertexBlock block; thread.blocks) + { + allocator.freeBlock(block.memory); + } + thread.blocks.clear(); + } + render_blocks = 0; + current_block = 0; + prepared_items = 0; + draw_list.clear(); + } + + void pushData() + { + foreach(ref Thread thread; threads) + { + foreach(VertexBlock block; thread.blocks) + { + uint items = block.items; + if(items + item_id >= MaxObjects)items = MaxObjects - item_id; + batch_vbo[0].bufferSubData(Buffer.BindTarget.array,items*4*14,item_id*4*14,block.batch_vertices.ptr); + batch_ibo[0].bufferSubData(Buffer.BindTarget.element_array,items*2*6,item_id*2*6,block.batch_indices.ptr); + draw_list.add(DrawCall(item_id,items)); + item_id += items; + } + //thread.blocks.clear(); + } + //if(!isRemainingBlocks())return; + /* while(isRemainingBlocks()) + { + VertexBlock block = fetchBlock(); + uint items = block.items; + if(items + item_id >= MaxObjects)items = MaxObjects - item_id; + batch_vbo[0].bufferSubData(Buffer.BindTarget.array,items*4*14,item_id*4*14,block.batch_vertices.ptr); + batch_ibo[0].bufferSubData(Buffer.BindTarget.element_array,items*2*6,item_id*2*6,block.batch_indices.ptr); + draw_list.add(DrawCall(item_id,items)); + item_id += items; + }*/ + } + + void pushThreadsBlocks() + { + foreach(i, ref Thread thread; threads) + { + //pushBlock(thread.block); + thread.blocks.add(thread.block); + thread.block = getBlock(); + } + } + + struct Thread + { + //Vector!VertexBlock block; + RenderData[] render_list; + VertexBlock block; + Vector!VertexBlock blocks; + } + Thread[] threads; + + Buffer[2] ubos; int block_alignment = 1; int block_max_size = 16384; @@ -71,7 +203,7 @@ struct Renderer Buffer[2] batch_vbo; Buffer[2] batch_ibo; - float[] batch_vertices; + ubyte[] batch_vertices; ushort[] batch_indices; Buffer indirect_buffer; @@ -90,8 +222,17 @@ struct Renderer uint mesh_id; } + struct DrawCall + { + uint start; + uint count; + } + + Vector!DrawCall draw_list; + RenderData[] render_list; uint item_id; + uint prepared_items; uint[] multi_count; uint[] multi_offset; @@ -109,6 +250,18 @@ struct Renderer { //this.technique = __ecs_used_technique; __initialize(this); + + get_block_mutex = Mallocator.make!Mutex(); + block_stack_mutex = Mallocator.make!Mutex(); + get_block_mutex.initialize(); + block_stack_mutex.initialize(); + + + threads = Mallocator.makeArray!Thread(32); + foreach(ref Thread thread;threads) + { + thread.block = getBlock(); + } } private static void __initialize_gl(ref Renderer this_) @@ -141,16 +294,16 @@ struct Renderer case Technique.vbo_batch: batch_vbo[0].create(); batch_ibo[0].create(); - batch_vbo[0].bufferData(Buffer.BindTarget.array,16,4*MaxObjects,BufferUsage,null); + batch_vbo[0].bufferData(Buffer.BindTarget.array,14,4*MaxObjects,BufferUsage,null); batch_ibo[0].bufferData(Buffer.BindTarget.element_array,2,6*MaxObjects,BufferUsage,null); batch_vbo[1].create(); batch_ibo[1].create(); - batch_vbo[1].bufferData(Buffer.BindTarget.array,16,4*MaxObjects,BufferUsage,null); + batch_vbo[1].bufferData(Buffer.BindTarget.array,14,4*MaxObjects,BufferUsage,null); batch_ibo[1].bufferData(Buffer.BindTarget.element_array,2,6*MaxObjects,BufferUsage,null); - batch_vertices = Mallocator.makeArray!float(16*MaxObjects); - batch_indices = Mallocator.makeArray!ushort(6*MaxObjects); + //batch_vertices = Mallocator.makeArray!ubyte(14*4*MaxObjects); + //batch_indices = Mallocator.makeArray!ushort(6*MaxObjects); break; case Technique.instanced_attrib_divisor: goto case(Technique.uniform_buffer_indexed); @@ -253,6 +406,8 @@ struct Renderer SDL_Log("Uniform block alignment: %u",block_alignment); SDL_Log("Uniform block max size: %u",block_max_size); SDL_Log("Data offset: %u",data_offset); + + allocator = BlockAllocator(block_size, 32); } } @@ -261,12 +416,13 @@ struct Renderer } - void draw(Texture tex, vec2 pos, vec2 size, vec4 coords, float angle = 0, uint material_id = 0, uint mesh_id = 0) + void draw(Texture tex, vec2 pos, vec2 size, vec4 coords, short depth = 0, uint color = uint.max, float angle = 0, uint material_id = 0, uint mesh_id = 0, uint thread_id = 0) { - __draw(this,tex,pos,size,coords,angle,material_id,mesh_id); + if(prepared_items >= MaxObjects)return; + __draw(this,tex,pos,size,coords,depth,color,angle,material_id,mesh_id,thread_id); } - private static void __draw_sdl(ref Renderer this_, Texture tex, vec2 pos, vec2 size, vec4 coords, float angle, uint material_id, uint mesh_id) + private static void __draw_sdl(ref Renderer this_, Texture tex, vec2 pos, vec2 size, vec4 coords, short depth, uint color, float angle, uint material_id, uint mesh_id, uint thread_id) { /*with(this_) { @@ -286,7 +442,7 @@ struct Renderer }*/ } - private static void __draw_gl(ref Renderer this_, Texture tex, vec2 pos, vec2 size, vec4 coords, float angle, uint material_id, uint mesh_id) + private static void __draw_gl(ref Renderer this_, Texture tex, vec2 pos, vec2 size, vec4 coords, short depth, uint color, float angle, uint material_id, uint mesh_id, uint thread_id) { //import core.stdc.string; with(this_) @@ -330,19 +486,20 @@ struct Renderer data_index += data_offset; item_id++; + prepared_items++; } } - private static void __draw_gl_vbo_batch(ref Renderer this_, Texture tex, vec2 pos, vec2 size, vec4 coords, float angle, uint material_id, uint mesh_id) + private static void __draw_gl_vbo_batch(ref Renderer this_, Texture tex, vec2 pos, vec2 size, vec4 coords, short depth, uint color, float angle, uint material_id, uint mesh_id, uint thread_id = 0) { import ecs_utils.gfx.config; + short[3] mem = [depth, *cast(short*)&color, *(cast(short*)&color + 1)]; //import core.stdc.string; with(this_) { - if(item_id >= MaxObjects)return; + //if(item_id >= MaxObjects)return; //pos += view_pos; - size.x *= view_size.x; - size.y *= view_size.y; + pos.x = pos.x * view_size.x + view_pos.x; pos.y = pos.y * view_size.y + view_pos.y;//*/ @@ -355,67 +512,134 @@ struct Renderer memcpy(ptr+16,pos.data.ptr,8); memcpy(ptr+32,coords.data.ptr,16);*/ + short[] verts = cast(short[])threads[thread_id].block.batch_vertices; + uint item_id = threads[thread_id].block.items; + if(angle == 0) { - batch_vertices[item_id*16] = GfxConfig.meshes[mesh_id].vertices[0] * size.x + pos.x; - batch_vertices[item_id*16+1] = GfxConfig.meshes[mesh_id].vertices[1] * size.y + pos.y; - batch_vertices[item_id*16+4] = GfxConfig.meshes[mesh_id].vertices[4] * size.x + pos.x; - batch_vertices[item_id*16+5] = GfxConfig.meshes[mesh_id].vertices[5] * size.y + pos.y; - batch_vertices[item_id*16+8] = GfxConfig.meshes[mesh_id].vertices[8] * size.x + pos.x; - batch_vertices[item_id*16+9] = GfxConfig.meshes[mesh_id].vertices[9] * size.y + pos.y; - batch_vertices[item_id*16+12] = GfxConfig.meshes[mesh_id].vertices[12] * size.x + pos.x; - batch_vertices[item_id*16+13] = GfxConfig.meshes[mesh_id].vertices[13] * size.y + pos.y; + size.x *= view_size.x; + size.y *= view_size.y; + + verts[item_id*28] = cast(short)((GfxConfig.meshes[mesh_id].vertices[0] * size.x + pos.x) * 8191); + verts[item_id*28+1] = cast(short)((GfxConfig.meshes[mesh_id].vertices[1] * size.y + pos.y) * 8191); + verts[item_id*28+2] = cast(short)((GfxConfig.meshes[mesh_id].vertices[2] * coords.z + coords.x)*32767); + verts[item_id*28+3] = cast(short)((GfxConfig.meshes[mesh_id].vertices[3] * coords.w + coords.y)*32767); + memcpy(verts.ptr+item_id*28+4,mem.ptr,6); + + + verts[item_id*28+7] = cast(short)((GfxConfig.meshes[mesh_id].vertices[4] * size.x + pos.x) * 8191); + verts[item_id*28+8] = cast(short)((GfxConfig.meshes[mesh_id].vertices[5] * size.y + pos.y) * 8191); + verts[item_id*28+9] = cast(short)((GfxConfig.meshes[mesh_id].vertices[6] * coords.z + coords.x)*32767); + verts[item_id*28+10] = cast(short)((GfxConfig.meshes[mesh_id].vertices[7] * coords.w + coords.y)*32767); + memcpy(verts.ptr+item_id*28+11,mem.ptr,6); + + + verts[item_id*28+14] = cast(short)((GfxConfig.meshes[mesh_id].vertices[8] * size.x + pos.x) * 8191); + verts[item_id*28+15] = cast(short)((GfxConfig.meshes[mesh_id].vertices[9] * size.y + pos.y) * 8191); + verts[item_id*28+16] = cast(short)((GfxConfig.meshes[mesh_id].vertices[10] * coords.z + coords.x)*32767); + verts[item_id*28+17] = cast(short)((GfxConfig.meshes[mesh_id].vertices[11] * coords.w + coords.y)*32767); + memcpy(verts.ptr+item_id*28+18,mem.ptr,6); + + + verts[item_id*28+21] = cast(short)((GfxConfig.meshes[mesh_id].vertices[12] * size.x + pos.x) * 8191); + verts[item_id*28+22] = cast(short)((GfxConfig.meshes[mesh_id].vertices[13] * size.y + pos.y) * 8191); + verts[item_id*28+23] = cast(short)((GfxConfig.meshes[mesh_id].vertices[14] * coords.z + coords.x)*32767); + verts[item_id*28+24] = cast(short)((GfxConfig.meshes[mesh_id].vertices[15] * coords.w + coords.y)*32767); + memcpy(verts.ptr+item_id*28+25,mem.ptr,6); } else { //import core.stdc.math; - float sinn = sinf(angle); - float coss = cosf(angle); + float sinx = sinf(angle) * size.x * view_size.y; + float cosx = cosf(angle) * size.x * view_size.x; + float siny = sinf(angle) * size.y * view_size.x; + float cosy = cosf(angle) * size.y * view_size.y; - /*batch_vertices[item_id*16] = GfxConfig.meshes[mesh_id].vertices[0] * size.x; - batch_vertices[item_id*16+1] = GfxConfig.meshes[mesh_id].vertices[1] * size.y; - batch_vertices[item_id*16+4] = GfxConfig.meshes[mesh_id].vertices[4] * size.x; - batch_vertices[item_id*16+5] = GfxConfig.meshes[mesh_id].vertices[5] * size.y; - batch_vertices[item_id*16+8] = GfxConfig.meshes[mesh_id].vertices[8] * size.x; - batch_vertices[item_id*16+9] = GfxConfig.meshes[mesh_id].vertices[9] * size.y; - batch_vertices[item_id*16+12] = GfxConfig.meshes[mesh_id].vertices[12] * size.x; - batch_vertices[item_id*16+13] = GfxConfig.meshes[mesh_id].vertices[13] * size.y;*/ + /*batch_vertices[item_id*28] = GfxConfig.meshes[mesh_id].vertices[0] * size.x; + batch_vertices[item_id*28+1] = GfxConfig.meshes[mesh_id].vertices[1] * size.y; + batch_vertices[item_id*28+4] = GfxConfig.meshes[mesh_id].vertices[4] * size.x; + batch_vertices[item_id*28+5] = GfxConfig.meshes[mesh_id].vertices[5] * size.y; + batch_vertices[item_id*28+8] = GfxConfig.meshes[mesh_id].vertices[8] * size.x; + batch_vertices[item_id*28+9] = GfxConfig.meshes[mesh_id].vertices[9] * size.y; + batch_vertices[item_id*28+12] = GfxConfig.meshes[mesh_id].vertices[12] * size.x; + batch_vertices[item_id*28+13] = GfxConfig.meshes[mesh_id].vertices[13] * size.y;*/ - batch_vertices[item_id*16] = (GfxConfig.meshes[mesh_id].vertices[0] * coss + GfxConfig.meshes[mesh_id].vertices[1] * sinn) * size.x + pos.x; - batch_vertices[item_id*16+1] = (GfxConfig.meshes[mesh_id].vertices[1] * coss - GfxConfig.meshes[mesh_id].vertices[0] * sinn) * size.y + pos.y; - batch_vertices[item_id*16+4] = (GfxConfig.meshes[mesh_id].vertices[4] * coss + GfxConfig.meshes[mesh_id].vertices[5] * sinn) * size.x + pos.x; - batch_vertices[item_id*16+5] = (GfxConfig.meshes[mesh_id].vertices[5] * coss - GfxConfig.meshes[mesh_id].vertices[4] * sinn) * size.y + pos.y; - batch_vertices[item_id*16+8] = (GfxConfig.meshes[mesh_id].vertices[8] * coss + GfxConfig.meshes[mesh_id].vertices[9] * sinn) * size.x + pos.x; - batch_vertices[item_id*16+9] = (GfxConfig.meshes[mesh_id].vertices[9] * coss - GfxConfig.meshes[mesh_id].vertices[8] * sinn) * size.y + pos.y; - batch_vertices[item_id*16+12] = (GfxConfig.meshes[mesh_id].vertices[12] * coss + GfxConfig.meshes[mesh_id].vertices[13] * sinn) * size.x + pos.x; - batch_vertices[item_id*16+13] = (GfxConfig.meshes[mesh_id].vertices[13] * coss - GfxConfig.meshes[mesh_id].vertices[12] * sinn) * size.y + pos.y; + verts[item_id*28] = cast(short)(((GfxConfig.meshes[mesh_id].vertices[0] * cosx + GfxConfig.meshes[mesh_id].vertices[1] * siny) + pos.x) * 8191); + verts[item_id*28+1] = cast(short)(((GfxConfig.meshes[mesh_id].vertices[1] * cosy - GfxConfig.meshes[mesh_id].vertices[0] * sinx) + pos.y) * 8191); + verts[item_id*28+2] = cast(short)((GfxConfig.meshes[mesh_id].vertices[2] * coords.z + coords.x)*32767); + verts[item_id*28+3] = cast(short)((GfxConfig.meshes[mesh_id].vertices[3] * coords.w + coords.y)*32767); + memcpy(verts.ptr+item_id*28+4,mem.ptr,6); + + + verts[item_id*28+7] = cast(short)(((GfxConfig.meshes[mesh_id].vertices[4] * cosx + GfxConfig.meshes[mesh_id].vertices[5] * siny) + pos.x) * 8191); + verts[item_id*28+8] = cast(short)(((GfxConfig.meshes[mesh_id].vertices[5] * cosy - GfxConfig.meshes[mesh_id].vertices[4] * sinx) + pos.y) * 8191); + verts[item_id*28+9] = cast(short)((GfxConfig.meshes[mesh_id].vertices[6] * coords.z + coords.x)*32767); + verts[item_id*28+10] = cast(short)((GfxConfig.meshes[mesh_id].vertices[7] * coords.w + coords.y)*32767); + memcpy(verts.ptr+item_id*28+11,mem.ptr,6); + + + verts[item_id*28+14] = cast(short)(((GfxConfig.meshes[mesh_id].vertices[8] * cosx + GfxConfig.meshes[mesh_id].vertices[9] * siny) + pos.x) * 8191); + verts[item_id*28+15] = cast(short)(((GfxConfig.meshes[mesh_id].vertices[9] * cosy - GfxConfig.meshes[mesh_id].vertices[8] * sinx) + pos.y) * 8191); + verts[item_id*28+16] = cast(short)((GfxConfig.meshes[mesh_id].vertices[10] * coords.z + coords.x)*32767); + verts[item_id*28+17] = cast(short)((GfxConfig.meshes[mesh_id].vertices[11] * coords.w + coords.y)*32767); + memcpy(verts.ptr+item_id*28+18,mem.ptr,6); + + + verts[item_id*28+21] = cast(short)(((GfxConfig.meshes[mesh_id].vertices[12] * cosx + GfxConfig.meshes[mesh_id].vertices[13] * siny) + pos.x) * 8191); + verts[item_id*28+22] = cast(short)(((GfxConfig.meshes[mesh_id].vertices[13] * cosy - GfxConfig.meshes[mesh_id].vertices[12] * sinx) + pos.y) * 8191); + verts[item_id*28+23] = cast(short)((GfxConfig.meshes[mesh_id].vertices[14] * coords.z + coords.x)*32767); + verts[item_id*28+24] = cast(short)((GfxConfig.meshes[mesh_id].vertices[15] * coords.w + coords.y)*32767); + memcpy(verts.ptr+item_id*28+25,mem.ptr,6); } - batch_vertices[item_id*16+2] = GfxConfig.meshes[mesh_id].vertices[2] * coords.z + coords.x; - batch_vertices[item_id*16+3] = GfxConfig.meshes[mesh_id].vertices[3] * coords.w + coords.y; - batch_vertices[item_id*16+6] = GfxConfig.meshes[mesh_id].vertices[6] * coords.z + coords.x; - batch_vertices[item_id*16+7] = GfxConfig.meshes[mesh_id].vertices[7] * coords.w + coords.y; - batch_vertices[item_id*16+10] = GfxConfig.meshes[mesh_id].vertices[10] * coords.z + coords.x; - batch_vertices[item_id*16+11] = GfxConfig.meshes[mesh_id].vertices[11] * coords.w + coords.y; - batch_vertices[item_id*16+14] = GfxConfig.meshes[mesh_id].vertices[14] * coords.z + coords.x; - batch_vertices[item_id*16+15] = GfxConfig.meshes[mesh_id].vertices[15] * coords.w + coords.y; + /*verts[item_id*28+2] = cast(short)((GfxConfig.meshes[mesh_id].vertices[2] * coords.z + coords.x)*32767); + verts[item_id*28+3] = cast(short)((GfxConfig.meshes[mesh_id].vertices[3] * coords.w + coords.y)*32767); + verts[item_id*28+9] = cast(short)((GfxConfig.meshes[mesh_id].vertices[6] * coords.z + coords.x)*32767); + verts[item_id*28+10] = cast(short)((GfxConfig.meshes[mesh_id].vertices[7] * coords.w + coords.y)*32767); + verts[item_id*28+16] = cast(short)((GfxConfig.meshes[mesh_id].vertices[10] * coords.z + coords.x)*32767); + verts[item_id*28+17] = cast(short)((GfxConfig.meshes[mesh_id].vertices[11] * coords.w + coords.y)*32767); + verts[item_id*28+23] = cast(short)((GfxConfig.meshes[mesh_id].vertices[14] * coords.z + coords.x)*32767); + verts[item_id*28+24] = cast(short)((GfxConfig.meshes[mesh_id].vertices[15] * coords.w + coords.y)*32767);*/ - uint ind_id = item_id % 16_384; + /*verts[item_id*28+4] = depth; + verts[item_id*28+11] = depth; + verts[item_id*28+18] = depth; + verts[item_id*28+25] = depth; - batch_indices[item_id*6] = cast(ushort)(GfxConfig.meshes[mesh_id].indices[0] + ind_id*4); - batch_indices[item_id*6+1] = cast(ushort)(GfxConfig.meshes[mesh_id].indices[1] + ind_id*4); - batch_indices[item_id*6+2] = cast(ushort)(GfxConfig.meshes[mesh_id].indices[2] + ind_id*4); - batch_indices[item_id*6+3] = cast(ushort)(GfxConfig.meshes[mesh_id].indices[3] + ind_id*4); - batch_indices[item_id*6+4] = cast(ushort)(GfxConfig.meshes[mesh_id].indices[4] + ind_id*4); - batch_indices[item_id*6+5] = cast(ushort)(GfxConfig.meshes[mesh_id].indices[5] + ind_id*4); + *cast(uint*)&verts[item_id*28+5] = color; + *cast(uint*)&verts[item_id*28+12] = color; + *cast(uint*)&verts[item_id*28+19] = color; + *cast(uint*)&verts[item_id*28+26] = color; + + memcpy(verts.ptr+item_id*28+4,mem.ptr,6); + memcpy(verts.ptr+item_id*28+11,mem.ptr,6); + memcpy(verts.ptr+item_id*28+18,mem.ptr,6); + memcpy(verts.ptr+item_id*28+25,mem.ptr,6);*/ + + uint ind_id = (item_id % batch_size)*4; + + ushort[] indices = threads[thread_id].block.batch_indices; + + indices[item_id*6] = cast(ushort)(GfxConfig.meshes[mesh_id].indices[0] + ind_id); + indices[item_id*6+1] = cast(ushort)(GfxConfig.meshes[mesh_id].indices[1] + ind_id); + indices[item_id*6+2] = cast(ushort)(GfxConfig.meshes[mesh_id].indices[2] + ind_id); + indices[item_id*6+3] = cast(ushort)(GfxConfig.meshes[mesh_id].indices[3] + ind_id); + indices[item_id*6+4] = cast(ushort)(GfxConfig.meshes[mesh_id].indices[4] + ind_id); + indices[item_id*6+5] = cast(ushort)(GfxConfig.meshes[mesh_id].indices[5] + ind_id); //render_list[item_id] = RenderData(tex,material_id,mesh_id); - render_list[item_id].texture = tex; - render_list[item_id].material_id = material_id; - render_list[item_id].mesh_id = mesh_id; + //render_list[item_id].texture = tex; + //render_list[item_id].material_id = material_id; + //render_list[item_id].mesh_id = mesh_id; //data_index += 1;//data_offset; - item_id++; + threads[thread_id].block.items++; + if(threads[thread_id].block.items >= VertexBlock.max_items) + { + //pushBlock(threads[thread_id].block); + threads[thread_id].blocks.add(threads[thread_id].block); + threads[thread_id].block = getBlock(); + } } } @@ -433,9 +657,22 @@ struct Renderer { glClearColor(0,0,0,0); glViewport(0,0,this_.resolution.x,this_.resolution.y); - glClear(GL_COLOR_BUFFER_BIT);// | GL_DEPTH_BUFFER_BIT); - glDisable(GL_DEPTH_TEST); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + //glDisable(GL_DEPTH_TEST); + glEnable(GL_DEPTH_TEST); glDisable(GL_CULL_FACE); + glDepthFunc(GL_LESS); + + version(WebAssembly) + { + glDepthRangef(0,1); + } + else + { + glDepthRange(0,1); + } + //glDepthRange(0,1); + //glClearDepth(1); } void present() @@ -450,6 +687,10 @@ struct Renderer private static void __present_gl(ref Renderer this_) { + + this_.pushThreadsBlocks(); + this_.pushData(); + glViewport(0,0,this_.resolution.x,this_.resolution.y); //glEnable(GL_ALPHA_TEST); //glAlphaFunc(GL_GREATER, 0.01); @@ -471,14 +712,17 @@ struct Renderer break; case Technique.vbo_batch: //if(data_index){ - batch_vbo[0].bufferSubData(Buffer.BindTarget.array,item_id*4*16,0,batch_vertices.ptr); - batch_ibo[0].bufferSubData(Buffer.BindTarget.element_array,item_id*6*2,0,batch_indices.ptr); + //batch_vbo[0].bufferSubData(Buffer.BindTarget.array,item_id*4*14,0,batch_vertices.ptr); + //batch_ibo[0].bufferSubData(Buffer.BindTarget.element_array,item_id*6*2,0,batch_indices.ptr); batch_vbo[0].bind(Buffer.BindTarget.array); batch_ibo[0].bind(Buffer.BindTarget.element_array); - glVertexAttribPointer(0,2,GL_FLOAT,false,16,null); - glVertexAttribPointer(1,2,GL_FLOAT,false,16,cast(void*)8);//} + //glVertexAttribPointer(0,2,GL_SHORT,true,14,null); + //glVertexAttribPointer(1,2,GL_SHORT,true,14,cast(void*)4);//} + glEnableVertexAttribArray(2); + glEnableVertexAttribArray(3); + //glVertexAttribPointer(2,1,GL_SHORT,true,14,cast(void*)6);//} break; case Technique.instanced_attrib_divisor: ubos[0].bufferSubData(Buffer.BindTarget.uniform,data_index,0,uniform_block.ptr); @@ -575,8 +819,8 @@ struct Renderer //glBeginQuery(GL_TIME_ELAPSED, time_queries[0]); if(technique == Technique.vbo_batch) { - uint items = item_id/16_384+1; - foreach(i; 0..items) + //uint items = item_id/batch_size+1; + foreach(i; 0..draw_list.length) { if(material_id != render_list[i].material_id) { @@ -591,16 +835,20 @@ struct Renderer render_list[i].texture.bind(); } - uint instance_count = 16_384; - if((i+1)*16_384 > item_id) + /*uint instance_count = batch_size; + if((i+1)*batch_size > item_id) { - instance_count = item_id%16_384; - } + instance_count = item_id%batch_size; + }*/ - glVertexAttribPointer(0,2,GL_FLOAT,false,16,cast(void*)(i*16_384*4*16)); - glVertexAttribPointer(1,2,GL_FLOAT,false,16,cast(void*)(i*16_384*4*16+8)); + // glVertexAttribPointer(0,2,GL_FLOAT,false,16,cast(void*)(i*batch_size*4*16)); + // glVertexAttribPointer(1,2,GL_FLOAT,false,16,cast(void*)(i*batch_size*4*16+8)); + glVertexAttribPointer(0,2,GL_SHORT,true,14,cast(void*)(draw_list[i].start*4*14)); + glVertexAttribPointer(1,2,GL_SHORT,true,14,cast(void*)(draw_list[i].start*4*14+4)); + glVertexAttribPointer(2,1,GL_SHORT,true,14,cast(void*)(draw_list[i].start*4*14+8)); + glVertexAttribPointer(3,4,GL_UNSIGNED_BYTE,true,14,cast(void*)(draw_list[i].start*4*14+10)); - glDrawElements(GL_TRIANGLES,instance_count*6,GL_UNSIGNED_SHORT,cast(void*)(i*16_384*6*2)); + glDrawElements(GL_TRIANGLES,draw_list[i].count*6,GL_UNSIGNED_SHORT,cast(void*)(draw_list[i].start*6*2)); //glDrawElementsBaseVertex(GL_TRIANGLES,instance_count*6,GL_UNSIGNED_SHORT,cast(void*)(i*16_384*6*2),i*16_384*4); } @@ -783,6 +1031,9 @@ struct Renderer } glDisableVertexAttribArray(0); glDisableVertexAttribArray(1); + glDisableVertexAttribArray(2); + glDisableVertexAttribArray(3); + this_.freeBlocks(); /*glUseProgram(0); glBindBuffer(GL_ARRAY_BUFFER, 0); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);*/ @@ -803,7 +1054,7 @@ struct Renderer view_pos = (pos - size * 0.5) * view_size; } - __gshared void function(ref Renderer this_, Texture tex, vec2 pos, vec2 size, vec4 coords, float angle, uint material_id, uint mesh_id) __draw; + __gshared void function(ref Renderer this_, Texture tex, vec2 pos, vec2 size, vec4 coords, short depth, uint color, float angle, uint material_id, uint mesh_id, uint thread_id) __draw; __gshared void function(ref Renderer this_) __present; __gshared void function(ref Renderer this_) __clear; __gshared void function(ref Renderer this_) __initialize; diff --git a/demos/utils/source/ecs_utils/gfx/shader.d b/demos/utils/source/ecs_utils/gfx/shader.d index 7749013..5e24d9a 100644 --- a/demos/utils/source/ecs_utils/gfx/shader.d +++ b/demos/utils/source/ecs_utils/gfx/shader.d @@ -2,7 +2,7 @@ module ecs_utils.gfx.shader; import bindbc.sdl; -import ecs.std; +import bubel.ecs.std; import glad.gl.gl; diff --git a/demos/utils/source/ecs_utils/gfx/texture.d b/demos/utils/source/ecs_utils/gfx/texture.d index bb4c62a..d4e2089 100644 --- a/demos/utils/source/ecs_utils/gfx/texture.d +++ b/demos/utils/source/ecs_utils/gfx/texture.d @@ -2,7 +2,7 @@ module ecs_utils.gfx.texture; import bindbc.sdl; -import ecs.std; +import bubel.ecs.std; import ecs_utils.math.vector; @@ -54,6 +54,8 @@ struct Texture data.data = Mallocator.makeArray!ubyte(surf.w*surf.h*surf.format.BytesPerPixel); data.data[0..$] = (cast(ubyte*)surf.pixels)[0..data.data.length]; + SDL_FreeSurface(surf); + glGenTextures(1, &data.gl_handle); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D,data.gl_handle); @@ -78,11 +80,12 @@ struct Texture glBindTexture(GL_TEXTURE_2D, data.gl_handle); } - void destory() + void destory() @nogc nothrow { if(data) { glDeleteTextures(1, &data.gl_handle); + if(data.data)Mallocator.dispose(data.data); Mallocator.dispose(data); data = null; } diff --git a/demos/utils/source/ecs_utils/gfx/vertex.d b/demos/utils/source/ecs_utils/gfx/vertex.d index 1d11fdd..b63803c 100644 --- a/demos/utils/source/ecs_utils/gfx/vertex.d +++ b/demos/utils/source/ecs_utils/gfx/vertex.d @@ -1,6 +1,6 @@ module ecs_utils.gfx.vertex; -import ecs.std; +import bubel.ecs.std; struct Vertex { diff --git a/demos/utils/source/ecs_utils/math/vector.d b/demos/utils/source/ecs_utils/math/vector.d index 4b9f3af..a8f14f8 100644 --- a/demos/utils/source/ecs_utils/math/vector.d +++ b/demos/utils/source/ecs_utils/math/vector.d @@ -2,6 +2,18 @@ module ecs_utils.math.vector; struct vec2 { + this(float v) @nogc nothrow + { + x = v; + y = v; + } + + this(float x, float y) @nogc nothrow + { + this.x = x; + this.y = y; + } + union { struct @@ -75,6 +87,22 @@ struct vec4 float[4] data; } + this(float v) @nogc nothrow + { + x = v; + y = v; + z = v; + w = v; + } + + this(float x, float y, float z, float w) @nogc nothrow + { + this.x = x; + this.y = y; + this.z = z; + this.w = w; + } + vec4 opBinary(string op)(float v) { static if (op == "+") return vec4(x + v, y + v, z + v, w + v); @@ -96,6 +124,27 @@ struct ivec2 } int[2] data; } + + this(int v) @nogc nothrow + { + x = v; + y = v; + } + + this(int x, int y) @nogc nothrow + { + this.x = x; + this.y = y; + } + + ivec2 opBinary(string op, T)(T v) + { + static if (op == "+") return ivec2(x + v, y + v); + else static if (op == "-") return ivec2(x - v, y - v); + else static if (op == "*") return ivec2(x * v, y * v); + else static if (op == "/") return ivec2(x / v, y / v); + else static assert(0, "Operator "~op~" not implemented"); + } vec2 opCast() { @@ -116,4 +165,20 @@ struct ivec4 } int[4] data; } + + this(int v) @nogc nothrow + { + x = v; + y = v; + z = v; + w = v; + } + + this(int x, int y, int z, int w) @nogc nothrow + { + this.x = x; + this.y = y; + this.z = z; + this.w = w; + } } \ No newline at end of file diff --git a/demos/utils/source/ecs_utils/utils.d b/demos/utils/source/ecs_utils/utils.d index 4c143fd..8ce5cd1 100644 --- a/demos/utils/source/ecs_utils/utils.d +++ b/demos/utils/source/ecs_utils/utils.d @@ -21,7 +21,19 @@ float randomRangef(float min, float max) return rand()%4096; }*/ -extern(C) int printf(scope const char* format, ...) @nogc nothrow @system; +version(GNU) +{ + public import core.stdc.stdio : printf; + pragma(inline, true) T[n] staticArray(T, size_t n)(auto ref T[n] a) + { + return a; + } +} +else +{ + extern(C) int printf(scope const char* format, ...) @nogc nothrow @system; + public import std.array : staticArray; +} extern(C) int rand(); version(D_BetterC) diff --git a/dub.json b/dub.json index c23a4e6..01cf85c 100755 --- a/dub.json +++ b/dub.json @@ -74,6 +74,9 @@ "dflags": [ "-betterC", "-defaultlib=" + ], + "dflags-gdc": [ + "-fno-druntime" ] }, { @@ -88,9 +91,7 @@ ], "dflags-gdc": [ "-fno-druntime", - "-fvisibility=hidden" - ], - "lflags-gdc": [ + "-fvisibility=hidden", "-lpthread" ] }, @@ -105,9 +106,7 @@ "-betterC" ], "dflags-gdc": [ - "-fno-druntime" - ], - "lflags-gdc": [ + "-fno-druntime", "-lpthread" ] }, @@ -118,6 +117,9 @@ "-betterC", "-unittest" ], + "dflags-gdc": [ + "-fno-druntime" + ], "sourcePaths": ["source/","tests/"], "mainSourceFile":"tests/runner.d", "excludedSourceFiles":[ diff --git a/meson.build b/meson.build index 3317d5c..c31b93a 100644 --- a/meson.build +++ b/meson.build @@ -1,21 +1,21 @@ project('DECS', 'd') src = [ - 'source/ecs/atomic.d', - 'source/ecs/attributes.d', - 'source/ecs/block_allocator.d', - 'source/ecs/core.d', - 'source/ecs/entity.d', - 'source/ecs/events.d', - 'source/ecs/hash_map.d', - 'source/ecs/id_manager.d', - 'source/ecs/manager.d', - 'source/ecs/package.d', - 'source/ecs/simple_vector.d', - 'source/ecs/std.d', - 'source/ecs/system.d', - 'source/ecs/traits.d', - 'source/ecs/vector.d' + 'source/bubel/ecs/atomic.d', + 'source/bubel/ecs/attributes.d', + 'source/bubel/ecs/block_allocator.d', + 'source/bubel/ecs/core.d', + 'source/bubel/ecs/entity.d', + 'source/bubel/ecs/events.d', + 'source/bubel/ecs/hash_map.d', + 'source/bubel/ecs/id_manager.d', + 'source/bubel/ecs/manager.d', + 'source/bubel/ecs/package.d', + 'source/bubel/ecs/simple_vector.d', + 'source/bubel/ecs/std.d', + 'source/bubel/ecs/system.d', + 'source/bubel/ecs/traits.d', + 'source/bubel/ecs/vector.d' ] tests_src = [ diff --git a/source/bubel/ecs/atomic.d b/source/bubel/ecs/atomic.d new file mode 100644 index 0000000..8ea43df --- /dev/null +++ b/source/bubel/ecs/atomic.d @@ -0,0 +1,132 @@ +/************************************************************************************************************************ +It's internal code. Can be used for atomics if emscripten backend will be used. + +This module contain atomic operations which include support for emscripten atomics functions. +Emscripten functions are contained in API similar to druntime. + +Copyright: Copyright © 2018-2019, Dawid Masiukiewicz, Michał Masiukiewicz +License: BSD 3-clause, see LICENSE file in project root folder. +*/ +module bubel.ecs.atomic; + +version (Emscripten) version = ECSEmscripten; + +version (ECSEmscripten) +{ + import std.traits; + + enum MemoryOrder + { + acq, + acq_rel, + raw, + rel, + seq + } + + extern (C) ubyte emscripten_atomic_cas_u8(void* addr, ubyte oldVal, ubyte newVal) @nogc nothrow pure; + extern (C) ushort emscripten_atomic_cas_u16(void* addr, ushort oldVal, ushort newVal) @nogc nothrow pure; + extern (C) uint emscripten_atomic_cas_u32(void* addr, uint oldVal, uint newVal) @nogc nothrow pure; + + extern (C) ubyte emscripten_atomic_load_u8(const void* addr) @nogc nothrow pure; + extern (C) ushort emscripten_atomic_load_u16(const void* addr) @nogc nothrow pure; + extern (C) uint emscripten_atomic_load_u32(const void* addr) @nogc nothrow pure; + + extern (C) ubyte emscripten_atomic_store_u8(void* addr, ubyte val) @nogc nothrow pure; + extern (C) ushort emscripten_atomic_store_u16(void* addr, ushort val) @nogc nothrow pure; + extern (C) uint emscripten_atomic_store_u32(void* addr, uint val) @nogc nothrow pure; + + extern (C) ubyte emscripten_atomic_add_u8(void* addr, ubyte val) @nogc nothrow pure; + extern (C) ushort emscripten_atomic_add_u16(void* addr, ushort val) @nogc nothrow pure; + extern (C) uint emscripten_atomic_add_u32(void* addr, uint val) @nogc nothrow pure; + + extern (C) ubyte emscripten_atomic_sub_u8(void* addr, ubyte val) @nogc nothrow pure; + extern (C) ushort emscripten_atomic_sub_u16(void* addr, ushort val) @nogc nothrow pure; + extern (C) uint emscripten_atomic_sub_u32(void* addr, uint val) @nogc nothrow pure; + + public pure nothrow @nogc Unqual!T atomicOp(string op, T, V1)(ref shared T val, V1 mod) + { + static if (op == "+=") + { + static if (is(T == byte) || is(T == ubyte)) + return cast(Unqual!T)(emscripten_atomic_add_u8(cast(void*)&val, + cast(Unqual!T) mod) + 1); + else static if (is(T == short) || is(T == ushort)) + return cast(Unqual!T)(emscripten_atomic_add_u16(cast(void*)&val, + cast(Unqual!T) mod) + 1); + else static if (is(T == int) || is(T == uint)) + return cast(Unqual!T)(emscripten_atomic_add_u32(cast(void*)&val, + cast(Unqual!T) mod) + 1); + else + static assert(0); + } + else static if (op == "-=") + { + static if (is(T == byte) || is(T == ubyte)) + return cast(Unqual!T)(emscripten_atomic_sub_u8(cast(void*)&val, + cast(Unqual!T) mod) - 1); + else static if (is(T == short) || is(T == ushort)) + return cast(Unqual!T)(emscripten_atomic_sub_u16(cast(void*)&val, + cast(Unqual!T) mod) - 1); + else static if (is(T == int) || is(T == uint)) + return cast(Unqual!T)(emscripten_atomic_sub_u32(cast(void*)&val, + cast(Unqual!T) mod) - 1); + else + static assert(0); + } + } + + public pure nothrow @nogc @trusted void atomicStore(MemoryOrder ms = MemoryOrder.seq, T, V)(ref T val, + V newval) + { + alias UT = Unqual!T; + static if (is(UT == bool) || is(UT == byte) || is(UT == ubyte)) + emscripten_atomic_store_u8(cast(void*)&val, cast(UT) newval); + else static if (is(UT == short) || is(UT == ushort)) + emscripten_atomic_store_u16(cast(void*)&val, cast(UT) newval); + else static if (is(UT == int) || is(UT == uint)) + emscripten_atomic_store_u32(cast(void*)&val, cast(UT) newval); + else + static assert(0); + } + + public pure nothrow @nogc @trusted T atomicLoad(MemoryOrder ms = MemoryOrder.seq, T)( + ref const T val) + { + alias UT = Unqual!T; + static if (is(UT == bool)) + return emscripten_atomic_load_u8(cast(const void*)&val) != 0; + else static if (is(UT == byte) || is(UT == ubyte)) + return emscripten_atomic_load_u8(cast(const void*)&val); + else static if (is(UT == short) || is(UT == ushort)) + return emscripten_atomic_load_u16(cast(const void*)&val); + else static if (is(UT == int) || is(UT == uint)) + return emscripten_atomic_load_u32(cast(const void*)&val); + else + static assert(0); + } + + public pure nothrow @nogc @trusted bool cas(MemoryOrder succ = MemoryOrder.seq, + MemoryOrder fail = MemoryOrder.seq, T, V1, V2)(T* here, V1 ifThis, V2 writeThis) + { + alias UT = Unqual!T; + static if (is(UT == bool)) + return emscripten_atomic_cas_u8(cast(void*) here, + cast(Unqual!T) ifThis, cast(Unqual!T) writeThis) == ifThis; + else static if (is(UT == byte) || is(UT == ubyte)) + return emscripten_atomic_cas_u8(cast(void*) here, + cast(Unqual!T) ifThis, cast(Unqual!T) writeThis) == ifThis; + else static if (is(UT == short) || is(UT == ushort)) + return emscripten_atomic_cas_u16(cast(void*) here, + cast(Unqual!T) ifThis, cast(Unqual!T) writeThis) == ifThis; + else static if (is(UT == int) || is(UT == uint)) + return emscripten_atomic_cas_u32(cast(void*) here, + cast(Unqual!T) ifThis, cast(Unqual!T) writeThis) == ifThis; + else + static assert(0); + } +} +else +{ + public import core.atomic; +} diff --git a/source/ecs/attributes.d b/source/bubel/ecs/attributes.d similarity index 94% rename from source/ecs/attributes.d rename to source/bubel/ecs/attributes.d index 20d0f60..d094aad 100644 --- a/source/ecs/attributes.d +++ b/source/bubel/ecs/attributes.d @@ -20,9 +20,9 @@ Struct EntitiesData Copyright: Copyright © 2018-2019, Dawid Masiukiewicz, Michał Masiukiewicz License: BSD 3-clause, see LICENSE file in project root folder. */ -module ecs.attributes; +module bubel.ecs.attributes; ///Used to mark optional components for system. enum optional = "optional"; ///Used to mark readonly components for system. "const" can be used insted. -enum readonly = "readonly"; \ No newline at end of file +enum readonly = "readonly"; diff --git a/source/ecs/block_allocator.d b/source/bubel/ecs/block_allocator.d similarity index 82% rename from source/ecs/block_allocator.d rename to source/bubel/ecs/block_allocator.d index d9f08ca..d3070c4 100644 --- a/source/ecs/block_allocator.d +++ b/source/bubel/ecs/block_allocator.d @@ -6,10 +6,10 @@ Module contain memory allocator. Copyright: Copyright © 2018-2019, Dawid Masiukiewicz, Michał Masiukiewicz License: BSD 3-clause, see LICENSE file in project root folder. */ -module ecs.block_allocator; +module bubel.ecs.block_allocator; -import ecs.manager; -import ecs.std; +import bubel.ecs.manager; +import bubel.ecs.std; /************************************************************************************************************************ Allocator allocate large blocks and return smaller blocks. When there is no more blocks then next large block is allocated. @@ -35,7 +35,7 @@ struct BlockAllocator */ void freeBlock(void* block) nothrow @nogc { - *cast(void**)block = next_block; + *cast(void**) block = next_block; next_block = block; } @@ -44,9 +44,9 @@ struct BlockAllocator */ void freeMemory() nothrow @nogc { - while(pointers) + while (pointers) { - foreach(i;0..pointers.numberof) + foreach (i; 0 .. pointers.numberof) { Mallocator.alignDispose(pointers.blocks[i]); } @@ -60,11 +60,14 @@ private: void allocBlock() nothrow @nogc { - next_block = cast(void*) Mallocator.alignAlloc( - block_size * blocks_in_allocation, block_size); + next_block = cast(void*) Mallocator.alignAlloc(block_size * blocks_in_allocation, + block_size); + if (next_block is null) + assert(0); - if(pointers is null)pointers = Mallocator.make!BlockPointers; - if(pointers.numberof >= 32) + if (pointers is null) + pointers = Mallocator.make!BlockPointers; + if (pointers.numberof >= 32) { BlockPointers* new_pointers = Mallocator.make!BlockPointers; new_pointers.next_pointers = pointers; @@ -77,8 +80,7 @@ private: void** pointer = cast(void**)(next_block + i * block_size); *pointer = next_block + (i + 1) * block_size; } - void** pointer = cast(void**)( - next_block + (blocks_in_allocation - 1) * block_size); + void** pointer = cast(void**)(next_block + (blocks_in_allocation - 1) * block_size); *pointer = null; } diff --git a/source/ecs/core.d b/source/bubel/ecs/core.d similarity index 74% rename from source/ecs/core.d rename to source/bubel/ecs/core.d index c346c9f..c032d21 100644 --- a/source/ecs/core.d +++ b/source/bubel/ecs/core.d @@ -49,10 +49,10 @@ Struct System1 Copyright: Copyright © 2018-2019, Dawid Masiukiewicz, Michał Masiukiewicz License: BSD 3-clause, see LICENSE file in project root folder. */ -module ecs.core; +module bubel.ecs.core; -public import ecs.manager; -public import ecs.entity; +public import bubel.ecs.manager; +public import bubel.ecs.entity; /************************************************************************************************************************ Main struct used as namespace for templates. @@ -74,15 +74,19 @@ static struct ECS mixin template Component() { __gshared ushort component_id = ushort.max; + + ComponentRef ref_() @nogc nothrow return + { + return ComponentRef(&this, component_id); + } } /************************************************************************************************************************ Mark structure as Event. Should be added on top of structure (before any data). */ - mixin template Event() + mixin template Event() { __gshared ushort event_id = ushort.max; - EntityID entity_id; } /************************************************************************************************************************ @@ -92,4 +96,20 @@ static struct ECS { alias ExcludedComponents = T; } -} \ No newline at end of file + + /************************************************************************************************************************ + Make list of readonly ependencies. This template get strings as arguments. Should be added inside System structure. + */ + mixin template ReadOnlyDependencies(T...) + { + alias ReadOnlyDependencies = T; + } + + /************************************************************************************************************************ + Make list of writable ependencies. This template get strings as arguments. Should be added inside System structure. + */ + mixin template WritableDependencies(T...) + { + alias WritableDependencies = T; + } +} diff --git a/source/ecs/entity.d b/source/bubel/ecs/entity.d similarity index 66% rename from source/ecs/entity.d rename to source/bubel/ecs/entity.d index 0bd2dea..6a64d50 100644 --- a/source/ecs/entity.d +++ b/source/bubel/ecs/entity.d @@ -4,10 +4,10 @@ Entity module. Copyright: Copyright © 2018-2019, Dawid Masiukiewicz, Michał Masiukiewicz License: BSD 3-clause, see LICENSE file in project root folder. */ -module ecs.entity; +module bubel.ecs.entity; -import ecs.system; -import ecs.manager; +import bubel.ecs.system; +import bubel.ecs.manager; /************************************************************************************************************************ Entity ID structure. Used as reference to Entity. Pointer to entity should be ever used to store entity reference! @@ -39,11 +39,44 @@ struct Entity if (T.component_id >= info.deltas.length || info.deltas[T.component_id] == 0) return null; - static if (EntityID.sizeof == 8) - uint ind = cast(uint)((cast(void*)&this - block.dataBegin()) >> 3); - else - uint ind = cast(uint)((cast(void*)&this - block.dataBegin()) / EntityID.sizeof()); - return cast(T*)(cast(void*)block + info.deltas[T.component_id] + ind * T.sizeof); + return cast(T*)(cast(void*)block + info.deltas[T.component_id] + block.entityIndex(&this) * T.sizeof); + } + + bool hasComponent(ushort component_id) + { + EntityManager.EntitiesBlock* block = gEM.getMetaData(&this); + EntityManager.EntityInfo* info = block.type_info; + if (component_id >= info.deltas.length || info.deltas[component_id] == 0)return false; + return true; + } + + EntityMeta getMeta() + { + EntityMeta meta; + meta.block = gEM.getMetaData(&this); + meta.index = meta.block.entityIndex(&this); + return meta; + } +} + +struct EntityMeta +{ + EntityManager.EntitiesBlock* block; + ushort index; + + T* getComponent(T)() const + { + const (EntityManager.EntityInfo)* info = block.type_info; + if (T.component_id >= info.deltas.length || info.deltas[T.component_id] == 0) + return null; + return cast(T*)(cast(void*)block + block.type_info.deltas[T.component_id] + index * T.sizeof); + } + + bool hasComponent(ushort component_id) + { + EntityManager.EntityInfo* info = block.type_info; + if (component_id >= info.deltas.length || info.deltas[component_id] == 0)return false; + return true; } } @@ -74,3 +107,14 @@ export struct EntityTemplate return cast(T*)(entity_data.ptr + info.tmpl_deltas[T.component_id]); } } + +/************************************************************************************************************************ +ComponentRef contain component ID and pointer to it. It used to add component data to entity. +*/ +export struct ComponentRef +{ + ///pointer to component + void* ptr; + ///component index + ushort component_id; +} diff --git a/source/ecs/events.d b/source/bubel/ecs/events.d similarity index 67% rename from source/ecs/events.d rename to source/bubel/ecs/events.d index ac7e185..64e0c79 100644 --- a/source/ecs/events.d +++ b/source/bubel/ecs/events.d @@ -1,9 +1,9 @@ -module ecs.events; +module bubel.ecs.events; -import ecs.block_allocator; -import ecs.entity; -import ecs.manager; -import ecs.std; +import bubel.ecs.block_allocator; +import bubel.ecs.entity; +import bubel.ecs.manager; +import bubel.ecs.std; import std.algorithm.comparison : max; @@ -20,7 +20,7 @@ package struct EventManager void destroy() nothrow @nogc { - if(event_block_alloc_mutex) + if (event_block_alloc_mutex) { event_block_alloc_mutex.destroy(); Mallocator.dispose(event_block_alloc_mutex); @@ -30,55 +30,60 @@ package struct EventManager export void sendEvent(Ev)(EntityID id, Ev event, uint thread_id = 0) nothrow @nogc { - uint block_id = current_index+thread_id; + uint block_id = current_index + thread_id; EventData* data = &events[Ev.event_id]; EventBlock* block = data.blocks[block_id]; //EntityManager.EventInfo* info = &manager.events[Ev.event_id]; - event.entity_id = id; + //event.entity_id = id; - if(block is null) + if (block is null) { event_block_alloc_mutex.lock(); - scope (exit) - event_block_alloc_mutex.unlock(); - block = cast(EventBlock*) allocator.getBlock(); + event_block_alloc_mutex.unlock(); + *block = EventBlock(); data.first_blocks[block_id] = block; data.blocks[block_id] = block; } - if(block.count >= data.max_events) + if (block.count >= data.max_events) { event_block_alloc_mutex.lock(); - scope (exit) - event_block_alloc_mutex.unlock(); - EventBlock* new_block = cast(EventBlock*) allocator.getBlock(); + event_block_alloc_mutex.unlock(); + *new_block = EventBlock(); block.next = new_block; block = new_block; data.blocks[block_id] = block; } - Ev* event_array = cast(Ev*)(cast(void*)block + data.data_offset); - event_array[block.count] = event; + uint size = Ev.sizeof + EntityID.sizeof; + void* ptr = cast(void*) block + data.data_offset + block.count * size; + *cast(EntityID*)ptr = id; + *cast(Ev*)(ptr + EntityID.sizeof) = event; + //Ev* event_array = cast(Ev*)(cast(void*) block + data.data_offset); + //event_array[block.count] = event; block.count++; } void swapCurrent() nothrow @nogc { - uint threads_count = cast(uint)manager.threads.length; - if(current_index == 0)current_index = threads_count; - else current_index = 0; + uint threads_count = cast(uint) manager.threads.length; + if (current_index == 0) + current_index = threads_count; + else + current_index = 0; - foreach(ref event;events) + foreach (ref event; events) { - foreach(ref first_block; event.first_blocks[current_index .. current_index + threads_count]) + foreach (ref first_block; event.first_blocks[current_index + .. current_index + threads_count]) { EventBlock* block = first_block; - while(block) + while (block) { EventBlock* to_dispose = block; block = block.next; @@ -86,7 +91,7 @@ package struct EventManager } first_block = null; } - foreach(ref block; event.blocks[current_index .. current_index + threads_count]) + foreach (ref block; event.blocks[current_index .. current_index + threads_count]) { block = null; } @@ -96,12 +101,12 @@ package struct EventManager void clearEvents() nothrow @nogc { //uint threads_count = cast(uint)manager.threads.length; - foreach(ref event;events) + foreach (ref event; events) { - foreach(ref first_block; event.first_blocks) + foreach (ref first_block; event.first_blocks) { EventBlock* block = first_block; - while(block) + while (block) { EventBlock* to_dispose = block; block = block.next; @@ -109,7 +114,7 @@ package struct EventManager } first_block = null; } - foreach(ref block; event.blocks) + foreach (ref block; event.blocks) { block = null; } @@ -120,23 +125,25 @@ package struct EventManager { disposeData(); events = Mallocator.makeArray!EventData(manager.events.length); - foreach(i,ref event;events) + foreach (i, ref event; events) { - event.blocks = Mallocator.makeArray!(EventBlock*)(threads_count*2); - event.first_blocks = Mallocator.makeArray!(EventBlock*)(threads_count*2); - event.data_offset = EventBlock.sizeof;//manager.events[i]. + event.blocks = Mallocator.makeArray!(EventBlock*)(threads_count * 2); + event.first_blocks = Mallocator.makeArray!(EventBlock*)(threads_count * 2); + event.data_offset = EventBlock.sizeof; //manager.events[i]. manager.alignNum(event.data_offset, manager.events[i].alignment); - event.max_events = cast(ushort)((events_block_size - event.data_offset) / manager.events[i].size); + uint size = manager.events[i].size + EntityID.sizeof; + event.max_events = cast(ushort)( + (events_block_size - event.data_offset) / size); } } private void disposeData() nothrow @nogc { clearEvents(); - if(events) + if (events) { - foreach(ref event;events) + foreach (ref event; events) { Mallocator.dispose(event.blocks); Mallocator.dispose(event.first_blocks); @@ -168,7 +175,7 @@ package struct EventManager ushort max_events; EventBlock*[] blocks; EventBlock*[] first_blocks; - + //EventBlock*[] current_blocks; } diff --git a/source/ecs/hash_map.d b/source/bubel/ecs/hash_map.d similarity index 61% rename from source/ecs/hash_map.d rename to source/bubel/ecs/hash_map.d index 5a8b253..764374c 100755 --- a/source/ecs/hash_map.d +++ b/source/bubel/ecs/hash_map.d @@ -1,9 +1,9 @@ -module ecs.hash_map; +module bubel.ecs.hash_map; import std.traits; -import ecs.vector; -import ecs.traits; +import bubel.ecs.vector; +import bubel.ecs.traits; enum doNotInline = "version(DigitalMars)pragma(inline,false);version(LDC)pragma(LDC_never_inline);"; @@ -11,36 +11,55 @@ private enum HASH_EMPTY = 0; private enum HASH_DELETED = 0x1; private enum HASH_FILLED_MARK = ulong(1) << 8 * ulong.sizeof - 1; -export ulong defaultHashFunc(T)(auto ref T t) nothrow @nogc { - static if (isIntegral!(T)) { +export ulong defaultHashFunc(T)(auto ref T t) nothrow @nogc +{ + static if (isIntegral!(T)) + { return hashInt(t); - } else { - return 0;//hashInt(t.hashOf); // hashOf is not giving proper distribution between H1 and H2 hash parts + } + else + { + static if(isArray!T)return hashInt(hash((cast(byte*)t.ptr)[0 .. t.length * ForeachType!(T).sizeof])); + else return hashInt(hash((cast(byte*)&t)[0 .. T.sizeof])); //hashInt(t.hashOf); // hashOf is not giving proper distribution between H1 and H2 hash parts } } +ulong hash(byte[] array) nothrow @nogc +{ + ulong hash = 0; + + foreach(c;array) + hash = c + (hash << 6) + (hash << 16) - hash; + + return hash; +} + // Can turn bad hash function to good one -export ulong hashInt(ulong x) nothrow @nogc @safe { +export ulong hashInt(ulong x) nothrow @nogc @safe +{ x = (x ^ (x >> 30)) * 0xbf58476d1ce4e5b9; x = (x ^ (x >> 27)) * 0x94d049bb133111eb; x = x ^ (x >> 31); return x; } -struct HashMap(KeyPar, ValuePar, alias hashFunc = defaultHashFunc) { +struct HashMap(KeyPar, ValuePar, alias hashFunc = defaultHashFunc) +{ alias Key = KeyPar; alias Value = ValuePar; - nothrow: +nothrow: enum rehashFactor = 0.75; enum size_t getIndexEmptyValue = size_t.max; - static struct KeyVal { + static struct KeyVal + { Key key; Value value; } - static struct Bucket { + static struct Bucket + { ulong hash; KeyVal keyValue; } @@ -49,58 +68,74 @@ struct HashMap(KeyPar, ValuePar, alias hashFunc = defaultHashFunc) { size_t length; // Used to compute loadFactor size_t markerdDeleted; - export void clear() { + export void clear() + { elements.clear(); length = 0; markerdDeleted = 0; } - export void reset() { + export void reset() + { elements.reset(); length = 0; markerdDeleted = 0; } - export bool isIn(ref Key el) { + export bool isIn(ref Key el) + { return getIndex(el) != getIndexEmptyValue; } - export bool isIn(Key el) { + export bool isIn(Key el) + { return getIndex(el) != getIndexEmptyValue; } - export Value* getPtr()(auto ref Key k) { + export Value* getPtr()(auto ref Key k) + { size_t index = getIndex(k); - if (index == getIndexEmptyValue) { + if (index == getIndexEmptyValue) + { return null; - } else { + } + else + { return &elements[index].keyValue.value; } } - export ref Value get()(auto ref Key k) { + export ref Value get()(auto ref Key k) + { size_t index = getIndex(k); assert(index != getIndexEmptyValue); return elements[index].keyValue.value; } deprecated("Use get with second parameter.") export auto ref Value getDefault()( - auto ref Key k, auto ref Value defaultValue) { + auto ref Key k, auto ref Value defaultValue) + { return get(k, defaultValue); } - export auto ref Value get()(auto ref Key k, auto ref Value defaultValue) { + export auto ref Value get()(auto ref Key k, auto ref Value defaultValue) + { size_t index = getIndex(k); - if (index == getIndexEmptyValue) { + if (index == getIndexEmptyValue) + { return defaultValue; - } else { + } + else + { return elements[index].keyValue.value; } } - export ref Value getInsertDefault()(auto ref Key k, auto ref Value defaultValue) { + export ref Value getInsertDefault()(auto ref Key k, auto ref Value defaultValue) + { size_t index = getIndex(k); - if (index == getIndexEmptyValue) { + if (index == getIndexEmptyValue) + { add(k, defaultValue); } index = getIndex(k); @@ -109,9 +144,11 @@ struct HashMap(KeyPar, ValuePar, alias hashFunc = defaultHashFunc) { } - export bool tryRemove(Key el) { + export bool tryRemove(Key el) + { size_t index = getIndex(el); - if (index == getIndexEmptyValue) { + if (index == getIndexEmptyValue) + { return false; } length--; @@ -120,28 +157,34 @@ struct HashMap(KeyPar, ValuePar, alias hashFunc = defaultHashFunc) { return true; } - export void remove(Key el) { + export void remove(Key el) + { bool ok = tryRemove(el); assert(ok); } - export ref Value opIndex()(auto ref Key key) { + export ref Value opIndex()(auto ref Key key) + { return get(key); } - export void opIndexAssign()(auto ref Value value, auto ref Key key) { + export void opIndexAssign()(auto ref Value value, auto ref Key key) + { add(key, value); } - export void add()(auto ref Key key, auto ref Value value) { + export void add()(auto ref Key key, auto ref Value value) + { size_t index = getIndex(key); - if (index != getIndexEmptyValue) { + if (index != getIndexEmptyValue) + { elements[index].keyValue.value = value; return; } if (getLoadFactor(length + 1) > rehashFactor - || getLoadFactor(length + markerdDeleted) > rehashFactor) { + || getLoadFactor(length + markerdDeleted) > rehashFactor) + { rehash(); } length++; @@ -150,10 +193,13 @@ struct HashMap(KeyPar, ValuePar, alias hashFunc = defaultHashFunc) { immutable size_t rotateMask = elements.length - 1; index = hash & rotateMask; // Starting point - while (true) { + while (true) + { Bucket* gr = &elements[index]; - if ((gr.hash & HASH_FILLED_MARK) == 0) { - if (gr.hash == HASH_DELETED) { + if ((gr.hash & HASH_FILLED_MARK) == 0) + { + if (gr.hash == HASH_DELETED) + { markerdDeleted--; } gr.hash = hash; @@ -171,15 +217,18 @@ struct HashMap(KeyPar, ValuePar, alias hashFunc = defaultHashFunc) { //int numA; //int numB; - export size_t getIndex(Key el) { + export size_t getIndex(Key el) + { return getIndex(el); } - export size_t getIndex(ref Key el) { + export size_t getIndex(ref Key el) + { mixin(doNotInline); immutable size_t groupsLength = elements.length; - if (groupsLength == 0) { + if (groupsLength == 0) + { return getIndexEmptyValue; } @@ -188,13 +237,16 @@ struct HashMap(KeyPar, ValuePar, alias hashFunc = defaultHashFunc) { size_t index = hash & rotateMask; // Starting point //numA++; - while (true) { + while (true) + { //numB++; Bucket* gr = &elements[index]; - if (gr.hash == hash && gr.keyValue.key == el) { + if (gr.hash == hash && gr.keyValue.key == el) + { return index; } - if (gr.hash == HASH_EMPTY) { + if (gr.hash == HASH_EMPTY) + { return getIndexEmptyValue; } @@ -204,21 +256,26 @@ struct HashMap(KeyPar, ValuePar, alias hashFunc = defaultHashFunc) { } - export float getLoadFactor(size_t forElementsNum) { - if (elements.length == 0) { + export float getLoadFactor(size_t forElementsNum) + { + if (elements.length == 0) + { return 1; } return cast(float) forElementsNum / (elements.length); } - export void rehash()() { + export void rehash()() + { mixin(doNotInline); // Get all elements Vector!KeyVal allElements; allElements.reserve(elements.length); - foreach (ref Bucket el; elements) { - if ((el.hash & HASH_FILLED_MARK) == 0) { + foreach (ref Bucket el; elements) + { + if ((el.hash & HASH_FILLED_MARK) == 0) + { el.hash = HASH_EMPTY; continue; } @@ -227,12 +284,14 @@ struct HashMap(KeyPar, ValuePar, alias hashFunc = defaultHashFunc) { } - if (getLoadFactor(length + 1) > rehashFactor) { // Reallocate + if (getLoadFactor(length + 1) > rehashFactor) + { // Reallocate elements.length = (elements.length ? elements.length : 4) << 1; // Power of two, initially 8 elements } // Insert elements - foreach (i, ref el; allElements) { + foreach (i, ref el; allElements) + { add(el.key, el.value); } length = allElements.length; @@ -240,19 +299,29 @@ struct HashMap(KeyPar, ValuePar, alias hashFunc = defaultHashFunc) { } // foreach support - export int opApply(DG)(scope DG dg) { + export int opApply(DG)(scope DG dg) + { int result; - foreach (ref Bucket gr; elements) { - if ((gr.hash & HASH_FILLED_MARK) == 0) { + foreach (ref Bucket gr; elements) + { + if ((gr.hash & HASH_FILLED_MARK) == 0) + { continue; } - static if (isForeachDelegateWithTypes!(DG, Key)) { + static if (isForeachDelegateWithTypes!(DG, Key)) + { result = dg(gr.keyValue.key); - } else static if (isForeachDelegateWithTypes!(DG, Value)) { + } + else static if (isForeachDelegateWithTypes!(DG, Value)) + { result = dg(gr.keyValue.value); - } else static if (isForeachDelegateWithTypes!(DG, Key, Value)) { + } + else static if (isForeachDelegateWithTypes!(DG, Key, Value)) + { result = dg(gr.keyValue.key, gr.keyValue.value); - } else { + } + else + { static assert(0); } if (result) @@ -263,9 +332,11 @@ struct HashMap(KeyPar, ValuePar, alias hashFunc = defaultHashFunc) { return result; } - export int byKey(scope int delegate(Key k) nothrow dg) { + export int byKey(scope int delegate(Key k) nothrow dg) + { int result; - foreach (ref Key k; this) { + foreach (ref Key k; this) + { result = dg(k); if (result) break; @@ -273,9 +344,11 @@ struct HashMap(KeyPar, ValuePar, alias hashFunc = defaultHashFunc) { return result; } - export int byValue(scope int delegate(ref Value k) nothrow dg) { + export int byValue(scope int delegate(ref Value k) nothrow dg) + { int result; - foreach (ref Value v; this) { + foreach (ref Value v; this) + { result = dg(v); if (result) break; @@ -283,13 +356,15 @@ struct HashMap(KeyPar, ValuePar, alias hashFunc = defaultHashFunc) { return result; } - export int byKeyValue(scope int delegate(ref Key k, ref Value v) nothrow dg) { + export int byKeyValue(scope int delegate(ref Key k, ref Value v) nothrow dg) + { int result; - foreach (ref Key k, ref Value v; this) { + foreach (ref Key k, ref Value v; this) + { result = dg(k, v); if (result) break; } return result; } -} \ No newline at end of file +} diff --git a/source/ecs/id_manager.d b/source/bubel/ecs/id_manager.d similarity index 75% rename from source/ecs/id_manager.d rename to source/bubel/ecs/id_manager.d index 1ab8465..aaeef30 100644 --- a/source/ecs/id_manager.d +++ b/source/bubel/ecs/id_manager.d @@ -1,10 +1,10 @@ -module ecs.id_manager; +module bubel.ecs.id_manager; -import ecs.entity; -import ecs.std; -import ecs.vector; +import bubel.ecs.entity; +import bubel.ecs.std; +import bubel.ecs.vector; -import ecs.atomic; +import bubel.ecs.atomic; import core.stdc.string : memcpy; /************************************************************************************************************************ @@ -17,12 +17,8 @@ struct IDManager */ pragma(inline, false) EntityID getNewID() nothrow @nogc { - //uint current = m_next_id; - //uint next;// = m_ids_array[m_next_id].next_id; -//begin: - //if (current == uint.max)//> m_last_id) int current = m_stack_top.atomicOp!"-="(1) + 1; - if(current < 0) + if (current < 0) { uint add_id = m_last_id.atomicOp!"+="(1) - 1; @@ -33,7 +29,7 @@ struct IDManager if (block_id >= m_blocks_count) { add_mutex.lock(); - if(block_id >= m_blocks_count) + if (block_id >= m_blocks_count) { m_blocks[m_blocks_count].alloc(); m_blocks_count++; @@ -48,29 +44,11 @@ struct IDManager return id; } - - //current += 1; uint index = m_free_stack[current]; EntityID id; id.id = index; id.counter = m_ids_array[index].counter; - //current = m_ids_array[index].next_id; return id; - - /*next = m_ids_array[current].next_id; - if(cas(&m_next_id,current,next)) - { - EntityID id; - id.id = current; - id.counter = m_ids_array[current].counter; - m_next_id = m_ids_array[current].next_id; - return id; - } - else - { - current = next; - goto begin; - }*/ } /************************************************************************************************************************ @@ -78,13 +56,12 @@ struct IDManager */ void releaseID(EntityID id) nothrow @nogc { + optimize(); Data* data = &m_ids_array[id.id]; if (data.counter != id.counter) return; data.counter++; - //data.next_id = m_next_id; data.entity = null; - ///m_next_id = id.id; m_stack_top.atomicOp!"+="(1); m_free_stack[m_stack_top] = id.id; @@ -136,9 +113,11 @@ struct IDManager */ export bool isExist(EntityID id) nothrow @nogc { - if(id.id >= m_ids_array.length)return false; + if (id.id >= m_ids_array.length) + return false; Data* data = &m_ids_array[id.id]; - if(data.entity is null)return false; + if (data.entity is null) + return false; return data.counter == id.counter; } @@ -150,7 +129,8 @@ struct IDManager m_ids_array = Mallocator.makeArray!Data(65536); m_free_stack = Mallocator.makeArray!uint(65536); m_blocks = Mallocator.makeArray!Block(64); - foreach(ref block;m_blocks)block = Block(); + foreach (ref block; m_blocks) + block = Block(); m_blocks_count = 1; m_blocks[0].alloc(); @@ -166,20 +146,23 @@ struct IDManager */ void deinitialize() @trusted @nogc nothrow { - if(m_ids_array)Mallocator.dispose(m_ids_array); - if(m_free_stack)Mallocator.dispose(m_free_stack); - if(m_blocks) + if (m_ids_array) + Mallocator.dispose(m_ids_array); + if (m_free_stack) + Mallocator.dispose(m_free_stack); + if (m_blocks) { - foreach(ref block;m_blocks) + foreach (ref block; m_blocks) { - if(block.data)block.free(); + if (block.data) + block.free(); } Mallocator.dispose(m_blocks); } - if(add_mutex) + if (add_mutex) { add_mutex.destroy(); - Mallocator.dispose(add_mutex);//cast(void*)add_mutex); //workaround for compiler bug + Mallocator.dispose(add_mutex); //cast(void*)add_mutex); //workaround for compiler bug add_mutex = null; } } @@ -189,27 +172,31 @@ struct IDManager */ void optimize() nothrow @nogc { - if(m_stack_top < -1)m_stack_top = -1; - if(m_last_id > m_ids_array.length) + if (m_stack_top < -1) + m_stack_top = -1; + if (m_last_id > m_ids_array.length) { - uint begin = cast(uint)m_ids_array.length; + uint begin = cast(uint) m_ids_array.length; Data[] new_array = Mallocator.makeArray!Data(begin + (m_blocks_count << 16)); memcpy(new_array.ptr, m_ids_array.ptr, m_ids_array.length * Data.sizeof); Mallocator.dispose(m_ids_array); m_ids_array = new_array; uint[] new_stack = Mallocator.makeArray!uint(m_ids_array.length); - memcpy(new_stack.ptr,m_free_stack.ptr,m_free_stack.length * uint.sizeof); + memcpy(new_stack.ptr, m_free_stack.ptr, m_free_stack.length * uint.sizeof); Mallocator.dispose(m_free_stack); m_free_stack = new_stack; - foreach(block;m_blocks[0..m_blocks_count-1]) + foreach (block; m_blocks[0 .. m_blocks_count - 1]) { - memcpy(cast(void*)m_ids_array.ptr + begin * Data.sizeof, block.data.ptr, 65536 * Data.sizeof); + memcpy(cast(void*) m_ids_array.ptr + begin * Data.sizeof, + block.data.ptr, 65536 * Data.sizeof); begin += 65536; } - memcpy(cast(void*)m_ids_array.ptr + begin * Data.sizeof, m_blocks[m_blocks_count-1].data.ptr, (m_last_id - begin) * Data.sizeof); - foreach(ref block;m_blocks[1..m_blocks_count])block.free(); + memcpy(cast(void*) m_ids_array.ptr + begin * Data.sizeof, + m_blocks[m_blocks_count - 1].data.ptr, (m_last_id - begin) * Data.sizeof); + foreach (ref block; m_blocks[1 .. m_blocks_count]) + block.free(); m_blocks_count = 1; } } @@ -241,15 +228,12 @@ struct IDManager private: Mutex* add_mutex; - //shared uint m_next_id = 0; - - //shared uint m_last_id = 0; + Data[] m_ids_array = null; uint m_blocks_count = 0; Block[] m_blocks; - //shared int m_stack_top = -1; uint[] m_free_stack = null; - + align(64) shared uint m_last_id = 0; align(64) shared int m_stack_top = -1; } diff --git a/source/ecs/manager.d b/source/bubel/ecs/manager.d similarity index 79% rename from source/ecs/manager.d rename to source/bubel/ecs/manager.d index aca7f53..0982531 100644 --- a/source/ecs/manager.d +++ b/source/bubel/ecs/manager.d @@ -4,7 +4,7 @@ Most important module. Almost every function is called from EntityManager. Copyright: Copyright © 2018-2019, Dawid Masiukiewicz, Michał Masiukiewicz License: BSD 3-clause, see LICENSE file in project root folder. */ -module ecs.manager; +module bubel.ecs.manager; import std.algorithm : max; import std.conv : to; @@ -14,21 +14,21 @@ import std.traits; //import core.stdc.stdlib : qsort; //import core.stdc.string; -import ecs.system; //not ordered as forward reference bug workaround -import ecs.block_allocator; -import ecs.entity; -import ecs.events; -import ecs.hash_map; -import ecs.id_manager; -import ecs.simple_vector; -import ecs.std; -import ecs.traits; -import ecs.vector; -import ecs.atomic; +import bubel.ecs.system; //not ordered as forward reference bug workaround +import bubel.ecs.block_allocator; +import bubel.ecs.entity; +import bubel.ecs.events; +import bubel.ecs.hash_map; +import bubel.ecs.id_manager; +import bubel.ecs.simple_vector; +import bubel.ecs.std; +import bubel.ecs.traits; +import bubel.ecs.vector; +import bubel.ecs.atomic; export alias gEM = EntityManager.instance; export alias gEntityManager = EntityManager.instance; -alias SerializeVector = ecs.vector.Vector!ubyte; +alias SerializeVector = bubel.ecs.vector.Vector!ubyte; /************************************************************************************************************************ Entity manager is responsible for everything. @@ -104,8 +104,8 @@ export struct EntityManager Mallocator.dispose(system.jobs); if (system.m_read_only_components) Mallocator.dispose(system.m_read_only_components); - if (system.m_modified_components) - Mallocator.dispose(system.m_modified_components); + if (system.m_writable_components) + Mallocator.dispose(system.m_writable_components); if (system.m_components) Mallocator.dispose(system.m_components); if (system.m_excluded_components) @@ -126,7 +126,7 @@ export struct EntityManager //if(info.components)Mallocator.dispose(info.components); Mallocator.dispose(info); - } //*/ + } foreach (UpdatePass* pass; passes) { @@ -402,7 +402,7 @@ export struct EntityManager Sys* data_system = cast(Sys*) data.system_pointer; Type* event = cast(Type*) data.event; - data_system.handleEvent(gEM.getEntity(event.entity_id), *event); + data_system.handleEvent(data.entity, *event); } void setEventCallers(Sys)(ref System system) @@ -452,6 +452,8 @@ export struct EntityManager uint excluded = 1; uint optional = 1; uint req = 1; + uint readonly_dep = 1; + uint writable_dep = 1; } static ComponentsCounts getComponentsCounts()() @@ -467,53 +469,55 @@ export struct EntityManager foreach (member; __traits(allMembers, Sys.EntitiesData)) { alias MemberType = typeof(__traits(getMember, Sys.EntitiesData, member)); - if (member == "length" || member == "thread_id" + if (member == "length" || member == "thread_id" || member == "job_id" || is(MemberType == Entity[]) || is(MemberType == const(Entity)[])) { - continue; + //continue; } - - string name; - static if (isArray!MemberType) - { // Workaround. This code is never called with: not an array type, but compiler prints an error - name = Unqual!(ForeachType!MemberType).stringof; - } - - bool is_optional; - bool is_read_only; - - if (is(CopyConstness!(ForeachType!(MemberType), int) == const(int))) + else { - is_read_only = true; - } - - foreach (att; __traits(getAttributes, __traits(getMember, - Sys.EntitiesData, member))) - { - if (att == "optional") - { - is_optional = true; + string name; + static if (isArray!MemberType) + { // Workaround. This code is never called with: not an array type, but compiler prints an error + name = Unqual!(ForeachType!MemberType).stringof; } - if (att == "readonly") + + bool is_optional; + bool is_read_only; + + if (is(CopyConstness!(ForeachType!(MemberType), int) == const(int))) { is_read_only = true; } - } - if (is_read_only) - { - components_counts.readonly++; - } - else - { - components_counts.mutable++; - } - if (is_optional) - { - components_counts.optional++; - } - else - { - components_counts.req++; + + foreach (att; __traits(getAttributes, __traits(getMember, + Sys.EntitiesData, member))) + { + if (att == "optional") + { + is_optional = true; + } + if (att == "readonly") + { + is_read_only = true; + } + } + if (is_read_only) + { + components_counts.readonly++; + } + else + { + components_counts.mutable++; + } + if (is_optional) + { + components_counts.optional++; + } + else + { + components_counts.req++; + } } } @@ -532,7 +536,22 @@ export struct EntityManager { components_counts.excluded++; } + } + } + static if (__traits(hasMember, Sys, "ReadOnlyDependencies")) + { + foreach (str; Sys.ReadOnlyDependencies) + { + components_counts.readonly_dep++; + } + } + + static if (__traits(hasMember, Sys, "WritableDependencies")) + { + foreach (str; Sys.WritableDependencies) + { + components_counts.writable_dep++; } } @@ -568,6 +587,16 @@ export struct EntityManager return m_req[0 .. m_req_counter]; } + CompInfo[] readonlyDeps() + { + return m_readonly_dep[0 .. m_readonly_dep_counter]; + } + + CompInfo[] writableDeps() + { + return m_writable_dep[0 .. m_writable_dep_counter]; + } + void addReadonly(CompInfo info) { m_readonly[m_readonly_counter++] = info; @@ -593,17 +622,31 @@ export struct EntityManager m_req[m_req_counter++] = info; } + void addReadonlyDep(CompInfo info) + { + m_readonly_dep[m_readonly_dep_counter++] = info; + } + + void addWritableDep(CompInfo info) + { + m_writable_dep[m_writable_dep_counter++] = info; + } + CompInfo[counts.readonly] m_readonly; CompInfo[counts.mutable] m_mutable; CompInfo[counts.excluded] m_excluded; CompInfo[counts.optional] m_optional; CompInfo[counts.req] m_req; + CompInfo[counts.readonly_dep] m_readonly_dep; + CompInfo[counts.writable_dep] m_writable_dep; uint m_readonly_counter; uint m_mutable_counter; uint m_excluded_counter; uint m_optional_counter; uint m_req_counter; + uint m_readonly_dep_counter; + uint m_writable_dep_counter; string entites_array; } @@ -615,7 +658,9 @@ export struct EntityManager size_t opt = components_info.optional.length; size_t excluded = components_info.excluded.length; size_t read_only = components_info.readonly.length; - size_t modified = components_info.mutable.length; + size_t writable = components_info.mutable.length; + size_t read_only_deps = components_info.readonlyDeps.length; + size_t writable_deps = components_info.writableDeps.length; if (req > 0) system.m_components = Mallocator.makeArray!ushort(req); @@ -625,8 +670,12 @@ export struct EntityManager system.m_excluded_components = Mallocator.makeArray!ushort(excluded); if (read_only > 0) system.m_read_only_components = Mallocator.makeArray!ushort(read_only); - if (modified > 0) - system.m_modified_components = Mallocator.makeArray!ushort(modified); + if (writable > 0) + system.m_writable_components = Mallocator.makeArray!ushort(writable); + if (read_only_deps > 0) + system.m_readonly_dependencies = Mallocator.makeArray!ushort(read_only_deps); + if (writable_deps > 0) + system.m_writable_dependencies = Mallocator.makeArray!ushort(writable_deps); } @@ -643,55 +692,57 @@ export struct EntityManager foreach (member; __traits(allMembers, Sys.EntitiesData)) { alias MemberType = typeof(__traits(getMember, Sys.EntitiesData, member)); - if (member == "length" || member == "thread_id" + if (member == "length" || member == "thread_id" || member == "job_id" || is(MemberType == Entity[]) || is(MemberType == const(Entity)[])) { if (is(MemberType == Entity[]) || is(MemberType == const(Entity)[])) components_info.entites_array = member; - continue; + //continue; } - - string name; - static if (isArray!MemberType) - { // Workaround. This code is never called with: not an array type, but compiler prints an error - name = Unqual!(ForeachType!MemberType).stringof; - } - - bool is_optional; - bool is_read_only; - - if (is(CopyConstness!(ForeachType!(MemberType), int) == const(int))) + else { - is_read_only = true; - } - - foreach (att; __traits(getAttributes, __traits(getMember, - Sys.EntitiesData, member))) - { - if (att == "optional") - { - is_optional = true; + string name; + static if (isArray!MemberType) + { // Workaround. This code is never called with: not an array type, but compiler prints an error + name = Unqual!(ForeachType!MemberType).stringof; } - if (att == "readonly") + + bool is_optional; + bool is_read_only; + + if (is(CopyConstness!(ForeachType!(MemberType), int) == const(int))) { is_read_only = true; } - } - if (is_read_only) - { - components_info.addReadonly(CompInfo(member, name)); - } - else - { - components_info.addMutable(CompInfo(member, name)); - } - if (is_optional) - { - components_info.addOptional(CompInfo(member, name)); - } - else - { - components_info.addReq(CompInfo(member, name)); + + foreach (att; __traits(getAttributes, __traits(getMember, + Sys.EntitiesData, member))) + { + if (att == "optional") + { + is_optional = true; + } + if (att == "readonly") + { + is_read_only = true; + } + } + if (is_read_only) + { + components_info.addReadonly(CompInfo(member, name)); + } + else + { + components_info.addMutable(CompInfo(member, name)); + } + if (is_optional) + { + components_info.addOptional(CompInfo(member, name)); + } + else + { + components_info.addReq(CompInfo(member, name)); + } } } @@ -714,6 +765,22 @@ export struct EntityManager } } + static if (__traits(hasMember, Sys, "ReadOnlyDependencies")) + { + foreach (str; Sys.ReadOnlyDependencies) + { + components_info.addReadonlyDep(CompInfo(str, str)); + } + } + + static if (__traits(hasMember, Sys, "WritableDependencies")) + { + foreach (str; Sys.WritableDependencies) + { + components_info.addWritableDep(CompInfo(str, str)); + } + } + return components_info; } @@ -742,6 +809,13 @@ export struct EntityManager static assert(MemberType.sizeof > 1, "EntitiesData 'thread_id' member can't be byte or ubyte."); } + else static if (member == "job_id") + { + static assert(isIntegral!(MemberType), + "EntitiesData 'job_id' member must be integral type."); + static assert(MemberType.sizeof > 1, + "EntitiesData 'job_id' member can't be byte or ubyte."); + } else static if (!(isArray!(MemberType))) static assert(0, "EntitiesData members should be arrays of elements!"); } @@ -807,12 +881,11 @@ export struct EntityManager else assert(comp != ushort.max, "Can't register system \"" ~ Sys.stringof ~ "\" due to non existing component \"" ~ comp_info.type ~ "\"."); - system.m_modified_components[iii] = comp; + system.m_writable_components[iii] = comp; } - } - static void fillInputData(ref Sys.EntitiesData input_data, EntityInfo* info, + static void fillInputData()(ref Sys.EntitiesData input_data, EntityInfo* info, EntitiesBlock* block, uint offset, uint entities_count, System* system) { //enum ComponentsIndices components_info = getComponentsInfo(); @@ -943,6 +1016,11 @@ export struct EntityManager .thread_id; } + static if (hasMember!(Sys.EntitiesData, "job_id")) + { + input_data.job_id = cast(typeof(input_data.job_id)) data.job_id; + } + //s.onUpdate(input_data); (cast(typeof(&__traits(getOverloads, s, "onUpdate")[OnUpdateOverloadNum])) data.update_delegate)(input_data); @@ -971,6 +1049,11 @@ export struct EntityManager input_data.thread_id = cast(typeof(input_data.thread_id)) data.thread_id; } + static if (hasMember!(Sys.EntitiesData, "job_id")) + { + input_data.job_id = cast(typeof(input_data.job_id)) data.job_id; + } + (cast(typeof(&__traits(getOverloads, s, "onUpdate")[OnUpdateOverloadNum])) data.update_delegate)(input_data); } @@ -1059,20 +1142,54 @@ export struct EntityManager genCompList(system, components_map); + foreach (iii, comp_info; components_info.readonlyDeps) + { + ushort comp = external_dependencies_map.get(cast(const(char)[]) comp_info.type, + ushort.max); + version (D_BetterC) + assert(comp != ushort.max, + "Can't register system \"" ~ Sys.stringof + ~ "\" due to non existing dependency."); + else + assert(comp != ushort.max, "Can't register system \"" ~ Sys.stringof + ~ "\" due to non existing dependency \"" ~ comp_info.type ~ "\"."); + system.m_readonly_dependencies[iii] = comp; + } + + foreach (iii, comp_info; components_info.writableDeps) + { + ushort comp = external_dependencies_map.get(cast(char[]) comp_info.type, ushort.max); + version (D_BetterC) + assert(comp != ushort.max, + "Can't register system \"" ~ Sys.stringof + ~ "\" due to non existing dependency."); + else + assert(comp != ushort.max, "Can't register system \"" ~ Sys.stringof + ~ "\" due to non existing dependency \"" ~ comp_info.type ~ "\"."); + system.m_writable_dependencies[iii] = comp; + } + ushort sys_id = systems_map.get(cast(char[]) Sys.stringof, ushort.max); if (sys_id < systems.length) { - system.enable(); + systems[sys_id].disable(); + if (systems[sys_id].m_destroy) + (cast(void function(void*)) systems[sys_id].m_destroy)( + systems[sys_id].m_system_pointer); if (system.m_create) (cast(void function(void*)) system.m_create)(system.m_system_pointer); + system.enable(); + system.m_id = sys_id; + system.m_name = systems[sys_id].m_name; systems[sys_id] = system; } else { system.m_name = Mallocator.makeArray(cast(char[]) Sys.stringof); + systems_map.add(system.m_name, cast(ushort) systems.length); system.m_id = cast(ushort)(systems.length); @@ -1118,6 +1235,11 @@ export struct EntityManager return cast(ushort)(passes.length - 1); } + export void registerDependency(const(char)[] name) + { + return external_dependencies_map.add(name, cast(ushort) external_dependencies_map.length); + } + /************************************************************************************************************************ Register component into EntityManager. */ @@ -1153,7 +1275,10 @@ export struct EntityManager info.create_callback = &callCreate; } - info.size = Comp.sizeof; + static if (Comp.sizeof == 1 && Fields!(Comp).length == 0) + info.size = 0; + else + info.size = Comp.sizeof; info.alignment = Comp.alignof; //8; info.init_data = Mallocator.makeArray!ubyte(Comp.sizeof); *cast(Comp*) info.init_data.ptr = Comp.init; // = Comp(); @@ -1219,7 +1344,9 @@ export struct EntityManager "Can't call function with system which hasn't EntitesData structure."); static assert(__traits(hasMember, Sys, "onUpdate"), "Can't call function with system which hasn't onUpdate function callback."); - static assert(is(SetFunctionAttributes!(T,functionLinkage!(s.onUpdate), functionAttributes!(s.onUpdate)) == typeof(&s.onUpdate)), "Function must match system update function."); + static assert(is(SetFunctionAttributes!(T, functionLinkage!(s.onUpdate), + functionAttributes!(s.onUpdate)) == typeof(&s.onUpdate)), + "Function must match system update function."); static assert(__traits(hasMember, Sys, "system_id"), "Sys must be system type."); System* system = getSystem(Sys.system_id); @@ -1253,7 +1380,7 @@ export struct EntityManager foreach (caller; passes[pass].system_callers) { System* sys = &systems[caller.system_id]; - if (sys.enabled && sys.execute) + if (sys.enabled && sys.willExecute) { if (sys.m_empty) { @@ -1293,7 +1420,7 @@ export struct EntityManager foreach (caller; passes[pass].system_callers) { System* sys = &systems[caller.system_id]; - if (sys.enabled && sys.execute) + if (sys.enabled && sys.willExecute) { uint job_id = 0; void nextJob() @@ -1304,6 +1431,7 @@ export struct EntityManager memcpy(callers.ptr, &tmp_datas[0], CallData.sizeof * tmp_datas.length); tmp_datas.clear(); sys.jobs[job_id].callers = callers; + sys.jobs[job_id].id = job_id; job_id++; } @@ -1490,6 +1618,8 @@ export struct EntityManager //fill components with default data foreach (comp; info.components) { + if (components[comp].size == 0) + continue; memcpy(temp.entity_data.ptr + info.tmpl_deltas[comp], components[comp].init_data.ptr, components[comp].size); } @@ -1499,6 +1629,8 @@ export struct EntityManager ushort index = block.entityIndex(entity); foreach (comp; info.components) { + if (components[comp].size == 0) + continue; memcpy(cast(void*) temp.entity_data.ptr + info.tmpl_deltas[comp], cast(void*) block + info.deltas[comp] + components[comp].size * index, components[comp].size); @@ -1547,6 +1679,8 @@ export struct EntityManager //fill components with default data foreach (comp; info.components) { + if (components[comp].size == 0) + continue; memcpy(temp.entity_data.ptr + info.tmpl_deltas[comp], components[comp].init_data.ptr, components[comp].size); } @@ -1614,14 +1748,19 @@ export struct EntityManager //fill components with default data and copy from base template foreach (comp; info.components) { - if (comp < base_tmpl.info.deltas.length && base_tmpl.info.deltas[comp] != ushort.max) //copy data from base component - { + if (comp < base_tmpl.info.tmpl_deltas.length + && base_tmpl.info.tmpl_deltas[comp] != ushort.max) //copy data from base component + { + if (components[comp].size == 0) + continue; memcpy(temp.entity_data.ptr + info.tmpl_deltas[comp], base_tmpl.entity_data.ptr + base_tmpl.info.tmpl_deltas[comp], components[comp].size); } else //fill with default data { + if (components[comp].size == 0) + continue; memcpy(temp.entity_data.ptr + info.tmpl_deltas[comp], components[comp].init_data.ptr, components[comp].size); } @@ -1630,6 +1769,20 @@ export struct EntityManager return temp; } + /************************************************************************************************************************ + Allocate EntityTemplate copy. + + Params: + copy_tmpl = template which should be copied + */ + export EntityTemplate* allocateTemplate(EntityTemplate* copy_tmpl) + { + EntityTemplate* tmpl = Mallocator.make!EntityTemplate; + tmpl.info = copy_tmpl.info; + tmpl.entity_data = Mallocator.makeArray(copy_tmpl.entity_data); + return tmpl; + } + /************************************************************************************************************************ Returns entity type info. @@ -1697,8 +1850,8 @@ export struct EntityManager } info.comp_add_info = Mallocator.makeArray!(EntityInfo*)(instance.components.length); - info.comp_rem_info = Mallocator.makeArray!(EntityInfo*)(instance.components.length, - info); + //info.comp_rem_info = Mallocator.makeArray!(EntityInfo*)(instance.components.length); + info.comp_rem_info = Mallocator.makeArray!(EntityInfo*)(info.deltas.length); foreach (comp; info.components) { @@ -1758,11 +1911,11 @@ export struct EntityManager } add_len++; //move elements after new listener - if(add_len < tmp_add.length) - for (int k = add_len; k > j; k--) - { - tmp_add[k] = tmp_add[k - 1]; - } + if (add_len < tmp_add.length) + for (int k = add_len; k > j; k--) + { + tmp_add[k] = tmp_add[k - 1]; + } //assign listener tmp_add[j] = cast(ushort) i; } @@ -1778,11 +1931,11 @@ export struct EntityManager } rem_len++; //move elements after new listener - if(rem_len < tmp_add.length) - for (int k = rem_len; k > j; k--) - { - tmp_rem[k] = tmp_rem[k - 1]; - } + if (rem_len < tmp_add.length) + for (int k = rem_len; k > j; k--) + { + tmp_rem[k] = tmp_rem[k - 1]; + } //assign listener tmp_rem[j] = cast(ushort) i; } @@ -1798,11 +1951,11 @@ export struct EntityManager } ch_len++; //move elements after new listener - if(ch_len < tmp_add.length) - for (int k = ch_len; k > j; k--) - { - tmp_ch[k] = tmp_ch[k - 1]; - } + if (ch_len < tmp_add.length) + for (int k = ch_len; k > j; k--) + { + tmp_ch[k] = tmp_ch[k - 1]; + } //assign listener tmp_ch[j] = cast(ushort) i; } @@ -1958,10 +2111,10 @@ export struct EntityManager { ThreadData* data = &threads[threadID]; uint num = cast(uint) del_ids.length; - data.change_entities_list.add(0); - data.change_entities_list.add((cast(ubyte*)&entity_id)[0 .. EntityID.sizeof]); - data.change_entities_list.add((cast(ubyte*)&num)[0 .. uint.sizeof]); - data.change_entities_list.add((cast(ubyte*) del_ids.ptr)[0 .. num * 2]); + data.changeEntitiesList.add(0); + data.changeEntitiesList.add((cast(ubyte*)&entity_id)[0 .. EntityID.sizeof]); + data.changeEntitiesList.add((cast(ubyte*)&num)[0 .. uint.sizeof]); + data.changeEntitiesList.add((cast(ubyte*) del_ids.ptr)[0 .. num * 2]); } private void __removeComponents(EntityID entity_id, ushort[] del_ids) @@ -2001,6 +2154,8 @@ export struct EntityManager return;*/ EntitiesBlock* new_block = findBlockWithFreeSpace(new_info); + updateEntityInfoBlocks(new_info); + assert(new_block.added_count == 0); void* start = new_block.dataBegin() + new_block.entities_count * EntityID.sizeof; @@ -2024,10 +2179,16 @@ export struct EntityManager foreach (comp; new_info.components) { uint comp_size = components[comp].size; + if (comp_size == 0) + continue; memcpy(cast(void*) new_block + new_info.deltas[comp] + new_block.entities_count * comp_size, cast(void*) block + info.deltas[comp] + ind * comp_size, comp_size); } + new_block.entities_count++; + if (new_block != new_info.update_block) + new_info.update_block = new_block; + if (new_info.add_listeners) { foreach (listener; new_info.add_listeners) @@ -2035,7 +2196,7 @@ export struct EntityManager if (!info.systems[listener]) { callAddEntityListener(&systems[listener], new_info, new_block, - new_block.entities_count, new_block.entities_count + 1); + new_block.entities_count - 1, new_block.entities_count); } } } @@ -2047,13 +2208,11 @@ export struct EntityManager if (info.systems[listener]) { callChangeEntityListener(&systems[listener], new_info, new_block, - new_block.entities_count, new_block.entities_count + 1, del_ids); + new_block.entities_count - 1, new_block.entities_count, del_ids); } } } - new_block.entities_count++; - removeEntityNoID(entity, block); } @@ -2136,12 +2295,14 @@ export struct EntityManager //EntityInfo* new_info = getEntityInfo(ids[0 .. len]); EntitiesBlock* new_block = findBlockWithFreeSpace(new_info); + updateEntityInfoBlocks(new_info); + assert(new_block.added_count == 0); void* start = new_block.dataBegin() + new_block.entities_count * EntityID.sizeof; Entity* new_entity = cast(Entity*) start; new_entity.id = entity.id; - id_manager.update(*new_entity); //new_entity.updateID(); + id_manager.update(*new_entity); uint j = 0; uint k = 0; @@ -2160,28 +2321,37 @@ export struct EntityManager foreach (id; new_info.components) //ids[0 .. len]) { - void* dst = cast(void*) new_block + new_info.deltas[id] + ( - new_block.entities_count) * components[id].size; uint size = components[id].size; + void* dst = void; + if (size != 0) + dst = cast(void*) new_block + new_info.deltas[id] + (new_block.entities_count) + * size; if (k >= new_ids.length) { - memcpy(dst, cast(void*) block + info.deltas[id] + ind * size, size); + if (size != 0) + memcpy(dst, cast(void*) block + info.deltas[id] + ind * size, size); j++; } else if (j >= info.components.length || id == new_ids[k]) { - memcpy(dst, data_pointers[k], size); + if (size != 0) + memcpy(dst, data_pointers[k], size); k++; } else { assert(id != new_ids[0]); - memcpy(dst, cast(void*) block + info.deltas[id] + ind * size, size); + if (size != 0) + memcpy(dst, cast(void*) block + info.deltas[id] + ind * size, size); j++; } } + new_block.entities_count++; + if (new_block != new_info.update_block) + new_info.update_block = new_block; + if (new_info.add_listeners) { foreach (listener; new_info.add_listeners) @@ -2189,7 +2359,7 @@ export struct EntityManager if (!info.systems[listener]) { callAddEntityListener(&systems[listener], new_info, new_block, - new_block.entities_count, new_block.entities_count + 1); + new_block.entities_count - 1, new_block.entities_count); } } } @@ -2201,12 +2371,11 @@ export struct EntityManager if (info.systems[listener]) { callChangeEntityListener(&systems[listener], new_info, new_block, - new_block.entities_count, new_block.entities_count + 1, new_ids); + new_block.entities_count - 1, new_block.entities_count, new_ids); } } } - new_block.entities_count++; removeEntityNoID(entity, block); } @@ -2220,12 +2389,7 @@ export struct EntityManager void addComponents(Components...)(const EntityID entity_id, Components comps) nothrow @nogc { const uint num = Components.length; - //Entity* entity = id_manager.getEntityPointer(entity_id); - //EntitiesBlock* block = getMetaData(entity); - //EntityInfo* info = block.type_info; - /*ushort[] ids = (cast(ushort*) alloca(ushort.sizeof * (info.components.length + num)))[0 - .. info.components.length + num];*/ - ushort[num] new_ids; + /*ushort[num] new_ids; static foreach (i, comp; Components) { @@ -2233,16 +2397,48 @@ export struct EntityManager } ThreadData* data = &threads[threadID]; - data.change_entities_list.add(cast(ubyte) 1u); - data.change_entities_list.add((cast(ubyte*)&entity_id)[0 .. EntityID.sizeof]); - data.change_entities_list.add((cast(ubyte*)&num)[0 .. uint.sizeof]); - data.change_entities_list.add(cast(ubyte[]) new_ids); + data.changeEntitiesList.add(cast(ubyte) 1u); + data.changeEntitiesList.add((cast(ubyte*)&entity_id)[0 .. EntityID.sizeof]); + data.changeEntitiesList.add((cast(ubyte*)&num)[0 .. uint.sizeof]); + data.changeEntitiesList.add(cast(ubyte[]) new_ids); static foreach (i, comp; comps) { - data.change_entities_list.add((cast(ubyte*)&comp)[0 .. comp.sizeof]); - } + data.changeEntitiesList.add((cast(ubyte*)&comp)[0 .. comp.sizeof]); + }*/ //__addComponents(entity_id, new_ids, pointers); + + ComponentRef[num] _comps; + static foreach (i, comp; comps) + { + _comps[i] = comp.ref_; + } + addComponents(entity_id, _comps); + + } + + export void addComponents(const EntityID entity_id, ComponentRef[] comps) nothrow @nogc + { + uint num = cast(uint) comps.length; + ThreadData* data = &threads[threadID]; + data.changeEntitiesList.add(cast(ubyte) 1u); + data.changeEntitiesList.add((cast(ubyte*)&entity_id)[0 .. EntityID.sizeof]); + data.changeEntitiesList.add((cast(ubyte*)&num)[0 .. uint.sizeof]); + foreach (ref_; comps) + { + data.changeEntitiesList.add((cast(ubyte*)&ref_.component_id)[0 .. ushort.sizeof]); + } + foreach (ref_; comps) + { + if (components[ref_.component_id].size != 0) + data.changeEntitiesList.add( + (cast(ubyte*) ref_.ptr)[0 .. components[ref_.component_id].size]); + } + /*data.changeEntitiesList.add(cast(ubyte[]) new_ids); + static foreach (i, comp; comps) + { + data.changeEntitiesList.add((cast(ubyte*)&comp)[0 .. comp.sizeof]); + }*/ } /************************************************************************************************************************ @@ -2251,7 +2447,7 @@ export struct EntityManager Params: template_ = pointer entity template allocated by EntityManager. */ - export void freeTemplate(EntityTemplate* template_) + export void freeTemplate(EntityTemplate* template_) @nogc nothrow { Mallocator.dispose(template_.entity_data); Mallocator.dispose(template_); @@ -2288,25 +2484,24 @@ export struct EntityManager foreach (i, comp; info.components) { - memcpy(cast(void*) new_block + info.deltas[comp] + components[comp].size * new_id, - cast(void*) block + info.deltas[comp] + components[comp].size * index, - components[comp].size); + ushort size = components[comp].size; + if (size != 0) + memcpy(cast(void*) new_block + info.deltas[comp] + size * new_id, + cast(void*) block + info.deltas[comp] + size * index, size); if (components[comp].create_callback) { - components[comp].create_callback(cast( - void*) block + info.deltas[comp] + new_id * components[comp].size); + components[comp].create_callback( + cast(void*) block + info.deltas[comp] + new_id * size); } } - if (new_index == 1) - threads[threadID].blocks_to_update.add(new_block); + if (new_index == 1 && info.update_block == block) + threads[threadID].infosToUpdate.add(info); Entity* new_entity = cast(Entity*) start; - //add_mutex.lock_nothrow(); new_entity.id = id_manager.getNewID(); - //add_mutex.unlock_nothrow(); - id_manager.update(*new_entity); //new_entity.updateID(); + id_manager.update(*new_entity); return new_entity; } @@ -2319,6 +2514,56 @@ export struct EntityManager tmpl = pointer entity template allocated by EntityManager. */ export Entity* addEntity(EntityTemplate* tmpl) + { + /*EntityInfo* info = tmpl.info; + + ushort index = 0; + EntitiesBlock* block; + do + { + block = findBlockWithFreeSpaceMT(info); + index = block.added_count.atomicOp!"+="(1); + } + while (block.entities_count + index > info.max_entities); + + uint id = (block.entities_count + index - 1); //block.added_count); + + void* data_begin = block.dataBegin(); + void* start = data_begin + EntityID.sizeof * id; + + foreach (comp; info.components) + { + memcpy(cast(void*) block + info.deltas[comp] + components[comp].size * id, + tmpl.entity_data.ptr + info.tmpl_deltas[comp], components[comp].size); + + if (components[comp].create_callback) + { + components[comp].create_callback( + cast(void*) block + info.deltas[comp] + id * components[comp].size); + } + + } + + if (index == 1) + threads[threadID].infosToUpdate.add(block); + + Entity* entity = cast(Entity*) start; + entity.id = id_manager.getNewID(); + id_manager.update(*entity); //entity.updateID(); + + return entity;*/ + return addEntity(tmpl, null); + } + + /************************************************************************************************************************ + Add entity to system. Returen pointer is valid only before one from commit(), begin() or end() will be called. To save entity to further + use you should save ID instead of pointer. + + Params: + tmpl = pointer entity template allocated by EntityManager. + replacement = list of components references to used. Memory form list replace data from template inside new entity. Should be used only for data which vary between most entities (like 3D position etc.) + */ + export Entity* addEntity(EntityTemplate* tmpl, ComponentRef[] replacement) { EntityInfo* info = tmpl.info; @@ -2336,27 +2581,43 @@ export struct EntityManager void* data_begin = block.dataBegin(); void* start = data_begin + EntityID.sizeof * id; + foreach (comp; info.components) + { + uint size = components[comp].size; + if (size != 0) + memcpy(cast(void*) block + info.deltas[comp] + size * id, + tmpl.entity_data.ptr + info.tmpl_deltas[comp], size); + } + + foreach (comp; replacement) + { + if (comp.component_id < info.deltas.length) + { + ushort delta = info.deltas[comp.component_id]; + if (delta != 0) + { + uint size = components[comp.component_id].size; + if (size != 0) + memcpy(cast(void*) block + delta + size * id, comp.ptr, size); + } + } + } + foreach (i, comp; info.components) { - memcpy(cast(void*) block + info.deltas[comp] + components[comp].size * id, - tmpl.entity_data.ptr + info.tmpl_deltas[comp], components[comp].size); - if (components[comp].create_callback) { components[comp].create_callback( cast(void*) block + info.deltas[comp] + id * components[comp].size); } - } - if (index == 1) - threads[threadID].blocks_to_update.add(block); + if (index == 1 && info.update_block == block) + threads[threadID].infosToUpdate.add(info); Entity* entity = cast(Entity*) start; - //add_mutex.lock_nothrow(); entity.id = id_manager.getNewID(); - //add_mutex.unlock_nothrow(); - id_manager.update(*entity); //entity.updateID(); + id_manager.update(*entity); return entity; } @@ -2375,6 +2636,7 @@ export struct EntityManager block.id = 0; info.first_block = block; info.last_block = block; + info.update_block = block; } else if (block.entities_count >= info.max_entities) { @@ -2385,6 +2647,12 @@ export struct EntityManager new_block.id = cast(ushort)(block.id + 1); block = new_block; info.last_block = block; + ///make sure that update_block point to unfilled block + if (info.update_block.entities_count == info.max_entities) + { + assert(!info.update_block.added_count); + info.update_block = block; + } } return block; } @@ -2410,8 +2678,9 @@ export struct EntityManager block.id = 0; info.first_block = block; info.last_block = block; + info.update_block = block; } - else if (block.entities_count + block.added_count > info.max_entities) + else if (block.entities_count + block.added_count >= info.max_entities) { EntitiesBlock* last_block = info.last_block; @@ -2429,6 +2698,12 @@ export struct EntityManager new_block.id = cast(ushort)(block.id + 1); block = new_block; info.last_block = block; + ///make sure that update_block point to unfilled block + if (info.update_block.entities_count == info.max_entities) + { + assert(!info.update_block.added_count); + info.update_block = block; + } } return block; } @@ -2441,15 +2716,17 @@ export struct EntityManager */ export void removeEntity(EntityID id) { - threads[threadID].entities_to_remove.add(id); + threads[threadID].entitesToRemove.add(id); } private void __removeEntity(EntityID id) nothrow @nogc { //get entity and block meta data pointers Entity* entity = id_manager.getEntityPointer(id); + if (entity is null) return; //return if entity doesn't exist + EntitiesBlock* block = getMetaData(entity); EntityInfo* info = block.type_info; @@ -2470,6 +2747,11 @@ export struct EntityManager { EntityInfo* info = block.type_info; + updateEntityInfoBlocks(info); + + assert(info.last_block.added_count == 0); + assert(info.last_block.entities_count > 0); + info.last_block.entities_count--; uint pos = block.entityIndex(entity); @@ -2490,21 +2772,24 @@ export struct EntityManager { foreach (comp; info.components) { + uint size = components[comp].size; + if (size == 0) + continue; void* src = cast(void*) info.last_block + info.deltas[comp]; void* dst = cast(void*) block + info.deltas[comp]; - uint size = components[comp].size; memcpy(dst + pos * size, src + info.last_block.entities_count * size, size); } block = info.last_block; entity.id = *cast(EntityID*)(block.dataBegin() + block.entities_count * EntityID.sizeof); - id_manager.update(*entity); //entity.updateID(); + id_manager.update(*entity); } block = info.last_block; if (block.entities_count == 0) { + assert(info.update_block is block); info.last_block = block.prev_block; if (info.first_block is block) { @@ -2513,7 +2798,9 @@ export struct EntityManager if (block.prev_block) { block.prev_block.next_block = null; - block.prev_block.added_count = 0; + info.update_block = block.prev_block; + assert(block.prev_block.added_count == 0); + //block.prev_block.added_count.atomicStore(cast(ushort)0); } allocator.freeBlock(block); } @@ -2530,47 +2817,52 @@ export struct EntityManager return cast(EntitiesBlock*)(cast(size_t) pointer & (~cast(size_t)(m_page_size - 1))); } - private void changeEntities() + private bool changeEntities() { - foreach (ref thread; threads) + bool has_work = false; + //foreach (ref ThreadData thread; threads)thread.swapToChange(); + foreach (ref ThreadData thread; threads) { uint index = 0; - uint len = cast(uint) thread.change_entities_list.length; + uint len = cast(uint) thread.changeEntitiesListPrev.length; + if (len) + has_work = true; void*[32] pointers; // = (cast(void**) alloca(num * (void*).sizeof))[0 .. num]; while (index < len) { - if (!thread.change_entities_list[index++]) + if (!thread.changeEntitiesListPrev[index++]) { - EntityID id = *cast(EntityID*)&thread.change_entities_list[index]; + EntityID id = *cast(EntityID*)&thread.changeEntitiesListPrev[index]; index += EntityID.sizeof; - uint num = *cast(uint*)&thread.change_entities_list[index]; + uint num = *cast(uint*)&thread.changeEntitiesListPrev[index]; index += uint.sizeof; ushort[] ids; // = (cast(ushort*) alloca(num * ushort.sizeof))[0 .. num]; - ids = (cast(ushort*)&thread.change_entities_list[index])[0 .. num]; + ids = (cast(ushort*)&thread.changeEntitiesListPrev[index])[0 .. num]; index += ushort.sizeof * num; __removeComponents(id, ids); } else { - EntityID id = *cast(EntityID*)&thread.change_entities_list[index]; + EntityID id = *cast(EntityID*)&thread.changeEntitiesListPrev[index]; index += EntityID.sizeof; - uint num = *cast(uint*)&thread.change_entities_list[index]; + uint num = *cast(uint*)&thread.changeEntitiesListPrev[index]; index += uint.sizeof; ushort[] ids; // = (cast(ushort*) alloca(num * ushort.sizeof))[0 .. num]; - ids = (cast(ushort*)&thread.change_entities_list[index])[0 .. num]; + ids = (cast(ushort*)&thread.changeEntitiesListPrev[index])[0 .. num]; index += ushort.sizeof * num; //void*[] pointers = (cast(void**) alloca(num * (void*).sizeof))[0 .. num]; foreach (i; 0 .. num) { - pointers[i] = &thread.change_entities_list[index]; + pointers[i] = &thread.changeEntitiesListPrev[index]; index += components[ids[i]].size; } - + __addComponents(id, ids, pointers[0 .. num]); } } - thread.change_entities_list.clear(); + thread.changeEntitiesListPrev.clear(); } + return has_work; } private void callAddEntityListeners(EntityInfo* info, EntitiesBlock* block, int begin, int end) @nogc nothrow @@ -2582,7 +2874,7 @@ export struct EntityManager } } - private void callAddEntityListener(System* system, EntityInfo* info, + private static void callAddEntityListener(System* system, EntityInfo* info, EntitiesBlock* block, int begin, int end) @nogc nothrow { ListenerCallData data; @@ -2603,8 +2895,8 @@ export struct EntityManager } } - private void callRemoveEntityListener(System* system, EntityInfo* info, - EntitiesBlock* block, int begin, int end) @nogc nothrow + private static void callRemoveEntityListener(System* system, + EntityInfo* info, EntitiesBlock* block, int begin, int end) @nogc nothrow { ListenerCallData data; data.system = system; @@ -2651,108 +2943,173 @@ export struct EntityManager (cast(void function(ref ListenerCallData) nothrow @nogc) system.m_change_entity)(data); } - private void updateBlocks() + private void updateEntityInfoBlocks(EntityInfo* info) nothrow @nogc { - foreach (ref thread; threads) + while (info.last_block.added_count) { - foreach (block; thread.blocks_to_update) + EntitiesBlock* block = info.update_block; + assert(block !is null); + if (block.entities_count == info.max_entities) { - EntityInfo* info = block.type_info; - ushort entities_count = block.entities_count; - block.entities_count += block.added_count; - if (block.entities_count > block.type_info.max_entities) - { - block.entities_count = block.type_info.max_entities; - } - block.added_count.atomicStore(cast(ushort) 0); - - if (info.add_listeners) - { - callAddEntityListeners(info, block, entities_count, block.entities_count); - } - + assert(!block.added_count); + block = block.next_block; } - thread.blocks_to_update.clear(); + assert(!block.prev_block || !block.prev_block.added_count); + info.update_block = info.last_block; + + while (block) + { + assert(block.added_count.atomicLoad() > 0); + updateBlock(block); + block = block.next_block; + } + } + assert(info.last_block is info.update_block); + } + + private void updateBlock(EntitiesBlock* block) @nogc nothrow + { + //if(block.added_count == 0)return; + assert(block.added_count != 0); + EntityInfo* info = block.type_info; + ushort entities_count = block.entities_count; + block.entities_count += block.added_count; + if (block.entities_count > block.type_info.max_entities) + { + block.entities_count = block.type_info.max_entities; + } + block.added_count.atomicStore(cast(ushort) 0); + + if (info.add_listeners) + { + callAddEntityListeners(info, block, entities_count, block.entities_count); } } - private void removeEntities() nothrow @nogc + private bool updateBlocks() { - foreach (i, ref thread; threads) + bool has_work = false; + foreach (ref ThreadData thread; threads) { - foreach (id; thread.entities_to_remove) + if (thread.infosToUpdatePrev.length) + has_work = true; + foreach (info; thread.infosToUpdatePrev) + { + updateEntityInfoBlocks(info); + } + thread.infosToUpdatePrev.clear(); + } + return has_work; + } + + private bool removeEntities() nothrow @nogc + { + bool has_work = false; + //foreach (ref ThreadData thread; threads)thread.swapToRemove(); + foreach (ref ThreadData thread; threads) + { + if (thread.entitiesToRemovePrev.length) + has_work = true; + foreach (id; thread.entitiesToRemovePrev) { __removeEntity(id); } - thread.entities_to_remove.clear(); + thread.entitiesToRemovePrev.clear(); } + return has_work; } - private void updateEvents() nothrow @nogc + private bool updateEvents() nothrow @nogc { - bool empty = true; - while (1) + bool has_work = false; + // bool empty = true; + //while (1) + //{ + //event_manager.swapCurrent(); + uint current_index; + if (event_manager.current_index == 0) + current_index = cast(uint) threads.length; + else + current_index = 0; + foreach (i, event; event_manager.events) { - event_manager.swapCurrent(); - uint current_index; - if (event_manager.current_index == 0) - current_index = cast(uint) threads.length; - else - current_index = 0; - foreach (i, event; event_manager.events) + foreach (first_block; event.first_blocks[current_index .. current_index + threads + .length]) { - foreach (first_block; event.first_blocks[current_index - .. current_index + threads.length]) + EventManager.EventBlock* block = first_block; + if (block) + has_work = true; + // { + // has_work = true; + // //empty = false; + // } + while (block) { - EventManager.EventBlock* block = first_block; - if (block) - empty = false; - while (block) + EventCallData call_data; + void* event_pointer = cast(void*) block + event.data_offset; + foreach (j; 0 .. block.count) { - EventCallData call_data; - void* event_pointer = cast(void*) block + event.data_offset; - foreach (j; 0 .. block.count) + call_data.event = event_pointer + EntityID.sizeof; + EntityID entity_id = *cast(EntityID*)(event_pointer); + Entity* entity = id_manager.getEntityPointer(entity_id); + if (entity) { - call_data.event = event_pointer; - EntityID entity_id = *cast(EntityID*) event_pointer; - Entity* entity = id_manager.getEntityPointer(entity_id); - if (entity) - { - call_data.block = getMetaData(entity); - call_data.id = call_data.block.entityIndex(entity); + call_data.block = getMetaData(entity); + call_data.id = call_data.block.entityIndex(entity); + call_data.entity = entity; - foreach (caller; events[i].callers) - { - if ( - call_data.block.type_info.systems[caller.system.m_id] - == false) - continue; - call_data.system_pointer = caller.system.m_system_pointer; - (cast(void function( - ref EventCallData) nothrow @nogc) caller.callback)( - call_data); - } + foreach (caller; events[i].callers) + { + if (call_data.block.type_info.systems[caller.system.m_id] == false + || !caller.system.enabled || !caller.system.willExecute) + continue; + call_data.system_pointer = caller.system.m_system_pointer; + (cast(void function(ref EventCallData) nothrow @nogc) caller + .callback)(call_data); } - if(events[i].destroy_callback)events[i].destroy_callback(event_pointer); - event_pointer += events[i].size; } - block = block.next; + if (events[i].destroy_callback) + events[i].destroy_callback(event_pointer); + event_pointer += events[i].size + EntityID.sizeof; } + block = block.next; } } - if (empty) - break; - empty = true; + } + // if (empty) + // break; + // empty = true; + //} + return has_work; + } + + private void swapData() nothrow @nogc + { + event_manager.swapCurrent(); + foreach (ref ThreadData thread; threads) + { + thread.swapData(); } } export void commit() { - id_manager.optimize(); - updateBlocks(); - changeEntities(); - updateEvents(); - removeEntities(); + bool has_work = true; + while (has_work) + { + swapData(); + + has_work = false; + // has_work |= updateBlocks(); + // has_work |= changeEntities(); + // has_work |= removeEntities(); + has_work |= updateEvents(); + + //id_manager.optimize(); + has_work |= updateBlocks(); + has_work |= changeEntities(); + has_work |= removeEntities(); + } event_manager.clearEvents(); } @@ -2820,13 +3177,16 @@ export struct EntityManager foreach (caller; pass.system_callers) { index = 0; + ///gets systems which are excluding each other out_for: foreach (caller2; pass.system_callers) { if (caller is caller2) continue; - foreach (cmp; caller.system.m_read_only_components) + + ///check for external dependencies + foreach (cmp; caller.system.m_readonly_dependencies) { - foreach (cmp2; caller2.system.m_modified_components) + foreach (cmp2; caller2.system.m_writable_dependencies) { if (cmp == cmp2) { @@ -2835,7 +3195,39 @@ export struct EntityManager } } } - foreach (cmp; caller.system.m_modified_components) + foreach (cmp; caller.system.m_writable_dependencies) + { + foreach (cmp2; caller2.system.m_readonly_dependencies) + { + if (cmp == cmp2) + { + exclusion[index++] = caller2; + continue out_for; + } + } + foreach (cmp2; caller2.system.m_writable_dependencies) + { + if (cmp == cmp2) + { + exclusion[index++] = caller2; + continue out_for; + } + } + } + + ///check for component dependencies + foreach (cmp; caller.system.m_read_only_components) + { + foreach (cmp2; caller2.system.m_writable_components) + { + if (cmp == cmp2) + { + exclusion[index++] = caller2; + continue out_for; + } + } + } + foreach (cmp; caller.system.m_writable_components) { foreach (cmp2; caller2.system.m_read_only_components) { @@ -2845,7 +3237,7 @@ export struct EntityManager continue out_for; } } - foreach (cmp2; caller2.system.m_modified_components) + foreach (cmp2; caller2.system.m_writable_components) { if (cmp == cmp2) { @@ -2923,6 +3315,19 @@ export struct EntityManager } } + const(UpdatePass)* getPass(const(char)[] name) + { + ushort id = getPassID(name); + if (id == ushort.max) + return null; + return passes[id]; + } + + ushort getPassID(const(char)[] name) + { + return passes_map.get(name, ushort.max); + } + /************************************************************************************************************************ Component info; */ @@ -2956,6 +3361,7 @@ export struct EntityManager EntitiesBlock* block; void* system_pointer; void* event; + Entity* entity; ushort id; } @@ -3046,9 +3452,9 @@ export struct EntityManager return new_info; } - EntityInfo* getNewInfoRemove(ushort id) + EntityInfo* getNewInfoRemove(ushort id) return { - if (comp_rem_info.length <= id) + /*if (comp_rem_info.length <= id) { EntityInfo*[] new_infos = Mallocator.makeArray!(EntityInfo*)( instance.components.length, &this); @@ -3060,7 +3466,7 @@ export struct EntityManager Mallocator.dispose(comp_rem_info); } comp_rem_info = new_infos; - } + }*/ if (comp_rem_info[id]) return comp_rem_info[id]; @@ -3075,8 +3481,9 @@ export struct EntityManager ids[len++] = comp; } } - if (len == components.length) - return &this; + assert(len != components.length); + //if (len == components.length) + // return &this; assert(len == components.length - 1); @@ -3118,7 +3525,7 @@ export struct EntityManager EntityInfo*[] comp_rem_info; ///alignment of whole entity - ushort alignment; //unused in linear-layout + ushort alignment; //unused in linear-layout TODO: to remove ///size of entity (with alignment respect) ushort size; ///max number of entities in block @@ -3137,6 +3544,8 @@ export struct EntityManager EntitiesBlock* first_block; ///pointer to last block EntitiesBlock* last_block; + ///pointer to last updated block + EntitiesBlock* update_block; } /************************************************************************************************************************ @@ -3144,23 +3553,14 @@ export struct EntityManager */ struct EntitiesBlock { - ///return distance (in bytes) from begin of block to data - ///TODO: probably to remove. It's used by old code if I remeber correctly. - /*export uint dataDelta() nothrow @nogc pure - { - ushort dif = EntitiesBlock.sizeof; - alignNum(dif, type_info.alignment); - return dif; - }*/ - ///return pointer to first element in block - export void* dataBegin() nothrow @nogc pure + export void* dataBegin() nothrow @nogc pure return { ushort dif = EntitiesBlock.sizeof; return cast(void*)&this + dif; } - export ushort entityIndex(Entity* entity) nothrow @nogc pure + export ushort entityIndex(const(Entity)* entity) nothrow @nogc pure { static if (EntityID.sizeof == 8) return cast(ushort)((cast(void*) entity - dataBegin()) >> 3); @@ -3218,6 +3618,8 @@ export struct EntityManager ushort end; ///current thread index uint thread_id; + //current job index + uint job_id; } struct ListenerCallData @@ -3231,6 +3633,7 @@ export struct EntityManager struct Job { CallData[] callers; + uint id; export void execute() nothrow @nogc { @@ -3238,6 +3641,7 @@ export struct EntityManager foreach (ref caller; callers) { caller.thread_id = EntityManager.instance.threadID(); + caller.job_id = id; caller.update(); } } @@ -3278,10 +3682,48 @@ export struct EntityManager struct ThreadData { - Vector!EntityID entities_to_remove; - //Vector!ubyte change_entities_list; - SimpleVector change_entities_list; - Vector!(EntitiesBlock*) blocks_to_update; + ref Vector!EntityID entitesToRemove() @nogc nothrow return + { + return entities_to_remove[data_index]; + } + + ref SimpleVector changeEntitiesList() @nogc nothrow return + { + return change_entities_list[data_index]; + } + + ref Vector!(EntityInfo*) infosToUpdate() @nogc nothrow return + { + return infos_to_update[data_index]; + } + + ref Vector!EntityID entitiesToRemovePrev() @nogc nothrow return + { + return entities_to_remove[1 - data_index]; + } + + ref SimpleVector changeEntitiesListPrev() @nogc nothrow return + { + return change_entities_list[1 - data_index]; + } + + ref Vector!(EntityInfo*) infosToUpdatePrev() @nogc nothrow return + { + return infos_to_update[1 - data_index]; + } + + private: + + void swapData() @nogc nothrow + { + data_index = cast(ubyte)(1 - data_index); + } + + Vector!EntityID[2] entities_to_remove; + SimpleVector[2] change_entities_list; + Vector!(EntityInfo*)[2] infos_to_update; + + ubyte data_index = 0; } export struct UpdatePass @@ -3350,6 +3792,7 @@ export struct EntityManager HashMap!(char[], ushort) components_map; HashMap!(const(char)[], ushort) events_map; HashMap!(const(char)[], ushort) passes_map; + HashMap!(const(char)[], ushort) external_dependencies_map; Vector!System systems; Vector!ComponentInfo components; Vector!EventInfo events; diff --git a/source/bubel/ecs/package.d b/source/bubel/ecs/package.d new file mode 100644 index 0000000..51da325 --- /dev/null +++ b/source/bubel/ecs/package.d @@ -0,0 +1,10 @@ +module ecs; + +public import bubel.ecs.core; +public import bubel.ecs.entity; +public import bubel.ecs.manager; +public import bubel.ecs.system; + +import bubel.ecs.events; +import bubel.ecs.id_manager; +import bubel.ecs.std; diff --git a/source/bubel/ecs/simple_vector.d b/source/bubel/ecs/simple_vector.d new file mode 100644 index 0000000..bb4b610 --- /dev/null +++ b/source/bubel/ecs/simple_vector.d @@ -0,0 +1,77 @@ +module bubel.ecs.simple_vector; + +import bubel.ecs.std; + +//import core.stdc.string; + +/************************************************************************************************************************ +Vector for byte data. Simpler than standard template-based implementation designed for better performance. \ +Rellocates 1024 elements at once instead of doubling size. +*/ +struct SimpleVector +{ + + @disable this(this); + + ///Add element to vector + void add(ubyte el) nothrow @nogc + { + while (used >= data.length) + { + if (data is null) + data = Mallocator.makeArray!ubyte(1024); + else + data = Mallocator.expandArray(data, data.length); + } + data[used++] = el; + } + + ///Add array of elements to vector + void add(ubyte[] el) nothrow @nogc + { + while (used + el.length >= data.length) + { + if (data is null) + data = Mallocator.makeArray!ubyte(1024); + else + data = Mallocator.expandArray(data, data.length); + } + memcpy(data.ptr + used, el.ptr, el.length); + used += el.length; + } + + ///Return vector length + size_t length() nothrow @nogc + { + return used; + } + + export ref ubyte opIndex(size_t pos) nothrow @nogc + { + return data[pos]; + } + + export ubyte[] opSlice() nothrow @nogc + { + return data[0 .. used]; + } + + export ubyte[] opSlice(size_t x, size_t y) nothrow @nogc + { + return data[x .. y]; + } + + export size_t opDollar() nothrow @nogc + { + return used; + } + + ///set vector length to 0 + void clear() nothrow @nogc + { + used = 0; + } + + ubyte[] data = null; + size_t used = 0; +} diff --git a/source/bubel/ecs/std.d b/source/bubel/ecs/std.d new file mode 100644 index 0000000..a7dd846 --- /dev/null +++ b/source/bubel/ecs/std.d @@ -0,0 +1,363 @@ +/************************************************************************************************************************ +It's internal code! +This module contain implementation of standard functionality. + +Copyright: Copyright © 2018-2019, Dawid Masiukiewicz, Michał Masiukiewicz +License: BSD 3-clause, see LICENSE file in project root folder. +*/ +module bubel.ecs.std; + +version (Emscripten) version = ECSEmscripten; + +import std.traits; + +version (ECSEmscripten) +{ + extern (C) struct pthread_mutex_t + { + union + { + int[6] __i; + void[6]* __p; + } + } + + extern (C) struct pthread_mutexattr_t + { + uint __attr; + } + + extern (C) int memcmp(const void* s1, const void* s2, size_t size); + extern (C) void exit(int status) nothrow @nogc; + extern (C) void __assert(const(char)* msg, const(char)* file, uint line) + { + exit(-20); + } + + extern (C) void free(void*) @nogc nothrow @system; + extern (C) void* malloc(size_t size) @nogc nothrow @system; + extern (C) void* realloc(void*, size_t size) @nogc nothrow @system; + extern (C) void* memcpy(return void*, scope const void*, size_t size) @nogc nothrow @system; + extern (C) void* memset(void*, int val, size_t size) @nogc nothrow @system; + extern (C) int posix_memalign(void**, size_t, size_t) @nogc nothrow @system; + extern (C) void qsort(void* base, size_t num, size_t size, + int function(const void*, const void*) compar) @nogc nothrow @system; + + extern (C) int pthread_mutex_lock(pthread_mutex_t* mutex) @nogc nothrow; + extern (C) int pthread_mutex_trylock(pthread_mutex_t* mutex) @nogc nothrow; + extern (C) int pthread_mutex_unlock(pthread_mutex_t* mutex) @nogc nothrow; + extern (C) void pthread_mutexattr_settype(pthread_mutexattr_t* attr, int type) @nogc nothrow; + extern (C) void pthread_mutexattr_destroy(pthread_mutexattr_t* attr) @nogc nothrow; + extern (C) int pthread_mutexattr_init(pthread_mutexattr_t* attr) @nogc nothrow; + extern (C) int pthread_mutex_destroy(pthread_mutex_t* mutex) @nogc nothrow; + extern (C) int pthread_mutex_init(pthread_mutex_t* mutex, const pthread_mutexattr_t* attr) @nogc nothrow; + +} +else +{ + public import core.stdc.stdlib : malloc, free, realloc; + public import core.stdc.string : memcpy, memset; + public import core.stdc.stdlib : qsort; +} + +version (ECSEmscripten) +{ +} +else version (Windows) +{ + import core.sys.windows.windows; + + extern (Windows) void* _aligned_malloc(size_t size, size_t alignment) @nogc nothrow @system; + extern (Windows) void _aligned_free(void* ptr) @nogc nothrow @system; + + version (LDC) + { + /*extern(Windows) void* __alloca(size_t size) @nogc nothrow @system; + alias alloca = __alloca;*/ + + extern (Windows) void ___chkstk_ms() @nogc nothrow @system; + + extern (Windows) void __chkstk() + { + ___chkstk_ms(); + } + } +} +else version (Posix) +{ + import core.sys.posix.pthread; + import core.sys.posix.stdlib : posix_memalign; +} + +version (ECSEmscripten) +{ + private const uint max_alloca = 10000; + private __gshared byte[max_alloca] alloca_array; + private __gshared uint alloca_pos = 0; + export extern (C) void* alloca(size_t length) @nogc nothrow + { + if (alloca_pos + length > max_alloca) + alloca_pos = 0; + void* ret = &alloca_array[alloca_pos]; + alloca_pos += length; + return ret; + } + //extern(C) void* alloca(size_t size) @nogc nothrow; + /*export extern(C) void* alloca(size_t length) @nogc nothrow + { + return null; + }*/ +} +else version (D_BetterC) +{ + private const uint max_alloca = 10000; + private __gshared byte[max_alloca] alloca_array; + private uint alloca_pos = 0; + export extern (C) void* __alloca(size_t length) @nogc nothrow + { + if (alloca_pos + length > max_alloca) + alloca_pos = 0; + void* ret = &alloca_array[alloca_pos]; + alloca_pos += length; + return ret; + } + + alias alloca = __alloca; + + version (DigitalMars) + { + export extern (C) float* _memsetFloat(float* p, float value, size_t count) @nogc nothrow + { + float* pstart = p; + float* ptop; + + for (ptop = &p[count]; p < ptop; p++) + *p = value; + return pstart; + } + } + + version (GNU) + { + extern (C) void __gdc_personality_v0() + { + + } + } +} +else +{ + public import core.stdc.stdlib : alloca; +} + +static struct Mallocator +{ + static T[] makeArray(T)(size_t length) nothrow @nogc + { + T[] ret = (cast(T*) malloc(T.sizeof * length))[0 .. length]; + + static if (__traits(isPOD, T)) + { + static immutable T init = T.init; + + foreach (i; 0 .. ret.length) + { + memcpy(&ret[i], &init, T.sizeof); + } + } + else + { + static import std.conv; + + foreach (i; 0 .. ret.length) + { + std.conv.emplace(&ret[i]); + } + } + return ret; + } + + static T[] makeArray(T)(size_t length, T initializer) nothrow @nogc + { + T[] ret = (cast(T*) malloc(T.sizeof * length))[0 .. length]; + foreach (ref v; ret) + v = initializer; + return ret; + } + + static T[] expandArray(T)(T[] array, size_t length) nothrow @nogc + { + size_t new_length = array.length + length; + return (cast(T*) realloc(array.ptr, T.sizeof * new_length))[0 .. new_length]; + } + + static T[] makeArray(T)(T[] array) nothrow @nogc + { + T[] ret = (cast(T*) malloc(T.sizeof * array.length))[0 .. array.length]; //Mallocator.makeArray!(T)(array.length); + foreach (i, ref v; ret) + v = array[i]; + return ret; + } + + static T* make(T, Args...)(Args args) + { + T* ret = cast(T*) malloc(T.sizeof); + static import std.conv; + + static if (__traits(isPOD, T)) + { + static immutable T init = T.init; + memcpy(ret, &init, T.sizeof); + } + else static if (is(T == struct)) + std.conv.emplace(ret, args); + return ret; + } + + static void* alignAlloc(size_t length, size_t alignment) nothrow @nogc + { + void* ret; + version (Posix) + posix_memalign(&ret, alignment, length); //ret = aligned_alloc(alignment, length); + else version (Windows) + ret = _aligned_malloc(length, alignment); + else version (ECSEmscripten) + posix_memalign(&ret, alignment, length); //malloc(length); + else + static assert(0, "Unimplemented platform!"); + return ret; + } + + static void dispose(T)(T object) nothrow @nogc + { + static if (__traits(hasMember, T, "__xdtor")) + object.__xdtor(); + else static if (__traits(hasMember, T, "__dtor")) + object.__dtor(); + free(cast(void*) object); + } + + static void alignDispose(T)(T object) + { + static if (__traits(hasMember, T, "__xdtor")) + object.__xdtor(); + else static if (__traits(hasMember, T, "__dtor")) + object.__dtor(); + version (Posix) + free(cast(void*) object); + else version (Windows) + _aligned_free(cast(void*) object); + else version (ECSEmscripten) + free(cast(void*) object); + else + static assert(0, "Unimplemented platform!"); + } +} + +struct Mutex +{ + + version (ECSEmscripten) + { + void initialize() nothrow @nogc + { + pthread_mutexattr_t attr = void; + + //pthread_mutexattr_init(&attr); + + //pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); + pthread_mutex_init(cast(pthread_mutex_t*)&m_handle, &attr); + + //pthread_mutexattr_destroy(&attr); + } + + void destroy() nothrow @nogc + { + pthread_mutex_destroy(&m_handle); + } + + void lock() nothrow @nogc + { + pthread_mutex_lock(&m_handle); + } + + void unlock() nothrow @nogc + { + pthread_mutex_unlock(&m_handle); + } + + int tryLock() nothrow @nogc + { + return pthread_mutex_trylock(&m_handle) == 0; + } + + private pthread_mutex_t m_handle; + } + else version (Windows) + { + void initialize() nothrow @nogc + { + InitializeCriticalSection(cast(CRITICAL_SECTION*)&m_handle); + } + + void destroy() nothrow @nogc + { + DeleteCriticalSection(&m_handle); + } + + void lock() nothrow @nogc + { + EnterCriticalSection(&m_handle); + } + + void unlock() nothrow @nogc + { + LeaveCriticalSection(&m_handle); + } + + int tryLock() nothrow @nogc + { + return TryEnterCriticalSection(&m_handle) != 0; + } + + CRITICAL_SECTION m_handle; + } + else version (Posix) + { + void initialize() nothrow @nogc + { + pthread_mutexattr_t attr = void; + + pthread_mutexattr_init(&attr); + + pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); + pthread_mutex_init(cast(pthread_mutex_t*)&m_handle, &attr); + + pthread_mutexattr_destroy(&attr); + } + + void destroy() nothrow @nogc + { + pthread_mutex_destroy(&m_handle); + } + + void lock() nothrow @nogc + { + pthread_mutex_lock(&m_handle); + } + + void unlock() nothrow @nogc + { + pthread_mutex_unlock(&m_handle); + } + + int tryLock() nothrow @nogc + { + return pthread_mutex_trylock(&m_handle) == 0; + } + + private pthread_mutex_t m_handle; + } + else + static assert(0, "unsupported platform!"); +} diff --git a/source/ecs/system.d b/source/bubel/ecs/system.d similarity index 77% rename from source/ecs/system.d rename to source/bubel/ecs/system.d index 22a3955..7bcaf01 100644 --- a/source/ecs/system.d +++ b/source/bubel/ecs/system.d @@ -4,26 +4,26 @@ System module. Copyright: Copyright © 2018-2019, Dawid Masiukiewicz, Michał Masiukiewicz License: BSD 3-clause, see LICENSE file in project root folder. */ -module ecs.system; +module bubel.ecs.system; -import ecs.entity; -import ecs.manager; +import bubel.ecs.entity; +import bubel.ecs.manager; /************************************************************************************************************************ System contain data required to proper glue EntityManager with Systems. System callbacks: $(LIST * void onUpdate(EntitesData); - * void onEnable() - * void onDisable(); - * bool onBegin(); - * void onEnd(); - * void onCreate() - * void onDestroy(); - * void onAddEntity(EntitesData); - * void onRemoveEntity(EntitiesData); - * void onChangeEntity(EntitiesData); - * void handleEvent(Entity*, Event); + * void onEnable() - called inside system.enable() function + * void onDisable() - called inside system.disable() function + * bool onBegin() - called inside manager.begin() + * void onEnd() - called inside manager.end() + * void onCreate() - called after registration inside registerSystem function + * void onDestroy() - called during re-registration and inside manager destructor + * void onAddEntity(EntitesData) - called for every entity which are assigned to system (by adding new entity or changing its components) + * void onRemoveEntity(EntitiesData) - called for every entity removed from system update process + * void onChangeEntity(EntitiesData) - called for every entity which components are changed but it was previously assigned to system + * void handleEvent(Entity*, Event) - called for every event supported by system ) */ struct System @@ -66,15 +66,15 @@ struct System } /************************************************************************************************************************ - Get system priority. + Get if system will be executed during current frame. Should be checked after manager.begin(). Its value is setted as result of manager.onBegin() callback. */ - export bool execute() nothrow @nogc + export bool willExecute() nothrow @nogc { return m_execute; } /************************************************************************************************************************ - Get system priority. + Get system id. */ export ushort id() nothrow @nogc { @@ -127,7 +127,10 @@ package: //System*[] m_dependencies; ushort[] m_read_only_components; - ushort[] m_modified_components; + ushort[] m_writable_components; + + ushort[] m_readonly_dependencies; + ushort[] m_writable_dependencies; EntityManager.SystemCaller* m_any_system_caller; diff --git a/source/ecs/traits.d b/source/bubel/ecs/traits.d similarity index 97% rename from source/ecs/traits.d rename to source/bubel/ecs/traits.d index d19259f..7043b2e 100644 --- a/source/ecs/traits.d +++ b/source/bubel/ecs/traits.d @@ -1,4 +1,4 @@ -module ecs.traits; +module bubel.ecs.traits; import std.traits; diff --git a/source/ecs/vector.d b/source/bubel/ecs/vector.d similarity index 53% rename from source/ecs/vector.d rename to source/bubel/ecs/vector.d index 84ecc51..019673b 100644 --- a/source/ecs/vector.d +++ b/source/bubel/ecs/vector.d @@ -1,30 +1,36 @@ -module ecs.vector; +module bubel.ecs.vector; import core.bitop; + //import core.stdc.stdlib : free, malloc; -import ecs.std; +import bubel.ecs.std; + //import core.stdc.string : memcpy, memset; //import std.algorithm : swap; import std.conv : emplace; import std.traits : hasMember, isCopyable, TemplateOf, Unqual; -export @nogc @safe nothrow pure size_t nextPow2(size_t num) { +export @nogc @safe nothrow pure size_t nextPow2(size_t num) +{ return 1 << bsr(num) + 1; } export __gshared size_t gVectorsCreated = 0; export __gshared size_t gVectorsDestroyed = 0; -struct Vector(T) { +struct Vector(T) +{ T[] array; size_t used; public: - export this()(T t) { + export this()(T t) + { add(t); } - export this(X)(X[] t) if (is(Unqual!X == Unqual!T)) { + export this(X)(X[] t) if (is(Unqual!X == Unqual!T)) + { add(t); } @@ -42,76 +48,101 @@ public: @disable this(this); - export ~this() { + export ~this() + { clear(); } - export void clear() { + export void clear() + { removeAll(); } - export void removeAll() { - if (array !is null) { + export void removeAll() + { + if (array !is null) + { /*foreach (ref el; array[0 .. used]) { destroy(el); }*/ - freeData(cast(void[]) array); + //freeData(cast(void[]) array); + freeData((cast(void*) array.ptr)[0 .. array.length * T.sizeof]); gVectorsDestroyed++; } array = null; used = 0; } - export bool empty() { + export bool empty() const + { return (used == 0); } - export size_t length() { + export size_t length() const + { return used; } - export void length(size_t newLength) { - if (newLength > used) { + export void length(size_t newLength) + { + if (newLength > used) + { reserve(newLength); - foreach (ref el; array[used .. newLength]) { + foreach (ref el; array[used .. newLength]) + { emplace(&el); } - } else { - foreach (ref el; array[newLength .. used]) { - destroy(el); + } + else + { + foreach (ref el; array[newLength .. used]) + { + //destroy(el); + static if (__traits(hasMember, T, "__xdtor")) + el.__xdtor(); + else static if (__traits(hasMember, T, "__dtor")) + el.__dtor(); } } used = newLength; } - export void reset() { + export void reset() + { used = 0; } - export void reserve(size_t numElements) { - if (numElements > array.length) { + export void reserve(size_t numElements) + { + if (numElements > array.length) + { extend(numElements); } } - export size_t capacity() { + export size_t capacity() + { return array.length - used; } - export void extend(size_t newNumOfElements) { + export void extend(size_t newNumOfElements) + { auto oldArray = manualExtend(array, newNumOfElements); - if (oldArray !is null) { + if (oldArray !is null) + { freeData(oldArray); } } - export @nogc void freeData(void[] data) { + export @nogc void freeData(void[] data) + { // 0x0F probably invalid value for pointers and other types memset(data.ptr, 0x0F, data.length); // Makes bugs show up xD free(data.ptr); } - export static void[] manualExtend(ref T[] array, size_t newNumOfElements = 0) { + export static void[] manualExtend(ref T[] array, size_t newNumOfElements = 0) + { if (newNumOfElements == 0) newNumOfElements = 2; if (array.length == 0) @@ -122,22 +153,27 @@ public: T* memory = cast(T*) malloc(newSize); memcpy(cast(void*) memory, cast(void*) oldArray.ptr, oldSize); array = memory[0 .. newNumOfElements]; - return cast(void[]) oldArray; + //return cast(void[]) oldArray; + return (cast(void*) oldArray.ptr)[0 .. oldArray.length * T.sizeof]; } - export Vector!T copy()() { + export Vector!T copy()() + { Vector!T duplicate; duplicate.reserve(used); duplicate ~= array[0 .. used]; return duplicate; } - export bool canAddWithoutRealloc(uint elemNum = 1) { + /*export bool canAddWithoutRealloc(uint elemNum = 1) + { return used + elemNum <= array.length; - } + }*/ - export void add()(T t) { - if (used >= array.length) { + export void add()(T t) + { + if (used >= array.length) + { extend(nextPow2(used + 1)); } emplace(&array[used], t); @@ -145,46 +181,62 @@ public: } /// Add element at given position moving others - export void add()(T t, size_t pos) { + export void add()(T t, size_t pos) + { assert(pos <= used); - if (used >= array.length) { + if (used >= array.length) + { extend(array.length * 2); } - foreach_reverse (size_t i; pos .. used) { + foreach_reverse (size_t i; pos .. used) + { //swap(array[i + 1], array[i]); - array[i+1] = array[i]; + array[i + 1] = array[i]; } emplace(&array[pos], t); used++; } - export void add(X)(X[] t) if (is(Unqual!X == Unqual!T)) { - if (used + t.length > array.length) { + export void add(X)(X[] t) if (is(Unqual!X == Unqual!T)) + { + if (used + t.length > array.length) + { extend(nextPow2(used + t.length)); } - foreach (i; 0 .. t.length) { + foreach (i; 0 .. t.length) + { emplace(&array[used + i], t[i]); } used += t.length; } - export void remove(size_t elemNum) { - destroy(array[elemNum]); + export void remove(size_t elemNum) + { + //destroy(array[elemNum]); + static if (__traits(hasMember, T, "__xdtor")) + array[elemNum].__xdtor(); + else static if (__traits(hasMember, T, "__dtor")) + array[elemNum].__dtor(); //swap(array[elemNum], array[used - 1]); array[elemNum] = array[used - 1]; used--; } - export void removeStable()(size_t elemNum) { + export void removeStable()(size_t elemNum) + { used--; - foreach (i; 0 .. used) { + foreach (i; 0 .. used) + { array[i] = array[i + 1]; } } - export bool tryRemoveElement()(T elem) { - foreach (i, ref el; array[0 .. used]) { - if (el == elem) { + export bool tryRemoveElement()(T elem) + { + foreach (i, ref el; array[0 .. used]) + { + if (el == elem) + { remove(i); return true; } @@ -192,55 +244,66 @@ public: return false; } - export void removeElement()(T elem) { + export void removeElement()(T elem) + { bool ok = tryRemoveElement(elem); assert(ok, "There is no such an element in vector"); } - export ref T opIndex(size_t elemNum) { + export ref T opIndex(size_t elemNum) const + { //debug assert(elemNum < used, "Range violation [index]"); - return array.ptr[elemNum]; + return *cast(T*)&array.ptr[elemNum]; } - export auto opSlice() { + export auto opSlice() + { return array.ptr[0 .. used]; } - export T[] opSlice(size_t x, size_t y) { + export T[] opSlice(size_t x, size_t y) + { assert(y <= used); return array.ptr[x .. y]; } - export size_t opDollar() { + export size_t opDollar() + { return used; } - export void opAssign(X)(X[] slice) { + export void opAssign(X)(X[] slice) + { reset(); this ~= slice; } - export void opOpAssign(string op)(T obj) { + export void opOpAssign(string op)(T obj) + { //static assert(op == "~"); add(obj); } - export void opOpAssign(string op, X)(X[] obj) { + export void opOpAssign(string op, X)(X[] obj) + { //static assert(op == "~"); add(obj); } - export void opIndexAssign()(T obj, size_t elemNum) { + export void opIndexAssign()(T obj, size_t elemNum) + { assert(elemNum < used, "Range viloation"); array[elemNum] = obj; } - export void opSliceAssign()(T[] obj, size_t a, size_t b) { + export void opSliceAssign()(T[] obj, size_t a, size_t b) + { assert(b <= used && a <= b, "Range viloation"); array.ptr[a .. b] = obj; } - export bool opEquals()(auto ref const Vector!(T) r) const { + export bool opEquals()(auto ref const Vector!(T) r) const + { return used == r.used && array.ptr[0 .. used] == r.array.ptr[0 .. r.used]; } -} \ No newline at end of file +} diff --git a/source/ecs/atomic.d b/source/ecs/atomic.d deleted file mode 100644 index 5e5f447..0000000 --- a/source/ecs/atomic.d +++ /dev/null @@ -1,97 +0,0 @@ -/************************************************************************************************************************ -It's internal code. Can be used for atomics if emscripten backend will be used. - -This module contain atomic operations which include support for emscripten atomics functions. -Emscripten functions are contained in API similar to druntime. - -Copyright: Copyright © 2018-2019, Dawid Masiukiewicz, Michał Masiukiewicz -License: BSD 3-clause, see LICENSE file in project root folder. -*/ -module ecs.atomic; - -version(Emscripten)version = ECSEmscripten; - -version(ECSEmscripten) -{ - import std.traits; - - enum MemoryOrder - { - acq, - acq_rel, - raw, - rel, - seq - } - - extern(C) ubyte emscripten_atomic_cas_u8(void *addr, ubyte oldVal, ubyte newVal) @nogc nothrow pure; - extern(C) ushort emscripten_atomic_cas_u16(void *addr, ushort oldVal, ushort newVal) @nogc nothrow pure; - extern(C) uint emscripten_atomic_cas_u32(void *addr, uint oldVal, uint newVal) @nogc nothrow pure; - - extern(C) ubyte emscripten_atomic_load_u8(const void *addr) @nogc nothrow pure; - extern(C) ushort emscripten_atomic_load_u16(const void *addr) @nogc nothrow pure; - extern(C) uint emscripten_atomic_load_u32(const void *addr) @nogc nothrow pure; - - extern(C) ubyte emscripten_atomic_store_u8(void *addr, ubyte val) @nogc nothrow pure; - extern(C) ushort emscripten_atomic_store_u16(void *addr, ushort val) @nogc nothrow pure; - extern(C) uint emscripten_atomic_store_u32(void *addr, uint val) @nogc nothrow pure; - - extern(C) ubyte emscripten_atomic_add_u8(void *addr, ubyte val) @nogc nothrow pure; - extern(C) ushort emscripten_atomic_add_u16(void *addr, ushort val) @nogc nothrow pure; - extern(C) uint emscripten_atomic_add_u32(void *addr, uint val) @nogc nothrow pure; - - extern(C) ubyte emscripten_atomic_sub_u8(void *addr, ubyte val) @nogc nothrow pure; - extern(C) ushort emscripten_atomic_sub_u16(void *addr, ushort val) @nogc nothrow pure; - extern(C) uint emscripten_atomic_sub_u32(void *addr, uint val) @nogc nothrow pure; - - public pure nothrow @nogc Unqual!T atomicOp(string op, T, V1)(ref shared T val, V1 mod) - { - static if(op == "+=") - { - static if(is(T == byte) || is(T == ubyte))return cast(Unqual!T)(emscripten_atomic_add_u8(cast(void*)&val, cast(Unqual!T)mod) + 1); - else static if(is(T == short) || is(T == ushort))return cast(Unqual!T)(emscripten_atomic_add_u16(cast(void*)&val, cast(Unqual!T)mod) + 1); - else static if(is(T == int) || is(T == uint))return cast(Unqual!T)(emscripten_atomic_add_u32(cast(void*)&val, cast(Unqual!T)mod) + 1); - else static assert(0); - } - else static if(op == "-=") - { - static if(is(T == byte) || is(T == ubyte))return cast(Unqual!T)(emscripten_atomic_sub_u8(cast(void*)&val, cast(Unqual!T)mod) - 1); - else static if(is(T == short) || is(T == ushort))return cast(Unqual!T)(emscripten_atomic_sub_u16(cast(void*)&val, cast(Unqual!T)mod) - 1); - else static if(is(T == int) || is(T == uint))return cast(Unqual!T)(emscripten_atomic_sub_u32(cast(void*)&val, cast(Unqual!T)mod) - 1); - else static assert(0); - } - } - - public pure nothrow @nogc @trusted void atomicStore(MemoryOrder ms = MemoryOrder.seq, T, V)(ref T val, V newval) - { - alias UT = Unqual!T; - static if(is(UT == bool) || is(UT == byte) || is(UT == ubyte))emscripten_atomic_store_u8(cast(void*)&val, cast(UT)newval); - else static if(is(UT == short) || is(UT == ushort))emscripten_atomic_store_u16(cast(void*)&val, cast(UT)newval); - else static if(is(UT == int) || is(UT == uint))emscripten_atomic_store_u32(cast(void*)&val, cast(UT)newval); - else static assert(0); - } - - public pure nothrow @nogc @trusted T atomicLoad(MemoryOrder ms = MemoryOrder.seq, T)(ref const T val) - { - alias UT = Unqual!T; - static if(is(UT == bool))return emscripten_atomic_load_u8(cast(const void*)&val) != 0; - else static if(is(UT == byte) || is(UT == ubyte))return emscripten_atomic_load_u8(cast(const void*)&val); - else static if(is(UT == short) || is(UT == ushort))return emscripten_atomic_load_u16(cast(const void*)&val); - else static if(is(UT == int) || is(UT == uint))return emscripten_atomic_load_u32(cast(const void*)&val); - else static assert(0); - } - - public pure nothrow @nogc @trusted bool cas(MemoryOrder succ = MemoryOrder.seq, MemoryOrder fail = MemoryOrder.seq, T, V1, V2)(T* here, V1 ifThis, V2 writeThis) - { - alias UT = Unqual!T; - static if(is(UT == bool))return emscripten_atomic_cas_u8(cast(void*)here, cast(Unqual!T)ifThis, cast(Unqual!T)writeThis) == ifThis; - else static if(is(UT == byte) || is(UT == ubyte))return emscripten_atomic_cas_u8(cast(void*)here, cast(Unqual!T)ifThis, cast(Unqual!T)writeThis) == ifThis; - else static if(is(UT == short) || is(UT == ushort))return emscripten_atomic_cas_u16(cast(void*)here, cast(Unqual!T)ifThis, cast(Unqual!T)writeThis) == ifThis; - else static if(is(UT == int) || is(UT == uint))return emscripten_atomic_cas_u32(cast(void*)here, cast(Unqual!T)ifThis, cast(Unqual!T)writeThis) == ifThis; - else static assert(0); - } -} -else -{ - public import core.atomic; -} \ No newline at end of file diff --git a/source/ecs/package.d b/source/ecs/package.d deleted file mode 100644 index eda440d..0000000 --- a/source/ecs/package.d +++ /dev/null @@ -1,10 +0,0 @@ -module ecs; - -public import ecs.core; -public import ecs.entity; -public import ecs.manager; -public import ecs.system; - -import ecs.events; -import ecs.id_manager; -import ecs.std; \ No newline at end of file diff --git a/source/ecs/simple_vector.d b/source/ecs/simple_vector.d deleted file mode 100644 index 175c015..0000000 --- a/source/ecs/simple_vector.d +++ /dev/null @@ -1,65 +0,0 @@ -module ecs.simple_vector; - -import ecs.std; - -//import core.stdc.string; - -struct SimpleVector -{ - - @disable this(this); - - void add(ubyte el) nothrow @nogc - { - while(used >= data.length) - { - if(data is null)data = Mallocator.makeArray!ubyte(1024); - else data = Mallocator.expandArray(data,data.length); - } - data[used++] = el; - } - - void add(ubyte[] el) nothrow @nogc - { - while(used + el.length >= data.length) - { - if(data is null)data = Mallocator.makeArray!ubyte(1024); - else data = Mallocator.expandArray(data,data.length); - } - memcpy(data.ptr + used, el.ptr, el.length); - used += el.length; - } - - size_t length() nothrow @nogc - { - return used; - } - - export ref ubyte opIndex(size_t pos) nothrow @nogc - { - return data[pos]; - } - - export ubyte[] opSlice() nothrow @nogc - { - return data[0 .. used]; - } - - export ubyte[] opSlice(size_t x, size_t y) nothrow @nogc - { - return data[x .. y]; - } - - export size_t opDollar() nothrow @nogc - { - return used; - } - - void clear() nothrow @nogc - { - used = 0; - } - - ubyte[] data = null; - size_t used = 0; -} \ No newline at end of file diff --git a/source/ecs/std.d b/source/ecs/std.d deleted file mode 100644 index c027fd5..0000000 --- a/source/ecs/std.d +++ /dev/null @@ -1,314 +0,0 @@ -/************************************************************************************************************************ -It's internal code! -This module contain implementation of standard functionality. - -Copyright: Copyright © 2018-2019, Dawid Masiukiewicz, Michał Masiukiewicz -License: BSD 3-clause, see LICENSE file in project root folder. -*/ -module ecs.std; - -version(Emscripten)version = ECSEmscripten; - -import std.traits; - -version(ECSEmscripten) -{ - extern(C) struct pthread_mutex_t - { - union - { - int[6] __i; - void[6] *__p; - } - } - - extern(C) struct pthread_mutexattr_t - { - uint __attr; - } - - extern(C) int memcmp (const void *s1, const void *s2, size_t size); - extern(C) void exit (int status) nothrow @nogc; - extern(C) void __assert(const(char)* msg, const(char)* file, uint line) { exit(-20);} - extern(C) void free(void*) @nogc nothrow @system; - extern(C) void* malloc(size_t size) @nogc nothrow @system; - extern(C) void* realloc(void*, size_t size) @nogc nothrow @system; - extern(C) void* memcpy(return void*, scope const void*, size_t size) @nogc nothrow @system; - extern(C) void* memset(void*, int val, size_t size) @nogc nothrow @system; - extern(C) int posix_memalign(void**, size_t, size_t) @nogc nothrow @system; - extern(C) void qsort(void* base, size_t num, size_t size, int function(const void*,const void*) compar) @nogc nothrow @system; - - extern(C) int pthread_mutex_lock(pthread_mutex_t *mutex) @nogc nothrow; - extern(C) int pthread_mutex_trylock(pthread_mutex_t *mutex) @nogc nothrow; - extern(C) int pthread_mutex_unlock(pthread_mutex_t *mutex) @nogc nothrow; - extern(C) void pthread_mutexattr_settype(pthread_mutexattr_t *attr, int type) @nogc nothrow; - extern(C) void pthread_mutexattr_destroy(pthread_mutexattr_t *attr) @nogc nothrow; - extern(C) int pthread_mutexattr_init(pthread_mutexattr_t *attr) @nogc nothrow; - extern(C) int pthread_mutex_destroy(pthread_mutex_t *mutex) @nogc nothrow; - extern(C) int pthread_mutex_init(pthread_mutex_t* mutex, const pthread_mutexattr_t* attr) @nogc nothrow; - -} -else -{ - public import core.stdc.stdlib : malloc, free, realloc; - public import core.stdc.string : memcpy, memset; - public import core.stdc.stdlib : qsort; -} - -version(ECSEmscripten) -{ -} -else version (Windows) -{ - import core.sys.windows.windows; - extern(Windows) void* _aligned_malloc(size_t size,size_t alignment) @nogc nothrow @system; - extern(Windows) void _aligned_free(void* ptr) @nogc nothrow @system; - - version(LDC) - { - /*extern(Windows) void* __alloca(size_t size) @nogc nothrow @system; - alias alloca = __alloca;*/ - - extern(Windows) void ___chkstk_ms() @nogc nothrow @system; - - extern(Windows) void __chkstk() - { - ___chkstk_ms(); - } - } -} -else version (Posix) -{ - import core.sys.posix.pthread; - import core.sys.posix.stdlib; -} - -version(ECSEmscripten) -{ - private const uint max_alloca = 10000; - private __gshared byte[max_alloca] alloca_array; - private __gshared uint alloca_pos = 0; - export extern(C) void* alloca(size_t length) @nogc nothrow - { - if(alloca_pos + length > max_alloca)alloca_pos = 0; - void* ret = &alloca_array[alloca_pos]; - alloca_pos += length; - return ret; - } - //extern(C) void* alloca(size_t size) @nogc nothrow; - /*export extern(C) void* alloca(size_t length) @nogc nothrow - { - return null; - }*/ -} -else version(D_BetterC) -{ - private const uint max_alloca = 10000; - private __gshared byte[max_alloca] alloca_array; - private uint alloca_pos = 0; - export extern(C) void* alloca(size_t length) @nogc nothrow - { - if(alloca_pos + length > max_alloca)alloca_pos = 0; - void* ret = &alloca_array[alloca_pos]; - alloca_pos += length; - return ret; - } -} -else -{ - public import core.stdc.stdlib : alloca; -} - -static struct Mallocator -{ - static T[] makeArray(T)(size_t length) nothrow @nogc - { - T[] ret = (cast(T*)malloc(T.sizeof * length))[0 .. length]; - - static if(__traits(isPOD, T)) - { - static immutable T init = T.init; - - foreach(i;0..ret.length) - { - memcpy(&ret[i], &init, T.sizeof); - } - } - else - { - static import std.conv; - foreach(i;0..ret.length) - { - std.conv.emplace(&ret[i]); - } - } - return ret; - } - - static T[] makeArray(T)(size_t length, T initializer) nothrow @nogc - { - T[] ret = (cast(T*)malloc(T.sizeof * length))[0 .. length]; - foreach(ref v; ret)v = initializer; - return ret; - } - - static T[] expandArray(T)(T[] array, size_t length) nothrow @nogc - { - size_t new_length = array.length + length; - return (cast(T*)realloc(array.ptr, T.sizeof * new_length))[0 .. new_length]; - } - - static T[] makeArray(T)(T[] array) nothrow @nogc - { - T[] ret = (cast(T*)malloc(T.sizeof * array.length))[0 .. array.length];//Mallocator.makeArray!(T)(array.length); - foreach(i, ref v;ret)v = array[i]; - return ret; - } - - static T* make(T, Args...)(Args args) - { - T* ret = cast(T*)malloc(T.sizeof); - static import std.conv; - static if(__traits(isPOD, T)) - { - static immutable T init = T.init; - memcpy(ret, &init, T.sizeof); - } - else static if(is(T == struct))std.conv.emplace(ret, args); - return ret; - } - - static void* alignAlloc(size_t length, size_t alignment) nothrow @nogc - { - void* ret; - version(Posix)posix_memalign(&ret, alignment, length);//ret = aligned_alloc(alignment, length); - else version(Windows)ret = _aligned_malloc(length, alignment); - else version(ECSEmscripten)posix_memalign(&ret, alignment, length);//malloc(length); - else static assert(0, "Unimplemented platform!"); - return ret; - } - - static void dispose(T)(T object) nothrow @nogc - { - static if(__traits(hasMember, T, "__xdtor"))object.__xdtor(); - else static if(__traits(hasMember, T, "__dtor"))object.__dtor(); - free(cast(void*)object); - } - - static void alignDispose(T)(T object) - { - static if(__traits(hasMember, T, "__xdtor"))object.__xdtor(); - else static if(__traits(hasMember, T, "__dtor"))object.__dtor(); - version(Posix)free(cast(void*)object); - else version(Windows)_aligned_free(cast(void*)object); - else version(ECSEmscripten)free(cast(void*)object); - else static assert(0, "Unimplemented platform!"); - } -} - -struct Mutex -{ - - version(ECSEmscripten) - { - void initialize() nothrow @nogc - { - pthread_mutexattr_t attr = void; - - //pthread_mutexattr_init(&attr); - - //pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); - pthread_mutex_init(cast(pthread_mutex_t*) &m_handle, &attr); - - //pthread_mutexattr_destroy(&attr); - } - - void destroy() nothrow @nogc - { - pthread_mutex_destroy(&m_handle); - } - - void lock() nothrow @nogc - { - pthread_mutex_lock(&m_handle); - } - - void unlock() nothrow @nogc - { - pthread_mutex_unlock(&m_handle); - } - - int tryLock() nothrow @nogc - { - return pthread_mutex_trylock(&m_handle) == 0; - } - - private pthread_mutex_t m_handle; - } - else version (Windows) - { - void initialize() nothrow @nogc - { - InitializeCriticalSection(cast(CRITICAL_SECTION*) &m_handle); - } - - void destroy() nothrow @nogc - { - DeleteCriticalSection(&m_handle); - } - - void lock() nothrow @nogc - { - EnterCriticalSection(&m_handle); - } - - void unlock() nothrow @nogc - { - LeaveCriticalSection(&m_handle); - } - - int tryLock() nothrow @nogc - { - return TryEnterCriticalSection(&m_handle) != 0; - } - - CRITICAL_SECTION m_handle; - } - else version (Posix) - { - void initialize() nothrow @nogc - { - pthread_mutexattr_t attr = void; - - pthread_mutexattr_init(&attr); - - pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); - pthread_mutex_init(cast(pthread_mutex_t*) &m_handle, &attr); - - pthread_mutexattr_destroy(&attr); - } - - void destroy() nothrow @nogc - { - pthread_mutex_destroy(&m_handle); - } - - void lock() nothrow @nogc - { - pthread_mutex_lock(&m_handle); - } - - void unlock() nothrow @nogc - { - pthread_mutex_unlock(&m_handle); - } - - int tryLock() nothrow @nogc - { - return pthread_mutex_trylock(&m_handle) == 0; - } - - private pthread_mutex_t m_handle; - } - else static assert(0, "unsupported platform!"); -} \ No newline at end of file diff --git a/tests/access_perf.d b/tests/access_perf.d new file mode 100644 index 0000000..36da0c0 --- /dev/null +++ b/tests/access_perf.d @@ -0,0 +1,135 @@ +module tests.access_perf; + +import tests.runner; + +import bubel.ecs.core; +import bubel.ecs.manager; +import bubel.ecs.entity; + +version(GNU) +{ + pragma(inline, true) T[n] staticArray(T, size_t n)(auto ref T[n] a) + { + return a; + } +} +else import std.array : staticArray; + +import core.stdc.stdio; + +struct CLong +{ + mixin ECS.Component; + + alias value this; + + long value = 10; +} + +struct CInt +{ + mixin ECS.Component; + + alias value this; + + int value = 10; +} + +struct CUInt +{ + mixin ECS.Component; + + alias value this; + + uint value = 12; +} + +struct CBig +{ + mixin ECS.Component; + uint[32] data; +} + +EntityTemplate* tmpl; + +void beforeEveryTest() +{ + gEM.initialize(0); + + gEM.beginRegister(); + + gEM.registerComponent!CLong; + gEM.registerComponent!CInt; + gEM.registerComponent!CUInt; + gEM.registerComponent!CBig; + + gEM.endRegister(); + + tmpl = gEM.allocateTemplate([CLong.component_id, CInt.component_id, CUInt.component_id, CBig.component_id].staticArray); + foreach(i; 0 .. 100_000)gEM.addEntity(tmpl); +} + +void afterEveryTest() +{ + if(tmpl)gEM.freeTemplate(tmpl); + tmpl = null; + gEM.destroy(); +} + +@("DirectAccess100k1comp") +unittest +{ + foreach(i;0..25000) + { + Entity* entity = gEM.getEntity(EntityID(i*4+1,0)); + CUInt* comp1 = entity.getComponent!CUInt; + comp1.value = 4; + } +} + +@("DirectAccess100k4comp") +unittest +{ + foreach(i;0..25000) + { + Entity* entity = gEM.getEntity(EntityID(i*4+1,0)); + CUInt* comp1 = entity.getComponent!CUInt; + comp1.value = 4; + CInt* comp2 = entity.getComponent!CInt; + comp2.value = 3; + CLong* comp3 = entity.getComponent!CLong; + comp3.value = 1; + CBig* comp4 = entity.getComponent!CBig; + comp4.data[0] = 2; + } +} + +@("DirectAccess100k1compWithMeta") +unittest +{ + foreach(i;0..25000) + { + Entity* entity = gEM.getEntity(EntityID(i*4+1,0)); + EntityMeta meta = entity.getMeta(); + CUInt* comp1 = meta.getComponent!CUInt; + comp1.value = 4; + } +} + +@("DirectAccess100k4compWithMeta") +unittest +{ + foreach(i;0..25000) + { + Entity* entity = gEM.getEntity(EntityID(i*4+1,0)); + EntityMeta meta = entity.getMeta(); + CUInt* comp1 = meta.getComponent!CUInt; + comp1.value = 4; + CInt* comp2 = meta.getComponent!CInt; + comp2.value = 3; + CLong* comp3 = meta.getComponent!CLong; + comp3.value = 1; + CBig* comp4 = meta.getComponent!CBig; + comp4.data[0] = 2; + } +} \ No newline at end of file diff --git a/tests/basic.d b/tests/basic.d index f3f2832..5046dff 100644 --- a/tests/basic.d +++ b/tests/basic.d @@ -1,11 +1,18 @@ module tests.basic; -import ecs.core; -import ecs.manager; -import ecs.system; -import ecs.attributes; +import bubel.ecs.core; +import bubel.ecs.manager; +import bubel.ecs.system; +import bubel.ecs.attributes; -import std.array : staticArray; +version(GNU) +{ + pragma(inline, true) T[n] staticArray(T, size_t n)(auto ref T[n] a) + { + return a; + } +} +else import std.array : staticArray; struct CInt { @@ -61,6 +68,11 @@ struct CUnregistered short value = 12; } +struct CFlag +{ + mixin ECS.Component; +} + struct LongAddSystem { mixin ECS.System; @@ -103,6 +115,7 @@ struct EmptySystem void beforeEveryTest() { + CUnregistered.component_id = ushort.max; gEM.initialize(0); gEM.beginRegister(); @@ -112,6 +125,7 @@ void beforeEveryTest() gEM.registerComponent!CDouble; gEM.registerComponent!CLong; gEM.registerComponent!CShort; + gEM.registerComponent!CFlag; gEM.endRegister(); } @@ -121,14 +135,33 @@ void afterEveryTest() gEM.destroy(); } +@("EntityMeta") +unittest +{ + EntityTemplate* tmpl_ = gEM.allocateTemplate([CInt.component_id, CFloat.component_id, CFlag.component_id].staticArray); + Entity* entity = gEM.addEntity(tmpl_); + EntityMeta meta = entity.getMeta(); + assert(meta.hasComponent(CInt.component_id)); + assert(meta.getComponent!CInt); + assert(meta.hasComponent(CFloat.component_id)); + assert(meta.getComponent!CFloat); + assert(!meta.getComponent!CLong); + assert(!meta.hasComponent(CLong.component_id)); + assert(!meta.getComponent!CUnregistered); + assert(!meta.hasComponent(CUnregistered.component_id)); + assert(*meta.getComponent!CInt == 1); + assert(*meta.getComponent!CFloat == 2.0); +} + @("AddEntity") unittest { - ushort[2] ids = [CInt.component_id, CFloat.component_id]; - EntityTemplate* tmpl_ = gEM.allocateTemplate(ids); - assert(tmpl_.info.components.length == 2); + EntityTemplate* tmpl_ = gEM.allocateTemplate([CInt.component_id, CFloat.component_id, CFlag.component_id].staticArray); + assert(tmpl_.info.components.length == 3); + assert(tmpl_.info.size == (CInt.sizeof + CFloat.sizeof + EntityID.sizeof)); assert(tmpl_.getComponent!CInt); assert(tmpl_.getComponent!CFloat); + assert(tmpl_.getComponent!CFlag); assert(!tmpl_.getComponent!CLong); assert(!tmpl_.getComponent!CUnregistered); assert(*tmpl_.getComponent!CInt == 1); @@ -146,6 +179,67 @@ unittest assert(entity2.getComponent!CFloat); assert(*entity2.getComponent!CInt == 2); assert(*entity2.getComponent!CFloat == 2.0); + + //CInt cint = CInt(10); + //CLong clong; + //Entity* entity3 = gEM.addEntity(tmpl_, [cint.ref_, clong.ref_].staticArray); + Entity* entity3 = gEM.addEntity(tmpl_, [CInt(10).ref_, CLong().ref_, CFlag().ref_].staticArray); + EntityID id = entity3.id; + assert(entity3.hasComponent(CInt.component_id)); + assert(entity3.hasComponent(CFloat.component_id)); + assert(*entity3.getComponent!CInt == 10); + assert(*entity3.getComponent!CFloat == 2.0); + + gEM.addComponents(entity3.id, [CFlag().ref_,CShort(2).ref_].staticArray); + gEM.commit(); + entity3 = gEM.getEntity(id); + assert(entity3.getComponent!CInt); + assert(entity3.getComponent!CFloat); + assert(entity3.getComponent!CFlag); + assert(entity3.getComponent!CShort); + assert(*entity3.getComponent!CInt == 10); + assert(*entity3.getComponent!CFloat == 2.0); + assert(*entity3.getComponent!CShort == 2); + + gEM.removeComponents(entity3.id, [CFlag().component_id,CShort(2).component_id].staticArray); + gEM.commit(); + entity3 = gEM.getEntity(id); + assert(entity3.getComponent!CInt); + assert(entity3.getComponent!CFloat); + assert(!entity3.getComponent!CFlag); + assert(!entity3.getComponent!CShort); + assert(*entity3.getComponent!CInt == 10); + assert(*entity3.getComponent!CFloat == 2.0); + + gEM.addComponents(entity3.id, [CFlag().ref_,CShort(2).ref_].staticArray); + gEM.removeComponents(entity3.id, [CUnregistered.component_id].staticArray); + gEM.commit(); + entity3 = gEM.getEntity(id); + assert(entity3.getComponent!CInt); + assert(entity3.getComponent!CFloat); + assert(entity3.getComponent!CFlag); + assert(entity3.getComponent!CShort); + assert(*entity3.getComponent!CInt == 10); + assert(*entity3.getComponent!CFloat == 2.0); + assert(*entity3.getComponent!CShort == 2); + + gEM.beginRegister(); + + gEM.registerComponent!CUnregistered; + + gEM.endRegister(); + + gEM.addComponents(entity3.id, [CUnregistered(4).ref_].staticArray); + gEM.commit(); + entity3 = gEM.getEntity(id); + assert(entity3.getComponent!CUnregistered); + assert(*entity3.getComponent!CUnregistered == 4); + + gEM.removeComponents(entity3.id, [CUnregistered.component_id].staticArray); + gEM.commit(); + entity3 = gEM.getEntity(id); + assert(!entity3.getComponent!CUnregistered); + } //allocate templates @@ -156,32 +250,48 @@ unittest ushort[2] ids = [CInt.component_id, CFloat.component_id]; EntityTemplate* tmpl_ = gEM.allocateTemplate(ids); EntityTemplate* tmpl_d = gEM.allocateTemplate([CFloat.component_id, CInt.component_id, CFloat.component_id].staticArray); + EntityTemplate* tmpl_cp = gEM.allocateTemplate(tmpl_); assert(tmpl_d.info == tmpl_.info); + assert(tmpl_cp.info == tmpl_cp.info); assert(tmpl_.info.components.length == 2); assert(tmpl_.getComponent!CInt); assert(tmpl_.getComponent!CFloat); assert(*tmpl_.getComponent!CInt == 1); assert(*tmpl_.getComponent!CFloat == 2.0); + assert(tmpl_cp.getComponent!CFloat); + assert(tmpl_cp.getComponent!CInt); + assert(tmpl_.getComponent!CInt != tmpl_cp.getComponent!CInt); + assert(tmpl_.getComponent!CFloat != tmpl_cp.getComponent!CFloat); + assert(*tmpl_.getComponent!CInt == *tmpl_cp.getComponent!CInt); + assert(*tmpl_.getComponent!CFloat == *tmpl_cp.getComponent!CFloat); *tmpl_.getComponent!CInt = 4; *tmpl_.getComponent!CFloat = 5.0; - //allocate template from template with additional component - ushort[1] ids2 = [CDouble.component_id]; + //allocate template from template with additional components + ushort[2] ids2 = [CDouble.component_id,CFlag.component_id]; EntityTemplate* tmpl_2 = gEM.allocateTemplate(tmpl_, ids2); - assert(tmpl_2.info.components.length == 3); + assert(tmpl_2.info.components.length == 4); assert(tmpl_2.getComponent!CInt); assert(tmpl_2.getComponent!CFloat); assert(tmpl_2.getComponent!CDouble); + assert(tmpl_2.getComponent!CFlag); assert(*tmpl_2.getComponent!CInt == 4); assert(*tmpl_2.getComponent!CFloat == 5.0); assert(*tmpl_2.getComponent!CDouble == 3.0); + assert(tmpl_.info.blocksCount() == 0); + Entity* entity = gEM.addEntity(tmpl_); - gEM.addComponents(entity.id, CDouble(8.0)); + gEM.addComponents(entity.id, CFloat(100)); + gEM.addComponents(entity.id, CDouble(8.0), CFloat(100)); + + assert(tmpl_.info.blocksCount() == 1); //apply entity changes gEM.commit(); + assert(tmpl_.info.blocksCount() == 0); + //allocate template as entity copy EntityTemplate* tmpl_3 = gEM.allocateTemplate(entity.id); assert(tmpl_3.info.components.length == 3); @@ -202,18 +312,20 @@ unittest assert(*tmpl_4.getComponent!CFloat == 2.0); assert(*tmpl_4.getComponent!CDouble == 3.0); - //allocate template from template with two additional component - ushort[2] ids3 = [CDouble.component_id, CLong.component_id]; - EntityTemplate* tmpl_5 = gEM.allocateTemplate(tmpl_, ids3); - assert(tmpl_5.info.components.length == 4); + //allocate template from template with three additional component + ushort[3] ids3 = [CDouble.component_id, CLong.component_id, CShort.component_id]; + EntityTemplate* tmpl_5 = gEM.allocateTemplate(tmpl_2, ids3); + assert(tmpl_5.info.components.length == 6); assert(tmpl_5.getComponent!CInt); assert(tmpl_5.getComponent!CFloat); assert(tmpl_5.getComponent!CDouble); assert(tmpl_5.getComponent!CLong); + assert(tmpl_5.getComponent!CShort); assert(*tmpl_5.getComponent!CInt == 4); assert(*tmpl_5.getComponent!CFloat == 5.0); assert(*tmpl_5.getComponent!CDouble == 3.0); assert(*tmpl_5.getComponent!CLong == 10); + assert(*tmpl_5.getComponent!CShort == 12); //allocate template from template without one component ushort[1] rem_ids = [CFloat.component_id]; @@ -224,7 +336,7 @@ unittest //allocate template from template without one component and two additional EntityTemplate* tmpl_7 = gEM.allocateTemplate(tmpl_, ids3, rem_ids); - assert(tmpl_7.info.components.length == 3); + assert(tmpl_7.info.components.length == 4); assert(tmpl_7.getComponent!CInt); assert(tmpl_7.getComponent!CDouble); assert(tmpl_7.getComponent!CLong); @@ -481,6 +593,10 @@ unittest gEM.endRegister(); + assert(gEM.getPass("custom")); + assert(!gEM.getPass("custommm")); + + LongAddSystem* system = gEM.getSystem!LongAddSystem; assert(system !is null); assert(system.updates_count == 0); @@ -1116,9 +1232,9 @@ unittest assert(*entity2.getComponent!CShort == 12); gEM.sendEvent(id,ETest()); - gEM.sendEvent(id,ETest2(id,10)); + gEM.sendEvent(id,ETest2(10)); gEM.sendEvent(id2,ETest()); - gEM.sendEvent(id2,ETest2(id2,12)); + gEM.sendEvent(id2,ETest2(12)); gEM.commit(); assert(ETest2.destory == 2); @@ -1129,20 +1245,20 @@ unittest gEM.addComponents(id, CInt(2), CShort(1)); gEM.sendEvent(id,ETest()); - gEM.sendEvent(id,ETest2(id,2)); + gEM.sendEvent(id,ETest2(2)); gEM.commit(); assert(ETest2.destory == 3); entity = gEM.getEntity(id); assert(*entity.getComponent!CLong == 66); - assert(*entity.getComponent!CInt == 36); + assert(*entity.getComponent!CInt == 2);//36); //test for multiple event blocks long result = *entity.getComponent!CLong; foreach(i;0..10000) { gEM.sendEvent(id,ETest()); - gEM.sendEvent(id,ETest2(id,4)); + gEM.sendEvent(id,ETest2(4)); result += 16; result += 8; } @@ -1220,4 +1336,247 @@ unittest assert(*entity2.getComponent!CInt == 13); gEM.end(); +} + +@("SystemDependencies") +unittest +{ + struct TestSystem + { + mixin ECS.System; + + struct EntitiesData + { + uint length; + @readonly CInt[] int_; + } + + void onUpdate(EntitiesData entities) + { + + } + } + + struct TestSystem2 + { + mixin ECS.System; + + struct EntitiesData + { + uint length; + CInt[] int_; + } + + void onUpdate(EntitiesData entities) + { + + } + } + + struct TestSystem3 + { + mixin ECS.System; + + struct EntitiesData + { + uint length; + @readonly CInt[] int_; + } + + void onUpdate(EntitiesData entities) + { + + } + } + + struct TestSystem4 + { + mixin ECS.System; + + struct EntitiesData + { + uint length; + CInt[] int_; + CLong[] long_; + } + + void onUpdate(EntitiesData entities) + { + + } + } + + struct TestSystem5 + { + mixin ECS.System; + + struct EntitiesData + { + uint length; + @readonly CLong[] int_; + } + + void onUpdate(EntitiesData entities) + { + + } + } + + gEM.beginRegister(); + + gEM.registerSystem!TestSystem(0); + gEM.registerSystem!TestSystem2(1); + gEM.registerSystem!TestSystem3(2); + gEM.registerSystem!TestSystem4(3); + gEM.registerSystem!TestSystem5(4); + + gEM.endRegister(); + + const (EntityManager.UpdatePass)* pass = gEM.getPass("update"); + assert(pass != null); + assert(pass.system_callers.length == 5); + assert(pass.system_callers[0].system_id == TestSystem.system_id); + assert(pass.system_callers[1].system_id == TestSystem2.system_id); + assert(pass.system_callers[2].system_id == TestSystem3.system_id); + assert(pass.system_callers[3].system_id == TestSystem4.system_id); + assert(pass.system_callers[4].system_id == TestSystem5.system_id); + assert(pass.system_callers[0].dependencies.length == 0); + assert(pass.system_callers[1].dependencies.length == 1); + assert(pass.system_callers[2].dependencies.length == 1); + assert(pass.system_callers[3].dependencies.length == 3); + assert(pass.system_callers[4].dependencies.length == 1); + assert(pass.system_callers[1].dependencies[0].system_id == TestSystem.system_id); + assert(pass.system_callers[2].dependencies[0].system_id == TestSystem2.system_id); + assert(pass.system_callers[3].dependencies[0].system_id == TestSystem.system_id); + assert(pass.system_callers[3].dependencies[1].system_id == TestSystem2.system_id); + assert(pass.system_callers[3].dependencies[2].system_id == TestSystem3.system_id); + assert(pass.system_callers[4].dependencies[0].system_id == TestSystem4.system_id); +} + +@("ExternalSystemDependencies") +unittest +{ + enum TestDependency = "TestDepencency"; + + struct TestSystem + { + mixin ECS.System; + + mixin ECS.ReadOnlyDependencies!(TestDependency); + + struct EntitiesData + { + uint length; + @readonly CInt[] int_; + } + + void onUpdate(EntitiesData entities) + { + + } + } + + struct TestSystem2 + { + mixin ECS.System; + + mixin ECS.WritableDependencies!(TestDependency); + + struct EntitiesData + { + uint length; + @readonly CInt[] int_; + } + + void onUpdate(EntitiesData entities) + { + + } + } + + struct TestSystem3 + { + mixin ECS.System; + + mixin ECS.ReadOnlyDependencies!(TestDependency); + + struct EntitiesData + { + uint thread_id; + } + + void onUpdate(EntitiesData entities) + { + + } + } + + struct TestSystem4 + { + mixin ECS.System; + + mixin ECS.WritableDependencies!(TestDependency); + + struct EntitiesData + { + uint length; + @readonly CInt[] int_; + } + + void onUpdate(EntitiesData entities) + { + + } + } + + struct TestSystem5 + { + mixin ECS.System; + + mixin ECS.ReadOnlyDependencies!(TestDependency); + + struct EntitiesData + { + uint length; + @readonly CLong[] int_; + } + + void onUpdate(EntitiesData entities) + { + + } + } + + gEM.beginRegister(); + + gEM.registerDependency(TestDependency); + + gEM.registerSystem!TestSystem(0); + gEM.registerSystem!TestSystem2(1); + gEM.registerSystem!TestSystem3(2); + gEM.registerSystem!TestSystem4(3); + gEM.registerSystem!TestSystem5(4); + + gEM.endRegister(); + + const (EntityManager.UpdatePass)* pass = gEM.getPass("update"); + assert(pass != null); + assert(pass.system_callers.length == 5); + assert(pass.system_callers[0].system_id == TestSystem.system_id); + assert(pass.system_callers[1].system_id == TestSystem2.system_id); + assert(pass.system_callers[2].system_id == TestSystem3.system_id); + assert(pass.system_callers[3].system_id == TestSystem4.system_id); + assert(pass.system_callers[4].system_id == TestSystem5.system_id); + assert(pass.system_callers[0].dependencies.length == 0); + assert(pass.system_callers[1].dependencies.length == 1); + assert(pass.system_callers[2].dependencies.length == 1); + assert(pass.system_callers[3].dependencies.length == 3); + assert(pass.system_callers[4].dependencies.length == 2); + assert(pass.system_callers[1].dependencies[0].system_id == TestSystem.system_id); + assert(pass.system_callers[2].dependencies[0].system_id == TestSystem2.system_id); + assert(pass.system_callers[3].dependencies[0].system_id == TestSystem.system_id); + assert(pass.system_callers[3].dependencies[1].system_id == TestSystem2.system_id); + assert(pass.system_callers[3].dependencies[2].system_id == TestSystem3.system_id); + assert(pass.system_callers[4].dependencies[0].system_id == TestSystem2.system_id); + assert(pass.system_callers[4].dependencies[1].system_id == TestSystem4.system_id); } \ No newline at end of file diff --git a/tests/bugs.d b/tests/bugs.d new file mode 100644 index 0000000..4c4153a --- /dev/null +++ b/tests/bugs.d @@ -0,0 +1,142 @@ +module tests.bugs; + +import tests.basic; + +import bubel.ecs.core; +import bubel.ecs.manager; +import bubel.ecs.system; +import bubel.ecs.attributes; + +version(GNU) +{ + pragma(inline, true) T[n] staticArray(T, size_t n)(auto ref T[n] a) + { + return a; + } +} +else import std.array : staticArray; + +@("Bug0001") +unittest +{ + struct Event1 + { + mixin ECS.Event; + + EntityID id; + } + + struct Event2 + { + mixin ECS.Event; + } + + struct System1 + { + mixin ECS.System; + + struct EntitiesData + { + CInt[] int_; + } + + EntityTemplate* tmpl; + EntityID id; + + void onCreate() + { + tmpl = gEM.allocateTemplate([CInt.component_id, CLong.component_id].staticArray); + } + + void onDestroy() + { + gEM.freeTemplate(tmpl); + } + + void handleEvent(Entity* entity, Event1 event) + { + gEM.removeEntity(event.id); + gEM.sendEvent(entity.id,Event2()); + } + + void handleEvent(Entity* entity, Event2 event) + { + id = gEM.addEntity(tmpl).id; + } + } + + struct System2 + { + mixin ECS.System; + + struct EntitiesData + { + Entity[] entity; + } + + ///check if every entity was removed correctly + void onUpdate(EntitiesData data) + { + assert(0); + } + } + + struct System3 + { + mixin ECS.System; + + struct EntitiesData + { + uint length; + Entity[] entity; + } + + ///remove every entity + void onUpdate(EntitiesData data) + { + foreach(i;0..data.length)gEM.removeEntity(data.entity[i].id); + } + } + + gEM.initialize(0); + + gEM.beginRegister(); + + gEM.registerComponent!CInt; + gEM.registerComponent!CFloat; + gEM.registerComponent!CDouble; + gEM.registerComponent!CLong; + gEM.registerComponent!CShort; + gEM.registerComponent!CFlag; + + gEM.registerEvent!Event1; + gEM.registerEvent!Event2; + + gEM.registerSystem!System1(0); + gEM.registerSystem!System2(-200); + gEM.registerSystem!System3(-200); + + gEM.endRegister(); + + EntityTemplate* tmpl = gEM.allocateTemplate([CInt.component_id, CLong.component_id].staticArray); + EntityID id = gEM.addEntity(tmpl,[CLong(10).ref_, CInt(6).ref_].staticArray).id; + EntityID id2 = gEM.addEntity(tmpl,[CInt(4).ref_].staticArray).id; + gEM.freeTemplate(tmpl); + gEM.commit(); + + gEM.sendEvent(id2, Event1(id)); + + gEM.getSystem(System2.system_id).disable(); + + gEM.begin(); + gEM.update(); + gEM.end(); + + gEM.getSystem(System2.system_id).enable(); + + gEM.begin(); + gEM.update(); + gEM.end(); + + gEM.destroy(); +} \ No newline at end of file diff --git a/tests/id_manager.d b/tests/id_manager.d index afaafe5..b0f97d5 100644 --- a/tests/id_manager.d +++ b/tests/id_manager.d @@ -1,7 +1,7 @@ module tests.id_manager; -import ecs.id_manager; -import ecs.entity; +import bubel.ecs.id_manager; +import bubel.ecs.entity; unittest { diff --git a/tests/map.d b/tests/map.d new file mode 100644 index 0000000..a82985b --- /dev/null +++ b/tests/map.d @@ -0,0 +1,53 @@ +module tests.map; + +import bubel.ecs.hash_map; + +version(GNU) +{ + pragma(inline, true) T[n] staticArray(T, size_t n)(auto ref T[n] a) + { + return a; + } +} +else import std.array : staticArray; + +@("HashMap") +unittest +{ + HashMap!(string, int) map; + + assert(map.length == 0); + map.add("asd",1); + assert(map.length == 1); + map.clear(); + assert(map.length == 0); + map.add("asd",1); + assert(map.length == 1); + map.reset(); + assert(map.length == 0); + + map.add("asd",1); + string asd = "asd"; + assert(map.isIn("asd")); + assert(map.isIn(asd)); + assert(!map.isIn("asdf")); + map.tryRemove("asdf"); + map.tryRemove("asd"); + assert(map.length == 0); + map.add("asdf",1); + map.add("asd",2); + assert(map["asd"] == 2); + assert(map["asdf"] == 1); + assert(map.length == 2); + map.tryRemove("asdf"); + assert(map.length == 1); + map.remove("asd"); + assert(map.length == 0); + + map.add("asd",1); + map.add("asdwwghe",6); + foreach(k,v;&map.byKeyValue) + { + assert(map[k] == v); + } +} \ No newline at end of file diff --git a/tests/perf.d b/tests/perf.d new file mode 100644 index 0000000..b6a2692 --- /dev/null +++ b/tests/perf.d @@ -0,0 +1,185 @@ +module tests.perf; + +import tests.runner; + +import bubel.ecs.core; +import bubel.ecs.manager; +import bubel.ecs.entity; + +version(GNU) +{ + pragma(inline, true) T[n] staticArray(T, size_t n)(auto ref T[n] a) + { + return a; + } +} +else import std.array : staticArray; + +import core.stdc.stdio; + +struct CLong +{ + mixin ECS.Component; + + alias value this; + + long value = 10; +} + +struct CShort +{ + mixin ECS.Component; + + alias value this; + + short value = 12; +} + +struct CInt +{ + mixin ECS.Component; + + alias value this; + + int value = 10; +} + +struct CUInt +{ + mixin ECS.Component; + + alias value this; + + uint value = 12; +} + +struct CBig +{ + mixin ECS.Component; + uint[32] data; +} + +EntityTemplate* tmpl; + +void beforeEveryTest() +{ + gEM.initialize(0); + + gEM.beginRegister(); + + gEM.registerComponent!CLong; + gEM.registerComponent!CShort; + gEM.registerComponent!CInt; + gEM.registerComponent!CUInt; + gEM.registerComponent!CBig; + + gEM.endRegister(); + tmpl = null; +} + +void afterEveryTest() +{ + if(tmpl)gEM.freeTemplate(tmpl); + tmpl = null; + gEM.destroy(); +} + +void smallTmpl() +{ + tmpl = gEM.allocateTemplate([CShort.component_id].staticArray); +} + +void bigTmpl() +{ + tmpl = gEM.allocateTemplate([CBig.component_id].staticArray); +} + +void multiSmallTmpl() +{ + tmpl = gEM.allocateTemplate([CShort.component_id, CLong.component_id, CInt.component_id, CUInt.component_id].staticArray); +} + +void multiBigTmpl() +{ + tmpl = gEM.allocateTemplate([CLong.component_id, CInt.component_id, CUInt.component_id, CBig.component_id].staticArray); +} + +@("AddEntities100k1comp2b") @(before, &smallTmpl) +unittest +{ + foreach(i; 0..100_000)gEM.addEntity(tmpl); +} + +@("AddEntities100k1comp128b") @(before, &bigTmpl) +unittest +{ + foreach(i; 0..100_000)gEM.addEntity(tmpl); +} + +@("AddEntities100k4comp18b") @(before, &multiSmallTmpl) +unittest +{ + foreach(i; 0..100_000)gEM.addEntity(tmpl); +} + +@("AddEntities100k4comp144b") @(before, &multiBigTmpl) +unittest +{ + foreach(i; 0..100_000)gEM.addEntity(tmpl); +} + +void allocDealloc100k() +{ + foreach(i; 0..100_000)gEM.addEntity(tmpl); + gEM.commit(); + foreach(i; 0..100_000)gEM.removeEntity(EntityID(i + 1,0)); + gEM.commit(); +} + +void smallTmplPreAlloc() +{ + tmpl = gEM.allocateTemplate([CShort.component_id].staticArray); + allocDealloc100k(); +} + +void bigTmplPreAlloc() +{ + tmpl = gEM.allocateTemplate([CBig.component_id].staticArray); + allocDealloc100k(); +} + +void multiSmallTmplPreAlloc() +{ + tmpl = gEM.allocateTemplate([CShort.component_id, CLong.component_id, CInt.component_id, CUInt.component_id].staticArray); + allocDealloc100k(); +} + +void multiBigTmplPreAlloc() +{ + tmpl = gEM.allocateTemplate([CLong.component_id, CInt.component_id, CUInt.component_id, CBig.component_id].staticArray); + allocDealloc100k(); +} + +@("AddEntities100k1comp2bPreAlloc") @(before, &smallTmplPreAlloc) +unittest +{ + foreach(i; 0..100_000)gEM.addEntity(tmpl); +} + +@("AddEntities100k1comp128bPreAlloc") @(before, &bigTmplPreAlloc) +unittest +{ + foreach(i; 0..100_000)gEM.addEntity(tmpl); +} + +@("AddEntities100k4comp18bPreAlloc") @(before, &multiSmallTmplPreAlloc) +unittest +{ + foreach(i; 0..100_000)gEM.addEntity(tmpl); +} + +@("AddEntities100k4comp144bPreAlloc") @(before, &multiBigTmplPreAlloc) +unittest +{ + foreach(i; 0..100_000)gEM.addEntity(tmpl); +} \ No newline at end of file diff --git a/tests/runner.d b/tests/runner.d index 5eaf99b..7e3dd07 100644 --- a/tests/runner.d +++ b/tests/runner.d @@ -5,9 +5,22 @@ import core.stdc.stdio; import core.stdc.string; import core.sys.posix.setjmp; -import ecs.vector; -import ecs.simple_vector; -import ecs.std; +import bubel.ecs.vector; +import bubel.ecs.simple_vector; +import bubel.ecs.std; + +import std.traits; + +import tests.time; + +version (LDC) +{ + import ldc.attributes; +} +else +{ + enum optStrategy = 0; +} enum int ASSERTED = 123; enum string OUT_FILE = "test_report.xml"; @@ -95,6 +108,8 @@ struct TestRunner(Args...) write(test.name); write("\" classname=\""); write(suite.name); + write("\" time=\""); + write(cast(double)test.time*0.000001); write("\">"); if (test.msg) { @@ -120,42 +135,65 @@ struct TestRunner(Args...) write(""); } + @(optStrategy,"none") void runTests(string[] include = null, string[] exclude = null) { foreach (i, module_; Args) { TestSuite* suite = &suites[i]; suite.name = module_.stringof; + + void function() before; + void function() after; + foreach (index, unittest_; __traits(getUnitTests, module_)) { enum attributes = __traits(getAttributes, unittest_); + static if (attributes.length != 0) { - if (include.length > 0) + foreach(attr_id, attr; attributes) { - bool matched = false; - foreach (str; include) + static if(isFunctionPointer!(attr)){} + else static if(attr == "_tr_before") { - if (match(str, attributes[0])) - { - matched = true; - break; - } + static assert(attr_id+1 < attributes.length); + enum attr2 = attributes[attr_id + 1]; + //static assert(__traits(hasMember, module_, attr2)); + //alias func = __traits(getMember, module_, attr2); + //attr2(); + before = attr2; + //static assert(is(typeof(__traits(getMember, module_, attr2)) == void function())); } - - foreach (str; exclude) + else { - if (match(str, attributes[0])) + if (include.length > 0) { - matched = false; - break; - } - } + bool matched = false; + foreach (str; include) + { + if (match(str, attr)) + { + matched = true; + break; + } + } - if (!matched) - { - suite.skipped++; - continue; + foreach (str; exclude) + { + if (match(str, attr)) + { + matched = false; + break; + } + } + + if (!matched) + { + suite.skipped++; + continue; + } + } } } } @@ -172,8 +210,9 @@ struct TestRunner(Args...) else test.name = attributes[0]; - static if (__traits(hasMember, module_, "beforeEveryTest")) + static if (__traits(hasMember, module_, "beforeEveryTest") && __traits(compiles, module_.beforeEveryTest())) module_.beforeEveryTest(); + if(before)before(); version(D_BetterC) { @@ -189,8 +228,10 @@ struct TestRunner(Args...) } else { + long time = Time.getUSecTime(); unittest_(); test.passed = true; + test.time = cast(int)(Time.getUSecTime() - time); } } else @@ -215,7 +256,7 @@ struct TestRunner(Args...) else suite.failed++; suite.tests ~= test; - static if (__traits(hasMember, module_, "afterEveryTest")) + static if (__traits(hasMember, module_, "afterEveryTest") && __traits(compiles, module_.beforeEveryTest())) module_.afterEveryTest(); } passed += suite.passed; @@ -281,6 +322,14 @@ struct TestRunner(Args...) junit.add(cast(ubyte[]) txt); } + void write(double num) + { + ubyte[40] buffer; + int len; + len = sprintf(cast(char*) buffer.ptr, "%2.8lf", num); + junit.add(buffer[0 .. len]); + } + void write(uint num) { ubyte[20] buffer; @@ -304,6 +353,8 @@ version (notBetterC) version (D_Coverage) extern (C) void dmd_coverDestPath(string path); } +enum before = "_tr_before"; + void extractStrings(ref Vector!string container, string str) { uint s = 0; @@ -369,7 +420,7 @@ extern (C) int main(int argc, char** args) } } - TestRunner!(tests.runner, tests.id_manager, tests.vector, tests.basic) runner; + TestRunner!(tests.id_manager, tests.vector, tests.basic, tests.perf, tests.access_perf, tests.bugs, tests.map) runner; runner.runTests(include[], exclude[]); diff --git a/tests/tests.d b/tests/tests.d index ea554d1..d923116 100644 --- a/tests/tests.d +++ b/tests/tests.d @@ -3,12 +3,12 @@ module tests.tests; import std.experimental.allocator; import std.experimental.allocator.mallocator;*/ -import ecs.entity; -import ecs.events; -import ecs.manager; -import ecs.system; -import ecs.attributes; -import ecs.core; +import bubel.ecs.entity; +import bubel.ecs.events; +import bubel.ecs.manager; +import bubel.ecs.system; +import bubel.ecs.attributes; +import bubel.ecs.core; version (WebAssembly) { @@ -714,7 +714,7 @@ else: //foreach(i; 0..1_000_000)gEM.removeEntity(gEM.addEntity(tmpl).id); - import ecs.std; + import bubel.ecs.std; EntityID[] idss = Mallocator.makeArray!EntityID(5000); //[5000] //scope(exit)Mallocator.dispose(idss); diff --git a/tests/time.d b/tests/time.d new file mode 100644 index 0000000..e91b76e --- /dev/null +++ b/tests/time.d @@ -0,0 +1,66 @@ +module tests.time; + + +version (WebAssembly) +{ + alias int time_t; + alias int clockid_t; + enum CLOCK_REALTIME = 0; + + struct timespec + { + time_t tv_sec; + int tv_nsec; + } + + extern (C) int clock_gettime(clockid_t, timespec*) @nogc nothrow @system; + + struct Time + { + static long getUSecTime() + { + time_t time; + timespec spec; + + clock_gettime(CLOCK_REALTIME, &spec); + + //time = spec.tv_sec; + return spec.tv_sec * 1000_000 + spec.tv_nsec / 1000; //time / 1000_000; + } + } +} +else version (Windows) +{ + import core.stdc.stdio : printf; + import core.sys.windows.windows; + + struct Time + { + static long getUSecTime() + { + LARGE_INTEGER time, freq; + QueryPerformanceFrequency(&freq); + QueryPerformanceCounter(&time); + return time.QuadPart / (freq.QuadPart / 1000_000); + } + } +} +else version (Posix) +{ + import core.stdc.stdio : printf; + import core.sys.posix.time; + + struct Time + { + static long getUSecTime() + { + time_t time; + timespec spec; + + clock_gettime(CLOCK_REALTIME, &spec); + + //time = spec.tv_sec; + return spec.tv_sec * 1000_000 + spec.tv_nsec / 1000; //time / 1000_000; + } + } +} \ No newline at end of file diff --git a/tests/vector.d b/tests/vector.d index 4b2ad5b..1756518 100644 --- a/tests/vector.d +++ b/tests/vector.d @@ -1,7 +1,16 @@ module tests.vector; -import ecs.simple_vector; -//import ecs.vector; +import bubel.ecs.simple_vector; +import bubel.ecs.vector; + +version(GNU) +{ + pragma(inline, true) T[n] staticArray(T, size_t n)(auto ref T[n] a) + { + return a; + } +} +else import std.array : staticArray; @("simple-vector") unittest @@ -33,3 +42,38 @@ unittest assert(vector2[1023] == 'a'); assert(vector2[1024] == 'b'); } + +@("Vector") +unittest +{ + struct G + { + int a; + } + + Vector!G vector; + assert(vector.empty()); + vector.add(G(1)); + assert(!vector.empty()); + vector.clear(); + assert(vector.empty()); + vector.add(G(1)); + assert(!vector.empty()); + vector.reset(); + assert(vector.empty()); + + vector.add(G(1)); + vector.add([G(2),G(5)].staticArray); + assert(vector.length == 3); + assert(vector.capacity == 1); + + Vector!G vector2; + vector2.add([G(1),G(2),G(5)].staticArray); + assert(vector == vector2); + vector2.remove(1); + assert(vector != vector2); + assert(vector2.length == 2); + assert(vector2[1] == G(5)); + vector2.add(G(2),1); + assert(vector == vector2); +} From 66860b904222ee8eb37e4234b28283e1c4851962 Mon Sep 17 00:00:00 2001 From: Mergul Date: Mon, 1 Jun 2020 11:24:50 +0200 Subject: [PATCH 152/217] Android update and small improvements -fixed code do cross compiling to android -fixed build with GCC (workaround) -added little benchmark -several small fixes -updated meson build (demos building, working with GCC, LDC and DMD) -added some meson options -added ImGUI bind for OpenGL3 --- .gitignore | 3 +- compile_android.py | 78 +++ demos/.gitignore | 1 + demos/compile_android.py | 91 +++ demos/dub.json | 3 +- .../external/android/bindbc/loader/package.d | 11 + .../android/bindbc/loader/sharedlib.d | 335 ++++++++++ demos/external/android/bindbc/loader/system.d | 55 ++ demos/external/sources/mmutils/thread_pool.d | 15 + .../wasm_imports/bindbc/sdl/dynload.d | 12 +- .../external/wasm_imports/bindbc/sdl/image.d | 4 +- demos/libs/armeabi-v7a/libcimgui.so | Bin 0 -> 3111272 bytes demos/source/app.d | 68 +- demos/source/demos/space_invaders.d | 2 +- demos/source/game_core/job_updater.d | 12 + demos/utils/dub.json | 3 +- demos/utils/source/ecs_utils/gfx/buffer.d | 12 +- demos/utils/source/ecs_utils/gfx/material.d | 4 +- demos/utils/source/ecs_utils/gfx/mesh.d | 4 +- demos/utils/source/ecs_utils/gfx/renderer.d | 6 + demos/utils/source/ecs_utils/gfx/shader.d | 6 +- demos/utils/source/ecs_utils/gfx/texture.d | 4 +- demos/utils/source/ecs_utils/imgui_bind.d | 598 ++++++++++++++---- demos/utils/source/ecs_utils/utils.d | 8 + meson.build | 35 +- meson_options.txt | 4 +- source/bubel/ecs/id_manager.d | 2 +- source/bubel/ecs/manager.d | 13 +- source/bubel/ecs/std.d | 31 +- tests/tests.d | 111 ++++ 30 files changed, 1358 insertions(+), 173 deletions(-) create mode 100644 compile_android.py create mode 100644 demos/compile_android.py create mode 100644 demos/external/android/bindbc/loader/package.d create mode 100644 demos/external/android/bindbc/loader/sharedlib.d create mode 100644 demos/external/android/bindbc/loader/system.d create mode 100755 demos/libs/armeabi-v7a/libcimgui.so diff --git a/.gitignore b/.gitignore index e595637..636ea36 100644 --- a/.gitignore +++ b/.gitignore @@ -9,4 +9,5 @@ !skeleton.html !meson.build !meson_options.txt -!compile_wasm.py \ No newline at end of file +!compile_wasm.py +!compile_android.py \ No newline at end of file diff --git a/compile_android.py b/compile_android.py new file mode 100644 index 0000000..15f04ea --- /dev/null +++ b/compile_android.py @@ -0,0 +1,78 @@ +import os +import ntpath +import sys + +def compile(sources, output): + files = [] + # r=root, d=directories, f = files + for path in sources: + for r, d, f in os.walk(path): + for file in f: + if ntpath.basename(file) != 'win_dll.d': + filename, file_extension = os.path.splitext(file) + if file_extension == '.d' and filename != 'package': + files.append(os.path.join(r, file)) + + ldc_path = 'ldc' + if 'LDC' in os.environ: + ldc_path = os.environ['LDC'] + + ldc_cmd = ldc_path + ' ' + ldc_flags + '-lib -mtriple=armv7-none-linux-androideabi -fvisibility=hidden -betterC -oq -od=obj/ --singleobj --of=' + output + ' ' + + for path in sources: + ldc_cmd += '-I' + path + ' ' + + for path in import_paths: + ldc_cmd += '-I' + path + ' ' + + for f in files: + ldc_cmd += f + ' ' + + print(ldc_cmd) + + if os.system(ldc_cmd): + exit(0) + print() + +clean = 0 +ldc_flags = '' +import_paths = ['source','tests'] +build_tests = 0 + +for arg in sys.argv[1:]: + if(arg == '-release'): + ldc_flags += '-release ' + elif(arg == '-enable-inlining'): + ldc_flags += '-enable-inlining ' + elif(arg == '-O3'): + ldc_flags += '-O3 ' + elif(arg == '-O2'): + ldc_flags += '-O2 ' + elif(arg == '-O1'): + ldc_flags += '-O1 ' + elif(arg == '-O0'): + ldc_flags += '-O0 ' + elif(arg == '-Os'): + ldc_flags += '-Os ' + elif(arg == '-Oz'): + ldc_flags += '-Oz ' + elif(arg == '-g'): + ldc_flags += '-g ' + elif(arg == '-opt'): + ldc_flags += '-release -enable-inlining -O3 ' + else: + print('unknown argument: ' + arg) + exit() + +compile(['source'], 'ecs.a') + +#export LDC_LIBS=/path/to/your/ldc-build-runtime.tmp/lib/ +CC = os.environ['NDK'] + '/toolchains/llvm/prebuilt/linux-x86_64/bin/clang' +TOOLCHAIN = os.environ['NDK'] + '/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86_64' +SYSROOT = os.environ['NDK'] + '/platforms/android-21/arch-arm' +LDC_LIBS = ''#os.environ['LDC_LIBS'] + '/libphobos2-ldc.a ' + os.environ['LDC_LIBS'] + '/libdruntime-ldc.a' + +os.system(CC + ' -Wl,-soname,libecs.so -shared --sysroot=' + SYSROOT + ' obj/*.o ' + LDC_LIBS + ' -lgcc -gcc-toolchain ' + TOOLCHAIN + +' -no-canonical-prefixes -fuse-ld=bfd -target armv7-none-linux-androideabi -fvisibility=hidden \ +-Wl,--gc-sections -Wl,--fix-cortex-a8 -Wl,--no-undefined -Wl,-z,noexecstack -Wl,-z,relro \ +-Wl,-z,now -mthumb -o libecs.so') diff --git a/demos/.gitignore b/demos/.gitignore index 1ac2a4a..974bbb2 100644 --- a/demos/.gitignore +++ b/demos/.gitignore @@ -14,4 +14,5 @@ !cimgui.bc !emscripten_shell.html !emscripten_multi_shell.html +!compile_android.py .dub \ No newline at end of file diff --git a/demos/compile_android.py b/demos/compile_android.py new file mode 100644 index 0000000..2e3f967 --- /dev/null +++ b/demos/compile_android.py @@ -0,0 +1,91 @@ +import os +import ntpath +import sys + +def compile(sources, output): + files = [] + # r=root, d=directories, f = files + for path in sources: + for r, d, f in os.walk(path): + for file in f: + if ntpath.basename(file) != 'win_dll.d': + filename, file_extension = os.path.splitext(file) + if file_extension == '.d': + files.append(os.path.join(r, file)) + + ldc_path = 'ldc' + if 'LDC' in os.environ: + ldc_path = os.environ['LDC'] + + ldc_cmd = ldc_path + ' ' + ldc_flags + '-lib -mtriple=armv7-none-linux-androideabi -fvisibility=hidden -betterC -oq -od=obj/ --singleobj --of=' + output + ' ' + + for path in sources: + ldc_cmd += '-I' + path + ' ' + + for path in import_paths: + ldc_cmd += '-I' + path + ' ' + + for f in files: + ldc_cmd += f + ' ' + + print(ldc_cmd) + + if os.system(ldc_cmd): + print('some kind of error') + exit(0) + print() + +clean = 0 +ldc_flags = '--d-version=SDL_209 --d-version=BindSDL_Image --d-version=MM_USE_POSIX_THREADS ' +#import_paths = ['source','tests'] +import_paths = ['external','external/sources', 'external/imports', 'external/wasm_imports', '../source', 'utils/source', 'simple/source'] +build_tests = 0 + +for arg in sys.argv[1:]: + if(arg == '-release'): + ldc_flags += '-release ' + elif(arg == '-enable-inlining'): + ldc_flags += '-enable-inlining ' + elif(arg == '-O3'): + ldc_flags += '-O3 ' + elif(arg == '-O2'): + ldc_flags += '-O2 ' + elif(arg == '-O1'): + ldc_flags += '-O1 ' + elif(arg == '-O0'): + ldc_flags += '-O0 ' + elif(arg == '-Os'): + ldc_flags += '-Os ' + elif(arg == '-Oz'): + ldc_flags += '-Oz ' + elif(arg == '-g'): + ldc_flags += '-g ' + elif(arg == '-opt'): + ldc_flags += '-release -enable-inlining -O3 ' + else: + print('unknown argument: ' + arg) + exit() + +#compile(['source'], 'ecs.a') +compile(['external/wasm_imports/bindbc/sdl'], 'build/bindbc-sdl.a') +compile(['utils/source'], 'build/utils.a') +compile(['external/sources/mmutils'], 'build/mmutils.a') +compile(['external/sources/glad'], 'build/glad.a') +compile(['external/android/bindbc'], 'build/bindbc.a') +compile(['source'], 'build/demo.a') + +#compile(['external/wasm_imports/bindbc/sdl','utils/source','external/sources/mmutils','external/sources/glad'], 'build/asd.a') + +#export LDC_LIBS=/path/to/your/ldc-build-runtime.tmp/lib/ +CC = os.environ['NDK'] + '/toolchains/llvm/prebuilt/linux-x86_64/bin/clang' +TOOLCHAIN = os.environ['NDK'] + '/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86_64' +SYSROOT = os.environ['NDK'] + '/platforms/android-21/arch-arm' +#LDC_LIBS = os.environ['LDC_LIBS'] + '/libphobos2-ldc.a ' + os.environ['LDC_LIBS'] + '/libdruntime-ldc.a' +LDC_LIBS = '' +LIBS = '-L/platforms/android-21/arch-arm/usr/lib' + +os.system(CC + ' -Wl,-soname,libdemos.so -shared --sysroot=' + SYSROOT + ' ../obj/*.o obj/*.o ' + LDC_LIBS + ' -lgcc -gcc-toolchain ' + TOOLCHAIN + +' -no-canonical-prefixes -fuse-ld=bfd -target armv7-none-linux-androideabi -fvisibility=hidden \ +-Wl,--gc-sections -Wl,--fix-cortex-a8 -Wl,--no-undefined -Wl,-z,noexecstack -Wl,-z,relro \ +-Wl,-z,now -mthumb -lm -lc -Llibs/armeabi-v7a -lcimgui -o libdemos.so') + diff --git a/demos/dub.json b/demos/dub.json index 1c1fe65..417b831 100644 --- a/demos/dub.json +++ b/demos/dub.json @@ -19,7 +19,8 @@ "libs-linux-x86_64": ["cimgui","SDL2","SDL2_image"], "lflags-linux-x86_64": ["-rpath=libs/linux/x64/","-Llibs/linux/x64/"], "dflags-ldc" : [ - "--ffast-math" + "--ffast-math", + "-enable-cross-module-inlining" ], "configurations" : [ { diff --git a/demos/external/android/bindbc/loader/package.d b/demos/external/android/bindbc/loader/package.d new file mode 100644 index 0000000..3ed4e31 --- /dev/null +++ b/demos/external/android/bindbc/loader/package.d @@ -0,0 +1,11 @@ + +// Copyright Michael D. Parker 2018. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +module bindbc.loader; + +public +import bindbc.loader.sharedlib, + bindbc.loader.system; \ No newline at end of file diff --git a/demos/external/android/bindbc/loader/sharedlib.d b/demos/external/android/bindbc/loader/sharedlib.d new file mode 100644 index 0000000..ab6c444 --- /dev/null +++ b/demos/external/android/bindbc/loader/sharedlib.d @@ -0,0 +1,335 @@ + +// Copyright Michael D. Parker 2018. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +module bindbc.loader.sharedlib; + +import core.stdc.stdlib; +import core.stdc.string; + +/// Handle to a shared library +struct SharedLib { + private void* _handle; +} + +/// Indicates an uninitialized or unassigned handle. +enum invalidHandle = SharedLib.init; + +// Contains information about shared library and symbol load failures. +struct ErrorInfo { +private: + char[32] _error; + char[96] _message; + +public @nogc nothrow @property: + /** + Returns the string "Missing Symbol" to indicate a symbol load failure, and + the name of a library to indicate a library load failure. + */ + const(char)* error() const { return _error.ptr; } + + /** + Returns a symbol name for symbol load failures, and a system-specific error + message for library load failures. + */ + const(char)* message() const { return _message.ptr; } +} + +private { + __gshared ErrorInfo[] _errors; + __gshared size_t _errorCount; +} + +@nogc nothrow: + +/** + Returns an slice containing all errors that have been accumulated by the + `load` and `bindSymbol` functions since the last call to `resetErrors`. +*/ +const(ErrorInfo)[] errors() +{ + return _errors[0 .. _errorCount]; +} + +/** + Returns the total number of errors that have been accumulated by the + `load` and `bindSymbol` functions since the last call to `resetErrors`. +*/ +size_t errorCount() +{ + return _errorCount; +} + +/** + Sets the error count to 0 and erases all accumulated errors. This function + does not release any memory allocated for the error list. +*/ +void resetErrors() +{ + _errorCount = 0; + memset(_errors.ptr, 0, _errors.length * ErrorInfo.sizeof); +} + +/* +void freeErrors() +{ + free(_errors.ptr); + _errors.length = _errorCount = 0; +} +*/ + +/** + Loads a symbol from a shared library and assigns it to a caller-supplied pointer. + + Params: + lib = a valid handle to a shared library loaded via the `load` function. + ptr = a pointer to a function or variable pointer whose declaration is + appropriate for the symbol being bound (it is up to the caller to + verify the types match). + symbolName = the name of the symbol to bind. +*/ +void bindSymbol(SharedLib lib, void** ptr, const(char)* symbolName) +{ + // Without this, DMD can hang in release builds + pragma(inline, false); + + assert(lib._handle); + auto sym = loadSymbol(lib._handle, symbolName); + if(sym) { + *ptr = sym; + } + else { + addErr("Missing Symbol", symbolName); + } +} + +/** + Formats a symbol using the Windows stdcall mangling if necessary before passing it on to + bindSymbol. + + Params: + lib = a valid handle to a shared library loaded via the `load` function. + ptr = a pointer to a function or variable pointer whose declaration is + appropriate for the symbol being bound (it is up to the caller to + verify the types match). + symbolName = the name of the symbol to bind. +*/ +void bindSymbol_stdcall(Func)(SharedLib lib, ref Func f, const(char)* symbolName) +{ + import bindbc.loader.system : bindWindows, bind32; + + static if(bindWindows && bind32) { + import core.stdc.stdio : snprintf; + import std.traits : ParameterTypeTuple; + + uint paramSize(A...)(A args) + { + size_t sum = 0; + foreach(arg; args) { + sum += arg.sizeof; + + // Align on 32-bit stack + if((sum & 3) != 0) { + sum += 4 - (sum & 3); + } + } + return sum; + } + + ParameterTypeTuple!f params; + char[128] mangled; + snprintf(mangled.ptr, mangled.length, "_%s@%d", symbolName, paramSize(params)); + symbolName = mangled.ptr; + } + bindSymbol(lib, cast(void**)&f, symbolName); +} + +/** + Loads a shared library from disk, using the system-specific API and search rules. + + libName = the name of the library to load. May include the full or relative + path for the file. +*/ +SharedLib load(const(char)* libName) +{ + auto handle = loadLib(libName); + if(handle) return SharedLib(handle); + else { + addErr(libName, null); + return invalidHandle; + } +} + +/** + Unloads a shared library from process memory. + + Generally, it is not necessary to call this function at program exit, as the system will ensure + any shared libraries loaded by the process will be unloaded then. However, any loaded shared + libraries that are no longer needed by the program during runtime, such as those that are part + of a "hot swap" mechanism, should be unloaded to free up resources. +*/ +void unload(ref SharedLib lib) { + if(lib._handle) { + unloadLib(lib._handle); + lib = invalidHandle; + } +} + +private: +void allocErrs() { + size_t newSize = _errorCount == 0 ? 16 : _errors.length * 2; + auto errs = cast(ErrorInfo*)malloc(ErrorInfo.sizeof * newSize); + if(!errs) exit(EXIT_FAILURE); + + if(_errorCount > 0) { + memcpy(errs, _errors.ptr, ErrorInfo.sizeof * _errors.length); + free(_errors.ptr); + } + + _errors = errs[0 .. newSize]; +} + +void addErr(const(char)* errstr, const(char)* message) +{ + if(_errors.length == 0 || _errorCount >= _errors.length) { + allocErrs(); + } + + auto pinfo = &_errors[_errorCount]; + strcpy(pinfo._error.ptr, errstr); + + if(message) { + strncpy(pinfo._message.ptr, message, pinfo._message.length); + pinfo._message[pinfo._message.length - 1] = 0; + } + else { + sysError(pinfo._message.ptr, pinfo._message.length); + } + ++_errorCount; +} + +version(Windows) +{ + import core.sys.windows.windows; + extern(Windows) @nogc nothrow alias pSetDLLDirectory = BOOL function(const(char)*); + pSetDLLDirectory setDLLDirectory; + + void* loadLib(const(char)* name) + { + return LoadLibraryA(name); + } + + void unloadLib(void* lib) + { + FreeLibrary(lib); + } + + void* loadSymbol(void* lib, const(char)* symbolName) + { + return GetProcAddress(lib, symbolName); + } + + void sysError(char* buf, size_t len) + { + char* msgBuf; + enum uint langID = MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT); + + FormatMessageA( + FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, + null, + GetLastError(), + langID, + cast(char*)&msgBuf, + 0, + null + ); + + if(msgBuf) { + strncpy(buf, msgBuf, len); + buf[len - 1] = 0; + LocalFree(msgBuf); + } + else strncpy(buf, "Unknown Error\0", len); + } + + /** + Adds a path to the default search path on Windows, replacing the path set in a previous + call to the same function. + + Any path added to this function will be added to the default DLL search path as documented at + https://docs.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-setdlldirectoryw. + + Generally, when loading DLLs on a path that is not on the search path, e.g., from a subdirectory + of the application, the path should be prepended to the DLL name passed to the load function, + e.g., "dlls\\SDL2.dll". If `setCustomLoaderSearchPath(".\\dlls")` is called first, then the subdirectory + will become part of the DLL search path and the path may be omitted from the load function. (Be + aware that ".\\dlls" is relative to the current working directory, which may not be the application + directory, so the path should be built appropriately.) + + Some DLLs may depend on other DLLs, perhaps even attempting to load them dynamically at run time + (e.g., SDL2_image only loads dependencies such as libpng if it is initialized at run time with + PNG support). In this case, if the DLL and its dependencies are placed in a subdirectory and + loaded as e.g., "dlls\\SDL2_image.dll", then it will not be able to find its dependencies; the + system loader will look for them on the regular DLL search path. When that happens, the solution + is to call `setCustomLoaderSearchPath` with the subdirectory before initializing the library. + + Calling this function with `null` as the argument will reset the default search path. + + When the function returns `false`, the relevant `ErrorInfo` is added to the global error list and can + be retrieved by looping through the array returned by the `errors` function. + + When placing DLLs in a subdirectory of the application, it should be considered good practice to + call `setCustomLoaderSearchPath` to ensure all DLLs load properly. It should also be considered good + practice to reset the default search path once all DLLs are loaded. + + This function is only available on Windows, so any usage of it should be preceded with + `version(Windows)`. + + Params: + path = the path to add to the DLL search path, or `null` to reset the default. + + Returns: + `true` if the path was successfully added to the DLL search path, otherwise `false`. + */ + public + bool setCustomLoaderSearchPath(const(char)* path) + { + if(!setDLLDirectory) { + auto lib = load("Kernel32.dll"); + if(lib == invalidHandle) return false; + lib.bindSymbol(cast(void**)&setDLLDirectory, "SetDllDirectoryA"); + if(!setDLLDirectory) return false; + } + return setDLLDirectory(path) != 0; + } +} +else version(Posix) { + import core.sys.posix.dlfcn; + + void* loadLib(const(char)* name) + { + return dlopen(name, RTLD_NOW); + } + + void unloadLib(void* lib) + { + dlclose(lib); + } + + void* loadSymbol(void* lib, const(char)* symbolName) + { + return dlsym(lib, symbolName); + } + + void sysError(char* buf, size_t len) + { + const (char)* msg = dlerror(); + strncpy(buf, msg != null ? msg : "Unknown Error", len); + buf[len - 1] = 0; + } +} +else static assert(0, "bindbc-loader is not implemented on this platform."); \ No newline at end of file diff --git a/demos/external/android/bindbc/loader/system.d b/demos/external/android/bindbc/loader/system.d new file mode 100644 index 0000000..c721100 --- /dev/null +++ b/demos/external/android/bindbc/loader/system.d @@ -0,0 +1,55 @@ + +// Copyright Michael D. Parker 2018. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +module bindbc.loader.system; + +static if((void*).sizeof == 8) { + enum bind64 = true; + enum bind32 = false; +} +else { + enum bind64 = false; + enum bind32 = true; +} + +version(Windows) enum bindWindows = true; +else enum bindWindows = false; + +version(OSX) enum bindMac = true; +else enum bindMac = false; + +version(linux) enum bindLinux = true; +else enum bindLinux = false; + +version(Posix) enum bindPosix = true; +else enum bindPosix = false; + +version(Android) enum bindAndroid = true; +else enum bindAndroid = false; + +enum bindIOS = false; +enum bindWinRT = false; + +version(FreeBSD) { + enum bindBSD = true; + enum bindFreeBSD = true; + enum bindOpenBSD = false; +} +else version(OpenBSD) { + enum bindBSD = true; + enum bindFreeBSD = false; + enum bindOpenBSD = true; +} +else version(BSD) { + enum bindBSD = true; + enum bindFreeBSD = false; + enum bindOpenBSD = false; +} +else { + enum bindBSD = false; + enum bindFreeBSD = false; + enum bindOpenBSD = false; +} \ No newline at end of file diff --git a/demos/external/sources/mmutils/thread_pool.d b/demos/external/sources/mmutils/thread_pool.d index 52136d4..b830026 100644 --- a/demos/external/sources/mmutils/thread_pool.d +++ b/demos/external/sources/mmutils/thread_pool.d @@ -201,6 +201,21 @@ void instructionPause() static assert(0); } } + else version (Android) + { + version(LDC) + { + import ldc.attributes; + @optStrategy("none") + static void nop() + { + int i; + i++; + } + nop(); + } + else static assert(0); + } else version(WebAssembly) { version(LDC) diff --git a/demos/external/wasm_imports/bindbc/sdl/dynload.d b/demos/external/wasm_imports/bindbc/sdl/dynload.d index 0aa3b84..3a15c97 100644 --- a/demos/external/wasm_imports/bindbc/sdl/dynload.d +++ b/demos/external/wasm_imports/bindbc/sdl/dynload.d @@ -14,8 +14,8 @@ import bindbc.sdl.config, bindbc.sdl.bind; private { - SharedLib lib; - SDLSupport loadedVersion; + __gshared SharedLib lib; + __gshared SDLSupport loadedVersion; } void unloadSDL() @@ -664,14 +664,14 @@ SDLSupport loadSDL(const(char)* libName) lib.bindSymbol(cast(void**)&SDL_HasColorKey, "SDL_HasColorKey"); lib.bindSymbol(cast(void**)&SDL_GetDisplayOrientation, "SDL_GetDisplayOrientation"); - version(linux) { - lib.bindSymbol(cast(void**)&SDL_LinuxSetThreadPriority, "SDL_LinuxSetThreadPriority"); - } - else version(Android) { + version(Android) { lib.bindSymbol(cast(void**)&SDL_IsChromebook, "SDL_IsChromebook"); lib.bindSymbol(cast(void**)&SDL_IsDeXMode, "SDL_IsDeXMode"); lib.bindSymbol(cast(void**)&SDL_AndroidBackButton, "SDL_AndroidBackButton"); } + else version(linux) { + lib.bindSymbol(cast(void**)&SDL_LinuxSetThreadPriority, "SDL_LinuxSetThreadPriority"); + } if(errorCount() != errCount) return SDLSupport.badLibrary; else loadedVersion = SDLSupport.sdl209; diff --git a/demos/external/wasm_imports/bindbc/sdl/image.d b/demos/external/wasm_imports/bindbc/sdl/image.d index 8cf160e..8af6e81 100644 --- a/demos/external/wasm_imports/bindbc/sdl/image.d +++ b/demos/external/wasm_imports/bindbc/sdl/image.d @@ -229,8 +229,8 @@ else { } private { - SharedLib lib; - SDLImageSupport loadedVersion; + __gshared SharedLib lib; + __gshared SDLImageSupport loadedVersion; } void unloadSDLImage() diff --git a/demos/libs/armeabi-v7a/libcimgui.so b/demos/libs/armeabi-v7a/libcimgui.so new file mode 100755 index 0000000000000000000000000000000000000000..5dca812e96fa3fd8221c264798d39798416bea16 GIT binary patch literal 3111272 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

      #3}j*GT( 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%0An`Q7_OeqP^ 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£?MMXF+K%Zdl^yW;%8q46;l^ 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

      _At8{<}X2v(%m8jm~aB6m;X*buXz_bl5${!qC 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

      *x6KmdI3m&B#S}du*||fXIq0xSICt@W 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 {UxgxDSs?5a+sKB!Gd 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 YHu^WdvPp93c$EetCF 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

      A0O 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'LL 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

      a< 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
      !uGdojxBf2+Ljd1g3jQVajo32Yl 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

      TW^3)ezJ^s369MWJ1^#2-67^tu3+~UHC?H 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

      M{BL{yiO>7|-T9(# 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 literal 0 HcmV?d00001 diff --git a/demos/source/app.d b/demos/source/app.d index ede93b5..003922b 100644 --- a/demos/source/app.d +++ b/demos/source/app.d @@ -203,12 +203,10 @@ void mainLoop(void* arg) temp_fps = 0; } - SDL_Event event; while (SDL_PollEvent(&event)) { - version(WebAssembly)ImGui_ImplSDL2_ProcessEvent(&event); - else ImGui_ImplSDL2_ProcessEvent(&event); + ImGui_ImplSDL2_ProcessEvent(&event); if(launcher.event)launcher.event(&event); if (event.type == SDL_QUIT || (event.type == SDL_KEYDOWN && event.key.keysym.scancode == SDL_SCANCODE_ESCAPE)) { quit(); @@ -278,7 +276,8 @@ void mainLoop(void* arg) } else { - ImGuiImplOpenGL2NewFrame(); + //ImGuiImplOpenGL2NewFrame(); + ImGui_ImplOpenGL3_NewFrame(); ImGuiImplSDL2NewFrame(launcher.window); } @@ -632,7 +631,9 @@ void mainLoop(void* arg) igRender(); version(WebAssembly)ImGui_ImplOpenGL3_RenderDrawData(igGetDrawData()); - else ImGuiImplOpenGL2RenderDrawData(igGetDrawData()); + else version(Android)ImGui_ImplOpenGL3_RenderDrawData(igGetDrawData()); + else ImGui_ImplOpenGL3_RenderDrawData(igGetDrawData()); + //ImGuiImplOpenGL2RenderDrawData(igGetDrawData()); //launcher.renderer.clear(); //launcher.renderer.present(); @@ -652,15 +653,48 @@ void quit() version(WebAssembly)emscripten_cancel_main_loop(); } -int main(int argc, char** argv) +version(Android) { + export extern (C) int SDL_main(int argc, char** args) + { + return app_main(argc,args); + } + + import ldc.attributes; + + extern (C) __gshared + { + @section(".tdata") + int _tlsstart = 0; + @section(".tcommon") + int _tlsend = 0; + } + +} +else +{ + extern (C) int main(int argc, char** argv) + { + return app_main(argc,argv); + } +} + +int app_main(int argc, char** argv) +//int main(int argc, char** argv) +{ + + version(BindSDL_Static){} + else + { + loadSDL(); + loadSDLImage(); + } if (SDL_Init(SDL_INIT_VIDEO) < 0) { printf("SDL could not initialize! SDL_Error: %s", SDL_GetError()); return -1; } - SDL_version sdl_version; SDL_GetVersion(&sdl_version); printf("SDL version: %u.%u.%u\n",cast(uint)sdl_version.major,cast(uint)sdl_version.minor,cast(uint)sdl_version.patch); @@ -692,6 +726,21 @@ int main(int argc, char** argv) return -3; } } + else version(Android) + { + //gladLoadGL(); + gladLoadGLES2(x => SDL_GL_GetProcAddress(x)); + if(!ImGuiImplSDL2InitForOpenGL(launcher.window,launcher.gl_context)) + { + printf("ImGui initialization failed!"); + return -2; + } + if(!ImGui_ImplOpenGL3_Init("#version 100")) + { + printf("ImGui OpenGL initialization failed!"); + return -3; + } + } else { gladLoadGL(); @@ -700,13 +749,14 @@ int main(int argc, char** argv) printf("ImGui initialization failed!"); return -2; } - if(!ImGuiImplOpenGL2Init()) + //if(!ImGuiImplOpenGL2Init()) + if(!ImGui_ImplOpenGL3_Init("#version 120")) { printf("ImGui OpenGL initialization failed!"); return -3; } } - + ImFontConfig* config = ImFontConfig_ImFontConfig(); ImGuiIO* io = igGetIO(); const ushort* font_ranges = ImFontAtlas_GetGlyphRangesDefault(io.Fonts); diff --git a/demos/source/demos/space_invaders.d b/demos/source/demos/space_invaders.d index 5615f0d..45dd06d 100644 --- a/demos/source/demos/space_invaders.d +++ b/demos/source/demos/space_invaders.d @@ -1392,7 +1392,7 @@ struct UpgradeCollisionSystem if(space_invaders.shoot_grid.test(id, data.location[i], cast(ubyte)(0xFF))) { Entity* entity = launcher.manager.getEntity(id); - if(entity.hasComponent(CShip.component_id)) + if(entity && entity.hasComponent(CShip.component_id)) { launcher.manager.sendEvent(id, EUpgrade()); launcher.manager.removeEntity(data.entity[i].id); diff --git a/demos/source/game_core/job_updater.d b/demos/source/game_core/job_updater.d index 47d2423..025da6e 100644 --- a/demos/source/game_core/job_updater.d +++ b/demos/source/game_core/job_updater.d @@ -37,12 +37,17 @@ struct ECSJobUpdater //pool.unregistExternalThread(thread_data); if(jobs)Mallocator.dispose(jobs); version(WebAssembly)pthread_key_delete(tls_key); + else version(Android)pthread_key_delete(tls_key); } version(WebAssembly) { __gshared pthread_key_t tls_key; } + else version(Android) + { + __gshared pthread_key_t tls_key; + } else static uint thread_id = 0; ThreadPool pool; @@ -105,6 +110,7 @@ struct ECSJobUpdater void onCreate(uint threads_count) { version(WebAssembly)pthread_key_create(&tls_key, null); + else version(Android)pthread_key_create(&tls_key, null); pool.initialize(); thread_data = pool.registerExternalThread(); @@ -116,6 +122,7 @@ struct ECSJobUpdater uint getThreadID() @nogc nothrow { version(WebAssembly)return cast(int)pthread_getspecific(tls_key); + else version(Android)return cast(int)pthread_getspecific(tls_key); else return thread_id; } @@ -200,6 +207,11 @@ struct ECSJobUpdater } else job.execute(); } + else version(Android) + { + pthread_setspecific(tls_key, cast(void*)th_data.threadId); + job.execute(); + } else { updater.thread_id = th_data.threadId; diff --git a/demos/utils/dub.json b/demos/utils/dub.json index d8ecfb1..5302fd8 100644 --- a/demos/utils/dub.json +++ b/demos/utils/dub.json @@ -15,14 +15,13 @@ "../external/sources" ], "dependencies": { - "bindbc-sdl":"0.13.0", + "bindbc-sdl":"0.19.0", "ecs":{"path":"../../"} }, "versions": [ "BindSDL_Image", "SDL_2010" ], - "configurations" : [ { "name" : "default", diff --git a/demos/utils/source/ecs_utils/gfx/buffer.d b/demos/utils/source/ecs_utils/gfx/buffer.d index b11cb85..bfdad62 100644 --- a/demos/utils/source/ecs_utils/gfx/buffer.d +++ b/demos/utils/source/ecs_utils/gfx/buffer.d @@ -2,8 +2,12 @@ module ecs_utils.gfx.buffer; import bubel.ecs.std; -import glad.gl.gl; -import glad.gl.gles2; +//import glad.gl.gl; +//import glad.gl.gles2; + +version(WebAssembly)import glad.gl.gles2; +else version(Android)import glad.gl.gles2; +else import glad.gl.gl; extern(C): @@ -64,13 +68,13 @@ struct Buffer void map(BindTarget target) nothrow { bind(target); - data.map_ptr = glMapBuffer(target,GL_WRITE_ONLY); + version(Android){}else data.map_ptr = glMapBuffer(target,GL_WRITE_ONLY); } void map(uint offset, uint size, BindTarget target, uint flags = MapFlagBits.write | MapFlagBits.flush_explict | MapFlagBits.invalidate_buffer) nothrow { bind(target); - data.map_ptr = glMapBufferRange(target,offset,size,flags); + version(Android){}else data.map_ptr = glMapBufferRange(target,offset,size,flags); } void flush(uint offset, uint size, BindTarget target) nothrow diff --git a/demos/utils/source/ecs_utils/gfx/material.d b/demos/utils/source/ecs_utils/gfx/material.d index fbd88b9..1bde9c8 100644 --- a/demos/utils/source/ecs_utils/gfx/material.d +++ b/demos/utils/source/ecs_utils/gfx/material.d @@ -6,7 +6,9 @@ import bubel.ecs.std; import ecs_utils.gfx.shader; -import glad.gl.gl; +version(WebAssembly)import glad.gl.gles2; +else version(Android)import glad.gl.gles2; +else import glad.gl.gl; //import mutils.serializer.json; diff --git a/demos/utils/source/ecs_utils/gfx/mesh.d b/demos/utils/source/ecs_utils/gfx/mesh.d index 20d5855..e953778 100644 --- a/demos/utils/source/ecs_utils/gfx/mesh.d +++ b/demos/utils/source/ecs_utils/gfx/mesh.d @@ -6,7 +6,9 @@ import bubel.ecs.std; import ecs_utils.gfx.buffer; -import glad.gl.gl; +version(WebAssembly)import glad.gl.gles2; +else version(Android)import glad.gl.gles2; +else import glad.gl.gl; //import mutils.serializer.json; extern(C): diff --git a/demos/utils/source/ecs_utils/gfx/renderer.d b/demos/utils/source/ecs_utils/gfx/renderer.d index fcd6a88..93d009e 100644 --- a/demos/utils/source/ecs_utils/gfx/renderer.d +++ b/demos/utils/source/ecs_utils/gfx/renderer.d @@ -12,6 +12,7 @@ import ecs_utils.math.vector; import bubel.ecs.block_allocator; import bubel.ecs.vector; version(WebAssembly)import glad.gl.gles2; +else version(Android)import glad.gl.gles2; else import glad.gl.gl; version = ver1; @@ -637,6 +638,7 @@ struct Renderer if(threads[thread_id].block.items >= VertexBlock.max_items) { //pushBlock(threads[thread_id].block); + prepared_items += threads[thread_id].block.items; threads[thread_id].blocks.add(threads[thread_id].block); threads[thread_id].block = getBlock(); } @@ -667,6 +669,10 @@ struct Renderer { glDepthRangef(0,1); } + else version(Android) + { + glDepthRangef(0,1); + } else { glDepthRange(0,1); diff --git a/demos/utils/source/ecs_utils/gfx/shader.d b/demos/utils/source/ecs_utils/gfx/shader.d index 5e24d9a..e941289 100644 --- a/demos/utils/source/ecs_utils/gfx/shader.d +++ b/demos/utils/source/ecs_utils/gfx/shader.d @@ -4,7 +4,9 @@ import bindbc.sdl; import bubel.ecs.std; -import glad.gl.gl; +version(WebAssembly)import glad.gl.gles2; +else version(Android)import glad.gl.gles2; +else import glad.gl.gl; //version = ver1; @@ -67,10 +69,12 @@ struct Shader } version(WebAssembly)const char* glsl = "#version 100\n"; + else version(Android)const char* glsl = "#version 100\n"; else const char* glsl = "#version 330\n"; const char* buffer = data.code.ptr; char* ver; version(WebAssembly)ver = cast(char*)"#define ver1 1\n#define GLES\n".ptr; + else version(Android)ver = cast(char*)"#define ver1 1\n#define GLES\n".ptr; else ver = cast(char*)"#define ver1 1\n".ptr; /*switch(__ecs_used_technique) { diff --git a/demos/utils/source/ecs_utils/gfx/texture.d b/demos/utils/source/ecs_utils/gfx/texture.d index d4e2089..7affed3 100644 --- a/demos/utils/source/ecs_utils/gfx/texture.d +++ b/demos/utils/source/ecs_utils/gfx/texture.d @@ -6,7 +6,9 @@ import bubel.ecs.std; import ecs_utils.math.vector; -import glad.gl.gl; +version(WebAssembly)import glad.gl.gles2; +else version(Android)import glad.gl.gles2; +else import glad.gl.gl; extern(C): diff --git a/demos/utils/source/ecs_utils/imgui_bind.d b/demos/utils/source/ecs_utils/imgui_bind.d index b6572cb..a65b6b2 100644 --- a/demos/utils/source/ecs_utils/imgui_bind.d +++ b/demos/utils/source/ecs_utils/imgui_bind.d @@ -22,7 +22,9 @@ else : import bindbc.sdl; -import glad.gl.gl; +version(WebAssembly)import glad.gl.gles2; +else version(Android)import glad.gl.gles2; +else import glad.gl.gl; import cimgui.cimgui; @@ -210,7 +212,7 @@ static void ImGui_ImplSDL2_UpdateMousePosAndButtons() // SDL_CaptureMouse() let the OS know e.g. that our imgui drag outside the SDL window boundaries shouldn't e.g. trigger the OS window resize cursor. // The function is only supported from SDL 2.0.4 (released Jan 2016) - bool any_mouse_button_down = ImGui::IsAnyMouseDown(); + bool any_mouse_button_down = ImGui.IsAnyMouseDown(); SDL_CaptureMouse(any_mouse_button_down ? SDL_TRUE : SDL_FALSE); //#else*/ if (SDL_GetWindowFlags(g_Window) & SDL_WINDOW_INPUT_FOCUS) @@ -291,10 +293,11 @@ void ImGuiImplSDL2NewFrame(SDL_Window* window) int w, h; int display_w, display_h; SDL_GetWindowSize(window, &w, &h); - SDL_GL_GetDrawableSize(window, &display_w, &display_h); + // SDL_GL_GetDrawableSize(window, &display_w, &display_h); FIXME: you see io.DisplaySize = ImVec2(cast(float)w, cast(float)h); - if (w > 0 && h > 0) - io.DisplayFramebufferScale = ImVec2(cast(float)display_w / w, cast(float)display_h / h); + // if (w > 0 && h > 0) + // io.DisplayFramebufferScale = ImVec2(cast(float)display_w / w, cast(float)display_h / h); + io.DisplayFramebufferScale = ImVec2(1,1); // Setup time step (we don't use SDL_GetTicks() because it is using millisecond resolution) frequency = SDL_GetPerformanceFrequency(); @@ -310,89 +313,460 @@ void ImGuiImplSDL2NewFrame(SDL_Window* window) } +__gshared GLuint g_GlVersion = 0; // Extracted at runtime using GL_MAJOR_VERSION, GL_MINOR_VERSION queries (e.g. 320 for GL 3.2) +__gshared char[32] g_GlslVersionString = ""; // Specified by user or detected based on compile time GL settings. +//__gshared GLuint g_FontTexture = 0; +__gshared GLuint g_ShaderHandle = 0, g_VertHandle = 0, g_FragHandle = 0; +__gshared int g_AttribLocationTex = 0, g_AttribLocationProjMtx = 0; // Uniforms location +__gshared int g_AttribLocationVtxPos = 0, g_AttribLocationVtxUV = 0, g_AttribLocationVtxColor = 0; // Vertex attributes location +__gshared uint g_VboHandle = 0, g_ElementsHandle = 0; - - - - - - - -bool ImGuiImplOpenGL2Init() +bool ImGui_ImplOpenGL3_Init(const char* glsl_version) { // Setup back-end capabilities flags ImGuiIO* io = igGetIO(); - io.BackendRendererName = "imgui_impl_opengl2"; + io.BackendRendererName = "imgui_impl_opengl3"; + + + // Store GLSL version string so we can refer to it later in case we recreate shaders. + // Note: GLSL version is NOT the same as GL version. Leave this to null if unsure. +/*#if defined(IMGUI_IMPL_OPENGL_ES2) + if (glsl_version == null) + glsl_version = "#version 100"; +#elif defined(IMGUI_IMPL_OPENGL_ES3) + if (glsl_version == null) + glsl_version = "#version 300 es"; +#elif defined(__APPLE__) + if (glsl_version == null) + glsl_version = "#version 150"; +#else + if (glsl_version == null) + glsl_version = "#version 130"; +#endif + IM_ASSERT((int)strlen(glsl_version) + 2 < IM_ARRAYSIZE(g_GlslVersionString));*/ + //const (char)*glsl_version = "#version 100"; + import core.stdc.string; + strcpy(g_GlslVersionString.ptr, glsl_version); + strcat(g_GlslVersionString.ptr, "\n"); + + // Dummy construct to make it easily visible in the IDE and debugger which GL loader has been selected. + // The code actually never uses the 'gl_loader' variable! It is only here so you can read it! + // If auto-detection fails or doesn't select the same GL loader file as used by your application, + // you are likely to get a crash below. + // You can explicitly select a loader by using '#define IMGUI_IMPL_OPENGL_LOADER_XXX' in imconfig.h or compiler command-line. + /*const char* gl_loader = "Unknown"; + IM_UNUSED(gl_loader); +#if defined(IMGUI_IMPL_OPENGL_LOADER_GL3W) + gl_loader = "GL3W"; +#elif defined(IMGUI_IMPL_OPENGL_LOADER_GLEW) + gl_loader = "GLEW"; +#elif defined(IMGUI_IMPL_OPENGL_LOADER_GLAD) + gl_loader = "GLAD"; +#elif defined(IMGUI_IMPL_OPENGL_LOADER_GLBINDING2) + gl_loader = "glbinding2"; +#elif defined(IMGUI_IMPL_OPENGL_LOADER_GLBINDING3) + gl_loader = "glbinding3"; +#elif defined(IMGUI_IMPL_OPENGL_LOADER_CUSTOM) + gl_loader = "custom"; +#else + gl_loader = "none"; +#endif*/ + + // Make a dummy GL call (we don't actually need the result) + // IF YOU GET A CRASH HERE: it probably means that you haven't initialized the OpenGL function loader used by this code. + // Desktop OpenGL 3/4 need a function loader. See the IMGUI_IMPL_OPENGL_LOADER_xxx explanation above. + /*GLint current_texture; + glGetIntegerv(GL_TEXTURE_BINDING_2D, ¤t_texture);*/ + return true; } -void ImGuiImplOpenGL2Shutdown() +static void ImGui_ImplOpenGL3_SetupRenderState(ImDrawData* draw_data, int fb_width, int fb_height, GLuint vertex_array_object) { - ImGuiImplOpenGL2DestroyDeviceObjects(); -} - -void ImGuiImplOpenGL2NewFrame() -{ - if (!g_FontTexture) - ImGuiImplOpenGL2CreateDeviceObjects(); -} - -static void ImGuiImplOpenGL2SetupRenderState(ImDrawData* draw_data, int fb_width, int fb_height) -{ - // Setup render state: alpha-blending enabled, no face culling, no depth testing, scissor enabled, vertex/texcoord/color pointers, polygon fill. + // Setup render state: alpha-blending enabled, no face culling, no depth testing, scissor enabled, polygon fill glEnable(GL_BLEND); + glBlendEquation(GL_FUNC_ADD); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glDisable(GL_CULL_FACE); glDisable(GL_DEPTH_TEST); - //glDisable(GL_LIGHTING); - //glDisable(GL_COLOR_MATERIAL); glEnable(GL_SCISSOR_TEST); - glEnableClientState(GL_VERTEX_ARRAY); - glEnableClientState(GL_TEXTURE_COORD_ARRAY); - glEnableClientState(GL_COLOR_ARRAY); - glEnable(GL_TEXTURE_2D); - glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); +// #ifdef GL_POLYGON_MODE +// glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); +// #endif - // If you are using this code with non-legacy OpenGL header/contexts (which you should not, prefer using imgui_impl_opengl3.cpp!!), - // you may need to backup/reset/restore current shader using the lines below. DO NOT MODIFY THIS FILE! Add the code in your calling function: - // GLint last_program; - // glGetIntegerv(GL_CURRENT_PROGRAM, &last_program); - // glUseProgram(0); - // ImGui_ImplOpenGL2_RenderDrawData(...); - // glUseProgram(last_program) + // Support for GL 4.5 rarely used glClipControl(GL_UPPER_LEFT) + bool clip_origin_lower_left = true; +// #if defined(GL_CLIP_ORIGIN) && !defined(__APPLE__) +// GLenum current_clip_origin = 0; glGetIntegerv(GL_CLIP_ORIGIN, (GLint*)¤t_clip_origin); +// if (current_clip_origin == GL_UPPER_LEFT) +// clip_origin_lower_left = false; +// #endif // Setup viewport, orthographic projection matrix // Our visible imgui space lies from draw_data.DisplayPos (top left) to draw_data.DisplayPos+data_data.DisplaySize (bottom right). DisplayPos is (0,0) for single viewport apps. glViewport(0, 0, cast(GLsizei)fb_width, cast(GLsizei)fb_height); - glMatrixMode(GL_PROJECTION); - glPushMatrix(); - glLoadIdentity(); - glOrtho(draw_data.DisplayPos.x, draw_data.DisplayPos.x + draw_data.DisplaySize.x, draw_data.DisplayPos.y + draw_data.DisplaySize.y, draw_data.DisplayPos.y, -1.0f, +1.0f); - glMatrixMode(GL_MODELVIEW); - glPushMatrix(); - glLoadIdentity(); + float L = draw_data.DisplayPos.x; + float R = draw_data.DisplayPos.x + draw_data.DisplaySize.x; + float T = draw_data.DisplayPos.y; + float B = draw_data.DisplayPos.y + draw_data.DisplaySize.y; + if (!clip_origin_lower_left) { float tmp = T; T = B; B = tmp; } // Swap top and bottom if origin is upper left + const float[4][4] ortho_projection = + [ + [ 2.0f/(R-L), 0.0f, 0.0f, 0.0f ], + [ 0.0f, 2.0f/(T-B), 0.0f, 0.0f ], + [ 0.0f, 0.0f, -1.0f, 0.0f ], + [ (R+L)/(L-R), (T+B)/(B-T), 0.0f, 1.0f ], + ]; + glUseProgram(g_ShaderHandle); + glUniform1i(g_AttribLocationTex, 0); + glUniformMatrix4fv(g_AttribLocationProjMtx, 1, GL_FALSE, &ortho_projection[0][0]); +// #ifdef GL_SAMPLER_BINDING +// glBindSampler(0, 0); // We use combined texture/sampler state. Applications using GL 3.3 may set that otherwise. +// #endif + +// (void)vertex_array_object; +// #ifndef IMGUI_IMPL_OPENGL_ES2 +// glBindVertexArray(vertex_array_object); +// #endif + + // Bind vertex/index buffers and setup attributes for ImDrawVert + glBindBuffer(GL_ARRAY_BUFFER, g_VboHandle); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, g_ElementsHandle); + glEnableVertexAttribArray(g_AttribLocationVtxPos); + glEnableVertexAttribArray(g_AttribLocationVtxUV); + glEnableVertexAttribArray(g_AttribLocationVtxColor); + glVertexAttribPointer(g_AttribLocationVtxPos, 2, GL_FLOAT, GL_FALSE, ImDrawVert.sizeof, cast(GLvoid*)ImDrawVert.pos.offsetof); + glVertexAttribPointer(g_AttribLocationVtxUV, 2, GL_FLOAT, GL_FALSE, ImDrawVert.sizeof, cast(GLvoid*)ImDrawVert.uv.offsetof); + glVertexAttribPointer(g_AttribLocationVtxColor, 4, GL_UNSIGNED_BYTE, GL_TRUE, ImDrawVert.sizeof, cast(GLvoid*)ImDrawVert.col.offsetof); } -// OpenGL2 Render function. -// (this used to be set in io.RenderDrawListsFn and called by ImGui::Render(), but you can now call this directly from your main loop) -// Note that this implementation is little overcomplicated because we are saving/setting up/restoring every OpenGL state explicitly, in order to be able to run within any OpenGL engine that doesn't do so. -void ImGuiImplOpenGL2RenderDrawData(ImDrawData* draw_data) + +void ImGui_ImplOpenGL3_Shutdown() +{ + ImGui_ImplOpenGL3_DestroyDeviceObjects(); +} + +void ImGui_ImplOpenGL3_NewFrame() +{ + if (!g_ShaderHandle) + ImGui_ImplOpenGL3_CreateDeviceObjects(); +} + +bool ImGui_ImplOpenGL3_CreateDeviceObjects() +{ + // Backup GL state + GLint last_texture, last_array_buffer; + glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture); + glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &last_array_buffer); +// #ifndef IMGUI_IMPL_OPENGL_ES2 +// GLint last_vertex_array; +// glGetIntegerv(GL_VERTEX_ARRAY_BINDING, &last_vertex_array); +// #endif + + // Parse GLSL version string + import core.stdc.stdio; + int glsl_version = 130; + sscanf(g_GlslVersionString.ptr, "#version %d", &glsl_version); + + const GLchar* vertex_shader_glsl_120 = + "uniform mat4 ProjMtx;\n + attribute vec2 Position;\n + attribute vec2 UV;\n + attribute vec4 Color;\n + varying vec2 Frag_UV;\n + varying vec4 Frag_Color;\n + void main()\n + {\n + Frag_UV = UV;\n + Frag_Color = Color;\n + gl_Position = ProjMtx * vec4(Position.xy,0,1);\n + }\n"; + + const GLchar* vertex_shader_glsl_130 = + "uniform mat4 ProjMtx;\n + in vec2 Position;\n + in vec2 UV;\n + in vec4 Color;\n + out vec2 Frag_UV;\n + out vec4 Frag_Color;\n + void main()\n + {\n + Frag_UV = UV;\n + Frag_Color = Color;\n + gl_Position = ProjMtx * vec4(Position.xy,0,1);\n + }\n"; + + const GLchar* vertex_shader_glsl_300_es = + "precision mediump float;\n + layout (location = 0) in vec2 Position;\n + layout (location = 1) in vec2 UV;\n + layout (location = 2) in vec4 Color;\n + uniform mat4 ProjMtx;\n + out vec2 Frag_UV;\n + out vec4 Frag_Color;\n + void main()\n + {\n + Frag_UV = UV;\n + Frag_Color = Color;\n + gl_Position = ProjMtx * vec4(Position.xy,0,1);\n + }\n"; + + const GLchar* vertex_shader_glsl_410_core = + "layout (location = 0) in vec2 Position;\n + layout (location = 1) in vec2 UV;\n + layout (location = 2) in vec4 Color;\n + uniform mat4 ProjMtx;\n + out vec2 Frag_UV;\n + out vec4 Frag_Color;\n + void main()\n + {\n + Frag_UV = UV;\n + Frag_Color = Color;\n + gl_Position = ProjMtx * vec4(Position.xy,0,1);\n + }\n"; + + const GLchar* fragment_shader_glsl_120 = + "#ifdef GL_ES\n + precision mediump float;\n + #endif\n + uniform sampler2D Texture;\n + varying vec2 Frag_UV;\n + varying vec4 Frag_Color;\n + void main()\n + {\n + gl_FragColor = Frag_Color * texture2D(Texture, Frag_UV.st);\n + }\n"; + + const GLchar* fragment_shader_glsl_130 = + "uniform sampler2D Texture;\n + in vec2 Frag_UV;\n + in vec4 Frag_Color;\n + out vec4 Out_Color;\n + void main()\n + {\n + Out_Color = Frag_Color * texture(Texture, Frag_UV.st);\n + }\n"; + + const GLchar* fragment_shader_glsl_300_es = + "precision mediump float;\n + uniform sampler2D Texture;\n + in vec2 Frag_UV;\n + in vec4 Frag_Color;\n + layout (location = 0) out vec4 Out_Color;\n + void main()\n + {\n + Out_Color = Frag_Color * texture(Texture, Frag_UV.st);\n + }\n"; + + const GLchar* fragment_shader_glsl_410_core = + "in vec2 Frag_UV;\n + in vec4 Frag_Color;\n + uniform sampler2D Texture;\n + layout (location = 0) out vec4 Out_Color;\n + void main()\n + {\n + Out_Color = Frag_Color * texture(Texture, Frag_UV.st);\n + }\n"; + + // Select shaders matching our GLSL versions + const (char)* vertex_shader = null; + const (char)* fragment_shader = null; + if (glsl_version < 130) + { + vertex_shader = vertex_shader_glsl_120; + fragment_shader = fragment_shader_glsl_120; + } + else if (glsl_version >= 410) + { + vertex_shader = vertex_shader_glsl_410_core; + fragment_shader = fragment_shader_glsl_410_core; + } + else if (glsl_version == 300) + { + vertex_shader = vertex_shader_glsl_300_es; + fragment_shader = fragment_shader_glsl_300_es; + } + else + { + vertex_shader = vertex_shader_glsl_130; + fragment_shader = fragment_shader_glsl_130; + } + + // Create shaders + const (char)*[2] vertex_shader_with_version = [ g_GlslVersionString.ptr, vertex_shader ]; + g_VertHandle = glCreateShader(GL_VERTEX_SHADER); + glShaderSource(g_VertHandle, 2, vertex_shader_with_version.ptr, null); + glCompileShader(g_VertHandle); + CheckShader(g_VertHandle, "vertex shader"); + + const (char)*[2] fragment_shader_with_version = [ g_GlslVersionString.ptr, fragment_shader ]; + g_FragHandle = glCreateShader(GL_FRAGMENT_SHADER); + glShaderSource(g_FragHandle, 2, fragment_shader_with_version.ptr, null); + glCompileShader(g_FragHandle); + CheckShader(g_FragHandle, "fragment shader"); + + g_ShaderHandle = glCreateProgram(); + glAttachShader(g_ShaderHandle, g_VertHandle); + glAttachShader(g_ShaderHandle, g_FragHandle); + glLinkProgram(g_ShaderHandle); + CheckProgram(g_ShaderHandle, "shader program"); + + g_AttribLocationTex = glGetUniformLocation(g_ShaderHandle, "Texture"); + g_AttribLocationProjMtx = glGetUniformLocation(g_ShaderHandle, "ProjMtx"); + g_AttribLocationVtxPos = glGetAttribLocation(g_ShaderHandle, "Position"); + g_AttribLocationVtxUV = glGetAttribLocation(g_ShaderHandle, "UV"); + g_AttribLocationVtxColor = glGetAttribLocation(g_ShaderHandle, "Color"); + + // Create buffers + glGenBuffers(1, &g_VboHandle); + glGenBuffers(1, &g_ElementsHandle); + + ImGui_ImplOpenGL3_CreateFontsTexture(); + + // Restore modified GL state + glBindTexture(GL_TEXTURE_2D, last_texture); + glBindBuffer(GL_ARRAY_BUFFER, last_array_buffer); +// #ifndef IMGUI_IMPL_OPENGL_ES2 +// glBindVertexArray(last_vertex_array); +// #endif + + return true; +} + +void ImGui_ImplOpenGL3_DestroyDeviceObjects() +{ + if (g_VboHandle) { glDeleteBuffers(1, &g_VboHandle); g_VboHandle = 0; } + if (g_ElementsHandle) { glDeleteBuffers(1, &g_ElementsHandle); g_ElementsHandle = 0; } + if (g_ShaderHandle && g_VertHandle) { glDetachShader(g_ShaderHandle, g_VertHandle); } + if (g_ShaderHandle && g_FragHandle) { glDetachShader(g_ShaderHandle, g_FragHandle); } + if (g_VertHandle) { glDeleteShader(g_VertHandle); g_VertHandle = 0; } + if (g_FragHandle) { glDeleteShader(g_FragHandle); g_FragHandle = 0; } + if (g_ShaderHandle) { glDeleteProgram(g_ShaderHandle); g_ShaderHandle = 0; } + + ImGui_ImplOpenGL3_DestroyFontsTexture(); +} + +static bool CheckShader(GLuint handle, const char* desc) +{ + GLint status = 0, log_length = 0; + glGetShaderiv(handle, GL_COMPILE_STATUS, &status); + glGetShaderiv(handle, GL_INFO_LOG_LENGTH, &log_length); + /*if (cast(GLboolean)status == GL_FALSE) + fprintf(stderr, "ERROR: ImGui_ImplOpenGL3_CreateDeviceObjects: failed to compile %s!\n", desc); + if (log_length > 1) + { + ImVector buf; + buf.resize(cast(int)(log_length + 1)); + glGetShaderInfoLog(handle, log_length, null, cast(GLchar*)buf.begin()); + fprintf(stderr, "%s\n", buf.begin()); + }*/ + return cast(GLboolean)status == GL_TRUE; +} + +// If you get an error please report on GitHub. You may try different GL context version or GLSL version. +static bool CheckProgram(GLuint handle, const char* desc) +{ + GLint status = 0, log_length = 0; + glGetProgramiv(handle, GL_LINK_STATUS, &status); + glGetProgramiv(handle, GL_INFO_LOG_LENGTH, &log_length); + /*if (cast(GLboolean)status == GL_FALSE) + fprintf(stderr, "ERROR: ImGui_ImplOpenGL3_CreateDeviceObjects: failed to link %s! (with GLSL '%s')\n", desc, g_GlslVersionString); + if (log_length > 1) + { + ImVector buf; + buf.resize(cast(int)(log_length + 1)); + glGetProgramInfoLog(handle, log_length, null, cast(GLchar*)buf.begin()); + fprintf(stderr, "%s\n", buf.begin()); + }*/ + return cast(GLboolean)status == GL_TRUE; +} + +bool ImGui_ImplOpenGL3_CreateFontsTexture() +{ + // Build texture atlas + ImGuiIO* io = igGetIO(); + ubyte* pixels; + int width, height, bpp; + + ImFontAtlas_GetTexDataAsRGBA32(io.Fonts,&pixels, &width, &height, &bpp); + //io.Fonts.GetTexDataAsRGBA32(&pixels, &width, &height); // Load as RGBA 32-bit (75% of the memory is wasted, but default font is so small) because it is more likely to be compatible with user's existing shaders. If your ImTextureId represent a higher-level concept than just a GL texture id, consider calling GetTexDataAsAlpha8() instead to save on GPU memory. + + // Upload texture to graphics system + GLint last_texture; + glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture); + glGenTextures(1, &g_FontTexture); + glBindTexture(GL_TEXTURE_2D, g_FontTexture); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); +// #ifdef GL_UNPACK_ROW_LENGTH +// glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); +// #endif + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels); + + // Store our identifier + io.Fonts.TexID = cast(ImTextureID)cast(sizediff_t)g_FontTexture; + + // Restore state + glBindTexture(GL_TEXTURE_2D, last_texture); + + return true; +} + +void ImGui_ImplOpenGL3_DestroyFontsTexture() +{ + if (g_FontTexture) + { + ImGuiIO* io = igGetIO(); + glDeleteTextures(1, &g_FontTexture); + io.Fonts.TexID = null; + g_FontTexture = 0; + } +} + +void ImGui_ImplOpenGL3_RenderDrawData(ImDrawData* draw_data) { // Avoid rendering when minimized, scale coordinates for retina displays (screen coordinates != framebuffer coordinates) int fb_width = cast(int)(draw_data.DisplaySize.x * draw_data.FramebufferScale.x); int fb_height = cast(int)(draw_data.DisplaySize.y * draw_data.FramebufferScale.y); - if (fb_width == 0 || fb_height == 0) + if (fb_width <= 0 || fb_height <= 0) return; // Backup GL state + GLenum last_active_texture; glGetIntegerv(GL_ACTIVE_TEXTURE, cast(GLint*)&last_active_texture); + glActiveTexture(GL_TEXTURE0); + GLint last_program; glGetIntegerv(GL_CURRENT_PROGRAM, &last_program); GLint last_texture; glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture); - GLint[2] last_polygon_mode; glGetIntegerv(GL_POLYGON_MODE, last_polygon_mode.ptr); +// #ifdef GL_SAMPLER_BINDING +// GLint last_sampler; glGetIntegerv(GL_SAMPLER_BINDING, &last_sampler); +// #endif + GLint last_array_buffer; glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &last_array_buffer); +// #ifndef IMGUI_IMPL_OPENGL_ES2 +// GLint last_vertex_array_object; glGetIntegerv(GL_VERTEX_ARRAY_BINDING, &last_vertex_array_object); +// #endif +// #ifdef GL_POLYGON_MODE +// GLint last_polygon_mode[2]; glGetIntegerv(GL_POLYGON_MODE, last_polygon_mode); +// #endif GLint[4] last_viewport; glGetIntegerv(GL_VIEWPORT, last_viewport.ptr); GLint[4] last_scissor_box; glGetIntegerv(GL_SCISSOR_BOX, last_scissor_box.ptr); - glPushAttrib(GL_ENABLE_BIT | GL_COLOR_BUFFER_BIT | GL_TRANSFORM_BIT); + GLenum last_blend_src_rgb; glGetIntegerv(GL_BLEND_SRC_RGB, cast(GLint*)&last_blend_src_rgb); + GLenum last_blend_dst_rgb; glGetIntegerv(GL_BLEND_DST_RGB, cast(GLint*)&last_blend_dst_rgb); + GLenum last_blend_src_alpha; glGetIntegerv(GL_BLEND_SRC_ALPHA, cast(GLint*)&last_blend_src_alpha); + GLenum last_blend_dst_alpha; glGetIntegerv(GL_BLEND_DST_ALPHA, cast(GLint*)&last_blend_dst_alpha); + GLenum last_blend_equation_rgb; glGetIntegerv(GL_BLEND_EQUATION_RGB, cast(GLint*)&last_blend_equation_rgb); + GLenum last_blend_equation_alpha; glGetIntegerv(GL_BLEND_EQUATION_ALPHA, cast(GLint*)&last_blend_equation_alpha); + GLboolean last_enable_blend = glIsEnabled(GL_BLEND); + GLboolean last_enable_cull_face = glIsEnabled(GL_CULL_FACE); + GLboolean last_enable_depth_test = glIsEnabled(GL_DEPTH_TEST); + GLboolean last_enable_scissor_test = glIsEnabled(GL_SCISSOR_TEST); // Setup desired GL state - ImGuiImplOpenGL2SetupRenderState(draw_data, fb_width, fb_height); + // Recreate the VAO every time (this is to easily allow multiple GL contexts to be rendered to. VAO are not shared among GL contexts) + // The renderer would actually work without any VAO bound, but then our VertexAttrib calls would overwrite the default one currently bound. + GLuint vertex_array_object = 0; +// #ifndef IMGUI_IMPL_OPENGL_ES2 +// glGenVertexArrays(1, &vertex_array_object); +// #endif + ImGui_ImplOpenGL3_SetupRenderState(draw_data, fb_width, fb_height, vertex_array_object); // Will project scissor/clipping rectangles into framebuffer space ImVec2 clip_off = draw_data.DisplayPos; // (0,0) unless using multi-viewports @@ -401,23 +775,22 @@ void ImGuiImplOpenGL2RenderDrawData(ImDrawData* draw_data) // Render command lists for (int n = 0; n < draw_data.CmdListsCount; n++) { - ImDrawList* cmd_list = draw_data.CmdLists[n]; - ImDrawVert* vtx_buffer = cmd_list.VtxBuffer.Data; - ImDrawIdx* idx_buffer = cmd_list.IdxBuffer.Data; - glVertexPointer(2, GL_FLOAT, ImDrawVert.sizeof, cast(const GLvoid*)(cast(const char*)vtx_buffer + ImDrawVert.pos.offsetof)); - glTexCoordPointer(2, GL_FLOAT, ImDrawVert.sizeof, cast(const GLvoid*)(cast(const char*)vtx_buffer + ImDrawVert.uv.offsetof)); - glColorPointer(4, GL_UNSIGNED_BYTE, ImDrawVert.sizeof, cast(const GLvoid*)(cast(const char*)vtx_buffer + ImDrawVert.col.offsetof)); + const ImDrawList* cmd_list = draw_data.CmdLists[n]; + + // Upload vertex/index buffers + glBufferData(GL_ARRAY_BUFFER, cast(GLsizeiptr)cmd_list.VtxBuffer.Size * ImDrawVert.sizeof, cast(const GLvoid*)cmd_list.VtxBuffer.Data, GL_STREAM_DRAW); + glBufferData(GL_ELEMENT_ARRAY_BUFFER, cast(GLsizeiptr)cmd_list.IdxBuffer.Size * ImDrawIdx.sizeof, cast(const GLvoid*)cmd_list.IdxBuffer.Data, GL_STREAM_DRAW); for (int cmd_i = 0; cmd_i < cmd_list.CmdBuffer.Size; cmd_i++) { const ImDrawCmd* pcmd = &cmd_list.CmdBuffer.Data[cmd_i]; - if (pcmd.UserCallback) + if (pcmd.UserCallback != null) { // User callback, registered via ImDrawList::AddCallback() // (ImDrawCallback_ResetRenderState is a special callback value used by the user to request the renderer to reset render state.) - /*if (pcmd.UserCallback == &ImDrawCallback_ResetRenderState) - ImGui_ImplOpenGL2_SetupRenderState(draw_data, fb_width, fb_height); - else*/ + // if (pcmd.UserCallback == ImDrawCallback_ResetRenderState) + // ImGui_ImplOpenGL3_SetupRenderState(draw_data, fb_width, fb_height, vertex_array_object); + // else pcmd.UserCallback(cmd_list, pcmd); } else @@ -435,74 +808,43 @@ void ImGuiImplOpenGL2RenderDrawData(ImDrawData* draw_data) glScissor(cast(int)clip_rect.x, cast(int)(fb_height - clip_rect.w), cast(int)(clip_rect.z - clip_rect.x), cast(int)(clip_rect.w - clip_rect.y)); // Bind texture, Draw - glBindTexture(GL_TEXTURE_2D, cast(GLuint)pcmd.TextureId); - glDrawElements(GL_TRIANGLES, cast(GLsizei)pcmd.ElemCount, ImDrawIdx.sizeof == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT, idx_buffer); + glBindTexture(GL_TEXTURE_2D, cast(GLuint)cast(sizediff_t)pcmd.TextureId); +// #if IMGUI_IMPL_OPENGL_MAY_HAVE_VTX_OFFSET +// if (g_GlVersion >= 320) +// glDrawElementsBaseVertex(GL_TRIANGLES, (GLsizei)pcmd.ElemCount, sizeof(ImDrawIdx) == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT, (void*)(intptr_t)(pcmd.IdxOffset * sizeof(ImDrawIdx)), (GLint)pcmd.VtxOffset); +// else +// #endif + glDrawElements(GL_TRIANGLES, cast(GLsizei)pcmd.ElemCount, ImDrawIdx.sizeof == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT, cast(void*)cast(sizediff_t)(pcmd.IdxOffset * ImDrawIdx.sizeof)); } } - idx_buffer += pcmd.ElemCount; } } + // Destroy the temporary VAO +// #ifndef IMGUI_IMPL_OPENGL_ES2 +// glDeleteVertexArrays(1, &vertex_array_object); +// #endif + // Restore modified GL state - glDisableClientState(GL_COLOR_ARRAY); - glDisableClientState(GL_TEXTURE_COORD_ARRAY); - glDisableClientState(GL_VERTEX_ARRAY); - glBindTexture(GL_TEXTURE_2D, cast(GLuint)last_texture); - glMatrixMode(GL_MODELVIEW); - glPopMatrix(); - glMatrixMode(GL_PROJECTION); - glPopMatrix(); - glPopAttrib(); - glPolygonMode(GL_FRONT, cast(GLenum)last_polygon_mode[0]); glPolygonMode(GL_BACK, cast(GLenum)last_polygon_mode[1]); + glUseProgram(last_program); + glBindTexture(GL_TEXTURE_2D, last_texture); +// #ifdef GL_SAMPLER_BINDING +// glBindSampler(0, last_sampler); +// #endif + glActiveTexture(last_active_texture); +// #ifndef IMGUI_IMPL_OPENGL_ES2 +// glBindVertexArray(last_vertex_array_object); +// #endif + glBindBuffer(GL_ARRAY_BUFFER, last_array_buffer); + glBlendEquationSeparate(last_blend_equation_rgb, last_blend_equation_alpha); + glBlendFuncSeparate(last_blend_src_rgb, last_blend_dst_rgb, last_blend_src_alpha, last_blend_dst_alpha); + if (last_enable_blend) glEnable(GL_BLEND); else glDisable(GL_BLEND); + if (last_enable_cull_face) glEnable(GL_CULL_FACE); else glDisable(GL_CULL_FACE); + if (last_enable_depth_test) glEnable(GL_DEPTH_TEST); else glDisable(GL_DEPTH_TEST); + if (last_enable_scissor_test) glEnable(GL_SCISSOR_TEST); else glDisable(GL_SCISSOR_TEST); +// #ifdef GL_POLYGON_MODE +// glPolygonMode(GL_FRONT_AND_BACK, (GLenum)last_polygon_mode[0]); +// #endif glViewport(last_viewport[0], last_viewport[1], cast(GLsizei)last_viewport[2], cast(GLsizei)last_viewport[3]); glScissor(last_scissor_box[0], last_scissor_box[1], cast(GLsizei)last_scissor_box[2], cast(GLsizei)last_scissor_box[3]); -} - -bool ImGuiImplOpenGL2CreateFontsTexture() -{ - // Build texture atlas - ImGuiIO* io = igGetIO(); - ubyte* pixels; - int width, height; - int bpp; - ImFontAtlas_GetTexDataAsRGBA32(io.Fonts, &pixels, &width, &height, &bpp); // Load as RGBA 32-bits (75% of the memory is wasted, but default font is so small) because it is more likely to be compatible with user's existing shaders. If your ImTextureId represent a higher-level concept than just a GL texture id, consider calling GetTexDataAsAlpha8() instead to save on GPU memory. - - // Upload texture to graphics system - GLint last_texture; - glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture); - glGenTextures(1, &g_FontTexture); - glBindTexture(GL_TEXTURE_2D, g_FontTexture); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels); - - // Store our identifier - io.Fonts.TexID = cast(ImTextureID)g_FontTexture; - - // Restore state - glBindTexture(GL_TEXTURE_2D, last_texture); - - return true; -} - -void ImGuiImplOpenGL2DestroyFontsTexture() -{ - if (g_FontTexture) - { - ImGuiIO* io = igGetIO(); - glDeleteTextures(1, &g_FontTexture); - io.Fonts.TexID = null; - g_FontTexture = 0; - } -} - -bool ImGuiImplOpenGL2CreateDeviceObjects() -{ - return ImGuiImplOpenGL2CreateFontsTexture(); -} - -void ImGuiImplOpenGL2DestroyDeviceObjects() -{ - ImGuiImplOpenGL2DestroyFontsTexture(); } \ No newline at end of file diff --git a/demos/utils/source/ecs_utils/utils.d b/demos/utils/source/ecs_utils/utils.d index 8ce5cd1..144d24f 100644 --- a/demos/utils/source/ecs_utils/utils.d +++ b/demos/utils/source/ecs_utils/utils.d @@ -58,7 +58,15 @@ version(D_BetterC) } } +version(Android) +{ + alias pthread_key_t = uint; + extern (C) int pthread_key_create(pthread_key_t *, void* function(void *)) @nogc nothrow; + extern (C) int pthread_key_delete(pthread_key_t) @nogc nothrow; + extern (C) void* pthread_getspecific(pthread_key_t) @nogc nothrow; + extern (C) int pthread_setspecific(pthread_key_t, const void *) @nogc nothrow; +} version(WebAssembly) { diff --git a/meson.build b/meson.build index c31b93a..94b9c64 100644 --- a/meson.build +++ b/meson.build @@ -23,6 +23,8 @@ tests_src = [ ] betterC_opt = get_option('betterC') +BuildDemos_opt = get_option('BuildDemos') +LTO_otp = get_option('LTO') comp = meson.get_compiler('d') @@ -31,16 +33,41 @@ comp_id = comp.get_id() args = [] link_args = [] +if comp_id == 'gcc' + args += '-pthread' + link_args += '-pthread' +endif + +if LTO_otp + if comp_id == 'gcc' + args += '-flto' + link_args += '-flto' + elif comp_id == 'llvm' + args += '-flto=thin' + link_args += '-flto=thin' + else + message('LTO don\'t work with DMD') + endif +endif + if betterC_opt - args += '-betterC' - link_args += '-betterC' + if comp_id == 'gcc' + args += ['-flto','-fno-druntime'] + link_args += ['-flto','-fno-druntime'] + else + args += '-betterC' + link_args += '-betterC' + endif endif inc = include_directories('source/') tests_inc = include_directories('source/') -ecs_lib = shared_library('ecs', src, include_directories : [tests_inc, inc], d_args: args, link_args: link_args) +ecs_lib = library('ecs', src, include_directories : [tests_inc, inc], d_args: args, link_args: link_args) executable('tests', tests_src, include_directories : [tests_inc, inc], d_args: args, link_args: link_args, link_with: ecs_lib) - +if BuildDemos_opt + subdir('demos/utils') + subdir('demos') +endif diff --git a/meson_options.txt b/meson_options.txt index fdf13a4..0ea2df9 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -1 +1,3 @@ -option('betterC', type: 'boolean', value: false) \ No newline at end of file +option('betterC', type: 'boolean', value: false) +option('BuildDemos', type: 'boolean', value: false) +option('LTO', type: 'boolean', value: false) \ No newline at end of file diff --git a/source/bubel/ecs/id_manager.d b/source/bubel/ecs/id_manager.d index aaeef30..db15b26 100644 --- a/source/bubel/ecs/id_manager.d +++ b/source/bubel/ecs/id_manager.d @@ -15,7 +15,7 @@ struct IDManager /************************************************************************************************************************ Get new ID. */ - pragma(inline, false) EntityID getNewID() nothrow @nogc + EntityID getNewID() nothrow @nogc { int current = m_stack_top.atomicOp!"-="(1) + 1; if (current < 0) diff --git a/source/bubel/ecs/manager.d b/source/bubel/ecs/manager.d index 0982531..19068cb 100644 --- a/source/bubel/ecs/manager.d +++ b/source/bubel/ecs/manager.d @@ -906,7 +906,8 @@ export struct EntityManager input_data.thread_id = cast(typeof(input_data.thread_id))threadID(); }//*/ - static foreach (iii, comp_info; components_info.req) + ///FIXME: should be "components_info.req()" but it's not compile with GCC + static foreach (iii, comp_info; components_info.m_req[0 .. components_info.m_req_counter]) { __traits(getMember, input_data, comp_info.name) = (cast(ForeachType!(typeof(__traits(getMember, Sys.EntitiesData, comp_info.name)))*)( @@ -914,7 +915,7 @@ export struct EntityManager .. entities_count]; } - static foreach (iii, comp_info; components_info.optional) + static foreach (iii, comp_info; components_info.m_optional[0 .. components_info.m_optional_counter]) { if (system.m_optional_components[iii] < info.deltas.length && info.deltas[system.m_optional_components[iii]] != 0) @@ -1344,9 +1345,9 @@ export struct EntityManager "Can't call function with system which hasn't EntitesData structure."); static assert(__traits(hasMember, Sys, "onUpdate"), "Can't call function with system which hasn't onUpdate function callback."); - static assert(is(SetFunctionAttributes!(T, functionLinkage!(s.onUpdate), - functionAttributes!(s.onUpdate)) == typeof(&s.onUpdate)), - "Function must match system update function."); + // static assert(is(SetFunctionAttributes!(T, functionLinkage!(s.onUpdate), + // functionAttributes!(s.onUpdate)) == typeof(&s.onUpdate)), + // "Function must match system update function."); FIXME: It's lead to crash on android build static assert(__traits(hasMember, Sys, "system_id"), "Sys must be system type."); System* system = getSystem(Sys.system_id); @@ -3105,7 +3106,7 @@ export struct EntityManager // has_work |= removeEntities(); has_work |= updateEvents(); - //id_manager.optimize(); + id_manager.optimize(); has_work |= updateBlocks(); has_work |= changeEntities(); has_work |= removeEntities(); diff --git a/source/bubel/ecs/std.d b/source/bubel/ecs/std.d index a7dd846..cac07b2 100644 --- a/source/bubel/ecs/std.d +++ b/source/bubel/ecs/std.d @@ -112,7 +112,7 @@ else version (D_BetterC) { private const uint max_alloca = 10000; private __gshared byte[max_alloca] alloca_array; - private uint alloca_pos = 0; + private __gshared uint alloca_pos = 0; export extern (C) void* __alloca(size_t length) @nogc nothrow { if (alloca_pos + length > max_alloca) @@ -158,7 +158,32 @@ static struct Mallocator static if (__traits(isPOD, T)) { - static immutable T init = T.init; + __gshared immutable T init = T.init; + + foreach (i; 0 .. ret.length) + { + memcpy(&ret[i], &init, T.sizeof); + } + } + else + { + static import std.conv; + + foreach (i; 0 .. ret.length) + { + std.conv.emplace(&ret[i]); + } + } + return ret; + } + + static T[] alignMakeArray(T)(size_t length, size_t alignment) nothrow @nogc + { + T[] ret = (cast(T*) alignAlloc(T.sizeof * length, alignment))[0 .. length]; + + static if (__traits(isPOD, T)) + { + __gshared immutable T init = T.init; foreach (i; 0 .. ret.length) { @@ -206,7 +231,7 @@ static struct Mallocator static if (__traits(isPOD, T)) { - static immutable T init = T.init; + __gshared immutable T init = T.init; memcpy(ret, &init, T.sizeof); } else static if (is(T == struct)) diff --git a/tests/tests.d b/tests/tests.d index d923116..9f69987 100644 --- a/tests/tests.d +++ b/tests/tests.d @@ -93,6 +93,13 @@ struct TestEvent2 float a; } +static struct CPosition +{ + mixin ECS.Component; + float x; + float y; +} + static struct TestComp { mixin ECS.Component; //__gshared ushort component_id; @@ -186,6 +193,52 @@ static struct TestComp5 } } +struct EverySystem +{ + mixin ECS.System; + + struct EntitiesData + { + uint length; + Entity[] entity; + CPosition[] pos; + } + + void onUpdate(EntitiesData data) + { + foreach(i;0..data.length) + { + data.pos[i].x++; + data.pos[i].y++; + } + } + + void iterate(EntitiesData data) + { + foreach(i;0..data.length) + { + data.pos[i].x++; + data.pos[i].y++; + } + } + + void free(EntitiesData data) + { + foreach(i;0..data.length) + { + gEM.removeEntity(data.entity[i].id); + } + } + + void addOne(EntitiesData data) + { + foreach(i;0..data.length) + { + gEM.addComponents(data.entity[i].id, TestComp2()); + } + } +} + struct ChangeTestSystem { mixin ECS.System!16; //__gshared ushort system_id; @@ -648,6 +701,7 @@ else: gEM.registerComponent!TestComp; gEM.registerComponent!TestComp3; gEM.registerComponent!TestComp5; + gEM.registerComponent!CPosition; gEM.registerEvent!TestEvent; gEM.registerEvent!TestEvent2; @@ -669,6 +723,7 @@ else: gEM.registerSystem!EmptySystem(2); gEM.registerSystem!EmptyEventSystem(2); gEM.registerSystem!EventSystem(2); + gEM.registerSystem!EverySystem(0); //gEM.registerSystem!TestSystemWithHighPriority(100); //gEM.registerSystem!TestSystem2(0); gEM.endRegister(); @@ -693,6 +748,62 @@ else: //dur = (MonoTime.currTime - time).total!"usecs"; //writeln("Template allocating: ", dur, " usecs"); printf("Template allocating: %f usecs\n", cast(float)(Time.getUSecTime() - time)); + + + time = Time.getUSecTime(); + ushort[1] empty_ids = [CPosition.component_id]; + EntityTemplate* tmpl_empty = gEM.allocateTemplate(empty_ids); + + gEM.commit(); + + time = Time.getUSecTime(); + + foreach(i;0..4_000_000)gEM.addEntity(tmpl_empty); + gEM.commit(); + foreach(i;0..4_000_000)gEM.addEntity(tmpl_empty); + gEM.commit(); + foreach(i;0..2_000_000)gEM.addEntity(tmpl_empty); + gEM.commit(); + + printf("Adding 1M entities: %f usecs\n", cast(float)(Time.getUSecTime() - time)); + + gEM.commit(); + time = Time.getUSecTime(); + gEM.callEntitiesFunction!EverySystem(&gEM.getSystem!EverySystem().iterate); + printf("Iterate 1M entities: %f usecs\n", cast(float)(Time.getUSecTime() - time)); + + gEM.begin(); + time = Time.getUSecTime(); + gEM.update(); + printf("Iterate 1M entities (update): %f usecs\n", cast(float)(Time.getUSecTime() - time)); + gEM.end(); + + time = Time.getUSecTime(); + gEM.callEntitiesFunction!EverySystem(&gEM.getSystem!EverySystem().free); + gEM.commit(); + printf("Deleting 1M entities: %f usecs\n", cast(float)(Time.getUSecTime() - time)); + + time = Time.getUSecTime(); + + foreach(i;0..4_000_000)gEM.addEntity(tmpl_empty); + gEM.commit(); + foreach(i;0..4_000_000)gEM.addEntity(tmpl_empty); + gEM.commit(); + foreach(i;0..2_000_000)gEM.addEntity(tmpl_empty); + gEM.commit(); + + printf("Adding 1M entities (prealloc): %f usecs\n", cast(float)(Time.getUSecTime() - time)); + + gEM.commit(); + time = Time.getUSecTime(); + gEM.callEntitiesFunction!EverySystem(&gEM.getSystem!EverySystem().addOne); + gEM.commit(); + printf("Adding 1M component: %f usecs\n", cast(float)(Time.getUSecTime() - time)); + + gEM.commit(); + gEM.callEntitiesFunction!EverySystem(&gEM.getSystem!EverySystem().free); + gEM.commit(); + time = Time.getUSecTime(); EntityID entity; From 13e6ed8fd529f62518abb1408e701da95a844693 Mon Sep 17 00:00:00 2001 From: Mergul Date: Sat, 6 Jun 2020 22:26:59 +0200 Subject: [PATCH 153/217] ECS core imprevement -Adedd function to resize array to Mallocator -significant speed up for first time ID allocation by using resizeArray instead of makeArray -fix: onUpdate called with zero length arrays -call updateBlocks before updateEvents (it's more accurate behaviour) -some minore fixes -fixed meson.build for GDC --- meson.build | 4 +-- source/bubel/ecs/id_manager.d | 10 ++---- source/bubel/ecs/manager.d | 61 ++++++++++++++++++++--------------- source/bubel/ecs/std.d | 44 +++++++++++++++++++++++++ 4 files changed, 83 insertions(+), 36 deletions(-) diff --git a/meson.build b/meson.build index 94b9c64..2a71fc7 100644 --- a/meson.build +++ b/meson.build @@ -52,8 +52,8 @@ endif if betterC_opt if comp_id == 'gcc' - args += ['-flto','-fno-druntime'] - link_args += ['-flto','-fno-druntime'] + args += ['-fno-druntime'] + link_args += ['-fno-druntime'] else args += '-betterC' link_args += '-betterC' diff --git a/source/bubel/ecs/id_manager.d b/source/bubel/ecs/id_manager.d index db15b26..86a611e 100644 --- a/source/bubel/ecs/id_manager.d +++ b/source/bubel/ecs/id_manager.d @@ -177,15 +177,9 @@ struct IDManager if (m_last_id > m_ids_array.length) { uint begin = cast(uint) m_ids_array.length; - Data[] new_array = Mallocator.makeArray!Data(begin + (m_blocks_count << 16)); - memcpy(new_array.ptr, m_ids_array.ptr, m_ids_array.length * Data.sizeof); - Mallocator.dispose(m_ids_array); - m_ids_array = new_array; - uint[] new_stack = Mallocator.makeArray!uint(m_ids_array.length); - memcpy(new_stack.ptr, m_free_stack.ptr, m_free_stack.length * uint.sizeof); - Mallocator.dispose(m_free_stack); - m_free_stack = new_stack; + m_ids_array = Mallocator.resizeArray(m_ids_array, begin + (m_blocks_count << 16)); + m_free_stack = Mallocator.resizeArray(m_free_stack, m_ids_array.length); foreach (block; m_blocks[0 .. m_blocks_count - 1]) { diff --git a/source/bubel/ecs/manager.d b/source/bubel/ecs/manager.d index 19068cb..4c543ce 100644 --- a/source/bubel/ecs/manager.d +++ b/source/bubel/ecs/manager.d @@ -456,7 +456,7 @@ export struct EntityManager uint writable_dep = 1; } - static ComponentsCounts getComponentsCounts()() + static ComponentsCounts getComponentsCounts() { ComponentsCounts components_counts; @@ -679,7 +679,7 @@ export struct EntityManager } - static ComponentsIndices!component_counts getComponentsInfo()() + static ComponentsIndices!component_counts getComponentsInfo() { ComponentsIndices!component_counts components_info; @@ -786,7 +786,7 @@ export struct EntityManager enum ComponentsIndices!component_counts components_info = getComponentsInfo(); - static void genCompList()(ref System system, ref HashMap!(char[], ushort) components_map) + static void genCompList(ref System system, ref HashMap!(char[], ushort) components_map) { foreach (member; __traits(allMembers, Sys.EntitiesData)) @@ -885,7 +885,7 @@ export struct EntityManager } } - static void fillInputData()(ref Sys.EntitiesData input_data, EntityInfo* info, + static void fillInputData(ref Sys.EntitiesData input_data, EntityInfo* info, EntitiesBlock* block, uint offset, uint entities_count, System* system) { //enum ComponentsIndices components_info = getComponentsInfo(); @@ -907,7 +907,8 @@ export struct EntityManager }//*/ ///FIXME: should be "components_info.req()" but it's not compile with GCC - static foreach (iii, comp_info; components_info.m_req[0 .. components_info.m_req_counter]) + static foreach (iii, comp_info; components_info.m_req[0 + .. components_info.m_req_counter]) { __traits(getMember, input_data, comp_info.name) = (cast(ForeachType!(typeof(__traits(getMember, Sys.EntitiesData, comp_info.name)))*)( @@ -915,7 +916,8 @@ export struct EntityManager .. entities_count]; } - static foreach (iii, comp_info; components_info.m_optional[0 .. components_info.m_optional_counter]) + static foreach (iii, comp_info; components_info.m_optional[0 + .. components_info.m_optional_counter]) { if (system.m_optional_components[iii] < info.deltas.length && info.deltas[system.m_optional_components[iii]] != 0) @@ -929,7 +931,7 @@ export struct EntityManager } } - /*bool checkOnUpdateParams()() + /*bool checkOnUpdateParams() { bool ret = false; foreach (func; __traits(getOverloads, Sys, "onUpdate")) @@ -1006,26 +1008,29 @@ export struct EntityManager else entities_count = block.entities_count; - assert(entities_count <= block.entities_count - && offset <= block.entities_count); - - fillInputData(input_data, info, block, offset, entities_count, system); - - static if (hasMember!(Sys.EntitiesData, "thread_id")) + if (entities_count > 0) { - input_data.thread_id = cast(typeof(input_data.thread_id)) data - .thread_id; + assert(entities_count <= block.entities_count + && offset <= block.entities_count); + + fillInputData(input_data, info, block, offset, entities_count, system); + + static if (hasMember!(Sys.EntitiesData, "thread_id")) + { + input_data.thread_id = cast( + typeof(input_data.thread_id)) data.thread_id; + } + + static if (hasMember!(Sys.EntitiesData, "job_id")) + { + input_data.job_id = cast(typeof(input_data.job_id)) data.job_id; + } + + //s.onUpdate(input_data); + (cast(typeof(&__traits(getOverloads, s, + "onUpdate")[OnUpdateOverloadNum])) data.update_delegate)( + input_data); } - - static if (hasMember!(Sys.EntitiesData, "job_id")) - { - input_data.job_id = cast(typeof(input_data.job_id)) data.job_id; - } - - //s.onUpdate(input_data); - (cast(typeof(&__traits(getOverloads, s, - "onUpdate")[OnUpdateOverloadNum])) data.update_delegate)(input_data); - block = block.next_block; offset = 0; blocks--; @@ -1339,10 +1344,12 @@ export struct EntityManager export void callEntitiesFunction(Sys, T)(T func) { + //TODO: check if onUpdate function is good Sys* s; static assert(isDelegate!func, "Function must be delegate."); static assert(__traits(hasMember, Sys, "EntitiesData"), "Can't call function with system which hasn't EntitesData structure."); + ///TODO: make possibly to call function to group without system with onUpdate function static assert(__traits(hasMember, Sys, "onUpdate"), "Can't call function with system which hasn't onUpdate function callback."); // static assert(is(SetFunctionAttributes!(T, functionLinkage!(s.onUpdate), @@ -1353,6 +1360,8 @@ export struct EntityManager System* system = getSystem(Sys.system_id); assert(system != null, "System must be registered in EntityManager before any funcion can be called."); + if (!system.m_any_system_caller) + return; foreach (info; system.m_any_system_caller.infos) { @@ -3101,7 +3110,7 @@ export struct EntityManager swapData(); has_work = false; - // has_work |= updateBlocks(); + has_work |= updateBlocks(); // has_work |= changeEntities(); // has_work |= removeEntities(); has_work |= updateEvents(); diff --git a/source/bubel/ecs/std.d b/source/bubel/ecs/std.d index cac07b2..38ad0d8 100644 --- a/source/bubel/ecs/std.d +++ b/source/bubel/ecs/std.d @@ -152,6 +152,50 @@ else static struct Mallocator { + static T[] resizeArray(T)(T[] array, size_t length) nothrow @nogc + { + T[] ret; + + if(length > array.length) + { + ret = (cast(T*) realloc(array.ptr, T.sizeof * length))[0 .. length]; + static if (__traits(isPOD, T)) + { + __gshared immutable T init = T.init; + + foreach (i; array.length .. ret.length) + { + memcpy(&ret[i], &init, T.sizeof); + } + } + else + { + static import std.conv; + + foreach (i; array.length .. ret.length) + { + std.conv.emplace(&ret[i]); + } + } + } + else + { + static if (__traits(hasMember, T, "__xdtor")) + foreach (i; length .. array.length) + { + array[i].__xdtor(); + } + else static if (__traits(hasMember, T, "__dtor")) + foreach (i; length .. array.length) + { + array[i].__dtor(); + } + ret = (cast(T*) realloc(array.ptr, T.sizeof * length))[0 .. length]; + } + + return ret; + } + static T[] makeArray(T)(size_t length) nothrow @nogc { T[] ret = (cast(T*) malloc(T.sizeof * length))[0 .. length]; From e76c5ccdb2c448d3ff17ab248902ef4fa9f7d580 Mon Sep 17 00:00:00 2001 From: Mergul Date: Sat, 6 Jun 2020 22:46:29 +0200 Subject: [PATCH 154/217] Huge demos update -moved C stdlib function definitions to ecs_utils.utils -added function to calculate mix(linear interpolation) and rsqrt(fast inverse sqrt) -added some math to vec2 (length, normalize...) -improved renderer with possibility to use multiple materials (one per block, not perfect solution for parallel compute, but works with some requirements) -added blending support for material (opaque, additive, mixed) -added Android support -added gprahical representation for mouse tools (tool_circle.d) -added initial support for editing template components variables -better Component and Templates listing -added possibility to add/removes components using mouse -move CLocation to game_core.basic and reuse in every test -moved tools code from demos to App (now code is fully separated from demos!) -some improvement and fixes in Snake demo, with additional systems to handle adding and removing entities -added new demo: Particles. By now demo has several particles to spawn and support for attractors and vortexes (calculation is made as every attractor with every entity) -fixed bug with window hover and tools -improved tool behaviour -added new material -now window is always opened as maximized windowed mode -some minor fixes and improvements --- demos/assets/shaders/circle.fp | 64 +++ demos/assets/shaders/circle.vp | 114 ++++ demos/assets/textures/atlas.png | Bin 41948 -> 42614 bytes demos/compile_android.py | 2 +- demos/external/sources/glad/gl/loader.d | 4 +- demos/source/app.d | 306 ++++++++++- demos/source/demos/particles.d | 545 ++++++++++++++++++++ demos/source/demos/simple.d | 101 ++-- demos/source/demos/snake.d | 211 ++++---- demos/source/demos/space_invaders.d | 113 ++-- demos/source/game_core/basic.d | 14 + demos/source/gui/attributes.d | 20 + demos/source/gui/component.d | 61 ++- demos/source/gui/manager.d | 317 +++++++++++- demos/source/gui/tool_circle.d | 52 ++ demos/utils/source/ecs_utils/gfx/buffer.d | 2 +- demos/utils/source/ecs_utils/gfx/material.d | 19 + demos/utils/source/ecs_utils/gfx/renderer.d | 76 ++- demos/utils/source/ecs_utils/math/vector.d | 22 + demos/utils/source/ecs_utils/utils.d | 49 +- 20 files changed, 1804 insertions(+), 288 deletions(-) create mode 100644 demos/assets/shaders/circle.fp create mode 100644 demos/assets/shaders/circle.vp create mode 100644 demos/source/demos/particles.d create mode 100644 demos/source/game_core/basic.d create mode 100644 demos/source/gui/attributes.d create mode 100644 demos/source/gui/tool_circle.d diff --git a/demos/assets/shaders/circle.fp b/demos/assets/shaders/circle.fp new file mode 100644 index 0000000..15f46fd --- /dev/null +++ b/demos/assets/shaders/circle.fp @@ -0,0 +1,64 @@ +precision mediump int; +precision mediump float; +precision lowp sampler2D; +precision lowp samplerCube; + + +#ifdef GLES + #define TEX(x,y) texture2D(x,y) + #if __VERSION__ >290 + #define M_IN in mediump + #define L_IN in lowp + #else + #define M_IN varying mediump + #define L_IN varying lowp + #endif +#else + #define TEX(x,y) texture(x,y) + #if __VERSION__ > 320 + #define M_IN in + #define L_IN in + #else + #define M_IN varying + #define L_IN varying + #endif +#endif + +M_IN vec2 pos; +M_IN float edge; +//flat M_IN vec2 fpos; + +//M_IN vec2 uv; +//M_IN vec4 color; +/* +#ifdef GLES + #if __VERSION__ >290 + in mediump vec2 uv; + #else + varying mediump vec2 uv; + #endif +#else + #if __VERSION__ > 320 + in vec2 uv; + #else + varying vec2 uv; + #endif +#endif*/ + +//layout(binding = 0)uniform sampler2D tex; + +//uniform sampler2D tex; + +//layout(location = 0) out vec4 outColor; + +void main() +{ + float len2 = dot(pos,pos); + + if(len2 > 1.0)discard; + + if(len2 > edge)gl_FragColor = vec4(0.4,0.8,1.0,0.8);//TEX(tex,uv) * color; + else gl_FragColor = vec4(0,0.6,1.0,0.35);//TEX(tex,uv) * color; + //gl_FragColor = vec4(pos,0,1); + //if(gl_FragColor.a < 0.01)discard; +} diff --git a/demos/assets/shaders/circle.vp b/demos/assets/shaders/circle.vp new file mode 100644 index 0000000..6997121 --- /dev/null +++ b/demos/assets/shaders/circle.vp @@ -0,0 +1,114 @@ +precision highp float; +precision highp int; +precision lowp sampler2D; +precision lowp samplerCube; +#ifdef GLES + #if __VERSION__ >290 + #define LOC(x) layout(location = x) + #define ATT in + #define M_OUT out mediump + #define L_OUT out lowp + #else + #define LOC(x) + #define ATT attribute + #define M_OUT varying mediump + #define L_OUT varying lowp + #endif +#else + #if __VERSION__ > 320 + #define LOC(x) layout(location = x) + #define ATT in + #define M_OUT out + #define L_OUT out + #else + #define LOC(x) + #define ATT attribute + #define M_OUT varying + #define L_OUT varying + #endif +#endif +/* +#ifdef GLES + #if __VERSION__ >290 + uniform vec4 matrix_1; + uniform vec4 matrix_2; + uniform vec4 uv_transform; + + layout(location = 0) in vec2 positions; + layout(location = 1) in vec2 tex_coords; + + out mediump vec2 uv; + #else + uniform vec4 matrix_1; + uniform vec4 matrix_2; + uniform vec4 uv_transform; + + attribute vec2 positions; + attribute vec2 tex_coords; + + varying mediump vec2 uv; + #endif +#else + #if __VERSION__ > 320 + uniform vec4 matrix_1; + uniform vec4 matrix_2; + uniform vec4 uv_transform; + + layout(location = 0) in vec2 positions; + layout(location = 1) in vec2 tex_coords; + + out vec2 uv; + #else + uniform vec4 matrix_1; + uniform vec4 matrix_2; + uniform vec4 uv_transform; + + attribute vec2 positions; + attribute vec2 tex_coords; + + varying vec2 uv; + #endif +#endif*/ + +//#define VBO_BATCH 1 + +//M_OUT vec2 uv; +//L_OUT vec4 color; +M_OUT vec2 pos; +M_OUT float edge; +//flat M_OUT vec2 fpos; + +LOC(0) ATT vec2 positions; +//LOC(1) ATT vec2 tex_coords; + +#ifdef VBO_BATCH + LOC(2) ATT float depth; + LOC(3) ATT vec4 vcolor; +#else + uniform vec4 matrix_1; + uniform vec4 matrix_2; + //uniform vec4 uv_transform; + //uniform vec4 vcolor; + + //float depth = matrix_2.z; +#endif + +void main() { + //#ifdef VBO_BATCH + // vec3 position = vec3(positions*4.0,1.0); + // uv = tex_coords; + //#else + //edge = mix(0.1, 0.96, (matrix_2.z / 256)); + edge = (matrix_1.w - matrix_2.z) / matrix_1.w;//matrix_2.z;//clamp((matrix_2,0.0,1.0); + edge *= edge; + pos = positions * 2.0;// / matrix_2.zw * 2; + //fpos = positions * matrix_2.xy; + vec3 position = mat3(matrix_1.x,matrix_1.y,0,matrix_1.z,matrix_1.w,0,matrix_2.xy,1.0) * vec3(positions,1.0); + // uv = tex_coords * uv_transform.zw + uv_transform.xy; + //#endif + + //color = vcolor * 2.0; + + gl_Position = vec4(position.xy,0,1.0); + +} diff --git a/demos/assets/textures/atlas.png b/demos/assets/textures/atlas.png index a799eb7706feddc336f6f1e6e75f780dcbea5467..eea925e600dde7ea3133047620c037882fdd4b2c 100644 GIT binary patch literal 42614 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 diff --git a/demos/compile_android.py b/demos/compile_android.py index 2e3f967..75d6106 100644 --- a/demos/compile_android.py +++ b/demos/compile_android.py @@ -38,7 +38,7 @@ def compile(sources, output): clean = 0 ldc_flags = '--d-version=SDL_209 --d-version=BindSDL_Image --d-version=MM_USE_POSIX_THREADS ' #import_paths = ['source','tests'] -import_paths = ['external','external/sources', 'external/imports', 'external/wasm_imports', '../source', 'utils/source', 'simple/source'] +import_paths = ['external/android','external/sources', 'external/imports', 'external/wasm_imports', '../source', 'utils/source', 'simple/source'] build_tests = 0 for arg in sys.argv[1:]: diff --git a/demos/external/sources/glad/gl/loader.d b/demos/external/sources/glad/gl/loader.d index d640c61..8bc904f 100644 --- a/demos/external/sources/glad/gl/loader.d +++ b/demos/external/sources/glad/gl/loader.d @@ -35,14 +35,14 @@ bool open_gl() @nogc { return false; } else { version(OSX) { - enum const(char)*[] NAMES = [ + enum const(char)*[4] NAMES = [ "../Frameworks/OpenGL.framework/OpenGL", "/Library/Frameworks/OpenGL.framework/OpenGL", "/System/Library/Frameworks/OpenGL.framework/OpenGL", "/System/Library/Frameworks/OpenGL.framework/Versions/Current/OpenGL" ]; } else { - enum const(char)*[] NAMES = ["libGL.so.1", "libGL.so"]; + enum const(char)*[2] NAMES = ["libGL.so.1", "libGL.so"]; } foreach(name; NAMES) { diff --git a/demos/source/app.d b/demos/source/app.d index 003922b..808426f 100644 --- a/demos/source/app.d +++ b/demos/source/app.d @@ -4,10 +4,11 @@ import bindbc.sdl; import cimgui.cimgui; +import game_core.basic; import game_core.job_updater; -import bubel.ecs.manager; import bubel.ecs.core; +import bubel.ecs.manager; import bubel.ecs.std; import ecs_utils.gfx.renderer; @@ -21,6 +22,7 @@ import glad.gl.gles2; import glad.gl.loader; import gui.manager; +import gui.tool_circle; extern (C) : @@ -50,7 +52,7 @@ struct Launcher bool function() loop; void function() end; void function(SDL_Event*) event; - void function(vec2, Tool, int) tool; + //void function(vec2, Tool, int, bool) tool; float scalling; ivec2 window_size = ivec2(1024,768); Renderer renderer; @@ -65,9 +67,12 @@ struct Launcher vec2 render_position; Tool used_tool; - int tool_size = 0; + int tool_size = 100; float tool_repeat = 0; float repeat_time = 0; + bool tool_show = true; + bool tool_mode = true; + ToolCircle* tool_circle; bool swap_interval = true; @@ -93,7 +98,7 @@ struct Launcher float draw_time = 0; } - void switchDemo(void function() start, bool function() loop, void function() end, void function(SDL_Event*) event, void function(vec2, Tool, int) tool, const (char)* tips) + void switchDemo(void function() start, bool function() loop, void function() end, void function(SDL_Event*) event, const (char)* tips) { gui_manager.clear(); //launcher.ent @@ -117,7 +122,97 @@ struct Launcher this.end = end; this.event = event; this.tips = tips; - this.tool = tool; + //this.tool = tool; + } + + void processTool(vec2 position, bool mode) + { + static struct Iterator + { + float size2; + vec2 position; + ComponentRef[] add_comps; + ushort[] rem_comps; + + void removeEntity(IteratorSystem.EntitiesData data) + { + foreach(i;0..data.length) + { + vec2 rel_vec = data.location[i] - position; + float length = rel_vec.x * rel_vec.x + rel_vec.y * rel_vec.y; + if(length < size2)gEM.removeEntity(data.entity[i].id); + } + } + + void addComponent(IteratorSystem.EntitiesData data) + { + foreach(i;0..data.length) + { + vec2 rel_vec = data.location[i] - position; + float length = rel_vec.x * rel_vec.x + rel_vec.y * rel_vec.y; + if(length < size2)gEM.addComponents(data.entity[i].id, add_comps); + } + } + + void removeComponent(IteratorSystem.EntitiesData data) + { + foreach(i;0..data.length) + { + vec2 rel_vec = data.location[i] - position; + float length = rel_vec.x * rel_vec.x + rel_vec.y * rel_vec.y; + if(length < size2)gEM.removeComponents(data.entity[i].id, rem_comps); + } + } + } + + float half_size = tool_size * 0.5; + float size2 = half_size * half_size; + Iterator iterator; + iterator.size2 = size2; + iterator.position = position; + + switch(used_tool) + { + case Tool.entity_spawner: + if(mode) + { + if(gui_manager.templates.length == 0)return; + EntityTemplate* tmpl = gui_manager.getSelectedTemplate(); + CLocation* location = tmpl.getComponent!CLocation; + if(location) + { + position += randomCircularSample() * half_size; + if(position.y < 16)position.y = 16; + else if(position.y > 299)position.y = 299; + *location = position; + } + manager.addEntity(tmpl); + } + else + { + manager.callEntitiesFunction!IteratorSystem(&iterator.removeEntity); + } + break; + case Tool.component_manipulator: + { + if(gui_manager.components.length == 0)return; + if(mode) + { + ComponentRef[1] comps = [gui_manager.getSelectedComponent()]; + iterator.add_comps = comps; + manager.callEntitiesFunction!IteratorSystem(&iterator.addComponent); + } + else + { + ushort[1] comps = [gui_manager.getSelectedComponent().component_id]; + iterator.rem_comps = comps; + manager.callEntitiesFunction!IteratorSystem(&iterator.removeComponent); + } + } + break; + default: + break; + } } bool getKeyState(SDL_Scancode key) @@ -184,6 +279,28 @@ struct CleanSystem } } +struct IteratorSystem +{ + mixin ECS.System!1; + + struct EntitiesData + { + uint length; + const (Entity)[] entity; + CLocation[] location; + } + + bool onBegin() + { + return false; + } + + void onUpdate(EntitiesData) + { + + } +} + void mainLoop(void* arg) { __gshared double time = 0; @@ -237,9 +354,12 @@ void mainLoop(void* arg) case SDL_BUTTON_MIDDLE:launcher.mouse.middle = true;break; default:break; } - if(launcher.tool && event.button.button == SDL_BUTTON_LEFT && launcher.tool_repeat == 0 && !igIsWindowHovered(ImGuiHoveredFlags_AnyWindow)) + if(!igIsAnyItemHovered())igSetWindowFocus(); + if(!igIsWindowHovered(ImGuiHoveredFlags_AnyWindow) && !igIsWindowFocused(ImGuiFocusedFlags_AnyWindow)) { - launcher.tool(vec2(event.button.x, launcher.window_size.y - event.button.y) * launcher.scalling - launcher.render_position, launcher.used_tool, launcher.tool_size); + launcher.repeat_time = 0; + if(event.button.button == SDL_BUTTON_LEFT)launcher.processTool(vec2(event.button.x, launcher.window_size.y - event.button.y) * launcher.scalling - launcher.render_position,launcher.tool_mode); + else if(event.button.button == SDL_BUTTON_RIGHT)launcher.processTool(vec2(event.button.x, launcher.window_size.y - event.button.y) * launcher.scalling - launcher.render_position,!launcher.tool_mode); } } else if(event.type == SDL_MOUSEBUTTONUP) @@ -255,17 +375,52 @@ void mainLoop(void* arg) else if(event.type == SDL_MOUSEMOTION) { launcher.mouse.position = vec2(event.motion.x, launcher.window_size.y - event.motion.y); + }else if(event.type == SDL_MOUSEWHEEL) + { + if(!igIsAnyItemHovered() && !igIsWindowHovered(ImGuiHoveredFlags_AnyWindow)) + { + if(SDL_GetModState() & KMOD_CTRL) + { + float sign = 1; + if(event.wheel.y < 0)sign = -1; + float val = sign * event.wheel.y * launcher.tool_repeat * 0.25; + if(val < 0.1)val = 0.1; + launcher.tool_repeat -= sign * val; + if(launcher.tool_repeat < 0)launcher.tool_repeat = 0; + else if(launcher.tool_repeat > 1000)launcher.tool_repeat = 1000; + } + else + { + int sign = 1; + if(event.wheel.y < 0)sign = -1; + int val = sign * event.wheel.y * launcher.tool_size / 4; + if(val < 1)val = 1; + launcher.tool_size -= sign * val; + if(launcher.tool_size < 1)launcher.tool_size = 1; + else if(launcher.tool_size > 256)launcher.tool_size = 256; + } + } } } - if(launcher.tool && launcher.tool_repeat != 0 && launcher.mouse.left && !igIsWindowHovered(ImGuiHoveredFlags_AnyWindow) && !igIsWindowFocused(ImGuiFocusedFlags_AnyWindow)) + if(launcher.tool_repeat != 0 && (launcher.mouse.left || launcher.mouse.right) && !igIsWindowHovered(ImGuiHoveredFlags_AnyWindow) && !igIsWindowFocused(ImGuiFocusedFlags_AnyWindow)) { + bool mode = launcher.tool_mode; + if(launcher.mouse.right)mode = !mode; float range = 500.0 / cast(float)launcher.tool_repeat; launcher.repeat_time += launcher.delta_time; - while(launcher.repeat_time > range) + if(launcher.used_tool != Tool.entity_spawner || !mode) { - launcher.repeat_time -= range; - launcher.tool((launcher.mouse.position*launcher.scalling)-launcher.render_position, launcher.used_tool, launcher.tool_size); + if(launcher.repeat_time > range)launcher.processTool((launcher.mouse.position*launcher.scalling)-launcher.render_position, mode); + while(launcher.repeat_time > range)launcher.repeat_time -= range; + } + else + { + while(launcher.repeat_time > range) + { + launcher.repeat_time -= range; + launcher.processTool((launcher.mouse.position*launcher.scalling)-launcher.render_position, mode); + } } } @@ -300,17 +455,22 @@ void mainLoop(void* arg) if(igMenuItemBool("Simpe",null,false,true)) { import demos.simple; - launcher.switchDemo(&simpleStart,&simpleLoop,&simpleEnd,&simpleEvent,&simpleTool,Simple.tips); + launcher.switchDemo(&simpleStart,&simpleLoop,&simpleEnd,&simpleEvent,Simple.tips); } if(igMenuItemBool("Snake",null,false,true)) { import demos.snake; - launcher.switchDemo(&snakeStart,&snakeLoop,&snakeEnd,&snakeEvent,&snakeTool,Snake.tips); + launcher.switchDemo(&snakeStart,&snakeLoop,&snakeEnd,&snakeEvent,Snake.tips); } if(igMenuItemBool("Space invaders",null,false,true)) { import demos.space_invaders; - launcher.switchDemo(&spaceInvadersStart,&spaceInvadersLoop,&spaceInvadersEnd,&spaceInvadersEvent,&spaceInvadersTool,SpaceInvaders.tips); + launcher.switchDemo(&spaceInvadersStart,&spaceInvadersLoop,&spaceInvadersEnd,&spaceInvadersEvent,SpaceInvaders.tips); + } + if(igMenuItemBool("Particles",null,false,true)) + { + import demos.particles; + launcher.switchDemo(&particlesStart,&particlesLoop,&particlesEnd,&particlesEvent,ParticlesDemo.tips); } igEndMenu(); } @@ -463,20 +623,22 @@ void mainLoop(void* arg) if(launcher.show_demo_wnd) { igSetNextWindowPos(ImVec2(launcher.window_size.x - 260, 30), ImGuiCond_Once, ImVec2(0,0)); - igSetNextWindowSize(ImVec2(250, 500), ImGuiCond_Once); + igSetNextWindowSize(ImVec2(250, launcher.window_size.y - 60), ImGuiCond_Once); if(igBegin("Demo",&launcher.show_demo_wnd,0)) { ImDrawList* draw_list = igGetWindowDrawList(); - //igBeginGroup(); + igBeginGroup(); launcher.gui_manager.gui(); - //igEndGroup(); + igEndGroup(); + ImDrawList_AddRect(draw_list, igGetItemRectMin(), ImVec2(igGetWindowPos().x+igGetWindowWidth()-2,igGetItemRectMax().y), igColorConvertFloat4ToU32(ImVec4(0.4,0.4,0.4,0.4)), 4, ImDrawCornerFlags_All, 1); + //ImDrawList_AddRect(draw_list, igGetItemRectMin(), igGetItemRectMax(), igColorConvertFloat4ToU32(ImVec4(0.4,0.4,0.4,0.4)), -1, 0, 1); //igBeginChildFrame(1,ImVec2(0,-1),ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_ChildWindow); //igBeginChild("Tool frame",ImVec2(-1,-1),true,0); - if(igCollapsingHeader("Tool##ToolHeader", ImGuiTreeNodeFlags_SpanAvailWidth)) + igBeginGroup(); + if(igCollapsingHeader("Tool##ToolHeader", ImGuiTreeNodeFlags_SpanAvailWidth | ImGuiTreeNodeFlags_DefaultOpen)) { igIndent(8); - igBeginGroup(); if(igBeginCombo("Tool",tool_strings[launcher.used_tool],0)) { if(igSelectable("Entity spawner",false,0,ImVec2(0,0))) @@ -493,14 +655,20 @@ void mainLoop(void* arg) } igEndCombo(); } + igCheckbox("Show Tool", &launcher.tool_show); + //igSelectable("Selectabe",false,ImGuiSelectableFlags_None,ImVec2(0,0)); + if(igRadioButtonBool("Add", launcher.tool_mode))launcher.tool_mode = true; + igSameLine(0,0); + if(igRadioButtonBool("Remove", !launcher.tool_mode))launcher.tool_mode = false; igSliderInt("Tool size", &launcher.tool_size, 0, 256, null); igSliderFloat("Tool repeat", &launcher.tool_repeat, 0, 1024, null, 4); launcher.gui_manager.toolGui(); - igEndGroup(); - ImDrawList_AddRect(draw_list, igGetItemRectMin(), igGetItemRectMax(), igColorConvertFloat4ToU32(ImVec4(0.4,0.4,0.4,0.4)), 4, ImDrawCornerFlags_All, 1); igUnindent(8); } + igEndGroup(); + ImDrawList_AddRect(draw_list, igGetItemRectMin(), ImVec2(igGetWindowPos().x+igGetWindowWidth()-2,igGetItemRectMax().y), igColorConvertFloat4ToU32(ImVec4(0.4,0.4,0.4,0.4)), 2, ImDrawCornerFlags_All, 1); + //igEndChild(); //igEndChildFrame(); @@ -516,7 +684,8 @@ void mainLoop(void* arg) if(launcher.show_profile_wnd) { - igSetNextWindowPos(ImVec2(launcher.window_size.x - 260, launcher.window_size.y - 280), ImGuiCond_Once, ImVec2(0,0)); + //igSetNextWindowPos(ImVec2(launcher.window_size.x - 260, launcher.window_size.y - 280), ImGuiCond_Once, ImVec2(0,0)); + igSetNextWindowPos(ImVec2(8, launcher.window_size.y - 258), ImGuiCond_Once, ImVec2(0,0)); igSetNextWindowSize(ImVec2(250, 250), ImGuiCond_Once); if(igBegin("Profile",&launcher.show_profile_wnd,0)) { @@ -577,6 +746,10 @@ void mainLoop(void* arg) launcher.renderer.present(); draw_time = launcher.getTime() - draw_time; + //import std.stdio; + //printf("Scalling: %f",launcher.scalling); + if(launcher.tool_show)launcher.tool_circle.draw(&launcher.renderer, (launcher.mouse.position*launcher.scalling)-launcher.render_position, cast(float)launcher.tool_size, launcher.renderer.view_size.y*6*launcher.scalling); + __gshared float plot_time = 0; __gshared uint plot_samples = 0; plot_time += launcher.delta_time; @@ -703,6 +876,7 @@ int app_main(int argc, char** argv) SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0); launcher.window = SDL_CreateWindow("Simple", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, launcher.window_size.x, launcher.window_size.y, SDL_WINDOW_SHOWN | SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE); + SDL_MaximizeWindow(launcher.window); launcher.gl_context = SDL_GL_CreateContext(launcher.window); launcher.context = igCreateContext(null); @@ -778,8 +952,11 @@ int app_main(int argc, char** argv) launcher.manager.registerPass("clean"); + launcher.manager.registerComponent!CLocation; + launcher.manager.registerSystem!CountSystem(10000); launcher.manager.registerSystem!CleanSystem(0,"clean"); + launcher.manager.registerSystem!IteratorSystem(0,"clean"); launcher.manager.endRegister(); @@ -796,8 +973,10 @@ int app_main(int argc, char** argv) { import demos.simple; import demos.space_invaders; - // launcher.switchDemo(&spaceInvadersStart,&spaceInvadersLoop,&spaceInvadersEnd,&spaceInvadersEvent,&spaceInvadersTool,SpaceInvaders.tips); - launcher.switchDemo(&simpleStart,&simpleLoop,&simpleEnd,&simpleEvent,&simpleTool,Simple.tips); + import demos.particles; + // launcher.switchDemo(&spaceInvadersStart,&spaceInvadersLoop,&spaceInvadersEnd,&spaceInvadersEvent,SpaceInvaders.tips); + // launcher.switchDemo(&particlesStart,&particlesLoop,&particlesEnd,&particlesEvent,ParticlesDemo.tips); + launcher.switchDemo(&simpleStart,&simpleLoop,&simpleEnd,&simpleEvent,Simple.tips); } int key_num; @@ -842,7 +1021,7 @@ void loadGFX() Texture.__loadBackend(); Renderer.__loadBackend(); - GfxConfig.materials = Mallocator.makeArray!Material(1); + GfxConfig.materials = Mallocator.makeArray!Material(3); GfxConfig.meshes = Mallocator.makeArray!Mesh(1); float[16] vertices = [-0.5,-0.5, 0,1, -0.5,0.5, 0,0, 0.5,-0.5, 1,1, 0.5,0.5, 1,0]; @@ -889,7 +1068,84 @@ void loadGFX() GfxConfig.materials[0].data.bindings[0] = GfxConfig.materials[0].getLocation("tex"); + Shader vsh2; + vsh2.create(); + vsh2.load("assets/shaders/circle.vp"); + vsh2.compile(); + + Shader fsh2; + fsh2.create(); + fsh2.load("assets/shaders/circle.fp"); + fsh2.compile(); + + GfxConfig.materials[1].create(); + GfxConfig.materials[1].data.blend_mode = Material.BlendMode.mixed; + GfxConfig.materials[1].data.mode = Material.TransformMode.position; + Material.ShaderModule[1] modules2 = [Material.ShaderModule(vsh2,fsh2)]; + GfxConfig.materials[1].attachModules(modules2); + //GfxConfig.materials[0]. + //GfxConfig.materials[0].load(load_data.materials[i].str); + GfxConfig.materials[1].compile(); + GfxConfig.materials[1].bindAttribLocation("positions",0); + //GfxConfig.materials[1].bindAttribLocation("tex_coords",1); + //GfxConfig.materials[1].bindAttribLocation("depth",2); + //GfxConfig.materials[1].bindAttribLocation("vcolor",3); + GfxConfig.materials[1].link(); + + /* import std.stdio; + writeln("positions ",glGetAttribLocation(GfxConfig.materials[0].data.modules[0].gl_handle,"positions")); + writeln("tex_coords ",glGetAttribLocation(GfxConfig.materials[0].data.modules[0].gl_handle,"tex_coords")); + writeln("depth ",glGetAttribLocation(GfxConfig.materials[0].data.modules[0].gl_handle,"depth")); + writeln("vcolor ",glGetAttribLocation(GfxConfig.materials[0].data.modules[0].gl_handle,"vcolor"));*/ + + GfxConfig.materials[1].data.uniforms = Mallocator.makeArray!(Material.Uniform)(2); + GfxConfig.materials[1].data.uniforms[0] = Material.Uniform(Material.Type.float4, GfxConfig.materials[1].getLocation("matrix_1"), 0); + GfxConfig.materials[1].data.uniforms[1] = Material.Uniform(Material.Type.float4, GfxConfig.materials[1].getLocation("matrix_2"), 16); + //GfxConfig.materials[1].data.uniforms[2] = Material.Uniform(Material.Type.float4, GfxConfig.materials[0].getLocation("uv_transform"), 32); + //GfxConfig.materials[1].data.bindings = Mallocator.makeArray!(int)(1); + //GfxConfig.materials[1].data.bindings[0] = GfxConfig.materials[0].getLocation("tex"); + + + + + + + GfxConfig.materials[2].create(); + GfxConfig.materials[2].data.blend_mode = Material.BlendMode.opaque; + GfxConfig.materials[2].data.mode = Material.TransformMode.position; + //Material.ShaderModule[1] modules = [Material.ShaderModule(vsh,fsh)]; + GfxConfig.materials[2].attachModules(modules); + //GfxConfig.materials[0]. + //GfxConfig.materials[0].load(load_data.materials[i].str); + GfxConfig.materials[2].compile(); + GfxConfig.materials[2].bindAttribLocation("positions",0); + GfxConfig.materials[2].bindAttribLocation("tex_coords",1); + GfxConfig.materials[2].bindAttribLocation("depth",2); + GfxConfig.materials[2].bindAttribLocation("vcolor",3); + GfxConfig.materials[2].link(); + + /* import std.stdio; + writeln("positions ",glGetAttribLocation(GfxConfig.materials[0].data.modules[0].gl_handle,"positions")); + writeln("tex_coords ",glGetAttribLocation(GfxConfig.materials[0].data.modules[0].gl_handle,"tex_coords")); + writeln("depth ",glGetAttribLocation(GfxConfig.materials[0].data.modules[0].gl_handle,"depth")); + writeln("vcolor ",glGetAttribLocation(GfxConfig.materials[0].data.modules[0].gl_handle,"vcolor"));*/ + + GfxConfig.materials[2].data.uniforms = Mallocator.makeArray!(Material.Uniform)(3); + GfxConfig.materials[2].data.uniforms[0] = Material.Uniform(Material.Type.float4, GfxConfig.materials[0].getLocation("matrix_1"), 0); + GfxConfig.materials[2].data.uniforms[1] = Material.Uniform(Material.Type.float4, GfxConfig.materials[0].getLocation("matrix_2"), 16); + GfxConfig.materials[2].data.uniforms[2] = Material.Uniform(Material.Type.float4, GfxConfig.materials[0].getLocation("uv_transform"), 32); + GfxConfig.materials[2].data.bindings = Mallocator.makeArray!(int)(1); + GfxConfig.materials[2].data.bindings[0] = GfxConfig.materials[0].getLocation("tex"); + GfxConfig.materials[2].data.blend_mode = Material.BlendMode.additive; + + + + + + /*glUseProgram(0); glBindBuffer(GL_ARRAY_BUFFER, 0); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);*/ + + launcher.tool_circle = Mallocator.make!ToolCircle; } \ No newline at end of file diff --git a/demos/source/demos/particles.d b/demos/source/demos/particles.d new file mode 100644 index 0000000..6ed8ea7 --- /dev/null +++ b/demos/source/demos/particles.d @@ -0,0 +1,545 @@ +module demos.particles; + +import app; + +import bindbc.sdl; + +import cimgui.cimgui; + +import bubel.ecs.attributes; +import bubel.ecs.core; +import bubel.ecs.entity; +import bubel.ecs.manager; +import bubel.ecs.std; + +import ecs_utils.gfx.texture; +import ecs_utils.math.vector; +import ecs_utils.utils; + +import game_core.basic; + +import gui.attributes; + +extern(C): + +private enum float px = 1.0/512.0; + +/*####################################################################################################################### +------------------------------------------------ Components ------------------------------------------------------------------ +#######################################################################################################################*/ + +/*struct CLocation +{ + mixin ECS.Component; + + alias location this; + + vec2 location; +}*/ + +struct CTexCoords +{ + mixin ECS.Component; + + vec4 value; +} + +struct CColor +{ + mixin ECS.Component; + + alias value this; + + @GUIColor uint value = uint.max; +} + +struct CVelocity +{ + mixin ECS.Component; + + alias value this; + + vec2 value = vec2(0); +} + +struct CForceRange +{ + mixin ECS.Component; + + vec2 range = vec2(20,200); +} + +struct CAttractor +{ + mixin ECS.Component; + + //alias value this; + float strength = 0.2; +} + +struct CVortex +{ + mixin ECS.Component; + + float strength = 0.6; +} + +struct CDamping +{ + mixin ECS.Component; + + alias power this; + + @GUIRange(0,9) ubyte power = 0; +} + +struct CGravity +{ + mixin ECS.Component; +} + +struct CParticleLife +{ + mixin ECS.Component; + + this(float life_in_secs) + { + life = cast(int)(life_in_secs * 1000_000); + } + + alias life this; + + int life = 1000000; +} + +/*####################################################################################################################### +------------------------------------------------ Systems ------------------------------------------------------------------ +#######################################################################################################################*/ + +struct DrawSystem +{ + mixin ECS.System!32; + + struct EntitiesData + { + uint length; + //uint thread_id; + uint job_id; + //@readonly CTexCoords[] coords; + @readonly CLocation[] locations; + + @optional @readonly CColor[] color; + } + + void onUpdate(EntitiesData data) + { + if(launcher.renderer.prepared_items >= launcher.renderer.MaxObjects)return;//simple leave loop if max visible objects count was reached + + if(!data.color) + { + foreach(i; 0..data.length) + { + launcher.renderer.draw(particles_demo.texture, data.locations[i], vec2(2,2), vec4(246,64,2,2)*px, 0, 0x80808080, 0, 2, 0, data.job_id); + } + } + else + { + foreach(i; 0..data.length) + { + launcher.renderer.draw(particles_demo.texture, data.locations[i], vec2(2,2), vec4(246,64,2,2)*px, 0, data.color[i].value, 0, 2, 0, data.job_id); + } + } + + } +} + +struct MoveSystem +{ + mixin ECS.System!64; + + struct EntitiesData + { + uint length; + CLocation[] locations; + @readonly CVelocity[] velocity; + } + + void onUpdate(EntitiesData data) + { + foreach(i; 0..data.length) + { + data.locations[i] += data.velocity[i] * launcher.delta_time; + } + } +} + +struct MouseAttractSystem +{ + mixin ECS.System!64; + + struct EntitiesData + { + uint length; + @readonly CLocation[] locations; + CVelocity[] velocity; + } + + vec2 mouse_pos; + + bool onBegin() + { + if(!launcher.getKeyState(SDL_SCANCODE_SPACE))return false; + mouse_pos = launcher.mouse.position; + mouse_pos = vec2(mouse_pos.x, mouse_pos.y) * launcher.scalling - launcher.render_position; + return true; + } + + void onUpdate(EntitiesData data) + { + float speed = launcher.delta_time * 0.01; + foreach(i;0..data.length) + { + vec2 rel_pos = mouse_pos - data.locations[i]; + float len2 = rel_pos.x * rel_pos.x + rel_pos.y * rel_pos.y; + if(len2 < 0.1)len2 = 0.1; + data.velocity[i] = data.velocity[i] + rel_pos / len2 * speed; + } + } +} + +struct AttractSystem +{ + mixin ECS.System!64; + + struct EntitiesData + { + uint length; + @readonly CLocation[] locations; + CVelocity[] velocity; + } + + struct Updater + { + AttractSystem.EntitiesData data; + + void onUpdate(AttractorIterator.EntitiesData adata) + { + float speed = launcher.delta_time * 0.00004; + if(adata.vortex) + { + foreach(i;0..data.length) + { + foreach(j;0..adata.length) + { + vec2 rel_pos = data.locations[i] - adata.locations[j]; + float len2 = rel_pos.length2(); + float inv_len = rsqrt(len2); + + if(1 < adata.force_range[j].range.y*inv_len) + { + float dist = (adata.force_range[j].range.y - 0.4)*inv_len - 1; + + vec2 vec = rel_pos * inv_len; + vec2 cvec = vec2(-vec.y,vec.x); + + float sign = -1; + if(1 < adata.force_range[j].range.x*inv_len)sign = 1; + + float str = adata.attractor[j].strength * sign; + float vortex_str = adata.vortex[j].strength; + data.velocity[i] = data.velocity[i] + (rel_pos * str + cvec * vortex_str) * speed * dist; + } + } + } + } + else + { + foreach(i;0..data.length) + { + foreach(j;0..adata.length) + { + vec2 rel_pos = data.locations[i] - adata.locations[j]; + float len2 = rel_pos.length2(); + float inv_len = rsqrt(len2); + + if(1 < adata.force_range[j].range.y*inv_len) + { + float dist = (adata.force_range[j].range.y - 0.4)*inv_len - 1; + + vec2 vec = rel_pos; + + float sign = -1; + if(1 < adata.force_range[j].range.x*inv_len)sign = 1; + + float str = adata.attractor[j].strength * speed * dist * sign; + data.velocity[i] = data.velocity[i] + vec * str; + } + } + } + } + } + } + + void onUpdate(EntitiesData data) + { + Updater updater; + updater.data = data; + launcher.manager.callEntitiesFunction!AttractorIterator(&updater.onUpdate); + } +} + +struct AttractorIterator +{ + mixin ECS.System!1; + + struct EntitiesData + { + uint length; + @readonly CLocation[] locations; + @readonly CAttractor[] attractor; + @readonly CForceRange[] force_range; + @optional @readonly CVortex[] vortex; + } + + bool onBegin() + { + return false; + } + + void onUpdate(EntitiesData data) + { + + } +} + +struct PlayAreaSystem +{ + mixin ECS.System!32; + + struct EntitiesData + { + uint length; + Entity[] entity; + @readonly CLocation[] locations; + } + + void onUpdate(EntitiesData data) + { + foreach(i; 0..data.length) + { + if(data.locations[i].x > 400)launcher.manager.removeEntity(data.entity[i].id); + else if(data.locations[i].x < 0)launcher.manager.removeEntity(data.entity[i].id); + if(data.locations[i].y > 300)launcher.manager.removeEntity(data.entity[i].id); + else if(data.locations[i].y < 0)launcher.manager.removeEntity(data.entity[i].id); + } + } +} + +struct DampingSystem +{ + mixin ECS.System!32; + + struct EntitiesData + { + uint length; + const (Entity)[] entity; + @readonly CDamping[] damping; + CVelocity[] velocity; + } + + float[10] damp = 0; + + bool onBegin() + { + foreach(i;0..10) + { + damp[i] = powf((0.99 - cast(float)i * 0.01),launcher.delta_time*0.1); + } + + return true; + } + + void onUpdate(EntitiesData data) + { + foreach(i; 0..data.length) + { + data.velocity[i] = data.velocity[i] * damp[data.damping[i]]; + } + } +} + +struct ParticleLifeSystem +{ + mixin ECS.System!32; + + struct EntitiesData + { + uint length; + const (Entity)[] entity; + CParticleLife[] life; + } + + int delta_time; + + bool onBegin() + { + delta_time = cast(int)(launcher.delta_time * 1000); + return true; + } + + void onUpdate(EntitiesData data) + { + foreach(i; 0..data.length) + { + data.life[i] -= delta_time; + if(data.life[i] < 0)launcher.manager.removeEntity(data.entity[i].id); + } + } +} + +struct GravitySystem +{ + mixin ECS.System!32; + + struct EntitiesData + { + uint length; + const (Entity)[] entity; + @readonly CGravity[] gravity; + CVelocity[] velocity; + } + + void onUpdate(EntitiesData data) + { + float delta_time = launcher.delta_time * 0.00_092; + foreach(i; 0..data.length) + { + data.velocity[i].y -= delta_time; + } + } +} + +/*####################################################################################################################### +------------------------------------------------ Functions ------------------------------------------------------------------ +#######################################################################################################################*/ + +struct ParticlesDemo +{ + __gshared const (char)* tips = "Use \"space\" to spwan entities.\n\nSystems can be enabled/disabled from \"Simple\" window."; + + Texture texture; +} + +__gshared ParticlesDemo* particles_demo; + +void particlesStart() +{ + particles_demo = Mallocator.make!ParticlesDemo; + + particles_demo.texture.create(); + particles_demo.texture.load("assets/textures/atlas.png"); + + launcher.manager.beginRegister(); + + launcher.manager.registerComponent!CLocation; + launcher.manager.registerComponent!CTexCoords; + launcher.manager.registerComponent!CColor; + launcher.manager.registerComponent!CVelocity; + launcher.manager.registerComponent!CAttractor; + launcher.manager.registerComponent!CDamping; + launcher.manager.registerComponent!CGravity; + launcher.manager.registerComponent!CVortex; + launcher.manager.registerComponent!CParticleLife; + launcher.manager.registerComponent!CForceRange; + + launcher.manager.registerSystem!MoveSystem(0); + launcher.manager.registerSystem!DrawSystem(100); + launcher.manager.registerSystem!PlayAreaSystem(102); + launcher.manager.registerSystem!AttractSystem(-1); + launcher.manager.registerSystem!MouseAttractSystem(1); + launcher.manager.registerSystem!DampingSystem(101); + launcher.manager.registerSystem!ParticleLifeSystem(-10); + launcher.manager.registerSystem!GravitySystem(-2); + + launcher.manager.registerSystem!AttractorIterator(-1); + + launcher.manager.endRegister(); + + launcher.gui_manager.addSystem(MoveSystem.system_id,"Move System"); + launcher.gui_manager.addSystem(DrawSystem.system_id,"Draw System"); + launcher.gui_manager.addSystem(PlayAreaSystem.system_id,"Play Area System"); + launcher.gui_manager.addSystem(AttractSystem.system_id,"Attract System"); + launcher.gui_manager.addSystem(MouseAttractSystem.system_id,"Mouse Attract System"); + launcher.gui_manager.addSystem(DampingSystem.system_id,"Damping System"); + launcher.gui_manager.addSystem(ParticleLifeSystem.system_id,"Particle Life System"); + + launcher.gui_manager.addComponent(CColor(),"Color (white)"); + launcher.gui_manager.addComponent(CColor(0xFF101540),"Color (red)"); + launcher.gui_manager.addComponent(CColor(0xFF251010),"Color (blue)"); + launcher.gui_manager.addComponent(CColor(0xFF102010),"Color (green)"); + launcher.gui_manager.addComponent(CAttractor(0.1),"Attractor (str 0.1)"); + launcher.gui_manager.addComponent(CForceRange(vec2(5,40)),"ForceRange (5,40)"); + launcher.gui_manager.addComponent(CVelocity(),"Velocity"); + launcher.gui_manager.addComponent(CDamping(),"Damping"); + launcher.gui_manager.addComponent(CVortex(),"Vortex"); + launcher.gui_manager.addComponent(CParticleLife(),"Particle Life"); + launcher.gui_manager.addComponent(CGravity(),"Gravity"); + + EntityTemplate* tmpl; + EntityTemplate* base_tmpl = launcher.manager.allocateTemplate([CLocation.component_id, CColor.component_id, CVelocity.component_id, CDamping.component_id].staticArray); + launcher.gui_manager.addTemplate(base_tmpl,"Particle"); + tmpl = launcher.manager.allocateTemplate(base_tmpl); + tmpl.getComponent!CColor().value = 0xFF251010; + launcher.gui_manager.addTemplate(tmpl,"Particle (blue)"); + tmpl = launcher.manager.allocateTemplate(base_tmpl); + tmpl.getComponent!CColor().value = 0xFF102010; + launcher.gui_manager.addTemplate(tmpl,"Particle (green)"); + tmpl = launcher.manager.allocateTemplate(base_tmpl); + tmpl.getComponent!CColor().value = 0xFF101540; + launcher.gui_manager.addTemplate(tmpl,"Particle (red)"); + // tmpl = launcher.manager.allocateTemplate(tmpl, [CDamping.component_id].staticArray); + // launcher.gui_manager.addTemplate(tmpl,"Particle (damping)"); + tmpl = launcher.manager.allocateTemplate(tmpl); + tmpl.getComponent!CDamping().power = 4; + launcher.gui_manager.addTemplate(tmpl,"Particle (damping!)"); + tmpl = launcher.manager.allocateTemplate([CAttractor.component_id, CLocation.component_id, CForceRange.component_id].staticArray); + launcher.gui_manager.addTemplate(tmpl,"Attractor"); + tmpl = launcher.manager.allocateTemplate(tmpl, [CVortex.component_id].staticArray); + launcher.gui_manager.addTemplate(tmpl,"Vortex"); + tmpl = launcher.manager.allocateTemplate(tmpl); + tmpl.getComponent!CVortex().strength = -0.6; + launcher.gui_manager.addTemplate(tmpl,"Vortex (reversed)"); + +} + +void particlesEnd() +{ + particles_demo.texture.destroy(); + + //launcher.manager.freeTemplate(simple.tmpl); + Mallocator.dispose(particles_demo); +} + +void particlesEvent(SDL_Event* event) +{ +} + +bool particlesLoop() +{ + launcher.render_position = (vec2(launcher.window_size.x,launcher.window_size.y)*launcher.scalling - vec2(400,300)) * 0.5; + + launcher.manager.begin(); + if(launcher.multithreading) + { + launcher.job_updater.begin(); + launcher.manager.updateMT(); + launcher.job_updater.call(); + } + else + { + launcher.manager.update(); + } + launcher.manager.end(); + + return true; +} \ No newline at end of file diff --git a/demos/source/demos/simple.d b/demos/source/demos/simple.d index 313cc00..ac3b3f7 100644 --- a/demos/source/demos/simple.d +++ b/demos/source/demos/simple.d @@ -4,46 +4,38 @@ import app; import bindbc.sdl; -import cimgui.cimgui; - import bubel.ecs.attributes; import bubel.ecs.core; import bubel.ecs.entity; import bubel.ecs.manager; import bubel.ecs.std; +import cimgui.cimgui; + import ecs_utils.gfx.texture; import ecs_utils.math.vector; import ecs_utils.utils; +import game_core.basic; + extern(C): -struct Simple -{ - __gshared const (char)* tips = "Use \"space\" to spwan entities.\n\nSystems can be enabled/disabled from \"Simple\" window."; +/*####################################################################################################################### +------------------------------------------------ Components ------------------------------------------------------------------ +#######################################################################################################################*/ - EntityTemplate* tmpl; - Texture texture; - - bool move_system = true; - bool draw_system = true; -} - -struct CLocation +/*struct CLocation { mixin ECS.Component; alias location this; vec2 location; -} +}*/ -struct CTexture -{ - mixin ECS.Component; - - Texture tex; -} +/*####################################################################################################################### +------------------------------------------------ Systems ------------------------------------------------------------------ +#######################################################################################################################*/ struct DrawSystem { @@ -54,7 +46,6 @@ struct DrawSystem uint length; //uint thread_id; uint job_id; - @readonly CTexture[] textures; @readonly CLocation[] locations; } @@ -63,7 +54,7 @@ struct DrawSystem if(launcher.renderer.prepared_items >= launcher.renderer.MaxObjects)return;//simple leave loop if max visible objects count was reached foreach(i; 0..data.length) { - launcher.renderer.draw(data.textures[i].tex, data.locations[i].location, vec2(16,16), vec4(0,0,1,1), cast(ushort)(data.locations[i].y), 0x80808080, 0, 0, 0, data.job_id); + launcher.renderer.draw(simple.texture, data.locations[i], vec2(16,16), vec4(0,0,1,1), cast(ushort)(data.locations[i].y), 0x80808080, 0, 0, 0, data.job_id); // launcher.renderer.draw(data.textures[i].tex, data.locations[i].location, vec2(16,16), vec4(0,0,1,1), 0, 0x80808080, 0, 0, 0, data.job_id); //draw(renderer, data.textures[i].tex, data.locations[i], vec2(32,32), vec4(0,0,1,1)); } @@ -85,12 +76,24 @@ struct MoveSystem { foreach(i; 0..data.length) { - data.locations[i].location.y = data.locations[i].location.y + 1; - if(data.locations[i].location.y > 300)data.locations[i].location.y = 0; + data.locations[i].y = data.locations[i].y + 1; + if(data.locations[i].y > 300)data.locations[i].y = 0; } } } +/*####################################################################################################################### +------------------------------------------------ Functions ------------------------------------------------------------------ +#######################################################################################################################*/ + +struct Simple +{ + __gshared const (char)* tips = "Use \"space\" to spwan entities.\n\nSystems can be enabled/disabled from \"Simple\" window."; + + EntityTemplate* tmpl; + Texture texture; +} + __gshared Simple* simple; void simpleStart() @@ -103,7 +106,6 @@ void simpleStart() launcher.manager.beginRegister(); launcher.manager.registerComponent!CLocation; - launcher.manager.registerComponent!CTexture; launcher.manager.registerSystem!MoveSystem(0); launcher.manager.registerSystem!DrawSystem(1); @@ -113,19 +115,17 @@ void simpleStart() launcher.gui_manager.addSystem(MoveSystem.system_id,"Move System"); launcher.gui_manager.addSystem(DrawSystem.system_id,"Draw System"); - ushort[2] components = [CLocation.component_id, CTexture.component_id]; + ushort[1] components = [CLocation.component_id]; simple.tmpl = launcher.manager.allocateTemplate(components); - CTexture* tex_comp = simple.tmpl.getComponent!CTexture; - tex_comp.tex = simple.texture; - CLocation* loc_comp = simple.tmpl.getComponent!CLocation; + //CLocation* loc_comp = simple.tmpl.getComponent!CLocation; launcher.gui_manager.addTemplate(simple.tmpl, "Basic"); foreach(i; 0..10) foreach(j; 0..10) { - loc_comp.location = vec2(i*16+64,j*16+64); - launcher.manager.addEntity(simple.tmpl); + //loc_comp.value = vec2(i*16+64,j*16+64); + launcher.manager.addEntity(simple.tmpl,[CLocation(vec2(i*16+64,j*16+64)).ref_].staticArray); } } @@ -140,46 +140,15 @@ void simpleEnd() Mallocator.dispose(simple); } -void simpleTool(vec2 position, Tool tool, int size) -{ - switch(tool) - { - case Tool.entity_spawner: - { - EntityTemplate* tmpl = launcher.gui_manager.getSelectedTemplate(); - CLocation* location = tmpl.getComponent!CLocation; - if(location) - { - position.x += (randomf - 0.5) * size; - position.y += (randomf - 0.5) * size; - if(position.x > 400)position.x -= 400; - else if(position.x < 0)position.x += 400; - if(position.y > 300)position.y -= 300; - else if(position.y < 0)position.y += 300; - *location = position; - } - launcher.manager.addEntity(tmpl); - } - break; - default: - break; - } -} - void simpleEvent(SDL_Event* event) { - /*if(event.type == event.button) - { - vec2 position = vec2(event.button.x, event.button.y); - - }*/ } void spawnEntity() { - CLocation* loc_comp = simple.tmpl.getComponent!CLocation; - loc_comp.location = vec2(randomf() * 400,0); - launcher.manager.addEntity(simple.tmpl); + //CLocation* loc_comp = simple.tmpl.getComponent!CLocation; + //loc_comp.value = vec2(randomf() * 400,0); + launcher.manager.addEntity(simple.tmpl,[CLocation(vec2(randomf() * 400,0)).ref_].staticArray); } bool simpleLoop() @@ -188,7 +157,7 @@ bool simpleLoop() if(launcher.getKeyState(SDL_SCANCODE_SPACE)) { - foreach(i;0..1)spawnEntity(); + foreach(i;0..20)spawnEntity(); } launcher.manager.begin(); diff --git a/demos/source/demos/snake.d b/demos/source/demos/snake.d index 01e9a36..f46009c 100644 --- a/demos/source/demos/snake.d +++ b/demos/source/demos/snake.d @@ -4,8 +4,6 @@ import app; import bindbc.sdl; -import cimgui.cimgui; - import bubel.ecs.attributes; import bubel.ecs.core; import bubel.ecs.entity; @@ -13,10 +11,14 @@ import bubel.ecs.manager; import bubel.ecs.std; import bubel.ecs.vector; +import cimgui.cimgui; + import ecs_utils.gfx.texture; import ecs_utils.math.vector; import ecs_utils.utils; +import game_core.basic; + //import std.array : staticArray; enum float px = 1.0/512.0; @@ -31,22 +33,6 @@ struct MapElement apple = 1, wall = 2, snake = 3, - - /* snake_head_up = 5, - snake_head_down = 6, - snake_head_left = 7, - snake_head_right = 8, - snake_tail_up = 9, - snake_tail_down = 10, - snake_tail_left = 11, - snake_tail_right = 12, - snake_turn_ld = 13, - snake_turn_lu = 14, - snake_turn_rd = 15, - snake_turn_ru = 16, - snake_vertical = 17, - snake_horizontal = 18*/ - } Type type; EntityID id; @@ -129,10 +115,7 @@ struct Snake } if(base_pos.x == random_pos.x && base_pos.y == random_pos.y)return; } - //CILocation* location = apple_tmpl.getComponent!CILocation; - //*location = random_pos; - //Entity* apple = - launcher.manager.addEntity(apple_tmpl,[CILocation(random_pos).ref_].staticArray); + launcher.manager.addEntity(apple_tmpl,[CLocation(cast(vec2)(random_pos)*16).ref_].staticArray); } } @@ -158,14 +141,14 @@ struct CILocation ivec2 location; } -struct CLocation -{ - mixin ECS.Component; +// struct CLocation +// { +// mixin ECS.Component; - alias location this; +// alias location this; - vec2 location = vec2(0,0); -} +// vec2 location = vec2(0,0); +// } struct CSnake { @@ -264,8 +247,8 @@ struct AppleSystem struct EntitiesData { uint length; - @readonly Entity[] entities; - @readonly CApple[] movement; + @readonly Entity[] entity; + @readonly CApple[] apple; @readonly CILocation[] location; } @@ -273,7 +256,17 @@ struct AppleSystem { foreach(i;0..data.length) { - snake.element(MapElement(MapElement.Type.apple,data.entities[i].id),data.location[i]); + if(snake.element(data.location[i]).id == EntityID())snake.element(MapElement(MapElement.Type.apple,data.entity[i].id),data.location[i]); + else launcher.manager.removeEntity(data.entity[i].id); + } + } + + void onRemoveEntity(EntitiesData data) + { + foreach(i;0..data.length) + { + if(snake.element(data.location[i].location).id == data.entity[i].id) + snake.element(MapElement(MapElement.Type.empty, EntityID()),data.location[i].location); } } } @@ -315,7 +308,7 @@ struct ParticleMovementSystem { foreach(i;0..data.length) { - data.location[i].location -= data.movement[i].velocity; + data.location[i] -= data.movement[i].velocity; } } } @@ -357,7 +350,7 @@ struct AnimationRenderSystem { foreach(i;0..data.length) { - launcher.renderer.draw(snake.texture, cast(vec2)cast(ivec2)data.location[i].location, vec2(16,16), data.animation[i].frames[cast(int)(data.animation[i].time)], -1, 0x80808080); + launcher.renderer.draw(snake.texture, cast(vec2)cast(ivec2)data.location[i], vec2(16,16), data.animation[i].frames[cast(int)(data.animation[i].time)], -1, 0x80808080); } } } @@ -477,7 +470,12 @@ struct MoveSystem break; case MapElement.Type.apple: launcher.manager.removeEntity(snake.element(data.location[i].location).id); - if(data.snakes[i].parts.length < 100)data.snakes[i].parts.add(new_location); + if(data.snakes[i].parts.length >= 99) + { + snake.addApple(); + goto case(MapElement.Type.empty); + } + data.snakes[i].parts.add(new_location); if(data.snakes[i].parts.length > 1) { @@ -506,7 +504,40 @@ struct MoveSystem } } } - + } +} + +struct SnakeSystem +{ + mixin ECS.System!1; + + struct EntitiesData + { + uint length; + Entity[] entity; + @readonly CSnake[] snake; + @readonly CILocation[] location; + } + + void onAddSystem(EntitiesData data) + { + foreach(i;0..data.length) + { + if(snake.element(data.location[i]).id == EntityID())snake.element(MapElement(MapElement.Type.snake,data.entity[i].id),data.location[i]); + else launcher.manager.removeEntity(data.entity[i].id); + } + } + + void onRemoveEntity(EntitiesData data) + { + foreach(i;0..data.length) + { + if(snake.element(data.location[i].location).id == data.entity[i].id) + snake.element(MapElement(MapElement.Type.empty, EntityID()),data.location[i].location); + foreach(part; data.snake[i].parts.array) + if(snake.element(part).id == data.entity[i].id) + snake.element(MapElement(MapElement.Type.empty, EntityID()),part); + } } } @@ -750,6 +781,35 @@ struct CleanSystem } } +struct CopyLocationSystem +{ + mixin ECS.System!32; + + struct EntitiesData + { + uint length; + const (Entity)[] entity; + CLocation[] location; + @readonly CILocation[] ilocation; + } + + void onAddEntity(EntitiesData data) + { + foreach(i;0..data.length) + { + data.ilocation[i] = cast(ivec2)(data.location[i] / 16); + } + } + + void onUpdate(EntitiesData data) + { + foreach(i;0..data.length) + { + data.location[i] = cast(vec2)(data.ilocation[i] * 16); + } + } +} + __gshared Snake* snake; void snakeStart() @@ -776,7 +836,6 @@ void snakeStart() launcher.manager.registerSystem!MoveSystem(0,"fixed"); launcher.manager.registerSystem!InputSystem(-100); launcher.manager.registerSystem!FixSnakeDirectionSystem(-1,"fixed"); - launcher.manager.registerSystem!AppleSystem(-1,"fixed"); launcher.manager.registerSystem!AnimationRenderSystem(100); launcher.manager.registerSystem!AnimationSystem(-1); launcher.manager.registerSystem!ParticleSystem(-1); @@ -784,8 +843,20 @@ void snakeStart() launcher.manager.registerSystem!DrawAppleSystem(99); launcher.manager.registerSystem!DrawSnakeSystem(101); + launcher.manager.registerSystem!CopyLocationSystem(100); + //launcher.manager.registerSystem!AppleRemoveSystem(100); + launcher.manager.registerSystem!AppleSystem(101); + launcher.manager.registerSystem!SnakeSystem(101); + launcher.manager.endRegister(); + launcher.gui_manager.addComponent(CApple(),"Apple"); + launcher.gui_manager.addComponent(CSnake(),"Snake"); + launcher.gui_manager.addComponent(CParticle(1000),"Particle (1s)"); + launcher.gui_manager.addComponent(CParticleVector(vec2(0,1)),"Particle Vector (UP)"); + launcher.gui_manager.addComponent(CInput(),"Input"); + launcher.gui_manager.addComponent(CMovement(CMovement.Direction.up),"Movement (UP)"); + launcher.gui_manager.addSystem(MoveSystem.system_id,"Move System"); launcher.gui_manager.addSystem(InputSystem.system_id,"Input System"); launcher.gui_manager.addSystem(FixSnakeDirectionSystem.system_id,"Fix Direction System"); @@ -797,15 +868,13 @@ void snakeStart() snake.snake_destroy_particle_frames = Mallocator.makeArray([vec4(64,144,16,16)*px,vec4(80,144,16,16)*px,vec4(96,144,16,16)*px,vec4(112,144,16,16)*px].staticArray); { - ushort[4] components = [CILocation.component_id, CSnake.component_id, CMovement.component_id, CInput.component_id]; + ushort[5] components = [CILocation.component_id, CSnake.component_id, CMovement.component_id, CInput.component_id, CLocation.component_id]; snake.snake_tmpl = launcher.manager.allocateTemplate(components); - //CILocation* loc_comp = snake.snake_tmpl.getComponent!CILocation; - //*loc_comp = ivec2(2,2); launcher.manager.addEntity(snake.snake_tmpl,[CILocation(ivec2(2,2)).ref_].staticArray); } { - snake.snake_destroy_particle = launcher.manager.allocateTemplate([CLocation.component_id, CParticle.component_id, CParticleVector.component_id, CAnimation.component_id].staticArray); + snake.snake_destroy_particle = launcher.manager.allocateTemplate([CLocation.component_id, CParticle.component_id, CParticleVector.component_id, CAnimation.component_id, CLocation.component_id].staticArray); CAnimation* canim = snake.snake_destroy_particle.getComponent!CAnimation; canim.frames = snake.snake_destroy_particle_frames; CParticle* particle = snake.snake_destroy_particle.getComponent!CParticle; @@ -813,7 +882,7 @@ void snakeStart() } { - ushort[2] components = [CILocation.component_id, CApple.component_id]; + ushort[3] components = [CILocation.component_id, CApple.component_id, CLocation.component_id]; snake.apple_tmpl = launcher.manager.allocateTemplate(components); snake.addApple(); } @@ -824,13 +893,6 @@ void snakeStart() MoveSystem* move_system = launcher.manager.getSystem!MoveSystem(); move_system.setTemplates(); - - /*foreach(i; 0..10) - foreach(j; 0..10) - { - loc_compation = vec2(i*32+64,j*32+64); - launcher.manager.addEntity(simple.tmpl); - }*/ } void snakeEnd() @@ -839,39 +901,6 @@ void snakeEnd() Mallocator.dispose(snake); } -void snakeTool(vec2 position, Tool tool, int size) -{ - switch(tool) - { - case Tool.entity_spawner: - { - EntityTemplate* tmpl = launcher.gui_manager.getSelectedTemplate(); - CLocation* location = tmpl.getComponent!CLocation; - if(location) - { - position.x += (randomf() - 0.5) * size; - position.y += (randomf() - 0.5) * size; - *location = position; - } - CILocation* ilocation = tmpl.getComponent!CILocation; - if(ilocation) - { - position.x += (randomf() - 0.5) * size; - position.y += (randomf() - 0.5) * size; - ivec2 ipos; - ipos.x = cast(int)(position.x / 16); - ipos.y = cast(int)(position.y / 16); - *ilocation = ipos; - if(snake.element(ipos).type != MapElement.Type.empty)return; - } - launcher.manager.addEntity(tmpl); - } - break; - default: - break; - } -} - void snakeEvent(SDL_Event* event) { @@ -881,16 +910,16 @@ bool snakeLoop() { launcher.render_position = (vec2(launcher.window_size.x,launcher.window_size.y)*launcher.scalling - vec2(288,288)) * 0.5; - /*if(launcher.show_demo_wnd) - { - igSetNextWindowPos(ImVec2(800 - 260, 30), ImGuiCond_Once, ImVec2(0,0)); - igSetNextWindowSize(ImVec2(250, 0), ImGuiCond_Once); - if(igBegin("Snake",&launcher.show_demo_wnd,0)) - { + // if(launcher.show_demo_wnd) + // { + // igSetNextWindowPos(ImVec2(800 - 260, 30), ImGuiCond_Once, ImVec2(0,0)); + // igSetNextWindowSize(ImVec2(250, 0), ImGuiCond_Once); + // if(igBegin("Snake",&launcher.show_demo_wnd,0)) + // { - } - igEnd(); - }*/ + // } + // igEnd(); + // } launcher.manager.begin(); @@ -912,7 +941,5 @@ bool snakeLoop() launcher.manager.end(); - //snake.drawMap(); - return true; } \ No newline at end of file diff --git a/demos/source/demos/space_invaders.d b/demos/source/demos/space_invaders.d index 45dd06d..ce2cd6a 100644 --- a/demos/source/demos/space_invaders.d +++ b/demos/source/demos/space_invaders.d @@ -4,25 +4,26 @@ import app; import bindbc.sdl; -import cimgui.cimgui; - import bubel.ecs.attributes; import bubel.ecs.core; import bubel.ecs.entity; import bubel.ecs.manager; import bubel.ecs.std; +import cimgui.cimgui; + import ecs_utils.gfx.texture; import ecs_utils.math.vector; import ecs_utils.utils; +import game_core.basic; + //import std.math : PI; -enum PI = 3.141592653589793238462643383279502884197169399375105820; //import std.array : staticArray; -enum float px = 1.0/512.0; +private enum float px = 1.0/512.0; extern(C): @@ -114,14 +115,14 @@ enum Direction : byte ------------------------------------------------ Components ------------------------------------------------------------------ #######################################################################################################################*/ -struct CLocation +/*struct CLocation { mixin ECS.Component; alias value this; vec2 value = vec2(0); -} +}*/ struct CScale { @@ -273,7 +274,7 @@ struct CTargetParent mixin ECS.Component; EntityID parent; - vec2 rel_pos; + vec2 rel_pos = vec2(0,0); } @@ -699,7 +700,7 @@ struct ShipWeaponSystem Entity[] entity; CInit[] init; //CShip[] ship; - //CChildren[] children; + CChildren[] children; } struct Ship @@ -1062,7 +1063,7 @@ struct CollisionSystem } } -struct LaserShootingSystem +struct ShootingSystem { mixin ECS.System!32; @@ -1187,7 +1188,7 @@ struct LaserShootingSystem else fire_velocity.value = vec2(0,0); fire_location.value = data.location[i]; - if(data.shoot_direction[i].direction == Direction.down) + if(data.shoot_direction && data.shoot_direction[i].direction == Direction.down) { fire_rotation.value = PI; //fire_location.value.y -= 16; @@ -1270,7 +1271,7 @@ struct DampingSystem } } -struct LaserCollisionSystem +struct BulletsCollisionSystem { mixin ECS.System!32; @@ -1423,9 +1424,12 @@ struct UpgradeSystem if(ship) { CChildren* children = entity.getComponent!CChildren; - foreach(child;children.childern) + if(children) { - launcher.manager.sendEvent(child,EUpgrade()); + foreach(child;children.childern) + { + launcher.manager.sendEvent(child,EUpgrade()); + } } } } @@ -1742,7 +1746,7 @@ struct ShootWaveSystem CLocation* location = entity.getComponent!CLocation; CGuild* guild = entity.getComponent!CGuild; - //LaserShootingSystem.bullet_tmpl + //ShootingSystem.bullet_tmpl EntityTemplate* tmpl = space_invaders.bullet_tmpl[wave.bullet_type]; foreach(dir;dirs) { @@ -2180,12 +2184,6 @@ struct CShipIterator //void handleEvent(Entity* entity, ) }//*/ -extern(C) float sqrtf(float x) @nogc nothrow @system; -extern(C) float acosf(float x) @nogc nothrow @system; -extern(C) float sinf(float x) @nogc nothrow @system; -extern(C) float cosf(float x) @nogc nothrow @system; -extern(C) float powf(float x, float y) @nogc nothrow @system; - /** *System is responsible for movement of objects with CInput component. *In this example every entity has same speed when using movement system. @@ -2348,9 +2346,9 @@ void spaceInvadersStart() launcher.manager.registerSystem!InputMovementSystem(-100); launcher.manager.registerSystem!MovementSystem(-99); launcher.manager.registerSystem!ClampPositionSystem(-90); - launcher.manager.registerSystem!LaserShootingSystem(0); + launcher.manager.registerSystem!ShootingSystem(0); launcher.manager.registerSystem!ChangeDirectionSystem(0); - launcher.manager.registerSystem!LaserCollisionSystem(-70); + launcher.manager.registerSystem!BulletsCollisionSystem(-70); launcher.manager.registerSystem!ShootGridManager(-80); launcher.manager.registerSystem!ShootGridCleaner(-101); launcher.manager.registerSystem!HitPointsSystem(0); @@ -2374,13 +2372,49 @@ void spaceInvadersStart() launcher.manager.endRegister(); + launcher.gui_manager.addComponent(CInput(),"Input"); + launcher.gui_manager.addComponent(CShip(),"Ship"); + launcher.gui_manager.addComponent(CEnemy(),"Enemy"); + launcher.gui_manager.addComponent(CAutoShoot(),"Auto Shoot"); + launcher.gui_manager.addComponent(CWeapon(0, CWeapon.Type.laser),"Weapon (laser)"); + launcher.gui_manager.addComponent(CVelocity(vec2(0,0)),"Velocity (0,0)"); + launcher.gui_manager.addComponent(CBullet(),"Bullet (dmg1)"); + launcher.gui_manager.addComponent(CSideMove(),"Side Move"); + launcher.gui_manager.addComponent(CSideMove(0),"Side Move (g1)"); + launcher.gui_manager.addComponent(CSideMove(1),"Side Move (g2)"); + launcher.gui_manager.addComponent(CShootGrid(),"Shoot Grid"); + launcher.gui_manager.addComponent(CGuild(),"Guild (Player)"); + launcher.gui_manager.addComponent(CGuild(1),"Guild (Enemy)"); + launcher.gui_manager.addComponent(CHitPoints(10),"Hit Points (10)"); + launcher.gui_manager.addComponent(CHitMark(),"Hit Mark"); + launcher.gui_manager.addComponent(CUpgrade(CUpgrade.Upgrade.laser),"Upgrade (laser)"); + launcher.gui_manager.addComponent(CParticle(1000),"Particle (1s)"); + //launcher.gui_manager.addComponent(CMaxHitPoints(),"Max Hit Points"); + launcher.gui_manager.addComponent(CDamping(0),"Damping (0)"); + launcher.gui_manager.addComponent(CDamping(4),"Damping (4)"); + launcher.gui_manager.addComponent(CDamping(8),"Damping (8)"); + launcher.gui_manager.addComponent(CTargetParent(),"Target Parent"); + launcher.gui_manager.addComponent(CTargetPlayerShip(),"Target Player Ship"); + launcher.gui_manager.addComponent(CTarget(),"Target"); + launcher.gui_manager.addComponent(CChildren(),"Children"); + launcher.gui_manager.addComponent(CWeaponLocation(vec2(0,16)),"Weapon Location (0,16)"); + launcher.gui_manager.addComponent(CInit(CInit.Type.space_ship),"Init (Ship)"); + launcher.gui_manager.addComponent(CInit(CInit.Type.boss),"Init (Boss)"); + launcher.gui_manager.addComponent(CInit(CInit.Type.tower),"Init (Tower)"); + launcher.gui_manager.addComponent(CBoss(),"Boss"); + launcher.gui_manager.addComponent(CColliderScale(),"Collider Scale"); + launcher.gui_manager.addComponent(CParticleEmitter(),"Particle Emitter"); + launcher.gui_manager.addComponent(CParticleEmitterTime(),"Particle Emitter Time"); + //launcher.gui_manager.addComponent(CSpawnUponDeath(),"Spawn Upon Death"); + launcher.gui_manager.addComponent(CShootWaveUponDeath(CWeapon.Type.canon),"Wave Upon Death"); + launcher.gui_manager.addSystem(DrawSystem.system_id,"Draw System"); launcher.gui_manager.addSystem(InputMovementSystem.system_id,"Input Movement"); - launcher.gui_manager.addSystem(LaserShootingSystem.system_id,"Laser Shooting"); + launcher.gui_manager.addSystem(ShootingSystem.system_id,"Shooting System"); launcher.gui_manager.addSystem(MovementSystem.system_id,"Movement System"); launcher.gui_manager.addSystem(ClampPositionSystem.system_id,"Clamp Position System"); launcher.gui_manager.addSystem(ChangeDirectionSystem.system_id,"Change Direction System"); - launcher.gui_manager.addSystem(LaserCollisionSystem.system_id,"Laser Collision System"); + launcher.gui_manager.addSystem(BulletsCollisionSystem.system_id,"Bullets Collision System"); launcher.gui_manager.addSystem(ShootGridManager.system_id,"Shoot Grid Manager"); launcher.gui_manager.addSystem(ShootGridCleaner.system_id,"Shoot Grid Cleaner"); launcher.gui_manager.addSystem(HitPointsSystem.system_id,"Hit Points System"); @@ -2560,7 +2594,7 @@ void spaceInvadersEnd() { /*launcher.manager.getSystem(DrawSystem.system_id).disable(); launcher.manager.getSystem(InputMovementSystem.system_id).disable(); - launcher.manager.getSystem(LaserShootingSystem.system_id).disable(); + launcher.manager.getSystem(ShootingSystem.system_id).disable(); launcher.manager.getSystem(MovementSystem.system_id).disable(); launcher.manager.getSystem(ClampPositionSystem.system_id).disable(); launcher.manager.getSystem(ShootGridCleaner.system_id).disable();*/ @@ -2570,35 +2604,6 @@ void spaceInvadersEnd() space_invaders = null; } -void spaceInvadersTool(vec2 position, Tool tool, int size) -{ - switch(tool) - { - case Tool.entity_spawner: - { - EntityTemplate* tmpl = launcher.gui_manager.getSelectedTemplate(); - CLocation* location = tmpl.getComponent!CLocation; - if(location) - { - position.x += (randomf - 0.5) * size; - position.y += (randomf - 0.5) * size; - if(position.y < 16)position.y = 16; - else if(position.y > 299)position.y = 299; - *location = position; - } - CWeapon* laser_weapon = tmpl.getComponent!CWeapon; - if(laser_weapon) - { - laser_weapon.shoot_time = randomf * CWeapon.levels[laser_weapon.level - 1].reload_time; - } - launcher.manager.addEntity(tmpl); - } - break; - default: - break; - } -} - void spaceInvadersEvent(SDL_Event* event) { diff --git a/demos/source/game_core/basic.d b/demos/source/game_core/basic.d new file mode 100644 index 0000000..993a5aa --- /dev/null +++ b/demos/source/game_core/basic.d @@ -0,0 +1,14 @@ +module game_core.basic; + +import bubel.ecs.core; + +import ecs_utils.math.vector; + +struct CLocation +{ + mixin ECS.Component; + + alias value this; + + vec2 value = vec2(0); +} \ No newline at end of file diff --git a/demos/source/gui/attributes.d b/demos/source/gui/attributes.d new file mode 100644 index 0000000..53605c2 --- /dev/null +++ b/demos/source/gui/attributes.d @@ -0,0 +1,20 @@ +module gui.attributes; + +enum GUIColor = "GUIColor"; + +struct GUIRange +{ + union + { + struct + { + int min; + int max; + } + struct + { + float minf; + float maxf; + } + } +} \ No newline at end of file diff --git a/demos/source/gui/component.d b/demos/source/gui/component.d index bbd7ec5..b19f069 100644 --- a/demos/source/gui/component.d +++ b/demos/source/gui/component.d @@ -1,6 +1,61 @@ -module gui.components; +module gui.component; + +import ecs_utils.utils; struct ComponentGUI { - -} \ No newline at end of file + const (char)* name; + void* data; + ushort component_id; +} + +struct ComponentEditGUI +{ + const (char)* name; + VariableGUI[] variables; + uint used; +} + +struct VariableGUI +{ + struct Int + { + int min; + int max; + } + + struct Float + { + float min; + float max; + } + + struct Enum + { + const (char)[][] strings; + } + + enum Type + { + byte_, + ubyte_, + short_, + ushort_, + int_, + uint_, + float_, + enum_, + color, + vec2, + ivec2 + } + Type type; + const (char)* name; + ushort offset; + union + { + Int int_; + Float float_; + Enum enum_; + } +} diff --git a/demos/source/gui/manager.d b/demos/source/gui/manager.d index 4d452ad..b7c8678 100644 --- a/demos/source/gui/manager.d +++ b/demos/source/gui/manager.d @@ -4,22 +4,32 @@ import app; import cimgui.cimgui; +import bubel.ecs.entity; +import bubel.ecs.manager; import bubel.ecs.std; import bubel.ecs.system; import bubel.ecs.vector; -import bubel.ecs.entity; +import ecs_utils.math.vector; + +import gui.attributes; +import gui.component; import gui.system; import gui.template_; +import std.traits; + extern(C): struct GUIManager { Vector!SystemGUI systems; + Vector!ComponentGUI components; Vector!TemplateGUI templates; + Vector!ComponentEditGUI edit_components; uint selected_tempalte = 0; + uint selected_component = 0; void clear() { @@ -27,10 +37,22 @@ struct GUIManager { launcher.manager.freeTemplate(tmpl.tmpl); } + foreach(comp; components) + { + free(comp.data); + } + foreach(ref comp; edit_components) + { + if(comp.variables)Mallocator.dispose(comp.variables); + comp.variables = null; + comp.used = 0; + } systems.clear(); templates.clear(); + components.clear(); selected_tempalte = 0; + selected_component = 0; } EntityTemplate* getSelectedTemplate() @@ -39,6 +61,12 @@ struct GUIManager else return null; } + ComponentRef getSelectedComponent() + { + if(components.length > selected_component)return ComponentRef(components[selected_component].data, components[selected_component].component_id); + else return ComponentRef(null, ushort.max); + } + void addSystem(ushort id, const (char)* name, bool enabled = true) { System* system = launcher.manager.getSystem(id); @@ -56,9 +84,112 @@ struct GUIManager templates.add(TemplateGUI(name, tmpl)); } + // void addComponent(ComponentRef comp, const (char)* name) + // { + // uint size = EntityManager.instance.components[comp.component_id].size; + // void* data = malloc(size); + // memcpy(data, comp.ptr, size); + // components.add(ComponentGUI(name, data, comp.component_id)); + // } + + void addComponent(T)(T comp, const (char)* name) + { + static assert(hasStaticMember!(T,"component_id")); + uint size = EntityManager.instance.components[comp.component_id].size; + void* data = malloc(size); + memcpy(data, &comp, size); + components.add(ComponentGUI(name, data, comp.component_id)); + + if(edit_components.length <= comp.component_id) + { + edit_components.length = comp.component_id+1;//.extend(comp.component_id + 1); + } + //edit_components[comp.component_id] = ComponentEditGUI(name); + ComponentEditGUI comp_edit; + comp_edit.name = T.stringof; + //enum fields = __traits(allMembers, T); + alias fields = FieldNameTuple!T; + //pragma(msg,fields); + comp_edit.variables = Mallocator.makeArray!VariableGUI(fields.length); + foreach(member_str; fields) + { + alias member = __traits(getMember, T, member_str); + alias member_type = typeof(member); + //pragma(msg,member); + //pragma(msg,member_type); + //pragma(msg,__traits(getMember, T, member).offsetof); + ushort offset = member.offsetof;//cast(ushort)__traits(getMember, T, member).offsetof; + static if(__traits(isIntegral,member_type)) + { + static if(__traits(isUnsigned, member_type)) + { + static if(hasUDA!(member,GUIColor)) + { + comp_edit.variables[comp_edit.used++] = VariableGUI(VariableGUI.Type.color,member_str,offset); + } + else switch(member_type.sizeof) + { + case 1: comp_edit.variables[comp_edit.used++] = VariableGUI(VariableGUI.Type.ubyte_,member_str,offset);break; + case 2: comp_edit.variables[comp_edit.used++] = VariableGUI(VariableGUI.Type.ushort_,member_str,offset);break; + case 4: comp_edit.variables[comp_edit.used++] = VariableGUI(VariableGUI.Type.uint_,member_str,offset);break; + default:break; + } + static if(hasUDA!(member,GUIRange)) + { + comp_edit.variables[comp_edit.used-1].int_.min = getUDAs!(member,GUIRange)[0].min; + comp_edit.variables[comp_edit.used-1].int_.max = getUDAs!(member,GUIRange)[0].max; + } + else + { + comp_edit.variables[comp_edit.used-1].int_.min = 0; + comp_edit.variables[comp_edit.used-1].int_.max = int.max; + } + } + else + { + switch(member_type.sizeof) + { + case 1: comp_edit.variables[comp_edit.used++] = VariableGUI(VariableGUI.Type.byte_,member_str,offset);break; + case 2: comp_edit.variables[comp_edit.used++] = VariableGUI(VariableGUI.Type.short_,member_str,offset);break; + case 4: comp_edit.variables[comp_edit.used++] = VariableGUI(VariableGUI.Type.int_,member_str,offset);break; + default:break; + } + static if(hasUDA!(member,GUIRange)) + { + comp_edit.variables[comp_edit.used-1].int_.min = getUDAs!(member,GUIRange)[0].min; + comp_edit.variables[comp_edit.used-1].int_.max = getUDAs!(member,GUIRange)[1].max; + } + { + comp_edit.variables[comp_edit.used-1].int_.min = int.min; + comp_edit.variables[comp_edit.used-1].int_.max = int.max; + } + } + } + else static if(__traits(isScalar,member_type)) + { + switch(member_type.sizeof) + { + case 4:comp_edit.variables[comp_edit.used++] = VariableGUI(VariableGUI.Type.float_,member_str,offset);break; + case 8: + default:break; + } + static if(hasUDA!(member,GUIRange)) + { + comp_edit.variables[comp_edit.used-1].float_.min = getUDAs!(member,GUIRange)[0].minf; + comp_edit.variables[comp_edit.used-1].float_.max = getUDAs!(member,GUIRange)[1].maxf; + } + { + comp_edit.variables[comp_edit.used-1].float_.min = -float.max; + comp_edit.variables[comp_edit.used-1].float_.max = float.max; + } + } + } + edit_components[comp.component_id] = comp_edit; + } + void gui() { - if(igCollapsingHeader("Systems", ImGuiTreeNodeFlags_Framed | ImGuiTreeNodeFlags_SpanFullWidth | ImGuiTreeNodeFlags_FramePadding)) + if(igCollapsingHeader("Systems", ImGuiTreeNodeFlags_SpanFullWidth | ImGuiTreeNodeFlags_DefaultOpen)) { bool true_ = true; igIndent(8); @@ -74,25 +205,177 @@ struct GUIManager } } - void toolGui() + static vec4 colorUintToVec4(uint color) { - if(templates.length) + // color = *cast(uint*)(comp_ptr+var.offset); + return vec4(cast(float)(color & 0xFF) / 255, + cast(float)(color >> 8 & 0xFF) / 255, + cast(float)(color >> 16 & 0xFF) / 255, + cast(float)(color >> 24 & 0xFF) / 255); + } + + static uint colorVec4ToUint(vec4 color) + { + return cast(uint)(color.x * 255) | + cast(uint)(color.y * 255) << 8 | + cast(uint)(color.z * 255) << 16 | + cast(uint)(color.w * 255) << 24; + } + + static bool igDragScalarClamp(const(char)* label, ImGuiDataType data_type, void* v, float v_speed, const(void)* v_min, const(void)* v_max, const(char)* format, float power) + { + ubyte[8] v_backup;// = *v; + final switch(data_type) { - if(igBeginCombo("Template",templates[selected_tempalte].name,0)) - { - foreach(i, tmpl; templates) - { - if(igSelectable(tmpl.name,false,0,ImVec2(0,0))) - { - selected_tempalte = cast(uint)i; - } - } - igEndCombo(); - } + case ImGuiDataType_S8:memcpy(v_backup.ptr, v, 1);break; + case ImGuiDataType_S16:memcpy(v_backup.ptr, v, 2);break; + case ImGuiDataType_S32:memcpy(v_backup.ptr, v, 4);break; + case ImGuiDataType_U8:memcpy(v_backup.ptr, v, 1);break; + case ImGuiDataType_U16:memcpy(v_backup.ptr, v, 2);break; + case ImGuiDataType_U32:memcpy(v_backup.ptr, v, 4);break; + case ImGuiDataType_Float:memcpy(v_backup.ptr, v, 4);break; } - else + if (!igDragScalar(label, data_type, v, v_speed, v_min, v_max, format, power)) + return false; + + final switch(data_type) { - if(igBeginCombo("Template",null,0))igEndCombo(); + case ImGuiDataType_S8: + if(*cast(byte*)v < *cast(byte*)v_min)*cast(byte*)v = *cast(byte*)v_min; + else if(*cast(byte*)v > *cast(byte*)v_max)*cast(byte*)v = *cast(byte*)v_max; + return *cast(byte*)v != *cast(byte*)v_backup.ptr; + case ImGuiDataType_S16: + if(*cast(short*)v < *cast(short*)v_min)*cast(short*)v = *cast(short*)v_min; + else if(*cast(short*)v > *cast(short*)v_max)*cast(short*)v = *cast(short*)v_max; + return *cast(short*)v != *cast(short*)v_backup.ptr; + case ImGuiDataType_S32: + if(*cast(int*)v < *cast(int*)v_min)*cast(int*)v = *cast(int*)v_min; + else if(*cast(int*)v > *cast(int*)v_max)*cast(int*)v = *cast(int*)v_max; + return *cast(int*)v != *cast(int*)v_backup.ptr; + case ImGuiDataType_U8: + if(*cast(ubyte*)v < *cast(ubyte*)v_min)*cast(ubyte*)v = *cast(ubyte*)v_min; + else if(*cast(ubyte*)v > *cast(ubyte*)v_max)*cast(ubyte*)v = *cast(ubyte*)v_max; + return *cast(ubyte*)v != *cast(ubyte*)v_backup.ptr; + case ImGuiDataType_U16: + if(*cast(ushort*)v < *cast(ushort*)v_min)*cast(ushort*)v = *cast(ushort*)v_min; + else if(*cast(ushort*)v > *cast(ushort*)v_max)*cast(ushort*)v = *cast(ushort*)v_max; + return *cast(ushort*)v != *cast(ushort*)v_backup.ptr; + case ImGuiDataType_U32: + if(*cast(uint*)v < *cast(uint*)v_min)*cast(uint*)v = *cast(uint*)v_min; + else if(*cast(uint*)v > *cast(uint*)v_max)*cast(uint*)v = *cast(uint*)v_max; + return *cast(uint*)v != *cast(uint*)v_backup.ptr; + case ImGuiDataType_Float: + if(*cast(float*)v < *cast(float*)v_min)*cast(float*)v = *cast(float*)v_min; + else if(*cast(float*)v > *cast(float*)v_max)*cast(float*)v = *cast(float*)v_max; + return *cast(float*)v != *cast(float*)v_backup.ptr; } } + + void entityComponentsGUI() + { + EntityTemplate* tmpl = templates[selected_tempalte].tmpl; + EntityManager.EntityInfo* info = tmpl.info; + void* data_ptr = tmpl.entity_data.ptr; + vec4 color; + foreach(comp_id; info.components) + { + if(comp_id >= edit_components.length)break; + void* comp_ptr = data_ptr + info.tmpl_deltas[comp_id]; + if(edit_components[comp_id].used) + { + if(igCollapsingHeader(edit_components[comp_id].name, ImGuiTreeNodeFlags_SpanAvailWidth | ImGuiTreeNodeFlags_DefaultOpen)) + { + igIndent(8); + foreach(ref VariableGUI var;edit_components[comp_id].variables[0 .. edit_components[comp_id].used]) + { + switch(var.type) + { + case VariableGUI.Type.byte_: + igDragScalarClamp(var.name, ImGuiDataType_S8, comp_ptr+var.offset, 1, cast(void*)&var.int_.min, cast(void*)&var.int_.max, null, 1); + break; + case VariableGUI.Type.ubyte_: + igDragScalarClamp(var.name, ImGuiDataType_U8, comp_ptr+var.offset, 1, cast(void*)&var.int_.min, cast(void*)&var.int_.max, null, 1); + break; + case VariableGUI.Type.short_: + igDragScalarClamp(var.name, ImGuiDataType_S16, comp_ptr+var.offset, 1, cast(void*)&var.int_.min, cast(void*)&var.int_.max, null, 1); + break; + case VariableGUI.Type.ushort_: + igDragScalarClamp(var.name, ImGuiDataType_U16, comp_ptr+var.offset, 1, cast(void*)&var.int_.min, cast(void*)&var.int_.max, null, 1); + break; + case VariableGUI.Type.int_: + igDragScalarClamp(var.name, ImGuiDataType_S32, comp_ptr+var.offset, 1, cast(void*)&var.int_.min, cast(void*)&var.int_.max, null, 1); + break; + case VariableGUI.Type.uint_: + igDragScalarClamp(var.name, ImGuiDataType_U32, comp_ptr+var.offset, 1, cast(void*)&var.int_.min, cast(void*)&var.int_.max, null, 1); + break; + case VariableGUI.Type.float_: + igDragScalarClamp(var.name, ImGuiDataType_Float, comp_ptr+var.offset, 1, cast(void*)&var.float_.min, cast(void*)&var.float_.max, null, 1); + break; + case VariableGUI.Type.color: + color = colorUintToVec4(*cast(uint*)(comp_ptr+var.offset)); + if(igColorEdit4(var.name, color.data, ImGuiColorEditFlags_None)) + *cast(uint*)(comp_ptr+var.offset) = colorVec4ToUint(color); + break; + default:break; + } + } + igUnindent(8); + } + } + } + } + + void toolGui() + { + ImGuiStyle * style = igGetStyle(); + ImVec4 col = style.Colors[ImGuiCol_Header]; + style.Colors[ImGuiCol_Header] = style.Colors[ImGuiCol_TextSelectedBg]; + //style. + //ImDrawList* draw_list = igGetWindowDrawList(); + final switch(launcher.used_tool) + { + case Tool.entity_spawner: + if(templates.length) + { + { + if(igListBoxHeaderInt("Template",cast(int)templates.length,cast(int)templates.length)) + { + foreach(i, tmpl; templates) + { + if(igSelectable(tmpl.name,selected_tempalte == i,ImGuiSelectableFlags_AllowDoubleClick,ImVec2(0,0))) + { + selected_tempalte = cast(uint)i; + } + } + igListBoxFooter(); + } + } + } + style.Colors[ImGuiCol_Header] = col; + entityComponentsGUI(); + break; + case Tool.component_manipulator: + if(components.length) + { + if(igListBoxHeaderInt("Components",cast(int)components.length,cast(int)components.length)) + { + { + foreach(i, comp; components) + { + if(igSelectable(comp.name,selected_component == i,0,ImVec2(0,0))) + { + selected_component = cast(uint)i; + } + } + igListBoxFooter(); + } + } + } + break; + case Tool.selector: + break; + } + + style.Colors[ImGuiCol_Header] = col; + } } \ No newline at end of file diff --git a/demos/source/gui/tool_circle.d b/demos/source/gui/tool_circle.d new file mode 100644 index 0000000..c43ade3 --- /dev/null +++ b/demos/source/gui/tool_circle.d @@ -0,0 +1,52 @@ +module gui.tool_circle; + +import ecs_utils.gfx.buffer; +import ecs_utils.gfx.shader; +import ecs_utils.gfx.config; +import ecs_utils.gfx.renderer; + +import ecs_utils.math.vector; + +version(WebAssembly)import glad.gl.gles2; +else version(Android)import glad.gl.gles2; +else import glad.gl.gl; + +struct ToolCircle +{ + //Buffer vbo; + //Buffer ibo; + + uint material_id = 1; + uint mesh_id = 0; + + /*/void generate() + { + ushort[] + }*/ + + void draw(Renderer* renderer, vec2 position, float size, float edge = 1) + { + position = position * renderer.view_size + renderer.view_pos; + vec2 sizes = renderer.view_size * size; + vec2 sizes2 = vec2(edge,0); + + import core.stdc.string; + ubyte[32] uniform_block; + void* ptr = uniform_block.ptr; + *cast(float*)(ptr) = sizes.x; + *cast(float*)(ptr+4) = 0; + *cast(float*)(ptr+8) = 0; + *cast(float*)(ptr+12) = sizes.y; + memcpy(ptr+16,position.data.ptr,8); + memcpy(ptr+24,sizes2.data.ptr,8); + glEnableVertexAttribArray(0); + + GfxConfig.meshes[mesh_id].bind(); + GfxConfig.materials[material_id].bind(); + GfxConfig.materials[material_id].pushBindings(); + GfxConfig.materials[material_id].pushUniforms(uniform_block.ptr); + //glDisable(GL_DEPTH_TEST); + + glDrawElements(GL_TRIANGLES,6,GL_UNSIGNED_SHORT,null); + } +} \ No newline at end of file diff --git a/demos/utils/source/ecs_utils/gfx/buffer.d b/demos/utils/source/ecs_utils/gfx/buffer.d index bfdad62..76cab50 100644 --- a/demos/utils/source/ecs_utils/gfx/buffer.d +++ b/demos/utils/source/ecs_utils/gfx/buffer.d @@ -68,7 +68,7 @@ struct Buffer void map(BindTarget target) nothrow { bind(target); - version(Android){}else data.map_ptr = glMapBuffer(target,GL_WRITE_ONLY); + version(Android){}else version(WebAssembly){}else data.map_ptr = glMapBuffer(target,GL_WRITE_ONLY); } void map(uint offset, uint size, BindTarget target, uint flags = MapFlagBits.write | MapFlagBits.flush_explict | MapFlagBits.invalidate_buffer) nothrow diff --git a/demos/utils/source/ecs_utils/gfx/material.d b/demos/utils/source/ecs_utils/gfx/material.d index 1bde9c8..0fca5fb 100644 --- a/demos/utils/source/ecs_utils/gfx/material.d +++ b/demos/utils/source/ecs_utils/gfx/material.d @@ -78,6 +78,25 @@ struct Material void bind() nothrow { + final switch(data.blend_mode) + { + case BlendMode.mixed: + glDepthMask(0); + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + break; + case BlendMode.opaque: + glDepthMask(1); + glDisable(GL_BLEND); + break; + case BlendMode.additive: + glDepthMask(0); + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE); + //glBlendFunc(GL_ONE, GL_ONE); + break; + } + glUseProgram(data.modules[0].gl_handle); } diff --git a/demos/utils/source/ecs_utils/gfx/renderer.d b/demos/utils/source/ecs_utils/gfx/renderer.d index 93d009e..4e34b54 100644 --- a/demos/utils/source/ecs_utils/gfx/renderer.d +++ b/demos/utils/source/ecs_utils/gfx/renderer.d @@ -67,8 +67,10 @@ struct Renderer enum max_items = batch_size;//963; byte[] batch_vertices; ushort[] batch_indices; - void* memory; + void* memory = null; uint items = 0; + uint material_id; + uint texture_id; } Mutex* get_block_mutex; @@ -128,11 +130,11 @@ struct Renderer block_stack_mutex.unlock();*/ foreach(ref Thread thread; threads) { - foreach(VertexBlock block; thread.blocks) + foreach(VertexBlock block; thread.filled_blocks) { allocator.freeBlock(block.memory); } - thread.blocks.clear(); + thread.filled_blocks.clear(); } render_blocks = 0; current_block = 0; @@ -144,13 +146,13 @@ struct Renderer { foreach(ref Thread thread; threads) { - foreach(VertexBlock block; thread.blocks) + foreach(VertexBlock block; thread.filled_blocks) { uint items = block.items; if(items + item_id >= MaxObjects)items = MaxObjects - item_id; batch_vbo[0].bufferSubData(Buffer.BindTarget.array,items*4*14,item_id*4*14,block.batch_vertices.ptr); batch_ibo[0].bufferSubData(Buffer.BindTarget.element_array,items*2*6,item_id*2*6,block.batch_indices.ptr); - draw_list.add(DrawCall(item_id,items)); + draw_list.add(DrawCall(block.texture_id,block.material_id,item_id,items)); item_id += items; } //thread.blocks.clear(); @@ -173,8 +175,15 @@ struct Renderer foreach(i, ref Thread thread; threads) { //pushBlock(thread.block); - thread.blocks.add(thread.block); - thread.block = getBlock(); + foreach(ref block; thread.blocks) + { + if(block.items > 0) + { + thread.filled_blocks.add(block); + block.items = 0; + } + } + //thread.blocks = getBlock(); } } @@ -182,8 +191,8 @@ struct Renderer { //Vector!VertexBlock block; RenderData[] render_list; - VertexBlock block; - Vector!VertexBlock blocks; + VertexBlock[] blocks; + Vector!VertexBlock filled_blocks; } Thread[] threads; @@ -225,6 +234,8 @@ struct Renderer struct DrawCall { + uint texture_id; + uint material_id; uint start; uint count; } @@ -249,6 +260,7 @@ struct Renderer void initialize() { + import ecs_utils.gfx.config; //this.technique = __ecs_used_technique; __initialize(this); @@ -261,7 +273,8 @@ struct Renderer threads = Mallocator.makeArray!Thread(32); foreach(ref Thread thread;threads) { - thread.block = getBlock(); + //thread.blocks = getBlock(); + thread.blocks = Mallocator.makeArray!VertexBlock(GfxConfig.materials.length); } } @@ -494,12 +507,33 @@ struct Renderer private static void __draw_gl_vbo_batch(ref Renderer this_, Texture tex, vec2 pos, vec2 size, vec4 coords, short depth, uint color, float angle, uint material_id, uint mesh_id, uint thread_id = 0) { import ecs_utils.gfx.config; - short[3] mem = [depth, *cast(short*)&color, *(cast(short*)&color + 1)]; + //import core.stdc.string; with(this_) { //if(item_id >= MaxObjects)return; //pos += view_pos; + Thread* thread = &threads[thread_id]; + VertexBlock* block; + assert(thread.blocks.length > material_id); + block = &thread.blocks[material_id]; + if(block.items == 0) + { + thread.blocks[material_id] = getBlock(); + block = &thread.blocks[material_id]; + block.material_id = material_id; + } + else if(block.items >= VertexBlock.max_items) + { + //pushBlock(thread.block); + prepared_items += block.items; + thread.filled_blocks.add(*block); + thread.blocks[material_id] = getBlock(); + block = &thread.blocks[material_id]; + block.material_id = material_id; + } + + short[3] mem = [depth, *cast(short*)&color, *(cast(short*)&color + 1)]; pos.x = pos.x * view_size.x + view_pos.x; pos.y = pos.y * view_size.y + view_pos.y;//*/ @@ -513,8 +547,8 @@ struct Renderer memcpy(ptr+16,pos.data.ptr,8); memcpy(ptr+32,coords.data.ptr,16);*/ - short[] verts = cast(short[])threads[thread_id].block.batch_vertices; - uint item_id = threads[thread_id].block.items; + short[] verts = cast(short[])block.batch_vertices; + uint item_id = block.items; if(angle == 0) { @@ -619,7 +653,7 @@ struct Renderer uint ind_id = (item_id % batch_size)*4; - ushort[] indices = threads[thread_id].block.batch_indices; + ushort[] indices = block.batch_indices; indices[item_id*6] = cast(ushort)(GfxConfig.meshes[mesh_id].indices[0] + ind_id); indices[item_id*6+1] = cast(ushort)(GfxConfig.meshes[mesh_id].indices[1] + ind_id); @@ -634,14 +668,7 @@ struct Renderer //render_list[item_id].mesh_id = mesh_id; //data_index += 1;//data_offset; - threads[thread_id].block.items++; - if(threads[thread_id].block.items >= VertexBlock.max_items) - { - //pushBlock(threads[thread_id].block); - prepared_items += threads[thread_id].block.items; - threads[thread_id].blocks.add(threads[thread_id].block); - threads[thread_id].block = getBlock(); - } + block.items++; } } @@ -659,6 +686,7 @@ struct Renderer { glClearColor(0,0,0,0); glViewport(0,0,this_.resolution.x,this_.resolution.y); + glDepthMask(1); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); //glDisable(GL_DEPTH_TEST); glEnable(GL_DEPTH_TEST); @@ -828,9 +856,9 @@ struct Renderer //uint items = item_id/batch_size+1; foreach(i; 0..draw_list.length) { - if(material_id != render_list[i].material_id) + if(material_id != draw_list[i].material_id) { - material_id = render_list[i].material_id; + material_id = draw_list[i].material_id; GfxConfig.materials[material_id].bind(); float[3*4] data = [1,0,0,1,0,0,0,0,0,0,1,1]; GfxConfig.materials[material_id].pushUniforms(data.ptr); diff --git a/demos/utils/source/ecs_utils/math/vector.d b/demos/utils/source/ecs_utils/math/vector.d index a8f14f8..adb3a36 100644 --- a/demos/utils/source/ecs_utils/math/vector.d +++ b/demos/utils/source/ecs_utils/math/vector.d @@ -1,5 +1,7 @@ module ecs_utils.math.vector; +import ecs_utils.utils; + struct vec2 { this(float v) @nogc nothrow @@ -71,6 +73,26 @@ struct vec2 } else static assert(0, "Operator "~op~" not implemented"); } + + float length2() + { + return x*x + y*y; + } + + float length() + { + return sqrtf(length2); + } + + float fastSqrLength() + { + return rsqrt(length2); + } + + vec2 normalize() + { + return this * fastSqrLength(); + } } struct vec4 diff --git a/demos/utils/source/ecs_utils/utils.d b/demos/utils/source/ecs_utils/utils.d index 144d24f..da5453f 100644 --- a/demos/utils/source/ecs_utils/utils.d +++ b/demos/utils/source/ecs_utils/utils.d @@ -2,13 +2,24 @@ module ecs_utils.utils; extern(C): -int randomRange(int min, int max) +import ecs_utils.math.vector; + +enum PI = 3.141592653589793238462643383279502884197169399375105820; + +extern(C) float sqrtf(float x) @nogc nothrow @system; +extern(C) float acosf(float x) @nogc nothrow @system; +extern(C) float sinf(float x) @nogc nothrow @system; +extern(C) float cosf(float x) @nogc nothrow @system; +extern(C) float powf(float x, float y) @nogc nothrow @system; +extern(C) float fabs(float x) @nogc nothrow @system; + +int randomRange(int min, int max) nothrow @nogc @trusted { int range = max - min; return rand() % range - min; } -float randomf() +float randomf() nothrow @nogc @trusted { const float scale = 1.0 / 32_767.0; return cast(float)(rand() & 0x007FFF) * scale; @@ -21,6 +32,38 @@ float randomRangef(float min, float max) return rand()%4096; }*/ +float mix(float x, float y, float a) +{ + //return x*a + y*(a-1); + //return x*a + y*a - y; + return x*(a+y) - y; +} + +float rsqrt(float number) +{ + long i; + float x2, y; + const float threehalfs = 1.5F; + + x2 = number * 0.5F; + y = number; + i = * cast( long * ) &y; // evil floating point bit level hacking + i = 0x5f3759df - ( i >> 1 ); // what the fuck? + y = * cast( float * ) &i; + y = y * ( threehalfs - ( x2 * y * y ) ); // 1st iteration + + return y; +} + +vec2 randomCircularSample() nothrow @nogc @trusted +{ + float angle = 2 * PI * randomf; + float radius = sqrtf(randomf); + float s = sinf(angle); + float c = cosf(angle); + return vec2(c,s)*radius; +} + version(GNU) { public import core.stdc.stdio : printf; @@ -34,7 +77,7 @@ else extern(C) int printf(scope const char* format, ...) @nogc nothrow @system; public import std.array : staticArray; } -extern(C) int rand(); +extern(C) int rand() nothrow @nogc @trusted; version(D_BetterC) { From 5018464a410fc2ea4c8c90d2c0a02d603b3736ef Mon Sep 17 00:00:00 2001 From: Mergul Date: Wed, 10 Jun 2020 14:13:01 +0200 Subject: [PATCH 155/217] Demo GUI fixes and improvements plus some shortcuts -added option to override components (by remove them before adding) -added shortcuts for tools -fixed mouse scroll on WASM -addding entity filtering option (WIP) -added some tooltips -remove Components duplicates in ComponentManipulator menu -fixed ImGUI controls IDs -added possibility to change values of component to add --- demos/source/app.d | 124 +++++++++++++++++++------ demos/source/demos/particles.d | 44 ++++----- demos/source/demos/snake.d | 10 ++- demos/source/gui/manager.d | 159 ++++++++++++++++++++++----------- 4 files changed, 237 insertions(+), 100 deletions(-) diff --git a/demos/source/app.d b/demos/source/app.d index 808426f..d526f97 100644 --- a/demos/source/app.d +++ b/demos/source/app.d @@ -71,6 +71,7 @@ struct Launcher float tool_repeat = 0; float repeat_time = 0; bool tool_show = true; + bool override_ = true; bool tool_mode = true; ToolCircle* tool_circle; @@ -154,6 +155,20 @@ struct Launcher } } + void overrideComponent(IteratorSystem.EntitiesData data) + { + foreach(i;0..data.length) + { + vec2 rel_vec = data.location[i] - position; + float length = rel_vec.x * rel_vec.x + rel_vec.y * rel_vec.y; + if(length < size2) + { + gEM.removeComponents(data.entity[i].id, rem_comps); + gEM.addComponents(data.entity[i].id, add_comps); + } + } + } + void removeComponent(IteratorSystem.EntitiesData data) { foreach(i;0..data.length) @@ -200,7 +215,13 @@ struct Launcher { ComponentRef[1] comps = [gui_manager.getSelectedComponent()]; iterator.add_comps = comps; - manager.callEntitiesFunction!IteratorSystem(&iterator.addComponent); + if(launcher.override_) + { + ushort[1] rcomps = [gui_manager.getSelectedComponent().component_id]; + iterator.rem_comps = rcomps; + manager.callEntitiesFunction!IteratorSystem(&iterator.overrideComponent); + } + else manager.callEntitiesFunction!IteratorSystem(&iterator.addComponent); } else { @@ -330,6 +351,33 @@ void mainLoop(void* arg) *cast(bool*)arg = false; return; } + else if(event.type == SDL_KEYDOWN) + { + if(event.key.state) + { + if(SDL_GetModState() & KMOD_CTRL) + { + switch(event.key.keysym.scancode) + { + case SDL_SCANCODE_1:launcher.used_tool=Tool.entity_spawner;break; + case SDL_SCANCODE_2:launcher.used_tool=Tool.component_manipulator;break; + case SDL_SCANCODE_3:launcher.used_tool=Tool.selector;break; + default:break; + } + } + else + { + switch(event.key.keysym.scancode) + { + case SDL_SCANCODE_1:break; + case SDL_SCANCODE_2:break; + case SDL_SCANCODE_3:break; + case SDL_SCANCODE_4:break; + default:break; + } + } + } + } else if(event.type == SDL_WINDOWEVENT) { switch(event.window.event) @@ -383,17 +431,32 @@ void mainLoop(void* arg) { float sign = 1; if(event.wheel.y < 0)sign = -1; - float val = sign * event.wheel.y * launcher.tool_repeat * 0.25; + float val = /*sign * event.wheel.y */ launcher.tool_repeat * 0.25; if(val < 0.1)val = 0.1; launcher.tool_repeat -= sign * val; if(launcher.tool_repeat < 0)launcher.tool_repeat = 0; else if(launcher.tool_repeat > 1000)launcher.tool_repeat = 1000; } + else if(SDL_GetModState() & KMOD_SHIFT) + { + int sign = 1; + if(event.wheel.y < 0)sign = -1; + switch(launcher.used_tool) + { + case Tool.entity_spawner: + launcher.gui_manager.selectTemplate(launcher.gui_manager.selected_template-sign); + break; + case Tool.component_manipulator: + launcher.gui_manager.selectComponent(launcher.gui_manager.selected_component-sign); + break; + default:break; + } + } else { int sign = 1; if(event.wheel.y < 0)sign = -1; - int val = sign * event.wheel.y * launcher.tool_size / 4; + int val = /*sign * event.wheel.y */ launcher.tool_size / 4; if(val < 1)val = 1; launcher.tool_size -= sign * val; if(launcher.tool_size < 1)launcher.tool_size = 1; @@ -503,22 +566,11 @@ void mainLoop(void* arg) } if(igBeginMenu("Show",true)) { - if(igMenuItemBool("Statistics",null,launcher.show_stat_wnd,true)) - { - launcher.show_stat_wnd = !launcher.show_stat_wnd; - } - else if(igMenuItemBool("Demo",null,launcher.show_demo_wnd,true)) - { - launcher.show_demo_wnd = !launcher.show_demo_wnd; - } - else if(igMenuItemBool("Tips",null,launcher.show_tips,true)) - { - launcher.show_tips = !launcher.show_tips; - } - else if(igMenuItemBool("Virual keys",null,launcher.show_virtual_keys_wnd,true)) - { - launcher.show_virtual_keys_wnd = !launcher.show_virtual_keys_wnd; - } + igMenuItemBoolPtr("Statistics",null,&launcher.show_stat_wnd,true); + igMenuItemBoolPtr("Demo",null,&launcher.show_demo_wnd,true); + igMenuItemBoolPtr("Tips",null,&launcher.show_tips,true); + igMenuItemBoolPtr("Virual keys",null,&launcher.show_virtual_keys_wnd,true); + igMenuItemBoolPtr("Profile",null,&launcher.show_profile_wnd,true); igEndMenu(); } if(igBeginMenu("Style",true)) @@ -655,12 +707,25 @@ void mainLoop(void* arg) } igEndCombo(); } + if(igIsItemHovered(0))igSetTooltip("Select tool (CTRL + 1,2,3)"); igCheckbox("Show Tool", &launcher.tool_show); + if(igIsItemHovered(0))igSetTooltip("Show/hide graphical tool representation"); + if(launcher.used_tool == Tool.component_manipulator) + { + igSameLine(0,4); + igCheckbox("Override", &launcher.override_); + } //igSelectable("Selectabe",false,ImGuiSelectableFlags_None,ImVec2(0,0)); - if(igRadioButtonBool("Add", launcher.tool_mode))launcher.tool_mode = true; - igSameLine(0,0); - if(igRadioButtonBool("Remove", !launcher.tool_mode))launcher.tool_mode = false; + if(launcher.used_tool != Tool.selector) + { + if(igRadioButtonBool("Add", launcher.tool_mode))launcher.tool_mode = true; + if(igIsItemHovered(0))igSetTooltip("Tool should adding (Entities or components)"); + igSameLine(0,4); + if(igRadioButtonBool("Remove", !launcher.tool_mode))launcher.tool_mode = false; + if(igIsItemHovered(0))igSetTooltip("Tool should removing (Entities or components)"); + } + igSliderInt("Tool size", &launcher.tool_size, 0, 256, null); igSliderFloat("Tool repeat", &launcher.tool_repeat, 0, 1024, null, 4); launcher.gui_manager.toolGui(); @@ -668,7 +733,16 @@ void mainLoop(void* arg) } igEndGroup(); ImDrawList_AddRect(draw_list, igGetItemRectMin(), ImVec2(igGetWindowPos().x+igGetWindowWidth()-2,igGetItemRectMax().y), igColorConvertFloat4ToU32(ImVec4(0.4,0.4,0.4,0.4)), 2, ImDrawCornerFlags_All, 1); - + + //igBeginGroup(); + if(igCollapsingHeader("Filter", ImGuiTreeNodeFlags_SpanAvailWidth)) + { + igIndent(8); + launcher.gui_manager.filterGUI(); + igUnindent(8); + } + //igEndGroup(); + //ImDrawList_AddRect(draw_list, igGetItemRectMin(), ImVec2(igGetWindowPos().x+igGetWindowWidth()-2,igGetItemRectMax().y), igColorConvertFloat4ToU32(ImVec4(0.4,0.4,0.4,0.4)), 2, ImDrawCornerFlags_All, 1); //igEndChild(); //igEndChildFrame(); @@ -975,8 +1049,8 @@ int app_main(int argc, char** argv) import demos.space_invaders; import demos.particles; // launcher.switchDemo(&spaceInvadersStart,&spaceInvadersLoop,&spaceInvadersEnd,&spaceInvadersEvent,SpaceInvaders.tips); - // launcher.switchDemo(&particlesStart,&particlesLoop,&particlesEnd,&particlesEvent,ParticlesDemo.tips); - launcher.switchDemo(&simpleStart,&simpleLoop,&simpleEnd,&simpleEvent,Simple.tips); + launcher.switchDemo(&particlesStart,&particlesLoop,&particlesEnd,&particlesEvent,ParticlesDemo.tips); + // launcher.switchDemo(&simpleStart,&simpleLoop,&simpleEnd,&simpleEvent,Simple.tips); } int key_num; diff --git a/demos/source/demos/particles.d b/demos/source/demos/particles.d index 6ed8ea7..b58b775 100644 --- a/demos/source/demos/particles.d +++ b/demos/source/demos/particles.d @@ -473,12 +473,13 @@ void particlesStart() launcher.gui_manager.addSystem(DampingSystem.system_id,"Damping System"); launcher.gui_manager.addSystem(ParticleLifeSystem.system_id,"Particle Life System"); - launcher.gui_manager.addComponent(CColor(),"Color (white)"); - launcher.gui_manager.addComponent(CColor(0xFF101540),"Color (red)"); - launcher.gui_manager.addComponent(CColor(0xFF251010),"Color (blue)"); - launcher.gui_manager.addComponent(CColor(0xFF102010),"Color (green)"); - launcher.gui_manager.addComponent(CAttractor(0.1),"Attractor (str 0.1)"); - launcher.gui_manager.addComponent(CForceRange(vec2(5,40)),"ForceRange (5,40)"); + // launcher.gui_manager.addComponent(CColor(),"Color (white)"); + // launcher.gui_manager.addComponent(CColor(0xFF101540),"Color (red)"); + // launcher.gui_manager.addComponent(CColor(0xFF251010),"Color (blue)"); + // launcher.gui_manager.addComponent(CColor(0xFF102010),"Color (green)"); + launcher.gui_manager.addComponent(CColor(0xFF101540),"Color"); + launcher.gui_manager.addComponent(CAttractor(0.1),"Attractor"); + launcher.gui_manager.addComponent(CForceRange(vec2(5,40)),"ForceRange"); launcher.gui_manager.addComponent(CVelocity(),"Velocity"); launcher.gui_manager.addComponent(CDamping(),"Damping"); launcher.gui_manager.addComponent(CVortex(),"Vortex"); @@ -487,28 +488,29 @@ void particlesStart() EntityTemplate* tmpl; EntityTemplate* base_tmpl = launcher.manager.allocateTemplate([CLocation.component_id, CColor.component_id, CVelocity.component_id, CDamping.component_id].staticArray); + base_tmpl.getComponent!CColor().value = 0xFF251010; launcher.gui_manager.addTemplate(base_tmpl,"Particle"); - tmpl = launcher.manager.allocateTemplate(base_tmpl); - tmpl.getComponent!CColor().value = 0xFF251010; - launcher.gui_manager.addTemplate(tmpl,"Particle (blue)"); - tmpl = launcher.manager.allocateTemplate(base_tmpl); - tmpl.getComponent!CColor().value = 0xFF102010; - launcher.gui_manager.addTemplate(tmpl,"Particle (green)"); - tmpl = launcher.manager.allocateTemplate(base_tmpl); - tmpl.getComponent!CColor().value = 0xFF101540; - launcher.gui_manager.addTemplate(tmpl,"Particle (red)"); + // tmpl = launcher.manager.allocateTemplate(base_tmpl); + // tmpl.getComponent!CColor().value = 0xFF251010; + // launcher.gui_manager.addTemplate(tmpl,"Particle (blue)"); + // tmpl = launcher.manager.allocateTemplate(base_tmpl); + // tmpl.getComponent!CColor().value = 0xFF102010; + // launcher.gui_manager.addTemplate(tmpl,"Particle (green)"); + // tmpl = launcher.manager.allocateTemplate(base_tmpl); + // tmpl.getComponent!CColor().value = 0xFF101540; + // launcher.gui_manager.addTemplate(tmpl,"Particle (red)"); // tmpl = launcher.manager.allocateTemplate(tmpl, [CDamping.component_id].staticArray); // launcher.gui_manager.addTemplate(tmpl,"Particle (damping)"); - tmpl = launcher.manager.allocateTemplate(tmpl); - tmpl.getComponent!CDamping().power = 4; - launcher.gui_manager.addTemplate(tmpl,"Particle (damping!)"); + // tmpl = launcher.manager.allocateTemplate(tmpl); + // tmpl.getComponent!CDamping().power = 4; + // launcher.gui_manager.addTemplate(tmpl,"Particle (damping!)"); tmpl = launcher.manager.allocateTemplate([CAttractor.component_id, CLocation.component_id, CForceRange.component_id].staticArray); launcher.gui_manager.addTemplate(tmpl,"Attractor"); tmpl = launcher.manager.allocateTemplate(tmpl, [CVortex.component_id].staticArray); launcher.gui_manager.addTemplate(tmpl,"Vortex"); - tmpl = launcher.manager.allocateTemplate(tmpl); - tmpl.getComponent!CVortex().strength = -0.6; - launcher.gui_manager.addTemplate(tmpl,"Vortex (reversed)"); + // tmpl = launcher.manager.allocateTemplate(tmpl); + // tmpl.getComponent!CVortex().strength = -0.6; + // launcher.gui_manager.addTemplate(tmpl,"Vortex (reversed)"); } diff --git a/demos/source/demos/snake.d b/demos/source/demos/snake.d index f46009c..579bc54 100644 --- a/demos/source/demos/snake.d +++ b/demos/source/demos/snake.d @@ -852,10 +852,12 @@ void snakeStart() launcher.gui_manager.addComponent(CApple(),"Apple"); launcher.gui_manager.addComponent(CSnake(),"Snake"); - launcher.gui_manager.addComponent(CParticle(1000),"Particle (1s)"); - launcher.gui_manager.addComponent(CParticleVector(vec2(0,1)),"Particle Vector (UP)"); + launcher.gui_manager.addComponent(CParticle(1000),"Particle"); + launcher.gui_manager.addComponent(CParticleVector(vec2(0,1)),"Particle Vector"); launcher.gui_manager.addComponent(CInput(),"Input"); - launcher.gui_manager.addComponent(CMovement(CMovement.Direction.up),"Movement (UP)"); + launcher.gui_manager.addComponent(CMovement(CMovement.Direction.up),"Movement"); + //launcher.gui_manager.addComponent(CAnimation(),"Movement"); + launcher.gui_manager.addComponent(CILocation(),"Int Location"); launcher.gui_manager.addSystem(MoveSystem.system_id,"Move System"); launcher.gui_manager.addSystem(InputSystem.system_id,"Input System"); @@ -864,6 +866,8 @@ void snakeStart() launcher.gui_manager.addSystem(AnimationSystem.system_id,"Animation System"); launcher.gui_manager.addSystem(ParticleSystem.system_id,"Particle Life System"); launcher.gui_manager.addSystem(ParticleMovementSystem.system_id,"Particle Movement System"); + launcher.gui_manager.addSystem(DrawAppleSystem.system_id,"Draw Apple System"); + launcher.gui_manager.addSystem(DrawSnakeSystem.system_id,"Draw Snake System"); snake.snake_destroy_particle_frames = Mallocator.makeArray([vec4(64,144,16,16)*px,vec4(80,144,16,16)*px,vec4(96,144,16,16)*px,vec4(112,144,16,16)*px].staticArray); diff --git a/demos/source/gui/manager.d b/demos/source/gui/manager.d index b7c8678..4ae9688 100644 --- a/demos/source/gui/manager.d +++ b/demos/source/gui/manager.d @@ -28,8 +28,24 @@ struct GUIManager Vector!TemplateGUI templates; Vector!ComponentEditGUI edit_components; - uint selected_tempalte = 0; - uint selected_component = 0; + int selected_template = 0; + int selected_component = 0; + + void selectTemplate(int id) + { + if(templates.length == 0)return; + selected_template = id; + while(selected_template < 0)selected_template += cast(int)templates.length; + while(selected_template >= templates.length)selected_template -= cast(int)templates.length; + } + + void selectComponent(int id) + { + if(components.length == 0)return; + selected_component = id; + while(selected_component < 0)selected_component += cast(int)components.length; + while(selected_component >= components.length)selected_component -= cast(int)components.length; + } void clear() { @@ -51,13 +67,13 @@ struct GUIManager systems.clear(); templates.clear(); components.clear(); - selected_tempalte = 0; + selected_template = 0; selected_component = 0; } EntityTemplate* getSelectedTemplate() { - if(templates.length > selected_tempalte)return templates[selected_tempalte].tmpl; + if(templates.length > selected_template)return templates[selected_template].tmpl; else return null; } @@ -271,57 +287,65 @@ struct GUIManager } } + void componentGUI(ushort comp_id, void* data_ptr) + { + vec4 color; + if(comp_id >= edit_components.length)return; + if(edit_components[comp_id].used) + { + if(igCollapsingHeader(edit_components[comp_id].name, ImGuiTreeNodeFlags_SpanAvailWidth | ImGuiTreeNodeFlags_DefaultOpen)) + { + igIndent(8); + foreach(ref VariableGUI var;edit_components[comp_id].variables[0 .. edit_components[comp_id].used]) + { + igPushIDPtr(&var); + switch(var.type) + { + case VariableGUI.Type.byte_: + igDragScalarClamp(var.name, ImGuiDataType_S8, data_ptr+var.offset, 0.1, cast(void*)&var.int_.min, cast(void*)&var.int_.max, null, 1); + break; + case VariableGUI.Type.ubyte_: + igDragScalarClamp(var.name, ImGuiDataType_U8, data_ptr+var.offset, 0.1, cast(void*)&var.int_.min, cast(void*)&var.int_.max, null, 1); + break; + case VariableGUI.Type.short_: + igDragScalarClamp(var.name, ImGuiDataType_S16, data_ptr+var.offset, 0.1, cast(void*)&var.int_.min, cast(void*)&var.int_.max, null, 1); + break; + case VariableGUI.Type.ushort_: + igDragScalarClamp(var.name, ImGuiDataType_U16, data_ptr+var.offset, 0.1, cast(void*)&var.int_.min, cast(void*)&var.int_.max, null, 1); + break; + case VariableGUI.Type.int_: + igDragScalarClamp(var.name, ImGuiDataType_S32, data_ptr+var.offset, 0.1, cast(void*)&var.int_.min, cast(void*)&var.int_.max, null, 1); + break; + case VariableGUI.Type.uint_: + igDragScalarClamp(var.name, ImGuiDataType_U32, data_ptr+var.offset, 0.1, cast(void*)&var.int_.min, cast(void*)&var.int_.max, null, 1); + break; + case VariableGUI.Type.float_: + igDragScalarClamp(var.name, ImGuiDataType_Float, data_ptr+var.offset, 0.1, cast(void*)&var.float_.min, cast(void*)&var.float_.max, "%2.2f", 1); + break; + case VariableGUI.Type.color: + color = colorUintToVec4(*cast(uint*)(data_ptr+var.offset)); + if(igColorEdit4(var.name, color.data, ImGuiColorEditFlags_None)) + *cast(uint*)(data_ptr+var.offset) = colorVec4ToUint(color); + break; + default:break; + } + igPopID(); + } + //igPopID(); + igUnindent(8); + } + } + } + void entityComponentsGUI() { - EntityTemplate* tmpl = templates[selected_tempalte].tmpl; + EntityTemplate* tmpl = templates[selected_template].tmpl; EntityManager.EntityInfo* info = tmpl.info; - void* data_ptr = tmpl.entity_data.ptr; - vec4 color; foreach(comp_id; info.components) { - if(comp_id >= edit_components.length)break; + void* data_ptr = tmpl.entity_data.ptr; void* comp_ptr = data_ptr + info.tmpl_deltas[comp_id]; - if(edit_components[comp_id].used) - { - if(igCollapsingHeader(edit_components[comp_id].name, ImGuiTreeNodeFlags_SpanAvailWidth | ImGuiTreeNodeFlags_DefaultOpen)) - { - igIndent(8); - foreach(ref VariableGUI var;edit_components[comp_id].variables[0 .. edit_components[comp_id].used]) - { - switch(var.type) - { - case VariableGUI.Type.byte_: - igDragScalarClamp(var.name, ImGuiDataType_S8, comp_ptr+var.offset, 1, cast(void*)&var.int_.min, cast(void*)&var.int_.max, null, 1); - break; - case VariableGUI.Type.ubyte_: - igDragScalarClamp(var.name, ImGuiDataType_U8, comp_ptr+var.offset, 1, cast(void*)&var.int_.min, cast(void*)&var.int_.max, null, 1); - break; - case VariableGUI.Type.short_: - igDragScalarClamp(var.name, ImGuiDataType_S16, comp_ptr+var.offset, 1, cast(void*)&var.int_.min, cast(void*)&var.int_.max, null, 1); - break; - case VariableGUI.Type.ushort_: - igDragScalarClamp(var.name, ImGuiDataType_U16, comp_ptr+var.offset, 1, cast(void*)&var.int_.min, cast(void*)&var.int_.max, null, 1); - break; - case VariableGUI.Type.int_: - igDragScalarClamp(var.name, ImGuiDataType_S32, comp_ptr+var.offset, 1, cast(void*)&var.int_.min, cast(void*)&var.int_.max, null, 1); - break; - case VariableGUI.Type.uint_: - igDragScalarClamp(var.name, ImGuiDataType_U32, comp_ptr+var.offset, 1, cast(void*)&var.int_.min, cast(void*)&var.int_.max, null, 1); - break; - case VariableGUI.Type.float_: - igDragScalarClamp(var.name, ImGuiDataType_Float, comp_ptr+var.offset, 1, cast(void*)&var.float_.min, cast(void*)&var.float_.max, null, 1); - break; - case VariableGUI.Type.color: - color = colorUintToVec4(*cast(uint*)(comp_ptr+var.offset)); - if(igColorEdit4(var.name, color.data, ImGuiColorEditFlags_None)) - *cast(uint*)(comp_ptr+var.offset) = colorVec4ToUint(color); - break; - default:break; - } - } - igUnindent(8); - } - } + componentGUI(comp_id, comp_ptr); } } @@ -342,14 +366,15 @@ struct GUIManager { foreach(i, tmpl; templates) { - if(igSelectable(tmpl.name,selected_tempalte == i,ImGuiSelectableFlags_AllowDoubleClick,ImVec2(0,0))) + if(igSelectable(tmpl.name,selected_template == i,ImGuiSelectableFlags_AllowDoubleClick,ImVec2(0,0))) { - selected_tempalte = cast(uint)i; + selected_template = cast(uint)i; } } igListBoxFooter(); } } + if(igIsItemHovered(0))igSetTooltip("Select entity to spawn (SHIFT + Scroll)"); } style.Colors[ImGuiCol_Header] = col; entityComponentsGUI(); @@ -370,7 +395,10 @@ struct GUIManager igListBoxFooter(); } } + if(igIsItemHovered(0))igSetTooltip("Select component to add/remove (SHIFT + Scroll)"); } + style.Colors[ImGuiCol_Header] = col; + componentGUI(components[selected_component].component_id, components[selected_component].data); break; case Tool.selector: break; @@ -378,4 +406,33 @@ struct GUIManager style.Colors[ImGuiCol_Header] = col; } + + void filterGUI() + { + ImGuiStyle * style = igGetStyle(); + ImVec4 col = style.Colors[ImGuiCol_Header]; + style.Colors[ImGuiCol_Header] = style.Colors[ImGuiCol_TextSelectedBg]; + + int length = 0; + foreach(comp; edit_components) + { + if(comp.name !is null)length++; + } + + if(length && igListBoxHeaderInt("Components",cast(int)length,cast(int)length)) + { + foreach(i, comp; edit_components) + { + if(comp.name is null)return; + if(igSelectable(comp.name,false,0,ImVec2(0,0))) + { + + } + } + igListBoxFooter(); + } + if(igIsItemHovered(0))igSetTooltip("Select components to filter while tool work.\nComponents are only changed for filtered entities."); + + style.Colors[ImGuiCol_Header] = col; + } } \ No newline at end of file From 8cba2626be1d8279550acd19bdc93ce6d3346a52 Mon Sep 17 00:00:00 2001 From: Mergul Date: Wed, 10 Jun 2020 15:35:42 +0200 Subject: [PATCH 156/217] Added entity filering support and fixed minor bug --- demos/source/app.d | 16 +++++++++++++++ demos/source/gui/manager.d | 42 ++++++++++++++++++++++++++++---------- source/bubel/ecs/entity.d | 2 +- 3 files changed, 48 insertions(+), 12 deletions(-) diff --git a/demos/source/app.d b/demos/source/app.d index d526f97..6808e42 100644 --- a/demos/source/app.d +++ b/demos/source/app.d @@ -134,9 +134,21 @@ struct Launcher vec2 position; ComponentRef[] add_comps; ushort[] rem_comps; + ushort[] filter; + + bool filterEntity(ref const Entity entity) + { + EntityMeta meta = entity.getMeta(); + foreach(id;filter) + { + if(!meta.hasComponent(id))return false; + } + return true; + } void removeEntity(IteratorSystem.EntitiesData data) { + if(!filterEntity(data.entity[0]))return; foreach(i;0..data.length) { vec2 rel_vec = data.location[i] - position; @@ -147,6 +159,7 @@ struct Launcher void addComponent(IteratorSystem.EntitiesData data) { + if(!filterEntity(data.entity[0]))return; foreach(i;0..data.length) { vec2 rel_vec = data.location[i] - position; @@ -157,6 +170,7 @@ struct Launcher void overrideComponent(IteratorSystem.EntitiesData data) { + if(!filterEntity(data.entity[0]))return; foreach(i;0..data.length) { vec2 rel_vec = data.location[i] - position; @@ -171,6 +185,7 @@ struct Launcher void removeComponent(IteratorSystem.EntitiesData data) { + if(!filterEntity(data.entity[0]))return; foreach(i;0..data.length) { vec2 rel_vec = data.location[i] - position; @@ -185,6 +200,7 @@ struct Launcher Iterator iterator; iterator.size2 = size2; iterator.position = position; + iterator.filter = gui_manager.filter_list[]; switch(used_tool) { diff --git a/demos/source/gui/manager.d b/demos/source/gui/manager.d index 4ae9688..6fb3165 100644 --- a/demos/source/gui/manager.d +++ b/demos/source/gui/manager.d @@ -27,6 +27,8 @@ struct GUIManager Vector!ComponentGUI components; Vector!TemplateGUI templates; Vector!ComponentEditGUI edit_components; + Vector!bool filter; + Vector!ushort filter_list; int selected_template = 0; int selected_component = 0; @@ -62,8 +64,14 @@ struct GUIManager if(comp.variables)Mallocator.dispose(comp.variables); comp.variables = null; comp.used = 0; + comp.name = null; + } + foreach(ref comp; filter) + { + comp = false; } + filter_list.clear(); systems.clear(); templates.clear(); components.clear(); @@ -384,16 +392,14 @@ struct GUIManager { if(igListBoxHeaderInt("Components",cast(int)components.length,cast(int)components.length)) { + foreach(i, comp; components) { - foreach(i, comp; components) + if(igSelectable(comp.name,selected_component == i,0,ImVec2(0,0))) { - if(igSelectable(comp.name,selected_component == i,0,ImVec2(0,0))) - { - selected_component = cast(uint)i; - } + selected_component = cast(uint)i; } - igListBoxFooter(); } + igListBoxFooter(); } if(igIsItemHovered(0))igSetTooltip("Select component to add/remove (SHIFT + Scroll)"); } @@ -407,26 +413,40 @@ struct GUIManager style.Colors[ImGuiCol_Header] = col; } + private void genFilterList() + { + filter_list.clear(); + foreach(i, comp; filter) + { + if(comp) + { + filter_list.add(cast(ushort)i); + } + } + } + void filterGUI() { ImGuiStyle * style = igGetStyle(); ImVec4 col = style.Colors[ImGuiCol_Header]; style.Colors[ImGuiCol_Header] = style.Colors[ImGuiCol_TextSelectedBg]; + if(filter.length < edit_components.length)filter.length(edit_components.length); + int length = 0; foreach(comp; edit_components) { if(comp.name !is null)length++; } - if(length && igListBoxHeaderInt("Components",cast(int)length,cast(int)length)) + if(length && igListBoxHeaderInt("Components##FilterComponents",cast(int)length,cast(int)length)) { - foreach(i, comp; edit_components) + foreach(i, ref comp; edit_components) { - if(comp.name is null)return; - if(igSelectable(comp.name,false,0,ImVec2(0,0))) + if(comp.name is null)continue; + if(igSelectableBoolPtr(comp.name,&filter[i],0,ImVec2(0,0))) { - + genFilterList(); } } igListBoxFooter(); diff --git a/source/bubel/ecs/entity.d b/source/bubel/ecs/entity.d index 6a64d50..2c64c60 100644 --- a/source/bubel/ecs/entity.d +++ b/source/bubel/ecs/entity.d @@ -50,7 +50,7 @@ struct Entity return true; } - EntityMeta getMeta() + EntityMeta getMeta() const { EntityMeta meta; meta.block = gEM.getMetaData(&this); From 3a7a5b2a212279cd2af72635dad574b160602bcc Mon Sep 17 00:00:00 2001 From: Mergul Date: Fri, 12 Jun 2020 14:53:59 +0200 Subject: [PATCH 157/217] Slightly changed rendering code -renderer draw function now takes struct instead of multiple parameters --- demos/source/demos/particles.d | 15 ++- demos/source/demos/simple.d | 14 ++- demos/source/demos/snake.d | 69 ++++++++++---- demos/source/demos/space_invaders.d | 73 ++++++++++---- demos/utils/source/ecs_utils/gfx/renderer.d | 100 +++++++++++++------- 5 files changed, 199 insertions(+), 72 deletions(-) diff --git a/demos/source/demos/particles.d b/demos/source/demos/particles.d index b58b775..8b27f80 100644 --- a/demos/source/demos/particles.d +++ b/demos/source/demos/particles.d @@ -134,19 +134,30 @@ struct DrawSystem void onUpdate(EntitiesData data) { if(launcher.renderer.prepared_items >= launcher.renderer.MaxObjects)return;//simple leave loop if max visible objects count was reached + import ecs_utils.gfx.renderer; + Renderer.DrawData draw_data; + draw_data.size = vec2(2,2); + draw_data.coords = vec4(246,64,2,2)*px; + draw_data.color = 0x80808080; + draw_data.material_id = 2; + draw_data.thread_id = data.job_id; + draw_data.texture = particles_demo.texture; if(!data.color) { foreach(i; 0..data.length) { - launcher.renderer.draw(particles_demo.texture, data.locations[i], vec2(2,2), vec4(246,64,2,2)*px, 0, 0x80808080, 0, 2, 0, data.job_id); + draw_data.position = data.locations[i]; + launcher.renderer.draw(draw_data);//particles_demo.texture, data.locations[i], vec2(2,2), vec4(246,64,2,2)*px, 0, 0x80808080, 0, 2, 0, data.job_id); } } else { foreach(i; 0..data.length) { - launcher.renderer.draw(particles_demo.texture, data.locations[i], vec2(2,2), vec4(246,64,2,2)*px, 0, data.color[i].value, 0, 2, 0, data.job_id); + draw_data.position = data.locations[i]; + draw_data.color = data.color[i].value; + launcher.renderer.draw(draw_data);//particles_demo.texture, data.locations[i], vec2(2,2), vec4(246,64,2,2)*px, 0, data.color[i].value, 0, 2, 0, data.job_id); } } diff --git a/demos/source/demos/simple.d b/demos/source/demos/simple.d index ac3b3f7..6876e4f 100644 --- a/demos/source/demos/simple.d +++ b/demos/source/demos/simple.d @@ -52,9 +52,21 @@ struct DrawSystem void onUpdate(EntitiesData data) { if(launcher.renderer.prepared_items >= launcher.renderer.MaxObjects)return;//simple leave loop if max visible objects count was reached + import ecs_utils.gfx.renderer; + Renderer.DrawData draw_data; + draw_data.size = vec2(16,16); + draw_data.coords = vec4(0,0,1,1); + draw_data.color = 0x80808080; + draw_data.material_id = 0; + draw_data.thread_id = data.job_id; + draw_data.texture = simple.texture; + foreach(i; 0..data.length) { - launcher.renderer.draw(simple.texture, data.locations[i], vec2(16,16), vec4(0,0,1,1), cast(ushort)(data.locations[i].y), 0x80808080, 0, 0, 0, data.job_id); + draw_data.position = data.locations[i]; + draw_data.depth = cast(ushort)(data.locations[i].y); + launcher.renderer.draw(draw_data); + //launcher.renderer.draw(simple.texture, data.locations[i], vec2(16,16), vec4(0,0,1,1), cast(ushort)(data.locations[i].y), 0x80808080, 0, 0, 0, data.job_id); // launcher.renderer.draw(data.textures[i].tex, data.locations[i].location, vec2(16,16), vec4(0,0,1,1), 0, 0x80808080, 0, 0, 0, data.job_id); //draw(renderer, data.textures[i].tex, data.locations[i], vec2(32,32), vec4(0,0,1,1)); } diff --git a/demos/source/demos/snake.d b/demos/source/demos/snake.d index 579bc54..c42f690 100644 --- a/demos/source/demos/snake.d +++ b/demos/source/demos/snake.d @@ -348,9 +348,21 @@ struct AnimationRenderSystem void onUpdate(EntitiesData data) { + import ecs_utils.gfx.renderer; + Renderer.DrawData draw_data; + draw_data.size = vec2(16,16); + //draw_data.coords = vec4(0,0,1,1)*px; + draw_data.color = 0x80808080; + draw_data.material_id = 0; + draw_data.thread_id = 0; + draw_data.texture = snake.texture; + draw_data.depth = -1; foreach(i;0..data.length) { - launcher.renderer.draw(snake.texture, cast(vec2)cast(ivec2)data.location[i], vec2(16,16), data.animation[i].frames[cast(int)(data.animation[i].time)], -1, 0x80808080); + draw_data.position = data.location[i]; + draw_data.coords = data.animation[i].frames[cast(int)(data.animation[i].time)]; + launcher.renderer.draw(draw_data); + //launcher.renderer.draw(snake.texture, cast(vec2)cast(ivec2)data.location[i], vec2(16,16), data.animation[i].frames[cast(int)(data.animation[i].time)], -1, 0x80808080); } } } @@ -649,9 +661,19 @@ struct DrawAppleSystem void onUpdate(EntitiesData data) { + import ecs_utils.gfx.renderer; + Renderer.DrawData draw_data; + draw_data.size = vec2(16,16); + draw_data.coords = vec4(0,32*px,16*px,16*px); + draw_data.color = 0x80808080; + draw_data.material_id = 0; + draw_data.thread_id = 0; + draw_data.texture = snake.texture; foreach(i; 0..data.location.length) { - launcher.renderer.draw(snake.texture, vec2(data.location[i].x*16,data.location[i].y*16), vec2(16,16), vec4(0,32*px,16*px,16*px), 0, 0x80808080, 0); + draw_data.position = vec2(data.location[i].x*16,data.location[i].y*16); + launcher.renderer.draw(draw_data); + //launcher.renderer.draw(snake.texture, vec2(data.location[i].x*16,data.location[i].y*16), vec2(16,16), vec4(0,32*px,16*px,16*px), 0, 0x80808080, 0); } } } @@ -719,34 +741,49 @@ struct DrawSnakeSystem static void drawElement(ivec2 loc, SnakePart part) { + import ecs_utils.gfx.renderer; + Renderer.DrawData draw_data; + draw_data.size = vec2(16,16); + draw_data.color = 0x80808080; + draw_data.texture = snake.texture; + draw_data.position = cast(vec2)loc; final switch(cast(ubyte)part) { - case SnakePart.tail_up:launcher.renderer.draw(.snake.texture, cast(vec2)loc, vec2(16,16), vec4(16,112,16,16)*px, 0, 0x80808080, 0);break; - case SnakePart.tail_down:launcher.renderer.draw(.snake.texture, cast(vec2)loc, vec2(16,16), vec4(0,112,16,16)*px, 0, 0x80808080, 0);break; - case SnakePart.tail_left:launcher.renderer.draw(.snake.texture, cast(vec2)loc, vec2(16,16), vec4(32,112,16,16)*px, 0, 0x80808080, 0);break; - case SnakePart.tail_right:launcher.renderer.draw(.snake.texture, cast(vec2)loc, vec2(16,16), vec4(0,144,16,16)*px, 0, 0x80808080, 0);break; - case SnakePart.turn_ld:launcher.renderer.draw(.snake.texture, cast(vec2)loc, vec2(16,16), vec4(64,128,16,16)*px, 0, 0x80808080, 0);break; - case SnakePart.turn_lu:launcher.renderer.draw(.snake.texture, cast(vec2)loc, vec2(16,16), vec4(32,144,16,16)*px, 0, 0x80808080, 0);break; - case SnakePart.turn_rd:launcher.renderer.draw(.snake.texture, cast(vec2)loc, vec2(16,16), vec4(16,144,16,16)*px, 0, 0x80808080, 0);break; - case SnakePart.turn_ru:launcher.renderer.draw(.snake.texture, cast(vec2)loc, vec2(16,16), vec4(64,112,16,16)*px, 0, 0x80808080, 0);break; - case SnakePart.vertical:launcher.renderer.draw(.snake.texture, cast(vec2)loc, vec2(16,16), vec4(16,128,16,16)*px, 0, 0x80808080, 0);break; - case SnakePart.horizontal:launcher.renderer.draw(.snake.texture, cast(vec2)loc, vec2(16,16), vec4(48,128,16,16)*px, 0, 0x80808080, 0);break; + case SnakePart.tail_up:draw_data.coords = vec4(16,112,16,16)*px;break; + case SnakePart.tail_down:draw_data.coords = vec4(0,112,16,16)*px;break; + case SnakePart.tail_left:draw_data.coords = vec4(32,112,16,16)*px;break; + case SnakePart.tail_right:draw_data.coords = vec4(0,144,16,16)*px;break; + case SnakePart.turn_ld:draw_data.coords = vec4(64,128,16,16)*px;break; + case SnakePart.turn_lu:draw_data.coords = vec4(32,144,16,16)*px;break; + case SnakePart.turn_rd:draw_data.coords = vec4(16,144,16,16)*px;break; + case SnakePart.turn_ru:draw_data.coords = vec4(64,112,16,16)*px;break; + case SnakePart.vertical:draw_data.coords = vec4(16,128,16,16)*px;break; + case SnakePart.horizontal:draw_data.coords = vec4(48,128,16,16)*px;break; } + launcher.renderer.draw(draw_data); } void onUpdate(EntitiesData data) { + import ecs_utils.gfx.renderer; + Renderer.DrawData draw_data; + draw_data.size = vec2(16,16); + draw_data.color = 0x80808080; + draw_data.texture = snake.texture; + foreach(i; 0..data.length) { const (CSnake)* snake = &data.snake[i]; scope vec2 loc = cast(vec2)(data.location[i].location * 16); + draw_data.position = loc; final switch(snake.direction) { - case CMovement.Direction.up:launcher.renderer.draw(.snake.texture, vec2(data.location[i].x*16,data.location[i].y*16), vec2(16,16), vec4(48,112,16,16)*px, 0, 0x80808080, 0);break; - case CMovement.Direction.down:launcher.renderer.draw(.snake.texture, vec2(data.location[i].x*16,data.location[i].y*16), vec2(16,16), vec4(48,144,16,16)*px, 0, 0x80808080, 0);break; - case CMovement.Direction.left:launcher.renderer.draw(.snake.texture, vec2(data.location[i].x*16,data.location[i].y*16), vec2(16,16), vec4(0,128,16,16)*px, 0, 0x80808080, 0);break; - case CMovement.Direction.right:launcher.renderer.draw(.snake.texture, vec2(data.location[i].x*16,data.location[i].y*16), vec2(16,16), vec4(32,128,16,16)*px, 0, 0x80808080, 0);break; + case CMovement.Direction.up:draw_data.coords = vec4(48,112,16,16)*px;break; + case CMovement.Direction.down:draw_data.coords = vec4(48,144,16,16)*px;break; + case CMovement.Direction.left:draw_data.coords = vec4(0,128,16,16)*px;break; + case CMovement.Direction.right:draw_data.coords = vec4(32,128,16,16)*px;break; } + launcher.renderer.draw(draw_data); if(snake.parts.length >1) { foreach(j;1..snake.parts.length - 1)drawElement(snake.parts[j]*16, snakePart(snake.parts[j], snake.parts[j+1], snake.parts[j-1])); diff --git a/demos/source/demos/space_invaders.d b/demos/source/demos/space_invaders.d index ce2cd6a..b08b9ac 100644 --- a/demos/source/demos/space_invaders.d +++ b/demos/source/demos/space_invaders.d @@ -976,31 +976,52 @@ struct DrawSystem void onUpdate(EntitiesData data) { + if(launcher.renderer.prepared_items >= launcher.renderer.MaxObjects)return;//simple leave loop if max visible objects count was reached + import ecs_utils.gfx.renderer; + Renderer.DrawData draw_data; + draw_data.color = 0x80808080; + draw_data.thread_id = data.job_id; + draw_data.texture = space_invaders.texture; + //uint color_mask = 0xFCFCFCFC; + uint const_map = 0x80A08080;//0x80808080; if(!data.depth) { if(data.hit_mark) { foreach(i; 0..data.length) { - uint color = 0x80808080 + 0x01010101 * data.hit_mark[i]; - short depth = cast(short)(data.locations[i].y); - launcher.renderer.draw(space_invaders.texture, data.locations[i].value, data.scale[i], data.textures[i].coords, depth, color, 0, 0, 0, data.job_id); + draw_data.color = 0x80808080 + 0x01010101 * data.hit_mark[i]; + draw_data.depth = cast(short)(data.locations[i].y); + draw_data.coords = data.textures[i].coords; + draw_data.size = data.scale[i]; + draw_data.position = data.locations[i]; + launcher.renderer.draw(draw_data); + //launcher.renderer.draw(space_invaders.texture, data.locations[i].value, data.scale[i], data.textures[i].coords, depth, color|const_map, 0, 0, 0, data.job_id); } } else if(data.rotation) { foreach(i; 0..data.length) { - short depth = cast(short)(data.locations[i].y); - launcher.renderer.draw(space_invaders.texture, data.locations[i].value, data.scale[i], data.textures[i].coords, depth, 0x80808080, data.rotation[i], 0, 0, data.job_id); + draw_data.depth = cast(short)(data.locations[i].y); + draw_data.angle = data.rotation[i]; + draw_data.coords = data.textures[i].coords; + draw_data.size = data.scale[i]; + draw_data.position = data.locations[i]; + launcher.renderer.draw(draw_data); + //launcher.renderer.draw(space_invaders.texture, data.locations[i].value, data.scale[i], data.textures[i].coords, depth, 0x80808080|const_map, data.rotation[i], 0, 0, data.job_id); } } else { foreach(i; 0..data.length) { - short depth = cast(short)(data.locations[i].y); - launcher.renderer.draw(space_invaders.texture, data.locations[i].value, data.scale[i], data.textures[i].coords, depth, 0x80808080, 0, 0, 0, data.job_id); + draw_data.depth = cast(short)(data.locations[i].y); + draw_data.coords = data.textures[i].coords; + draw_data.size = data.scale[i]; + draw_data.position = data.locations[i]; + launcher.renderer.draw(draw_data); + //launcher.renderer.draw(space_invaders.texture, data.locations[i].value, data.scale[i], data.textures[i].coords, depth, 0x80808080|const_map, 0, 0, 0, data.job_id); } } } @@ -1012,18 +1033,27 @@ struct DrawSystem { foreach(i; 0..data.length) { - uint color = 0x80808080 + 0x01010101 * data.hit_mark[i]; - short depth = cast(short)(data.depth[i] * 8 + data.locations[i].y); - launcher.renderer.draw(space_invaders.texture, data.locations[i].value, data.scale[i], data.textures[i].coords, depth, color, data.rotation[i], 0, 0, data.job_id); + draw_data.color = 0x80808080 + 0x01010101 * data.hit_mark[i]; + draw_data.angle = data.rotation[i]; + draw_data.depth = cast(short)(data.depth[i] * 8 + data.locations[i].y); + draw_data.coords = data.textures[i].coords; + draw_data.size = data.scale[i]; + draw_data.position = data.locations[i]; + launcher.renderer.draw(draw_data); + //launcher.renderer.draw(space_invaders.texture, data.locations[i].value, data.scale[i], data.textures[i].coords, depth, color|const_map, data.rotation[i], 0, 0, data.job_id); } } else { foreach(i; 0..data.length) { - uint color = 0x80808080 + 0x01010101 * data.hit_mark[i]; - short depth = cast(short)(data.depth[i] * 8 + data.locations[i].y); - launcher.renderer.draw(space_invaders.texture, data.locations[i].value, data.scale[i], data.textures[i].coords, depth, color, 0, 0, 0, data.job_id); + draw_data.color = 0x80808080 + 0x01010101 * data.hit_mark[i]; + draw_data.depth = cast(short)(data.depth[i] * 8 + data.locations[i].y); + draw_data.coords = data.textures[i].coords; + draw_data.size = data.scale[i]; + draw_data.position = data.locations[i]; + launcher.renderer.draw(draw_data); + //launcher.renderer.draw(space_invaders.texture, data.locations[i].value, data.scale[i], data.textures[i].coords, depth, color|const_map, 0, 0, 0, data.job_id); } } } @@ -1031,16 +1061,25 @@ struct DrawSystem { foreach(i; 0..data.length) { - short depth = cast(short)(data.depth[i] * 8 + data.locations[i].y); - launcher.renderer.draw(space_invaders.texture, data.locations[i].value, data.scale[i], data.textures[i].coords, depth, 0x80808080, data.rotation[i], 0, 0, data.job_id); + draw_data.angle = data.rotation[i]; + draw_data.depth = cast(short)(data.depth[i] * 8 + data.locations[i].y); + draw_data.coords = data.textures[i].coords; + draw_data.size = data.scale[i]; + draw_data.position = data.locations[i]; + launcher.renderer.draw(draw_data); + //launcher.renderer.draw(space_invaders.texture, data.locations[i].value, data.scale[i], data.textures[i].coords, depth, 0x80808080|const_map, data.rotation[i], 0, 0, data.job_id); } } else { foreach(i; 0..data.length) { - short depth = cast(short)(data.depth[i] * 8 + data.locations[i].y); - launcher.renderer.draw(space_invaders.texture, data.locations[i].value, data.scale[i], data.textures[i].coords, depth, 0x80808080, 0, 0, 0, data.job_id); + draw_data.depth = cast(short)(data.depth[i] * 8 + data.locations[i].y); + draw_data.coords = data.textures[i].coords; + draw_data.size = data.scale[i]; + draw_data.position = data.locations[i]; + launcher.renderer.draw(draw_data); + //launcher.renderer.draw(space_invaders.texture, data.locations[i].value, data.scale[i], data.textures[i].coords, depth, 0x80808080|const_map, 0, 0, 0, data.job_id); } } } diff --git a/demos/utils/source/ecs_utils/gfx/renderer.d b/demos/utils/source/ecs_utils/gfx/renderer.d index 4e34b54..ef53543 100644 --- a/demos/utils/source/ecs_utils/gfx/renderer.d +++ b/demos/utils/source/ecs_utils/gfx/renderer.d @@ -430,13 +430,29 @@ struct Renderer } - void draw(Texture tex, vec2 pos, vec2 size, vec4 coords, short depth = 0, uint color = uint.max, float angle = 0, uint material_id = 0, uint mesh_id = 0, uint thread_id = 0) + struct DrawData { - if(prepared_items >= MaxObjects)return; - __draw(this,tex,pos,size,coords,depth,color,angle,material_id,mesh_id,thread_id); + Texture texture; + vec2 position; + vec2 size; + vec4 coords; + short depth = 0; + uint color = uint.max; + float angle = 0; + uint material_id = 0; + uint mesh_id = 0; + uint thread_id = 0; } - private static void __draw_sdl(ref Renderer this_, Texture tex, vec2 pos, vec2 size, vec4 coords, short depth, uint color, float angle, uint material_id, uint mesh_id, uint thread_id) + //void draw(Texture tex, vec2 pos, vec2 size, vec4 coords, short depth = 0, uint color = uint.max, float angle = 0, uint material_id = 0, uint mesh_id = 0, uint thread_id = 0) + void draw(scope ref const(DrawData) data) + { + if(prepared_items >= MaxObjects)return; + __draw(this,data);//tex,pos,size,coords,depth,color,angle,material_id,mesh_id,thread_id); + } + + //private static void __draw_sdl(ref Renderer this_, Texture tex, vec2 pos, vec2 size, vec4 coords, short depth, uint color, float angle, uint material_id, uint mesh_id, uint thread_id) + private static void __draw_sdl(ref Renderer this_, scope ref const(DrawData) data) { /*with(this_) { @@ -456,22 +472,25 @@ struct Renderer }*/ } - private static void __draw_gl(ref Renderer this_, Texture tex, vec2 pos, vec2 size, vec4 coords, short depth, uint color, float angle, uint material_id, uint mesh_id, uint thread_id) + // private static void __draw_gl(ref Renderer this_, Texture tex, vec2 pos, vec2 size, vec4 coords, short depth, uint color, float angle, uint material_id, uint mesh_id, uint thread_id) + private static void __draw_gl(ref Renderer this_, scope ref const(DrawData) data) { //import core.stdc.string; with(this_) { //pos += view_pos; - size.x *= view_size.x; - size.y *= view_size.y; - pos.x = pos.x * view_size.x + view_pos.x; - pos.y = pos.y * view_size.y + view_pos.y;//*/ + vec2 pos = void; + vec2 size = void; + size.x = data.size.x * view_size.x; + size.y = data.size.y * view_size.y; + pos.x = data.position.x * view_size.x + view_pos.x; + pos.y = data.position.y * view_size.y + view_pos.y;//*/ /*version(ver6)void* ptr = ubos[0].mappedPointer() + data_index; else void* ptr = uniform_block.ptr + data_index;*/ if(data_ptr is null)return; void* ptr = data_ptr + data_index; - if(angle == 0) + if(data.angle == 0) { *cast(float*)ptr = size.x; *cast(float*)(ptr+4) = 0; @@ -481,8 +500,8 @@ struct Renderer else { //import core.stdc.math; - float sinn = sinf(angle); - float coss = cosf(angle); + float sinn = sinf(data.angle); + float coss = cosf(data.angle); *cast(float*)ptr = coss * size.x; *cast(float*)(ptr+4) = -sinn * size.y; *cast(float*)(ptr+8) = sinn * size.x; @@ -491,12 +510,12 @@ struct Renderer //memcpy(ptr,); memcpy(ptr+16,pos.data.ptr,8); - memcpy(ptr+32,coords.data.ptr,16); + memcpy(ptr+32,data.coords.data.ptr,16); //render_list[item_id] = RenderData(tex,material_id,mesh_id); - render_list[item_id].texture = tex; - render_list[item_id].material_id = material_id; - render_list[item_id].mesh_id = mesh_id; + render_list[item_id].texture = *cast(Texture*)&data.texture; + render_list[item_id].material_id = data.material_id; + render_list[item_id].mesh_id = data.mesh_id; data_index += data_offset; item_id++; @@ -504,39 +523,43 @@ struct Renderer } } - private static void __draw_gl_vbo_batch(ref Renderer this_, Texture tex, vec2 pos, vec2 size, vec4 coords, short depth, uint color, float angle, uint material_id, uint mesh_id, uint thread_id = 0) + // private static void __draw_gl_vbo_batch(ref Renderer this_, Texture tex, vec2 pos, vec2 size, vec4 coords, short depth, uint color, float angle, uint material_id, uint mesh_id, uint thread_id = 0) + private static void __draw_gl_vbo_batch(ref Renderer this_, scope ref const(DrawData) data) { import ecs_utils.gfx.config; //import core.stdc.string; with(this_) { + uint thread_id = data.thread_id; //if(item_id >= MaxObjects)return; //pos += view_pos; Thread* thread = &threads[thread_id]; VertexBlock* block; - assert(thread.blocks.length > material_id); - block = &thread.blocks[material_id]; + assert(thread.blocks.length > data.material_id); + block = &thread.blocks[data.material_id]; if(block.items == 0) { - thread.blocks[material_id] = getBlock(); - block = &thread.blocks[material_id]; - block.material_id = material_id; + thread.blocks[data.material_id] = getBlock(); + block = &thread.blocks[data.material_id]; + block.material_id = data.material_id; } else if(block.items >= VertexBlock.max_items) { //pushBlock(thread.block); prepared_items += block.items; thread.filled_blocks.add(*block); - thread.blocks[material_id] = getBlock(); - block = &thread.blocks[material_id]; - block.material_id = material_id; + thread.blocks[data.material_id] = getBlock(); + block = &thread.blocks[data.material_id]; + block.material_id = data.material_id; } - short[3] mem = [depth, *cast(short*)&color, *(cast(short*)&color + 1)]; + short[3] mem = [data.depth, *cast(short*)&data.color, *(cast(short*)&data.color + 1)]; - pos.x = pos.x * view_size.x + view_pos.x; - pos.y = pos.y * view_size.y + view_pos.y;//*/ + vec2 pos = void; + vec2 size = void; + pos.x = data.position.x * view_size.x + view_pos.x; + pos.y = data.position.y * view_size.y + view_pos.y;//*/ /*void* ptr = data_ptr + data_index; *cast(float*)ptr = size.x; @@ -550,10 +573,13 @@ struct Renderer short[] verts = cast(short[])block.batch_vertices; uint item_id = block.items; - if(angle == 0) + uint mesh_id = data.mesh_id; + vec4 coords = data.coords; + + if(data.angle == 0) { - size.x *= view_size.x; - size.y *= view_size.y; + size.x = data.size.x * view_size.x; + size.y = data.size.y * view_size.y; verts[item_id*28] = cast(short)((GfxConfig.meshes[mesh_id].vertices[0] * size.x + pos.x) * 8191); verts[item_id*28+1] = cast(short)((GfxConfig.meshes[mesh_id].vertices[1] * size.y + pos.y) * 8191); @@ -585,10 +611,11 @@ struct Renderer else { //import core.stdc.math; - float sinx = sinf(angle) * size.x * view_size.y; - float cosx = cosf(angle) * size.x * view_size.x; - float siny = sinf(angle) * size.y * view_size.x; - float cosy = cosf(angle) * size.y * view_size.y; + float angle = data.angle; + float sinx = sinf(angle) * data.size.x * view_size.y; + float cosx = cosf(angle) * data.size.x * view_size.x; + float siny = sinf(angle) * data.size.y * view_size.x; + float cosy = cosf(angle) * data.size.y * view_size.y; /*batch_vertices[item_id*28] = GfxConfig.meshes[mesh_id].vertices[0] * size.x; batch_vertices[item_id*28+1] = GfxConfig.meshes[mesh_id].vertices[1] * size.y; @@ -1088,7 +1115,8 @@ struct Renderer view_pos = (pos - size * 0.5) * view_size; } - __gshared void function(ref Renderer this_, Texture tex, vec2 pos, vec2 size, vec4 coords, short depth, uint color, float angle, uint material_id, uint mesh_id, uint thread_id) __draw; + // __gshared void function(ref Renderer this_, Texture tex, vec2 pos, vec2 size, vec4 coords, short depth, uint color, float angle, uint material_id, uint mesh_id, uint thread_id) __draw; + __gshared void function(ref Renderer this_, scope ref const(DrawData) data) __draw; __gshared void function(ref Renderer this_) __present; __gshared void function(ref Renderer this_) __clear; __gshared void function(ref Renderer this_) __initialize; From d733bb514ccc65c3ff877b787c95b21a6b9000c1 Mon Sep 17 00:00:00 2001 From: Mergul Date: Fri, 12 Jun 2020 20:51:05 +0200 Subject: [PATCH 158/217] Make common draw system, moved some components to basic components and fixed bug with GUI for signed short integers --- demos/source/demos/particles.d | 16 +-- demos/source/demos/space_invaders.d | 151 +++++++++++------------ demos/source/game_core/basic.d | 45 +++++++ demos/source/game_core/rendering.d | 178 ++++++++++++++++++++++++++++ demos/source/gui/manager.d | 22 +++- 5 files changed, 326 insertions(+), 86 deletions(-) create mode 100644 demos/source/game_core/rendering.d diff --git a/demos/source/demos/particles.d b/demos/source/demos/particles.d index 8b27f80..2242ecf 100644 --- a/demos/source/demos/particles.d +++ b/demos/source/demos/particles.d @@ -35,13 +35,6 @@ private enum float px = 1.0/512.0; alias location this; vec2 location; -}*/ - -struct CTexCoords -{ - mixin ECS.Component; - - vec4 value; } struct CColor @@ -53,6 +46,13 @@ struct CColor @GUIColor uint value = uint.max; } +struct CTexCoords +{ + mixin ECS.Component; + + vec4 value; +}*/ + struct CVelocity { mixin ECS.Component; @@ -453,7 +453,7 @@ void particlesStart() launcher.manager.beginRegister(); launcher.manager.registerComponent!CLocation; - launcher.manager.registerComponent!CTexCoords; + //launcher.manager.registerComponent!CTexCoords; launcher.manager.registerComponent!CColor; launcher.manager.registerComponent!CVelocity; launcher.manager.registerComponent!CAttractor; diff --git a/demos/source/demos/space_invaders.d b/demos/source/demos/space_invaders.d index b08b9ac..311feb3 100644 --- a/demos/source/demos/space_invaders.d +++ b/demos/source/demos/space_invaders.d @@ -17,6 +17,7 @@ import ecs_utils.math.vector; import ecs_utils.utils; import game_core.basic; +import game_core.rendering; //import std.math : PI; @@ -122,7 +123,7 @@ enum Direction : byte alias value this; vec2 value = vec2(0); -}*/ +} struct CScale { @@ -134,13 +135,13 @@ struct CScale vec2 value = vec2(16,16); } -struct CColliderScale +struct CDepth { mixin ECS.Component; - alias value this; + alias depth this; - vec2 value = vec2(16,16); + short depth; } struct CRotation @@ -160,6 +161,15 @@ struct CTexture //Texture tex; uint id; vec4 coords = vec4(0,0,0,1); +}*/ + +struct CColliderScale +{ + mixin ECS.Component; + + alias value this; + + vec2 value = vec2(16,16); } struct CVelocity @@ -255,15 +265,6 @@ struct CSideMove byte group = -1; } -struct CDepth -{ - mixin ECS.Component; - - alias depth this; - - short depth; -} - struct CShootGrid { mixin ECS.Component; @@ -754,11 +755,11 @@ struct ShipWeaponSystem CDepth* depth = entity.getComponent!CDepth; EntityID[2] weapons; weapon_tmpl.getComponent!CTargetParent().parent = entity.id; - if(depth)weapon_tmpl.getComponent!CDepth().depth = cast(short)(depth.depth - 1); - else weapon_tmpl.getComponent!CDepth().depth = -1; + if(depth)weapon_tmpl.getComponent!CDepth().value = cast(short)(depth.value - 1); + else weapon_tmpl.getComponent!CDepth().value = -1; top_tmpl.getComponent!CTargetParent().parent = entity.id; - if(depth)top_tmpl.getComponent!CDepth().depth = cast(short)(depth.depth - 2); - else top_tmpl.getComponent!CDepth().depth = -2; + if(depth)top_tmpl.getComponent!CDepth().value = cast(short)(depth.value - 2); + else top_tmpl.getComponent!CDepth().value = -2; weapons[0] = launcher.manager.addEntity(weapon_tmpl).id; weapons[1] = launcher.manager.addEntity(top_tmpl).id; @@ -771,7 +772,7 @@ struct ShipWeaponSystem [CWeapon.component_id, CLocation.component_id, CShootDirection.component_id, CTargetParent.component_id, CGuild.component_id, CVelocity.component_id, CAutoShoot.component_id, CTarget.component_id, CTargetPlayerShip.component_id, - CRotation.component_id, CScale.component_id, CTexture.component_id, + CRotation.component_id, CScale.component_id, CTexCoords.component_id, CDepth.component_id, CWeaponLocation.component_id].staticArray); *weapon_tmpl.getComponent!CWeapon = CWeapon(0,CWeapon.Type.laser,3); weapon_tmpl.getComponent!CTargetParent().rel_pos = vec2(0,0); @@ -779,17 +780,17 @@ struct ShipWeaponSystem weapon_tmpl.getComponent!CScale().value = vec2(4,16); //weapon_tmpl.getComponent!CWeapon().level = 1; *weapon_tmpl.getComponent!CWeapon() = CWeapon(0,CWeapon.Type.canon,1); - weapon_tmpl.getComponent!CDepth().depth = -1; - weapon_tmpl.getComponent!CTexture().coords = vec4(136,96,4,16)*px; + weapon_tmpl.getComponent!CDepth().value = -1; + weapon_tmpl.getComponent!CTexCoords().value = vec4(136,96,4,16)*px; weapon_tmpl.getComponent!CWeaponLocation().rel_pos = vec2(0,12); top_tmpl = launcher.manager.allocateTemplate( [CLocation.component_id, CTargetParent.component_id, CScale.component_id, - CTexture.component_id, CDepth.component_id].staticArray); + CTexCoords.component_id, CDepth.component_id].staticArray); top_tmpl.getComponent!CTargetParent().rel_pos = vec2(0,1); top_tmpl.getComponent!CScale().value = vec2(10,11); - top_tmpl.getComponent!CDepth().depth = -2; - top_tmpl.getComponent!CTexture().coords = vec4(112,96,10,11)*px; + top_tmpl.getComponent!CDepth().value = -2; + top_tmpl.getComponent!CTexCoords().value = vec4(112,96,10,11)*px; } @@ -829,21 +830,23 @@ struct ShipWeaponSystem { tower1_tmpl = launcher.manager.allocateTemplate( [CHitMark.component_id, CHitPoints.component_id, CLocation.component_id, - CTexture.component_id, CScale.component_id, CEnemy.component_id, + CTexCoords.component_id, CScale.component_id, CEnemy.component_id, CShootGrid.component_id, CGuild.component_id, CInit.component_id, CChildren.component_id, CDepth.component_id, CTargetParent.component_id, CSpawnUponDeath.component_id, CShootWaveUponDeath.component_id].staticArray ); - CTexture* tex_comp = tower1_tmpl.getComponent!CTexture; + /*CTexCoords* tex_comp = tower1_tmpl.getComponent!CTexCoords; //tex_comp.tex = space_invaders.texture;//ship_tex; tex_comp.coords = vec4(96*px,96*px,16*px,16*px); CLocation* loc_comp = tower1_tmpl.getComponent!CLocation; - loc_comp.value = vec2(64,space_invaders.map_size.y - 16); + loc_comp.value = vec2(64,space_invaders.map_size.y - 16);*/ + tower1_tmpl.getComponent!CTexCoords().value = vec4(96*px,96*px,16*px,16*px); + tower1_tmpl.getComponent!CLocation().value = vec2(64,space_invaders.map_size.y - 16); tower1_tmpl.getComponent!CGuild().guild = 1; tower1_tmpl.getComponent!CInit().type = CInit.Type.tower; tower1_tmpl.getComponent!CHitPoints().value = 10; - tower1_tmpl.getComponent!CDepth().depth = -2; + tower1_tmpl.getComponent!CDepth().value = -2; tower1_tmpl.getComponent!CShootWaveUponDeath().bullet_type = CWeapon.Type.canon; tower1_tmpl.getComponent!CTargetParent().rel_pos = vec2(-33,2); @@ -851,11 +854,11 @@ struct ShipWeaponSystem tower2_tmpl.getComponent!CTargetParent().rel_pos = vec2(33,2); tower3_tmpl = launcher.manager.allocateTemplate(tower1_tmpl); - tower3_tmpl.getComponent!CDepth().depth = 0; + tower3_tmpl.getComponent!CDepth().value = 0; tower3_tmpl.getComponent!CTargetParent().rel_pos = vec2(-40,-15); tower4_tmpl = launcher.manager.allocateTemplate(tower1_tmpl); - tower4_tmpl.getComponent!CDepth().depth = 0; + tower4_tmpl.getComponent!CDepth().value = 0; tower4_tmpl.getComponent!CTargetParent().rel_pos = vec2(40,-15); } @@ -966,7 +969,7 @@ struct DrawSystem uint length; //uint thread_id; uint job_id; - @readonly CTexture[] textures; + @readonly CTexCoords[] textures; @readonly CLocation[] locations; @readonly CScale[] scale; @readonly @optional CRotation[] rotation; @@ -992,7 +995,7 @@ struct DrawSystem { draw_data.color = 0x80808080 + 0x01010101 * data.hit_mark[i]; draw_data.depth = cast(short)(data.locations[i].y); - draw_data.coords = data.textures[i].coords; + draw_data.coords = data.textures[i].value; draw_data.size = data.scale[i]; draw_data.position = data.locations[i]; launcher.renderer.draw(draw_data); @@ -1005,7 +1008,7 @@ struct DrawSystem { draw_data.depth = cast(short)(data.locations[i].y); draw_data.angle = data.rotation[i]; - draw_data.coords = data.textures[i].coords; + draw_data.coords = data.textures[i].value; draw_data.size = data.scale[i]; draw_data.position = data.locations[i]; launcher.renderer.draw(draw_data); @@ -1017,7 +1020,7 @@ struct DrawSystem foreach(i; 0..data.length) { draw_data.depth = cast(short)(data.locations[i].y); - draw_data.coords = data.textures[i].coords; + draw_data.coords = data.textures[i].value; draw_data.size = data.scale[i]; draw_data.position = data.locations[i]; launcher.renderer.draw(draw_data); @@ -1036,7 +1039,7 @@ struct DrawSystem draw_data.color = 0x80808080 + 0x01010101 * data.hit_mark[i]; draw_data.angle = data.rotation[i]; draw_data.depth = cast(short)(data.depth[i] * 8 + data.locations[i].y); - draw_data.coords = data.textures[i].coords; + draw_data.coords = data.textures[i].value; draw_data.size = data.scale[i]; draw_data.position = data.locations[i]; launcher.renderer.draw(draw_data); @@ -1049,7 +1052,7 @@ struct DrawSystem { draw_data.color = 0x80808080 + 0x01010101 * data.hit_mark[i]; draw_data.depth = cast(short)(data.depth[i] * 8 + data.locations[i].y); - draw_data.coords = data.textures[i].coords; + draw_data.coords = data.textures[i].value; draw_data.size = data.scale[i]; draw_data.position = data.locations[i]; launcher.renderer.draw(draw_data); @@ -1063,7 +1066,7 @@ struct DrawSystem { draw_data.angle = data.rotation[i]; draw_data.depth = cast(short)(data.depth[i] * 8 + data.locations[i].y); - draw_data.coords = data.textures[i].coords; + draw_data.coords = data.textures[i].value; draw_data.size = data.scale[i]; draw_data.position = data.locations[i]; launcher.renderer.draw(draw_data); @@ -1075,7 +1078,7 @@ struct DrawSystem foreach(i; 0..data.length) { draw_data.depth = cast(short)(data.depth[i] * 8 + data.locations[i].y); - draw_data.coords = data.textures[i].coords; + draw_data.coords = data.textures[i].value; draw_data.size = data.scale[i]; draw_data.position = data.locations[i]; launcher.renderer.draw(draw_data); @@ -1138,31 +1141,31 @@ struct ShootingSystem void onCreate() { /*bullet_tmpl[0] = launcher.manager.allocateTemplate( - [CLocation.component_id, CTexture.component_id, CVelocity.component_id, + [CLocation.component_id, CTexCoords.component_id, CVelocity.component_id, CScale.component_id, CBullet.component_id, CGuild.component_id].staticArray ); - bullet_tmpl[0].getComponent!CTexture().coords = vec4(0,24,2,8)*px; + bullet_tmpl[0].getComponent!CTexCoords().value = vec4(0,24,2,8)*px; bullet_tmpl[0].getComponent!CScale().value = vec2(2,8); bullet_tmpl[1] = launcher.manager.allocateTemplate(bullet_tmpl[0]); bullet_tmpl[2] = launcher.manager.allocateTemplate(bullet_tmpl[0]); - bullet_tmpl[2].getComponent!CTexture().coords = vec4(64,32,8,16)*px; + bullet_tmpl[2].getComponent!CTexCoords().value = vec4(64,32,8,16)*px; bullet_tmpl[2].getComponent!CScale().value = vec2(8,16); bullet_tmpl[3] = launcher.manager.allocateTemplate(bullet_tmpl[0]); - bullet_tmpl[3].getComponent!CTexture().coords = vec4(56,32,2,2)*px; + bullet_tmpl[3].getComponent!CTexCoords().value = vec4(56,32,2,2)*px; bullet_tmpl[3].getComponent!CScale().value = vec2(2,2); - // bullet_tmpl[3].getComponent!CTexture().coords = vec4(48,32,8,8)*px; + // bullet_tmpl[3].getComponent!CTexCoords().value = vec4(48,32,8,8)*px; // bullet_tmpl[3].getComponent!CScale().value = vec2(8,8); bullet_tmpl[4] = launcher.manager.allocateTemplate(bullet_tmpl[0]);*/ fire_tmpl = launcher.manager.allocateTemplate( - [CLocation.component_id, CTexture.component_id, CScale.component_id, + [CLocation.component_id, CTexCoords.component_id, CScale.component_id, CAnimation.component_id, CParticle.component_id, CRotation.component_id, CVelocity.component_id, CDamping.component_id].staticArray ); - fire_tmpl.getComponent!CTexture().coords = vec4(96,64,8,16)*px; + fire_tmpl.getComponent!CTexCoords().value = vec4(96,64,8,16)*px; fire_tmpl.getComponent!CScale().value = vec2(8,16); fire_tmpl.getComponent!(CParticle).life = 300; *fire_tmpl.getComponent!(CAnimation) = CAnimation(fire_frames, 0, 3); @@ -1364,7 +1367,7 @@ struct ParticleEmittingSystem void onCreate() { templates[0] = launcher.manager.allocateTemplate( - [CLocation.component_id, CTexture.component_id, CScale.component_id, + [CLocation.component_id, CTexCoords.component_id, CScale.component_id, CAnimation.component_id, CParticle.component_id, CRotation.component_id, CVelocity.component_id, CDamping.component_id, CDepth.component_id].staticArray); *templates[0].getComponent!CAnimation() = CAnimation(flashes,0,2); @@ -1400,7 +1403,7 @@ struct ParticleEmittingSystem if(data.depth) { - depth.depth = data.depth[i]; + depth.value = data.depth[i]; } launcher.manager.addEntity(templates[0],[data.location[i].ref_,velocity.ref_,depth.ref_].staticArray); @@ -1659,18 +1662,18 @@ struct HitPointsSystem void onCreate() { upgrade_tmpl = launcher.manager.allocateTemplate( - [CVelocity.component_id, CLocation.component_id, CTexture.component_id, + [CVelocity.component_id, CLocation.component_id, CTexCoords.component_id, CScale.component_id, CUpgrade.component_id, CAnimation.component_id, CAnimationLooped.component_id].staticArray); //tex_comp.tex = space_invaders.texture;//ship_tex; - upgrade_tmpl.getComponent!CTexture().coords = vec4(0*px,32*px,16*px,16*px); + upgrade_tmpl.getComponent!CTexCoords().value = vec4(0*px,32*px,16*px,16*px); *upgrade_tmpl.getComponent!CAnimation = CAnimation(upgrade_laser_frames, 0, 1); upgrade_tmpl.getComponent!CVelocity().value = vec2(0,-0.1); explosion_tmpl = launcher.manager.allocateTemplate( [CDepth.component_id, CParticle.component_id, CLocation.component_id, - CTexture.component_id, CScale.component_id, CAnimation.component_id].staticArray); - //explosion_tmpl.getComponent!(CTexture).tex = space_invaders.texture; + CTexCoords.component_id, CScale.component_id, CAnimation.component_id].staticArray); + //explosion_tmpl.getComponent!(CTexCoords).tex = space_invaders.texture; *explosion_tmpl.getComponent!CAnimation = CAnimation(explosion_laser_frames, 0, 1.333); explosion_tmpl.getComponent!(CParticle).life = 600; *explosion_tmpl.getComponent!CDepth = -1; @@ -2005,7 +2008,8 @@ struct AnimationSystem { uint length; CAnimation[] animation; - CTexture[] texture; + //CTexture[] texture; + CTexCoords[] texcoords; @optional @readonly CAnimationLooped[] looped; } @@ -2020,7 +2024,7 @@ struct AnimationSystem while(cast(uint)data.animation[i].time >= data.animation[i].frames.length)data.animation[i].time -= cast(float)data.animation[i].frames.length; if(cast(uint)(data.animation[i].time) >= data.animation[i].frames.length)assert(0); uint index = cast(uint)(data.animation[i].time); - if(index < data.animation[i].frames.length)data.texture[i].coords = data.animation[i].frames[index]; + if(index < data.animation[i].frames.length)data.texcoords[i].value = data.animation[i].frames[index]; } } else @@ -2030,7 +2034,7 @@ struct AnimationSystem data.animation[i].time += dt * data.animation[i].speed; if(cast(uint)data.animation[i].time >= data.animation[i].frames.length)data.animation[i].time = data.animation[i].frames.length - 0.9; uint index = cast(uint)(data.animation[i].time); - if(index < data.animation[i].frames.length)data.texture[i].coords = data.animation[i].frames[index]; + if(index < data.animation[i].frames.length)data.texcoords[i].value = data.animation[i].frames[index]; } } @@ -2241,7 +2245,7 @@ struct InputMovementSystem //components are treated as required by default //CLocation[] locations; CVelocity[] velocity; - CTexture[] textures; + //CTexture[] textures; } /** @@ -2336,7 +2340,8 @@ void spaceInvadersStart() launcher.manager.registerDependency(ShootGridDependency); launcher.manager.registerComponent!CLocation; - launcher.manager.registerComponent!CTexture; + launcher.manager.registerComponent!CTexCoords; + //launcher.manager.registerComponent!CTexture; launcher.manager.registerComponent!CInput; launcher.manager.registerComponent!CShip; launcher.manager.registerComponent!CEnemy; @@ -2478,12 +2483,12 @@ void spaceInvadersStart() { space_invaders.ship_tmpl = launcher.manager.allocateTemplate( [CVelocity.component_id, CHitMark.component_id, CHitPoints.component_id, - CLocation.component_id, CTexture.component_id, CInput.component_id, + CLocation.component_id, CTexCoords.component_id, CInput.component_id, CShip.component_id, CScale.component_id, CColliderScale.component_id, CShootDirection.component_id, CShootGrid.component_id, CGuild.component_id, CDamping.component_id, CChildren.component_id, CInit.component_id].staticArray ); - space_invaders.ship_tmpl.getComponent!CTexture().coords = vec4(0,80,48,32)*px; + space_invaders.ship_tmpl.getComponent!CTexCoords().value = vec4(0,80,48,32)*px; space_invaders.ship_tmpl.getComponent!CScale().value = vec2(48,32); space_invaders.ship_tmpl.getComponent!CHitPoints().value = 1000; space_invaders.ship_tmpl.getComponent!CDamping().value = 7; @@ -2494,10 +2499,10 @@ void spaceInvadersStart() } { - ushort[6] components = [CLocation.component_id, CTexture.component_id, CVelocity.component_id, CScale.component_id, CBullet.component_id, CGuild.component_id]; + ushort[6] components = [CLocation.component_id, CTexCoords.component_id, CVelocity.component_id, CScale.component_id, CBullet.component_id, CGuild.component_id]; space_invaders.laser_tmpl = launcher.manager.allocateTemplate(components); - space_invaders.laser_tmpl.getComponent!CTexture().coords = vec4(0,24,2,8)*px; + space_invaders.laser_tmpl.getComponent!CTexCoords().value = vec4(0,24,2,8)*px; space_invaders.laser_tmpl.getComponent!CScale().value = vec2(2,8); space_invaders.laser_tmpl.getComponent!CVelocity().value = vec2(0,1); } @@ -2513,7 +2518,7 @@ void spaceInvadersStart() { boss_tmpl = launcher.manager.allocateTemplate( [CHitMark.component_id, CParts.component_id, CLocation.component_id, - CTexture.component_id, CScale.component_id, CEnemy.component_id, + CTexCoords.component_id, CScale.component_id, CEnemy.component_id, CBoss.component_id, CGuild.component_id, CInit.component_id, CChildren.component_id, CSideMove.component_id, CVelocity.component_id, CDepth.component_id].staticArray @@ -2524,11 +2529,11 @@ void spaceInvadersStart() //tex_comp.coords = vec4(128*px,0*px,96*px,48*px); //CLocation* loc_comp = boss_tmpl.getComponent!CLocation; //loc_comp.value = vec2(64,space_invaders.map_size.y - 16); - boss_tmpl.getComponent!CTexture().coords = vec4(128,0,96,48)*px; + boss_tmpl.getComponent!CTexCoords().value = vec4(128,0,96,48)*px; boss_tmpl.getComponent!CGuild().guild = 1; boss_tmpl.getComponent!CInit().type = CInit.Type.boss; boss_tmpl.getComponent!CScale().value = vec2(96,48); - boss_tmpl.getComponent!CDepth().depth = -1; + boss_tmpl.getComponent!CDepth().value = -1; boss_tmpl.getComponent!CParts().count = 4; boss_tmpl.getComponent!CVelocity().value = vec2(0.05,0); } @@ -2536,12 +2541,12 @@ void spaceInvadersStart() { tower_tmpl = launcher.manager.allocateTemplate( [CHitMark.component_id, CHitPoints.component_id, CLocation.component_id, - CTexture.component_id, CScale.component_id, CEnemy.component_id, + CTexCoords.component_id, CScale.component_id, CEnemy.component_id, CShootGrid.component_id, CGuild.component_id, CInit.component_id, CChildren.component_id].staticArray ); - tower_tmpl.getComponent!CTexture().coords = vec4(96,96,16,16)*px; + tower_tmpl.getComponent!CTexCoords().value = vec4(96,96,16,16)*px; tower_tmpl.getComponent!CGuild().guild = 1; tower_tmpl.getComponent!CInit().type = CInit.Type.tower; tower_tmpl.getComponent!CHitPoints().value = 10; @@ -2551,12 +2556,12 @@ void spaceInvadersStart() space_invaders.enemy_tmpl = launcher.manager.allocateTemplate( [CWeaponLocation.component_id, CHitMark.component_id, CHitPoints.component_id, CVelocity.component_id, CAutoShoot.component_id, CLocation.component_id, - CTexture.component_id, CScale.component_id, CWeapon.component_id, + CTexCoords.component_id, CScale.component_id, CWeapon.component_id, CEnemy.component_id, CShootDirection.component_id, CShootGrid.component_id, CGuild.component_id].staticArray ); - space_invaders.enemy_tmpl.getComponent!CTexture().coords = vec4(32,32,16,16)*px; + space_invaders.enemy_tmpl.getComponent!CTexCoords().value = vec4(32,32,16,16)*px; space_invaders.enemy_tmpl.getComponent!CShootDirection().direction = Direction.down; space_invaders.enemy_tmpl.getComponent!CVelocity().value = vec2(0.1,0); space_invaders.enemy_tmpl.getComponent!CGuild().guild = 1; @@ -2588,8 +2593,8 @@ void spaceInvadersStart() EntityTemplate* upgrade_tmpl; { - upgrade_tmpl = launcher.manager.allocateTemplate([CVelocity.component_id, CLocation.component_id, CTexture.component_id, CScale.component_id, CUpgrade.component_id, CAnimationLooped.component_id, CAnimation.component_id].staticArray); - upgrade_tmpl.getComponent!CTexture().coords = vec4(0,32,16,16)*px; + upgrade_tmpl = launcher.manager.allocateTemplate([CVelocity.component_id, CLocation.component_id, CTexCoords.component_id, CScale.component_id, CUpgrade.component_id, CAnimationLooped.component_id, CAnimation.component_id].staticArray); + upgrade_tmpl.getComponent!CTexCoords().value = vec4(0,32,16,16)*px; upgrade_tmpl.getComponent!CVelocity().value = vec2(0,-0.1); *upgrade_tmpl.getComponent!CAnimation = CAnimation(HitPointsSystem.upgrade_laser_frames, 0, 0.75); } @@ -2600,20 +2605,20 @@ void spaceInvadersStart() grouped_tmpl = launcher.manager.allocateTemplate(grouped_id); space_invaders.bullet_tmpl[0] = launcher.manager.allocateTemplate( - [CLocation.component_id, CTexture.component_id, CVelocity.component_id, + [CLocation.component_id, CTexCoords.component_id, CVelocity.component_id, CScale.component_id, CBullet.component_id, CGuild.component_id].staticArray ); - space_invaders.bullet_tmpl[0].getComponent!CTexture().coords = vec4(0,24,2,8)*px; + space_invaders.bullet_tmpl[0].getComponent!CTexCoords().value = vec4(0,24,2,8)*px; space_invaders.bullet_tmpl[0].getComponent!CScale().value = vec2(2,8); space_invaders.bullet_tmpl[1] = launcher.manager.allocateTemplate(space_invaders.bullet_tmpl[0]); space_invaders.bullet_tmpl[2] = launcher.manager.allocateTemplate(space_invaders.bullet_tmpl[0]); - space_invaders.bullet_tmpl[2].getComponent!CTexture().coords = vec4(64,32,8,16)*px; + space_invaders.bullet_tmpl[2].getComponent!CTexCoords().value = vec4(64,32,8,16)*px; space_invaders.bullet_tmpl[2].getComponent!CScale().value = vec2(8,16); space_invaders.bullet_tmpl[3] = launcher.manager.allocateTemplate(space_invaders.bullet_tmpl[0]); - space_invaders.bullet_tmpl[3].getComponent!CTexture().coords = vec4(56,32,2,2)*px; + space_invaders.bullet_tmpl[3].getComponent!CTexCoords().value = vec4(56,32,2,2)*px; space_invaders.bullet_tmpl[3].getComponent!CScale().value = vec2(2,2); - // bullet_tmpl[3].getComponent!CTexture().coords = vec4(48,32,8,8)*px; + // bullet_tmpl[3].getComponent!CTexCoords().value = vec4(48,32,8,8)*px; // bullet_tmpl[3].getComponent!CScale().value = vec2(8,8); space_invaders.bullet_tmpl[4] = launcher.manager.allocateTemplate(space_invaders.bullet_tmpl[0]); diff --git a/demos/source/game_core/basic.d b/demos/source/game_core/basic.d index 993a5aa..156680b 100644 --- a/demos/source/game_core/basic.d +++ b/demos/source/game_core/basic.d @@ -4,6 +4,8 @@ import bubel.ecs.core; import ecs_utils.math.vector; +import gui.attributes; + struct CLocation { mixin ECS.Component; @@ -11,4 +13,47 @@ struct CLocation alias value this; vec2 value = vec2(0); +} + +struct CScale +{ + mixin ECS.Component; + + alias value this;///use component as it value + + vec2 value = vec2(16,16); +} + +struct CRotation +{ + mixin ECS.Component; + + alias value this;///use component as it value + + float value = 0; +} + +struct CDepth +{ + mixin ECS.Component; + + alias value this; + + short value; +} + +struct CColor +{ + mixin ECS.Component; + + alias value this; + + @GUIColor uint value; +} + +struct CSelected +{ + mixin ECS.Component; + + bool value = false; } \ No newline at end of file diff --git a/demos/source/game_core/rendering.d b/demos/source/game_core/rendering.d new file mode 100644 index 0000000..de5f0b5 --- /dev/null +++ b/demos/source/game_core/rendering.d @@ -0,0 +1,178 @@ +module game_core.rendering; + +import bubel.ecs.core; +import bubel.ecs.attributes; + +import ecs_utils.math.vector; +import ecs_utils.gfx.texture; + +import game_core.basic; + +struct CTexCoords +{ + mixin ECS.Component; + + alias value this;///use component as it value + + vec4 value; +} + +struct CTexCoordsIndex +{ + mixin ECS.Component; + + ushort value; +} + +struct TexCoordsManager +{ + import bubel.ecs.vector; + import bubel.ecs.hash_map; + + Vector!vec4 coords; + HashMap!(vec4,ushort) coords_map; +} + +struct DrawSystem +{ + mixin ECS.System!32; + + import ecs_utils.gfx.renderer : Renderer; + + struct EntitiesData + { + uint length; + //uint thread_id; + uint job_id; + @readonly CLocation[] locations; + @readonly CScale[] scale; + @readonly CTexCoords[] texcoord; + // @readonly @optional CTexCoords[] texcoord; + // @readonly @optional CTexCoordsIndex[] texcoord_index; + @readonly @optional CRotation[] rotation; + @readonly @optional CDepth[] depth; + @readonly @optional CColor[] color; + } + + Renderer.DrawData default_data; + + void onUpdate(EntitiesData data) + { + import app : launcher; + + if(launcher.renderer.prepared_items >= launcher.renderer.MaxObjects)return;//simple leave loop if max visible objects count was reached + Renderer.DrawData draw_data = default_data; + draw_data.thread_id = data.job_id; + + if(!data.depth) + { + if(!data.color) + { + if(!data.rotation) + { + foreach(i; 0..data.length) + { + draw_data.coords = data.texcoord[i]; + draw_data.size = data.scale[i]; + draw_data.position = data.locations[i]; + launcher.renderer.draw(draw_data); + } + } + else + { + foreach(i; 0..data.length) + { + draw_data.angle = data.rotation[i]; + draw_data.coords = data.texcoord[i]; + draw_data.size = data.scale[i]; + draw_data.position = data.locations[i]; + launcher.renderer.draw(draw_data); + } + } + } + else + { + if(!data.rotation) + { + foreach(i; 0..data.length) + { + draw_data.color = data.color[i]; + draw_data.coords = data.texcoord[i]; + draw_data.size = data.scale[i]; + draw_data.position = data.locations[i]; + launcher.renderer.draw(draw_data); + } + } + else + { + foreach(i; 0..data.length) + { + draw_data.color = data.color[i]; + draw_data.angle = data.rotation[i]; + draw_data.coords = data.texcoord[i]; + draw_data.size = data.scale[i]; + draw_data.position = data.locations[i]; + launcher.renderer.draw(draw_data); + } + } + } + } + else + { + if(!data.color) + { + if(!data.rotation) + { + foreach(i; 0..data.length) + { + draw_data.depth = data.depth[i]; + draw_data.coords = data.texcoord[i]; + draw_data.size = data.scale[i]; + draw_data.position = data.locations[i]; + launcher.renderer.draw(draw_data); + } + } + else + { + foreach(i; 0..data.length) + { + draw_data.depth = data.depth[i]; + draw_data.angle = data.rotation[i]; + draw_data.coords = data.texcoord[i]; + draw_data.size = data.scale[i]; + draw_data.position = data.locations[i]; + launcher.renderer.draw(draw_data); + } + } + } + else + { + if(!data.rotation) + { + foreach(i; 0..data.length) + { + draw_data.depth = data.depth[i]; + draw_data.color = data.color[i]; + draw_data.coords = data.texcoord[i]; + draw_data.size = data.scale[i]; + draw_data.position = data.locations[i]; + launcher.renderer.draw(draw_data); + } + } + else + { + foreach(i; 0..data.length) + { + draw_data.depth = data.depth[i]; + draw_data.color = data.color[i]; + draw_data.angle = data.rotation[i]; + draw_data.coords = data.texcoord[i]; + draw_data.size = data.scale[i]; + draw_data.position = data.locations[i]; + launcher.renderer.draw(draw_data); + } + } + } + } + } +} \ No newline at end of file diff --git a/demos/source/gui/manager.d b/demos/source/gui/manager.d index 6fb3165..3f6e6cb 100644 --- a/demos/source/gui/manager.d +++ b/demos/source/gui/manager.d @@ -173,9 +173,21 @@ struct GUIManager { switch(member_type.sizeof) { - case 1: comp_edit.variables[comp_edit.used++] = VariableGUI(VariableGUI.Type.byte_,member_str,offset);break; - case 2: comp_edit.variables[comp_edit.used++] = VariableGUI(VariableGUI.Type.short_,member_str,offset);break; - case 4: comp_edit.variables[comp_edit.used++] = VariableGUI(VariableGUI.Type.int_,member_str,offset);break; + case 1: + comp_edit.variables[comp_edit.used++] = VariableGUI(VariableGUI.Type.byte_,member_str,offset); + comp_edit.variables[comp_edit.used-1].int_.min = byte.min; + comp_edit.variables[comp_edit.used-1].int_.max = byte.max; + break; + case 2: + comp_edit.variables[comp_edit.used++] = VariableGUI(VariableGUI.Type.short_,member_str,offset); + comp_edit.variables[comp_edit.used-1].int_.min = short.min; + comp_edit.variables[comp_edit.used-1].int_.max = short.max; + break; + case 4: + comp_edit.variables[comp_edit.used++] = VariableGUI(VariableGUI.Type.int_,member_str,offset); + comp_edit.variables[comp_edit.used-1].int_.min = int.min; + comp_edit.variables[comp_edit.used-1].int_.max = int.max; + break; default:break; } static if(hasUDA!(member,GUIRange)) @@ -183,10 +195,10 @@ struct GUIManager comp_edit.variables[comp_edit.used-1].int_.min = getUDAs!(member,GUIRange)[0].min; comp_edit.variables[comp_edit.used-1].int_.max = getUDAs!(member,GUIRange)[1].max; } - { + /*{ comp_edit.variables[comp_edit.used-1].int_.min = int.min; comp_edit.variables[comp_edit.used-1].int_.max = int.max; - } + }*/ } } else static if(__traits(isScalar,member_type)) From 3e7575c4b2579d9d4aa08a40b64189fa8a7f0076 Mon Sep 17 00:00:00 2001 From: Mergul Date: Mon, 15 Jun 2020 17:21:29 +0200 Subject: [PATCH 159/217] Bug fixes -fix: UnittestRunner don't catch RangeError -fix: sometimes onUpdate was called with empty array of entities --- source/bubel/ecs/manager.d | 28 +++++++++++++++++++++++++--- tests/runner.d | 9 ++++++++- 2 files changed, 33 insertions(+), 4 deletions(-) diff --git a/source/bubel/ecs/manager.d b/source/bubel/ecs/manager.d index 4c543ce..132ab62 100644 --- a/source/bubel/ecs/manager.d +++ b/source/bubel/ecs/manager.d @@ -1011,7 +1011,8 @@ export struct EntityManager if (entities_count > 0) { assert(entities_count <= block.entities_count - && offset <= block.entities_count); + && offset < block.entities_count); + assert(entities_count > offset); fillInputData(input_data, info, block, offset, entities_count, system); @@ -1489,21 +1490,27 @@ export struct EntityManager if (first_block is null || blocks_count == 0) continue; + //if this info will fill job if ((blocks_count - 1) * info.max_entities + entities_count + info.last_block.entities_count - first_elem >= entities_per_job) { int reamaining_entities = (entities_per_job - entities_count - ( first_block.entities_count - first_elem)); - if (reamaining_entities >= 0) + + //if first block don't fill job + if (reamaining_entities > 0) { + //take as many full blocks as possible int full_blocks_count = reamaining_entities / info.max_entities; EntitiesBlock* block = first_block; foreach (i; 0 .. full_blocks_count + 1) block = block.next_block; + //if full block + actual contained entities + remaining entities form first block > entities count per job if (full_blocks_count * info.max_entities + entities_count + ( first_block.entities_count - first_elem) >= entities_per_job) { + assert(entities_per_job == full_blocks_count * info.max_entities + entities_count + (first_block.entities_count - first_elem)); CallData data = CallData(caller.system_id, sys, info, sys.m_update_delegate, first_block, cast(ushort)(full_blocks_count + 1), @@ -1518,6 +1525,8 @@ export struct EntityManager entities_count += full_blocks_count * info.max_entities + ( first_block.entities_count - first_elem); // - first_elem; uint last_elem = entities_per_job - entities_count; // + first_elem - 1; + assert(last_elem > 0); + assert(last_elem <= block.entities_count); CallData data = CallData(caller.system_id, sys, info, sys.m_update_delegate, first_block, cast(ushort)(full_blocks_count + 2), @@ -1525,19 +1534,31 @@ export struct EntityManager tmp_datas.add(data); first_elem = last_elem; blocks_count -= full_blocks_count + 1; - assert(first_elem <= block.entities_count); first_block = block; + if(last_elem == block.entities_count) + { + assert(block.next_block == null); + first_block = null; + } } } else { uint last_elem = entities_per_job - entities_count; + assert(last_elem > 0); CallData data = CallData(caller.system_id, sys, info, sys.m_update_delegate, first_block, 1, cast(ushort) first_elem, cast(ushort)(first_elem + last_elem)); tmp_datas.add(data); first_elem += last_elem; assert(first_elem <= first_block.entities_count); + //if job takes every entity, take next block + if(first_elem == first_block.entities_count) + { + first_elem = 0; + first_block = first_block.next_block; + blocks_count--; + } } nextJob(); entities_count = 0; @@ -1545,6 +1566,7 @@ export struct EntityManager } else { + //take whole info blocks CallData data = CallData(caller.system_id, sys, info, sys.m_update_delegate, first_block, cast(ushort) blocks_count, cast(ushort) first_elem); tmp_datas.add(data); diff --git a/tests/runner.d b/tests/runner.d index 7e3dd07..83c2288 100644 --- a/tests/runner.d +++ b/tests/runner.d @@ -236,7 +236,7 @@ struct TestRunner(Args...) } else { - import core.exception : AssertError; + import core.exception : AssertError, RangeError; try { unittest_(); @@ -249,6 +249,13 @@ struct TestRunner(Args...) test.file_line = cast(int)error.line; test.msg = copyString(error.msg); } + catch(RangeError error) + { + test.passed = false; + test.file = copyString(error.file); + test.file_line = cast(int)error.line; + test.msg = copyString(error.msg); + } } if (test.passed) From ffc19d4723f214cc4d083343f4021825849355cb Mon Sep 17 00:00:00 2001 From: Mergul Date: Mon, 15 Jun 2020 22:28:55 +0200 Subject: [PATCH 160/217] Better multithread jobs generation tests --- source/bubel/ecs/manager.d | 9 +++---- tests/basic.d | 48 +++++++++++++++++++++++++++++++++----- 2 files changed, 47 insertions(+), 10 deletions(-) diff --git a/source/bubel/ecs/manager.d b/source/bubel/ecs/manager.d index 132ab62..fa64e7b 100644 --- a/source/bubel/ecs/manager.d +++ b/source/bubel/ecs/manager.d @@ -1496,7 +1496,7 @@ export struct EntityManager { int reamaining_entities = (entities_per_job - entities_count - ( first_block.entities_count - first_elem)); - + //if first block don't fill job if (reamaining_entities > 0) { @@ -1510,7 +1510,8 @@ export struct EntityManager if (full_blocks_count * info.max_entities + entities_count + ( first_block.entities_count - first_elem) >= entities_per_job) { - assert(entities_per_job == full_blocks_count * info.max_entities + entities_count + (first_block.entities_count - first_elem)); + assert(entities_per_job == full_blocks_count * info.max_entities + entities_count + ( + first_block.entities_count - first_elem)); CallData data = CallData(caller.system_id, sys, info, sys.m_update_delegate, first_block, cast(ushort)(full_blocks_count + 1), @@ -1535,7 +1536,7 @@ export struct EntityManager first_elem = last_elem; blocks_count -= full_blocks_count + 1; first_block = block; - if(last_elem == block.entities_count) + if (last_elem == block.entities_count) { assert(block.next_block == null); first_block = null; @@ -1553,7 +1554,7 @@ export struct EntityManager first_elem += last_elem; assert(first_elem <= first_block.entities_count); //if job takes every entity, take next block - if(first_elem == first_block.entities_count) + if (first_elem == first_block.entities_count) { first_elem = 0; first_block = first_block.next_block; diff --git a/tests/basic.d b/tests/basic.d index 5046dff..5830a7b 100644 --- a/tests/basic.d +++ b/tests/basic.d @@ -897,7 +897,7 @@ unittest { struct TestSystem { - mixin ECS.System; + mixin ECS.System!64; struct EntitiesData { @@ -1003,15 +1003,51 @@ unittest assert(empty_system.update == 3); system.entities = 0; - foreach(i;0..10000)gEM.addEntity(tmpl); + // foreach(i;0..10000)gEM.addEntity(tmpl); - gEM.begin(); + // gEM.begin(); - gEM.updateMT("custom"); + // gEM.updateMT("custom"); - gEM.end(); + // gEM.end(); - assert(system.entities == 12001); + // assert(system.entities == 12001); + + void clearEntities(TestSystem.EntitiesData data) + { + foreach(i;0..data.length) + { + gEM.removeEntity(data.entity[i].id); + } + } + gEM.callEntitiesFunction!TestSystem(&clearEntities); + gEM.commit(); + + foreach(i;0..2000) + { + gEM.addEntity(tmpl); + + gEM.begin(); + gEM.updateMT("custom"); + gEM.end(); + + assert(system.entities == i+1); + system.entities = 0; + } + + foreach(i;0..90000)gEM.addEntity(tmpl); + + foreach(i;0..2000) + { + gEM.addEntity(tmpl); + + gEM.begin(); + gEM.updateMT("custom"); + gEM.end(); + + assert(system.entities == i+92001); + system.entities = 0; + } } unittest From ef4faf27551cd5025614b4ac2fa83326e2212b98 Mon Sep 17 00:00:00 2001 From: Mergul Date: Wed, 1 Jul 2020 19:26:47 +0200 Subject: [PATCH 161/217] Changed Components/System/Events names to full name (with module) and fixed bug with flag --- source/bubel/ecs/manager.d | 63 ++++++++++++++++++++++---------------- 1 file changed, 36 insertions(+), 27 deletions(-) diff --git a/source/bubel/ecs/manager.d b/source/bubel/ecs/manager.d index fa64e7b..cce03c6 100644 --- a/source/bubel/ecs/manager.d +++ b/source/bubel/ecs/manager.d @@ -382,6 +382,9 @@ export struct EntityManager else assert(pass < passes.length, "Update pass (ID " ~ pass.to!string ~ ") doesn't exist."); + enum SystemName = fullyQualifiedName!Sys; + //enum SystemName = Sys.stringof; + System system; system.m_pass = pass; @@ -418,9 +421,9 @@ export struct EntityManager static if (Params.length == 2 && is(Params[0] == Entity*)) { alias EventParamType = Params[1]; - enum EventName = Unqual!(EventParamType).stringof; + enum EventName = fullyQualifiedName!(Unqual!(EventParamType));//.stringof; ushort evt = events_map.get(cast(char[]) EventName, ushort.max); - assert(evt != ushort.max, "Can't register system \"" ~ Sys.stringof + assert(evt != ushort.max, "Can't register system \"" ~ SystemName ~ "\" due to non existing event \"" ~ EventName ~ "\"."); callers[i].callback = cast(void*)&callEventHandler!(EventParamType); @@ -479,7 +482,7 @@ export struct EntityManager string name; static if (isArray!MemberType) { // Workaround. This code is never called with: not an array type, but compiler prints an error - name = Unqual!(ForeachType!MemberType).stringof; + name = fullyQualifiedName!(Unqual!(ForeachType!MemberType));//.stringof; } bool is_optional; @@ -704,7 +707,8 @@ export struct EntityManager string name; static if (isArray!MemberType) { // Workaround. This code is never called with: not an array type, but compiler prints an error - name = Unqual!(ForeachType!MemberType).stringof; + name = fullyQualifiedName!(Unqual!(ForeachType!MemberType)); + //name = Unqual!(ForeachType!MemberType).stringof; } bool is_optional; @@ -759,7 +763,8 @@ export struct EntityManager { foreach (str; Sys.ExcludedComponents) { - components_info.addExcluded(CompInfo(str.stringof, str.stringof)); + components_info.addExcluded(CompInfo(str.stringof, fullyQualifiedName!str)); + // components_info.addExcluded(CompInfo(str.stringof, str.stringof)); } } @@ -828,10 +833,10 @@ export struct EntityManager ushort comp = components_map.get(cast(char[]) comp_info.type, ushort.max); version (D_BetterC) assert(comp != ushort.max, - "Can't register system \"" ~ Sys.stringof + "Can't register system \"" ~ SystemName ~ "\" due to non existing component."); else - assert(comp != ushort.max, "Can't register system \"" ~ Sys.stringof + assert(comp != ushort.max, "Can't register system \"" ~ SystemName ~ "\" due to non existing component \"" ~ comp_info.type ~ "\"."); system.m_components[iii] = comp; } @@ -840,10 +845,10 @@ export struct EntityManager ushort comp = components_map.get(cast(char[]) comp_info.type, ushort.max); version (D_BetterC) assert(comp != ushort.max, - "Can't register system \"" ~ Sys.stringof + "Can't register system \"" ~ SystemName ~ "\" due to non existing component."); else - assert(comp != ushort.max, "Can't register system \"" ~ Sys.stringof + assert(comp != ushort.max, "Can't register system \"" ~ SystemName ~ "\" due to non existing component \"" ~ comp_info.type ~ "\"."); system.m_excluded_components[iii] = comp; } @@ -852,10 +857,10 @@ export struct EntityManager ushort comp = components_map.get(cast(char[]) comp_info.type, ushort.max); version (D_BetterC) assert(comp != ushort.max, - "Can't register system \"" ~ Sys.stringof + "Can't register system \"" ~ SystemName ~ "\" due to non existing component."); else - assert(comp != ushort.max, "Can't register system \"" ~ Sys.stringof + assert(comp != ushort.max, "Can't register system \"" ~ SystemName ~ "\" due to non existing component \"" ~ comp_info.type ~ "\"."); system.m_optional_components[iii] = comp; } @@ -864,10 +869,10 @@ export struct EntityManager ushort comp = components_map.get(cast(char[]) comp_info.type, ushort.max); version (D_BetterC) assert(comp != ushort.max, - "Can't register system \"" ~ Sys.stringof + "Can't register system \"" ~ SystemName ~ "\" due to non existing component."); else - assert(comp != ushort.max, "Can't register system \"" ~ Sys.stringof + assert(comp != ushort.max, "Can't register system \"" ~ SystemName ~ "\" due to non existing component \"" ~ comp_info.type ~ "\"."); system.m_read_only_components[iii] = comp; } @@ -876,10 +881,10 @@ export struct EntityManager ushort comp = components_map.get(cast(char[]) comp_info.type, ushort.max); version (D_BetterC) assert(comp != ushort.max, - "Can't register system \"" ~ Sys.stringof + "Can't register system \"" ~ SystemName ~ "\" due to non existing component."); else - assert(comp != ushort.max, "Can't register system \"" ~ Sys.stringof + assert(comp != ushort.max, "Can't register system \"" ~ SystemName ~ "\" due to non existing component \"" ~ comp_info.type ~ "\"."); system.m_writable_components[iii] = comp; } @@ -1155,10 +1160,10 @@ export struct EntityManager ushort.max); version (D_BetterC) assert(comp != ushort.max, - "Can't register system \"" ~ Sys.stringof + "Can't register system \"" ~ SystemName ~ "\" due to non existing dependency."); else - assert(comp != ushort.max, "Can't register system \"" ~ Sys.stringof + assert(comp != ushort.max, "Can't register system \"" ~ SystemName ~ "\" due to non existing dependency \"" ~ comp_info.type ~ "\"."); system.m_readonly_dependencies[iii] = comp; } @@ -1168,15 +1173,15 @@ export struct EntityManager ushort comp = external_dependencies_map.get(cast(char[]) comp_info.type, ushort.max); version (D_BetterC) assert(comp != ushort.max, - "Can't register system \"" ~ Sys.stringof + "Can't register system \"" ~ SystemName ~ "\" due to non existing dependency."); else - assert(comp != ushort.max, "Can't register system \"" ~ Sys.stringof + assert(comp != ushort.max, "Can't register system \"" ~ SystemName ~ "\" due to non existing dependency \"" ~ comp_info.type ~ "\"."); system.m_writable_dependencies[iii] = comp; } - ushort sys_id = systems_map.get(cast(char[]) Sys.stringof, ushort.max); + ushort sys_id = systems_map.get(cast(char[]) SystemName, ushort.max); if (sys_id < systems.length) { systems[sys_id].disable(); @@ -1195,7 +1200,7 @@ export struct EntityManager } else { - system.m_name = Mallocator.makeArray(cast(char[]) Sys.stringof); + system.m_name = Mallocator.makeArray(cast(char[]) SystemName); systems_map.add(system.m_name, cast(ushort) systems.length); @@ -1254,6 +1259,9 @@ export struct EntityManager { ComponentInfo info; + enum ComponentName = fullyQualifiedName!Comp; + //enum ComponentName = Comp.stringof; + static if (!(hasMember!(Comp, "component_id")) || !is(typeof(Comp.component_id) == ushort)) { static assert(0, "Add \"mixin ECS.Component;\" in top of component structure;"); @@ -1290,7 +1298,7 @@ export struct EntityManager info.init_data = Mallocator.makeArray!ubyte(Comp.sizeof); *cast(Comp*) info.init_data.ptr = Comp.init; // = Comp(); - ushort comp_id = components_map.get(cast(char[]) Comp.stringof, ushort.max); + ushort comp_id = components_map.get(cast(char[]) ComponentName, ushort.max); if (comp_id < components.length) { Comp.component_id = comp_id; @@ -1300,9 +1308,7 @@ export struct EntityManager { components.add(info); Comp.component_id = cast(ushort)(components.length - 1); - char[] name = Mallocator.makeArray(cast(char[]) Comp.stringof); - /*char[] name = Mallocator.makeArray!char(Comp.stringof.length); - name[0..$] = Comp.stringof;*/ + char[] name = Mallocator.makeArray(cast(char[]) ComponentName); components_map.add(name, cast(ushort)(components.length - 1)); } } @@ -1330,7 +1336,8 @@ export struct EntityManager info.size = Ev.sizeof; info.alignment = Ev.alignof; - ushort event_id = events_map.get(Ev.stringof, ushort.max); + //ushort event_id = events_map.get(Ev.stringof, ushort.max); + ushort event_id = events_map.get(fullyQualifiedName!Ev, ushort.max); if (event_id < events.length) { Ev.event_id = event_id; @@ -1339,7 +1346,8 @@ export struct EntityManager { events.add(info); Ev.event_id = cast(ushort)(events.length - 1); - events_map.add(Ev.stringof, cast(ushort)(events.length - 1)); + // events_map.add(Ev.stringof, cast(ushort)(events.length - 1)); + events_map.add(fullyQualifiedName!Ev, cast(ushort)(events.length - 1)); } } @@ -1861,6 +1869,7 @@ export struct EntityManager foreach (i, id; ids) { + if(current_delta == 0)current_delta = ushort.max; alignNum(current_delta, components[id].alignment); info.deltas[id] = cast(ushort) current_delta; current_delta += entites_in_block * components[id].size; From b0b64b965f1989fba39ccf884fa10d2cd4d776ef Mon Sep 17 00:00:00 2001 From: Mergul Date: Wed, 1 Jul 2020 19:45:53 +0200 Subject: [PATCH 162/217] Demos update -added some new types to gui manager + some fixes -TexCoordsManager now working (probably) -added CRenderDefault components which makes entities without texcoords possible to draw -makes better way of binding demos to launcher -moved some registration related to rendering to one function (basic components + draw system) -added Sandbox demo (demo which takes all demos to one demo) -extends ParticlesDemo play area -added BirckBreaker demo (WIP) -added special material to additive particles -added whole bunch of rendering code to rendering module -added ability to show filtered entities (blinking) --- demos/assets/shaders/additive_particles.fp | 55 +++ demos/assets/shaders/additive_particles.vp | 106 +++++ demos/source/app.d | 93 +++- demos/source/demos/brick_breaker.d | 193 +++++++++ demos/source/demos/particles.d | 45 +- demos/source/demos/sandbox.d | 89 ++++ demos/source/demos/simple.d | 39 +- demos/source/demos/snake.d | 14 + demos/source/demos/space_invaders.d | 40 +- demos/source/game_core/rendering.d | 472 ++++++++++++++++++++- demos/source/gui/component.d | 4 +- demos/source/gui/manager.d | 46 +- 12 files changed, 1122 insertions(+), 74 deletions(-) create mode 100644 demos/assets/shaders/additive_particles.fp create mode 100644 demos/assets/shaders/additive_particles.vp create mode 100644 demos/source/demos/brick_breaker.d create mode 100644 demos/source/demos/sandbox.d diff --git a/demos/assets/shaders/additive_particles.fp b/demos/assets/shaders/additive_particles.fp new file mode 100644 index 0000000..047f647 --- /dev/null +++ b/demos/assets/shaders/additive_particles.fp @@ -0,0 +1,55 @@ +precision mediump int; +precision mediump float; +precision lowp sampler2D; +precision lowp samplerCube; + + +#ifdef GLES + #define TEX(x,y) texture2D(x,y) + #if __VERSION__ >290 + #define M_IN in mediump + #define L_IN in lowp + #else + #define M_IN varying mediump + #define L_IN varying lowp + #endif +#else + #define TEX(x,y) texture(x,y) + #if __VERSION__ > 320 + #define M_IN in + #define L_IN in + #else + #define M_IN varying + #define L_IN varying + #endif +#endif + + +M_IN vec2 uv; +M_IN vec4 color; +/* +#ifdef GLES + #if __VERSION__ >290 + in mediump vec2 uv; + #else + varying mediump vec2 uv; + #endif +#else + #if __VERSION__ > 320 + in vec2 uv; + #else + varying vec2 uv; + #endif +#endif*/ + +//layout(binding = 0)uniform sampler2D tex; + +uniform sampler2D tex; + +//layout(location = 0) out vec4 outColor; + +void main() +{ + gl_FragColor = /*TEX(tex,uv) **/ color; + if(gl_FragColor.a < 0.01)discard; +} diff --git a/demos/assets/shaders/additive_particles.vp b/demos/assets/shaders/additive_particles.vp new file mode 100644 index 0000000..2777a24 --- /dev/null +++ b/demos/assets/shaders/additive_particles.vp @@ -0,0 +1,106 @@ +precision highp float; +precision highp int; +precision lowp sampler2D; +precision lowp samplerCube; +#ifdef GLES + #if __VERSION__ >290 + #define LOC(x) layout(location = x) + #define ATT in + #define M_OUT out mediump + #define L_OUT out lowp + #else + #define LOC(x) + #define ATT attribute + #define M_OUT varying mediump + #define L_OUT varying lowp + #endif +#else + #if __VERSION__ > 320 + #define LOC(x) layout(location = x) + #define ATT in + #define M_OUT out + #define L_OUT out + #else + #define LOC(x) + #define ATT attribute + #define M_OUT varying + #define L_OUT varying + #endif +#endif +/* +#ifdef GLES + #if __VERSION__ >290 + uniform vec4 matrix_1; + uniform vec4 matrix_2; + uniform vec4 uv_transform; + + layout(location = 0) in vec2 positions; + layout(location = 1) in vec2 tex_coords; + + out mediump vec2 uv; + #else + uniform vec4 matrix_1; + uniform vec4 matrix_2; + uniform vec4 uv_transform; + + attribute vec2 positions; + attribute vec2 tex_coords; + + varying mediump vec2 uv; + #endif +#else + #if __VERSION__ > 320 + uniform vec4 matrix_1; + uniform vec4 matrix_2; + uniform vec4 uv_transform; + + layout(location = 0) in vec2 positions; + layout(location = 1) in vec2 tex_coords; + + out vec2 uv; + #else + uniform vec4 matrix_1; + uniform vec4 matrix_2; + uniform vec4 uv_transform; + + attribute vec2 positions; + attribute vec2 tex_coords; + + varying vec2 uv; + #endif +#endif*/ + +#define VBO_BATCH 1 + +M_OUT vec2 uv; +L_OUT vec4 color; + +LOC(0) ATT vec2 positions; +LOC(1) ATT vec2 tex_coords; + +#ifdef VBO_BATCH + LOC(2) ATT float depth; + LOC(3) ATT vec4 vcolor; +#else + uniform vec4 matrix_1; + uniform vec4 matrix_2; + uniform vec4 uv_transform; + uniform vec4 vcolor; + + float depth = matrix_2.z; +#endif + +void main() { + #ifdef VBO_BATCH + vec3 position = vec3(positions*4.0,1.0); + uv = tex_coords; + #else + vec3 position = mat3(matrix_1.x,matrix_1.y,0,matrix_1.z,matrix_1.w,0,matrix_2.xy,1.0) * vec3(positions,1.0); + uv = tex_coords * uv_transform.zw + uv_transform.xy; + #endif + + color = vcolor; + + gl_Position = vec4(position.xy,depth,1.0); + +} diff --git a/demos/source/app.d b/demos/source/app.d index 6808e42..2310413 100644 --- a/demos/source/app.d +++ b/demos/source/app.d @@ -41,6 +41,15 @@ struct Mouse bool left, right, middle; } +struct DemoCallbacks +{ + void function() initialize; + void function() deinitialize; + bool function() loop; + void function(SDL_Event*) event; + const (char)* tips; +} + struct Launcher { ECSJobUpdater* job_updater; @@ -49,9 +58,9 @@ struct Launcher SDL_Window* window; SDL_GLContext gl_context; EntityManager* manager; - bool function() loop; + /*bool function() loop; void function() end; - void function(SDL_Event*) event; + void function(SDL_Event*) event;*/ //void function(vec2, Tool, int, bool) tool; float scalling; ivec2 window_size = ivec2(1024,768); @@ -74,12 +83,13 @@ struct Launcher bool override_ = true; bool tool_mode = true; ToolCircle* tool_circle; + bool show_filtered; bool swap_interval = true; float windows_alpha = 0.75; - const (char)* tips; + //const (char)* tips; bool show_stat_wnd = true; bool show_tips = true; @@ -99,12 +109,14 @@ struct Launcher float draw_time = 0; } - void switchDemo(void function() start, bool function() loop, void function() end, void function(SDL_Event*) event, const (char)* tips) + DemoCallbacks demo; + + void switchDemo(DemoCallbacks callbacks)//void function() start, bool function() loop, void function() end, void function(SDL_Event*) event, const (char)* tips) { gui_manager.clear(); //launcher.ent - if(this.end)this.end(); + if(this.demo.deinitialize)this.demo.deinitialize(); manager.begin(); manager.update("clean"); @@ -118,14 +130,29 @@ struct Launcher /*launcher.manager.getSystem(CountSystem.system_id).enable(); launcher.manager.getSystem(CleanSystem.system_id).enable();//*/ - if(start)start(); - this.loop = loop; + if(callbacks.initialize)callbacks.initialize(); + demo = callbacks; + /*this.loop = loop; this.end = end; this.event = event; - this.tips = tips; + this.tips = tips;*/ //this.tool = tool; } + bool filterEntity(ref const Entity entity) + { + EntityMeta meta = entity.getMeta(); + foreach(id;gui_manager.filter_list) + { + if(!meta.hasComponent(id))return false; + } + if(used_tool == Tool.component_manipulator) + { + if(!meta.hasComponent(gui_manager.getSelectedComponent().component_id))return false; + } + return true; + } + void processTool(vec2 position, bool mode) { static struct Iterator @@ -361,7 +388,7 @@ void mainLoop(void* arg) while (SDL_PollEvent(&event)) { ImGui_ImplSDL2_ProcessEvent(&event); - if(launcher.event)launcher.event(&event); + if(launcher.demo.event)launcher.demo.event(&event); if (event.type == SDL_QUIT || (event.type == SDL_KEYDOWN && event.key.keysym.scancode == SDL_SCANCODE_ESCAPE)) { quit(); *cast(bool*)arg = false; @@ -534,22 +561,32 @@ void mainLoop(void* arg) if(igMenuItemBool("Simpe",null,false,true)) { import demos.simple; - launcher.switchDemo(&simpleStart,&simpleLoop,&simpleEnd,&simpleEvent,Simple.tips); + launcher.switchDemo(getSimpleDemo());//&simpleStart,&simpleLoop,&simpleEnd,&simpleEvent,Simple.tips); } if(igMenuItemBool("Snake",null,false,true)) { import demos.snake; - launcher.switchDemo(&snakeStart,&snakeLoop,&snakeEnd,&snakeEvent,Snake.tips); + launcher.switchDemo(getSnakeDemo());//&snakeStart,&snakeLoop,&snakeEnd,&snakeEvent,Snake.tips); } - if(igMenuItemBool("Space invaders",null,false,true)) + if(igMenuItemBool("Space Invaders",null,false,true)) { import demos.space_invaders; - launcher.switchDemo(&spaceInvadersStart,&spaceInvadersLoop,&spaceInvadersEnd,&spaceInvadersEvent,SpaceInvaders.tips); + launcher.switchDemo(getSpaceInvadersDemo());//&spaceInvadersStart,&spaceInvadersLoop,&spaceInvadersEnd,&spaceInvadersEvent,SpaceInvaders.tips); } if(igMenuItemBool("Particles",null,false,true)) { import demos.particles; - launcher.switchDemo(&particlesStart,&particlesLoop,&particlesEnd,&particlesEvent,ParticlesDemo.tips); + launcher.switchDemo(getParticlesDemo());//&particlesStart,&particlesLoop,&particlesEnd,&particlesEvent,ParticlesDemo.tips); + } + if(igMenuItemBool("Brick Breaker",null,false,true)) + { + import demos.brick_breaker; + launcher.switchDemo(getBrickBreakerDemo());//&particlesStart,&particlesLoop,&particlesEnd,&particlesEvent,ParticlesDemo.tips); + } + if(igMenuItemBool("Sandbox",null,false,true)) + { + import demos.sandbox; + launcher.switchDemo(getSanboxDemo());//&particlesStart,&particlesLoop,&particlesEnd,&particlesEvent,ParticlesDemo.tips); } igEndMenu(); } @@ -683,7 +720,7 @@ void mainLoop(void* arg) igSetNextWindowBgAlpha(launcher.windows_alpha); if(igBegin("Tips",&launcher.show_tips,ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoSavedSettings)) { - igTextWrapped(launcher.tips); + igTextWrapped(launcher.demo.tips); } igEnd(); } @@ -726,9 +763,11 @@ void mainLoop(void* arg) if(igIsItemHovered(0))igSetTooltip("Select tool (CTRL + 1,2,3)"); igCheckbox("Show Tool", &launcher.tool_show); if(igIsItemHovered(0))igSetTooltip("Show/hide graphical tool representation"); + igSameLine(0,4); + igCheckbox("Show Filtered", &launcher.show_filtered); + if(igIsItemHovered(0))igSetTooltip("Show/hide filtered entities"); if(launcher.used_tool == Tool.component_manipulator) { - igSameLine(0,4); igCheckbox("Override", &launcher.override_); } @@ -823,7 +862,7 @@ void mainLoop(void* arg) double loop_time = launcher.getTime(); launcher.job_updater.pool.tryWaitCount = 10000; - if(launcher.loop && !launcher.loop()) + if(launcher.demo.loop && !launcher.demo.loop()) { quit(); *cast(bool*)arg = false; @@ -1053,6 +1092,8 @@ int app_main(int argc, char** argv) loadGFX(); launcher.renderer.initialize(); + import game_core.rendering : TexCoordsManager; + TexCoordsManager.initialize(); import mmutils.thread_pool : ThreadPool; launcher.threads = ThreadPool.getCPUCoresCount(); @@ -1065,8 +1106,10 @@ int app_main(int argc, char** argv) import demos.space_invaders; import demos.particles; // launcher.switchDemo(&spaceInvadersStart,&spaceInvadersLoop,&spaceInvadersEnd,&spaceInvadersEvent,SpaceInvaders.tips); - launcher.switchDemo(&particlesStart,&particlesLoop,&particlesEnd,&particlesEvent,ParticlesDemo.tips); + // launcher.switchDemo(&particlesStart,&particlesLoop,&particlesEnd,&particlesEvent,ParticlesDemo.tips); // launcher.switchDemo(&simpleStart,&simpleLoop,&simpleEnd,&simpleEvent,Simple.tips); + // launcher.switchDemo(getParticlesDemo()); + launcher.switchDemo(getSimpleDemo()); } int key_num; @@ -1094,6 +1137,7 @@ int app_main(int argc, char** argv) } } + TexCoordsManager.destroy(); EntityManager.destroy(); return 0; @@ -1198,13 +1242,22 @@ void loadGFX() + + Shader vsh3; + vsh3.create(); + vsh3.load("assets/shaders/additive_particles.vp"); + vsh3.compile(); + Shader fsh3; + fsh3.create(); + fsh3.load("assets/shaders/additive_particles.fp"); + fsh3.compile(); GfxConfig.materials[2].create(); GfxConfig.materials[2].data.blend_mode = Material.BlendMode.opaque; GfxConfig.materials[2].data.mode = Material.TransformMode.position; - //Material.ShaderModule[1] modules = [Material.ShaderModule(vsh,fsh)]; - GfxConfig.materials[2].attachModules(modules); + Material.ShaderModule[1] modules3 = [Material.ShaderModule(vsh3,fsh3)]; + GfxConfig.materials[2].attachModules(modules3); //GfxConfig.materials[0]. //GfxConfig.materials[0].load(load_data.materials[i].str); GfxConfig.materials[2].compile(); diff --git a/demos/source/demos/brick_breaker.d b/demos/source/demos/brick_breaker.d new file mode 100644 index 0000000..1af22b9 --- /dev/null +++ b/demos/source/demos/brick_breaker.d @@ -0,0 +1,193 @@ +module demos.brick_breaker; + +import app; + +import bindbc.sdl; + +import bubel.ecs.attributes; +import bubel.ecs.core; +import bubel.ecs.entity; +import bubel.ecs.manager; +import bubel.ecs.std; + +import cimgui.cimgui; + +import ecs_utils.gfx.texture; +import ecs_utils.math.vector; +import ecs_utils.utils; + +import game_core.basic; +import game_core.rendering; + +extern(C): + +/*####################################################################################################################### +------------------------------------------------ Components ------------------------------------------------------------------ +#######################################################################################################################*/ + +/*struct CLocation +{ + mixin ECS.Component; + + alias location this; + + vec2 location; +}*/ + +struct CBrick +{ + mixin ECS.Component; +} + +struct CPaddle +{ + mixin ECS.Component; +} + +struct CBall +{ + mixin ECS.Component; + + ubyte radius; +} + +struct CVelocity +{ + mixin ECS.Component; + + alias value this; + + vec2 value; +} + +/*####################################################################################################################### +------------------------------------------------ Systems ------------------------------------------------------------------ +#######################################################################################################################*/ + +struct MoveSystem +{ + mixin ECS.System!64; + + struct EntitiesData + { + uint length; + CLocation[] location; + @readonly CVelocity[] velocity; + } + + void onUpdate(EntitiesData data) + { + foreach(i; 0..data.length) + { + data.location[i] += data.velocity[i] * launcher.delta_time; + } + } +} + +struct BallCollisionSystem +{ + mixin ECS.System!64; + + struct EntitiesData + { + uint length; + CLocation[] location; + CVelocity[] velocity; + } + + void onUpdate(EntitiesData data) + { + foreach(i; 0..data.length) + { + + } + } +} + +/*####################################################################################################################### +------------------------------------------------ Functions ------------------------------------------------------------------ +#######################################################################################################################*/ + +struct BrickBreakerDemo +{ + __gshared const (char)* tips = "Brick breaker demo. It's a game about destroying evil bricks."; + + EntityTemplate* tmpl; + Texture texture; +} + +__gshared BrickBreakerDemo* demo; + +void brickBreakerStart() +{ + demo = Mallocator.make!BrickBreakerDemo; + + launcher.manager.beginRegister(); + + registerRenderingModule(launcher.manager); + + launcher.manager.registerComponent!CLocation; + launcher.manager.registerComponent!CRotation; + launcher.manager.registerComponent!CScale; + launcher.manager.registerComponent!CTexCoords; + launcher.manager.registerComponent!CTexCoordsIndex; + launcher.manager.registerComponent!CVelocity; + + launcher.manager.registerSystem!MoveSystem(-100); + launcher.manager.registerSystem!BallCollisionSystem(-99); + + launcher.manager.endRegister(); + + demo.texture.create(); + demo.texture.load("assets/textures/atlas.png"); + + launcher.manager.beginRegister(); + + launcher.manager.registerComponent!CLocation; + + launcher.manager.endRegister(); +} + +void brickBreakerEnd() +{ + launcher.manager.getSystem(MoveSystem.system_id).disable(); + launcher.manager.getSystem(DrawSystem.system_id).disable(); + + demo.texture.destroy(); + + Mallocator.dispose(demo); +} + +void brickBreakerEvent(SDL_Event* event) +{ +} + +bool brickBreakerLoop() +{ + launcher.render_position = (vec2(launcher.window_size.x,launcher.window_size.y)*launcher.scalling - vec2(400,300)) * 0.5; + + launcher.manager.begin(); + if(launcher.multithreading) + { + launcher.job_updater.begin(); + launcher.manager.updateMT(); + launcher.job_updater.call(); + } + else + { + launcher.manager.update(); + } + launcher.manager.end(); + + return true; +} + +DemoCallbacks getBrickBreakerDemo() +{ + DemoCallbacks demo; + demo.initialize = &brickBreakerStart; + demo.deinitialize = &brickBreakerEnd; + demo.loop = &brickBreakerLoop; + demo.tips = .demo.tips; + return demo; +} \ No newline at end of file diff --git a/demos/source/demos/particles.d b/demos/source/demos/particles.d index 2242ecf..8dac7ff 100644 --- a/demos/source/demos/particles.d +++ b/demos/source/demos/particles.d @@ -17,6 +17,7 @@ import ecs_utils.math.vector; import ecs_utils.utils; import game_core.basic; +import game_core.rendering; import gui.attributes; @@ -115,7 +116,7 @@ struct CParticleLife /*####################################################################################################################### ------------------------------------------------ Systems ------------------------------------------------------------------ #######################################################################################################################*/ - +/* struct DrawSystem { mixin ECS.System!32; @@ -162,7 +163,7 @@ struct DrawSystem } } -} +}*/ struct MoveSystem { @@ -338,10 +339,10 @@ struct PlayAreaSystem { foreach(i; 0..data.length) { - if(data.locations[i].x > 400)launcher.manager.removeEntity(data.entity[i].id); - else if(data.locations[i].x < 0)launcher.manager.removeEntity(data.entity[i].id); - if(data.locations[i].y > 300)launcher.manager.removeEntity(data.entity[i].id); - else if(data.locations[i].y < 0)launcher.manager.removeEntity(data.entity[i].id); + if(data.locations[i].x > 440)launcher.manager.removeEntity(data.entity[i].id); + else if(data.locations[i].x < -40)launcher.manager.removeEntity(data.entity[i].id); + if(data.locations[i].y > 340)launcher.manager.removeEntity(data.entity[i].id); + else if(data.locations[i].y < -40)launcher.manager.removeEntity(data.entity[i].id); } } } @@ -452,16 +453,24 @@ void particlesStart() launcher.manager.beginRegister(); + registerRenderingModule(launcher.manager); + launcher.manager.registerComponent!CLocation; //launcher.manager.registerComponent!CTexCoords; launcher.manager.registerComponent!CColor; launcher.manager.registerComponent!CVelocity; + launcher.manager.registerComponent!CScale; + launcher.manager.registerComponent!CTexCoords; + launcher.manager.registerComponent!CTexCoordsIndex; + launcher.manager.registerComponent!CRotation; + launcher.manager.registerComponent!CDepth; launcher.manager.registerComponent!CAttractor; launcher.manager.registerComponent!CDamping; launcher.manager.registerComponent!CGravity; launcher.manager.registerComponent!CVortex; launcher.manager.registerComponent!CParticleLife; launcher.manager.registerComponent!CForceRange; + launcher.manager.registerComponent!CMaterialIndex; launcher.manager.registerSystem!MoveSystem(0); launcher.manager.registerSystem!DrawSystem(100); @@ -476,6 +485,12 @@ void particlesStart() launcher.manager.endRegister(); + DrawSystem* draw_system = launcher.manager.getSystem!DrawSystem; + draw_system.default_data.size = vec2(2,2); + draw_system.default_data.coords = vec4(246,64,2,2)*px; + draw_system.default_data.material_id = 2; + draw_system.default_data.texture = particles_demo.texture; + launcher.gui_manager.addSystem(MoveSystem.system_id,"Move System"); launcher.gui_manager.addSystem(DrawSystem.system_id,"Draw System"); launcher.gui_manager.addSystem(PlayAreaSystem.system_id,"Play Area System"); @@ -498,8 +513,11 @@ void particlesStart() launcher.gui_manager.addComponent(CGravity(),"Gravity"); EntityTemplate* tmpl; - EntityTemplate* base_tmpl = launcher.manager.allocateTemplate([CLocation.component_id, CColor.component_id, CVelocity.component_id, CDamping.component_id].staticArray); + EntityTemplate* base_tmpl = launcher.manager.allocateTemplate([CTexCoords.component_id, CLocation.component_id, CColor.component_id, CVelocity.component_id, CDamping.component_id, CScale.component_id, CMaterialIndex.component_id].staticArray); base_tmpl.getComponent!CColor().value = 0xFF251010; + base_tmpl.getComponent!CScale().value = vec2(2); + base_tmpl.getComponent!CTexCoords().value = vec4(246,64,2,2)*px; + base_tmpl.getComponent!CMaterialIndex().value = 2; launcher.gui_manager.addTemplate(base_tmpl,"Particle"); // tmpl = launcher.manager.allocateTemplate(base_tmpl); // tmpl.getComponent!CColor().value = 0xFF251010; @@ -515,7 +533,8 @@ void particlesStart() // tmpl = launcher.manager.allocateTemplate(tmpl); // tmpl.getComponent!CDamping().power = 4; // launcher.gui_manager.addTemplate(tmpl,"Particle (damping!)"); - tmpl = launcher.manager.allocateTemplate([CAttractor.component_id, CLocation.component_id, CForceRange.component_id].staticArray); + tmpl = launcher.manager.allocateTemplate([CAttractor.component_id, CLocation.component_id, CForceRange.component_id, CScale.component_id].staticArray); + tmpl.getComponent!CScale().value = vec2(4); launcher.gui_manager.addTemplate(tmpl,"Attractor"); tmpl = launcher.manager.allocateTemplate(tmpl, [CVortex.component_id].staticArray); launcher.gui_manager.addTemplate(tmpl,"Vortex"); @@ -555,4 +574,14 @@ bool particlesLoop() launcher.manager.end(); return true; +} + +DemoCallbacks getParticlesDemo() +{ + DemoCallbacks demo; + demo.initialize = &particlesStart; + demo.deinitialize = &particlesEnd; + demo.loop = &particlesLoop; + demo.tips = ParticlesDemo.tips; + return demo; } \ No newline at end of file diff --git a/demos/source/demos/sandbox.d b/demos/source/demos/sandbox.d new file mode 100644 index 0000000..69a2ef2 --- /dev/null +++ b/demos/source/demos/sandbox.d @@ -0,0 +1,89 @@ +module demos.sandbox; + +import bindbc.sdl; + +import demos.simple; +import demos.snake; +import demos.space_invaders; +import demos.particles; + +import game_core.rendering; + +import app; + +import ecs_utils.math.vector; + +extern(C): + +void sandboxStart() +{ + simpleStart(); + snakeStart(); + spaceInvadersStart(); + particlesStart(); + + DrawSystem* draw_system = launcher.manager.getSystem!DrawSystem; + draw_system.default_data.size = vec2(16,16); + draw_system.default_data.coords = vec4(0,48,16,16)*demos.simple.px; + draw_system.default_data.material_id = 0; + draw_system.default_data.texture = particles_demo.texture; + draw_system.default_data.color = 0x80808080; +} + +void sandboxEnd() +{ + simpleEnd(); + snakeEnd(); + spaceInvadersEnd(); + particlesEnd(); +} +/* +void sandboxEvent(SDL_Event* event) +{ +}*/ + +bool sandboxLoop() +{ + launcher.render_position = (vec2(launcher.window_size.x,launcher.window_size.y)*launcher.scalling - vec2(400,300)) * 0.5; + + launcher.manager.begin(); + + float delta_time = launcher.delta_time; + if(delta_time > 2000)delta_time = 2000; + __gshared float time = 0; + + /*if(launcher.getKeyState(SDL_SCANCODE_SPACE))time += delta_time * 3; + else */ + time += delta_time; + + while(time > 100) + { + time -= 100; + + launcher.manager.update("fixed"); + } + + if(launcher.multithreading) + { + launcher.job_updater.begin(); + launcher.manager.updateMT(); + launcher.job_updater.call(); + } + else + { + launcher.manager.update(); + } + launcher.manager.end(); + + return true; +} + +DemoCallbacks getSanboxDemo() +{ + DemoCallbacks demo; + demo.initialize = &sandboxStart; + demo.deinitialize = &sandboxEnd; + demo.loop = &sandboxLoop; + demo.tips = "tips"; + return demo; +} \ No newline at end of file diff --git a/demos/source/demos/simple.d b/demos/source/demos/simple.d index 6876e4f..1aafcb2 100644 --- a/demos/source/demos/simple.d +++ b/demos/source/demos/simple.d @@ -17,9 +17,12 @@ import ecs_utils.math.vector; import ecs_utils.utils; import game_core.basic; +import game_core.rendering; extern(C): +enum float px = 1.0/512.0; + /*####################################################################################################################### ------------------------------------------------ Components ------------------------------------------------------------------ #######################################################################################################################*/ @@ -36,7 +39,7 @@ extern(C): /*####################################################################################################################### ------------------------------------------------ Systems ------------------------------------------------------------------ #######################################################################################################################*/ - +/* struct DrawSystem { mixin ECS.System!32; @@ -66,13 +69,9 @@ struct DrawSystem draw_data.position = data.locations[i]; draw_data.depth = cast(ushort)(data.locations[i].y); launcher.renderer.draw(draw_data); - //launcher.renderer.draw(simple.texture, data.locations[i], vec2(16,16), vec4(0,0,1,1), cast(ushort)(data.locations[i].y), 0x80808080, 0, 0, 0, data.job_id); - // launcher.renderer.draw(data.textures[i].tex, data.locations[i].location, vec2(16,16), vec4(0,0,1,1), 0, 0x80808080, 0, 0, 0, data.job_id); - //draw(renderer, data.textures[i].tex, data.locations[i], vec2(32,32), vec4(0,0,1,1)); } - //if(data.thread_id == 0)launcher.renderer.pushData(); } -} +}*/ struct MoveSystem { @@ -113,22 +112,30 @@ void simpleStart() simple = Mallocator.make!Simple; simple.texture.create(); - simple.texture.load("assets/textures/buckler.png"); + simple.texture.load("assets/textures/atlas.png"); launcher.manager.beginRegister(); + registerRenderingModule(launcher.manager); + launcher.manager.registerComponent!CLocation; launcher.manager.registerSystem!MoveSystem(0); - launcher.manager.registerSystem!DrawSystem(1); + // launcher.manager.registerSystem!DrawSystem(1); launcher.manager.endRegister(); + + DrawSystem* draw_system = launcher.manager.getSystem!DrawSystem; + draw_system.default_data.color = 0x80808080; + draw_system.default_data.texture = simple.texture; + draw_system.default_data.size = vec2(16,16); + draw_system.default_data.coords = vec4(0,48,16,16)*px;//vec4(0,0,1,1); - launcher.gui_manager.addSystem(MoveSystem.system_id,"Move System"); + launcher.gui_manager.addSystem(MoveSystem.system_id,"Move Up System"); launcher.gui_manager.addSystem(DrawSystem.system_id,"Draw System"); - ushort[1] components = [CLocation.component_id]; - simple.tmpl = launcher.manager.allocateTemplate(components); + simple.tmpl = launcher.manager.allocateTemplate([CLocation.component_id, CDrawDefault.component_id].staticArray); + //*simple.tmpl.getComponent!CTexCoordsIndex = TexCoordsManager.instance.getCoordIndex(vec4(0,48,16,16)*px); //CLocation* loc_comp = simple.tmpl.getComponent!CLocation; launcher.gui_manager.addTemplate(simple.tmpl, "Basic"); @@ -186,4 +193,14 @@ bool simpleLoop() launcher.manager.end(); return true; +} + +DemoCallbacks getSimpleDemo() +{ + DemoCallbacks demo; + demo.initialize = &simpleStart; + demo.deinitialize = &simpleEnd; + demo.loop = &simpleLoop; + demo.tips = simple.tips; + return demo; } \ No newline at end of file diff --git a/demos/source/demos/snake.d b/demos/source/demos/snake.d index c42f690..8ff0be6 100644 --- a/demos/source/demos/snake.d +++ b/demos/source/demos/snake.d @@ -851,6 +851,8 @@ __gshared Snake* snake; void snakeStart() { + import game_core.rendering; + snake = Mallocator.make!Snake; snake.texture.create(); @@ -860,6 +862,8 @@ void snakeStart() launcher.manager.registerPass("fixed"); + registerRenderingModule(launcher.manager); + launcher.manager.registerComponent!CLocation; launcher.manager.registerComponent!CILocation; launcher.manager.registerComponent!CSnake; @@ -983,4 +987,14 @@ bool snakeLoop() launcher.manager.end(); return true; +} + +DemoCallbacks getSnakeDemo() +{ + DemoCallbacks demo; + demo.initialize = &snakeStart; + demo.deinitialize = &snakeEnd; + demo.loop = &snakeLoop; + demo.tips = snake.tips; + return demo; } \ No newline at end of file diff --git a/demos/source/demos/space_invaders.d b/demos/source/demos/space_invaders.d index 311feb3..b249fc1 100644 --- a/demos/source/demos/space_invaders.d +++ b/demos/source/demos/space_invaders.d @@ -401,8 +401,8 @@ struct CParticleEmitter { mixin ECS.Component; - vec2 range; - vec2 time_range; + vec2 range = vec2(0,0); + vec2 time_range = vec2(500,1000); ///due to multithreading there should be separate template for every thread. ///It can be array of tempaltes or (like in this demo) simply index of template; uint tmpl_id; @@ -829,7 +829,7 @@ struct ShipWeaponSystem void create() { tower1_tmpl = launcher.manager.allocateTemplate( - [CHitMark.component_id, CHitPoints.component_id, CLocation.component_id, + [CColor.component_id, CHitMark.component_id, CHitPoints.component_id, CLocation.component_id, CTexCoords.component_id, CScale.component_id, CEnemy.component_id, CShootGrid.component_id, CGuild.component_id, CInit.component_id, CChildren.component_id, CDepth.component_id, CTargetParent.component_id, @@ -959,7 +959,7 @@ struct MoveToParentTargetSystem } } } - +/* struct DrawSystem { mixin ECS.System!32; @@ -1088,7 +1088,7 @@ struct DrawSystem } //if(data.thread_id == 0)launcher.renderer.pushData(); } -} +}*/ struct CollisionSystem { @@ -1325,7 +1325,7 @@ struct BulletsCollisionSystem uint length; const (Entity)[] entity; @readonly CLocation[] location; - @readonly CBullet[] laser; + @readonly CBullet[] bullet; @readonly CGuild[] guild; } @@ -1336,7 +1336,7 @@ struct BulletsCollisionSystem { if(space_invaders.shoot_grid.test(id, data.location[i], cast(ubyte)(~(1 << data.guild[i].guild)))) { - launcher.manager.sendEvent(id, EBulletHit(data.entity[i].id,1)); + launcher.manager.sendEvent(id, EBulletHit(data.entity[i].id,data.bullet[i].damage)); //launcher.manager.removeEntity(data.entity[i].id); } } @@ -1631,6 +1631,7 @@ struct HitMarkingSystem { uint length; CHitMark[] mark; + CColor[] color; } void onUpdate(EntitiesData data) @@ -1640,6 +1641,7 @@ struct HitMarkingSystem //if(data.mark[i] < 10)data.mark[i] = 0; //else data.mark[i] -= 1; data.mark[i] = cast(ubyte)(data.mark[i] * 0.9); + data.color[i] = 0x80808080 + 0x01010101 * data.mark[i]; } } } @@ -2339,6 +2341,8 @@ void spaceInvadersStart() launcher.manager.registerDependency(ShootGridDependency); + registerRenderingModule(launcher.manager); + launcher.manager.registerComponent!CLocation; launcher.manager.registerComponent!CTexCoords; //launcher.manager.registerComponent!CTexture; @@ -2416,6 +2420,10 @@ void spaceInvadersStart() launcher.manager.endRegister(); + DrawSystem* draw_system = launcher.manager.getSystem!DrawSystem; + draw_system.default_data.color = 0x80808080; + draw_system.default_data.texture = space_invaders.texture; + launcher.gui_manager.addComponent(CInput(),"Input"); launcher.gui_manager.addComponent(CShip(),"Ship"); launcher.gui_manager.addComponent(CEnemy(),"Enemy"); @@ -2482,7 +2490,7 @@ void spaceInvadersStart() //launcher.manager.getSystem(CleanSystem.system_id).disable(); { space_invaders.ship_tmpl = launcher.manager.allocateTemplate( - [CVelocity.component_id, CHitMark.component_id, CHitPoints.component_id, + [CVelocity.component_id, CColor.component_id, CHitMark.component_id, CHitPoints.component_id, CLocation.component_id, CTexCoords.component_id, CInput.component_id, CShip.component_id, CScale.component_id, CColliderScale.component_id, CShootDirection.component_id, CShootGrid.component_id, CGuild.component_id, @@ -2517,7 +2525,7 @@ void spaceInvadersStart() { boss_tmpl = launcher.manager.allocateTemplate( - [CHitMark.component_id, CParts.component_id, CLocation.component_id, + [CColor.component_id, CHitMark.component_id, CParts.component_id, CLocation.component_id, CTexCoords.component_id, CScale.component_id, CEnemy.component_id, CBoss.component_id, CGuild.component_id, CInit.component_id, CChildren.component_id, CSideMove.component_id, CVelocity.component_id, @@ -2540,7 +2548,7 @@ void spaceInvadersStart() { tower_tmpl = launcher.manager.allocateTemplate( - [CHitMark.component_id, CHitPoints.component_id, CLocation.component_id, + [CColor.component_id, CHitMark.component_id, CHitPoints.component_id, CLocation.component_id, CTexCoords.component_id, CScale.component_id, CEnemy.component_id, CShootGrid.component_id, CGuild.component_id, CInit.component_id, CChildren.component_id].staticArray @@ -2554,7 +2562,7 @@ void spaceInvadersStart() { space_invaders.enemy_tmpl = launcher.manager.allocateTemplate( - [CWeaponLocation.component_id, CHitMark.component_id, CHitPoints.component_id, + [CWeaponLocation.component_id, CColor.component_id, CHitMark.component_id, CHitPoints.component_id, CVelocity.component_id, CAutoShoot.component_id, CLocation.component_id, CTexCoords.component_id, CScale.component_id, CWeapon.component_id, CEnemy.component_id, CShootDirection.component_id, CShootGrid.component_id, @@ -2733,4 +2741,14 @@ bool spaceInvadersLoop() }*/ return true; +} + +DemoCallbacks getSpaceInvadersDemo() +{ + DemoCallbacks demo; + demo.initialize = &spaceInvadersStart; + demo.deinitialize = &spaceInvadersEnd; + demo.loop = &spaceInvadersLoop; + demo.tips = space_invaders.tips; + return demo; } \ No newline at end of file diff --git a/demos/source/game_core/rendering.d b/demos/source/game_core/rendering.d index de5f0b5..bee9367 100644 --- a/demos/source/game_core/rendering.d +++ b/demos/source/game_core/rendering.d @@ -1,13 +1,30 @@ module game_core.rendering; -import bubel.ecs.core; import bubel.ecs.attributes; +import bubel.ecs.core; +import bubel.ecs.std; -import ecs_utils.math.vector; import ecs_utils.gfx.texture; +import ecs_utils.math.vector; import game_core.basic; +void registerRenderingModule(EntityManager* manager) +{ + manager.registerComponent!CLocation; + manager.registerComponent!CScale; + manager.registerComponent!CRotation; + manager.registerComponent!CDepth; + manager.registerComponent!CColor; + manager.registerComponent!CSelected; + manager.registerComponent!CTexCoords; + manager.registerComponent!CTexCoordsIndex; + manager.registerComponent!CMaterialIndex; + manager.registerComponent!CDrawDefault; + + manager.registerSystem!DrawSystem(100); +} + struct CTexCoords { mixin ECS.Component; @@ -19,16 +36,63 @@ struct CTexCoords struct CTexCoordsIndex { - mixin ECS.Component; + mixin ECS.Component; + + alias value this; ushort value; } +struct CMaterialIndex +{ + mixin ECS.Component; + + alias value this; + + ushort value; +} + +struct CDrawDefault +{ + mixin ECS.Component; +} + struct TexCoordsManager { import bubel.ecs.vector; import bubel.ecs.hash_map; + __gshared TexCoordsManager* instance = null; + + static void initialize() + { + if(instance is null)instance = Mallocator.make!TexCoordsManager; + } + + static void destroy() + { + if(instance)Mallocator.dispose(instance); + instance = null; + } + + vec4 get(ushort index) + { + if(index > coords.length)return vec4(0,0,1,1); + else return coords[index]; + } + + ushort getCoordIndex(vec4 coords) + { + ushort ret = coords_map.get(coords, ushort.max); + if(ret != ushort.max) + { + return ret; + } + this.coords.add(coords); + coords_map.add(coords, cast(ushort)(this.coords.length - 1)); + return cast(ushort)(this.coords.length - 1); + } + Vector!vec4 coords; HashMap!(vec4,ushort) coords_map; } @@ -44,17 +108,34 @@ struct DrawSystem uint length; //uint thread_id; uint job_id; + const(Entity)[] entity; @readonly CLocation[] locations; - @readonly CScale[] scale; - @readonly CTexCoords[] texcoord; - // @readonly @optional CTexCoords[] texcoord; - // @readonly @optional CTexCoordsIndex[] texcoord_index; + @readonly @optional CScale[] scale; + // @readonly CTexCoords[] texcoord; + @readonly @optional CTexCoords[] texcoord; + @readonly @optional CTexCoordsIndex[] texcoord_index; @readonly @optional CRotation[] rotation; @readonly @optional CDepth[] depth; @readonly @optional CColor[] color; + @readonly @optional CMaterialIndex[] material; + @readonly @optional CDrawDefault[] draw_default; } Renderer.DrawData default_data; + float color_time = 0; + uint select_color = 0; + + bool onBegin() + { + import app : launcher; + color_time += launcher.delta_time * 0.001; + color_time = color_time - cast(int)(color_time*0.5)*2; + float ratio = color_time - cast(int)color_time; + if(color_time > 1)ratio = 1 - ratio; + uint multipler = cast(uint)(0x60 * ratio); + select_color = 0xA0A0A0A0 + cast(uint)(0x01010101 * multipler); + return true; + } void onUpdate(EntitiesData data) { @@ -63,10 +144,368 @@ struct DrawSystem if(launcher.renderer.prepared_items >= launcher.renderer.MaxObjects)return;//simple leave loop if max visible objects count was reached Renderer.DrawData draw_data = default_data; draw_data.thread_id = data.job_id; - - if(!data.depth) + + if(launcher.show_filtered && launcher.filterEntity(data.entity[0])) { - if(!data.color) + draw_data.color = select_color; + data.color = null; + } + //import std.stdio; + //writeln(data.draw_default); + //if(data.draw_default is null && data.texcoord is null && data.texcoord_index is null && !data.entity[0].hasComponent(CDrawDefault.component_id))return; + + if(data.texcoord is null && data.texcoord_index is null && data.draw_default is null)return; + + + foreach(i; 0..data.length) + { + draw_data.position = data.locations[i]; + if(data.color)draw_data.color = data.color[i]; + if(data.depth)draw_data.depth = data.depth[i]; + if(data.rotation)draw_data.angle = data.rotation[i]; + if(data.scale)draw_data.size = data.scale[i]; + if(data.texcoord)draw_data.coords = data.texcoord[i]; + else if(data.texcoord_index)draw_data.coords = TexCoordsManager.instance.get(data.texcoord_index[i]); + if(data.material)draw_data.material_id = data.material[i]; + launcher.renderer.draw(draw_data); + }//*/ + + /* + ubyte mode; + if(data.scale)mode |= 0x01; + if(data.texcoord)mode |= 0x02; + if(data.texcoord_index)mode |= 0x04; + if(data.rotation)mode |= 0x08; + if(data.depth)mode |= 0x10; + if(data.color)mode |= 0x20; + + if(launcher.show_filtered && launcher.filterEntity(data.entity[0])) + { + draw_data.color = select_color; + mode &= ~0x20; + //goto draw_nocolor; + } + + switch(mode) + { + case 0: + foreach(i; 0..data.length) + { + draw_data.position = data.locations[i]; + launcher.renderer.draw(draw_data); + } + break; + + case 0b000001: + foreach(i; 0..data.length) + { + draw_data.position = data.locations[i]; + draw_data.size = data.scale[i]; + launcher.renderer.draw(draw_data); + } + break; + + case 0b000010: + foreach(i; 0..data.length) + { + draw_data.position = data.locations[i]; + draw_data.coords = data.texcoord[i]; + launcher.renderer.draw(draw_data); + } + break; + case 0b000011: + foreach(i; 0..data.length) + { + draw_data.position = data.locations[i]; + draw_data.size = data.scale[i]; + draw_data.coords = data.texcoord[i]; + launcher.renderer.draw(draw_data); + } + break; + + case 0b001000: + foreach(i; 0..data.length) + { + draw_data.position = data.locations[i]; + draw_data.angle = data.rotation[i]; + launcher.renderer.draw(draw_data); + } + break; + case 0b001001: + foreach(i; 0..data.length) + { + draw_data.position = data.locations[i]; + draw_data.angle = data.rotation[i]; + draw_data.size = data.scale[i]; + launcher.renderer.draw(draw_data); + } + break; + case 0b001010: + foreach(i; 0..data.length) + { + draw_data.position = data.locations[i]; + draw_data.angle = data.rotation[i]; + draw_data.coords = data.texcoord[i]; + launcher.renderer.draw(draw_data); + } + break; + case 0b001011: + foreach(i; 0..data.length) + { + draw_data.position = data.locations[i]; + draw_data.angle = data.rotation[i]; + draw_data.size = data.scale[i]; + draw_data.coords = data.texcoord[i]; + launcher.renderer.draw(draw_data); + } + break; + + + case 0b010000: + foreach(i; 0..data.length) + { + draw_data.position = data.locations[i]; + draw_data.depth = data.depth[i]; + launcher.renderer.draw(draw_data); + } + break; + case 0b010001: + foreach(i; 0..data.length) + { + draw_data.position = data.locations[i]; + draw_data.depth = data.depth[i]; + draw_data.size = data.scale[i]; + launcher.renderer.draw(draw_data); + } + break; + case 0b010010: + foreach(i; 0..data.length) + { + draw_data.position = data.locations[i]; + draw_data.depth = data.depth[i]; + draw_data.coords = data.texcoord[i]; + launcher.renderer.draw(draw_data); + } + break; + case 0b010011: + foreach(i; 0..data.length) + { + draw_data.position = data.locations[i]; + draw_data.depth = data.depth[i]; + draw_data.size = data.scale[i]; + draw_data.coords = data.texcoord[i]; + launcher.renderer.draw(draw_data); + } + break; + case 0b011000: + foreach(i; 0..data.length) + { + draw_data.position = data.locations[i]; + draw_data.depth = data.depth[i]; + draw_data.angle = data.rotation[i]; + launcher.renderer.draw(draw_data); + } + break; + case 0b011001: + foreach(i; 0..data.length) + { + draw_data.position = data.locations[i]; + draw_data.depth = data.depth[i]; + draw_data.angle = data.rotation[i]; + draw_data.size = data.scale[i]; + launcher.renderer.draw(draw_data); + } + break; + case 0b011010: + foreach(i; 0..data.length) + { + draw_data.position = data.locations[i]; + draw_data.depth = data.depth[i]; + draw_data.angle = data.rotation[i]; + draw_data.coords = data.texcoord[i]; + launcher.renderer.draw(draw_data); + } + break; + case 0b011011: + foreach(i; 0..data.length) + { + draw_data.position = data.locations[i]; + draw_data.depth = data.depth[i]; + draw_data.angle = data.rotation[i]; + draw_data.size = data.scale[i]; + draw_data.coords = data.texcoord[i]; + launcher.renderer.draw(draw_data); + } + break; + + + case 0b100000: + foreach(i; 0..data.length) + { + draw_data.position = data.locations[i]; + draw_data.color = data.color[i]; + launcher.renderer.draw(draw_data); + } + break; + case 0b100001: + foreach(i; 0..data.length) + { + draw_data.position = data.locations[i]; + draw_data.color = data.color[i]; + draw_data.size = data.scale[i]; + launcher.renderer.draw(draw_data); + } + break; + case 0b100010: + foreach(i; 0..data.length) + { + draw_data.position = data.locations[i]; + draw_data.color = data.color[i]; + draw_data.coords = data.texcoord[i]; + launcher.renderer.draw(draw_data); + } + break; + case 0b100011: + foreach(i; 0..data.length) + { + draw_data.position = data.locations[i]; + draw_data.color = data.color[i]; + draw_data.size = data.scale[i]; + draw_data.coords = data.texcoord[i]; + launcher.renderer.draw(draw_data); + } + break; + case 0b101000: + foreach(i; 0..data.length) + { + draw_data.position = data.locations[i]; + draw_data.color = data.color[i]; + draw_data.angle = data.rotation[i]; + launcher.renderer.draw(draw_data); + } + break; + case 0b101001: + foreach(i; 0..data.length) + { + draw_data.position = data.locations[i]; + draw_data.color = data.color[i]; + draw_data.angle = data.rotation[i]; + draw_data.size = data.scale[i]; + launcher.renderer.draw(draw_data); + } + break; + case 0b101010: + foreach(i; 0..data.length) + { + draw_data.position = data.locations[i]; + draw_data.color = data.color[i]; + draw_data.angle = data.rotation[i]; + draw_data.coords = data.texcoord[i]; + launcher.renderer.draw(draw_data); + } + break; + case 0b101011: + foreach(i; 0..data.length) + { + draw_data.position = data.locations[i]; + draw_data.color = data.color[i]; + draw_data.angle = data.rotation[i]; + draw_data.size = data.scale[i]; + draw_data.coords = data.texcoord[i]; + launcher.renderer.draw(draw_data); + } + break; + case 0b110000: + foreach(i; 0..data.length) + { + draw_data.position = data.locations[i]; + draw_data.color = data.color[i]; + draw_data.depth = data.depth[i]; + launcher.renderer.draw(draw_data); + } + break; + case 0b110001: + foreach(i; 0..data.length) + { + draw_data.position = data.locations[i]; + draw_data.color = data.color[i]; + draw_data.depth = data.depth[i]; + draw_data.size = data.scale[i]; + launcher.renderer.draw(draw_data); + } + break; + case 0b110010: + foreach(i; 0..data.length) + { + draw_data.position = data.locations[i]; + draw_data.color = data.color[i]; + draw_data.depth = data.depth[i]; + draw_data.coords = data.texcoord[i]; + launcher.renderer.draw(draw_data); + } + break; + case 0b110011: + foreach(i; 0..data.length) + { + draw_data.position = data.locations[i]; + draw_data.color = data.color[i]; + draw_data.depth = data.depth[i]; + draw_data.size = data.scale[i]; + draw_data.coords = data.texcoord[i]; + launcher.renderer.draw(draw_data); + } + break; + case 0b111000: + foreach(i; 0..data.length) + { + draw_data.position = data.locations[i]; + draw_data.color = data.color[i]; + draw_data.depth = data.depth[i]; + draw_data.angle = data.rotation[i]; + launcher.renderer.draw(draw_data); + } + break; + case 0b111001: + foreach(i; 0..data.length) + { + draw_data.position = data.locations[i]; + draw_data.color = data.color[i]; + draw_data.depth = data.depth[i]; + draw_data.angle = data.rotation[i]; + draw_data.size = data.scale[i]; + launcher.renderer.draw(draw_data); + } + break; + case 0b111010: + foreach(i; 0..data.length) + { + draw_data.position = data.locations[i]; + draw_data.color = data.color[i]; + draw_data.depth = data.depth[i]; + draw_data.angle = data.rotation[i]; + draw_data.coords = data.texcoord[i]; + launcher.renderer.draw(draw_data); + } + break; + case 0b111011: + foreach(i; 0..data.length) + { + draw_data.position = data.locations[i]; + draw_data.color = data.color[i]; + draw_data.depth = data.depth[i]; + draw_data.angle = data.rotation[i]; + draw_data.size = data.scale[i]; + draw_data.coords = data.texcoord[i]; + launcher.renderer.draw(draw_data); + } + break; + default:break; + }//*/ +/* + if(!data.color) + { + draw_nocolor: + if(!data.depth) { if(!data.rotation) { @@ -96,7 +535,7 @@ struct DrawSystem { foreach(i; 0..data.length) { - draw_data.color = data.color[i]; + draw_data.depth = data.depth[i]; draw_data.coords = data.texcoord[i]; draw_data.size = data.scale[i]; draw_data.position = data.locations[i]; @@ -107,7 +546,7 @@ struct DrawSystem { foreach(i; 0..data.length) { - draw_data.color = data.color[i]; + draw_data.depth = data.depth[i]; draw_data.angle = data.rotation[i]; draw_data.coords = data.texcoord[i]; draw_data.size = data.scale[i]; @@ -119,13 +558,13 @@ struct DrawSystem } else { - if(!data.color) + if(!data.depth) { if(!data.rotation) { foreach(i; 0..data.length) { - draw_data.depth = data.depth[i]; + draw_data.color = data.color[i]; draw_data.coords = data.texcoord[i]; draw_data.size = data.scale[i]; draw_data.position = data.locations[i]; @@ -136,7 +575,7 @@ struct DrawSystem { foreach(i; 0..data.length) { - draw_data.depth = data.depth[i]; + draw_data.color = data.color[i]; draw_data.angle = data.rotation[i]; draw_data.coords = data.texcoord[i]; draw_data.size = data.scale[i]; @@ -165,7 +604,6 @@ struct DrawSystem { draw_data.depth = data.depth[i]; draw_data.color = data.color[i]; - draw_data.angle = data.rotation[i]; draw_data.coords = data.texcoord[i]; draw_data.size = data.scale[i]; draw_data.position = data.locations[i]; @@ -173,6 +611,6 @@ struct DrawSystem } } } - } + }*/ } } \ No newline at end of file diff --git a/demos/source/gui/component.d b/demos/source/gui/component.d index b19f069..e65dee4 100644 --- a/demos/source/gui/component.d +++ b/demos/source/gui/component.d @@ -47,7 +47,9 @@ struct VariableGUI enum_, color, vec2, - ivec2 + ivec2, + vec4, + ivec4 } Type type; const (char)* name; diff --git a/demos/source/gui/manager.d b/demos/source/gui/manager.d index 3f6e6cb..3745d9d 100644 --- a/demos/source/gui/manager.d +++ b/demos/source/gui/manager.d @@ -93,9 +93,13 @@ struct GUIManager void addSystem(ushort id, const (char)* name, bool enabled = true) { + foreach(ref sys; systems) + { + if(sys.id == id)return; + } System* system = launcher.manager.getSystem(id); //const (char)* name = - systems.add(SystemGUI(name,system,enabled)); + systems.add(SystemGUI(name,id,enabled)); } void addTemplate(ushort[] components, const (char)* name) @@ -143,7 +147,23 @@ struct GUIManager //pragma(msg,member_type); //pragma(msg,__traits(getMember, T, member).offsetof); ushort offset = member.offsetof;//cast(ushort)__traits(getMember, T, member).offsetof; - static if(__traits(isIntegral,member_type)) + static if(is(member_type == vec2)) + { + comp_edit.variables[comp_edit.used++] = VariableGUI(VariableGUI.Type.vec2,member_str,offset); + } + else static if(is(member_type == ivec2)) + { + comp_edit.variables[comp_edit.used++] = VariableGUI(VariableGUI.Type.ivec2,member_str,offset); + } + else static if(is(member_type == vec4)) + { + comp_edit.variables[comp_edit.used++] = VariableGUI(VariableGUI.Type.vec4,member_str,offset); + } + else static if(is(member_type == ivec4)) + { + comp_edit.variables[comp_edit.used++] = VariableGUI(VariableGUI.Type.ivec4,member_str,offset); + } + else static if(__traits(isIntegral,member_type)) { static if(__traits(isUnsigned, member_type)) { @@ -227,14 +247,15 @@ struct GUIManager { if(igCollapsingHeader("Systems", ImGuiTreeNodeFlags_SpanFullWidth | ImGuiTreeNodeFlags_DefaultOpen)) { - bool true_ = true; + //bool true_ = true; igIndent(8); foreach(ref SystemGUI system;systems) { if(igCheckbox(system.name,&system.enabled)) { - if(system.enabled)system.system.enable(); - else system.system.disable(); + System* sys = launcher.manager.getSystem(system.id); + if(system.enabled)sys.enable(); + else sys.disable(); } } igUnindent(8); @@ -347,6 +368,18 @@ struct GUIManager if(igColorEdit4(var.name, color.data, ImGuiColorEditFlags_None)) *cast(uint*)(data_ptr+var.offset) = colorVec4ToUint(color); break; + case VariableGUI.Type.vec2: + igDragFloat2(var.name, (cast(float*)(data_ptr+var.offset))[0..2], 0.1, -float.max, float.max, null, 1); + break; + case VariableGUI.Type.ivec2: + igDragInt2(var.name, (cast(int*)(data_ptr+var.offset))[0..2], 0.1, int.min, int.max, null); + break; + case VariableGUI.Type.vec4: + igDragFloat4(var.name, (cast(float*)(data_ptr+var.offset))[0..4], 0.1, -float.max, float.max, null, 1); + break; + case VariableGUI.Type.ivec4: + igDragInt4(var.name, (cast(int*)(data_ptr+var.offset))[0..4], 0.1, int.min, int.max, null); + break; default:break; } igPopID(); @@ -359,6 +392,7 @@ struct GUIManager void entityComponentsGUI() { + if(selected_template >= templates.length)return; EntityTemplate* tmpl = templates[selected_template].tmpl; EntityManager.EntityInfo* info = tmpl.info; foreach(comp_id; info.components) @@ -416,7 +450,7 @@ struct GUIManager if(igIsItemHovered(0))igSetTooltip("Select component to add/remove (SHIFT + Scroll)"); } style.Colors[ImGuiCol_Header] = col; - componentGUI(components[selected_component].component_id, components[selected_component].data); + if(selected_component < components.length)componentGUI(components[selected_component].component_id, components[selected_component].data); break; case Tool.selector: break; From a0efa4e67d0df98bfbbba48fcf857b6bb1f4b78e Mon Sep 17 00:00:00 2001 From: Mergul Date: Wed, 8 Jul 2020 22:04:13 +0200 Subject: [PATCH 163/217] Fixed unittests and betterC compilation (after adding fullyQualifiedName instead of simple stringof) -added new trait to get full name of structure (witho module and package, not tested on more nested packages) -some small improvements (like adding const to function which need it) --- dub.json | 3 ++- source/bubel/ecs/entity.d | 6 +++--- source/bubel/ecs/manager.d | 23 ++++++++++++++--------- source/bubel/ecs/traits.d | 32 ++++++++++++++++++++++++++++++++ tests/basic.d | 4 ++-- 5 files changed, 53 insertions(+), 15 deletions(-) diff --git a/dub.json b/dub.json index 01cf85c..ba935ee 100755 --- a/dub.json +++ b/dub.json @@ -118,7 +118,8 @@ "-unittest" ], "dflags-gdc": [ - "-fno-druntime" + "-fno-druntime", + "-lpthread" ], "sourcePaths": ["source/","tests/"], "mainSourceFile":"tests/runner.d", diff --git a/source/bubel/ecs/entity.d b/source/bubel/ecs/entity.d index 2c64c60..4cd0e70 100644 --- a/source/bubel/ecs/entity.d +++ b/source/bubel/ecs/entity.d @@ -42,7 +42,7 @@ struct Entity return cast(T*)(cast(void*)block + info.deltas[T.component_id] + block.entityIndex(&this) * T.sizeof); } - bool hasComponent(ushort component_id) + bool hasComponent(ushort component_id) const { EntityManager.EntitiesBlock* block = gEM.getMetaData(&this); EntityManager.EntityInfo* info = block.type_info; @@ -72,9 +72,9 @@ struct EntityMeta return cast(T*)(cast(void*)block + block.type_info.deltas[T.component_id] + index * T.sizeof); } - bool hasComponent(ushort component_id) + bool hasComponent(ushort component_id) const { - EntityManager.EntityInfo* info = block.type_info; + const EntityManager.EntityInfo* info = block.type_info; if (component_id >= info.deltas.length || info.deltas[component_id] == 0)return false; return true; } diff --git a/source/bubel/ecs/manager.d b/source/bubel/ecs/manager.d index cce03c6..7fb79f8 100644 --- a/source/bubel/ecs/manager.d +++ b/source/bubel/ecs/manager.d @@ -382,7 +382,8 @@ export struct EntityManager else assert(pass < passes.length, "Update pass (ID " ~ pass.to!string ~ ") doesn't exist."); - enum SystemName = fullyQualifiedName!Sys; + // enum SystemName = fullyQualifiedName!Sys; + enum SystemName = fullName!Sys; //enum SystemName = Sys.stringof; System system; @@ -421,7 +422,8 @@ export struct EntityManager static if (Params.length == 2 && is(Params[0] == Entity*)) { alias EventParamType = Params[1]; - enum EventName = fullyQualifiedName!(Unqual!(EventParamType));//.stringof; + enum EventName = fullName!(Unqual!(EventParamType)); + // enum EventName = fullyQualifiedName!(Unqual!(EventParamType));//.stringof; ushort evt = events_map.get(cast(char[]) EventName, ushort.max); assert(evt != ushort.max, "Can't register system \"" ~ SystemName ~ "\" due to non existing event \"" ~ EventName ~ "\"."); @@ -482,7 +484,8 @@ export struct EntityManager string name; static if (isArray!MemberType) { // Workaround. This code is never called with: not an array type, but compiler prints an error - name = fullyQualifiedName!(Unqual!(ForeachType!MemberType));//.stringof; + // name = fullyQualifiedName!(Unqual!(ForeachType!MemberType));//.stringof; + name = fullName!(Unqual!(ForeachType!MemberType)); } bool is_optional; @@ -707,7 +710,8 @@ export struct EntityManager string name; static if (isArray!MemberType) { // Workaround. This code is never called with: not an array type, but compiler prints an error - name = fullyQualifiedName!(Unqual!(ForeachType!MemberType)); + // name = fullyQualifiedName!(Unqual!(ForeachType!MemberType)); + name = fullName!(Unqual!(ForeachType!MemberType)); //name = Unqual!(ForeachType!MemberType).stringof; } @@ -763,7 +767,7 @@ export struct EntityManager { foreach (str; Sys.ExcludedComponents) { - components_info.addExcluded(CompInfo(str.stringof, fullyQualifiedName!str)); + components_info.addExcluded(CompInfo(str.stringof, fullName!str)); // components_info.addExcluded(CompInfo(str.stringof, str.stringof)); } @@ -1259,8 +1263,9 @@ export struct EntityManager { ComponentInfo info; - enum ComponentName = fullyQualifiedName!Comp; - //enum ComponentName = Comp.stringof; + // enum ComponentName = fullyQualifiedName!Comp; + enum ComponentName = fullName!Comp; + // enum ComponentName = Comp.stringof; static if (!(hasMember!(Comp, "component_id")) || !is(typeof(Comp.component_id) == ushort)) { @@ -1337,7 +1342,7 @@ export struct EntityManager info.alignment = Ev.alignof; //ushort event_id = events_map.get(Ev.stringof, ushort.max); - ushort event_id = events_map.get(fullyQualifiedName!Ev, ushort.max); + ushort event_id = events_map.get(fullName!Ev, ushort.max); if (event_id < events.length) { Ev.event_id = event_id; @@ -1347,7 +1352,7 @@ export struct EntityManager events.add(info); Ev.event_id = cast(ushort)(events.length - 1); // events_map.add(Ev.stringof, cast(ushort)(events.length - 1)); - events_map.add(fullyQualifiedName!Ev, cast(ushort)(events.length - 1)); + events_map.add(fullName!Ev, cast(ushort)(events.length - 1)); } } diff --git a/source/bubel/ecs/traits.d b/source/bubel/ecs/traits.d index 7043b2e..8214b01 100644 --- a/source/bubel/ecs/traits.d +++ b/source/bubel/ecs/traits.d @@ -37,3 +37,35 @@ static long getIndexOfTypeInEntitiesData(EntitiesData, Type)() } return index; } + +static string attachParentName(alias T, string str)() +{ + alias parent = __traits(parent, T); + enum parent_str = parent.stringof; + static if(parent_str[0..7] == "module ") + { + static if(__traits(compiles, __traits(parent, parent))) + { + return attachParentName!(parent, parent_str[7 .. $] ~ '.' ~ str); + } + else return parent_str[8 .. $] ~ '.' ~ str; + } + else static if(parent_str[0..8] == "package ") + { + static if(__traits(compiles, __traits(parent, parent))) + { + return attachParentName!(parent, parent_str[8 .. $] ~ '.' ~ str); + } + else return parent_str[8 .. $] ~ '.' ~ str; + } + else static if(__traits(compiles, __traits(parent, parent))) + { + return attachParentName!(parent, parent_str ~ '.' ~ str); + } + else return parent_str ~ '.' ~ str; +} + +static string fullName(T)() +{ + return attachParentName!(T, T.stringof); +} \ No newline at end of file diff --git a/tests/basic.d b/tests/basic.d index 5830a7b..59f88e2 100644 --- a/tests/basic.d +++ b/tests/basic.d @@ -401,7 +401,7 @@ unittest System* ecs_system = gEM.getSystem(EmptySystem.system_id); assert(ecs_system !is null); assert(ecs_system.id == EmptySystem.system_id); - assert(ecs_system.name == "EmptySystem"); + assert(ecs_system.name == "tests.basic.EmptySystem"); gEM.begin(); @@ -605,7 +605,7 @@ unittest assert(ecs_system !is null); assert(ecs_system.id == LongAddSystem.system_id); assert(ecs_system.priority == -1); - assert(ecs_system.name == "LongAddSystem"); + assert(ecs_system.name == "tests.basic.LongAddSystem"); ushort[1] ids = [CLong.component_id]; EntityTemplate* tmpl = gEM.allocateTemplate(ids); From 74179b4fc8e0f5a9b8276b9b2b4575b189495bd7 Mon Sep 17 00:00:00 2001 From: Mergul Date: Wed, 8 Jul 2020 22:09:10 +0200 Subject: [PATCH 164/217] Demo update -added 'dot' function to vector math -fixed Circle tool rendering -fixed some potentiall memory leaks -added 'collision' module which now separates ShootGrid from SpaceInvaders demo -separate some systems from demos to 'basic' module to better demos functionality sharing -slow down snake -added new graphics -BrickBreaker demo now works (without blocks breaking and with bugged collision detection) -some bug fixes --- demos/assets/textures/atlas.png | Bin 42614 -> 37325 bytes demos/source/app.d | 12 +- demos/source/demos/brick_breaker.d | 284 +++++++++++-- demos/source/demos/particles.d | 118 +++--- demos/source/demos/sandbox.d | 16 +- demos/source/demos/simple.d | 8 +- demos/source/demos/snake.d | 18 +- demos/source/demos/space_invaders.d | 444 ++++----------------- demos/source/game_core/basic.d | 196 +++++++++ demos/source/game_core/collision.d | 232 +++++++++++ demos/source/gui/manager.d | 2 +- demos/source/gui/system.d | 3 +- demos/source/gui/tool_circle.d | 1 + demos/utils/source/ecs_utils/math/vector.d | 5 + 14 files changed, 871 insertions(+), 468 deletions(-) create mode 100644 demos/source/game_core/collision.d diff --git a/demos/assets/textures/atlas.png b/demos/assets/textures/atlas.png index eea925e600dde7ea3133047620c037882fdd4b2c..b84c3fac2893e8d6d59cc78ebf30536c964665ab 100644 GIT binary patch literal 37325 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%0DFoV*h>^r~oo%I8wK z_cepIp3HX_Hqui?)V@&4@t=#2=2?0^;Ogp8TI`*T+}%SYFkWYFxp@ZOc%I%oYbfJ=#?!4t&_x zOhR90fe$j-Nw2H+X^l9_7^{%${<&m+awpCuGcRZ6-?kpl;MM@wxA*YKA$>A z7M+FfHxW#CHIV&ZryTh{lMR5auTyVrZ-1UE*Q#8Gl6=1ox>Y38mZ!$LZYXOZuIliK zLV$5(zm1gNZ9DYjMFqx*i#AORv+ei0JM=JDX?B&^S|ra;>)AsoEUZl51L>;m#Xl+1n6F*~?5Yc`!FBldqOL z;hcCZi>9Ij1z%#&Q)jEC;J4WH$1ZLxmTa^mAv*Oo_&(eCAFYnTiqb%T5;kCKnNl5e zYnuk-z&HL}N@VO4Zoq!6`eI{(y*W642H{5n`Gd+szb$G$d3r*4A`xVM5?5${H~k~x z&^rIeu`^!l0VfncrU&Q5w+Jp2;{*v{eYrQ*d`f(taAjk~+F4z7_Chb%eoTRW`N@{; z@ch)mkwTwM*rBr9rv6lRpNb-J@iF6o;qPY0_X2%wthh}&6e_d_hW~{?jRskj@0z27 zqFD|$|G*GrgF_jX$RVz4G~Og6RBkcWo#E18v+of=p(1k;rB-M zDY3UT@UXPUXbWx!f20>~Q^}b4ZlyqXA?-DP$%#DNuJ?Ds$TYAx568&>)5Kf`M~v{! zoAqjJuMn)1TrYM-IU(GK=!N9kphwH`%HUVJUY|Yy`1r|-p5!{~PB0u12Rry`)iV)n z4+EoKCps42=Q(J5s0Ja>W4}Q zjA+h#oSGcDhLfvny_EQ$8))$gCTsd;=5OAcrBSZTb@x^^qY>eE|Ni}(I-%H*7s|Yb zH*q9YPS=QO^tiEV!Tt{}>O$XFY5`Qk0;}zf@i`f#_}0UuUt$mgJAv8$}8qD-C$U_ePkJHy6@o!U>@$dUB7>4IPXZ; zJB{zOUGN&T^DXE`b%1z_RaiDpjd4cGXFBsf*dbJpWtFs4Hp(x5)}}e3n}BlGe@`M8 zfBMGnc^HlO?CSba^yS9W^0Z0Rpq~ONug0zy%DAukfeJ*m{e*kb`Gz+tG^FT#04EBk z&?54pjTa3^Nbb#Ak!BrH`l92bFE1fNsaqFeSQjCYxV0LFa?TMOxAb(KhGT*ni!u@$ZVu+R|@MY1Le3U=$sl=j)!cWlFup8@7zsH+nS7fr$N zEV4U#a`)5sy0v|*czARfapfZGUd}J|5+9zUfAnD;ysqif-*gPV>=nzRA}7&EtkuqV z&eT!$tKqL?|BeT1Zum{8@WAkNnZ^*V4vtW$-3&WLEpntd(#@3i%1a}GMem#Ul^x2z zSz*6B8gN>3TM{3fP86=xLKpd7VtjB*Kp4>KKrfaZwkX6qTj`EwIK|!FPnastXnLVL zfiW){A9O%#Gr^ytN#0_at#iJuCW;1t;&Q|{!7F%~^E(AY!G`XZjZ6K0i^tkWwkG`3 z78mR8aFMn|oN(#8H}!lp^JmXwZf0q`Z7;)_-{OSPTr#t7soMI z%)KfW3w!!4BGx?#$SK*AP)e33VRU3v(;~ls>p1xx|0WK|X=~Sv4NTPmHT03FR+=$6 zRU@7MQPmaBBWm=jZ(nyu;w@&WGexH-g`edrFv%O|R9W`ja4O`*Sif55=M7usY1dz2 z07lOJ14Ogj(dj69gEKC4s{Nz$6k59c!+JvG)9Yv8J#exS>-z6ja!YcAENv>IM>gRJ zvafMbl7~d)Q*1S!p5P>>5y_~M~@PX>` zdQM`mNYU$1B7gv=h3swQXvO*c%zh)QHL}Dahe*FyVa1P9v2JnEaYOCES^{=Ts^5}8 z%-4!7m(~K6=Oz1(o-e?ER{v1Z(51N-`o|(*#yX)Lnz3^pxwBs22!uw8DpySK_6_`c zUqwrm5#f33-;mE6d2O(TXd!4*bK30=qSs|E)~rWbAwP zC(T8l_8KOC9z}%*JFnmB@N5{vk)x&5r*>E^o{Q94NmS%GKCixNP~s`e())yq{bvRp z$RhD^&}Dz6#!AuCaYz-p846UJdL?f?DSA*q=PLQnyxYqyKoIUndBhicWBu^PzgCk% z2=Qx0x~|nK0dX_pE!XMeo0QS3p!3^ZZ7P}Px!H%3G%_%Z5)l#v{KUo(hJ!NF!<$Ni zfwR3ZLl3vYhP9>UMYnnoN68`* zpHy57_5Z?qlTmZ2czLNLbAEgb7O3g1Z?0&Vm!-geQ>AG(w|(q1sZwdkeQm(#`trrP z>u)_XAs4>Jp(A(w>Hk(DnjZR+yna^;_7CN}$_vt9xT1^aRGfh@kksP=5p-kf=^DWF|I7hb_NItA0fhL@1%1EJ)YD9ZKGFHSEtR+Hv_Kmq z%q4R7w$cDkEas>&1O=z<#Wy;a%XOFC;fsRek{%oV<+bxqF~9rF?1GJWT(lS|PClI2 zdot_m?#+)piF(5-O2+?vNh}Q-YKPnU2)DI>idC7P=S|VsNA`4|?0V)x;CG{Ei7lrj zP3HJ3mlrb>gE9r}CbGt6jyWkM#bS;EaA?2M4)K1(OGHK%ovjCBQ-#{M;4F>7IxdSi zYN|T!%Qs?;m59}URObPsA1k{~3|p(Ons;TMaut+rh5lf*CS}K+6%85Ns^_JwN78Xk z5g~q*TuTqQWWwJc?RGF3Y^%~cUCl!MVaiMPCqp~)i@r#o*J$e3onebt1!HITK@?d% z|9N^^z0$BXB^NpFReARp#sFtIzN|QTW_fkEc_gMEHDtnG@l!4*&2YdFZ;=G2%a9Kw zOwJr@w0yq&?4^`mmpm@y$Ay_2kUO1v?cR~TtfBfL90J2qF5zCM?AdmiqI{$SKRpi+ zkam8h@L7;>s9~L*H_7w+(&HuDi;;K7cugq~Mc6B2_c(YMwfJl*35nd9(5OR#P_ zHyXDi0@F6eN-ssrt4{Lh4_o0H?^b_uaII7ibS~m=USt=|i0HzZM89{Yra_62rvzc) zg!0ifSkKU>;0*UsU23lSzxK9QJvY(G95;(K5CgUvdYMxKBlr3fKm3bbXLNWfq zXW668R)rLpAYGp>VstU;T1*|h|Jqz*1AUEGN8LN(S@pF>uG!SDnk#zdMU(!Ra^=qB zKap8P12Y|g03|cS4$BG_UPJ%)TYx%bp!$j-l?o?17@26zXVnJ}ID2gm*J{E?3Ew%k z-86bSPJnKo{678Wu3ZIDLpxV7E8@H3X=Nw5$-1sqmtYJ~pO-XWkJs+XseQNF z`ucjk-`ba^Go>6quX{*5G;!ksUWvhRAJIS#X%rV`B7fZCyMMSpn~!r2k~}LmhW50q_IuWYmx0%v$>To% zmqLIyX**GitcI-cUX zIq<&wR$Pm3^ZiI9na*pT&IRe;A^={A+5T@_@O+TcIG~nn{5KLTMSRUir6U>+31iK; zvz`Ar)&WVxdq-BM^_t!8PfIdFQ*z@aNp?h7PYCJ$?CUDEX+JG28u6j{ZK&#|Q~1*- z9tgNp(kCVFYsH^`tZG9Jgo6tU3S9iRE(^eJUh0)nf(+RSU1#c7%|L7Sr*>RNd^#ECT1{DMYr=lpt|JdE}(6qfi?rrywJ(Vw+dD40+vf}q}T;4Zs)~JF| z^wv}QLL0kZVzss11a1^6 zOd=Gcoj&_Oz>c0Ag}fz6>XLHdE2dS++D+h_%Mz?nxa=Bo&XwvPJFoTJ!DU{ErYBwuUC7SI@>@T+RLYh~b4}B80}U zQ~Kop#=k=bUkSPFC;U*Zz5kzo@4TRti=zHk5=DX$z{IC+1#u!`YD(+*nU1ZV2;R!& zEm2Z~^7{^V$yB4?@AYL50(@#RUvY%nT^-w!cIEPAUA+oa?2yGH;EX-VUj9RNXefXu z%Y-=DW*bZPN=h)6=K1}iNU_GBGVBdXYqVH0%8zb;AIMu)5<;{)u~LbV{AE3-iuqhA zA>(5i5w2u$Zc}c37glMk-MPa=yGMj4Un{QR4&18)XV&Pzt0v@XqWIO=x0e4OVa~#n zdclVVbacid?ub^xmlyFoZq-1fZ9MC|T#f8xLQ}`upM_M?Ql6ud)qC3@gh+SdtPT|{1#wl_ap?S^g> zNS>*P-@l@M^F@v`l6t|UPPn-!v(2Ctvjx$Ss;E~r(hNI}eW$|Lo%`jnGNs-8TA;@K zr8C^>=77ouXHH;^jY7X@uGu?WZ+bd(`D~Onk_vuz?P5xd-t!t&JRCmuj`>H$Iuj)^ zWaAjs<;Ap(=cjS5M7C+K0HUeilVa~p=Dc#|>A+bX3uVQ=KJi@&fBEw5(l6Kh)f6@I z`Q*kN!1dnn`M!QUDjr7Nx-L`e(}d-KV(r?~Ow;;4=|gTiy~)?9QpMGNU!9{$rB zG;vKLG(EH)k5Z{pqD+-NuWC`d(0VLJ*Q*r* zeoyEe-_wIg=ZmRt9yd1F-BJL5Q={=XjoDPeADbiC!o{sWR`hTo2M*6?Y>!z+JHF9i z$5Mv(Qq(q5+5XBWNfCg&JJFO$WV+!*^f!ZHaxU$f=WW8%I8Q5Bx;rnF-kPGk8PZA+j067in+ zU)r-)#4~I(>YzL}6Tuk%J!8YG%bHeqbEPpmJMCQ=l!{U0gT(WZ1kAHk%%?~p73cQt zi#CH-S-CdA^4+1zHM;rBK{4bJ)GIvD>lTal=76byg3G>MC+rNBO%?AofiOw4O+KPd z=lK?V-bQXZb-CMn@_SayOT?Gzxr~;x+q!%BJee8y18~<}OzasN6|-|ZU)Luuq*)ff z$Iyhk{A|H8rHP$s9*hv?7Lktgble%q$y$3kAnf!M$-(hl8a!uZfv!pBo;HtPl*w7@ z0t!8kG{aU2F~Il{r7WQHoZ@W8II?{CW(xGhJ+;03*>TIbwlC71SrU%3zTX9?DkXm2 z-x$iCpE5t!4{ZV=y6gfQe%D{p!8wei-PZSF`qOZGe39Z6Brfi3GncfTmMP}yiPG2r zqjR=egcL`kvDoPQ$jpXQ3A7(w8rw!`?{*oLue6bFB=sTS<<-kSCXkqPZ!KEP5h9xb z9$)uJ6<%e(UNM81D=|*&H*w0m_{#{9l$3n&7ve1fqaD(psqNRzmBV7Ha&v|>zU5m~GSQa*E%(}e*}lH^6b7P^(O;a4N&t)o zpS5iF!0Wqb&$wHNU|#!6RRa3punhbSr<%1{^q?Z25VZR%+9InL@o4#e=vk2#QIvAS z?i6p*!DLuw?oafnHa$Rb6tx&`{KPIJBZCr#LhmsW{l-gO6fo`{?^}t(Wy#gnpF0pt z(Xc3JitD$)_Zek&u9lL-S8RYmT1P>q|P+4A3rCLMf+FjY*093K-Q> zO!W0N+Lz$ff11N(I*`}~X+2r*PRjq7Mm2yFiAnXgi zuuBa#*{1Bq#?Gr*Wv4Rn#%Oe4YpMIO;7dr91dbF{{@H`Wf(uX~PlTk!Y(Vd1pqbCC zGAXJ*>@n|5a`KaAs?Q3p>a&H+HWFodgx;Rz^7E}X+M1W4RZO+44+$*H6u`9JfkBIF z1dS{csx+6+!LkkXc;wf8GOZE!U3qf2tdB%gz%PkNA{A2T<*n`T{XhA;E^*CDANo+# zKuD0xN10!9&r7P9MLiuh#_92C@mFqa1k1kdIl{B5iwkZVymV0-9HY?#0x+)b)i!3F zcv2{JJig5TASd##%GN3{KJ@%)2y+Omt__Dy^rD1+6-(Y6^^mfLNY=4@2uwz6O z?f%}-@zS=mu#~;kVOXP5MO-V+zVWukhN7Gsk)JH;caRD->HA(xg%|3L#by&+S1S>1($?(=jN1iirGlZnNgM^ zED5t&Fm{Y0VPKO-sSuO7nd~7Z>2#$OS7FqEQtc45BHGSZN~g{ODK!E+&5D&3q$)jP|nv z-^sV^=X39gYA4(>4d@MF&$1*#L;@1UVa*)GeQ=`dMzhc&b}#}Ht(N9-kvGYHvTdU{FelI1(A?^5rEcO{Xux~irgN4f!YSX`UyJBn&4l)UYD#Ov z<$lCOjgqBCPrZeui)+Q7YMMgbfS*a&j~jwbLHvVt*@ORb9y`VbCBbkQKjo`3SK^^u6%S$uSt7f z9Oubu;K?Ak#``hk4rOJ*VfY<;?%%W-h{TsKEZkC6b0qUW;3in~TdVzU2*5k?5(1>R z)`IsKK+w#SVCfb__!~l!0eQ(6PH3%n^`>ajz%OH-{Rl>4(>7T_Mv`Xt+xDLFy;j*z zq-6hM8x7LayIKv<-UPU(T`?Jww-FLX09HQ&lrevh?vZt$Z3__>QTv$p z?X9>#Hx4wSCUt>Q_b%yg1(%f;O_(f(6YskUey)C_DLf`Cewube`ab)6d^vCV#5YRX zSbUSR`|iV`?6`OPfh@7IXjs8+2KU8%*v921RbW`c!42hw_6xPBGxcvh)x~jlxHve+ z^~0X{fbD7k1q29_{ly%t7!7+({r9J!gDWGeo+}4bYRO@1U={o4ou+Y%Q5ViY5-*#i zE8%TONC-333rm6?LMrO=7;7);i6Xd^(7grb{>J(m6<~QkT7GJT(s~r>Yce0mB*F9J zDnzz^dW3NM38u8phPTF#ghJ^bn+WGi|2En6PJ&MC@=8v;!T_}}K<3j50Ze2FiX3G( zc)5Fw2%M{-o}{84*`rCe`aCaHcit`{)Bcm9bR4A?Srr=TArBYmdqZ_|!?fUpBO~$S z9VrUk!9|;3w@9WJn!53g5rJ4RR}}RPMPTOUcMNhHSnTXoc$b)qG@3~?7=~#P%^}^^)&AXs+%^tNg1NnYI}&C!nI+X9?>4us*1&mmd8 zjPy^?i^wrrnr!xCA=P0gBx>|>?Hi4%)UWx)2cSU|R8ozugzl#@BKz77{3+pKFou0+ zVQ_8xipAsX^mJr&)F+Pf!`euu^lQf*LOcw=ueX8@Tg*{)PoRvnzcc=(VPTfLj_h6R z93CoHEZ1&X#ow=n@9X03xvJ>mqwd*k#$0~gvz=}i`p@kR^tE#-S0Cr;hx=UAu9e_& z1GgPipUQcDgK2sukQKx-{KY6cxHa2mua-Pq>XfzAP(W@Zr55icVDN(X*!`D>i8mpP zx&735ZIx$ag4%zyhy6QJPDCwnKjKI{MCT;^vzPW z=QsuU zz7tu?Gb?KGnbv(&@(-A&k^F(aaJY{P)Cait*nu|dMxgSVLVu?%bl8D;IA7@H_k|}+ zmtFJvX8eq9K@#$(8~3un41)E@DP$P6Hxyz4`nNImD2;mDR{T^_42MsC_q^|GuC1j2 zctk{sW*$9h83LNWA9G2 zf+@ptz@53Vz*&EK+-WGXvBCjuypTlnaB7QiNO1i78Y3zQrB|bWUk5`Qxm1?;sRRNd z!u%@L$kVAGtqskGoYb~7koD35;-qa*q~XdWEZiI)iR#^*kmh$?sqf6&a#gAhAHzL6 zUV|I%P+|ySgb)FYkY=a@!|giV+m2E%Pl#K+kblQdtRUIPlz0mlkIz?rvCp3GyPd|X ziLM=&ye6i1N^?EDC7}76m6$6}e#cOF@eHJjl>`R8uUjUr%F4JHpcUSP+yGc@Wl%fs zM$CroskkBd1l~!$Vh@qZj537+iF}si+|0lCuc4(KLJ&YpwjDvoUN8XctmhSPqb03?+3cD*Tdu+QsocBPJ|y>u%%Lw0Ed3BqMY z_0OJxITlMxJnqmAi_nMJnLIQ?1<-guEgcExZGkqTUc0&fLP-I^B-?$7QKbm`HHewfSO5yc zPPjOSq4>hK3P+L5ipyP9Xg$akwLcAMJ`RUq;-iDpsa0dH+(ic?sgWT+@A37=ffUQB zpV!=IpIYd3sV#AgG@EEj`D__B*NYi6on^{Aj^Y`$a#8#G>z>Bqb!>{8&klPNB0*yP zg79{s1)()ner?EeDK_-*-WPUE?DC9cC3N3A5cn14>Kce&8A0hoP}D*eF-X9cuHVG! z)oduY=B5^uE(3J_<|f4ekyK)!gTnN#{|#2fQwSk$Hq3P2cta%~RapU1?PO8BuF{Cq zx>@+0k?0QbzMOeQSVOqhBO!ErQ)h@)nbejmhiU;u0<~F&tXH$#4M}GowvIa|v(y1X zTQ`({k}uD3x6@v(HgaY+9SR`)`q5RTYMMN&nF}^VRUShtFeI#W^sOl+>LQR?*JoFQ z-c`&1F-jeQfd#3zuMrN8_lb;9rk!9|n2FdBqHieL4%YJml(P&_YCr9~rEs6PwdEBS zB}X@Jy5Bi;H@R@*i zLB#91VyqQ68(OC{W;+87Shv?3tmYZ?LDP;3v%0oc<+F;RNU5RU;9p4Vy&m`3r}9#L zBh7&YtC_v`x*rzRtuqULK{3YuAx&y?AAG(9ED23bGU#fyrJ6=m;2`oAP5AMfR#&|a zjFj+uS!?|3p06ycz2^EYoqfvbdf7S{2SrbaRBI>NhIA5#YfIz65G9!9iT;LTNA}lP zK>-Kcw^Xkk*1RchvnjgUD~rgP87tf?tv4Jf@rg1kiO_y|MO81@C?HC9u$S=h(;Ap( zE}QsHRwF@%L~o-GEb4K4GPp1d-D>w(N|};sj-5;ciy@74n1I;FQm4b!+9-fl;g`3f z$gL49Zz3)piY|GLR5sB448GJ)rjy8IQgL*qT$DB)C@Jj9l}mXalMD4$0-kZz9y1sG zjZNE!lY+0W(HDW(Cx~~fL${n9LE=3E$RiRGF*@%kac?vf9`flZ`7~E1xcd_7nficqN6WOc(2aE}r#DDu&!-Pu|r#9vqBYu3CJHucr8ZKgi0Yg5Vnu zA&jsW=6T{MS@m;A8VRsL9NmX_o$Hgq+Jw#x1uVza`fPKLUsRbAr0>F|D~$gc-BvuY ze&(H(q~=I#$~T)ZIivQ9H)O1W*wN+U_cwjs2CQf4@cfF0;TrKR!bidCUEX%;*mnA5 zmO+6jwp!8M{W2^qfBWd{&x=1dt?QvB zCCCRtBd|YiS>MucYEi>h^L4*#LnVj~XjdconnRX35*;{p2XL9bS3Jc4Dm5dyVe1-= z4aKSAtQ5)#Oh`8~(#)zNnOM>CXU{k#HJzR+_A9E2MUGm5%?v7Ki+j+8t~zXh;W`rU zqMZW24Lr=N+l|VNkmV{UZx=kkZ!Ry>WDrj|qhNhFW$rY1rsH{fem}SMYmJBigVDKA zK*IU0ZphtzH2qQAeC~96vsF9?)NsO^4LPIF2k##ip#ggyyWMX_I5hWZ2vAPXlM==r z^sI*>BH5t!Q|4a>wlw5p3cKh4xhNKKcv@z5TXI$Us#%x*?9%e-&~8x#x?PL zH5gpa$&6|Fy1zZG{o*K$kxO*hr~S^JbSvQuu371jhXrX$P(J?GWoylMCwO9I z4O1p_jQE@;!S?b7s*+`E=Q(y#-uNATi}5F3_;DKSQeQvNbG8VL_=B%FvHu$zDH9d# zcDrggTH4gsf9dQi>c1mJBJU1RB`hX&^w9F&7}lewWfCqePDQ|Ltnb!mBg>B$)VV}z zf3O*{_(O;&2i>W?Y6*amrKv&a>emC5R)K-IX9L{RCN_hiSv)NwUZU5V>|9*FLx=Cb zs651&Od;N`NXc}nj{3>GRL#J-PbUXbz1x*qx?ziSbcwcVz}h`jv_s_jgP^_YX3yhs z%RIg<1D|>{sah*gsGtvXD<|>3>zfbV;{Cn(JOQ+_Ew5MSujn^Jo?tNygtJ=ph5>4&>SKyD~t3Azmiovj~ zrs5P5!*aVj4Y-U5b5LKVGNAfJ#a|k#EntHQ+~0c!xfg}}$4Wm(op1qCzN@O>3aV5_ zYPqG_rKi}u<@Vq*mITY#sm@&m@HS#(0Ki}agndO6 zDH(ZsAIj2I&P%a%wn1}jr{}s(wFns&;YgBa`=T!d=FnUsTBHk3=c>Y3k^4x_c~YU<7mHf4mL zpP#wqQM)|5z82amKKv8CSKMOXr9`edqjP7P3%eeqi8#P#Bn>jJIQqIOv^f2{W7Xw$ zWcs(XeynoL-RAynvZMKR6~SR*n&mu2<_4%^FPb441qC6Z>jS(bJ?U?+$3wIcXIjle zHcPJKiNW3v)4-YjYZCvv%@y1~*((01G1F1S2y6w9@7Yn}X?+euIif@;K*IYBFcA*U zjOlZySwVm%{gA3F=7!z7OsBfEp&-9zLMegkX4;V!1SosRkoM{iHJ2&`A`s0VU-`s< zwG3UaaR4cV8hQa|Rpl}IBKC%0Wfq!gD4A)f=G0-VADuCm3{a0Dcz%F%QAd)Lv}K^; z_4=|=d9vwMMRf*WmVWoB{H7u!!3wupS9o(WQa0UPRa5h;x>{5ct*Y9ErO|)m$excy zj@m5d|H}m^Mxj5?3Sd@lgz;@8eSLyV3gYu0h2-SQMrjRsc}$>}@XZ zIY}^6OX#JcI;T7W41&LK@VYZGBCtY2`vD-k3;p=!j*^-Z4G05Y{cluK_)%{!Jpu2% z2JR`C@7kK{OruR}xH;h+A6R_W0stI1p)X#(e919Q&#d+=^RoBru-oZ7uGUBBAB#`0 zlt9D+Y?%G;F9m4T7RXfPvvysFV;3K$XvRW_#Pd6wO8eh*AXWT3RL;c)_B zZsB?PXk_!NB71JU4EoXdX(wCZf2Ni^833!K{xHW?!@$5BMi=al0-)o|4fIFQQ{(@t zO;EDnr+gb!w!nMPt~9-tO;Hok-<9yTP}bVI#0oh`&Wl4G@ewIV@I%M1%Seu%bjUs3 zzhU8EH4T|3cb7>!w7vYFbBGYELM63|M_c{?P>b^^Znh*}8Q z9u3VjELwO{{7-mGNUH(QF~d=e#U%E&qEg5U5#qD`S;BTha;?zEZuRw)w6s28bqPc4`n@` z<(lMlx+l2#rbjC0)k#~C?$6hpEheA&z)Qa~$wjhU=*uGv!m#`s6)pnW4SOwDZqrSd z1N2_co;AM`k5bKn_WaaHi(+Pgo#4BFmTA?1FsP)?`kJ>!QbrfBj`mtV%uUf`D6QP_ z4kyz9jhwO?w!MbbE2&1$>n{ewBA$X)aB8n2&oiW08$=$uw+Nz$^F^}j-{wgppXW7r z#lyV6>zmD)@tTzXAiY||Gm*RSR9B?QhejD&?bV_G624dw*ebsJYF_ZNm2tbK{@l+P2v+f_&9tr^SaIVbxEyVb- zb3=tNST^Q{8;%HA^)y7zn!kFALq7?tkXqS7dNO`l4lsnB#Mc?wfC!cAV7l+{UdrE3 zhQR)O0mt10Q?#ON$Sn9Sphx?H1+NAERgsu%KE=%TQn140sbjB&G*6?c9t+3s5j2$PncbbV|vf!a}5q^Q) z4=*^m!M@ghMxJ)(t z*Lzm{6S`1Qj5H)KY@p`+)r^Y%Pyq`vCiJA{1vpy7szWwdCcYx%-(Pc<}#lX1nte4*&SYk=ofMeLWqzL@ z1=I0PbUhN^q3U%M`8`Gl0WV}BTf^eD?sf3i`06Z1d^Gd$eiL81%G1$1uc zdIWE&f9P}`lt!nd^v`Q=5B*{UH&J1<T`l&&=Q8f)`)E$84l}?y86pO9(zRhQ zyL10>XsA*8jjNHO6W91#m>?x*A>m`{*48ta?Cy7A+w*+3=-Lpa8)~luO&L_LH@D{W zKuSKZMzFW-gg;v{qag3{#L_x6jyh<>(U`%1svI&H%Z;&|GHatN|CNoQoyy zzmg_expeoJTLCFwur6Ylx)#~CIk$fT0nN`P9RZ2qPofL@7tZr!&UUosQJOr$m8RvEYGWe7TXRivvd;VH~e!4SR^%u zH}ikQ4?~mqGk$;-EF7XVVz-9&Azw0mXH>S`HWIIYP7rW(arz>&|Cyc@Hil`3>{t!@ z?WwP?54l#lxDKF58yAu7AH1Mg$_24%KZNZWB*TrR)hZJj|qKS{Oi&1btC%GXg+bDc(L4=}ouaLiG@HQVr8X zqyJCIk;VAP^gM24%9+%~ThdiqG&r@jG88GXR##8z6T#>2Nq>C;E3^$UN%Uxc%RGKC>@LWm?tR zE=7Ymu|&7#h1zZU*XWQb4Bwac#xAA%*a zWqhB!$doz!Dz8^~OgPQ`B|*`E9UCYArfc*4BJ`x*3O8|-@aqE%CrP}-Y~72@C4%Jk@0Ey%uerW(%bBb>Z-NV=k@k#ClcJgh z+66y<)2g?CLqm#T7vjm5uN>EE#XGoivwOYLSk1kG_So}m}pJ4UKF6DXJ z`L8-(62`@DAwoQKliP>!i)%o5FGpsi`%Kby_73rrZcS&xcGz*w_KqWw!hP&S4Kaaf z*!jKKepJ?V!RX!#jdy594XfW%X29&nw`!{F(djWCqfh@RK=W^kS$(7Pw~HMg8Nd5q z^GS~zP_{H@MwYwXuIkZEDZ_-8LR|>Drn6X9ZJxG2&l`%a=1x+3u5{S$-g6DMG4JR5 z(A_gLqno=VP)hJHaC}>2&FLtF0mj8t2i%Sv$OR3Cc{9r*?St|}xa7P_qDRwl4uOVY54DQ@C$_WJ{l$69bVB_saE z3N3BS#mr`-yP;raQ%pEdvc!!tB4#gY&+k|-NOFI(8C9@B!@qbUXH4*6LQ-G=KGM|c zxq+&VDk|nLt=6pS#UPjGSIZD330gxBm!<^PsL+hpP+=wjJ-d+_<+>ZLZn~9&%8_Yy5XQj8$v z#FXVEaFwq;k`d=YSM=MRCR~`rPw8Qsf7j!_GstVV=lPX+ULLEC*#_(Umf-lB@#8Y1 z>sRj5gIn$oZp5dm{uy#<;E`MILn{uNG3CF@HZ?1iPoMt4{qHD#^3lOXND9855#q^! zqrgBJL|;1M+bD(0NJQ@LhaYWA>UTdToHcv)7L;Sp*_}RhwAmw#Q9GT{-Vb6hNCWo2nQ31VhCC7^W=*%LTV<{J^-EY1 zFADB&BvT+}h*bD3Rp7-kHZ<73jgD2GKtlRC3%k8pRSJx-CdNQo7fa++Ts+=E4X>yG z_XeoCR(ymg!}>Mn76au<<8hl;gexwNaj?G|t4zBZcx-GXU9GPPVV&Rx0Kvp~aC`rE z_Sl_yC4!pe|LOe=^|V^jVB7GU_BoGs-2!U5fWHqdj97vDwWZk2pGMd1&F4R>bEw?{ z$U!+*&c3fW1!f5F*mlF8ujH`vvzQ!H;Vo#_Bl@ek$;jiG^rSS@*U$aY0-U9y*41gZ z9|$lQBs%4+Ba*~(rj|rSIxnSX=*pWCT^-I&*E?t+ zP;Vwr`{7P$sx=Q3dok;D9oZqvgcL(bQ5a}EPdNeC3QH;V`KMo0jgF}%8l-2>^7I0M;RF)rqR;j$(BU? zgzyT@V-Q<8;11NS6zqa90a_O2{$!$=N_*BeDq_=|ba1kDv}D9>T?rN`D+>98X63J1ru@ zx|w>nfgE~yOsKE?7NKs^_<$h+-yjknK4AX&}T%A&aDC%@z=nOfLUs1#C>I+5Q(Cs8JIvH;x`xkGNl(l-8-=uA)UR~MOmr3NaVV!ztH6Wx^#cQ00`UO`elgc-758%-YqOU)S$X$ zvDFlt9bI@7GoT7%mytwg^nq11QTorm6#{6wF1he)@R>-Z9(lc-bk<5AiA7%w4h&$H zv<;WWH`?8eqNb1U_zd%*dBTQUCjBLEEd_jp&F#O8DB=NEeu}`I&%%#-mZ#*Ag)m!# z?$F|a63f-UpS2GLqx|a4Ox=~^6cso_(VbYSH49nZ2uUfzo$@~Fe0VvTJz4EG=pj;U zWT94QdG=Y?Qskw}$=@5(&5X)br`u0ssHuJ1ivLbiMay~cQEOx?G^sZHd(-JSuD&bo<&`W$MiU>QyX)TftdGFMX zfbs@=i)xHnxfzdC&ge@vAyXl4s=oHZoB%U1a9D@ddYg`jdt5s4&3$xJeUIkiEl{lW zA#OoO?#L#6|6oc~`qHKl;;PUZ82aZ0UtvIf(I5AA4)SR}fe!>%ymTssJapDq90|2^ z!#ZhNjAUmVK)$0+y;Zqkngk=+d;a&T>{Wbptw?HTz6>5ZE$i!K`~K<1ZI$2D&r0>i zPyg{9A&>_x2#Rj}3f7%Dl*L9$MoPrbF>1P#>2 zV2%|@T&k^a!QR=LLrCn0uiA)NX0he0uC{$I=sG^mcpFF0K68_>I4e0#=Y1dNt(Ec= z-E+va|K3><&HBTLDHA>55<+u%Mz@qOQVK(;%yXa(&aoWrs>{8~G_jG23s3%j$?~J0 zTr>YibsBe}#!#(@YWKoCGq$xR$3S2$3oZhuJvy-cFnT?3b4q8EJalOv`B9|EqogQp zDKDNPv_Ru)fu`=DZvEWU_UtbA@#3-u4V0z@`_9?M^SpJtaXMv?qt@k^w*!UMHpLL! zvZSqb#iS%b{}cSs(zkArq_&i#DyCJuf0>zyH7aFg*@~u#X26eC7y}&&^Zw>^pj9d` z-(_2C_L6W0WnmIqLiN~E;A1kX6MQLUOg(2OZf;#S0>_f-bKvq(ILA?-8)_F>Bd>$ctRlE?jXi_ii{urtX^?Pbw5vFioH%ieAL29>)&qRaAf=%O4#$68o)FQp#2zWjQ{>pEZU zGG&;~4%{1Z$7@|U-KFJXk?F9u8QOV&`u^A9hvtinTbp$1YnekEUx~^`)^ipvmD-aS zi)=gY#Wj`R;Ax9GxruNLa-;!FiZK+5wl>pJ=C{YZ!!TG-5 z-WQ?Jo2s*URrGLYU4_1juzbx@#6bT0l5?h1L8rddZ&l6RL^IyuGU8G z9j^loijpRwe`2=wV<-A%0&&;{l)#~hav}ZBvVgegNdEp7tFY&N>Sqv?RqIZWHoOVB zlm9-O#-uS%e$}pBtgKZ6mEu|_fAv;|W9#4uIVujDsrbrs8emwwnLSjZtjT#{>B1sJ z8XmxRsixJdAz$e*P4yi}yNOJ9;dQvcc38x=c&4w9p&(`J&~ynKfXU@gVjqEz%Z#)z zG4FwX%cZ>!KC!!8xIT-(Zr^@x!}5sjZ}(!0$1$DB2dw?yYn@khU~csrQRL}w<61uK zfcisgNDY!NmXh!e#bb-an~5M`(Ok~+ue;l?-{x{}GfS#m?DfPxsJmy3&%fc04zX~v zvoucqJgB)WagVh)k#>^|jb)ZsXI5V(Xl2F;))>IuUyATdIp8m1a%I`whPk{0=c7~n z>-R;o36S6J-_75z%PouxD>>?5U<)~{n>UZZ?1AZ8@_Vh7)*yr-*fRr z`ZM;PG)g)bmB;|T)5&QXBw>5?2f4*@8@llhQHrL{&gJIGGQWEl_d=93G%znzJ8$W% zI8Rtjt%@n94Ygy=g*_jHr1pQ`v&zf7+^s*yh0kq~*P&k=26K`+H_|p@Z`5~X*@wOf zkcxosAE>i$LV(Hj9F1FCr;qf<{$gR;q0hI2UngbimzQ~( z*&E7^hj(sf|BB5PEK4K)ytffu2j#Qbo27HJ8@xWj)E^J_BM}lMkH>C&@8ICR(Z#nt zy}W1bUhKo9KiwK#s#K6Lkh|pmw+T7={^sG|!N2XDfBeWKE&XzuM;dkOKDWEQ;GFKm zMq5iBX78X$h8Q({*DZXy5VAciz)W5EwT2upGWS3*AKUd?20Tn zys&j$xlUk9HBBEzL(+Lc&*S|B+UQzo-lOa&YfOk_91^6lhYeA7cM5hqpfV<5;SaG3ujfwABf-VoaQ$B z8a(t`bZK*Q;jJ#zX`=X?Zu#FgWeq3yqUI#^LQ7p}HEq;80M7aR9p~BMa=!-FTSDIK zD^MNp2P-k3EZIP6?;W-lTM`~~ltJgslvC}~#k9m@1S@PMov)V>Z_QW>Dgq(C?*9lb zb$-BHTWLSPzK558i^FIwt0W@_7v4F58ujvmLlX^9Xrol3i$|T+Kc4ba`=rQ! zyXbS6&1#PZ!BZ_xN%N>$L+J1u>Q8xD&Eg4-;)x&fvQ+rHv-zpdL}&5?X0x(rUc3=D zns?twx(>T+YCo!rq3uff8AbJmfQF`AqqS~Js6rIWNAH=z=7)}*GN(|}Pt=-#1(jTC~97G$` z4OEoTyoWU)W$}^bhBZ5>P#Z^Qr-{hn#e|XL=FY7|chEraH94$33m3Cv7>VTet{-)+ z8G^^4&Y)y~jW8dh<~>Iso?@ItR%y6E20uuK1E| zG0FOR$>QxL6(Y6;u9u#i0`3+P`4k+`m~(+)+L7K;M*$6d<*>+xoS!hT|9B(y7RdeO zzJG6ARsg+Yy^4{I%cCONGxtNuquF<#mhj#z?897{@c^$Q?AC^se4)+om_90&i)E4z z&dnpo-|tLkMH8O6i#jTV{B8d{oIs^K7yH|zWI^@W4porl;Z00PSJqYuw}qkgr^&Ah zsn`~WH|qV)N=fb(Vq-*ObBb=-_G5%qFAXO-_`Xm~k?mqxJbf>Y#U2;INsZ0Ng;K?d z2|wfB-uj{YF=74nw_2NSYo#j$e^>TyP02}XuL2t=7&z3g(2Qb9HEtsNf6Vx~53(L7 z|L#zNh+WMW(+iR>k+Uy<65Z0IG(}v(oYy^X_hPSTo9dorASW$9obMeuHNYtmOxz`c zAh;}vsyy^epx4d*r)`h~yw=jt1pw01hi3!~B?T97+;=;zt@uB5pCrnwYN638Gj0XY zHmu}-Bx_2}t*WRy3+D_|1AvPRdTW@)^w*M@-8zA-=L(#&Mjf4vk+~nLYSgFH!H4*A znPKmX|B=ueyJT;#^$+c4WRqe3s(9%gcg&56QC> zrSp9bZ&B9t!y|RWrj@wk13~o6vdRNysoQHXq@hUQ3>_X-zExqon*a9BrtzTl6jb=Y z>kp;6Cwk)7an`9xdHkMf4^tDQ%8+&AdYj}bRT#G9CUU|Ae%0r-q=-DZL2Iu~vwJ7Z z`}Vje)Ka;`Y#?P524Z(^-K%1UgziSb!u|XKM21D&)lQo4-B&h#J8X^Kpou|=SCii7 zE`W^4QJMOu`RB*3h)soU5Mync-opmdWfF0u3-uZ-jF+hZu}W-j>@1Lo#A(kI07b<= zoK|xkI1>JyK?cC>CGE1|59q>PTUNBtUa?`7r~cI9OL@kS|F5srzd_vXZN?`H-BZl@ zQ}u_xG%0eg`?jQH(9-GPyHuuol>U-PE87^6`fsM+Y|8r|>NPaYR00*d3QC$=vaUIK zIc$DZfj0fDrRitO%Z8EwD$99yc)6?2yGHITOG zk+q7mE*H31{hjy^R?xQWMyH4eA~#BDpyVwr_xfU21n!`qw6ar|n(i#}A!d5C4~E>09rn4o2>dSeG<*dxIpB5Smvrz864czNp zmyz2P33zZTDAjWoXk^QOd_wte+{jd6w1+nPmZb0bhGq#@LCvg1Rpdq7?+8)N1BGz& z;ic!#zOmB6O{HZk2LqB1Fw0zAOF5_vS=7~>oSoQP)TeI#{b8ihtgrsuVJe~Tp>wD_ z+;ZfQZZn5aMg&^AFEuG$5c~{6l^|i)ZA&!Q4XqRi|a430<@3Zmr>r#bEG0{2JN0uY?f z*dt#trNF6&1b`jEdrmrHHqh@(+h*|p(M*X5)y`2~9b`kD8!}OENq4dGwF>EGITb+I z)kQ997?jz-7kZ(8CWzj#&!(t;`IWQkiM?6zMw8!dD!zO|3?6;%B-SkVFd1W=30oP#_A3i{0qf4L#A?)RQaM;e= zqT)1uJA9b+7z5o4>G{^X_Go&j#0{?Mz1Y8;KTQBI11{d$g3ebx(uM+Js+uB8g+s2T zjM0fM)Md;z!YkEl-9Am1+TS8oBAU9zVN}2|W;~F1>S^{tv1wPCOiPy=$Q`qL*94QE zoO2&Py?tPCv>Rk8tG}NKSSM z0kA9trFk*|8}Zk@dFvYn^W-pY)I{0i$Yrp>ONzcA%+Nb6#?Gc?+57?mr*r}f1%Xx&x5_jJ)uhG4;*{yPgkGoh9VJcqs+BdR zUPzkmJ1b}X0aNnx&|tT2G}}t5UyDNv9U9nolfD`LXkg3io9`y_<^@J}<9fgi+Bzbw z(l#h?rq_GV8!l4Ul37rkSC9#jv`Zqw8Dc)qlW_72*)|WJ8AK4lmzS{xKkGgR_0HN7 zwkg2-=u-Stbw>2OOBxJKDH1q7kkLNb;?-9z3tQIT|KkYuDmmVzGvxh1%*g#0#-{1bO2_e4b18K)Ol(R;1I3!Mav)qF z6$EK z7g$2`zZ2sEr$mK2ebQzcu-70cUZ9%0NNFG|e3>d=Zp0-=8094sZ>K6{x@$lrf0{GomNLhV$tWbmwEuU-%} z*EeIvw>tNIfSsftTqlGm5@-$ITRbqR-)RZz^vPaxoEtep`-Pn$%^9~K<1MDi7;- z_vit45*T#g0Dlgv`E=tWI$#?%Q)3|IztcrJ)MwoJWkevcp**FZOYmK?LSz;_BlP5F zo&Wyi0R3BQ0j_caq%XA^z8BW8t{T7)q({X5yHOZG?;M zI|hfAM4oB~?S#C~vga#Bpk*DR?5Ig>dp}*#yxc37cPka>m>tcJdIkqBBNdKi)E=&< zkz33f#}m6aB=U3f!;L?pz!h;qj`H6$75nXK0K*^eN~3(|H2wJC(QeIct&dO6X7BG3 zs0DVtbJ96ms*MtKaevYVn%*?f|iJ#Nw9i%m|ns zlJ;x?{LNR{dxQI@MWr+1IOVtu*0{!}>~AZp*(NCDYno&P+l)Hfzw@E| z%Df6(eC9~G)pb0EO8>Y!E+?229#~1s;+V*pz6{1>ip|Og`^J@zr=sC0=NiQ-GU8hl z-d)r^MK7McKws|9dHdQ#(Y5WW1XNR#HVgF569E~kk8-)g=1LXHl(BlbZ+|f@5;5tzSsU^|BQ(S^YV#x`deQU+vb_Q{7 z{E5c0*nk}A(Tf2dgBumx=`V}F9+aOsUEg$U^f>K)CQmgo@+&t7+fOAX5iqZWSW|h| ziuzZ%O$h1n@x|@mhMWyr!%cwhABE7yzW8X|{fGO=wxf_yx{}3!yiVGnlRRUvZl5P_ znH3H>GCL8rMJ$3;=|XycxC4CJAS#G14u25je4Sj9rY~70exA zmmxOrK&;Ue!Cw#}Qk~Nq4G<`J#Ci~Q)vitz#mtd?U#~0V!D$TSCaxp zO)esisq4g2ezhhQ4EeF`5?s}E*l z!xl2rnd06G%KsO(f8Ta$Daa%<`hx5V%7vVY!JK+IbT7%bMqVt-Q+T6Z+1+BYI3iL> z6=Gow(i}^28soL(6iLc0$#&+kJ44m0Rq`ix46)Br=m}8Z0x4?$Tkxut6YnO8BvCt4Vbkb1V&KUOVyQ_(=A5AK=HnMez+M*KuMFGZO zq`6^;zgQ@x7poZZy%5dkf6|-dE5B0uX(S3{P`(tn>paD{PyTz4&ES=iZX@l{%b~qx zA<>_gABRlR@O7*(92KnrD=!8Vl_UpV=A8S^?)b%e_B)v}6r$Rfg_!BEWK^|}rSRf4 zJsLHWc*@4X$`jw45B-S6Aq+r){}AoP)%0$&hnV9OUCd2fG-l{6zfiZ}2)_t03g zv-f%-z7%*kxosV)0J*Xxs5_}B)WJ0C5)1pjTn>@7gc*-BJ#>H|024ZY1Egy=6(kQq zbCAQ7&9w6y-dlXjQo1m`hqAZ_(_S*annBfRqdy;TNdcdQ0}rbqz0Ch+&%yBGvGUCt zg>QKt^ht`iOvO7)MK;XV#oVsTH^9mh&Q~|A{Y*9rC0l> zku87oZwoQz=0Sr2KuCt_&B<3(ld8J79=eK^KYztJ7_CP7olAA9tKOncf%yP{#U)m( z8$~x0Q9zDHu7(~y3=6)D&gL$lc|Byl8nk82p`{`Q`h9B0={!}T*Hba=Ltjnan;j0tXSJJM{K?U3&S57)|IF&ssZC6aifXP7Ao0D;3cT6F7m#geuoN`~ z+gYB!Y-yt!#s+QTD6#bSYSB=luw6UPuHZnGPrbnFrh3*pYqq?c_G##->Xds;6IY8;73wOOxf<63-$HS}eKYtHD8#23 z_WDiPvJu!mQvuEl>t$-kUZm(BeVw|Y?ejjxU{MXdI(I4Oy}DP~SYN+M`FyxoBki5Y zoOl2?^X#Kn!G38eu~2gi060(^C4`C!q*l3w+$#TZQeLyMKZ2vH5$BesiNo{GY{-sj zc~9p=E5A-bfZ8+qbz?sA2;*z@ynZP)fxDWsh`8|=uYi7QH!1K#Q^$6oW20yHwcK}^ zqYD0HDDf0+Z}qndij=niE`aJAM;L5{Cca-s&?om7NyjXxZHz6a&1B3 zPDAk+5Qw>Xh5G;@&L~#j%xZ?WPQCq?mE=K+#~LD)TU9sl(0CBT;`g+6zZKN95S;_M zIOqHBw>xhEgc7!U6GJ0k7g=(O8Lw&JYQzS}PEZoTG(+XP)y%I#tQSDx?lJo(a{m4N j>w$kg@PF=s&KMQZJ!Z!@J|y8L?N);ih8-XW#uxq%NGF8Z literal 42614 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 299)position.y = 299; + //if(position.y < 16)position.y = 16; + //else if(position.y > 299)position.y = 299; *location = position; } manager.addEntity(tmpl); @@ -875,8 +877,6 @@ void mainLoop(void* arg) launcher.renderer.present(); draw_time = launcher.getTime() - draw_time; - //import std.stdio; - //printf("Scalling: %f",launcher.scalling); if(launcher.tool_show)launcher.tool_circle.draw(&launcher.renderer, (launcher.mouse.position*launcher.scalling)-launcher.render_position, cast(float)launcher.tool_size, launcher.renderer.view_size.y*6*launcher.scalling); __gshared float plot_time = 0; @@ -1105,11 +1105,13 @@ int app_main(int argc, char** argv) import demos.simple; import demos.space_invaders; import demos.particles; + import demos.brick_breaker; // launcher.switchDemo(&spaceInvadersStart,&spaceInvadersLoop,&spaceInvadersEnd,&spaceInvadersEvent,SpaceInvaders.tips); // launcher.switchDemo(&particlesStart,&particlesLoop,&particlesEnd,&particlesEvent,ParticlesDemo.tips); // launcher.switchDemo(&simpleStart,&simpleLoop,&simpleEnd,&simpleEvent,Simple.tips); // launcher.switchDemo(getParticlesDemo()); - launcher.switchDemo(getSimpleDemo()); + // launcher.switchDemo(getSimpleDemo()); + launcher.switchDemo(getBrickBreakerDemo()); } int key_num; diff --git a/demos/source/demos/brick_breaker.d b/demos/source/demos/brick_breaker.d index 1af22b9..ec4571f 100644 --- a/demos/source/demos/brick_breaker.d +++ b/demos/source/demos/brick_breaker.d @@ -18,9 +18,12 @@ import ecs_utils.utils; import game_core.basic; import game_core.rendering; +import game_core.collision; extern(C): +private enum float px = 1.0/512.0; + /*####################################################################################################################### ------------------------------------------------ Components ------------------------------------------------------------------ #######################################################################################################################*/ @@ -51,40 +54,60 @@ struct CBall ubyte radius; } -struct CVelocity -{ - mixin ECS.Component; +// struct CVelocityFactor +// { +// mixin ECS.Component; - alias value this; +// alias value this; - vec2 value; -} +// vec2 value = vec2(1); +// } + +// struct CVelocity +// { +// mixin ECS.Component; + +// alias value this; + +// vec2 value = vec2(0); +// } /*####################################################################################################################### ------------------------------------------------ Systems ------------------------------------------------------------------ #######################################################################################################################*/ -struct MoveSystem -{ - mixin ECS.System!64; +// struct MoveSystem +// { +// mixin ECS.System!64; - struct EntitiesData - { - uint length; - CLocation[] location; - @readonly CVelocity[] velocity; - } +// struct EntitiesData +// { +// uint length; +// CLocation[] location; +// @readonly CVelocity[] velocity; +// @optional @readonly CVelocityFactor[] vel_factor; +// } - void onUpdate(EntitiesData data) - { - foreach(i; 0..data.length) - { - data.location[i] += data.velocity[i] * launcher.delta_time; - } - } -} +// void onUpdate(EntitiesData data) +// { +// if(data.vel_factor) +// { +// foreach(i; 0..data.length) +// { +// data.location[i] += data.velocity[i] * data.vel_factor[i] * launcher.delta_time; +// } +// } +// else +// { +// foreach(i; 0..data.length) +// { +// data.location[i] += data.velocity[i] * launcher.delta_time; +// } +// } +// } +// } -struct BallCollisionSystem +struct EdgeCollisionSystem { mixin ECS.System!64; @@ -93,13 +116,117 @@ struct BallCollisionSystem uint length; CLocation[] location; CVelocity[] velocity; + //CBall[] ball_flag; } void onUpdate(EntitiesData data) { foreach(i; 0..data.length) { - + if(data.location[i].x < 0) + { + if(data.velocity[i].x < 0)data.velocity[i].x = -data.velocity[i].x; + data.location[i].x = 0; + } + else if(data.location[i].x > 400) + { + if(data.velocity[i].x > 0)data.velocity[i].x = -data.velocity[i].x; + data.location[i].x = 400; + } + + if(data.location[i].y < 0) + { + if(data.velocity[i].y < 0)data.velocity[i].y = -data.velocity[i].y; + data.location[i].y = 0; + } + else if(data.location[i].y > 300) + { + if(data.velocity[i].y > 0)data.velocity[i].y = -data.velocity[i].y; + data.location[i].y = 300; + } + } + } +} + +struct BallCollisionSystem +{ + mixin ECS.System!64; + + mixin ECS.ReadOnlyDependencies!(ShootGridDependency); + + struct EntitiesData + { + ///variable named "length" contain entites count + uint length; + const (Entity)[] entity; + CVelocity[] velocity; + @readonly CLocation[] location; + @readonly CScale[] scale; + @readonly CBall[] ball_flag; + } + + ShootGrid* grid; + + bool onBegin() + { + grid = launcher.manager.getSystem!ShootGridManager().grid; + if(grid is null)return false; + else return true; + } + + void onUpdate(EntitiesData data) + { + EntityID id; + foreach(i; 0..data.length) + { + float radius = data.scale[i].x; + //if(grid.test(id, data.location[i], ubyte.max)) + if(grid.test(id, data.location[i] - radius, data.location[i] + radius, ubyte.max)) + { + Entity* entity = launcher.manager.getEntity(id); + if(entity) + { + CLocation* location = entity.getComponent!CLocation; + CScale* scale = entity.getComponent!CScale; + if(location && scale) + { + vec2 rel_pos = *location - data.location[i]; + vec2 abs_rel_pos = rel_pos; + if(abs_rel_pos.x < 0)abs_rel_pos.x = -abs_rel_pos.x; + if(abs_rel_pos.y < 0)abs_rel_pos.y = -abs_rel_pos.y; + + vec2 half_scale = *scale * 0.25f; + + if(abs_rel_pos.x < half_scale.x + radius && + abs_rel_pos.y < half_scale.y + radius) + { + if(abs_rel_pos.x < half_scale.x) + { + if(rel_pos.y * data.velocity[i].y > 0)data.velocity[i].y = -data.velocity[i].y; + } + else if(abs_rel_pos.y < half_scale.y) + { + if(rel_pos.x * data.velocity[i].x > 0)data.velocity[i].x = -data.velocity[i].x; + } + else + { + vec2 vector = abs_rel_pos - half_scale; + if(rel_pos.x > 0)vector.x = -vector.x; + if(rel_pos.y > 0)vector.y = -vector.y; + + float pow_dist = vector.length2(); + if(pow_dist < radius*radius) + { + vector = vector / sqrtf(pow_dist); + data.velocity[i] = data.velocity[i] - vector * (2 * dot(vector, data.velocity[i])); + } + } + } + } + } + //launcher.manager.sendEvent(id, EBulletHit(data.entity[i].id,data.bullet[i].damage)); + //launcher.manager.removeEntity(data.entity[i].id); + } } } } @@ -118,13 +245,17 @@ struct BrickBreakerDemo __gshared BrickBreakerDemo* demo; -void brickBreakerStart() +void brickBreakerRegister() { demo = Mallocator.make!BrickBreakerDemo; + demo.texture.create(); + demo.texture.load("assets/textures/atlas.png"); + launcher.manager.beginRegister(); registerRenderingModule(launcher.manager); + registerCollisionModule(launcher.manager); launcher.manager.registerComponent!CLocation; launcher.manager.registerComponent!CRotation; @@ -132,27 +263,109 @@ void brickBreakerStart() launcher.manager.registerComponent!CTexCoords; launcher.manager.registerComponent!CTexCoordsIndex; launcher.manager.registerComponent!CVelocity; + launcher.manager.registerComponent!CInput; + launcher.manager.registerComponent!CPaddle; + launcher.manager.registerComponent!CDamping; + launcher.manager.registerComponent!CVelocityFactor; + launcher.manager.registerComponent!CBall; launcher.manager.registerSystem!MoveSystem(-100); - launcher.manager.registerSystem!BallCollisionSystem(-99); + launcher.manager.registerSystem!EdgeCollisionSystem(-99); + launcher.manager.registerSystem!BallCollisionSystem(-79); + launcher.manager.registerSystem!InputMovementSystem(-120); + launcher.manager.registerSystem!DampingSystem(-120); launcher.manager.endRegister(); +} - demo.texture.create(); - demo.texture.load("assets/textures/atlas.png"); +void brickBreakerStart() +{ + DrawSystem* draw_system = launcher.manager.getSystem!DrawSystem; + draw_system.default_data.color = 0x80808080; + draw_system.default_data.texture = demo.texture; + draw_system.default_data.size = vec2(16,16); + draw_system.default_data.coords = vec4(246,64,2,2)*px; + draw_system.default_data.material_id = 0; - launcher.manager.beginRegister(); + EntityTemplate* brick_tmpl = launcher.manager.allocateTemplate( + [CLocation.component_id, CScale.component_id, CColor.component_id, + CTexCoordsIndex.component_id, CShootGrid.component_id].staticArray + ); + brick_tmpl.getComponent!CTexCoordsIndex().value = TexCoordsManager.instance.getCoordIndex(vec4(304,40,16,8)*px); + brick_tmpl.getComponent!CColor().value = 0x80206020; + brick_tmpl.getComponent!CScale().value = vec2(16,8); - launcher.manager.registerComponent!CLocation; + EntityTemplate* big_brick_tmpl = launcher.manager.allocateTemplate(brick_tmpl); + big_brick_tmpl.getComponent!CTexCoordsIndex().value = TexCoordsManager.instance.getCoordIndex(vec4(320,32,16,16)*px); + big_brick_tmpl.getComponent!CScale().value = vec2(16,16); + + EntityTemplate* paddle_tmpl = launcher.manager.allocateTemplate( + [CLocation.component_id, CScale.component_id, CInput.component_id, + CTexCoordsIndex.component_id, CPaddle.component_id, CVelocity.component_id, + CDamping.component_id, CVelocityFactor.component_id, CShootGrid.component_id].staticArray + ); + paddle_tmpl.getComponent!CTexCoordsIndex().value = TexCoordsManager.instance.getCoordIndex(vec4(272,48,64,10)*px); + paddle_tmpl.getComponent!CScale().value = vec2(64,10); + paddle_tmpl.getComponent!CDamping().value = 14; + paddle_tmpl.getComponent!CVelocityFactor().value = vec2(1,0); + + EntityTemplate* ball_tmpl = launcher.manager.allocateTemplate( + [CLocation.component_id, CScale.component_id, //CDamping.component_id, + CTexCoordsIndex.component_id, CBall.component_id, CVelocity.component_id].staticArray + ); + ball_tmpl.getComponent!CTexCoordsIndex().value = TexCoordsManager.instance.getCoordIndex(vec4(304,32,8,8)*px); + ball_tmpl.getComponent!CScale().value = vec2(8,8); + ball_tmpl.getComponent!CVelocity().value = vec2(0.1,0.1); + // paddle_tmpl.getComponent!CDamping().value = 14; + + launcher.gui_manager.addComponent(CLocation(), "Location"); + launcher.gui_manager.addComponent(CRotation(), "Rotation"); + launcher.gui_manager.addComponent(CScale(), "Scale"); + launcher.gui_manager.addComponent(CColor(), "Color"); + launcher.gui_manager.addComponent(CTexCoords(), "Tex Coords"); + launcher.gui_manager.addComponent(CTexCoordsIndex(), "Tex Coords Index"); + launcher.gui_manager.addComponent(CVelocity(), "Velocity"); + launcher.gui_manager.addComponent(CInput(), "Velocity"); + launcher.gui_manager.addComponent(CDamping(), "Damping"); + launcher.gui_manager.addComponent(CBall(), "Ball"); + + launcher.gui_manager.addSystem(MoveSystem.system_id, "Move System"); + launcher.gui_manager.addSystem(BallCollisionSystem.system_id, "Ball Collision System"); + + launcher.gui_manager.addTemplate(brick_tmpl, "Brick"); + launcher.gui_manager.addTemplate(big_brick_tmpl, "Big Brick"); + launcher.gui_manager.addTemplate(paddle_tmpl, "Paddle"); + launcher.gui_manager.addTemplate(ball_tmpl, "Ball"); + + foreach(i;0..10) + { + CColor color; + final switch(i) + { + case 0:color = 0x80206020;break; + case 1:color = 0x80602020;break; + case 2:color = 0x80202060;break; + case 3:color = 0x80206060;break; + case 4:color = 0x80606020;break; + case 5:color = 0x80602060;break; + case 6:color = 0x80606060;break; + case 7:color = 0x80202020;break; + case 8:color = 0x80008030;break; + case 9:color = 0x80206080;break; + } + foreach (j; 0..20) + { + launcher.manager.addEntity(brick_tmpl,[CLocation(vec2(j*18,300-i*10)).ref_, color.ref_].staticArray); + } + } + + launcher.manager.addEntity(paddle_tmpl,[CLocation(vec2(190,20)).ref_].staticArray); + launcher.manager.addEntity(ball_tmpl,[CLocation(vec2(190,40)).ref_].staticArray); - launcher.manager.endRegister(); } void brickBreakerEnd() { - launcher.manager.getSystem(MoveSystem.system_id).disable(); - launcher.manager.getSystem(DrawSystem.system_id).disable(); - demo.texture.destroy(); Mallocator.dispose(demo); @@ -185,6 +398,7 @@ bool brickBreakerLoop() DemoCallbacks getBrickBreakerDemo() { DemoCallbacks demo; + demo.register = &brickBreakerRegister; demo.initialize = &brickBreakerStart; demo.deinitialize = &brickBreakerEnd; demo.loop = &brickBreakerLoop; diff --git a/demos/source/demos/particles.d b/demos/source/demos/particles.d index 8dac7ff..ec64774 100644 --- a/demos/source/demos/particles.d +++ b/demos/source/demos/particles.d @@ -54,14 +54,14 @@ struct CTexCoords vec4 value; }*/ -struct CVelocity -{ - mixin ECS.Component; +// struct CVelocity +// { +// mixin ECS.Component; - alias value this; +// alias value this; - vec2 value = vec2(0); -} +// vec2 value = vec2(0); +// } struct CForceRange { @@ -85,14 +85,14 @@ struct CVortex float strength = 0.6; } -struct CDamping -{ - mixin ECS.Component; +// struct CDamping +// { +// mixin ECS.Component; - alias power this; +// alias power this; - @GUIRange(0,9) ubyte power = 0; -} +// @GUIRange(0,9) ubyte power = 0; +// } struct CGravity { @@ -165,25 +165,25 @@ struct DrawSystem } }*/ -struct MoveSystem -{ - mixin ECS.System!64; +// struct MoveSystem +// { +// mixin ECS.System!64; - struct EntitiesData - { - uint length; - CLocation[] locations; - @readonly CVelocity[] velocity; - } +// struct EntitiesData +// { +// uint length; +// CLocation[] locations; +// @readonly CVelocity[] velocity; +// } - void onUpdate(EntitiesData data) - { - foreach(i; 0..data.length) - { - data.locations[i] += data.velocity[i] * launcher.delta_time; - } - } -} +// void onUpdate(EntitiesData data) +// { +// foreach(i; 0..data.length) +// { +// data.locations[i] += data.velocity[i] * launcher.delta_time; +// } +// } +// } struct MouseAttractSystem { @@ -347,38 +347,38 @@ struct PlayAreaSystem } } -struct DampingSystem -{ - mixin ECS.System!32; +// struct DampingSystem +// { +// mixin ECS.System!32; - struct EntitiesData - { - uint length; - const (Entity)[] entity; - @readonly CDamping[] damping; - CVelocity[] velocity; - } +// struct EntitiesData +// { +// uint length; +// const (Entity)[] entity; +// @readonly CDamping[] damping; +// CVelocity[] velocity; +// } - float[10] damp = 0; +// float[10] damp = 0; - bool onBegin() - { - foreach(i;0..10) - { - damp[i] = powf((0.99 - cast(float)i * 0.01),launcher.delta_time*0.1); - } +// bool onBegin() +// { +// foreach(i;0..10) +// { +// damp[i] = powf((0.99 - cast(float)i * 0.01),launcher.delta_time*0.1); +// } - return true; - } +// return true; +// } - void onUpdate(EntitiesData data) - { - foreach(i; 0..data.length) - { - data.velocity[i] = data.velocity[i] * damp[data.damping[i]]; - } - } -} +// void onUpdate(EntitiesData data) +// { +// foreach(i; 0..data.length) +// { +// data.velocity[i] = data.velocity[i] * damp[data.damping[i]]; +// } +// } +// } struct ParticleLifeSystem { @@ -444,7 +444,7 @@ struct ParticlesDemo __gshared ParticlesDemo* particles_demo; -void particlesStart() +void particlesRegister() { particles_demo = Mallocator.make!ParticlesDemo; @@ -484,7 +484,10 @@ void particlesStart() launcher.manager.registerSystem!AttractorIterator(-1); launcher.manager.endRegister(); +} +void particlesStart() +{ DrawSystem* draw_system = launcher.manager.getSystem!DrawSystem; draw_system.default_data.size = vec2(2,2); draw_system.default_data.coords = vec4(246,64,2,2)*px; @@ -579,6 +582,7 @@ bool particlesLoop() DemoCallbacks getParticlesDemo() { DemoCallbacks demo; + demo.register = &particlesRegister; demo.initialize = &particlesStart; demo.deinitialize = &particlesEnd; demo.loop = &particlesLoop; diff --git a/demos/source/demos/sandbox.d b/demos/source/demos/sandbox.d index 69a2ef2..925ebb2 100644 --- a/demos/source/demos/sandbox.d +++ b/demos/source/demos/sandbox.d @@ -6,6 +6,7 @@ import demos.simple; import demos.snake; import demos.space_invaders; import demos.particles; +import demos.brick_breaker; import game_core.rendering; @@ -17,10 +18,17 @@ extern(C): void sandboxStart() { + simpleRegister(); + snakeRegister(); + spaceInvadersRegister(); + particlesRegister(); + brickBreakerRegister(); + simpleStart(); snakeStart(); spaceInvadersStart(); particlesStart(); + brickBreakerStart(); DrawSystem* draw_system = launcher.manager.getSystem!DrawSystem; draw_system.default_data.size = vec2(16,16); @@ -28,6 +36,10 @@ void sandboxStart() draw_system.default_data.material_id = 0; draw_system.default_data.texture = particles_demo.texture; draw_system.default_data.color = 0x80808080; + + launcher.manager.getSystem(MouseAttractSystem.system_id).disable(); + launcher.manager.getSystem(demos.simple.MoveSystem.system_id).disable(); + } void sandboxEnd() @@ -56,9 +68,9 @@ bool sandboxLoop() else */ time += delta_time; - while(time > 100) + while(time > 200) { - time -= 100; + time -= 200; launcher.manager.update("fixed"); } diff --git a/demos/source/demos/simple.d b/demos/source/demos/simple.d index 1aafcb2..ecccc12 100644 --- a/demos/source/demos/simple.d +++ b/demos/source/demos/simple.d @@ -107,7 +107,7 @@ struct Simple __gshared Simple* simple; -void simpleStart() +void simpleRegister() { simple = Mallocator.make!Simple; @@ -124,7 +124,10 @@ void simpleStart() // launcher.manager.registerSystem!DrawSystem(1); launcher.manager.endRegister(); - +} + +void simpleStart() +{ DrawSystem* draw_system = launcher.manager.getSystem!DrawSystem; draw_system.default_data.color = 0x80808080; draw_system.default_data.texture = simple.texture; @@ -198,6 +201,7 @@ bool simpleLoop() DemoCallbacks getSimpleDemo() { DemoCallbacks demo; + demo.register = &simpleRegister; demo.initialize = &simpleStart; demo.deinitialize = &simpleEnd; demo.loop = &simpleLoop; diff --git a/demos/source/demos/snake.d b/demos/source/demos/snake.d index 8ff0be6..525b4ab 100644 --- a/demos/source/demos/snake.d +++ b/demos/source/demos/snake.d @@ -235,10 +235,10 @@ struct CMovement Direction direction; } -struct CInput -{ - mixin ECS.Component; -} +// struct CInput +// { +// mixin ECS.Component; +// } struct AppleSystem { @@ -849,7 +849,7 @@ struct CopyLocationSystem __gshared Snake* snake; -void snakeStart() +void snakeRegister() { import game_core.rendering; @@ -890,7 +890,10 @@ void snakeStart() launcher.manager.registerSystem!SnakeSystem(101); launcher.manager.endRegister(); +} +void snakeStart() +{ launcher.gui_manager.addComponent(CApple(),"Apple"); launcher.gui_manager.addComponent(CSnake(),"Snake"); launcher.gui_manager.addComponent(CParticle(1000),"Particle"); @@ -975,9 +978,9 @@ bool snakeLoop() if(launcher.getKeyState(SDL_SCANCODE_SPACE))time += delta_time * 3; else time += delta_time; - while(time > 100) + while(time > 200) { - time -= 100; + time -= 200; launcher.manager.update("fixed"); } @@ -992,6 +995,7 @@ bool snakeLoop() DemoCallbacks getSnakeDemo() { DemoCallbacks demo; + demo.register = &snakeRegister; demo.initialize = &snakeStart; demo.deinitialize = &snakeEnd; demo.loop = &snakeLoop; diff --git a/demos/source/demos/space_invaders.d b/demos/source/demos/space_invaders.d index b249fc1..66be099 100644 --- a/demos/source/demos/space_invaders.d +++ b/demos/source/demos/space_invaders.d @@ -18,6 +18,7 @@ import ecs_utils.utils; import game_core.basic; import game_core.rendering; +import game_core.collision; //import std.math : PI; @@ -29,8 +30,6 @@ private enum float px = 1.0/512.0; extern(C): -enum ShootGridDependency = "ShootGridDependency"; - /*####################################################################################################################### ------------------------------------------------ Types ------------------------------------------------------------------ #######################################################################################################################*/ @@ -57,7 +56,7 @@ struct SpaceInvaders ~this() @nogc nothrow { - if(shoot_grid)Mallocator.dispose(shoot_grid); + // if(shoot_grid)Mallocator.dispose(shoot_grid); if(enemy_tmpl)launcher.manager.freeTemplate(enemy_tmpl); if(ship_tmpl)launcher.manager.freeTemplate(ship_tmpl); if(laser_tmpl)launcher.manager.freeTemplate(laser_tmpl); @@ -163,28 +162,14 @@ struct CTexture vec4 coords = vec4(0,0,0,1); }*/ -struct CColliderScale -{ - mixin ECS.Component; +// struct CVelocity +// { +// mixin ECS.Component; - alias value this; +// alias value this; - vec2 value = vec2(16,16); -} - -struct CVelocity -{ - mixin ECS.Component; - - alias value this; - - vec2 value = vec2(0,0); -} - -struct CInput -{ - mixin ECS.Component; -} +// vec2 value = vec2(0,0); +// } struct CEnemy { @@ -265,11 +250,6 @@ struct CSideMove byte group = -1; } -struct CShootGrid -{ - mixin ECS.Component; -} - struct CTargetParent { mixin ECS.Component; @@ -336,14 +316,7 @@ struct CAnimationLooped mixin ECS.Component; } -struct CDamping -{ - mixin ECS.Component; - alias value this; - - byte value = 0; -} struct CParticle { @@ -514,163 +487,6 @@ struct EDestroyedChild ------------------------------------------------ Systems ------------------------------------------------------------------ #######################################################################################################################*/ -struct ShootGrid -{ - - ~this() @nogc nothrow - { - if(nodes)Mallocator.dispose(nodes); - if(masks)Mallocator.dispose(masks); - } - - struct Node - { - alias entity this; - - EntityID entity; - } - - void create(ivec2 nodes_count, vec2 node_size) - { - this.size = nodes_count; - this.node_size = node_size; - inv_node_size = vec2(1.0/node_size.x, 1.0/node_size.y); - nodes = Mallocator.makeArray!Node(nodes_count.x * nodes_count.y); - masks = Mallocator.makeArray!ubyte(nodes.length); - } - - void mark(EntityID id, vec2 beg, vec2 end, byte mask) - { - ivec2 ibeg = cast(ivec2)(beg * inv_node_size); - ivec2 iend = cast(ivec2)((end * inv_node_size) + 0.5); - if(ibeg.x < 0)ibeg.x = 0; - if(ibeg.y < 0)ibeg.y = 0; - if(iend.x > size.x)iend.x = size.x; - if(iend.y > size.y)iend.y = size.y; - foreach(i; ibeg.y .. iend.y) - { - foreach(j; ibeg.x .. iend.x) - { - nodes[i * size.x + j] = id; - masks[i * size.x +j] = mask; - } - } - } - - void clear() - { - size_t size = nodes.length * EntityID.sizeof; - memset(nodes.ptr, 0, size); - memset(masks.ptr, 0, masks.length); - } - - bool test(out EntityID id, vec2 beg, vec2 end) - { - ivec2 ibeg = cast(ivec2)(beg * inv_node_size); - ivec2 iend = cast(ivec2)((end * inv_node_size) + 0.5); - if(ibeg.x < 0)ibeg.x = 0; - if(ibeg.y < 0)ibeg.y = 0; - if(iend.x > size.x)iend.x = size.x; - if(iend.y > size.y)iend.y = size.y; - foreach(i; ibeg.y .. iend.y) - { - foreach(j; ibeg.x .. iend.x) - { - if(nodes[i * size.x + j].id != 0) - { - id = nodes[i * size.x + j]; - return true; - } - } - } - return false; - } - - bool test(out EntityID id, vec2 pos, ubyte mask) - { - ivec2 ipos = cast(ivec2)(pos * inv_node_size - 0.5); - if(ipos.x < 0)ipos.x = 0; - if(ipos.y < 0)ipos.y = 0; - if(ipos.x >= size.x)ipos.x = size.x - 1; - if(ipos.y >= size.y)ipos.y = size.y - 1; - size_t index = ipos.y * size.x + ipos.x; - if((masks[index] & mask) == 0)return false; - if(nodes[index].id != 0) - { - id = nodes[index]; - return true; - } - return false; - } - - vec2 inv_node_size; - ivec2 size; - vec2 node_size; - Node[] nodes; - ubyte[] masks; -} - -struct ShootGridCleaner -{ - mixin ECS.System!1; - - struct EntitiesData - { - - } - - void onUpdate(EntitiesData data) - { - if(space_invaders.shoot_grid)space_invaders.shoot_grid.clear(); - } -} - -struct ShootGridManager -{ - mixin ECS.System!128; - - mixin ECS.WritableDependencies!(ShootGridDependency); - - struct EntitiesData - { - uint length; - //uint thread_id; - const (Entity)[] entity; - @readonly CLocation[] locations; - @readonly CShootGrid[] grid_flag; - @readonly CGuild[] guild; - @optional @readonly CScale[] scale; - @optional @readonly CColliderScale[] collider_scale; - } - - ShootGrid* grid; - - void onCreate() - { - grid = space_invaders.shoot_grid; - } - - bool onBegin() - { - if(!grid)return false; - //grid.clear(); - return true; - } - - void onUpdate(EntitiesData data) - { - vec2[] scale; - if(data.collider_scale)scale = cast(vec2[])data.collider_scale; - else if(data.scale)scale = cast(vec2[])data.scale; - else return; - foreach(i; 0..data.length) - { - vec2 half_scale = scale[i] * 0.5; - grid.mark(data.entity[i].id, data.locations[i] - half_scale, data.locations[i] + half_scale, cast(ubyte)(1 << data.guild[i].guild)); - } - } -} - struct ParentOwnerSystem { mixin ECS.System; @@ -833,7 +649,7 @@ struct ShipWeaponSystem CTexCoords.component_id, CScale.component_id, CEnemy.component_id, CShootGrid.component_id, CGuild.component_id, CInit.component_id, CChildren.component_id, CDepth.component_id, CTargetParent.component_id, - CSpawnUponDeath.component_id, CShootWaveUponDeath.component_id].staticArray + CSpawnUponDeath.component_id, CShootWaveUponDeath.component_id, CShootGridMask.component_id].staticArray ); /*CTexCoords* tex_comp = tower1_tmpl.getComponent!CTexCoords; @@ -1215,8 +1031,8 @@ struct ShootingSystem laser.shoot_time -= CWeapon.levels[laser.level - 1].reload_time; laser_location.value = data.location[i]; - laser_velocity.value = vec2((randomf()*2-1) * CWeapon.levels[laser.level - 1].dispersion,1);//data.shoot_direction[i].direction == Direction.up ? 1.0 : -1.0); - if(data.shoot_direction && data.shoot_direction[i].direction == Direction.down)laser_velocity.y = -1; + laser_velocity.value = vec2((randomf()*2-1) * CWeapon.levels[laser.level - 1].dispersion,0.5);//data.shoot_direction[i].direction == Direction.up ? 1.0 : -1.0); + if(data.shoot_direction && data.shoot_direction[i].direction == Direction.down)laser_velocity.y = -0.5; laser_guild.guild = data.guild[i].guild; @@ -1280,39 +1096,6 @@ struct ShootingSystem } } -struct DampingSystem -{ - mixin ECS.System!32; - - struct EntitiesData - { - uint length; - const (Entity)[] entity; - @readonly CDamping[] damping; - CVelocity[] velocity; - } - - float[10] damp = 0; - - bool onBegin() - { - foreach(i;0..10) - { - damp[i] = powf((0.98 - cast(float)i * 0.02),launcher.delta_time*0.1); - } - - return true; - } - - void onUpdate(EntitiesData data) - { - foreach(i; 0..data.length) - { - data.velocity[i] = data.velocity[i] * damp[data.damping[i]]; - } - } -} - struct BulletsCollisionSystem { mixin ECS.System!32; @@ -1343,6 +1126,29 @@ struct BulletsCollisionSystem } } +struct CollisionMaskSystem +{ + mixin ECS.System; + + mixin ECS.ReadOnlyDependencies!(ShootGridDependency); + + struct EntitiesData + { + ///variable named "length" contain entites count + uint length; + CShootGridMask[] mask; + @readonly CGuild[] guild; + } + + void onAddEntity(EntitiesData data) + { + foreach(i;0..data.length) + { + data.mask[i] = cast(ubyte)(1 << data.guild[i].guild); + } + } +} + struct ParticleEmittingSystem { mixin ECS.System!32; @@ -1670,7 +1476,7 @@ struct HitPointsSystem //tex_comp.tex = space_invaders.texture;//ship_tex; upgrade_tmpl.getComponent!CTexCoords().value = vec4(0*px,32*px,16*px,16*px); *upgrade_tmpl.getComponent!CAnimation = CAnimation(upgrade_laser_frames, 0, 1); - upgrade_tmpl.getComponent!CVelocity().value = vec2(0,-0.1); + upgrade_tmpl.getComponent!CVelocity().value = vec2(0,-0.05); explosion_tmpl = launcher.manager.allocateTemplate( [CDepth.component_id, CParticle.component_id, CLocation.component_id, @@ -1975,32 +1781,32 @@ struct ClampPositionSystem } } -struct MovementSystem -{ - mixin ECS.System!32; +// struct MovementSystem +// { +// mixin ECS.System!32; - struct EntitiesData - { - uint length; - //read only components can be marked with @readonly attribute or with const expression instead - const (CVelocity)[] velocity; - //components are treated as required by default - CLocation[] locations; - //@optional const (CBullet)[] laser; - const (Entity)[] entities; +// struct EntitiesData +// { +// uint length; +// //read only components can be marked with @readonly attribute or with const expression instead +// const (CVelocity)[] velocity; +// //components are treated as required by default +// CLocation[] locations; +// //@optional const (CBullet)[] laser; +// const (Entity)[] entities; - //@optional CSideMove[] side_move; - } +// //@optional CSideMove[] side_move; +// } - void onUpdate(EntitiesData data) - { - foreach(i;0..data.length) - { - data.locations[i].x += data.velocity[i].x * launcher.delta_time * 0.5; - data.locations[i].y += data.velocity[i].y * launcher.delta_time * 0.5; - } - } -} +// void onUpdate(EntitiesData data) +// { +// foreach(i;0..data.length) +// { +// data.locations[i].x += data.velocity[i].x * launcher.delta_time * 0.5; +// data.locations[i].y += data.velocity[i].y * launcher.delta_time * 0.5; +// } +// } +// } struct AnimationSystem { @@ -2229,114 +2035,20 @@ struct CShipIterator //void handleEvent(Entity* entity, ) }//*/ -/** -*System is responsible for movement of objects with CInput component. -*In this example every entity has same speed when using movement system. -*/ -struct InputMovementSystem -{ - mixin ECS.System!32; - - vec2 move_vector; - - struct EntitiesData - { - uint length; - //read only components can be marked with @readonly attribute or with const expression instead - const (CInput)[] input; - //components are treated as required by default - //CLocation[] locations; - CVelocity[] velocity; - //CTexture[] textures; - } - - /** - *onBegin gives opportunity to check keys once and call update on entities only when - *one key is pressed. - */ - bool onBegin() - { - move_vector = vec2(0,0); - if(launcher.getKeyState(SDL_SCANCODE_W)) - { - move_vector += vec2(0,1); - } - else if(launcher.getKeyState(SDL_SCANCODE_S)) - { - move_vector += vec2(0,-1); - } - if(launcher.getKeyState(SDL_SCANCODE_A)) - { - move_vector += vec2(-1,0); - } - else if(launcher.getKeyState(SDL_SCANCODE_D)) - { - move_vector += vec2(1,0); - } - - if(move_vector.x != 0 ||move_vector.y != 0) - { - move_vector = move_vector / sqrtf(move_vector.x * move_vector.x + move_vector.y * move_vector.y); - return true; - } - //don't call system update because no key pressed - return false; - } - - /** - *Update is called multiple times in one "manager.update()" call. - *Number of "onUpdate" calls is count of buffers which must be updated during pass. - *When multithreading is used, number of "onUpdate" calls can be greater due to fact that - *JobSystem can split buffers for better data packing. - */ - void onUpdate(EntitiesData data) - { - /*if(move_vector.x == 0) - { - foreach(i; 0..data.length) - { - data.textures[i].coords = vec4(0*px,80*px,48*px,32*px); - } - //return; - }*/ - //move every entity using movement vector - //if(move_vector.x != 0 || move_vector.y != 0) - foreach(i; 0..data.length) - { - data.velocity[i] += move_vector * launcher.delta_time * 0.005; - if(data.velocity[i].x > 0.5)data.velocity[i].x = 0.5; - else if(data.velocity[i].x < -0.5)data.velocity[i].x = -0.5; - if(data.velocity[i].y > 0.5)data.velocity[i].y = 0.5; - else if(data.velocity[i].y < -0.5)data.velocity[i].y = -0.5; - //data.locations[i].x += move_vector.x * launcher.delta_time * 0.25; - //data.locations[i].y += move_vector.y * launcher.delta_time * 0.25; - //if(move_vector.x > 0)data.textures[i].coords = vec4(48*px,80*px,48*px,32*px); - //else data.textures[i].coords = vec4(0*px,80*px,48*px,32*px); - } - /*else - foreach(i; 0..data.length) - { - data.velocity[i] = vec2(0,0); - }*/ - } -} - /*####################################################################################################################### ------------------------------------------------ Functions ------------------------------------------------------------------ #######################################################################################################################*/ __gshared SpaceInvaders* space_invaders; -void spaceInvadersStart() +void spaceInvadersRegister() { + space_invaders = Mallocator.make!SpaceInvaders; space_invaders.texture.create(); space_invaders.texture.load("assets/textures/atlas.png"); - space_invaders.shoot_grid = Mallocator.make!ShootGrid; - space_invaders.shoot_grid.create(ivec2(80,60), vec2(5,5)); - launcher.manager.beginRegister(); launcher.manager.registerDependency(ShootGridDependency); @@ -2381,6 +2093,7 @@ void spaceInvadersStart() launcher.manager.registerComponent!CParticleEmitterTime; launcher.manager.registerComponent!CSpawnUponDeath; launcher.manager.registerComponent!CShootWaveUponDeath; + launcher.manager.registerComponent!CShootGridMask; launcher.manager.registerEvent!EChangeDirection; launcher.manager.registerEvent!EDamage; @@ -2392,7 +2105,8 @@ void spaceInvadersStart() //launcher.manager.registerSystem!MoveSystem(0); launcher.manager.registerSystem!DrawSystem(100); launcher.manager.registerSystem!InputMovementSystem(-100); - launcher.manager.registerSystem!MovementSystem(-99); + //launcher.manager.registerSystem!MovementSystem(-99); + launcher.manager.registerSystem!MoveSystem(-99); launcher.manager.registerSystem!ClampPositionSystem(-90); launcher.manager.registerSystem!ShootingSystem(0); launcher.manager.registerSystem!ChangeDirectionSystem(0); @@ -2417,8 +2131,18 @@ void spaceInvadersStart() launcher.manager.registerSystem!ChildDestroySystem(-110); launcher.manager.registerSystem!ShootWaveSystem(-100); //launcher.manager.registerSystem!SpawnUponDeathSystem(-110); + launcher.manager.registerSystem!CollisionMaskSystem(-100); launcher.manager.endRegister(); +} + +void spaceInvadersStart() +{ + + // space_invaders.shoot_grid = Mallocator.make!ShootGrid; + // space_invaders.shoot_grid.create(ivec2(80,60), vec2(5,5)); + + space_invaders.shoot_grid = launcher.manager.getSystem!ShootGridManager().grid; DrawSystem* draw_system = launcher.manager.getSystem!DrawSystem; draw_system.default_data.color = 0x80808080; @@ -2463,7 +2187,8 @@ void spaceInvadersStart() launcher.gui_manager.addSystem(DrawSystem.system_id,"Draw System"); launcher.gui_manager.addSystem(InputMovementSystem.system_id,"Input Movement"); launcher.gui_manager.addSystem(ShootingSystem.system_id,"Shooting System"); - launcher.gui_manager.addSystem(MovementSystem.system_id,"Movement System"); + //launcher.gui_manager.addSystem(MovementSystem.system_id,"Movement System"); + launcher.gui_manager.addSystem(MoveSystem.system_id,"Move System"); launcher.gui_manager.addSystem(ClampPositionSystem.system_id,"Clamp Position System"); launcher.gui_manager.addSystem(ChangeDirectionSystem.system_id,"Change Direction System"); launcher.gui_manager.addSystem(BulletsCollisionSystem.system_id,"Bullets Collision System"); @@ -2494,14 +2219,16 @@ void spaceInvadersStart() CLocation.component_id, CTexCoords.component_id, CInput.component_id, CShip.component_id, CScale.component_id, CColliderScale.component_id, CShootDirection.component_id, CShootGrid.component_id, CGuild.component_id, - CDamping.component_id, CChildren.component_id, CInit.component_id].staticArray + CDamping.component_id, CChildren.component_id, CInit.component_id, + CShootGridMask.component_id, CVelocityFactor.component_id].staticArray ); space_invaders.ship_tmpl.getComponent!CTexCoords().value = vec4(0,80,48,32)*px; space_invaders.ship_tmpl.getComponent!CScale().value = vec2(48,32); space_invaders.ship_tmpl.getComponent!CHitPoints().value = 1000; - space_invaders.ship_tmpl.getComponent!CDamping().value = 7; + space_invaders.ship_tmpl.getComponent!CDamping().value = 14; space_invaders.ship_tmpl.getComponent!CInit().type = CInit.Type.space_ship; space_invaders.ship_tmpl.getComponent!CColliderScale().value = vec2(26,24); + space_invaders.ship_tmpl.getComponent!CVelocityFactor().value = vec2(0.5,0.5); launcher.manager.addEntity(space_invaders.ship_tmpl,[CLocation(vec2(64,64)).ref_].staticArray); } @@ -2512,7 +2239,7 @@ void spaceInvadersStart() space_invaders.laser_tmpl.getComponent!CTexCoords().value = vec4(0,24,2,8)*px; space_invaders.laser_tmpl.getComponent!CScale().value = vec2(2,8); - space_invaders.laser_tmpl.getComponent!CVelocity().value = vec2(0,1); + space_invaders.laser_tmpl.getComponent!CVelocity().value = vec2(0,0.5); } EntityTemplate* enemy_tmpl; @@ -2543,7 +2270,7 @@ void spaceInvadersStart() boss_tmpl.getComponent!CScale().value = vec2(96,48); boss_tmpl.getComponent!CDepth().value = -1; boss_tmpl.getComponent!CParts().count = 4; - boss_tmpl.getComponent!CVelocity().value = vec2(0.05,0); + boss_tmpl.getComponent!CVelocity().value = vec2(0.025,0); } { @@ -2551,7 +2278,7 @@ void spaceInvadersStart() [CColor.component_id, CHitMark.component_id, CHitPoints.component_id, CLocation.component_id, CTexCoords.component_id, CScale.component_id, CEnemy.component_id, CShootGrid.component_id, CGuild.component_id, CInit.component_id, - CChildren.component_id].staticArray + CChildren.component_id, CShootGridMask.component_id].staticArray ); tower_tmpl.getComponent!CTexCoords().value = vec4(96,96,16,16)*px; @@ -2566,12 +2293,12 @@ void spaceInvadersStart() CVelocity.component_id, CAutoShoot.component_id, CLocation.component_id, CTexCoords.component_id, CScale.component_id, CWeapon.component_id, CEnemy.component_id, CShootDirection.component_id, CShootGrid.component_id, - CGuild.component_id].staticArray + CGuild.component_id, CShootGridMask.component_id].staticArray ); space_invaders.enemy_tmpl.getComponent!CTexCoords().value = vec4(32,32,16,16)*px; space_invaders.enemy_tmpl.getComponent!CShootDirection().direction = Direction.down; - space_invaders.enemy_tmpl.getComponent!CVelocity().value = vec2(0.1,0); + space_invaders.enemy_tmpl.getComponent!CVelocity().value = vec2(0.05,0); space_invaders.enemy_tmpl.getComponent!CGuild().guild = 1; space_invaders.enemy_tmpl.getComponent!CWeaponLocation().rel_pos = vec2(0,-15); @@ -2603,7 +2330,7 @@ void spaceInvadersStart() { upgrade_tmpl = launcher.manager.allocateTemplate([CVelocity.component_id, CLocation.component_id, CTexCoords.component_id, CScale.component_id, CUpgrade.component_id, CAnimationLooped.component_id, CAnimation.component_id].staticArray); upgrade_tmpl.getComponent!CTexCoords().value = vec4(0,32,16,16)*px; - upgrade_tmpl.getComponent!CVelocity().value = vec2(0,-0.1); + upgrade_tmpl.getComponent!CVelocity().value = vec2(0,-0.05); *upgrade_tmpl.getComponent!CAnimation = CAnimation(HitPointsSystem.upgrade_laser_frames, 0, 0.75); } @@ -2746,6 +2473,7 @@ bool spaceInvadersLoop() DemoCallbacks getSpaceInvadersDemo() { DemoCallbacks demo; + demo.register = &spaceInvadersRegister; demo.initialize = &spaceInvadersStart; demo.deinitialize = &spaceInvadersEnd; demo.loop = &spaceInvadersLoop; diff --git a/demos/source/game_core/basic.d b/demos/source/game_core/basic.d index 156680b..b47ba52 100644 --- a/demos/source/game_core/basic.d +++ b/demos/source/game_core/basic.d @@ -1,11 +1,18 @@ module game_core.basic; import bubel.ecs.core; +import bubel.ecs.attributes; import ecs_utils.math.vector; import gui.attributes; +import ecs_utils.utils; + +import app : launcher; + +import bindbc.sdl; + struct CLocation { mixin ECS.Component; @@ -56,4 +63,193 @@ struct CSelected mixin ECS.Component; bool value = false; +} + +struct CInput +{ + mixin ECS.Component; +} + +struct CDamping +{ + mixin ECS.Component; + + alias value this; + + @GUIRange(0,9) byte value = 1; +} + +struct CVelocity +{ + mixin ECS.Component; + + alias value this; + + vec2 value = vec2(0,0); +} + +struct CVelocityFactor +{ + mixin ECS.Component; + + alias value this; + + vec2 value = vec2(1); +} + + +struct DampingSystem +{ + mixin ECS.System!32; + + struct EntitiesData + { + uint length; + const (Entity)[] entity; + @readonly CDamping[] damping; + CVelocity[] velocity; + } + + float[20] damp = 0; + + bool onBegin() + { + foreach(i;0..20) + { + damp[i] = powf((0.99 - cast(float)i * 0.01),launcher.delta_time*0.1); + } + + return true; + } + + void onUpdate(EntitiesData data) + { + foreach(i; 0..data.length) + { + data.velocity[i] = data.velocity[i] * damp[data.damping[i]]; + } + } +} + +struct MoveSystem +{ + mixin ECS.System!64; + + struct EntitiesData + { + uint length; + CLocation[] location; + @readonly CVelocity[] velocity; + @optional @readonly CVelocityFactor[] vel_factor; + } + + void onUpdate(EntitiesData data) + { + if(data.vel_factor) + { + foreach(i; 0..data.length) + { + data.location[i] += data.velocity[i] * data.vel_factor[i] * launcher.delta_time; + } + } + else + { + foreach(i; 0..data.length) + { + data.location[i] += data.velocity[i] * launcher.delta_time; + } + } + } +} + +/** +*System is responsible for movement of objects with CInput component. +*In this example every entity has same speed when using movement system. +*/ +struct InputMovementSystem +{ + mixin ECS.System!32; + + vec2 move_vector; + + struct EntitiesData + { + uint length; + //read only components can be marked with @readonly attribute or with const expression instead + const (CInput)[] input; + //components are treated as required by default + //CLocation[] locations; + CVelocity[] velocity; + //CTexture[] textures; + } + + /** + *onBegin gives opportunity to check keys once and call update on entities only when + *one key is pressed. + */ + bool onBegin() + { + move_vector = vec2(0,0); + if(launcher.getKeyState(SDL_SCANCODE_W)) + { + move_vector += vec2(0,1); + } + else if(launcher.getKeyState(SDL_SCANCODE_S)) + { + move_vector += vec2(0,-1); + } + if(launcher.getKeyState(SDL_SCANCODE_A)) + { + move_vector += vec2(-1,0); + } + else if(launcher.getKeyState(SDL_SCANCODE_D)) + { + move_vector += vec2(1,0); + } + + if(move_vector.x != 0 ||move_vector.y != 0) + { + move_vector = move_vector / sqrtf(move_vector.x * move_vector.x + move_vector.y * move_vector.y); + return true; + } + //don't call system update because no key pressed + return false; + } + + /** + *Update is called multiple times in one "manager.update()" call. + *Number of "onUpdate" calls is count of buffers which must be updated during pass. + *When multithreading is used, number of "onUpdate" calls can be greater due to fact that + *JobSystem can split buffers for better data packing. + */ + void onUpdate(EntitiesData data) + { + /*if(move_vector.x == 0) + { + foreach(i; 0..data.length) + { + data.textures[i].coords = vec4(0*px,80*px,48*px,32*px); + } + //return; + }*/ + //move every entity using movement vector + //if(move_vector.x != 0 || move_vector.y != 0) + foreach(i; 0..data.length) + { + data.velocity[i] += move_vector * launcher.delta_time * 0.005; + if(data.velocity[i].x > 0.5)data.velocity[i].x = 0.5; + else if(data.velocity[i].x < -0.5)data.velocity[i].x = -0.5; + if(data.velocity[i].y > 0.5)data.velocity[i].y = 0.5; + else if(data.velocity[i].y < -0.5)data.velocity[i].y = -0.5; + //data.locations[i].x += move_vector.x * launcher.delta_time * 0.25; + //data.locations[i].y += move_vector.y * launcher.delta_time * 0.25; + //if(move_vector.x > 0)data.textures[i].coords = vec4(48*px,80*px,48*px,32*px); + //else data.textures[i].coords = vec4(0*px,80*px,48*px,32*px); + } + /*else + foreach(i; 0..data.length) + { + data.velocity[i] = vec2(0,0); + }*/ + } } \ No newline at end of file diff --git a/demos/source/game_core/collision.d b/demos/source/game_core/collision.d new file mode 100644 index 0000000..75c46f8 --- /dev/null +++ b/demos/source/game_core/collision.d @@ -0,0 +1,232 @@ +module game_core.collision; + +import bubel.ecs.attributes; +import bubel.ecs.core; +import bubel.ecs.std; + +import ecs_utils.math.vector; + +import game_core.basic; + + +void registerCollisionModule(EntityManager* manager) +{ + manager.registerDependency(ShootGridDependency); + + manager.registerComponent!CShootGrid; + manager.registerComponent!CShootGridMask; + manager.registerComponent!CColliderScale; + + manager.registerSystem!ShootGridManager(-80); + manager.registerSystem!ShootGridCleaner(-101); +} + +enum ShootGridDependency = "ShootGridDependency"; + +struct CShootGrid +{ + mixin ECS.Component; +} + +struct CShootGridMask +{ + mixin ECS.Component; + + alias value this; + + ubyte value; +} + +struct CColliderScale +{ + mixin ECS.Component; + + alias value this; + + vec2 value = vec2(16,16); +} + +struct ShootGrid +{ + + ~this() @nogc nothrow + { + if(nodes)Mallocator.dispose(nodes); + if(masks)Mallocator.dispose(masks); + } + + struct Node + { + alias entity this; + + EntityID entity; + } + + void create(ivec2 nodes_count, vec2 node_size) + { + this.size = nodes_count; + this.node_size = node_size; + inv_node_size = vec2(1.0/node_size.x, 1.0/node_size.y); + nodes = Mallocator.makeArray!Node(nodes_count.x * nodes_count.y); + masks = Mallocator.makeArray!ubyte(nodes.length); + } + + void mark(EntityID id, vec2 beg, vec2 end, ubyte mask) + { + ivec2 ibeg = cast(ivec2)(beg * inv_node_size); + ivec2 iend = cast(ivec2)(end * inv_node_size + 0.5); + if(ibeg.x < 0)ibeg.x = 0; + if(ibeg.y < 0)ibeg.y = 0; + if(iend.x > size.x)iend.x = size.x; + if(iend.y > size.y)iend.y = size.y; + foreach(i; ibeg.y .. iend.y) + { + foreach(j; ibeg.x .. iend.x) + { + nodes[i * size.x + j] = id; + masks[i * size.x +j] = mask; + } + } + } + + void clear() + { + size_t size = nodes.length * EntityID.sizeof; + memset(nodes.ptr, 0, size); + memset(masks.ptr, 0, masks.length); + } + + bool test(out EntityID id, vec2 beg, vec2 end, ubyte mask) + { + ivec2 ibeg = cast(ivec2)(beg * inv_node_size); + ivec2 iend = cast(ivec2)(end * inv_node_size + 0.5); + if(ibeg.x < 0)ibeg.x = 0; + if(ibeg.y < 0)ibeg.y = 0; + if(iend.x > size.x)iend.x = size.x; + if(iend.y > size.y)iend.y = size.y; + foreach(i; ibeg.y .. iend.y) + { + foreach(j; ibeg.x .. iend.x) + { + uint index = i * size.x + j; + if(nodes[index].id != 0) + { + if((masks[index] & mask) == 0)continue; + id = nodes[index]; + return true; + } + } + } + return false; + } + + bool test(out EntityID id, vec2 pos, ubyte mask) + { + ivec2 ipos = cast(ivec2)(pos * inv_node_size - 0.5); + if(ipos.x < 0)ipos.x = 0; + if(ipos.y < 0)ipos.y = 0; + if(ipos.x >= size.x)ipos.x = size.x - 1; + if(ipos.y >= size.y)ipos.y = size.y - 1; + size_t index = ipos.y * size.x + ipos.x; + if((masks[index] & mask) == 0)return false; + if(nodes[index].id != 0) + { + id = nodes[index]; + return true; + } + return false; + } + + vec2 inv_node_size; + ivec2 size; + vec2 node_size; + Node[] nodes; + ubyte[] masks; +} + +struct ShootGridCleaner +{ + mixin ECS.System!1; + + struct EntitiesData + { + + } + + ShootGrid* grid; + + bool onBegin() + { + grid = gEM.getSystem!ShootGridManager().grid; + if(grid != null)return true; + else return false; + } + + void onUpdate(EntitiesData data) + { + if(grid)grid.clear(); + } +} + +struct ShootGridManager +{ + mixin ECS.System!128; + + mixin ECS.WritableDependencies!(ShootGridDependency); + + struct EntitiesData + { + uint length; + //uint thread_id; + const (Entity)[] entity; + @readonly CLocation[] locations; + @readonly CShootGrid[] grid_flag; + //@readonly CGuild[] guild; + @optional @readonly CShootGridMask[] mask; + @optional @readonly CScale[] scale; + @optional @readonly CColliderScale[] collider_scale; + } + + ShootGrid* grid; + + void onCreate() + { + //grid = space_invaders.shoot_grid; + grid = Mallocator.make!ShootGrid; + grid.create(ivec2(80,60), vec2(5,5)); + } + + void onDestroy() + { + Mallocator.dispose(grid); + } + + // bool onBegin() + // { + // //if(!grid)return false; + // //grid.clear(); + // return true; + // } + + void onUpdate(EntitiesData data) + { + vec2[] scale; + if(data.collider_scale)scale = cast(vec2[])data.collider_scale; + else if(data.scale)scale = cast(vec2[])data.scale; + else return; + if(data.mask is null) + { + foreach(i; 0..data.length) + { + vec2 half_scale = scale[i] * 0.5; + grid.mark(data.entity[i].id, data.locations[i] - half_scale, data.locations[i] + half_scale, ubyte.max);//cast(ubyte)(1 << data.guild[i].guild)); + } + } + else foreach(i; 0..data.length) + { + vec2 half_scale = scale[i] * 0.5; + grid.mark(data.entity[i].id, data.locations[i] - half_scale, data.locations[i] + half_scale, data.mask[i]);//cast(ubyte)(1 << data.guild[i].guild)); + } + + } +} \ No newline at end of file diff --git a/demos/source/gui/manager.d b/demos/source/gui/manager.d index 3745d9d..b3381ef 100644 --- a/demos/source/gui/manager.d +++ b/demos/source/gui/manager.d @@ -213,7 +213,7 @@ struct GUIManager static if(hasUDA!(member,GUIRange)) { comp_edit.variables[comp_edit.used-1].int_.min = getUDAs!(member,GUIRange)[0].min; - comp_edit.variables[comp_edit.used-1].int_.max = getUDAs!(member,GUIRange)[1].max; + comp_edit.variables[comp_edit.used-1].int_.max = getUDAs!(member,GUIRange)[0].max; } /*{ comp_edit.variables[comp_edit.used-1].int_.min = int.min; diff --git a/demos/source/gui/system.d b/demos/source/gui/system.d index 112bed3..b4899fb 100644 --- a/demos/source/gui/system.d +++ b/demos/source/gui/system.d @@ -5,7 +5,8 @@ import bubel.ecs.system; struct SystemGUI { const (char)* name; - System* system; + //System* system; + ushort id; bool enabled = true; } \ No newline at end of file diff --git a/demos/source/gui/tool_circle.d b/demos/source/gui/tool_circle.d index c43ade3..c8968d4 100644 --- a/demos/source/gui/tool_circle.d +++ b/demos/source/gui/tool_circle.d @@ -26,6 +26,7 @@ struct ToolCircle void draw(Renderer* renderer, vec2 position, float size, float edge = 1) { + glDisable(GL_DEPTH_TEST); position = position * renderer.view_size + renderer.view_pos; vec2 sizes = renderer.view_size * size; vec2 sizes2 = vec2(edge,0); diff --git a/demos/utils/source/ecs_utils/math/vector.d b/demos/utils/source/ecs_utils/math/vector.d index adb3a36..c835d05 100644 --- a/demos/utils/source/ecs_utils/math/vector.d +++ b/demos/utils/source/ecs_utils/math/vector.d @@ -95,6 +95,11 @@ struct vec2 } } +float dot(vec2 a, vec2 b) +{ + return a.x*b.x + a.y*b.y; +} + struct vec4 { union From 96bbcb9956cd8e0d3cc2fcceb8c0d0126d41abf8 Mon Sep 17 00:00:00 2001 From: Mergul Date: Fri, 17 Jul 2020 13:34:08 +0200 Subject: [PATCH 165/217] Fixed issues and bugs -moved system destroy functionality to System structure "destroy()" function -now arrays are properly destroyed (with destructor calling (__xdtor)) -fixed bug which makes BlockAllocator crashing after freeing it's memory -fixed many smaller memory leaks --- source/bubel/ecs/block_allocator.d | 1 + source/bubel/ecs/manager.d | 44 ++++++++++-------------------- source/bubel/ecs/simple_vector.d | 6 ++++ source/bubel/ecs/std.d | 43 +++++++++++++++++++++++------ source/bubel/ecs/system.d | 32 ++++++++++++++++++++++ 5 files changed, 87 insertions(+), 39 deletions(-) diff --git a/source/bubel/ecs/block_allocator.d b/source/bubel/ecs/block_allocator.d index d3070c4..6894a17 100644 --- a/source/bubel/ecs/block_allocator.d +++ b/source/bubel/ecs/block_allocator.d @@ -54,6 +54,7 @@ struct BlockAllocator Mallocator.dispose(pointers); pointers = next_pointers; } + next_block = null; } private: diff --git a/source/bubel/ecs/manager.d b/source/bubel/ecs/manager.d index 7fb79f8..c26a414 100644 --- a/source/bubel/ecs/manager.d +++ b/source/bubel/ecs/manager.d @@ -96,29 +96,7 @@ export struct EntityManager { foreach (ref system; systems) { - system.disable(); - if (system.m_destroy) - (cast(void function(void*)) system.m_destroy)(system.m_system_pointer); - - if (system.jobs) - Mallocator.dispose(system.jobs); - if (system.m_read_only_components) - Mallocator.dispose(system.m_read_only_components); - if (system.m_writable_components) - Mallocator.dispose(system.m_writable_components); - if (system.m_components) - Mallocator.dispose(system.m_components); - if (system.m_excluded_components) - Mallocator.dispose(system.m_excluded_components); - if (system.m_optional_components) - Mallocator.dispose(system.m_optional_components); - if (system.m_name) - Mallocator.dispose(system.m_name); - if (system.m_event_callers) - Mallocator.dispose(system.m_event_callers); - - if (system.m_system_pointer) - Mallocator.dispose(system.m_system_pointer); + system.destroy(); } foreach (EntityInfo* info; &entities_infos.byValue) @@ -425,7 +403,8 @@ export struct EntityManager enum EventName = fullName!(Unqual!(EventParamType)); // enum EventName = fullyQualifiedName!(Unqual!(EventParamType));//.stringof; ushort evt = events_map.get(cast(char[]) EventName, ushort.max); - assert(evt != ushort.max, "Can't register system \"" ~ SystemName + assert(evt != ushort.max, + "Can't register system \"" ~ SystemName ~ "\" due to non existing event \"" ~ EventName ~ "\"."); callers[i].callback = cast(void*)&callEventHandler!(EventParamType); @@ -1188,10 +1167,9 @@ export struct EntityManager ushort sys_id = systems_map.get(cast(char[]) SystemName, ushort.max); if (sys_id < systems.length) { - systems[sys_id].disable(); - if (systems[sys_id].m_destroy) - (cast(void function(void*)) systems[sys_id].m_destroy)( - systems[sys_id].m_system_pointer); + system.m_name = systems[sys_id].m_name; + systems[sys_id].m_name = null; + systems[sys_id].destroy(); if (system.m_create) (cast(void function(void*)) system.m_create)(system.m_system_pointer); @@ -1199,7 +1177,6 @@ export struct EntityManager system.enable(); system.m_id = sys_id; - system.m_name = systems[sys_id].m_name; systems[sys_id] = system; } else @@ -1307,6 +1284,8 @@ export struct EntityManager if (comp_id < components.length) { Comp.component_id = comp_id; + if (components[comp_id].init_data) + Mallocator.dispose(components[comp_id].init_data); components[comp_id] = info; } else @@ -1874,7 +1853,8 @@ export struct EntityManager foreach (i, id; ids) { - if(current_delta == 0)current_delta = ushort.max; + if (current_delta == 0) + current_delta = ushort.max; alignNum(current_delta, components[id].alignment); info.deltas[id] = cast(ushort) current_delta; current_delta += entites_in_block * components[id].size; @@ -3548,6 +3528,10 @@ export struct EntityManager Mallocator.dispose(deltas); if (tmpl_deltas) Mallocator.dispose(tmpl_deltas); + if (comp_add_info) + Mallocator.dispose(comp_add_info); + if (comp_rem_info) + Mallocator.dispose(comp_rem_info); if (systems) Mallocator.dispose(systems); if (add_listeners) diff --git a/source/bubel/ecs/simple_vector.d b/source/bubel/ecs/simple_vector.d index bb4b610..acf01ee 100644 --- a/source/bubel/ecs/simple_vector.d +++ b/source/bubel/ecs/simple_vector.d @@ -12,6 +12,12 @@ struct SimpleVector { @disable this(this); + + ~this() nothrow @nogc + { + if(data) + Mallocator.dispose(data); + } ///Add element to vector void add(ubyte el) nothrow @nogc diff --git a/source/bubel/ecs/std.d b/source/bubel/ecs/std.d index 38ad0d8..d99a05c 100644 --- a/source/bubel/ecs/std.d +++ b/source/bubel/ecs/std.d @@ -156,7 +156,7 @@ static struct Mallocator { T[] ret; - if(length > array.length) + if (length > array.length) { ret = (cast(T*) realloc(array.ptr, T.sizeof * length))[0 .. length]; static if (__traits(isPOD, T)) @@ -178,21 +178,25 @@ static struct Mallocator } } } - else + else { static if (__traits(hasMember, T, "__xdtor")) + { foreach (i; length .. array.length) { array[i].__xdtor(); } + } else static if (__traits(hasMember, T, "__dtor")) + { foreach (i; length .. array.length) { array[i].__dtor(); } + } ret = (cast(T*) realloc(array.ptr, T.sizeof * length))[0 .. length]; } - + return ret; } @@ -297,13 +301,34 @@ static struct Mallocator return ret; } - static void dispose(T)(T object) nothrow @nogc + static void dispose(T)(T object) { - static if (__traits(hasMember, T, "__xdtor")) - object.__xdtor(); - else static if (__traits(hasMember, T, "__dtor")) - object.__dtor(); - free(cast(void*) object); + static if (isArray!T) + { + alias TT = PointerTarget!(typeof(object.ptr)); + static if (!isPointer!TT) + { + static if (__traits(hasMember, TT, "__xdtor")) + { + foreach (ref TT t; object) + t.__xdtor(); + } + else static if (__traits(hasMember, TT, "__dtor")) + { + foreach (TT t; object) + t.__dtor(); + } + } + free(cast(void*) object.ptr); + } + else + { + static if (__traits(hasMember, T, "__xdtor")) + object.__xdtor(); + else static if (__traits(hasMember, T, "__dtor")) + object.__dtor(); + free(cast(void*) object); + } } static void alignDispose(T)(T object) diff --git a/source/bubel/ecs/system.d b/source/bubel/ecs/system.d index 7bcaf01..cd8d2e3 100644 --- a/source/bubel/ecs/system.d +++ b/source/bubel/ecs/system.d @@ -91,6 +91,38 @@ struct System package: + void destroy() + { + import bubel.ecs.std : Mallocator; + disable(); + if (m_destroy) + (cast(void function(void*)) m_destroy)(m_system_pointer); + + if (m_name) + Mallocator.dispose(m_name); + if (m_components) + Mallocator.dispose(m_components); + if (m_excluded_components) + Mallocator.dispose(m_excluded_components); + if (m_optional_components) + Mallocator.dispose(m_optional_components); + if (jobs) + Mallocator.dispose(jobs); + if (m_read_only_components) + Mallocator.dispose(m_read_only_components); + if (m_writable_components) + Mallocator.dispose(m_writable_components); + if (m_readonly_dependencies) + Mallocator.dispose(m_readonly_dependencies); + if (m_writable_dependencies) + Mallocator.dispose(m_writable_dependencies); + if (m_event_callers) + Mallocator.dispose(m_event_callers); + + if (m_system_pointer) + Mallocator.dispose(m_system_pointer); + } + struct EventCaller { ushort id; From 64dc099e0a868595ae855b43105fdc8cb0b78f2c Mon Sep 17 00:00:00 2001 From: Mergul Date: Fri, 17 Jul 2020 13:38:41 +0200 Subject: [PATCH 166/217] Demos big update -Added some more math functions -fixed many memory leaks -added AABB and BVHTree support to collision.d *BVHTree has only incrementally adding entities implemented by now (and bad BottomUp algorithm) *ECS Systems use two trees, one for static and one for dynamic entities, dynamic BVH is builded every frame from scratch by now -BrickBreaker now uses BVHTree to collision detection *balls only use tree for checks (they aren't adding to tree) -fixed bug leading to crash --- demos/source/app.d | 19 +- demos/source/demos/brick_breaker.d | 202 ++++-- demos/source/demos/snake.d | 4 +- demos/source/demos/space_invaders.d | 5 +- demos/source/game_core/collision.d | 793 ++++++++++++++++++++- demos/source/gui/manager.d | 6 + demos/utils/source/ecs_utils/gfx/texture.d | 7 +- demos/utils/source/ecs_utils/math/vector.d | 5 + demos/utils/source/ecs_utils/utils.d | 2 + 9 files changed, 973 insertions(+), 70 deletions(-) diff --git a/demos/source/app.d b/demos/source/app.d index 1dbf9f4..5879daf 100644 --- a/demos/source/app.d +++ b/demos/source/app.d @@ -117,12 +117,12 @@ struct Launcher gui_manager.clear(); //launcher.ent - if(this.demo.deinitialize)this.demo.deinitialize(); - manager.begin(); manager.update("clean"); manager.end(); + if(this.demo.deinitialize)this.demo.deinitialize(); + foreach(ref system; manager.systems) { if(system.id != CountSystem.system_id && system.id != CleanSystem.system_id)system.disable(); @@ -946,12 +946,19 @@ void mainLoop(void* arg) void quit() { + import game_core.rendering : TexCoordsManager; launcher.gui_manager.clear(); Mallocator.dispose(launcher.gui_manager); + if(launcher.demo.deinitialize)launcher.demo.deinitialize(); + launcher.manager.destroy(); launcher.manager = null; + TexCoordsManager.destroy(); + + SDL_Quit(); + version(WebAssembly)emscripten_cancel_main_loop(); } @@ -1060,10 +1067,11 @@ int app_main(int argc, char** argv) } } - ImFontConfig* config = ImFontConfig_ImFontConfig(); + //ImFontConfig* config = ImFontConfig_ImFontConfig(); ImGuiIO* io = igGetIO(); const ushort* font_ranges = ImFontAtlas_GetGlyphRangesDefault(io.Fonts); - ImFontAtlas_AddFontFromFileTTF(io.Fonts,"assets/fonts/Ruda-Bold.ttf", 15.0f, config, font_ranges); + ImFontAtlas_AddFontFromFileTTF(io.Fonts,"assets/fonts/Ruda-Bold.ttf", 15.0f, null, font_ranges); + //ImFontConfig_destroy(config); setStyle(3); @@ -1139,9 +1147,6 @@ int app_main(int argc, char** argv) } } - TexCoordsManager.destroy(); - EntityManager.destroy(); - return 0; } diff --git a/demos/source/demos/brick_breaker.d b/demos/source/demos/brick_breaker.d index ec4571f..c15c503 100644 --- a/demos/source/demos/brick_breaker.d +++ b/demos/source/demos/brick_breaker.d @@ -54,6 +54,15 @@ struct CBall ubyte radius; } +struct CHitPoints +{ + mixin ECS.Component; + + alias value this; + + short value; +} + // struct CVelocityFactor // { // mixin ECS.Component; @@ -72,6 +81,13 @@ struct CBall // vec2 value = vec2(0); // } +struct EDamage +{ + mixin ECS.Event; + + ubyte damage = 1; +} + /*####################################################################################################################### ------------------------------------------------ Systems ------------------------------------------------------------------ #######################################################################################################################*/ @@ -152,7 +168,7 @@ struct BallCollisionSystem { mixin ECS.System!64; - mixin ECS.ReadOnlyDependencies!(ShootGridDependency); + mixin ECS.ReadOnlyDependencies!(ShootGridDependency, BVHDependency); struct EntitiesData { @@ -165,72 +181,136 @@ struct BallCollisionSystem @readonly CBall[] ball_flag; } + struct State + { + bool test(EntityID id) + { + Entity* entity = launcher.manager.getEntity(id); + if(entity) + { + CLocation* location = entity.getComponent!CLocation; + CScale* scale = entity.getComponent!CScale; + if(location && scale) + { + float radius = data.scale[i].x; + vec2 rel_pos = *location - data.location[i]; + vec2 abs_rel_pos = rel_pos; + if(abs_rel_pos.x < 0)abs_rel_pos.x = -abs_rel_pos.x; + if(abs_rel_pos.y < 0)abs_rel_pos.y = -abs_rel_pos.y; + + vec2 half_scale = *scale * 0.25f; + + if(abs_rel_pos.x < half_scale.x + radius && + abs_rel_pos.y < half_scale.y + radius) + { + if(abs_rel_pos.x < half_scale.x) + { + if(rel_pos.y * data.velocity[i].y > 0) + { + data.velocity[i].y = -data.velocity[i].y; + launcher.manager.sendEvent(id,EDamage(1)); + return false; + } + } + else if(abs_rel_pos.y < half_scale.y) + { + if(rel_pos.x * data.velocity[i].x > 0) + { + data.velocity[i].x = -data.velocity[i].x; + launcher.manager.sendEvent(id,EDamage(1)); + return false; + } + } + else + { + vec2 vector = abs_rel_pos - half_scale; + if(rel_pos.x > 0)vector.x = -vector.x; + if(rel_pos.y > 0)vector.y = -vector.y; + + float pow_dist = vector.length2(); + if(pow_dist < radius*radius) + { + vector = vector / sqrtf(pow_dist); + data.velocity[i] = data.velocity[i] - vector * (2 * dot(vector, data.velocity[i])); + launcher.manager.sendEvent(id,EDamage(1)); + return false; + } + } + } + } + } + return true; + } + + EntitiesData data; + uint i; + } + ShootGrid* grid; + BVHTree* tree; + BVHTree* static_tree; bool onBegin() { - grid = launcher.manager.getSystem!ShootGridManager().grid; - if(grid is null)return false; + //grid = launcher.manager.getSystem!ShootGridManager().grid; + tree = launcher.manager.getSystem!BVHBuilder().tree; + static_tree = launcher.manager.getSystem!StaticBVHBuilder().tree; + //if(grid is null)return false; + if(tree is null || static_tree is null)return false; else return true; } void onUpdate(EntitiesData data) { - EntityID id; + // State state; + // state.data = data; + // EntityID id; + // foreach(i; 0..data.length) + // { + // state.i = i; + // float radius = data.scale[i].x; + // if(grid.test(id, data.location[i] - radius, data.location[i] + radius, ubyte.max)) + // { + // state.test(id); + // } + // } + State state; + state.data = data; foreach(i; 0..data.length) { - float radius = data.scale[i].x; - //if(grid.test(id, data.location[i], ubyte.max)) - if(grid.test(id, data.location[i] - radius, data.location[i] + radius, ubyte.max)) - { - Entity* entity = launcher.manager.getEntity(id); - if(entity) - { - CLocation* location = entity.getComponent!CLocation; - CScale* scale = entity.getComponent!CScale; - if(location && scale) - { - vec2 rel_pos = *location - data.location[i]; - vec2 abs_rel_pos = rel_pos; - if(abs_rel_pos.x < 0)abs_rel_pos.x = -abs_rel_pos.x; - if(abs_rel_pos.y < 0)abs_rel_pos.y = -abs_rel_pos.y; - - vec2 half_scale = *scale * 0.25f; - - if(abs_rel_pos.x < half_scale.x + radius && - abs_rel_pos.y < half_scale.y + radius) - { - if(abs_rel_pos.x < half_scale.x) - { - if(rel_pos.y * data.velocity[i].y > 0)data.velocity[i].y = -data.velocity[i].y; - } - else if(abs_rel_pos.y < half_scale.y) - { - if(rel_pos.x * data.velocity[i].x > 0)data.velocity[i].x = -data.velocity[i].x; - } - else - { - vec2 vector = abs_rel_pos - half_scale; - if(rel_pos.x > 0)vector.x = -vector.x; - if(rel_pos.y > 0)vector.y = -vector.y; - - float pow_dist = vector.length2(); - if(pow_dist < radius*radius) - { - vector = vector / sqrtf(pow_dist); - data.velocity[i] = data.velocity[i] - vector * (2 * dot(vector, data.velocity[i])); - } - } - } - } - } - //launcher.manager.sendEvent(id, EBulletHit(data.entity[i].id,data.bullet[i].damage)); - //launcher.manager.removeEntity(data.entity[i].id); - } + state.i = i; + //float radius = data.scale[i].x; + AABB bounding = AABB(data.location[i]-data.scale[i], data.location[i]+data.scale[i]); + tree.test(bounding, cast(bool delegate(EntityID id))&state.test); + static_tree.test(bounding, cast(bool delegate(EntityID id))&state.test); } } } +struct DamageSystem +{ + mixin ECS.System!64; + + mixin ECS.ReadOnlyDependencies!(ShootGridDependency); + + struct EntitiesData + { + ///variable named "length" contain entites count + uint length; + const (Entity)[] entity; + CHitPoints[] hit_points; + } + + void handleEvent(Entity* entity, EDamage event) + { + EntityMeta meta = entity.getMeta(); + CHitPoints* hp = meta.getComponent!CHitPoints; + hp.value -= event.damage; + if(hp.value < 0)launcher.manager.removeEntity(entity.id); + } + +} + /*####################################################################################################################### ------------------------------------------------ Functions ------------------------------------------------------------------ #######################################################################################################################*/ @@ -239,7 +319,7 @@ struct BrickBreakerDemo { __gshared const (char)* tips = "Brick breaker demo. It's a game about destroying evil bricks."; - EntityTemplate* tmpl; + //EntityTemplate* tmpl; Texture texture; } @@ -268,12 +348,16 @@ void brickBreakerRegister() launcher.manager.registerComponent!CDamping; launcher.manager.registerComponent!CVelocityFactor; launcher.manager.registerComponent!CBall; + launcher.manager.registerComponent!CHitPoints; + + launcher.manager.registerEvent!EDamage; launcher.manager.registerSystem!MoveSystem(-100); launcher.manager.registerSystem!EdgeCollisionSystem(-99); launcher.manager.registerSystem!BallCollisionSystem(-79); launcher.manager.registerSystem!InputMovementSystem(-120); launcher.manager.registerSystem!DampingSystem(-120); + launcher.manager.registerSystem!DamageSystem(-120); launcher.manager.endRegister(); } @@ -289,11 +373,14 @@ void brickBreakerStart() EntityTemplate* brick_tmpl = launcher.manager.allocateTemplate( [CLocation.component_id, CScale.component_id, CColor.component_id, - CTexCoordsIndex.component_id, CShootGrid.component_id].staticArray + CTexCoordsIndex.component_id, CBVH.component_id, CHitPoints.component_id, + CAABB.component_id, CStatic.component_id].staticArray ); brick_tmpl.getComponent!CTexCoordsIndex().value = TexCoordsManager.instance.getCoordIndex(vec4(304,40,16,8)*px); brick_tmpl.getComponent!CColor().value = 0x80206020; brick_tmpl.getComponent!CScale().value = vec2(16,8); + brick_tmpl.getComponent!CHitPoints().value = 2; + //brick_tmpl.getComponent!CAABB().bounding = AABB(vec2(),vec2()); EntityTemplate* big_brick_tmpl = launcher.manager.allocateTemplate(brick_tmpl); big_brick_tmpl.getComponent!CTexCoordsIndex().value = TexCoordsManager.instance.getCoordIndex(vec4(320,32,16,16)*px); @@ -302,7 +389,8 @@ void brickBreakerStart() EntityTemplate* paddle_tmpl = launcher.manager.allocateTemplate( [CLocation.component_id, CScale.component_id, CInput.component_id, CTexCoordsIndex.component_id, CPaddle.component_id, CVelocity.component_id, - CDamping.component_id, CVelocityFactor.component_id, CShootGrid.component_id].staticArray + CDamping.component_id, CVelocityFactor.component_id, CBVH.component_id, + CAABB.component_id].staticArray ); paddle_tmpl.getComponent!CTexCoordsIndex().value = TexCoordsManager.instance.getCoordIndex(vec4(272,48,64,10)*px); paddle_tmpl.getComponent!CScale().value = vec2(64,10); @@ -330,7 +418,11 @@ void brickBreakerStart() launcher.gui_manager.addComponent(CBall(), "Ball"); launcher.gui_manager.addSystem(MoveSystem.system_id, "Move System"); + launcher.gui_manager.addSystem(EdgeCollisionSystem.system_id, "Edge Collision System"); launcher.gui_manager.addSystem(BallCollisionSystem.system_id, "Ball Collision System"); + launcher.gui_manager.addSystem(InputMovementSystem.system_id, "Input Movement System"); + launcher.gui_manager.addSystem(DampingSystem.system_id, "Damping System"); + launcher.gui_manager.addSystem(DamageSystem.system_id, "Damage System"); launcher.gui_manager.addTemplate(brick_tmpl, "Brick"); launcher.gui_manager.addTemplate(big_brick_tmpl, "Big Brick"); diff --git a/demos/source/demos/snake.d b/demos/source/demos/snake.d index 525b4ab..865ab75 100644 --- a/demos/source/demos/snake.d +++ b/demos/source/demos/snake.d @@ -72,7 +72,7 @@ struct Snake bool move_system = true; bool draw_system = true; - const int map_size = 18; + enum int map_size = 18; MapElement[map_size * map_size] map; @@ -83,7 +83,7 @@ struct Snake if(apple_tmpl)launcher.manager.freeTemplate(apple_tmpl); if(snake_tmpl)launcher.manager.freeTemplate(snake_tmpl); if(snake_destroy_particle)launcher.manager.freeTemplate(snake_destroy_particle); - texture.destory(); + texture.destroy(); } MapElement element(ivec2 pos) diff --git a/demos/source/demos/space_invaders.d b/demos/source/demos/space_invaders.d index 66be099..ece3c2b 100644 --- a/demos/source/demos/space_invaders.d +++ b/demos/source/demos/space_invaders.d @@ -64,7 +64,7 @@ struct SpaceInvaders { if(tmpl)launcher.manager.freeTemplate(tmpl); } - texture.destory(); + texture.destroy(); } } @@ -90,7 +90,7 @@ struct SceneGrid cells = Mallocator.makeArray!Cell(cells_count.x * cells_count.y); } - void destory() + void destroy() { if(cells) { @@ -707,6 +707,7 @@ struct ShipWeaponSystem void onDestroy() { + __xdtor(); /*launcher.manager.freeTemplate(laser1_tmpl); launcher.manager.freeTemplate(laser2_tmpl); launcher.manager.freeTemplate(main_weapon_tmpl);*/ diff --git a/demos/source/game_core/collision.d b/demos/source/game_core/collision.d index 75c46f8..794f8d8 100644 --- a/demos/source/game_core/collision.d +++ b/demos/source/game_core/collision.d @@ -1,10 +1,13 @@ module game_core.collision; import bubel.ecs.attributes; +import bubel.ecs.block_allocator; import bubel.ecs.core; import bubel.ecs.std; +import bubel.ecs.vector; import ecs_utils.math.vector; +import ecs_utils.utils; import game_core.basic; @@ -12,22 +15,54 @@ import game_core.basic; void registerCollisionModule(EntityManager* manager) { manager.registerDependency(ShootGridDependency); + manager.registerDependency(BVHDependency); + manager.registerDependency(StaticBVHDependency); manager.registerComponent!CShootGrid; manager.registerComponent!CShootGridMask; manager.registerComponent!CColliderScale; + manager.registerComponent!CBVH; + manager.registerComponent!CAABB; + manager.registerComponent!CStatic; manager.registerSystem!ShootGridManager(-80); manager.registerSystem!ShootGridCleaner(-101); + manager.registerSystem!BVHBuilder(-80); + manager.registerSystem!StaticBVHBuilder(-80); + //manager.registerSystem!BVHBuilder2(-79); + manager.registerSystem!AABBUpdater(-81); } enum ShootGridDependency = "ShootGridDependency"; +enum BVHDependency = "BVHDependency"; +enum StaticBVHDependency = "StaticBVHDependency"; struct CShootGrid { mixin ECS.Component; } +struct CBVH +{ + mixin ECS.Component; + + uint index; +} + +struct CStatic +{ + mixin ECS.Component; +} + +struct CAABB +{ + mixin ECS.Component; + + alias bounding this; + + AABB bounding; +} + struct CShootGridMask { mixin ECS.Component; @@ -46,6 +81,7 @@ struct CColliderScale vec2 value = vec2(16,16); } + struct ShootGrid { @@ -84,7 +120,7 @@ struct ShootGrid foreach(j; ibeg.x .. iend.x) { nodes[i * size.x + j] = id; - masks[i * size.x +j] = mask; + masks[i * size.x + j] = mask; } } } @@ -229,4 +265,759 @@ struct ShootGridManager } } +} + +struct AABB +{ + vec2 size() + { + return max-min; + } + + vec2 center() + { + return (max+min) * 0.5; + } + + float area() + { + return size.x * size.y; + } + + void set(ref AABB base, vec2 position, float angle, vec2 scale) + { + import std.algorithm.comparison : max; + + float sr = sinf(angle); + float cr = cosf(angle); + /*mat2 m = mat2(cr,-sr, + sr,cr);*/ + + + //vec2 pos = ;//m * ((base.max + base.min)*0.5*scale); + vec2 size = (base.max - base.min)*scale; + vec2[2] axis = [vec2(cr*size.x,sr*size.y),vec2(-sr*size.x,cr*size.y)]; + + this.max.x = max(fabs(axis[0].x),fabs(axis[1].x)); + this.max.y = max(fabs(axis[0].y),fabs(axis[1].y)); + + this.min = -this.max; + + this.min += center + position; + this.max += center + position; + } + + void set(ref AABB base, vec2 position, vec2 scale) + { + vec2 size = (base.max - base.min)*scale; + + this.min = -size; + this.max = size; + + this.min += center + position; + this.max += center + position; + } + + void set(ref AABB base, vec2 position, float angle) + { + import std.algorithm.comparison : max; + + float sr = sinf(angle); + float cr = cosf(angle); + /*mat2 m = mat2(cr,-sr, + sr,cr);*/ + + + //vec2 pos = ;//m * ((base.max + base.min)*0.5*scale); + vec2 size = (base.max - base.min);//*scale; + vec2[2] axis = [vec2(cr*size.x,sr*size.y),vec2(-sr*size.x,cr*size.y)]; + + this.max.x = max(fabs(axis[0].x),fabs(axis[1].x)); + this.max.y = max(fabs(axis[0].y),fabs(axis[1].y)); + + this.min = -this.max; + + this.min += center + position; + this.max += center + position; + } + + void set(ref AABB base, vec2 position) + { + min = base.min + position; + max = base.max + position; + } + + vec2 min; + vec2 max; +} + +bool test(AABB a, AABB b) +{ + if((a.max.x>b.min.x && a.max.y>b.min.y) && + (a.min.x b.max.x && a.max.y > b.max.y)return 2; + else if((a.max.x>b.min.x && a.max.y>b.min.y) && + (a.min.xb.min.x && point.y>b.min.y) && + (point.x Date: Sat, 22 Aug 2020 11:37:23 +0200 Subject: [PATCH 167/217] ECS fixes -fixed bug with addEntityCopy (on create was called for bad entity, and incorrect block was added to update) -added function to retrieve Component pointer from Entity (not template function) -fixed thread_pool bug --- demos/external/sources/mmutils/thread_pool.d | 4 +-- source/bubel/ecs/entity.d | 30 +++++++++++++++++--- source/bubel/ecs/manager.d | 6 ++-- 3 files changed, 31 insertions(+), 9 deletions(-) diff --git a/demos/external/sources/mmutils/thread_pool.d b/demos/external/sources/mmutils/thread_pool.d index b830026..bd05fe5 100644 --- a/demos/external/sources/mmutils/thread_pool.d +++ b/demos/external/sources/mmutils/thread_pool.d @@ -396,8 +396,8 @@ version (MM_USE_POSIX_THREADS) void start(DG dg) { threadStart = dg; - int ok = pthread_create(&handle, null, &threadRunFunc, cast(void*)&this); - if(!ok)handle = pthread_t(); + int err = pthread_create(&handle, null, &threadRunFunc, cast(void*)&this); + if(err)handle = pthread_t(); //assert(ok == 0); } diff --git a/source/bubel/ecs/entity.d b/source/bubel/ecs/entity.d index 4cd0e70..f713c78 100644 --- a/source/bubel/ecs/entity.d +++ b/source/bubel/ecs/entity.d @@ -34,12 +34,23 @@ struct Entity */ T* getComponent(T)() const { - EntityManager.EntitiesBlock* block = gEM.getMetaData(&this); + /*EntityManager.EntitiesBlock* block = gEM.getMetaData(&this); EntityManager.EntityInfo* info = block.type_info; if (T.component_id >= info.deltas.length || info.deltas[T.component_id] == 0) return null; - return cast(T*)(cast(void*)block + info.deltas[T.component_id] + block.entityIndex(&this) * T.sizeof); + return cast(T*)(cast(void*)block + info.deltas[T.component_id] + block.entityIndex(&this) * T.sizeof);*/ + return cast(T*)getComponent(T.component_id); + } + + void* getComponent(ushort component_id) const + { + EntityManager.EntitiesBlock* block = gEM.getMetaData(&this); + EntityManager.EntityInfo* info = block.type_info; + if (component_id >= info.deltas.length || info.deltas[component_id] == 0) + return null; + + return (cast(void*)block + info.deltas[component_id] + block.entityIndex(&this) * gEM.components[component_id].size); } bool hasComponent(ushort component_id) const @@ -66,10 +77,21 @@ struct EntityMeta T* getComponent(T)() const { - const (EntityManager.EntityInfo)* info = block.type_info; + /*const (EntityManager.EntityInfo)* info = block.type_info; if (T.component_id >= info.deltas.length || info.deltas[T.component_id] == 0) return null; - return cast(T*)(cast(void*)block + block.type_info.deltas[T.component_id] + index * T.sizeof); + return cast(T*)(cast(void*)block + info.deltas[T.component_id] + index * T.sizeof);*/ + return cast(T*)getComponent(T.component_id); + } + + void* getComponent(ushort component_id) const + { + const (EntityManager.EntityInfo)* info = block.type_info; + + if (component_id >= info.deltas.length || info.deltas[component_id] == 0) + return null; + + return (cast(void*)block + info.deltas[component_id] + index * gEM.components[component_id].size); } bool hasComponent(ushort component_id) const diff --git a/source/bubel/ecs/manager.d b/source/bubel/ecs/manager.d index c26a414..8ef4a20 100644 --- a/source/bubel/ecs/manager.d +++ b/source/bubel/ecs/manager.d @@ -2513,17 +2513,17 @@ export struct EntityManager { ushort size = components[comp].size; if (size != 0) - memcpy(cast(void*) new_block + info.deltas[comp] + size * new_id, + memcpy(cast(void*) new_block + info.deltas[comp] + new_id * size, cast(void*) block + info.deltas[comp] + size * index, size); if (components[comp].create_callback) { components[comp].create_callback( - cast(void*) block + info.deltas[comp] + new_id * size); + cast(void*) new_block + info.deltas[comp] + new_id * size); } } - if (new_index == 1 && info.update_block == block) + if (new_index == 1 && info.update_block == new_block) threads[threadID].infosToUpdate.add(info); Entity* new_entity = cast(Entity*) start; From 13c82acad49fe26a3343e488777b20f3cba89234 Mon Sep 17 00:00:00 2001 From: Mergul Date: Fri, 25 Sep 2020 10:50:11 +0200 Subject: [PATCH 168/217] -removed some unused code --- demos/.gitignore | 3 ++- source/bubel/ecs/manager.d | 37 ------------------------------------- 2 files changed, 2 insertions(+), 38 deletions(-) diff --git a/demos/.gitignore b/demos/.gitignore index 974bbb2..d74e2b0 100644 --- a/demos/.gitignore +++ b/demos/.gitignore @@ -15,4 +15,5 @@ !emscripten_shell.html !emscripten_multi_shell.html !compile_android.py -.dub \ No newline at end of file +.dub +Android \ No newline at end of file diff --git a/source/bubel/ecs/manager.d b/source/bubel/ecs/manager.d index 8ef4a20..1514cbc 100644 --- a/source/bubel/ecs/manager.d +++ b/source/bubel/ecs/manager.d @@ -2542,43 +2542,6 @@ export struct EntityManager */ export Entity* addEntity(EntityTemplate* tmpl) { - /*EntityInfo* info = tmpl.info; - - ushort index = 0; - EntitiesBlock* block; - do - { - block = findBlockWithFreeSpaceMT(info); - index = block.added_count.atomicOp!"+="(1); - } - while (block.entities_count + index > info.max_entities); - - uint id = (block.entities_count + index - 1); //block.added_count); - - void* data_begin = block.dataBegin(); - void* start = data_begin + EntityID.sizeof * id; - - foreach (comp; info.components) - { - memcpy(cast(void*) block + info.deltas[comp] + components[comp].size * id, - tmpl.entity_data.ptr + info.tmpl_deltas[comp], components[comp].size); - - if (components[comp].create_callback) - { - components[comp].create_callback( - cast(void*) block + info.deltas[comp] + id * components[comp].size); - } - - } - - if (index == 1) - threads[threadID].infosToUpdate.add(block); - - Entity* entity = cast(Entity*) start; - entity.id = id_manager.getNewID(); - id_manager.update(*entity); //entity.updateID(); - - return entity;*/ return addEntity(tmpl, null); } From a926b79223e4b39387af72fb329ad87789830fde Mon Sep 17 00:00:00 2001 From: Mergul Date: Tue, 29 Sep 2020 18:41:31 +0200 Subject: [PATCH 169/217] -add ecsID template function (get Component/System/Event ID, passes tests) -removed some ECS mixins code --- source/bubel/ecs/core.d | 19 ++--- source/bubel/ecs/entity.d | 9 +-- source/bubel/ecs/events.d | 3 +- source/bubel/ecs/manager.d | 50 +++++++------- source/bubel/ecs/traits.d | 12 ++++ tests/access_perf.d | 2 +- tests/basic.d | 138 ++++++++++++++++++------------------- tests/bugs.d | 12 ++-- tests/perf.d | 16 ++--- 9 files changed, 138 insertions(+), 123 deletions(-) diff --git a/source/bubel/ecs/core.d b/source/bubel/ecs/core.d index c032d21..dc5521f 100644 --- a/source/bubel/ecs/core.d +++ b/source/bubel/ecs/core.d @@ -53,6 +53,7 @@ module bubel.ecs.core; public import bubel.ecs.manager; public import bubel.ecs.entity; +public import bubel.ecs.traits : ecsID; /************************************************************************************************************************ Main struct used as namespace for templates. @@ -60,12 +61,12 @@ Main struct used as namespace for templates. static struct ECS { /************************************************************************************************************************ - Mark structure as System. Should be added on top of structure (before any data). + Set default system parameters (number of parallel jobs) */ mixin template System(uint jobs_count = 32) { - __gshared ushort system_id = ushort.max; - uint __ecs_jobs_count = jobs_count; + // __gshared ushort system_id = ushort.max; + __gshared uint __ecs_jobs_count = jobs_count; } /************************************************************************************************************************ @@ -73,21 +74,21 @@ static struct ECS */ mixin template Component() { - __gshared ushort component_id = ushort.max; + //__gshared ushort component_id = ushort.max; ComponentRef ref_() @nogc nothrow return { - return ComponentRef(&this, component_id); + return ComponentRef(&this, ecsID!(typeof(this))); } } /************************************************************************************************************************ Mark structure as Event. Should be added on top of structure (before any data). */ - mixin template Event() - { - __gshared ushort event_id = ushort.max; - } + // mixin template Event() + // { + // __gshared ushort event_id = ushort.max; + // } /************************************************************************************************************************ Make list of excluded components. This template get structure types as argument. Should be added inside System structure. diff --git a/source/bubel/ecs/entity.d b/source/bubel/ecs/entity.d index f713c78..c1ec9c7 100644 --- a/source/bubel/ecs/entity.d +++ b/source/bubel/ecs/entity.d @@ -8,6 +8,7 @@ module bubel.ecs.entity; import bubel.ecs.system; import bubel.ecs.manager; +import bubel.ecs.traits : ecsID; /************************************************************************************************************************ Entity ID structure. Used as reference to Entity. Pointer to entity should be ever used to store entity reference! @@ -40,7 +41,7 @@ struct Entity return null; return cast(T*)(cast(void*)block + info.deltas[T.component_id] + block.entityIndex(&this) * T.sizeof);*/ - return cast(T*)getComponent(T.component_id); + return cast(T*)getComponent(ecsID!T); } void* getComponent(ushort component_id) const @@ -81,7 +82,7 @@ struct EntityMeta if (T.component_id >= info.deltas.length || info.deltas[T.component_id] == 0) return null; return cast(T*)(cast(void*)block + info.deltas[T.component_id] + index * T.sizeof);*/ - return cast(T*)getComponent(T.component_id); + return cast(T*)getComponent(ecsID!T); } void* getComponent(ushort component_id) const @@ -125,8 +126,8 @@ export struct EntityTemplate */ T* getComponent(T)() nothrow @nogc { - if(T.component_id >= info.tmpl_deltas.length || info.tmpl_deltas[T.component_id] == ushort.max)return null; - return cast(T*)(entity_data.ptr + info.tmpl_deltas[T.component_id]); + if(ecsID!T >= info.tmpl_deltas.length || info.tmpl_deltas[ecsID!T] == ushort.max)return null; + return cast(T*)(entity_data.ptr + info.tmpl_deltas[ecsID!T]); } } diff --git a/source/bubel/ecs/events.d b/source/bubel/ecs/events.d index 64e0c79..65f50a0 100644 --- a/source/bubel/ecs/events.d +++ b/source/bubel/ecs/events.d @@ -4,6 +4,7 @@ import bubel.ecs.block_allocator; import bubel.ecs.entity; import bubel.ecs.manager; import bubel.ecs.std; +import bubel.ecs.traits : ecsID; import std.algorithm.comparison : max; @@ -32,7 +33,7 @@ package struct EventManager { uint block_id = current_index + thread_id; - EventData* data = &events[Ev.event_id]; + EventData* data = &events[ecsID!Ev]; EventBlock* block = data.blocks[block_id]; //EntityManager.EventInfo* info = &manager.events[Ev.event_id]; //event.entity_id = id; diff --git a/source/bubel/ecs/manager.d b/source/bubel/ecs/manager.d index 1514cbc..a830604 100644 --- a/source/bubel/ecs/manager.d +++ b/source/bubel/ecs/manager.d @@ -367,10 +367,10 @@ export struct EntityManager System system; system.m_pass = pass; - static if (!(hasMember!(Sys, "system_id")) || !is(typeof(Sys.system_id) == ushort)) - { - static assert(0, "Add \"mixin ECS.System;\" in top of system structure;"); - } + // static if (!(hasMember!(Sys, "system_id")) || !is(typeof(Sys.system_id) == ushort)) + // { + // static assert(0, "Add \"mixin ECS.System;\" in top of system structure;"); + // } static if (!(hasMember!(Sys, "EntitiesData"))) { @@ -408,7 +408,7 @@ export struct EntityManager ~ "\" due to non existing event \"" ~ EventName ~ "\"."); callers[i].callback = cast(void*)&callEventHandler!(EventParamType); - callers[i].id = EventParamType.event_id; + callers[i].id = ecsID!EventParamType; i++; } } @@ -1125,8 +1125,8 @@ export struct EntityManager system.m_priority = priority; //(cast(Sys*) system.m_system_pointer).__ecsInitialize(); //system.jobs = (cast(Sys*) system.m_system_pointer)._ecs_jobs; - system.jobs = Mallocator.makeArray!(Job)((cast(Sys*) system.m_system_pointer) - .__ecs_jobs_count); + static if(__traits(hasMember, Sys ,"__ecs_jobs_count"))system.jobs = Mallocator.makeArray!(Job)(Sys.__ecs_jobs_count); + else system.jobs = Mallocator.makeArray!(Job)(32); static if (OnUpdateOverloadNum != -1) { @@ -1194,7 +1194,7 @@ export struct EntityManager systems[$ - 1].enable(); } - Sys.system_id = system.id; + ecsID!Sys = system.id; } /************************************************************************************************************************ @@ -1212,9 +1212,9 @@ export struct EntityManager */ Sys* getSystem(Sys)() nothrow @nogc { - if (Sys.system_id >= systems.length) + if (ecsID!Sys >= systems.length) return null; - return cast(Sys*) systems[Sys.system_id].m_system_pointer; + return cast(Sys*) systems[ecsID!Sys].m_system_pointer; } export ushort registerPass(const(char)[] name) @@ -1244,10 +1244,10 @@ export struct EntityManager enum ComponentName = fullName!Comp; // enum ComponentName = Comp.stringof; - static if (!(hasMember!(Comp, "component_id")) || !is(typeof(Comp.component_id) == ushort)) - { - static assert(0, "Add \"mixin ECS.Component;\" in top of component structure;"); - } + // static if (!(hasMember!(Comp, "component_id")) || !is(typeof(Comp.component_id) == ushort)) + // { + // static assert(0, "Add \"mixin ECS.Component;\" in top of component structure;"); + // } static if (hasMember!(Comp, "onDestroy") && isFunction!(Comp.onDestroy) && is(ReturnType!(Comp.onDestroy) == void) @@ -1283,7 +1283,7 @@ export struct EntityManager ushort comp_id = components_map.get(cast(char[]) ComponentName, ushort.max); if (comp_id < components.length) { - Comp.component_id = comp_id; + ecsID!Comp = comp_id; if (components[comp_id].init_data) Mallocator.dispose(components[comp_id].init_data); components[comp_id] = info; @@ -1291,7 +1291,7 @@ export struct EntityManager else { components.add(info); - Comp.component_id = cast(ushort)(components.length - 1); + ecsID!Comp = cast(ushort)(components.length - 1); char[] name = Mallocator.makeArray(cast(char[]) ComponentName); components_map.add(name, cast(ushort)(components.length - 1)); } @@ -1301,10 +1301,10 @@ export struct EntityManager { EventInfo info; - static if (!(hasMember!(Ev, "event_id")) || !is(typeof(Ev.event_id) == ushort)) - { - static assert(0, "Add \"mixin ECS.Event;\" in top of event structure;"); - } + // static if (!(hasMember!(Ev, "event_id")) || !is(typeof(Ev.event_id) == ushort)) + // { + // static assert(0, "Add \"mixin ECS.Event;\" in top of event structure;"); + // } static if (hasMember!(Ev, "onDestroy") && isFunction!(Ev.onDestroy) && is(ReturnType!(Ev.onDestroy) == void) && Parameters!(Ev.onDestroy).length == 0) @@ -1324,12 +1324,12 @@ export struct EntityManager ushort event_id = events_map.get(fullName!Ev, ushort.max); if (event_id < events.length) { - Ev.event_id = event_id; + ecsID!Ev = event_id; } else { events.add(info); - Ev.event_id = cast(ushort)(events.length - 1); + ecsID!Ev = cast(ushort)(events.length - 1); // events_map.add(Ev.stringof, cast(ushort)(events.length - 1)); events_map.add(fullName!Ev, cast(ushort)(events.length - 1)); } @@ -1348,9 +1348,9 @@ export struct EntityManager // static assert(is(SetFunctionAttributes!(T, functionLinkage!(s.onUpdate), // functionAttributes!(s.onUpdate)) == typeof(&s.onUpdate)), // "Function must match system update function."); FIXME: It's lead to crash on android build - static assert(__traits(hasMember, Sys, "system_id"), "Sys must be system type."); + // static assert(__traits(hasMember, Sys, "system_id"), "Sys must be system type."); - System* system = getSystem(Sys.system_id); + System* system = getSystem(ecsID!Sys); assert(system != null, "System must be registered in EntityManager before any funcion can be called."); if (!system.m_any_system_caller) @@ -2256,7 +2256,7 @@ export struct EntityManager ushort[num] del_ids; static foreach (i, comp; Components) { - del_ids[i] = comp.component_id; + del_ids[i] = ecsID!comp; } removeComponents(entity_id, del_ids); diff --git a/source/bubel/ecs/traits.d b/source/bubel/ecs/traits.d index 8214b01..b2ead93 100644 --- a/source/bubel/ecs/traits.d +++ b/source/bubel/ecs/traits.d @@ -2,6 +2,18 @@ module bubel.ecs.traits; import std.traits; +ref ushort ecsID(T)() +{ + __gshared ushort id = ushort.max; + return id; +} + +ref ushort ecsID(T)(T obj) +{ + static if(isPointer!T)return ecsID!(PointerTarget!T); + else return ecsID!T; +} + bool isForeachDelegateWithTypes(DG, Types...)() { return is(DG == delegate) && is(ReturnType!DG == int) && is(Parameters!DG == Types); diff --git a/tests/access_perf.d b/tests/access_perf.d index 36da0c0..74d201b 100644 --- a/tests/access_perf.d +++ b/tests/access_perf.d @@ -65,7 +65,7 @@ void beforeEveryTest() gEM.endRegister(); - tmpl = gEM.allocateTemplate([CLong.component_id, CInt.component_id, CUInt.component_id, CBig.component_id].staticArray); + tmpl = gEM.allocateTemplate([ecsID!CLong, ecsID!CInt, ecsID!CUInt, ecsID!CBig].staticArray); foreach(i; 0 .. 100_000)gEM.addEntity(tmpl); } diff --git a/tests/basic.d b/tests/basic.d index 59f88e2..d544071 100644 --- a/tests/basic.d +++ b/tests/basic.d @@ -115,7 +115,7 @@ struct EmptySystem void beforeEveryTest() { - CUnregistered.component_id = ushort.max; + ecsID!CUnregistered = ushort.max; gEM.initialize(0); gEM.beginRegister(); @@ -138,17 +138,17 @@ void afterEveryTest() @("EntityMeta") unittest { - EntityTemplate* tmpl_ = gEM.allocateTemplate([CInt.component_id, CFloat.component_id, CFlag.component_id].staticArray); + EntityTemplate* tmpl_ = gEM.allocateTemplate([ecsID!CInt, ecsID!CFloat, ecsID!CFlag].staticArray); Entity* entity = gEM.addEntity(tmpl_); EntityMeta meta = entity.getMeta(); - assert(meta.hasComponent(CInt.component_id)); + assert(meta.hasComponent(ecsID!CInt)); assert(meta.getComponent!CInt); - assert(meta.hasComponent(CFloat.component_id)); + assert(meta.hasComponent(ecsID!CFloat)); assert(meta.getComponent!CFloat); assert(!meta.getComponent!CLong); - assert(!meta.hasComponent(CLong.component_id)); + assert(!meta.hasComponent(ecsID!CLong)); assert(!meta.getComponent!CUnregistered); - assert(!meta.hasComponent(CUnregistered.component_id)); + assert(!meta.hasComponent(ecsID!CUnregistered)); assert(*meta.getComponent!CInt == 1); assert(*meta.getComponent!CFloat == 2.0); } @@ -156,7 +156,7 @@ unittest @("AddEntity") unittest { - EntityTemplate* tmpl_ = gEM.allocateTemplate([CInt.component_id, CFloat.component_id, CFlag.component_id].staticArray); + EntityTemplate* tmpl_ = gEM.allocateTemplate([ecsID!CInt, ecsID!CFloat, ecsID!CFlag].staticArray); assert(tmpl_.info.components.length == 3); assert(tmpl_.info.size == (CInt.sizeof + CFloat.sizeof + EntityID.sizeof)); assert(tmpl_.getComponent!CInt); @@ -185,8 +185,8 @@ unittest //Entity* entity3 = gEM.addEntity(tmpl_, [cint.ref_, clong.ref_].staticArray); Entity* entity3 = gEM.addEntity(tmpl_, [CInt(10).ref_, CLong().ref_, CFlag().ref_].staticArray); EntityID id = entity3.id; - assert(entity3.hasComponent(CInt.component_id)); - assert(entity3.hasComponent(CFloat.component_id)); + assert(entity3.hasComponent(ecsID!CInt)); + assert(entity3.hasComponent(ecsID!CFloat)); assert(*entity3.getComponent!CInt == 10); assert(*entity3.getComponent!CFloat == 2.0); @@ -201,7 +201,7 @@ unittest assert(*entity3.getComponent!CFloat == 2.0); assert(*entity3.getComponent!CShort == 2); - gEM.removeComponents(entity3.id, [CFlag().component_id,CShort(2).component_id].staticArray); + gEM.removeComponents(entity3.id, [ecsID!CFlag,ecsID!CShort].staticArray); gEM.commit(); entity3 = gEM.getEntity(id); assert(entity3.getComponent!CInt); @@ -212,7 +212,7 @@ unittest assert(*entity3.getComponent!CFloat == 2.0); gEM.addComponents(entity3.id, [CFlag().ref_,CShort(2).ref_].staticArray); - gEM.removeComponents(entity3.id, [CUnregistered.component_id].staticArray); + gEM.removeComponents(entity3.id, [ecsID!CUnregistered].staticArray); gEM.commit(); entity3 = gEM.getEntity(id); assert(entity3.getComponent!CInt); @@ -235,7 +235,7 @@ unittest assert(entity3.getComponent!CUnregistered); assert(*entity3.getComponent!CUnregistered == 4); - gEM.removeComponents(entity3.id, [CUnregistered.component_id].staticArray); + gEM.removeComponents(entity3.id, [ecsID!CUnregistered].staticArray); gEM.commit(); entity3 = gEM.getEntity(id); assert(!entity3.getComponent!CUnregistered); @@ -247,9 +247,9 @@ unittest unittest { //basic template allocation - ushort[2] ids = [CInt.component_id, CFloat.component_id]; + ushort[2] ids = [ecsID!CInt, ecsID!CFloat]; EntityTemplate* tmpl_ = gEM.allocateTemplate(ids); - EntityTemplate* tmpl_d = gEM.allocateTemplate([CFloat.component_id, CInt.component_id, CFloat.component_id].staticArray); + EntityTemplate* tmpl_d = gEM.allocateTemplate([ecsID!CFloat, ecsID!CInt, ecsID!CFloat].staticArray); EntityTemplate* tmpl_cp = gEM.allocateTemplate(tmpl_); assert(tmpl_d.info == tmpl_.info); assert(tmpl_cp.info == tmpl_cp.info); @@ -268,7 +268,7 @@ unittest *tmpl_.getComponent!CFloat = 5.0; //allocate template from template with additional components - ushort[2] ids2 = [CDouble.component_id,CFlag.component_id]; + ushort[2] ids2 = [ecsID!CDouble,ecsID!CFlag]; EntityTemplate* tmpl_2 = gEM.allocateTemplate(tmpl_, ids2); assert(tmpl_2.info.components.length == 4); assert(tmpl_2.getComponent!CInt); @@ -313,7 +313,7 @@ unittest assert(*tmpl_4.getComponent!CDouble == 3.0); //allocate template from template with three additional component - ushort[3] ids3 = [CDouble.component_id, CLong.component_id, CShort.component_id]; + ushort[3] ids3 = [ecsID!CDouble, ecsID!CLong, ecsID!CShort]; EntityTemplate* tmpl_5 = gEM.allocateTemplate(tmpl_2, ids3); assert(tmpl_5.info.components.length == 6); assert(tmpl_5.getComponent!CInt); @@ -328,7 +328,7 @@ unittest assert(*tmpl_5.getComponent!CShort == 12); //allocate template from template without one component - ushort[1] rem_ids = [CFloat.component_id]; + ushort[1] rem_ids = [ecsID!CFloat]; EntityTemplate* tmpl_6 = gEM.allocateTemplate(tmpl_, null, rem_ids); assert(tmpl_6.info.components.length == 1); assert(tmpl_6.getComponent!CInt); @@ -358,8 +358,8 @@ unittest unittest { //basic template allocation - ushort[2] ids = [CFloat.component_id, CInt.component_id]; - ushort[2] ids2 = [CInt.component_id, CFloat.component_id]; + ushort[2] ids = [ecsID!CFloat, ecsID!CInt]; + ushort[2] ids2 = [ecsID!CInt, ecsID!CFloat]; EntityTemplate* tmpl_ = gEM.allocateTemplate(ids); EntityTemplate* tmpl_2 = gEM.allocateTemplate(ids2); assert(tmpl_.info.components.length == 2); @@ -398,9 +398,9 @@ unittest assert(system !is null); assert(system.count == 0); - System* ecs_system = gEM.getSystem(EmptySystem.system_id); + System* ecs_system = gEM.getSystem(ecsID!EmptySystem); assert(ecs_system !is null); - assert(ecs_system.id == EmptySystem.system_id); + assert(ecs_system.id == ecsID!EmptySystem); assert(ecs_system.name == "tests.basic.EmptySystem"); gEM.begin(); @@ -502,7 +502,7 @@ unittest //FIXME: currently destroy is only called with Manager.destory which is bug, but there is no workaround for this by now //assert(destroy == 1); - System* ecs_system = gEM.getSystem(system.system_id); + System* ecs_system = gEM.getSystem(system.ecsID); ecs_system.enable(); assert(system.enable == 1); @@ -513,7 +513,7 @@ unittest assert(system.disable == 1); - ushort[2] ids = [CLong.component_id,CFloat.component_id]; + ushort[2] ids = [ecsID!CLong,ecsID!CFloat]; EntityTemplate* tmpl = gEM.allocateTemplate(ids); scope (exit) gEM.freeTemplate(tmpl); gEM.addEntity(tmpl); @@ -527,7 +527,7 @@ unittest gEM.end(); assert(system.end == 1); - ushort[2] ids2 = [CLong.component_id, CInt.component_id]; + ushort[2] ids2 = [ecsID!CLong, ecsID!CInt]; EntityTemplate* tmpl2 = gEM.allocateTemplate(ids2); scope (exit) gEM.freeTemplate(tmpl2); gEM.addEntity(tmpl2); @@ -542,7 +542,7 @@ unittest gEM.end(); assert(system.end == 2); - ushort[2] ids3 = [CLong.component_id, CShort.component_id]; + ushort[2] ids3 = [ecsID!CLong, ecsID!CShort]; EntityTemplate* tmpl3 = gEM.allocateTemplate(ids3); scope (exit) gEM.freeTemplate(tmpl3); gEM.addEntity(tmpl3); @@ -601,13 +601,13 @@ unittest assert(system !is null); assert(system.updates_count == 0); - System* ecs_system = gEM.getSystem(LongAddSystem.system_id); + System* ecs_system = gEM.getSystem(ecsID!LongAddSystem); assert(ecs_system !is null); - assert(ecs_system.id == LongAddSystem.system_id); + assert(ecs_system.id == ecsID!LongAddSystem); assert(ecs_system.priority == -1); assert(ecs_system.name == "tests.basic.LongAddSystem"); - ushort[1] ids = [CLong.component_id]; + ushort[1] ids = [ecsID!CLong]; EntityTemplate* tmpl = gEM.allocateTemplate(ids); scope (exit) gEM.freeTemplate(tmpl); gEM.addEntity(tmpl); @@ -757,19 +757,19 @@ unittest assert(system.remove == 0); assert(system.change == 0); - EntityTemplate* tmpl = gEM.allocateTemplate([CLong.component_id,CFloat.component_id].staticArray); + EntityTemplate* tmpl = gEM.allocateTemplate([ecsID!CLong,ecsID!CFloat].staticArray); scope (exit) gEM.freeTemplate(tmpl); EntityID id0 = gEM.addEntity(tmpl).id; gEM.commit(); assert(system.add == 1); - EntityTemplate* tmpl2 = gEM.allocateTemplate([CLong.component_id, CInt.component_id].staticArray); + EntityTemplate* tmpl2 = gEM.allocateTemplate([ecsID!CLong, ecsID!CInt].staticArray); scope (exit) gEM.freeTemplate(tmpl2); EntityID id1 = gEM.addEntity(tmpl2).id; gEM.commit(); assert(system.add == 2); - EntityTemplate* tmpl3 = gEM.allocateTemplate([CLong.component_id, CShort.component_id].staticArray); + EntityTemplate* tmpl3 = gEM.allocateTemplate([ecsID!CLong, ecsID!CShort].staticArray); scope (exit) gEM.freeTemplate(tmpl3); EntityID id2 = gEM.addEntity(tmpl3).id; gEM.commit(); @@ -778,19 +778,19 @@ unittest gEM.beginRegister(); gEM.endRegister(); - gEM.removeComponents(id0, [CFloat.component_id].staticArray); + gEM.removeComponents(id0, [ecsID!CFloat].staticArray); gEM.commit(); assert(system.add == 2); assert(system.remove == 0); assert(system.change == 0); - gEM.removeComponents(id1, [CInt.component_id].staticArray); + gEM.removeComponents(id1, [ecsID!CInt].staticArray); gEM.commit(); assert(system.add == 2); assert(system.remove == 0); assert(system.change == 1); - gEM.removeComponents(id2, [CShort.component_id].staticArray); + gEM.removeComponents(id2, [ecsID!CShort].staticArray); gEM.commit(); assert(system.add == 3); assert(system.remove == 0); @@ -889,7 +889,7 @@ unittest } assert(gEM.getSystem!TestSystem is null); - assert(gEM.getSystem(TestSystem.system_id) is null); + assert(gEM.getSystem(ecsID!TestSystem) is null); } @("MultithreadedUpdate") @@ -961,10 +961,10 @@ unittest TestSystem* system = gEM.getSystem!TestSystem; TestEmptySystem* empty_system = gEM.getSystem!TestEmptySystem; - ushort[2] ids = [CLong.component_id,CFloat.component_id]; + ushort[2] ids = [ecsID!CLong,ecsID!CFloat]; EntityTemplate* tmpl = gEM.allocateTemplate(ids); scope (exit) gEM.freeTemplate(tmpl); - EntityTemplate* tmpl2 = gEM.allocateTemplate([CLong.component_id,CInt.component_id,CShort.component_id,CFloat.component_id].staticArray); + EntityTemplate* tmpl2 = gEM.allocateTemplate([ecsID!CLong,ecsID!CInt,ecsID!CShort,ecsID!CFloat].staticArray); scope (exit) gEM.freeTemplate(tmpl2); gEM.begin(); @@ -1059,7 +1059,7 @@ unittest @("AddRemoveEntities") unittest { - ushort[3] ids = [CLong.component_id,CFloat.component_id,CShort.component_id]; + ushort[3] ids = [ecsID!CLong,ecsID!CFloat,ecsID!CShort]; EntityTemplate* tmpl = gEM.allocateTemplate(ids); scope (exit) gEM.freeTemplate(tmpl); @@ -1089,7 +1089,7 @@ unittest gEM.endRegister(); - ushort[1] ids = [CLong.component_id]; + ushort[1] ids = [ecsID!CLong]; EntityTemplate* tmpl = gEM.allocateTemplate(ids); scope (exit) gEM.freeTemplate(tmpl); @@ -1118,7 +1118,7 @@ unittest assert(*entity.getComponent!CShort == 15); assert(*entity.getComponent!CFloat == 13); - ushort[3] ids2 = [CFloat.component_id, CLong.component_id, CUnregistered.component_id]; + ushort[3] ids2 = [ecsID!CFloat, ecsID!CLong, ecsID!CUnregistered]; gEM.removeComponents(id, ids2); gEM.commit(); @@ -1161,12 +1161,12 @@ unittest { struct ETest { - mixin ECS.Event; + // mixin ECS.Event; } struct ETest2 { - mixin ECS.Event; + // mixin ECS.Event; void onDestroy() { @@ -1253,10 +1253,10 @@ unittest gEM.endRegister(); - ushort[1] ids = [CLong.component_id]; + ushort[1] ids = [ecsID!CLong]; EntityTemplate* tmpl = gEM.allocateTemplate(ids); scope (exit) gEM.freeTemplate(tmpl); - ushort[1] ids2 = [CShort.component_id]; + ushort[1] ids2 = [ecsID!CShort]; EntityTemplate* tmpl2 = gEM.allocateTemplate(ids2); scope (exit) gEM.freeTemplate(tmpl2); @@ -1348,11 +1348,11 @@ unittest gEM.endRegister(); - EntityTemplate* tmpl = gEM.allocateTemplate([CInt.component_id].staticArray); + EntityTemplate* tmpl = gEM.allocateTemplate([ecsID!CInt].staticArray); scope (exit) gEM.freeTemplate(tmpl); EntityID id1 = gEM.addEntity(tmpl).id; - EntityTemplate* tmpl2 = gEM.allocateTemplate([CInt.component_id, CLong.component_id].staticArray); + EntityTemplate* tmpl2 = gEM.allocateTemplate([ecsID!CInt, ecsID!CLong].staticArray); scope (exit) gEM.freeTemplate(tmpl2); EntityID id2 = gEM.addEntity(tmpl2).id; @@ -1471,22 +1471,22 @@ unittest const (EntityManager.UpdatePass)* pass = gEM.getPass("update"); assert(pass != null); assert(pass.system_callers.length == 5); - assert(pass.system_callers[0].system_id == TestSystem.system_id); - assert(pass.system_callers[1].system_id == TestSystem2.system_id); - assert(pass.system_callers[2].system_id == TestSystem3.system_id); - assert(pass.system_callers[3].system_id == TestSystem4.system_id); - assert(pass.system_callers[4].system_id == TestSystem5.system_id); + assert(pass.system_callers[0].system_id == ecsID!TestSystem); + assert(pass.system_callers[1].system_id == ecsID!TestSystem2); + assert(pass.system_callers[2].system_id == ecsID!TestSystem3); + assert(pass.system_callers[3].system_id == ecsID!TestSystem4); + assert(pass.system_callers[4].system_id == ecsID!TestSystem5); assert(pass.system_callers[0].dependencies.length == 0); assert(pass.system_callers[1].dependencies.length == 1); assert(pass.system_callers[2].dependencies.length == 1); assert(pass.system_callers[3].dependencies.length == 3); assert(pass.system_callers[4].dependencies.length == 1); - assert(pass.system_callers[1].dependencies[0].system_id == TestSystem.system_id); - assert(pass.system_callers[2].dependencies[0].system_id == TestSystem2.system_id); - assert(pass.system_callers[3].dependencies[0].system_id == TestSystem.system_id); - assert(pass.system_callers[3].dependencies[1].system_id == TestSystem2.system_id); - assert(pass.system_callers[3].dependencies[2].system_id == TestSystem3.system_id); - assert(pass.system_callers[4].dependencies[0].system_id == TestSystem4.system_id); + assert(pass.system_callers[1].dependencies[0].system_id == ecsID!TestSystem); + assert(pass.system_callers[2].dependencies[0].system_id == ecsID!TestSystem2); + assert(pass.system_callers[3].dependencies[0].system_id == ecsID!TestSystem); + assert(pass.system_callers[3].dependencies[1].system_id == ecsID!TestSystem2); + assert(pass.system_callers[3].dependencies[2].system_id == ecsID!TestSystem3); + assert(pass.system_callers[4].dependencies[0].system_id == ecsID!TestSystem4); } @("ExternalSystemDependencies") @@ -1598,21 +1598,21 @@ unittest const (EntityManager.UpdatePass)* pass = gEM.getPass("update"); assert(pass != null); assert(pass.system_callers.length == 5); - assert(pass.system_callers[0].system_id == TestSystem.system_id); - assert(pass.system_callers[1].system_id == TestSystem2.system_id); - assert(pass.system_callers[2].system_id == TestSystem3.system_id); - assert(pass.system_callers[3].system_id == TestSystem4.system_id); - assert(pass.system_callers[4].system_id == TestSystem5.system_id); + assert(pass.system_callers[0].system_id == ecsID!TestSystem); + assert(pass.system_callers[1].system_id == ecsID!TestSystem2); + assert(pass.system_callers[2].system_id == ecsID!TestSystem3); + assert(pass.system_callers[3].system_id == ecsID!TestSystem4); + assert(pass.system_callers[4].system_id == ecsID!TestSystem5); assert(pass.system_callers[0].dependencies.length == 0); assert(pass.system_callers[1].dependencies.length == 1); assert(pass.system_callers[2].dependencies.length == 1); assert(pass.system_callers[3].dependencies.length == 3); assert(pass.system_callers[4].dependencies.length == 2); - assert(pass.system_callers[1].dependencies[0].system_id == TestSystem.system_id); - assert(pass.system_callers[2].dependencies[0].system_id == TestSystem2.system_id); - assert(pass.system_callers[3].dependencies[0].system_id == TestSystem.system_id); - assert(pass.system_callers[3].dependencies[1].system_id == TestSystem2.system_id); - assert(pass.system_callers[3].dependencies[2].system_id == TestSystem3.system_id); - assert(pass.system_callers[4].dependencies[0].system_id == TestSystem2.system_id); - assert(pass.system_callers[4].dependencies[1].system_id == TestSystem4.system_id); + assert(pass.system_callers[1].dependencies[0].system_id == ecsID!TestSystem); + assert(pass.system_callers[2].dependencies[0].system_id == ecsID!TestSystem2); + assert(pass.system_callers[3].dependencies[0].system_id == ecsID!TestSystem); + assert(pass.system_callers[3].dependencies[1].system_id == ecsID!TestSystem2); + assert(pass.system_callers[3].dependencies[2].system_id == ecsID!TestSystem3); + assert(pass.system_callers[4].dependencies[0].system_id == ecsID!TestSystem2); + assert(pass.system_callers[4].dependencies[1].system_id == ecsID!TestSystem4); } \ No newline at end of file diff --git a/tests/bugs.d b/tests/bugs.d index 4c4153a..4a97c03 100644 --- a/tests/bugs.d +++ b/tests/bugs.d @@ -21,14 +21,14 @@ unittest { struct Event1 { - mixin ECS.Event; + // mixin ECS.Event; EntityID id; } struct Event2 { - mixin ECS.Event; + // mixin ECS.Event; } struct System1 @@ -45,7 +45,7 @@ unittest void onCreate() { - tmpl = gEM.allocateTemplate([CInt.component_id, CLong.component_id].staticArray); + tmpl = gEM.allocateTemplate([ecsID!CInt, ecsID!CLong].staticArray); } void onDestroy() @@ -118,7 +118,7 @@ unittest gEM.endRegister(); - EntityTemplate* tmpl = gEM.allocateTemplate([CInt.component_id, CLong.component_id].staticArray); + EntityTemplate* tmpl = gEM.allocateTemplate([ecsID!CInt, ecsID!CLong].staticArray); EntityID id = gEM.addEntity(tmpl,[CLong(10).ref_, CInt(6).ref_].staticArray).id; EntityID id2 = gEM.addEntity(tmpl,[CInt(4).ref_].staticArray).id; gEM.freeTemplate(tmpl); @@ -126,13 +126,13 @@ unittest gEM.sendEvent(id2, Event1(id)); - gEM.getSystem(System2.system_id).disable(); + gEM.getSystem(ecsID!System2).disable(); gEM.begin(); gEM.update(); gEM.end(); - gEM.getSystem(System2.system_id).enable(); + gEM.getSystem(ecsID!System2).enable(); gEM.begin(); gEM.update(); diff --git a/tests/perf.d b/tests/perf.d index b6a2692..fcf3ab4 100644 --- a/tests/perf.d +++ b/tests/perf.d @@ -86,22 +86,22 @@ void afterEveryTest() void smallTmpl() { - tmpl = gEM.allocateTemplate([CShort.component_id].staticArray); + tmpl = gEM.allocateTemplate([ecsID!CShort].staticArray); } void bigTmpl() { - tmpl = gEM.allocateTemplate([CBig.component_id].staticArray); + tmpl = gEM.allocateTemplate([ecsID!CBig].staticArray); } void multiSmallTmpl() { - tmpl = gEM.allocateTemplate([CShort.component_id, CLong.component_id, CInt.component_id, CUInt.component_id].staticArray); + tmpl = gEM.allocateTemplate([ecsID!CShort, ecsID!CLong, ecsID!CInt, ecsID!CUInt].staticArray); } void multiBigTmpl() { - tmpl = gEM.allocateTemplate([CLong.component_id, CInt.component_id, CUInt.component_id, CBig.component_id].staticArray); + tmpl = gEM.allocateTemplate([ecsID!CLong, ecsID!CInt, ecsID!CUInt, ecsID!CBig].staticArray); } @("AddEntities100k1comp2b") @(before, &smallTmpl) @@ -138,25 +138,25 @@ void allocDealloc100k() void smallTmplPreAlloc() { - tmpl = gEM.allocateTemplate([CShort.component_id].staticArray); + tmpl = gEM.allocateTemplate([ecsID!CShort].staticArray); allocDealloc100k(); } void bigTmplPreAlloc() { - tmpl = gEM.allocateTemplate([CBig.component_id].staticArray); + tmpl = gEM.allocateTemplate([ecsID!CBig].staticArray); allocDealloc100k(); } void multiSmallTmplPreAlloc() { - tmpl = gEM.allocateTemplate([CShort.component_id, CLong.component_id, CInt.component_id, CUInt.component_id].staticArray); + tmpl = gEM.allocateTemplate([ecsID!CShort, ecsID!CLong, ecsID!CInt, ecsID!CUInt].staticArray); allocDealloc100k(); } void multiBigTmplPreAlloc() { - tmpl = gEM.allocateTemplate([CLong.component_id, CInt.component_id, CUInt.component_id, CBig.component_id].staticArray); + tmpl = gEM.allocateTemplate([ecsID!CLong, ecsID!CInt, ecsID!CUInt, ecsID!CBig].staticArray); allocDealloc100k(); } From 3c1c67efd0ebf6d501e7dfc229f172db3e984776 Mon Sep 17 00:00:00 2001 From: Mergul Date: Sun, 3 Jan 2021 13:05:48 +0100 Subject: [PATCH 170/217] -added filterEntity callback (used to filter EntityInfos for system, better control than simply @optional) -removed some redundant code (two times same code) -added some common functions --- source/bubel/ecs/entity.d | 9 ++++ source/bubel/ecs/manager.d | 63 +++++++++++++--------- source/bubel/ecs/system.d | 2 + tests/basic.d | 106 ++++++++++++++++++++++++++++++++++++- 4 files changed, 155 insertions(+), 25 deletions(-) diff --git a/source/bubel/ecs/entity.d b/source/bubel/ecs/entity.d index f713c78..72131b5 100644 --- a/source/bubel/ecs/entity.d +++ b/source/bubel/ecs/entity.d @@ -128,6 +128,15 @@ export struct EntityTemplate if(T.component_id >= info.tmpl_deltas.length || info.tmpl_deltas[T.component_id] == ushort.max)return null; return cast(T*)(entity_data.ptr + info.tmpl_deltas[T.component_id]); } + + /************************************************************************************************************************ + Get specified component. If component doesn't exist function return null. Returned pointer is valid during EntityTemplate lifetime. + */ + void* getComponent(ushort component_id) const nothrow @nogc + { + if(component_id >= info.tmpl_deltas.length || info.tmpl_deltas[component_id] == ushort.max)return null; + return cast(void*)(entity_data.ptr + info.tmpl_deltas[component_id]); + } } /************************************************************************************************************************ diff --git a/source/bubel/ecs/manager.d b/source/bubel/ecs/manager.d index 1514cbc..e82add3 100644 --- a/source/bubel/ecs/manager.d +++ b/source/bubel/ecs/manager.d @@ -1110,6 +1110,32 @@ export struct EntityManager } } + static void catchEntityFilterFunction(string func_name, RetType = void)(void** member) + { + static if (hasMember!(Sys, func_name)) + { + foreach (func; __traits(getOverloads, Sys, func_name)) + { + static if ((Parameters!(func)).length == 1 + && is(Parameters!(func)[0] == EntityInfo*) + && is(ReturnType!(func) == RetType)) + { + static RetType callFunc(void* system_pointer, EntityInfo* info) + { + Sys* s = cast(Sys*) system_pointer; + static if (is(RetTyp == void)) + mixin("s." ~ func_name ~ "(info)"); + else + return mixin("s." ~ func_name ~ "(info)"); + } + + *member = cast(void*)&callFunc; + break; + } + } + } + } + catchFunction!("onEnable")(&system.m_enable); catchFunction!("onDisable")(&system.m_disable); catchFunction!("onCreate")(&system.m_create); @@ -1121,6 +1147,8 @@ export struct EntityManager catchEntityFunction!("onRemoveEntity")(&system.m_remove_entity); catchEntityFunction!("onChangeEntity")(&system.m_change_entity); + catchEntityFilterFunction!("filterEntity", bool)(&system.m_filter_entity); + system.m_system_pointer = cast(void*) Mallocator.make!Sys; system.m_priority = priority; //(cast(Sys*) system.m_system_pointer).__ecsInitialize(); @@ -2035,6 +2063,9 @@ export struct EntityManager is_: } + ///call Custom Entity Filter test if function exists + if(system.m_filter_entity && !(cast(bool function(void* system_pointer, EntityInfo* info) @nogc nothrow)system.m_filter_entity)(system, &entity))return; + entity.systems[system_id] = true; } @@ -2077,30 +2108,8 @@ export struct EntityManager { System* system = &systems[system_id]; - if (system.m_excluded_components) - { - foreach (id; system.m_excluded_components) - { - foreach (id2; info.components) - { - if (id == id2) - return; - } - } - } - - foreach (id; system.m_components) - { - foreach (i2, id2; info.components) - { - if (id2 == id) - goto is_; - } - return; - is_: - } - - info.systems[system_id] = true; + connectListenerToEntityInfo(info, system_id); + if(!info.systems[system_id])return; uint index = 0; for (; index < passes[system.m_pass].system_callers.length; index++) @@ -3483,6 +3492,12 @@ export struct EntityManager return new_info; } + export bool hasComponent(ushort component_id) + { + if(component_id >= deltas.length || !deltas[component_id])return false; + return true; + } + export ~this() @nogc nothrow { if (components) diff --git a/source/bubel/ecs/system.d b/source/bubel/ecs/system.d index cd8d2e3..e571e8b 100644 --- a/source/bubel/ecs/system.d +++ b/source/bubel/ecs/system.d @@ -194,6 +194,8 @@ package: void* m_remove_entity; void* m_change_entity; + void* m_filter_entity; + //void function(ref EntityManager.CallData data) m_initialize; //void function(ref EntityManager.CallData data) m_deinitilize; void* m_initialize; diff --git a/tests/basic.d b/tests/basic.d index 59f88e2..4a9dc6f 100644 --- a/tests/basic.d +++ b/tests/basic.d @@ -139,6 +139,7 @@ void afterEveryTest() unittest { EntityTemplate* tmpl_ = gEM.allocateTemplate([CInt.component_id, CFloat.component_id, CFlag.component_id].staticArray); + scope(exit)gEM.freeTemplate(tmpl_); Entity* entity = gEM.addEntity(tmpl_); EntityMeta meta = entity.getMeta(); assert(meta.hasComponent(CInt.component_id)); @@ -1615,4 +1616,107 @@ unittest assert(pass.system_callers[3].dependencies[2].system_id == TestSystem3.system_id); assert(pass.system_callers[4].dependencies[0].system_id == TestSystem2.system_id); assert(pass.system_callers[4].dependencies[1].system_id == TestSystem4.system_id); -} \ No newline at end of file +} + + +@("CustomFilter") +unittest +{ + struct TestSystem + { + mixin ECS.System; + + struct EntitiesData + { + uint length; + @optional CInt[] int_; + @optional CLong[] long_; + @optional CFloat[] float_; + @optional CDouble[] double_; + } + + bool filterEntity(EntityManager.EntityInfo* info) + { + if(!info.hasComponent(CInt.component_id))return false; + int one_from = 0; + if(info.hasComponent(CLong.component_id))one_from++; + if(info.hasComponent(CFloat.component_id))one_from++; + if(info.hasComponent(CDouble.component_id))one_from++; + if(one_from == 1)return true; + return false; + } + + void onUpdate(EntitiesData entities) + { + updates++; + } + + uint updates = 0; + } + + struct TestSystem2 + { + mixin ECS.System; + + struct EntitiesData + { + uint length; + @optional CInt[] int_; + @optional CLong[] long_; + @optional CFloat[] float_; + @optional CDouble[] double_; + } + + bool filterEntity(EntityManager.EntityInfo* info) + { + if(info.hasComponent(CInt.component_id) && info.hasComponent(CFloat.component_id) && !info.hasComponent(CLong.component_id) && !info.hasComponent(CDouble.component_id))return true; + if(info.hasComponent(CLong.component_id) && info.hasComponent(CDouble.component_id) && !info.hasComponent(CInt.component_id) && !info.hasComponent(CFloat.component_id))return true; + return false; + } + + void onUpdate(EntitiesData entities) + { + updates++; + } + + uint updates = 0; + } + + gEM.beginRegister(); + + gEM.registerSystem!TestSystem(0); + gEM.registerSystem!TestSystem2(1); + + gEM.endRegister(); + + + EntityTemplate* tmpl_ = gEM.allocateTemplate([CInt.component_id, CLong.component_id, CFloat.component_id, CDouble.component_id].staticArray); + scope(exit)gEM.freeTemplate(tmpl_); + EntityTemplate* tmpl_2 = gEM.allocateTemplate([CInt.component_id, CFloat.component_id].staticArray); + scope(exit)gEM.freeTemplate(tmpl_2); + EntityTemplate* tmpl_3 = gEM.allocateTemplate([CLong.component_id, CDouble.component_id].staticArray); + scope(exit)gEM.freeTemplate(tmpl_3); + EntityTemplate* tmpl_4 = gEM.allocateTemplate([CInt.component_id, CLong.component_id, CDouble.component_id].staticArray); + scope(exit)gEM.freeTemplate(tmpl_4); + EntityTemplate* tmpl_5 = gEM.allocateTemplate([CInt.component_id, CDouble.component_id].staticArray); + scope(exit)gEM.freeTemplate(tmpl_5); + EntityTemplate* tmpl_6 = gEM.allocateTemplate([CDouble.component_id].staticArray); + scope(exit)gEM.freeTemplate(tmpl_6); + + gEM.addEntity(tmpl_); + gEM.addEntity(tmpl_2); + gEM.addEntity(tmpl_3); + gEM.addEntity(tmpl_4); + gEM.addEntity(tmpl_5); + gEM.addEntity(tmpl_6); + + TestSystem* test_system = gEM.getSystem!TestSystem; + TestSystem2* test_system2 = gEM.getSystem!TestSystem2; + + gEM.begin(); + gEM.update(); + gEM.end(); + + assert(test_system.updates == 2); + assert(test_system2.updates == 2); +} From 84ba5f9eb57d85b48c50ce46df87d64c43ad55f2 Mon Sep 17 00:00:00 2001 From: Mergul Date: Sun, 3 Jan 2021 13:08:29 +0100 Subject: [PATCH 171/217] -fixed emscripten compilation --- .../android/bindbc/loader/sharedlib.d | 53 ------------------- demos/external/sources/cimgui/cimgui.d | 10 +++- .../wasm_imports/bindbc/sdl/bind/sdllog.d | 6 ++- demos/source/demos/brick_breaker.d | 2 + demos/utils/source/ecs_utils/gfx/renderer.d | 30 +++++------ demos/utils/source/ecs_utils/utils.d | 6 ++- 6 files changed, 36 insertions(+), 71 deletions(-) diff --git a/demos/external/android/bindbc/loader/sharedlib.d b/demos/external/android/bindbc/loader/sharedlib.d index ab6c444..ca3c654 100644 --- a/demos/external/android/bindbc/loader/sharedlib.d +++ b/demos/external/android/bindbc/loader/sharedlib.d @@ -213,8 +213,6 @@ void addErr(const(char)* errstr, const(char)* message) version(Windows) { import core.sys.windows.windows; - extern(Windows) @nogc nothrow alias pSetDLLDirectory = BOOL function(const(char)*); - pSetDLLDirectory setDLLDirectory; void* loadLib(const(char)* name) { @@ -255,57 +253,6 @@ version(Windows) } else strncpy(buf, "Unknown Error\0", len); } - - /** - Adds a path to the default search path on Windows, replacing the path set in a previous - call to the same function. - - Any path added to this function will be added to the default DLL search path as documented at - https://docs.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-setdlldirectoryw. - - Generally, when loading DLLs on a path that is not on the search path, e.g., from a subdirectory - of the application, the path should be prepended to the DLL name passed to the load function, - e.g., "dlls\\SDL2.dll". If `setCustomLoaderSearchPath(".\\dlls")` is called first, then the subdirectory - will become part of the DLL search path and the path may be omitted from the load function. (Be - aware that ".\\dlls" is relative to the current working directory, which may not be the application - directory, so the path should be built appropriately.) - - Some DLLs may depend on other DLLs, perhaps even attempting to load them dynamically at run time - (e.g., SDL2_image only loads dependencies such as libpng if it is initialized at run time with - PNG support). In this case, if the DLL and its dependencies are placed in a subdirectory and - loaded as e.g., "dlls\\SDL2_image.dll", then it will not be able to find its dependencies; the - system loader will look for them on the regular DLL search path. When that happens, the solution - is to call `setCustomLoaderSearchPath` with the subdirectory before initializing the library. - - Calling this function with `null` as the argument will reset the default search path. - - When the function returns `false`, the relevant `ErrorInfo` is added to the global error list and can - be retrieved by looping through the array returned by the `errors` function. - - When placing DLLs in a subdirectory of the application, it should be considered good practice to - call `setCustomLoaderSearchPath` to ensure all DLLs load properly. It should also be considered good - practice to reset the default search path once all DLLs are loaded. - - This function is only available on Windows, so any usage of it should be preceded with - `version(Windows)`. - - Params: - path = the path to add to the DLL search path, or `null` to reset the default. - - Returns: - `true` if the path was successfully added to the DLL search path, otherwise `false`. - */ - public - bool setCustomLoaderSearchPath(const(char)* path) - { - if(!setDLLDirectory) { - auto lib = load("Kernel32.dll"); - if(lib == invalidHandle) return false; - lib.bindSymbol(cast(void**)&setDLLDirectory, "SetDllDirectoryA"); - if(!setDLLDirectory) return false; - } - return setDLLDirectory(path) != 0; - } } else version(Posix) { import core.sys.posix.dlfcn; diff --git a/demos/external/sources/cimgui/cimgui.d b/demos/external/sources/cimgui/cimgui.d index 507f616..1fc119f 100644 --- a/demos/external/sources/cimgui/cimgui.d +++ b/demos/external/sources/cimgui/cimgui.d @@ -2,9 +2,17 @@ //based on imgui.h file version "1.73" from Dear ImGui https://github.com/ocornut/imgui module cimgui.cimgui; -import core.stdc.stdarg; +// import core.stdc.stdarg; //import core.stdc.stdio; +version(WebAssembly) +{ + alias va_list = char*; + pragma(LDC_va_start) + void va_start(T)(out va_list ap, ref T parmn) @nogc; +} +else import core.stdc.stdarg; + extern (C): //alias ImU64 = ulong; diff --git a/demos/external/wasm_imports/bindbc/sdl/bind/sdllog.d b/demos/external/wasm_imports/bindbc/sdl/bind/sdllog.d index 3ff5b4c..36bf76d 100644 --- a/demos/external/wasm_imports/bindbc/sdl/bind/sdllog.d +++ b/demos/external/wasm_imports/bindbc/sdl/bind/sdllog.d @@ -6,7 +6,11 @@ module bindbc.sdl.bind.sdllog; -import core.stdc.stdarg : va_list; +version(WebAssembly) +{ + alias va_list = char*; +} +else import core.stdc.stdarg : va_list; import bindbc.sdl.config; enum SDL_MAX_LOG_MESSAGE = 4096; diff --git a/demos/source/demos/brick_breaker.d b/demos/source/demos/brick_breaker.d index c15c503..a170076 100644 --- a/demos/source/demos/brick_breaker.d +++ b/demos/source/demos/brick_breaker.d @@ -416,6 +416,8 @@ void brickBreakerStart() launcher.gui_manager.addComponent(CInput(), "Velocity"); launcher.gui_manager.addComponent(CDamping(), "Damping"); launcher.gui_manager.addComponent(CBall(), "Ball"); + launcher.gui_manager.addComponent(CBVH(), "BVH"); + launcher.gui_manager.addComponent(CAABB(), "AABB"); launcher.gui_manager.addSystem(MoveSystem.system_id, "Move System"); launcher.gui_manager.addSystem(EdgeCollisionSystem.system_id, "Edge Collision System"); diff --git a/demos/utils/source/ecs_utils/gfx/renderer.d b/demos/utils/source/ecs_utils/gfx/renderer.d index ef53543..b2091cf 100644 --- a/demos/utils/source/ecs_utils/gfx/renderer.d +++ b/demos/utils/source/ecs_utils/gfx/renderer.d @@ -187,6 +187,20 @@ struct Renderer } } + struct DrawData + { + Texture texture; + vec2 position; + vec2 size; + vec4 coords; + short depth = 0; + uint color = uint.max; + float angle = 0; + uint material_id = 0; + uint mesh_id = 0; + uint thread_id = 0; + } + struct Thread { //Vector!VertexBlock block; @@ -430,20 +444,6 @@ struct Renderer } - struct DrawData - { - Texture texture; - vec2 position; - vec2 size; - vec4 coords; - short depth = 0; - uint color = uint.max; - float angle = 0; - uint material_id = 0; - uint mesh_id = 0; - uint thread_id = 0; - } - //void draw(Texture tex, vec2 pos, vec2 size, vec4 coords, short depth = 0, uint color = uint.max, float angle = 0, uint material_id = 0, uint mesh_id = 0, uint thread_id = 0) void draw(scope ref const(DrawData) data) { @@ -570,7 +570,7 @@ struct Renderer memcpy(ptr+16,pos.data.ptr,8); memcpy(ptr+32,coords.data.ptr,16);*/ - short[] verts = cast(short[])block.batch_vertices; + short[] verts = (cast(short*)block.batch_vertices.ptr)[0..block.batch_vertices.length>>1]; uint item_id = block.items; uint mesh_id = data.mesh_id; diff --git a/demos/utils/source/ecs_utils/utils.d b/demos/utils/source/ecs_utils/utils.d index 5073d4e..1896856 100644 --- a/demos/utils/source/ecs_utils/utils.d +++ b/demos/utils/source/ecs_utils/utils.d @@ -77,7 +77,11 @@ version(GNU) else { extern(C) int printf(scope const char* format, ...) @nogc nothrow @system; - public import std.array : staticArray; + // public import std.array : staticArray; + pragma(inline, true) T[n] staticArray(T, size_t n)(auto ref T[n] a) + { + return a; + } } extern(C) int rand() nothrow @nogc @trusted; From edaa2286f436380e3cb3d244523268485b2bda12 Mon Sep 17 00:00:00 2001 From: Mergul Date: Sat, 9 Jan 2021 14:30:56 +0100 Subject: [PATCH 172/217] -fix some memory leaks in unittests -change name in dub.json ecs->bubel_ecs -add dependeny in meson.build --- dub.json | 2 +- meson.build | 2 ++ tests/basic.d | 4 ++++ tests/tests.d | 1 + 4 files changed, 8 insertions(+), 1 deletion(-) diff --git a/dub.json b/dub.json index ba935ee..4eca570 100755 --- a/dub.json +++ b/dub.json @@ -1,5 +1,5 @@ { - "name": "ecs", + "name": "bubel_ecs", "authors": [ "Michał Masiukiewicz", "Dawid Masiukiewicz" ], diff --git a/meson.build b/meson.build index 2a71fc7..4951584 100644 --- a/meson.build +++ b/meson.build @@ -67,6 +67,8 @@ ecs_lib = library('ecs', src, include_directories : [tests_inc, inc], d_args: ar executable('tests', tests_src, include_directories : [tests_inc, inc], d_args: args, link_args: link_args, link_with: ecs_lib) +bubel_ecs_dep = declare_dependency(include_directories : [inc], link_with : ecs_lib) + if BuildDemos_opt subdir('demos/utils') subdir('demos') diff --git a/tests/basic.d b/tests/basic.d index 4a9dc6f..bcea918 100644 --- a/tests/basic.d +++ b/tests/basic.d @@ -158,6 +158,7 @@ unittest unittest { EntityTemplate* tmpl_ = gEM.allocateTemplate([CInt.component_id, CFloat.component_id, CFlag.component_id].staticArray); + scope(exit)gEM.freeTemplate(tmpl_); assert(tmpl_.info.components.length == 3); assert(tmpl_.info.size == (CInt.sizeof + CFloat.sizeof + EntityID.sizeof)); assert(tmpl_.getComponent!CInt); @@ -346,6 +347,7 @@ unittest assert(*tmpl_7.getComponent!CLong == 10); gEM.freeTemplate(tmpl_d); + gEM.freeTemplate(tmpl_cp); gEM.freeTemplate(tmpl_); gEM.freeTemplate(tmpl_2); gEM.freeTemplate(tmpl_3); @@ -369,6 +371,8 @@ unittest assert(*tmpl_.getComponent!CInt == 1); assert(*tmpl_.getComponent!CFloat == 2.0); assert(tmpl_.info == tmpl_2.info); + gEM.freeTemplate(tmpl_); + gEM.freeTemplate(tmpl_2); } @("MultiRegister") diff --git a/tests/tests.d b/tests/tests.d index 9f69987..d539f89 100644 --- a/tests/tests.d +++ b/tests/tests.d @@ -1014,6 +1014,7 @@ else: writeEntityComponents(gEM.getEntity(entity)); //import std.stdio; ////writeln((cast(uint*)tmpl.info.first_block)[0..48]); + gEM.freeTemplate(tmpl_empty); gEM.freeTemplate(tmpl); gEM.freeTemplate(tmpl2); gEM.freeTemplate(copy_tempalte); From 9cef882faf3cd182af49893a50dfc0cfb7ee220f Mon Sep 17 00:00:00 2001 From: Mergul Date: Sat, 9 Jan 2021 15:13:53 +0100 Subject: [PATCH 173/217] -change targetName to "ecs" in order to fix CI guild (need to be renamed in CI in future) --- dub.json | 1 + 1 file changed, 1 insertion(+) diff --git a/dub.json b/dub.json index 4eca570..1a99040 100755 --- a/dub.json +++ b/dub.json @@ -1,5 +1,6 @@ { "name": "bubel_ecs", + "targetName" : "ecs", "authors": [ "Michał Masiukiewicz", "Dawid Masiukiewicz" ], From 00386ed52912246fed7c84fc9a2f981853f60e6d Mon Sep 17 00:00:00 2001 From: Mergul Date: Sun, 21 Feb 2021 17:38:03 +0100 Subject: [PATCH 174/217] -added missing meson.build files --- .gitignore | 2 +- demos/.gitignore | 1 + demos/meson.build | 45 +++++++++++++++++++++++++++++++++++++++++ demos/utils/meson.build | 31 ++++++++++++++++++++++++++++ 4 files changed, 78 insertions(+), 1 deletion(-) create mode 100644 demos/meson.build create mode 100644 demos/utils/meson.build diff --git a/.gitignore b/.gitignore index 636ea36..01f3210 100644 --- a/.gitignore +++ b/.gitignore @@ -7,7 +7,7 @@ !.gitignore !codecov.yml !skeleton.html -!meson.build +!**/meson.build !meson_options.txt !compile_wasm.py !compile_android.py \ No newline at end of file diff --git a/demos/.gitignore b/demos/.gitignore index d74e2b0..d137ce7 100644 --- a/demos/.gitignore +++ b/demos/.gitignore @@ -15,5 +15,6 @@ !emscripten_shell.html !emscripten_multi_shell.html !compile_android.py +!**/meson.build .dub Android \ No newline at end of file diff --git a/demos/meson.build b/demos/meson.build new file mode 100644 index 0000000..031928f --- /dev/null +++ b/demos/meson.build @@ -0,0 +1,45 @@ +demos_src = [ + 'source/app.d', + 'source/demos/brick_breaker.d', + 'source/demos/snake.d', + 'source/demos/simple.d', + 'source/demos/sandbox.d', + 'source/demos/bullet_madnes.d', + 'source/demos/particles.d', + 'source/demos/physics.d', + 'source/demos/space_invaders.d', + 'source/game_core/basic.d', + 'source/game_core/job_updater.d', + 'source/game_core/rendering.d', + 'source/game_core/collision.d', + 'source/gui/component.d', + 'source/gui/manager.d', + 'source/gui/template_.d', + 'source/gui/tool_circle.d', + 'source/gui/system.d' +] + +external_src = [ + 'external/sources/mmutils/thread_pool.d', + 'external/sources/glad/gl/gl.d', + 'external/sources/glad/gl/loader.d', + 'external/sources/glad/gl/ext.d', + 'external/sources/glad/gl/all.d', + 'external/sources/glad/gl/funcs.d', + 'external/sources/glad/gl/gles2.d', + 'external/sources/glad/gl/enums.d', + 'external/sources/glad/gl/types.d', + 'external/sources/cimgui/cimgui.d' +] + +demos_inc = include_directories(['source/']) + +#link_args += '-rpath=libs/linux/x64/' +link_args += '-L=' + meson.current_source_dir() + '/libs/linux/x64/libcimgui.so' +link_args += '-L' + meson.current_source_dir() + '/libs/linux/x64' +link_args += '-lcimgui' +#,"SDL2_image + +executable('demos', [demos_src, external_src], include_directories : [demos_inc, utils_inc, inc], d_args: args, link_args: link_args, + d_module_versions: ['BindSDL_Image','SDL_2010'], link_with: [ecs_lib, ecs_utils_lib], dependencies: [bc_loader_dep,sdl_dep], + build_rpath: '-L' + meson.current_source_dir() + '/libs/linux/x64/', install_rpath: 'libs/linux/x64/') \ No newline at end of file diff --git a/demos/utils/meson.build b/demos/utils/meson.build new file mode 100644 index 0000000..f184e16 --- /dev/null +++ b/demos/utils/meson.build @@ -0,0 +1,31 @@ +#project('ECSUtils', 'd') + +utils_src = [ + 'source/ecs_utils/gfx/mesh.d', + 'source/ecs_utils/gfx/sprite.d', + 'source/ecs_utils/gfx/mesh_module.d', + 'source/ecs_utils/gfx/material.d', + 'source/ecs_utils/gfx/shader.d', + 'source/ecs_utils/gfx/vertex.d', + 'source/ecs_utils/gfx/config.d', + 'source/ecs_utils/gfx/buffer.d', + 'source/ecs_utils/gfx/render_list.d', + 'source/ecs_utils/gfx/renderer.d', + 'source/ecs_utils/gfx/texture.d', + 'source/ecs_utils/utils.d', + 'source/ecs_utils/math/matrix.d', + 'source/ecs_utils/math/vector.d', + 'source/ecs_utils/imgui_styles.d', + 'source/ecs_utils/imgui_bind.d' +] + +bc_loader_dep = dependency('bindbc-loader', method: 'dub') +sdl_dep = dependency('bindbc-sdl', method: 'dub') + +utils_inc = include_directories(['source/','../external/sources/']) + +ecs_utils_lib = library('ecs_utils', utils_src, include_directories : [utils_inc, inc], d_args: args, link_args: link_args, + d_module_versions: ['BindSDL_Image','SDL_2010'], link_with: ecs_lib, dependencies: [bc_loader_dep,sdl_dep]) +#shared_library('ecs_utils', utils_src, include_directories : [utils_inc], d_args: args, link_args: link_args, link_with: ecs_lib) + + From 66b5807368e6cd6f9dfa6eb9f88b59e820fc07ff Mon Sep 17 00:00:00 2001 From: mmcomando Date: Sun, 21 Feb 2021 20:44:58 +0100 Subject: [PATCH 175/217] Improve meson build. -Add all required packages as wrap dependencies -Move source lsitnings to separate files -Proper dependencies declarations -Set global D compiler arguments -Add few asserts -Add test exe -Other small improvements Tested with dmd with betterC, demos executable has to be run from 'demos' directory to properly load assets. --- .gitignore | 1 + demos/external/meson.build | 12 ++++ demos/meson.build | 72 ++++++++----------- demos/source/meson.build | 20 ++++++ demos/utils/meson.build | 44 +++++------- demos/utils/source/ecs_utils/meson.build | 18 +++++ meson.build | 70 +++++++++--------- meson_options.txt | 4 +- source/meson.build | 17 +++++ subprojects/bindbc-loader.wrap | 7 ++ subprojects/bindbc-sdl.wrap | 7 ++ subprojects/cimgui.wrap | 8 +++ .../packagefiles/bindbc-loader/meson.build | 24 +++++++ .../packagefiles/bindbc-sdl/meson.build | 72 +++++++++++++++++++ subprojects/packagefiles/cimgui/meson.build | 29 ++++++++ tests/meson.build | 13 ++++ 16 files changed, 314 insertions(+), 104 deletions(-) create mode 100644 demos/external/meson.build create mode 100644 demos/source/meson.build create mode 100644 demos/utils/source/ecs_utils/meson.build create mode 100644 source/meson.build create mode 100644 subprojects/bindbc-loader.wrap create mode 100644 subprojects/bindbc-sdl.wrap create mode 100644 subprojects/cimgui.wrap create mode 100644 subprojects/packagefiles/bindbc-loader/meson.build create mode 100644 subprojects/packagefiles/bindbc-sdl/meson.build create mode 100644 subprojects/packagefiles/cimgui/meson.build create mode 100644 tests/meson.build diff --git a/.gitignore b/.gitignore index 01f3210..f2e30a3 100644 --- a/.gitignore +++ b/.gitignore @@ -8,6 +8,7 @@ !codecov.yml !skeleton.html !**/meson.build +!**/*.wrap !meson_options.txt !compile_wasm.py !compile_android.py \ No newline at end of file diff --git a/demos/external/meson.build b/demos/external/meson.build new file mode 100644 index 0000000..0bfd84c --- /dev/null +++ b/demos/external/meson.build @@ -0,0 +1,12 @@ +demos_src += files( + 'sources/cimgui/cimgui.d', + 'sources/glad/gl/all.d', + 'sources/glad/gl/enums.d', + 'sources/glad/gl/ext.d', + 'sources/glad/gl/funcs.d', + 'sources/glad/gl/gl.d', + 'sources/glad/gl/gles2.d', + 'sources/glad/gl/loader.d', + 'sources/glad/gl/types.d', + 'sources/mmutils/thread_pool.d', +) \ No newline at end of file diff --git a/demos/meson.build b/demos/meson.build index 031928f..20df64c 100644 --- a/demos/meson.build +++ b/demos/meson.build @@ -1,45 +1,35 @@ -demos_src = [ - 'source/app.d', - 'source/demos/brick_breaker.d', - 'source/demos/snake.d', - 'source/demos/simple.d', - 'source/demos/sandbox.d', - 'source/demos/bullet_madnes.d', - 'source/demos/particles.d', - 'source/demos/physics.d', - 'source/demos/space_invaders.d', - 'source/game_core/basic.d', - 'source/game_core/job_updater.d', - 'source/game_core/rendering.d', - 'source/game_core/collision.d', - 'source/gui/component.d', - 'source/gui/manager.d', - 'source/gui/template_.d', - 'source/gui/tool_circle.d', - 'source/gui/system.d' -] +# Files +demos_src = files() +external_src = files() +subdir('source') +subdir('external') -external_src = [ - 'external/sources/mmutils/thread_pool.d', - 'external/sources/glad/gl/gl.d', - 'external/sources/glad/gl/loader.d', - 'external/sources/glad/gl/ext.d', - 'external/sources/glad/gl/all.d', - 'external/sources/glad/gl/funcs.d', - 'external/sources/glad/gl/gles2.d', - 'external/sources/glad/gl/enums.d', - 'external/sources/glad/gl/types.d', - 'external/sources/cimgui/cimgui.d' -] +demos_inc = include_directories('source/') +external_inc = include_directories('external/sources/') -demos_inc = include_directories(['source/']) +# Argumesnts +versions = ['BindSDL_Image','SDL_208', 'BindBC_Static', 'BindSDL_Static'] -#link_args += '-rpath=libs/linux/x64/' -link_args += '-L=' + meson.current_source_dir() + '/libs/linux/x64/libcimgui.so' -link_args += '-L' + meson.current_source_dir() + '/libs/linux/x64' -link_args += '-lcimgui' -#,"SDL2_image +# Dependencies +bindbc_loader_dep = dependency('bindbc-loader') +bindbc_sdl_dep = dependency('bindbc-sdl') +cimgui_dep = dependency('cimgui') +sdl2_dep = dependency('SDL2') +sdl2_image_dep = dependency('SDL2_image') -executable('demos', [demos_src, external_src], include_directories : [demos_inc, utils_inc, inc], d_args: args, link_args: link_args, - d_module_versions: ['BindSDL_Image','SDL_2010'], link_with: [ecs_lib, ecs_utils_lib], dependencies: [bc_loader_dep,sdl_dep], - build_rpath: '-L' + meson.current_source_dir() + '/libs/linux/x64/', install_rpath: 'libs/linux/x64/') \ No newline at end of file +subdir('utils') # Utils library + +executable('decs-demos', [demos_src, external_src], + include_directories : [demos_inc, external_inc], + d_module_versions : versions, + link_with : [ecs_lib, ecs_utils_lib], + dependencies : [ + bindbc_loader_dep, + bindbc_sdl_dep, + cimgui_dep, + decs_dep, + ecs_utils_dep, + sdl2_dep, + sdl2_image_dep, + ], +) \ No newline at end of file diff --git a/demos/source/meson.build b/demos/source/meson.build new file mode 100644 index 0000000..e578ca0 --- /dev/null +++ b/demos/source/meson.build @@ -0,0 +1,20 @@ +demos_src += files( + 'app.d', + 'demos/brick_breaker.d', + 'demos/bullet_madnes.d', + 'demos/particles.d', + 'demos/physics.d', + 'demos/sandbox.d', + 'demos/simple.d', + 'demos/snake.d', + 'demos/space_invaders.d', + 'game_core/basic.d', + 'game_core/collision.d', + 'game_core/job_updater.d', + 'game_core/rendering.d', + 'gui/component.d', + 'gui/manager.d', + 'gui/system.d', + 'gui/template_.d', + 'gui/tool_circle.d', +) \ No newline at end of file diff --git a/demos/utils/meson.build b/demos/utils/meson.build index f184e16..de9e958 100644 --- a/demos/utils/meson.build +++ b/demos/utils/meson.build @@ -1,31 +1,25 @@ -#project('ECSUtils', 'd') +# Files +utils_src = files() +subdir('source/ecs_utils') -utils_src = [ - 'source/ecs_utils/gfx/mesh.d', - 'source/ecs_utils/gfx/sprite.d', - 'source/ecs_utils/gfx/mesh_module.d', - 'source/ecs_utils/gfx/material.d', - 'source/ecs_utils/gfx/shader.d', - 'source/ecs_utils/gfx/vertex.d', - 'source/ecs_utils/gfx/config.d', - 'source/ecs_utils/gfx/buffer.d', - 'source/ecs_utils/gfx/render_list.d', - 'source/ecs_utils/gfx/renderer.d', - 'source/ecs_utils/gfx/texture.d', - 'source/ecs_utils/utils.d', - 'source/ecs_utils/math/matrix.d', - 'source/ecs_utils/math/vector.d', - 'source/ecs_utils/imgui_styles.d', - 'source/ecs_utils/imgui_bind.d' -] +utils_inc = include_directories('source/') -bc_loader_dep = dependency('bindbc-loader', method: 'dub') -sdl_dep = dependency('bindbc-sdl', method: 'dub') +# Dependencies +ecs_utils_lib = library('ecs_utils', utils_src, + include_directories : [demos_inc, external_inc, utils_inc], + link_args : link_args, + d_module_versions : versions, + dependencies : [ + decs_dep, + bindbc_loader_dep, + bindbc_sdl_dep, + ] +) -utils_inc = include_directories(['source/','../external/sources/']) - -ecs_utils_lib = library('ecs_utils', utils_src, include_directories : [utils_inc, inc], d_args: args, link_args: link_args, - d_module_versions: ['BindSDL_Image','SDL_2010'], link_with: ecs_lib, dependencies: [bc_loader_dep,sdl_dep]) +ecs_utils_dep = declare_dependency( + include_directories : utils_inc, + link_with : ecs_utils_lib, +) #shared_library('ecs_utils', utils_src, include_directories : [utils_inc], d_args: args, link_args: link_args, link_with: ecs_lib) diff --git a/demos/utils/source/ecs_utils/meson.build b/demos/utils/source/ecs_utils/meson.build new file mode 100644 index 0000000..14d443d --- /dev/null +++ b/demos/utils/source/ecs_utils/meson.build @@ -0,0 +1,18 @@ +utils_src += files( + 'gfx/mesh.d', + 'gfx/sprite.d', + 'gfx/mesh_module.d', + 'gfx/material.d', + 'gfx/shader.d', + 'gfx/vertex.d', + 'gfx/config.d', + 'gfx/buffer.d', + 'gfx/render_list.d', + 'gfx/renderer.d', + 'gfx/texture.d', + 'utils.d', + 'math/matrix.d', + 'math/vector.d', + 'imgui_styles.d', + 'imgui_bind.d', +) \ No newline at end of file diff --git a/meson.build b/meson.build index 4951584..d5cb683 100644 --- a/meson.build +++ b/meson.build @@ -1,42 +1,29 @@ -project('DECS', 'd') - -src = [ - 'source/bubel/ecs/atomic.d', - 'source/bubel/ecs/attributes.d', - 'source/bubel/ecs/block_allocator.d', - 'source/bubel/ecs/core.d', - 'source/bubel/ecs/entity.d', - 'source/bubel/ecs/events.d', - 'source/bubel/ecs/hash_map.d', - 'source/bubel/ecs/id_manager.d', - 'source/bubel/ecs/manager.d', - 'source/bubel/ecs/package.d', - 'source/bubel/ecs/simple_vector.d', - 'source/bubel/ecs/std.d', - 'source/bubel/ecs/system.d', - 'source/bubel/ecs/traits.d', - 'source/bubel/ecs/vector.d' -] - -tests_src = [ - 'tests/tests.d' -] +project('decs', 'd', version : '0.5.0') +# Options betterC_opt = get_option('betterC') BuildDemos_opt = get_option('BuildDemos') LTO_otp = get_option('LTO') -comp = meson.get_compiler('d') +summary('betterC enabled', betterC_opt) +summary('build demos', BuildDemos_opt) +summary('LTO enabled', LTO_otp) -comp_id = comp.get_id() +meson_minimum_version = '>=0.57.1' +assert(meson.version().version_compare(meson_minimum_version), 'Newer verson of meson required, current version: @0@, required: @1@'.format(meson.version(), meson_minimum_version)) +# Files +src = files() +subdir('source') + +inc = include_directories('source/') + +# Arguments args = [] link_args = [] -if comp_id == 'gcc' - args += '-pthread' - link_args += '-pthread' -endif +comp = meson.get_compiler('d') +comp_id = comp.get_id() if LTO_otp if comp_id == 'gcc' @@ -46,7 +33,7 @@ if LTO_otp args += '-flto=thin' link_args += '-flto=thin' else - message('LTO don\'t work with DMD') + assert(false, 'Compiler "@0@" doesn\'t support LTO'.format(comp_id)) endif endif @@ -60,16 +47,27 @@ if betterC_opt endif endif -inc = include_directories('source/') -tests_inc = include_directories('source/') +add_global_arguments(args, language : 'd') +add_global_link_arguments(link_args, language : 'd') -ecs_lib = library('ecs', src, include_directories : [tests_inc, inc], d_args: args, link_args: link_args) +# Dependencies +threads_dep = dependency('threads') -executable('tests', tests_src, include_directories : [tests_inc, inc], d_args: args, link_args: link_args, link_with: ecs_lib) +ecs_lib = library('decs', + src, + include_directories : [inc], +) -bubel_ecs_dep = declare_dependency(include_directories : [inc], link_with : ecs_lib) +decs_dep = declare_dependency( + include_directories : [inc], + link_with : ecs_lib, + dependencies : threads_dep, +) +# Tests +subdir('tests') + +# Demos if BuildDemos_opt - subdir('demos/utils') subdir('demos') endif diff --git a/meson_options.txt b/meson_options.txt index 0ea2df9..ba79c90 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -1,3 +1,3 @@ -option('betterC', type: 'boolean', value: false) -option('BuildDemos', type: 'boolean', value: false) +option('betterC', type: 'boolean', value: true) +option('BuildDemos', type: 'boolean', value: true) option('LTO', type: 'boolean', value: false) \ No newline at end of file diff --git a/source/meson.build b/source/meson.build new file mode 100644 index 0000000..de5da33 --- /dev/null +++ b/source/meson.build @@ -0,0 +1,17 @@ +src += files( + 'bubel/ecs/atomic.d', + 'bubel/ecs/attributes.d', + 'bubel/ecs/block_allocator.d', + 'bubel/ecs/core.d', + 'bubel/ecs/entity.d', + 'bubel/ecs/events.d', + 'bubel/ecs/hash_map.d', + 'bubel/ecs/id_manager.d', + 'bubel/ecs/manager.d', + 'bubel/ecs/package.d', + 'bubel/ecs/simple_vector.d', + 'bubel/ecs/std.d', + 'bubel/ecs/system.d', + 'bubel/ecs/traits.d', + 'bubel/ecs/vector.d', +) \ No newline at end of file diff --git a/subprojects/bindbc-loader.wrap b/subprojects/bindbc-loader.wrap new file mode 100644 index 0000000..b99f744 --- /dev/null +++ b/subprojects/bindbc-loader.wrap @@ -0,0 +1,7 @@ +[wrap-git] +url = https://github.com/BindBC/bindbc-loader.git +revision = 9a51af991acce3c67e51695c07bf3fa6419ef938 +patch_directory = bindbc-loader + +[provide] +dependency_names = bindbc-loader diff --git a/subprojects/bindbc-sdl.wrap b/subprojects/bindbc-sdl.wrap new file mode 100644 index 0000000..3b159a0 --- /dev/null +++ b/subprojects/bindbc-sdl.wrap @@ -0,0 +1,7 @@ +[wrap-git] +url = https://github.com/BindBC/bindbc-sdl.git +revision = 5c936064b7226630f5080f4b12b77ee39c8ac64b +patch_directory = bindbc-sdl + +[provide] +dependency_names = bindbc-sdl diff --git a/subprojects/cimgui.wrap b/subprojects/cimgui.wrap new file mode 100644 index 0000000..67d2107 --- /dev/null +++ b/subprojects/cimgui.wrap @@ -0,0 +1,8 @@ +[wrap-git] +url = https://github.com/cimgui/cimgui.git +revision = 1c65ee2bdc719fb3ef62b4615d66fe8effa21148 +clone-recursive = true +patch_directory = cimgui + +[provide] +dependency_names = cimgui diff --git a/subprojects/packagefiles/bindbc-loader/meson.build b/subprojects/packagefiles/bindbc-loader/meson.build new file mode 100644 index 0000000..ce3bdf0 --- /dev/null +++ b/subprojects/packagefiles/bindbc-loader/meson.build @@ -0,0 +1,24 @@ +project('bindbc-loader', 'd', version : '0.3.2', default_options: ['default_library=static']) + +# Files +src = files( + 'source/bindbc/loader/package.d', + 'source/bindbc/loader/sharedlib.d', + 'source/bindbc/loader/system.d', +) + +inc = include_directories('source') + +# Dependencies +lib = library('bindbc-loader', src, + include_directories : [inc], + pic : true, + d_module_versions: ['BindBC_Static'], +) + +bindbc_loader_dep = declare_dependency( + include_directories : [inc], + link_with : lib, +) + +meson.override_dependency('bindbc-loader', bindbc_loader_dep) \ No newline at end of file diff --git a/subprojects/packagefiles/bindbc-sdl/meson.build b/subprojects/packagefiles/bindbc-sdl/meson.build new file mode 100644 index 0000000..0c95cc5 --- /dev/null +++ b/subprojects/packagefiles/bindbc-sdl/meson.build @@ -0,0 +1,72 @@ +project('bindbc-sdl', 'd', version : '0.19.2', default_options: ['default_library=static']) + +# Files +src = files( + 'source/bindbc/sdl/bind/package.d', + 'source/bindbc/sdl/bind/sdl.d', + 'source/bindbc/sdl/bind/sdlassert.d', + 'source/bindbc/sdl/bind/sdlatomic.d', + 'source/bindbc/sdl/bind/sdlaudio.d', + 'source/bindbc/sdl/bind/sdlblendmode.d', + 'source/bindbc/sdl/bind/sdlclipboard.d', + 'source/bindbc/sdl/bind/sdlcpuinfo.d', + 'source/bindbc/sdl/bind/sdlerror.d', + 'source/bindbc/sdl/bind/sdlevents.d', + 'source/bindbc/sdl/bind/sdlfilesystem.d', + 'source/bindbc/sdl/bind/sdlgamecontroller.d', + 'source/bindbc/sdl/bind/sdlgesture.d', + 'source/bindbc/sdl/bind/sdlhaptic.d', + 'source/bindbc/sdl/bind/sdlhints.d', + 'source/bindbc/sdl/bind/sdljoystick.d', + 'source/bindbc/sdl/bind/sdlkeyboard.d', + 'source/bindbc/sdl/bind/sdlkeycode.d', + 'source/bindbc/sdl/bind/sdlloadso.d', + 'source/bindbc/sdl/bind/sdllog.d', + 'source/bindbc/sdl/bind/sdlmessagebox.d', + 'source/bindbc/sdl/bind/sdlmouse.d', + 'source/bindbc/sdl/bind/sdlmutex.d', + 'source/bindbc/sdl/bind/sdlpixels.d', + 'source/bindbc/sdl/bind/sdlplatform.d', + 'source/bindbc/sdl/bind/sdlpower.d', + 'source/bindbc/sdl/bind/sdlrect.d', + 'source/bindbc/sdl/bind/sdlrender.d', + 'source/bindbc/sdl/bind/sdlrwops.d', + 'source/bindbc/sdl/bind/sdlscancode.d', + 'source/bindbc/sdl/bind/sdlshape.d', + 'source/bindbc/sdl/bind/sdlstdinc.d', + 'source/bindbc/sdl/bind/sdlsurface.d', + 'source/bindbc/sdl/bind/sdlsystem.d', + 'source/bindbc/sdl/bind/sdlsyswm.d', + 'source/bindbc/sdl/bind/sdlthread.d', + 'source/bindbc/sdl/bind/sdltimer.d', + 'source/bindbc/sdl/bind/sdltouch.d', + 'source/bindbc/sdl/bind/sdlversion.d', + 'source/bindbc/sdl/bind/sdlvideo.d', + 'source/bindbc/sdl/bind/sdlvulkan.d', + 'source/bindbc/sdl/config.d', + 'source/bindbc/sdl/dynload.d', + 'source/bindbc/sdl/image.d', + 'source/bindbc/sdl/mixer.d', + 'source/bindbc/sdl/net.d', + 'source/bindbc/sdl/package.d', + 'source/bindbc/sdl/ttf.d', +) + +inc = include_directories('source') + +# Dependencies +bindbc_loader_dep = dependency('bindbc-loader') + +lib = library('bindbc-sdl', src, + dependencies : bindbc_loader_dep, + include_directories : [inc], + d_module_versions: ['BindBC_Static'], + pic : true, +) + +bindbc_sdl_dep = declare_dependency( + include_directories : [inc], + link_with : lib, +) + +meson.override_dependency('bindbc-sdl', bindbc_sdl_dep) \ No newline at end of file diff --git a/subprojects/packagefiles/cimgui/meson.build b/subprojects/packagefiles/cimgui/meson.build new file mode 100644 index 0000000..e4c1a41 --- /dev/null +++ b/subprojects/packagefiles/cimgui/meson.build @@ -0,0 +1,29 @@ +project('cimgui', 'cpp', version : '1.73.0', default_options: ['default_library=shared', 'warning_level=1']) + +# Files +src = [ + 'cimgui.cpp', + 'imgui/imgui.cpp', + 'imgui/imgui_draw.cpp', + 'imgui/imgui_demo.cpp', + 'imgui/imgui_widgets.cpp', +] + +inc = [ '.' ] +pub_inc = [ 'imgui' ] + +# Dependencies +# bindbc_loader_dep = dependency('bindbc-loader') + +lib = shared_library('cimgui', src, + # dependencies : bindbc_loader_dep, + include_directories : [inc, pub_inc], + # pic : true, +) + +cimgui_dep = declare_dependency( + include_directories : [pub_inc], + link_with : lib, +) + +meson.override_dependency('cimgui', cimgui_dep) \ No newline at end of file diff --git a/tests/meson.build b/tests/meson.build new file mode 100644 index 0000000..dae8536 --- /dev/null +++ b/tests/meson.build @@ -0,0 +1,13 @@ +tests_src = files( + 'tests.d', +) + +exe = executable('decs-tests', + tests_src, + include_directories : [inc], + d_args : args, + link_args : link_args, + dependencies : decs_dep, +) + +test('basic-tests', exe) From 073f91fc4a0a0d213e5d89c22872e263000889bf Mon Sep 17 00:00:00 2001 From: Dawid Masiukiewicz Date: Thu, 25 Feb 2021 18:49:39 +0000 Subject: [PATCH 176/217] Update meson_options.txt --- meson_options.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/meson_options.txt b/meson_options.txt index ba79c90..1ab62f0 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -1,3 +1,3 @@ -option('betterC', type: 'boolean', value: true) -option('BuildDemos', type: 'boolean', value: true) -option('LTO', type: 'boolean', value: false) \ No newline at end of file +option('betterC', type: 'boolean', value: false) +option('BuildDemos', type: 'boolean', value: false) +option('LTO', type: 'boolean', value: false) From a6d92cb21bea48794d1e8c351497d80538d72525 Mon Sep 17 00:00:00 2001 From: Mergul Date: Sat, 27 Feb 2021 17:25:13 +0100 Subject: [PATCH 177/217] -change ecsID to becsID -change component_id/system_id to becsID in demos --- demos/source/app.d | 6 +- demos/source/demos/brick_breaker.d | 30 ++--- demos/source/demos/particles.d | 22 ++-- demos/source/demos/sandbox.d | 6 +- demos/source/demos/simple.d | 10 +- demos/source/demos/snake.d | 24 ++-- demos/source/demos/space_invaders.d | 196 ++++++++++++++-------------- demos/source/gui/manager.d | 19 ++- source/bubel/ecs/core.d | 45 +++++-- source/bubel/ecs/entity.d | 10 +- source/bubel/ecs/events.d | 4 +- source/bubel/ecs/manager.d | 22 ++-- source/bubel/ecs/traits.d | 14 +- tests/access_perf.d | 2 +- tests/basic.d | 134 +++++++++---------- tests/bugs.d | 8 +- tests/perf.d | 16 +-- 17 files changed, 296 insertions(+), 272 deletions(-) diff --git a/demos/source/app.d b/demos/source/app.d index 5879daf..08c154c 100644 --- a/demos/source/app.d +++ b/demos/source/app.d @@ -125,11 +125,11 @@ struct Launcher foreach(ref system; manager.systems) { - if(system.id != CountSystem.system_id && system.id != CleanSystem.system_id)system.disable(); + if(system.id != becsID!CountSystem && system.id != becsID!CleanSystem)system.disable(); } - /*launcher.manager.getSystem(CountSystem.system_id).enable(); - launcher.manager.getSystem(CleanSystem.system_id).enable();//*/ + /*launcher.manager.getSystem(becsID!CountSystem).enable(); + launcher.manager.getSystem(becsID!CleanSystem).enable();//*/ if(callbacks.register)callbacks.register(); if(callbacks.initialize)callbacks.initialize(); diff --git a/demos/source/demos/brick_breaker.d b/demos/source/demos/brick_breaker.d index c15c503..b9e30c5 100644 --- a/demos/source/demos/brick_breaker.d +++ b/demos/source/demos/brick_breaker.d @@ -372,9 +372,9 @@ void brickBreakerStart() draw_system.default_data.material_id = 0; EntityTemplate* brick_tmpl = launcher.manager.allocateTemplate( - [CLocation.component_id, CScale.component_id, CColor.component_id, - CTexCoordsIndex.component_id, CBVH.component_id, CHitPoints.component_id, - CAABB.component_id, CStatic.component_id].staticArray + [becsID!CLocation, becsID!CScale, becsID!CColor, + becsID!CTexCoordsIndex, becsID!CBVH, becsID!CHitPoints, + becsID!CAABB, becsID!CStatic].staticArray ); brick_tmpl.getComponent!CTexCoordsIndex().value = TexCoordsManager.instance.getCoordIndex(vec4(304,40,16,8)*px); brick_tmpl.getComponent!CColor().value = 0x80206020; @@ -387,10 +387,10 @@ void brickBreakerStart() big_brick_tmpl.getComponent!CScale().value = vec2(16,16); EntityTemplate* paddle_tmpl = launcher.manager.allocateTemplate( - [CLocation.component_id, CScale.component_id, CInput.component_id, - CTexCoordsIndex.component_id, CPaddle.component_id, CVelocity.component_id, - CDamping.component_id, CVelocityFactor.component_id, CBVH.component_id, - CAABB.component_id].staticArray + [becsID!CLocation, becsID!CScale, becsID!CInput, + becsID!CTexCoordsIndex, becsID!CPaddle, becsID!CVelocity, + becsID!CDamping, becsID!CVelocityFactor, becsID!CBVH, + becsID!CAABB].staticArray ); paddle_tmpl.getComponent!CTexCoordsIndex().value = TexCoordsManager.instance.getCoordIndex(vec4(272,48,64,10)*px); paddle_tmpl.getComponent!CScale().value = vec2(64,10); @@ -398,8 +398,8 @@ void brickBreakerStart() paddle_tmpl.getComponent!CVelocityFactor().value = vec2(1,0); EntityTemplate* ball_tmpl = launcher.manager.allocateTemplate( - [CLocation.component_id, CScale.component_id, //CDamping.component_id, - CTexCoordsIndex.component_id, CBall.component_id, CVelocity.component_id].staticArray + [becsID!CLocation, becsID!CScale, //becsID!CDamping, + becsID!CTexCoordsIndex, becsID!CBall, becsID!CVelocity].staticArray ); ball_tmpl.getComponent!CTexCoordsIndex().value = TexCoordsManager.instance.getCoordIndex(vec4(304,32,8,8)*px); ball_tmpl.getComponent!CScale().value = vec2(8,8); @@ -417,12 +417,12 @@ void brickBreakerStart() launcher.gui_manager.addComponent(CDamping(), "Damping"); launcher.gui_manager.addComponent(CBall(), "Ball"); - launcher.gui_manager.addSystem(MoveSystem.system_id, "Move System"); - launcher.gui_manager.addSystem(EdgeCollisionSystem.system_id, "Edge Collision System"); - launcher.gui_manager.addSystem(BallCollisionSystem.system_id, "Ball Collision System"); - launcher.gui_manager.addSystem(InputMovementSystem.system_id, "Input Movement System"); - launcher.gui_manager.addSystem(DampingSystem.system_id, "Damping System"); - launcher.gui_manager.addSystem(DamageSystem.system_id, "Damage System"); + launcher.gui_manager.addSystem(becsID!MoveSystem, "Move System"); + launcher.gui_manager.addSystem(becsID!EdgeCollisionSystem, "Edge Collision System"); + launcher.gui_manager.addSystem(becsID!BallCollisionSystem, "Ball Collision System"); + launcher.gui_manager.addSystem(becsID!InputMovementSystem, "Input Movement System"); + launcher.gui_manager.addSystem(becsID!DampingSystem, "Damping System"); + launcher.gui_manager.addSystem(becsID!DamageSystem, "Damage System"); launcher.gui_manager.addTemplate(brick_tmpl, "Brick"); launcher.gui_manager.addTemplate(big_brick_tmpl, "Big Brick"); diff --git a/demos/source/demos/particles.d b/demos/source/demos/particles.d index ec64774..b976308 100644 --- a/demos/source/demos/particles.d +++ b/demos/source/demos/particles.d @@ -494,13 +494,13 @@ void particlesStart() draw_system.default_data.material_id = 2; draw_system.default_data.texture = particles_demo.texture; - launcher.gui_manager.addSystem(MoveSystem.system_id,"Move System"); - launcher.gui_manager.addSystem(DrawSystem.system_id,"Draw System"); - launcher.gui_manager.addSystem(PlayAreaSystem.system_id,"Play Area System"); - launcher.gui_manager.addSystem(AttractSystem.system_id,"Attract System"); - launcher.gui_manager.addSystem(MouseAttractSystem.system_id,"Mouse Attract System"); - launcher.gui_manager.addSystem(DampingSystem.system_id,"Damping System"); - launcher.gui_manager.addSystem(ParticleLifeSystem.system_id,"Particle Life System"); + launcher.gui_manager.addSystem(becsID!MoveSystem,"Move System"); + launcher.gui_manager.addSystem(becsID!DrawSystem,"Draw System"); + launcher.gui_manager.addSystem(becsID!PlayAreaSystem,"Play Area System"); + launcher.gui_manager.addSystem(becsID!AttractSystem,"Attract System"); + launcher.gui_manager.addSystem(becsID!MouseAttractSystem,"Mouse Attract System"); + launcher.gui_manager.addSystem(becsID!DampingSystem,"Damping System"); + launcher.gui_manager.addSystem(becsID!ParticleLifeSystem,"Particle Life System"); // launcher.gui_manager.addComponent(CColor(),"Color (white)"); // launcher.gui_manager.addComponent(CColor(0xFF101540),"Color (red)"); @@ -516,7 +516,7 @@ void particlesStart() launcher.gui_manager.addComponent(CGravity(),"Gravity"); EntityTemplate* tmpl; - EntityTemplate* base_tmpl = launcher.manager.allocateTemplate([CTexCoords.component_id, CLocation.component_id, CColor.component_id, CVelocity.component_id, CDamping.component_id, CScale.component_id, CMaterialIndex.component_id].staticArray); + EntityTemplate* base_tmpl = launcher.manager.allocateTemplate([becsID!CTexCoords, becsID!CLocation, becsID!CColor, becsID!CVelocity, becsID!CDamping, becsID!CScale, becsID!CMaterialIndex].staticArray); base_tmpl.getComponent!CColor().value = 0xFF251010; base_tmpl.getComponent!CScale().value = vec2(2); base_tmpl.getComponent!CTexCoords().value = vec4(246,64,2,2)*px; @@ -531,15 +531,15 @@ void particlesStart() // tmpl = launcher.manager.allocateTemplate(base_tmpl); // tmpl.getComponent!CColor().value = 0xFF101540; // launcher.gui_manager.addTemplate(tmpl,"Particle (red)"); - // tmpl = launcher.manager.allocateTemplate(tmpl, [CDamping.component_id].staticArray); + // tmpl = launcher.manager.allocateTemplate(tmpl, [becsID!CDamping].staticArray); // launcher.gui_manager.addTemplate(tmpl,"Particle (damping)"); // tmpl = launcher.manager.allocateTemplate(tmpl); // tmpl.getComponent!CDamping().power = 4; // launcher.gui_manager.addTemplate(tmpl,"Particle (damping!)"); - tmpl = launcher.manager.allocateTemplate([CAttractor.component_id, CLocation.component_id, CForceRange.component_id, CScale.component_id].staticArray); + tmpl = launcher.manager.allocateTemplate([becsID!CAttractor, becsID!CLocation, becsID!CForceRange, becsID!CScale].staticArray); tmpl.getComponent!CScale().value = vec2(4); launcher.gui_manager.addTemplate(tmpl,"Attractor"); - tmpl = launcher.manager.allocateTemplate(tmpl, [CVortex.component_id].staticArray); + tmpl = launcher.manager.allocateTemplate(tmpl, [becsID!CVortex].staticArray); launcher.gui_manager.addTemplate(tmpl,"Vortex"); // tmpl = launcher.manager.allocateTemplate(tmpl); // tmpl.getComponent!CVortex().strength = -0.6; diff --git a/demos/source/demos/sandbox.d b/demos/source/demos/sandbox.d index 925ebb2..e7abb06 100644 --- a/demos/source/demos/sandbox.d +++ b/demos/source/demos/sandbox.d @@ -2,6 +2,8 @@ module demos.sandbox; import bindbc.sdl; +import bubel.ecs.core; + import demos.simple; import demos.snake; import demos.space_invaders; @@ -37,8 +39,8 @@ void sandboxStart() draw_system.default_data.texture = particles_demo.texture; draw_system.default_data.color = 0x80808080; - launcher.manager.getSystem(MouseAttractSystem.system_id).disable(); - launcher.manager.getSystem(demos.simple.MoveSystem.system_id).disable(); + launcher.manager.getSystem(becsID!MouseAttractSystem).disable(); + launcher.manager.getSystem(becsID!(demos.simple.MoveSystem)).disable(); } diff --git a/demos/source/demos/simple.d b/demos/source/demos/simple.d index ecccc12..7a8357a 100644 --- a/demos/source/demos/simple.d +++ b/demos/source/demos/simple.d @@ -134,10 +134,10 @@ void simpleStart() draw_system.default_data.size = vec2(16,16); draw_system.default_data.coords = vec4(0,48,16,16)*px;//vec4(0,0,1,1); - launcher.gui_manager.addSystem(MoveSystem.system_id,"Move Up System"); - launcher.gui_manager.addSystem(DrawSystem.system_id,"Draw System"); + launcher.gui_manager.addSystem(becsID!MoveSystem,"Move Up System"); + launcher.gui_manager.addSystem(becsID!DrawSystem,"Draw System"); - simple.tmpl = launcher.manager.allocateTemplate([CLocation.component_id, CDrawDefault.component_id].staticArray); + simple.tmpl = launcher.manager.allocateTemplate([becsID!CLocation, becsID!CDrawDefault].staticArray); //*simple.tmpl.getComponent!CTexCoordsIndex = TexCoordsManager.instance.getCoordIndex(vec4(0,48,16,16)*px); //CLocation* loc_comp = simple.tmpl.getComponent!CLocation; @@ -153,8 +153,8 @@ void simpleStart() void simpleEnd() { - launcher.manager.getSystem(MoveSystem.system_id).disable(); - launcher.manager.getSystem(DrawSystem.system_id).disable(); + launcher.manager.getSystem(becsID!MoveSystem).disable(); + launcher.manager.getSystem(becsID!DrawSystem).disable(); simple.texture.destroy(); diff --git a/demos/source/demos/snake.d b/demos/source/demos/snake.d index 865ab75..7591978 100644 --- a/demos/source/demos/snake.d +++ b/demos/source/demos/snake.d @@ -903,26 +903,26 @@ void snakeStart() //launcher.gui_manager.addComponent(CAnimation(),"Movement"); launcher.gui_manager.addComponent(CILocation(),"Int Location"); - launcher.gui_manager.addSystem(MoveSystem.system_id,"Move System"); - launcher.gui_manager.addSystem(InputSystem.system_id,"Input System"); - launcher.gui_manager.addSystem(FixSnakeDirectionSystem.system_id,"Fix Direction System"); - launcher.gui_manager.addSystem(AnimationRenderSystem.system_id,"Animation Render System"); - launcher.gui_manager.addSystem(AnimationSystem.system_id,"Animation System"); - launcher.gui_manager.addSystem(ParticleSystem.system_id,"Particle Life System"); - launcher.gui_manager.addSystem(ParticleMovementSystem.system_id,"Particle Movement System"); - launcher.gui_manager.addSystem(DrawAppleSystem.system_id,"Draw Apple System"); - launcher.gui_manager.addSystem(DrawSnakeSystem.system_id,"Draw Snake System"); + launcher.gui_manager.addSystem(becsID!MoveSystem,"Move System"); + launcher.gui_manager.addSystem(becsID!InputSystem,"Input System"); + launcher.gui_manager.addSystem(becsID!FixSnakeDirectionSystem,"Fix Direction System"); + launcher.gui_manager.addSystem(becsID!AnimationRenderSystem,"Animation Render System"); + launcher.gui_manager.addSystem(becsID!AnimationSystem,"Animation System"); + launcher.gui_manager.addSystem(becsID!ParticleSystem,"Particle Life System"); + launcher.gui_manager.addSystem(becsID!ParticleMovementSystem,"Particle Movement System"); + launcher.gui_manager.addSystem(becsID!DrawAppleSystem,"Draw Apple System"); + launcher.gui_manager.addSystem(becsID!DrawSnakeSystem,"Draw Snake System"); snake.snake_destroy_particle_frames = Mallocator.makeArray([vec4(64,144,16,16)*px,vec4(80,144,16,16)*px,vec4(96,144,16,16)*px,vec4(112,144,16,16)*px].staticArray); { - ushort[5] components = [CILocation.component_id, CSnake.component_id, CMovement.component_id, CInput.component_id, CLocation.component_id]; + ushort[5] components = [becsID!CILocation, becsID!CSnake, becsID!CMovement, becsID!CInput, becsID!CLocation]; snake.snake_tmpl = launcher.manager.allocateTemplate(components); launcher.manager.addEntity(snake.snake_tmpl,[CILocation(ivec2(2,2)).ref_].staticArray); } { - snake.snake_destroy_particle = launcher.manager.allocateTemplate([CLocation.component_id, CParticle.component_id, CParticleVector.component_id, CAnimation.component_id, CLocation.component_id].staticArray); + snake.snake_destroy_particle = launcher.manager.allocateTemplate([becsID!CLocation, becsID!CParticle, becsID!CParticleVector, becsID!CAnimation, becsID!CLocation].staticArray); CAnimation* canim = snake.snake_destroy_particle.getComponent!CAnimation; canim.frames = snake.snake_destroy_particle_frames; CParticle* particle = snake.snake_destroy_particle.getComponent!CParticle; @@ -930,7 +930,7 @@ void snakeStart() } { - ushort[3] components = [CILocation.component_id, CApple.component_id, CLocation.component_id]; + ushort[3] components = [becsID!CILocation, becsID!CApple, becsID!CLocation]; snake.apple_tmpl = launcher.manager.allocateTemplate(components); snake.addApple(); } diff --git a/demos/source/demos/space_invaders.d b/demos/source/demos/space_invaders.d index ece3c2b..67332f8 100644 --- a/demos/source/demos/space_invaders.d +++ b/demos/source/demos/space_invaders.d @@ -542,8 +542,8 @@ struct ShipWeaponSystem void create() { - laser1_tmpl = launcher.manager.allocateTemplate([CWeapon.component_id, CLocation.component_id, CShootDirection.component_id, CTargetParent.component_id, CGuild.component_id, CVelocity.component_id].staticArray); - main_weapon_tmpl = launcher.manager.allocateTemplate([CLocation.component_id, CShootDirection.component_id, CTargetParent.component_id, CGuild.component_id, CVelocity.component_id].staticArray); + laser1_tmpl = launcher.manager.allocateTemplate([becsID!CWeapon, becsID!CLocation, becsID!CShootDirection, becsID!CTargetParent, becsID!CGuild, becsID!CVelocity].staticArray); + main_weapon_tmpl = launcher.manager.allocateTemplate([becsID!CLocation, becsID!CShootDirection, becsID!CTargetParent, becsID!CGuild, becsID!CVelocity].staticArray); *laser1_tmpl.getComponent!CWeapon = CWeapon(0,CWeapon.Type.laser,3); laser1_tmpl.getComponent!CTargetParent().rel_pos = vec2(10,13); main_weapon_tmpl.getComponent!CTargetParent().rel_pos = vec2(0,4); @@ -585,11 +585,11 @@ struct ShipWeaponSystem void create() { weapon_tmpl = launcher.manager.allocateTemplate( - [CWeapon.component_id, CLocation.component_id, CShootDirection.component_id, - CTargetParent.component_id, CGuild.component_id, CVelocity.component_id, - CAutoShoot.component_id, CTarget.component_id, CTargetPlayerShip.component_id, - CRotation.component_id, CScale.component_id, CTexCoords.component_id, - CDepth.component_id, CWeaponLocation.component_id].staticArray); + [becsID!CWeapon, becsID!CLocation, becsID!CShootDirection, + becsID!CTargetParent, becsID!CGuild, becsID!CVelocity, + becsID!CAutoShoot, becsID!CTarget, becsID!CTargetPlayerShip, + becsID!CRotation, becsID!CScale, becsID!CTexCoords, + becsID!CDepth, becsID!CWeaponLocation].staticArray); *weapon_tmpl.getComponent!CWeapon = CWeapon(0,CWeapon.Type.laser,3); weapon_tmpl.getComponent!CTargetParent().rel_pos = vec2(0,0); weapon_tmpl.getComponent!CGuild().guild = 1; @@ -601,8 +601,8 @@ struct ShipWeaponSystem weapon_tmpl.getComponent!CWeaponLocation().rel_pos = vec2(0,12); top_tmpl = launcher.manager.allocateTemplate( - [CLocation.component_id, CTargetParent.component_id, CScale.component_id, - CTexCoords.component_id, CDepth.component_id].staticArray); + [becsID!CLocation, becsID!CTargetParent, becsID!CScale, + becsID!CTexCoords, becsID!CDepth].staticArray); top_tmpl.getComponent!CTargetParent().rel_pos = vec2(0,1); top_tmpl.getComponent!CScale().value = vec2(10,11); top_tmpl.getComponent!CDepth().value = -2; @@ -645,11 +645,11 @@ struct ShipWeaponSystem void create() { tower1_tmpl = launcher.manager.allocateTemplate( - [CColor.component_id, CHitMark.component_id, CHitPoints.component_id, CLocation.component_id, - CTexCoords.component_id, CScale.component_id, CEnemy.component_id, - CShootGrid.component_id, CGuild.component_id, CInit.component_id, - CChildren.component_id, CDepth.component_id, CTargetParent.component_id, - CSpawnUponDeath.component_id, CShootWaveUponDeath.component_id, CShootGridMask.component_id].staticArray + [becsID!CColor, becsID!CHitMark, becsID!CHitPoints, becsID!CLocation, + becsID!CTexCoords, becsID!CScale, becsID!CEnemy, + becsID!CShootGrid, becsID!CGuild, becsID!CInit, + becsID!CChildren, becsID!CDepth, becsID!CTargetParent, + becsID!CSpawnUponDeath, becsID!CShootWaveUponDeath, becsID!CShootGridMask].staticArray ); /*CTexCoords* tex_comp = tower1_tmpl.getComponent!CTexCoords; @@ -696,8 +696,8 @@ struct ShipWeaponSystem ship.create(); tower.create(); boss.create(); - /*ship.laser1_tmpl = launcher.manager.allocateTemplate([CWeapon.component_id, CLocation.component_id, CShootDirection.component_id, CTargetParent.component_id, CGuild.component_id, CVelocity.component_id].staticArray); - ship.main_weapon_tmpl = launcher.manager.allocateTemplate([CLocation.component_id, CShootDirection.component_id, CTargetParent.component_id, CGuild.component_id, CVelocity.component_id].staticArray); + /*ship.laser1_tmpl = launcher.manager.allocateTemplate([becsID!CWeapon, becsID!CLocation, becsID!CShootDirection, becsID!CTargetParent, becsID!CGuild, becsID!CVelocity].staticArray); + ship.main_weapon_tmpl = launcher.manager.allocateTemplate([becsID!CLocation, becsID!CShootDirection, becsID!CTargetParent, becsID!CGuild, becsID!CVelocity].staticArray); *ship.laser1_tmpl.getComponent!CWeapon = CWeapon(3,0.0); ship.laser1_tmpl.getComponent!CTargetParent().rel_pos = vec2(10,13); ship.main_weapon_tmpl.getComponent!CTargetParent().rel_pos = vec2(0,4); @@ -958,8 +958,8 @@ struct ShootingSystem void onCreate() { /*bullet_tmpl[0] = launcher.manager.allocateTemplate( - [CLocation.component_id, CTexCoords.component_id, CVelocity.component_id, - CScale.component_id, CBullet.component_id, CGuild.component_id].staticArray + [becsID!CLocation, becsID!CTexCoords, becsID!CVelocity, + becsID!CScale, becsID!CBullet, becsID!CGuild].staticArray ); bullet_tmpl[0].getComponent!CTexCoords().value = vec4(0,24,2,8)*px; bullet_tmpl[0].getComponent!CScale().value = vec2(2,8); @@ -977,9 +977,9 @@ struct ShootingSystem fire_tmpl = launcher.manager.allocateTemplate( - [CLocation.component_id, CTexCoords.component_id, CScale.component_id, - CAnimation.component_id, CParticle.component_id, CRotation.component_id, - CVelocity.component_id, CDamping.component_id].staticArray + [becsID!CLocation, becsID!CTexCoords, becsID!CScale, + becsID!CAnimation, becsID!CParticle, becsID!CRotation, + becsID!CVelocity, becsID!CDamping].staticArray ); fire_tmpl.getComponent!CTexCoords().value = vec4(96,64,8,16)*px; @@ -1174,9 +1174,9 @@ struct ParticleEmittingSystem void onCreate() { templates[0] = launcher.manager.allocateTemplate( - [CLocation.component_id, CTexCoords.component_id, CScale.component_id, - CAnimation.component_id, CParticle.component_id, CRotation.component_id, - CVelocity.component_id, CDamping.component_id, CDepth.component_id].staticArray); + [becsID!CLocation, becsID!CTexCoords, becsID!CScale, + becsID!CAnimation, becsID!CParticle, becsID!CRotation, + becsID!CVelocity, becsID!CDamping, becsID!CDepth].staticArray); *templates[0].getComponent!CAnimation() = CAnimation(flashes,0,2); *templates[0].getComponent!CParticle() = CParticle(350); //*templates[0].getComponent!CDepth() = CDepth(-3); @@ -1242,7 +1242,7 @@ struct UpgradeCollisionSystem if(space_invaders.shoot_grid.test(id, data.location[i], cast(ubyte)(0xFF))) { Entity* entity = launcher.manager.getEntity(id); - if(entity && entity.hasComponent(CShip.component_id)) + if(entity && entity.hasComponent(becsID!CShip)) { launcher.manager.sendEvent(id, EUpgrade()); launcher.manager.removeEntity(data.entity[i].id); @@ -1471,17 +1471,17 @@ struct HitPointsSystem void onCreate() { upgrade_tmpl = launcher.manager.allocateTemplate( - [CVelocity.component_id, CLocation.component_id, CTexCoords.component_id, - CScale.component_id, CUpgrade.component_id, CAnimation.component_id, - CAnimationLooped.component_id].staticArray); + [becsID!CVelocity, becsID!CLocation, becsID!CTexCoords, + becsID!CScale, becsID!CUpgrade, becsID!CAnimation, + becsID!CAnimationLooped].staticArray); //tex_comp.tex = space_invaders.texture;//ship_tex; upgrade_tmpl.getComponent!CTexCoords().value = vec4(0*px,32*px,16*px,16*px); *upgrade_tmpl.getComponent!CAnimation = CAnimation(upgrade_laser_frames, 0, 1); upgrade_tmpl.getComponent!CVelocity().value = vec2(0,-0.05); explosion_tmpl = launcher.manager.allocateTemplate( - [CDepth.component_id, CParticle.component_id, CLocation.component_id, - CTexCoords.component_id, CScale.component_id, CAnimation.component_id].staticArray); + [becsID!CDepth, becsID!CParticle, becsID!CLocation, + becsID!CTexCoords, becsID!CScale, becsID!CAnimation].staticArray); //explosion_tmpl.getComponent!(CTexCoords).tex = space_invaders.texture; *explosion_tmpl.getComponent!CAnimation = CAnimation(explosion_laser_frames, 0, 1.333); explosion_tmpl.getComponent!(CParticle).life = 600; @@ -1627,8 +1627,8 @@ struct PartsDestroySystem { flashes_emitter = launcher.manager.allocateTemplate( [ - CVelocity.component_id, CLocation.component_id, CParticleEmitter.component_id, - CParticleEmitterTime.component_id, CTargetParent.component_id, CDepth.component_id + becsID!CVelocity, becsID!CLocation, becsID!CParticleEmitter, + becsID!CParticleEmitterTime, becsID!CTargetParent, becsID!CDepth ].staticArray); *flashes_emitter.getComponent!CParticleEmitter() = CParticleEmitter(vec2(0,0), vec2(800,1600), 0); } @@ -1992,8 +1992,8 @@ struct CShipIterator { flashes_emitter = launcher.manager.allocateTemplate( [ - CVelocity.component_id, CLocation.component_id, CParticleEmitter.component_id, - CParticleEmitterTime.component_id, CTargetParent.component_id + becsID!CVelocity, becsID!CLocation, becsID!CParticleEmitter, + becsID!CParticleEmitterTime, becsID!CTargetParent ].staticArray); *flashes_emitter.getComponent!CParticleEmitter() = CParticleEmitter(vec2(0,0), vec2(400,400), 0); } @@ -2185,43 +2185,43 @@ void spaceInvadersStart() //launcher.gui_manager.addComponent(CSpawnUponDeath(),"Spawn Upon Death"); launcher.gui_manager.addComponent(CShootWaveUponDeath(CWeapon.Type.canon),"Wave Upon Death"); - launcher.gui_manager.addSystem(DrawSystem.system_id,"Draw System"); - launcher.gui_manager.addSystem(InputMovementSystem.system_id,"Input Movement"); - launcher.gui_manager.addSystem(ShootingSystem.system_id,"Shooting System"); - //launcher.gui_manager.addSystem(MovementSystem.system_id,"Movement System"); - launcher.gui_manager.addSystem(MoveSystem.system_id,"Move System"); - launcher.gui_manager.addSystem(ClampPositionSystem.system_id,"Clamp Position System"); - launcher.gui_manager.addSystem(ChangeDirectionSystem.system_id,"Change Direction System"); - launcher.gui_manager.addSystem(BulletsCollisionSystem.system_id,"Bullets Collision System"); - launcher.gui_manager.addSystem(ShootGridManager.system_id,"Shoot Grid Manager"); - launcher.gui_manager.addSystem(ShootGridCleaner.system_id,"Shoot Grid Cleaner"); - launcher.gui_manager.addSystem(HitPointsSystem.system_id,"Hit Points System"); - launcher.gui_manager.addSystem(HitMarkingSystem.system_id,"Hit Marking System"); - launcher.gui_manager.addSystem(UpgradeCollisionSystem.system_id,"Upgrade Collision System"); - launcher.gui_manager.addSystem(UpgradeSystem.system_id,"Upgrade System"); - launcher.gui_manager.addSystem(ParticleSystem.system_id,"Particle System"); - launcher.gui_manager.addSystem(AnimationSystem.system_id,"Animation System"); - launcher.gui_manager.addSystem(DampingSystem.system_id,"Damping System"); - launcher.gui_manager.addSystem(MoveToParentTargetSystem.system_id,"Move To Target System"); - launcher.gui_manager.addSystem(ParentOwnerSystem.system_id,"Parent Owner System"); - launcher.gui_manager.addSystem(ShipWeaponSystem.system_id,"Ship Weapon System"); - launcher.gui_manager.addSystem(ParticleEmittingSystem.system_id,"Particle Emitting System"); - launcher.gui_manager.addSystem(RotateToTargetSystem.system_id,"Rotate To Target System"); - launcher.gui_manager.addSystem(ShipTargetSystem.system_id,"Ship Target System"); - launcher.gui_manager.addSystem(PartsDestroySystem.system_id,"Parts Destroy System"); - launcher.gui_manager.addSystem(ChildDestroySystem.system_id,"Child Destroy System"); - launcher.gui_manager.addSystem(ShootWaveSystem.system_id,"Shoot Wave System"); - //launcher.gui_manager.addSystem(SpawnUponDeathSystem.system_id,"Child Destroy System"); + launcher.gui_manager.addSystem(becsID!DrawSystem,"Draw System"); + launcher.gui_manager.addSystem(becsID!InputMovementSystem,"Input Movement"); + launcher.gui_manager.addSystem(becsID!ShootingSystem,"Shooting System"); + //launcher.gui_manager.addSystem(becsID!MovementSystem,"Movement System"); + launcher.gui_manager.addSystem(becsID!MoveSystem,"Move System"); + launcher.gui_manager.addSystem(becsID!ClampPositionSystem,"Clamp Position System"); + launcher.gui_manager.addSystem(becsID!ChangeDirectionSystem,"Change Direction System"); + launcher.gui_manager.addSystem(becsID!BulletsCollisionSystem,"Bullets Collision System"); + launcher.gui_manager.addSystem(becsID!ShootGridManager,"Shoot Grid Manager"); + launcher.gui_manager.addSystem(becsID!ShootGridCleaner,"Shoot Grid Cleaner"); + launcher.gui_manager.addSystem(becsID!HitPointsSystem,"Hit Points System"); + launcher.gui_manager.addSystem(becsID!HitMarkingSystem,"Hit Marking System"); + launcher.gui_manager.addSystem(becsID!UpgradeCollisionSystem,"Upgrade Collision System"); + launcher.gui_manager.addSystem(becsID!UpgradeSystem,"Upgrade System"); + launcher.gui_manager.addSystem(becsID!ParticleSystem,"Particle System"); + launcher.gui_manager.addSystem(becsID!AnimationSystem,"Animation System"); + launcher.gui_manager.addSystem(becsID!DampingSystem,"Damping System"); + launcher.gui_manager.addSystem(becsID!MoveToParentTargetSystem,"Move To Target System"); + launcher.gui_manager.addSystem(becsID!ParentOwnerSystem,"Parent Owner System"); + launcher.gui_manager.addSystem(becsID!ShipWeaponSystem,"Ship Weapon System"); + launcher.gui_manager.addSystem(becsID!ParticleEmittingSystem,"Particle Emitting System"); + launcher.gui_manager.addSystem(becsID!RotateToTargetSystem,"Rotate To Target System"); + launcher.gui_manager.addSystem(becsID!ShipTargetSystem,"Ship Target System"); + launcher.gui_manager.addSystem(becsID!PartsDestroySystem,"Parts Destroy System"); + launcher.gui_manager.addSystem(becsID!ChildDestroySystem,"Child Destroy System"); + launcher.gui_manager.addSystem(becsID!ShootWaveSystem,"Shoot Wave System"); + //launcher.gui_manager.addSystem(becsID!SpawnUponDeathSystem,"Child Destroy System"); - //launcher.manager.getSystem(CleanSystem.system_id).disable(); + //launcher.manager.getSystem(becsID!CleanSystem).disable(); { space_invaders.ship_tmpl = launcher.manager.allocateTemplate( - [CVelocity.component_id, CColor.component_id, CHitMark.component_id, CHitPoints.component_id, - CLocation.component_id, CTexCoords.component_id, CInput.component_id, - CShip.component_id, CScale.component_id, CColliderScale.component_id, - CShootDirection.component_id, CShootGrid.component_id, CGuild.component_id, - CDamping.component_id, CChildren.component_id, CInit.component_id, - CShootGridMask.component_id, CVelocityFactor.component_id].staticArray + [becsID!CVelocity, becsID!CColor, becsID!CHitMark, becsID!CHitPoints, + becsID!CLocation, becsID!CTexCoords, becsID!CInput, + becsID!CShip, becsID!CScale, becsID!CColliderScale, + becsID!CShootDirection, becsID!CShootGrid, becsID!CGuild, + becsID!CDamping, becsID!CChildren, becsID!CInit, + becsID!CShootGridMask, becsID!CVelocityFactor].staticArray ); space_invaders.ship_tmpl.getComponent!CTexCoords().value = vec4(0,80,48,32)*px; space_invaders.ship_tmpl.getComponent!CScale().value = vec2(48,32); @@ -2235,7 +2235,7 @@ void spaceInvadersStart() } { - ushort[6] components = [CLocation.component_id, CTexCoords.component_id, CVelocity.component_id, CScale.component_id, CBullet.component_id, CGuild.component_id]; + ushort[6] components = [becsID!CLocation, becsID!CTexCoords, becsID!CVelocity, becsID!CScale, becsID!CBullet, becsID!CGuild]; space_invaders.laser_tmpl = launcher.manager.allocateTemplate(components); space_invaders.laser_tmpl.getComponent!CTexCoords().value = vec4(0,24,2,8)*px; @@ -2253,11 +2253,11 @@ void spaceInvadersStart() { boss_tmpl = launcher.manager.allocateTemplate( - [CColor.component_id, CHitMark.component_id, CParts.component_id, CLocation.component_id, - CTexCoords.component_id, CScale.component_id, CEnemy.component_id, - CBoss.component_id, CGuild.component_id, CInit.component_id, - CChildren.component_id, CSideMove.component_id, CVelocity.component_id, - CDepth.component_id].staticArray + [becsID!CColor, becsID!CHitMark, becsID!CParts, becsID!CLocation, + becsID!CTexCoords, becsID!CScale, becsID!CEnemy, + becsID!CBoss, becsID!CGuild, becsID!CInit, + becsID!CChildren, becsID!CSideMove, becsID!CVelocity, + becsID!CDepth].staticArray ); //CTexture* tex_comp = boss_tmpl.getComponent!CTexture; @@ -2276,10 +2276,10 @@ void spaceInvadersStart() { tower_tmpl = launcher.manager.allocateTemplate( - [CColor.component_id, CHitMark.component_id, CHitPoints.component_id, CLocation.component_id, - CTexCoords.component_id, CScale.component_id, CEnemy.component_id, - CShootGrid.component_id, CGuild.component_id, CInit.component_id, - CChildren.component_id, CShootGridMask.component_id].staticArray + [becsID!CColor, becsID!CHitMark, becsID!CHitPoints, becsID!CLocation, + becsID!CTexCoords, becsID!CScale, becsID!CEnemy, + becsID!CShootGrid, becsID!CGuild, becsID!CInit, + becsID!CChildren, becsID!CShootGridMask].staticArray ); tower_tmpl.getComponent!CTexCoords().value = vec4(96,96,16,16)*px; @@ -2290,11 +2290,11 @@ void spaceInvadersStart() { space_invaders.enemy_tmpl = launcher.manager.allocateTemplate( - [CWeaponLocation.component_id, CColor.component_id, CHitMark.component_id, CHitPoints.component_id, - CVelocity.component_id, CAutoShoot.component_id, CLocation.component_id, - CTexCoords.component_id, CScale.component_id, CWeapon.component_id, - CEnemy.component_id, CShootDirection.component_id, CShootGrid.component_id, - CGuild.component_id, CShootGridMask.component_id].staticArray + [becsID!CWeaponLocation, becsID!CColor, becsID!CHitMark, becsID!CHitPoints, + becsID!CVelocity, becsID!CAutoShoot, becsID!CLocation, + becsID!CTexCoords, becsID!CScale, becsID!CWeapon, + becsID!CEnemy, becsID!CShootDirection, becsID!CShootGrid, + becsID!CGuild, becsID!CShootGridMask].staticArray ); space_invaders.enemy_tmpl.getComponent!CTexCoords().value = vec4(32,32,16,16)*px; @@ -2329,7 +2329,7 @@ void spaceInvadersStart() EntityTemplate* upgrade_tmpl; { - upgrade_tmpl = launcher.manager.allocateTemplate([CVelocity.component_id, CLocation.component_id, CTexCoords.component_id, CScale.component_id, CUpgrade.component_id, CAnimationLooped.component_id, CAnimation.component_id].staticArray); + upgrade_tmpl = launcher.manager.allocateTemplate([becsID!CVelocity, becsID!CLocation, becsID!CTexCoords, becsID!CScale, becsID!CUpgrade, becsID!CAnimationLooped, becsID!CAnimation].staticArray); upgrade_tmpl.getComponent!CTexCoords().value = vec4(0,32,16,16)*px; upgrade_tmpl.getComponent!CVelocity().value = vec2(0,-0.05); *upgrade_tmpl.getComponent!CAnimation = CAnimation(HitPointsSystem.upgrade_laser_frames, 0, 0.75); @@ -2341,8 +2341,8 @@ void spaceInvadersStart() grouped_tmpl = launcher.manager.allocateTemplate(grouped_id); space_invaders.bullet_tmpl[0] = launcher.manager.allocateTemplate( - [CLocation.component_id, CTexCoords.component_id, CVelocity.component_id, - CScale.component_id, CBullet.component_id, CGuild.component_id].staticArray + [becsID!CLocation, becsID!CTexCoords, becsID!CVelocity, + becsID!CScale, becsID!CBullet, becsID!CGuild].staticArray ); space_invaders.bullet_tmpl[0].getComponent!CTexCoords().value = vec4(0,24,2,8)*px; space_invaders.bullet_tmpl[0].getComponent!CScale().value = vec2(2,8); @@ -2372,12 +2372,12 @@ void spaceInvadersStart() void spaceInvadersEnd() { - /*launcher.manager.getSystem(DrawSystem.system_id).disable(); - launcher.manager.getSystem(InputMovementSystem.system_id).disable(); - launcher.manager.getSystem(ShootingSystem.system_id).disable(); - launcher.manager.getSystem(MovementSystem.system_id).disable(); - launcher.manager.getSystem(ClampPositionSystem.system_id).disable(); - launcher.manager.getSystem(ShootGridCleaner.system_id).disable();*/ + /*launcher.manager.getSystem(becsID!DrawSystem).disable(); + launcher.manager.getSystem(becsID!InputMovementSystem).disable(); + launcher.manager.getSystem(becsID!ShootingSystem).disable(); + launcher.manager.getSystem(becsID!MovementSystem).disable(); + launcher.manager.getSystem(becsID!ClampPositionSystem).disable(); + launcher.manager.getSystem(becsID!ShootGridCleaner).disable();*/ //launcher.manager.freeTemplate(space_invaders.enemy_tmpl); Mallocator.dispose(space_invaders); @@ -2401,13 +2401,13 @@ bool spaceInvadersLoop() { if(igCheckbox("Move system",&simple.move_system)) { - if(simple.move_system)launcher.manager.getSystem(MoveSystem.system_id).enable(); - else launcher.manager.getSystem(MoveSystem.system_id).disable(); + if(simple.move_system)launcher.manager.getSystem(becsID!MoveSystem).enable(); + else launcher.manager.getSystem(becsID!MoveSystem).disable(); } if(igCheckbox("Draw system",&simple.draw_system)) { - if(simple.draw_system)launcher.manager.getSystem(DrawSystem.system_id).enable(); - else launcher.manager.getSystem(DrawSystem.system_id).disable(); + if(simple.draw_system)launcher.manager.getSystem(becsID!DrawSystem).enable(); + else launcher.manager.getSystem(becsID!DrawSystem).disable(); } igPushButtonRepeat(true); igColumns(3,null,0); @@ -2429,11 +2429,11 @@ bool spaceInvadersLoop() igColumns(1,null,0); if(igButton("Clear",ImVec2(-1,0))) { - launcher.manager.getSystem(CleanSystem.system_id).enable(); + launcher.manager.getSystem(becsID!CleanSystem).enable(); launcher.manager.begin(); launcher.manager.update(); launcher.manager.end(); - launcher.manager.getSystem(CleanSystem.system_id).disable(); + launcher.manager.getSystem(becsID!CleanSystem).disable(); } } igEnd(); diff --git a/demos/source/gui/manager.d b/demos/source/gui/manager.d index c7be12f..b172ffc 100644 --- a/demos/source/gui/manager.d +++ b/demos/source/gui/manager.d @@ -119,26 +119,25 @@ struct GUIManager // void addComponent(ComponentRef comp, const (char)* name) // { - // uint size = EntityManager.instance.components[comp.component_id].size; + // uint size = EntityManager.instance.components[becsID(comp)].size; // void* data = malloc(size); // memcpy(data, comp.ptr, size); - // components.add(ComponentGUI(name, data, comp.component_id)); + // components.add(ComponentGUI(name, data, becsID(comp))); // } void addComponent(T)(T comp, const (char)* name) { - static assert(hasStaticMember!(T,"component_id")); - uint size = EntityManager.instance.components[comp.component_id].size; + uint size = EntityManager.instance.components[becsID(comp)].size; void* data = malloc(size); memcpy(data, &comp, size); - components.add(ComponentGUI(name, data, comp.component_id)); + components.add(ComponentGUI(name, data, becsID(comp))); - if(edit_components.length <= comp.component_id) + if(edit_components.length <= becsID(comp)) { - edit_components.length = comp.component_id+1;//.extend(comp.component_id + 1); + edit_components.length = becsID(comp)+1;//.extend(becsID(comp) + 1); } - //edit_components[comp.component_id] = ComponentEditGUI(name); - if(edit_components[comp.component_id].variables)return; + //edit_components[becsID(comp)] = ComponentEditGUI(name); + if(edit_components[becsID(comp)].variables)return; ComponentEditGUI comp_edit; comp_edit.name = T.stringof; //enum fields = __traits(allMembers, T); @@ -246,7 +245,7 @@ struct GUIManager } } } - edit_components[comp.component_id] = comp_edit; + edit_components[becsID(comp)] = comp_edit; } void gui() diff --git a/source/bubel/ecs/core.d b/source/bubel/ecs/core.d index dc5521f..eceacf8 100644 --- a/source/bubel/ecs/core.d +++ b/source/bubel/ecs/core.d @@ -1,6 +1,6 @@ /************************************************************************************************************************ -This module contain main templates for user. -There are three structure templates (mixins) which should be added on top of structure: +This module contain main helper templates for user. +There are three structure templates (mixins) which can be added on top of structure: $(LIST * System: make system structure * Component: make component structure @@ -46,6 +46,26 @@ Struct System1 } --- +Templates ReadOnlyDependencies nad WritableDependencies are used to create list of dependencies for System. +Writable dependencies are bloking parallel execution of system which has same dependency (as writable or readonly). +This dependencies works same as Component dependencies but can be used for creating external dependencies (e.g. dependency on spatial partitioning tree access). + +--- +enum ExternalDependency1 = "ExternalDependency1"; + +Struct System1 +{ + mixin!ECS.System; + + struct EntitiesData + { + ... //used components + } + + ReadOnlyDependencies!(ExternalDependency1); +} +--- + Copyright: Copyright © 2018-2019, Dawid Masiukiewicz, Michał Masiukiewicz License: BSD 3-clause, see LICENSE file in project root folder. */ @@ -53,7 +73,7 @@ module bubel.ecs.core; public import bubel.ecs.manager; public import bubel.ecs.entity; -public import bubel.ecs.traits : ecsID; +public import bubel.ecs.traits : becsID; /************************************************************************************************************************ Main struct used as namespace for templates. @@ -65,30 +85,27 @@ static struct ECS */ mixin template System(uint jobs_count = 32) { - // __gshared ushort system_id = ushort.max; - __gshared uint __ecs_jobs_count = jobs_count; + __gshared uint __becs_jobs_count = jobs_count; } /************************************************************************************************************************ - Mark structure as Component. Should be added on top of structure (before any data). + Mark structure as Component */ mixin template Component() { - //__gshared ushort component_id = ushort.max; - ComponentRef ref_() @nogc nothrow return { - return ComponentRef(&this, ecsID!(typeof(this))); + return ComponentRef(&this, becsID!(typeof(this))); } } /************************************************************************************************************************ - Mark structure as Event. Should be added on top of structure (before any data). + Mark structure as Event */ - // mixin template Event() - // { - // __gshared ushort event_id = ushort.max; - // } + mixin template Event() + { + + } /************************************************************************************************************************ Make list of excluded components. This template get structure types as argument. Should be added inside System structure. diff --git a/source/bubel/ecs/entity.d b/source/bubel/ecs/entity.d index c1ec9c7..b6cdcb5 100644 --- a/source/bubel/ecs/entity.d +++ b/source/bubel/ecs/entity.d @@ -8,7 +8,7 @@ module bubel.ecs.entity; import bubel.ecs.system; import bubel.ecs.manager; -import bubel.ecs.traits : ecsID; +public import bubel.ecs.traits : becsID; /************************************************************************************************************************ Entity ID structure. Used as reference to Entity. Pointer to entity should be ever used to store entity reference! @@ -41,7 +41,7 @@ struct Entity return null; return cast(T*)(cast(void*)block + info.deltas[T.component_id] + block.entityIndex(&this) * T.sizeof);*/ - return cast(T*)getComponent(ecsID!T); + return cast(T*)getComponent(becsID!T); } void* getComponent(ushort component_id) const @@ -82,7 +82,7 @@ struct EntityMeta if (T.component_id >= info.deltas.length || info.deltas[T.component_id] == 0) return null; return cast(T*)(cast(void*)block + info.deltas[T.component_id] + index * T.sizeof);*/ - return cast(T*)getComponent(ecsID!T); + return cast(T*)getComponent(becsID!T); } void* getComponent(ushort component_id) const @@ -126,8 +126,8 @@ export struct EntityTemplate */ T* getComponent(T)() nothrow @nogc { - if(ecsID!T >= info.tmpl_deltas.length || info.tmpl_deltas[ecsID!T] == ushort.max)return null; - return cast(T*)(entity_data.ptr + info.tmpl_deltas[ecsID!T]); + if(becsID!T >= info.tmpl_deltas.length || info.tmpl_deltas[becsID!T] == ushort.max)return null; + return cast(T*)(entity_data.ptr + info.tmpl_deltas[becsID!T]); } } diff --git a/source/bubel/ecs/events.d b/source/bubel/ecs/events.d index 65f50a0..7cb0d0c 100644 --- a/source/bubel/ecs/events.d +++ b/source/bubel/ecs/events.d @@ -4,7 +4,7 @@ import bubel.ecs.block_allocator; import bubel.ecs.entity; import bubel.ecs.manager; import bubel.ecs.std; -import bubel.ecs.traits : ecsID; +import bubel.ecs.traits : becsID; import std.algorithm.comparison : max; @@ -33,7 +33,7 @@ package struct EventManager { uint block_id = current_index + thread_id; - EventData* data = &events[ecsID!Ev]; + EventData* data = &events[becsID!Ev]; EventBlock* block = data.blocks[block_id]; //EntityManager.EventInfo* info = &manager.events[Ev.event_id]; //event.entity_id = id; diff --git a/source/bubel/ecs/manager.d b/source/bubel/ecs/manager.d index a830604..a18dbba 100644 --- a/source/bubel/ecs/manager.d +++ b/source/bubel/ecs/manager.d @@ -408,7 +408,7 @@ export struct EntityManager ~ "\" due to non existing event \"" ~ EventName ~ "\"."); callers[i].callback = cast(void*)&callEventHandler!(EventParamType); - callers[i].id = ecsID!EventParamType; + callers[i].id = becsID!EventParamType; i++; } } @@ -1125,7 +1125,7 @@ export struct EntityManager system.m_priority = priority; //(cast(Sys*) system.m_system_pointer).__ecsInitialize(); //system.jobs = (cast(Sys*) system.m_system_pointer)._ecs_jobs; - static if(__traits(hasMember, Sys ,"__ecs_jobs_count"))system.jobs = Mallocator.makeArray!(Job)(Sys.__ecs_jobs_count); + static if(__traits(hasMember, Sys ,"__becs_jobs_count"))system.jobs = Mallocator.makeArray!(Job)(Sys.__becs_jobs_count); else system.jobs = Mallocator.makeArray!(Job)(32); static if (OnUpdateOverloadNum != -1) @@ -1194,7 +1194,7 @@ export struct EntityManager systems[$ - 1].enable(); } - ecsID!Sys = system.id; + becsID!Sys = system.id; } /************************************************************************************************************************ @@ -1212,9 +1212,9 @@ export struct EntityManager */ Sys* getSystem(Sys)() nothrow @nogc { - if (ecsID!Sys >= systems.length) + if (becsID!Sys >= systems.length) return null; - return cast(Sys*) systems[ecsID!Sys].m_system_pointer; + return cast(Sys*) systems[becsID!Sys].m_system_pointer; } export ushort registerPass(const(char)[] name) @@ -1283,7 +1283,7 @@ export struct EntityManager ushort comp_id = components_map.get(cast(char[]) ComponentName, ushort.max); if (comp_id < components.length) { - ecsID!Comp = comp_id; + becsID!Comp = comp_id; if (components[comp_id].init_data) Mallocator.dispose(components[comp_id].init_data); components[comp_id] = info; @@ -1291,7 +1291,7 @@ export struct EntityManager else { components.add(info); - ecsID!Comp = cast(ushort)(components.length - 1); + becsID!Comp = cast(ushort)(components.length - 1); char[] name = Mallocator.makeArray(cast(char[]) ComponentName); components_map.add(name, cast(ushort)(components.length - 1)); } @@ -1324,12 +1324,12 @@ export struct EntityManager ushort event_id = events_map.get(fullName!Ev, ushort.max); if (event_id < events.length) { - ecsID!Ev = event_id; + becsID!Ev = event_id; } else { events.add(info); - ecsID!Ev = cast(ushort)(events.length - 1); + becsID!Ev = cast(ushort)(events.length - 1); // events_map.add(Ev.stringof, cast(ushort)(events.length - 1)); events_map.add(fullName!Ev, cast(ushort)(events.length - 1)); } @@ -1350,7 +1350,7 @@ export struct EntityManager // "Function must match system update function."); FIXME: It's lead to crash on android build // static assert(__traits(hasMember, Sys, "system_id"), "Sys must be system type."); - System* system = getSystem(ecsID!Sys); + System* system = getSystem(becsID!Sys); assert(system != null, "System must be registered in EntityManager before any funcion can be called."); if (!system.m_any_system_caller) @@ -2256,7 +2256,7 @@ export struct EntityManager ushort[num] del_ids; static foreach (i, comp; Components) { - del_ids[i] = ecsID!comp; + del_ids[i] = becsID!comp; } removeComponents(entity_id, del_ids); diff --git a/source/bubel/ecs/traits.d b/source/bubel/ecs/traits.d index b2ead93..3af4b86 100644 --- a/source/bubel/ecs/traits.d +++ b/source/bubel/ecs/traits.d @@ -2,16 +2,22 @@ module bubel.ecs.traits; import std.traits; -ref ushort ecsID(T)() +/************************************************************************************************************************ + Return Component/System/Event unique ID +*/ +ref ushort becsID(T)() { __gshared ushort id = ushort.max; return id; } -ref ushort ecsID(T)(T obj) +/************************************************************************************************************************ + Return Component/System/Event unique ID +*/ +ref ushort becsID(T)(T obj) { - static if(isPointer!T)return ecsID!(PointerTarget!T); - else return ecsID!T; + static if(isPointer!T)return becsID!(PointerTarget!T); + else return becsID!T; } bool isForeachDelegateWithTypes(DG, Types...)() diff --git a/tests/access_perf.d b/tests/access_perf.d index 74d201b..b1b16bf 100644 --- a/tests/access_perf.d +++ b/tests/access_perf.d @@ -65,7 +65,7 @@ void beforeEveryTest() gEM.endRegister(); - tmpl = gEM.allocateTemplate([ecsID!CLong, ecsID!CInt, ecsID!CUInt, ecsID!CBig].staticArray); + tmpl = gEM.allocateTemplate([becsID!CLong, becsID!CInt, becsID!CUInt, becsID!CBig].staticArray); foreach(i; 0 .. 100_000)gEM.addEntity(tmpl); } diff --git a/tests/basic.d b/tests/basic.d index d544071..5f1fbd7 100644 --- a/tests/basic.d +++ b/tests/basic.d @@ -115,7 +115,7 @@ struct EmptySystem void beforeEveryTest() { - ecsID!CUnregistered = ushort.max; + becsID!CUnregistered = ushort.max; gEM.initialize(0); gEM.beginRegister(); @@ -138,17 +138,17 @@ void afterEveryTest() @("EntityMeta") unittest { - EntityTemplate* tmpl_ = gEM.allocateTemplate([ecsID!CInt, ecsID!CFloat, ecsID!CFlag].staticArray); + EntityTemplate* tmpl_ = gEM.allocateTemplate([becsID!CInt, becsID!CFloat, becsID!CFlag].staticArray); Entity* entity = gEM.addEntity(tmpl_); EntityMeta meta = entity.getMeta(); - assert(meta.hasComponent(ecsID!CInt)); + assert(meta.hasComponent(becsID!CInt)); assert(meta.getComponent!CInt); - assert(meta.hasComponent(ecsID!CFloat)); + assert(meta.hasComponent(becsID!CFloat)); assert(meta.getComponent!CFloat); assert(!meta.getComponent!CLong); - assert(!meta.hasComponent(ecsID!CLong)); + assert(!meta.hasComponent(becsID!CLong)); assert(!meta.getComponent!CUnregistered); - assert(!meta.hasComponent(ecsID!CUnregistered)); + assert(!meta.hasComponent(becsID!CUnregistered)); assert(*meta.getComponent!CInt == 1); assert(*meta.getComponent!CFloat == 2.0); } @@ -156,7 +156,7 @@ unittest @("AddEntity") unittest { - EntityTemplate* tmpl_ = gEM.allocateTemplate([ecsID!CInt, ecsID!CFloat, ecsID!CFlag].staticArray); + EntityTemplate* tmpl_ = gEM.allocateTemplate([becsID!CInt, becsID!CFloat, becsID!CFlag].staticArray); assert(tmpl_.info.components.length == 3); assert(tmpl_.info.size == (CInt.sizeof + CFloat.sizeof + EntityID.sizeof)); assert(tmpl_.getComponent!CInt); @@ -185,8 +185,8 @@ unittest //Entity* entity3 = gEM.addEntity(tmpl_, [cint.ref_, clong.ref_].staticArray); Entity* entity3 = gEM.addEntity(tmpl_, [CInt(10).ref_, CLong().ref_, CFlag().ref_].staticArray); EntityID id = entity3.id; - assert(entity3.hasComponent(ecsID!CInt)); - assert(entity3.hasComponent(ecsID!CFloat)); + assert(entity3.hasComponent(becsID!CInt)); + assert(entity3.hasComponent(becsID!CFloat)); assert(*entity3.getComponent!CInt == 10); assert(*entity3.getComponent!CFloat == 2.0); @@ -201,7 +201,7 @@ unittest assert(*entity3.getComponent!CFloat == 2.0); assert(*entity3.getComponent!CShort == 2); - gEM.removeComponents(entity3.id, [ecsID!CFlag,ecsID!CShort].staticArray); + gEM.removeComponents(entity3.id, [becsID!CFlag,becsID!CShort].staticArray); gEM.commit(); entity3 = gEM.getEntity(id); assert(entity3.getComponent!CInt); @@ -212,7 +212,7 @@ unittest assert(*entity3.getComponent!CFloat == 2.0); gEM.addComponents(entity3.id, [CFlag().ref_,CShort(2).ref_].staticArray); - gEM.removeComponents(entity3.id, [ecsID!CUnregistered].staticArray); + gEM.removeComponents(entity3.id, [becsID!CUnregistered].staticArray); gEM.commit(); entity3 = gEM.getEntity(id); assert(entity3.getComponent!CInt); @@ -235,7 +235,7 @@ unittest assert(entity3.getComponent!CUnregistered); assert(*entity3.getComponent!CUnregistered == 4); - gEM.removeComponents(entity3.id, [ecsID!CUnregistered].staticArray); + gEM.removeComponents(entity3.id, [becsID!CUnregistered].staticArray); gEM.commit(); entity3 = gEM.getEntity(id); assert(!entity3.getComponent!CUnregistered); @@ -247,9 +247,9 @@ unittest unittest { //basic template allocation - ushort[2] ids = [ecsID!CInt, ecsID!CFloat]; + ushort[2] ids = [becsID!CInt, becsID!CFloat]; EntityTemplate* tmpl_ = gEM.allocateTemplate(ids); - EntityTemplate* tmpl_d = gEM.allocateTemplate([ecsID!CFloat, ecsID!CInt, ecsID!CFloat].staticArray); + EntityTemplate* tmpl_d = gEM.allocateTemplate([becsID!CFloat, becsID!CInt, becsID!CFloat].staticArray); EntityTemplate* tmpl_cp = gEM.allocateTemplate(tmpl_); assert(tmpl_d.info == tmpl_.info); assert(tmpl_cp.info == tmpl_cp.info); @@ -268,7 +268,7 @@ unittest *tmpl_.getComponent!CFloat = 5.0; //allocate template from template with additional components - ushort[2] ids2 = [ecsID!CDouble,ecsID!CFlag]; + ushort[2] ids2 = [becsID!CDouble,becsID!CFlag]; EntityTemplate* tmpl_2 = gEM.allocateTemplate(tmpl_, ids2); assert(tmpl_2.info.components.length == 4); assert(tmpl_2.getComponent!CInt); @@ -313,7 +313,7 @@ unittest assert(*tmpl_4.getComponent!CDouble == 3.0); //allocate template from template with three additional component - ushort[3] ids3 = [ecsID!CDouble, ecsID!CLong, ecsID!CShort]; + ushort[3] ids3 = [becsID!CDouble, becsID!CLong, becsID!CShort]; EntityTemplate* tmpl_5 = gEM.allocateTemplate(tmpl_2, ids3); assert(tmpl_5.info.components.length == 6); assert(tmpl_5.getComponent!CInt); @@ -328,7 +328,7 @@ unittest assert(*tmpl_5.getComponent!CShort == 12); //allocate template from template without one component - ushort[1] rem_ids = [ecsID!CFloat]; + ushort[1] rem_ids = [becsID!CFloat]; EntityTemplate* tmpl_6 = gEM.allocateTemplate(tmpl_, null, rem_ids); assert(tmpl_6.info.components.length == 1); assert(tmpl_6.getComponent!CInt); @@ -358,8 +358,8 @@ unittest unittest { //basic template allocation - ushort[2] ids = [ecsID!CFloat, ecsID!CInt]; - ushort[2] ids2 = [ecsID!CInt, ecsID!CFloat]; + ushort[2] ids = [becsID!CFloat, becsID!CInt]; + ushort[2] ids2 = [becsID!CInt, becsID!CFloat]; EntityTemplate* tmpl_ = gEM.allocateTemplate(ids); EntityTemplate* tmpl_2 = gEM.allocateTemplate(ids2); assert(tmpl_.info.components.length == 2); @@ -398,9 +398,9 @@ unittest assert(system !is null); assert(system.count == 0); - System* ecs_system = gEM.getSystem(ecsID!EmptySystem); + System* ecs_system = gEM.getSystem(becsID!EmptySystem); assert(ecs_system !is null); - assert(ecs_system.id == ecsID!EmptySystem); + assert(ecs_system.id == becsID!EmptySystem); assert(ecs_system.name == "tests.basic.EmptySystem"); gEM.begin(); @@ -502,7 +502,7 @@ unittest //FIXME: currently destroy is only called with Manager.destory which is bug, but there is no workaround for this by now //assert(destroy == 1); - System* ecs_system = gEM.getSystem(system.ecsID); + System* ecs_system = gEM.getSystem(system.becsID); ecs_system.enable(); assert(system.enable == 1); @@ -513,7 +513,7 @@ unittest assert(system.disable == 1); - ushort[2] ids = [ecsID!CLong,ecsID!CFloat]; + ushort[2] ids = [becsID!CLong,becsID!CFloat]; EntityTemplate* tmpl = gEM.allocateTemplate(ids); scope (exit) gEM.freeTemplate(tmpl); gEM.addEntity(tmpl); @@ -527,7 +527,7 @@ unittest gEM.end(); assert(system.end == 1); - ushort[2] ids2 = [ecsID!CLong, ecsID!CInt]; + ushort[2] ids2 = [becsID!CLong, becsID!CInt]; EntityTemplate* tmpl2 = gEM.allocateTemplate(ids2); scope (exit) gEM.freeTemplate(tmpl2); gEM.addEntity(tmpl2); @@ -542,7 +542,7 @@ unittest gEM.end(); assert(system.end == 2); - ushort[2] ids3 = [ecsID!CLong, ecsID!CShort]; + ushort[2] ids3 = [becsID!CLong, becsID!CShort]; EntityTemplate* tmpl3 = gEM.allocateTemplate(ids3); scope (exit) gEM.freeTemplate(tmpl3); gEM.addEntity(tmpl3); @@ -601,13 +601,13 @@ unittest assert(system !is null); assert(system.updates_count == 0); - System* ecs_system = gEM.getSystem(ecsID!LongAddSystem); + System* ecs_system = gEM.getSystem(becsID!LongAddSystem); assert(ecs_system !is null); - assert(ecs_system.id == ecsID!LongAddSystem); + assert(ecs_system.id == becsID!LongAddSystem); assert(ecs_system.priority == -1); assert(ecs_system.name == "tests.basic.LongAddSystem"); - ushort[1] ids = [ecsID!CLong]; + ushort[1] ids = [becsID!CLong]; EntityTemplate* tmpl = gEM.allocateTemplate(ids); scope (exit) gEM.freeTemplate(tmpl); gEM.addEntity(tmpl); @@ -757,19 +757,19 @@ unittest assert(system.remove == 0); assert(system.change == 0); - EntityTemplate* tmpl = gEM.allocateTemplate([ecsID!CLong,ecsID!CFloat].staticArray); + EntityTemplate* tmpl = gEM.allocateTemplate([becsID!CLong,becsID!CFloat].staticArray); scope (exit) gEM.freeTemplate(tmpl); EntityID id0 = gEM.addEntity(tmpl).id; gEM.commit(); assert(system.add == 1); - EntityTemplate* tmpl2 = gEM.allocateTemplate([ecsID!CLong, ecsID!CInt].staticArray); + EntityTemplate* tmpl2 = gEM.allocateTemplate([becsID!CLong, becsID!CInt].staticArray); scope (exit) gEM.freeTemplate(tmpl2); EntityID id1 = gEM.addEntity(tmpl2).id; gEM.commit(); assert(system.add == 2); - EntityTemplate* tmpl3 = gEM.allocateTemplate([ecsID!CLong, ecsID!CShort].staticArray); + EntityTemplate* tmpl3 = gEM.allocateTemplate([becsID!CLong, becsID!CShort].staticArray); scope (exit) gEM.freeTemplate(tmpl3); EntityID id2 = gEM.addEntity(tmpl3).id; gEM.commit(); @@ -778,19 +778,19 @@ unittest gEM.beginRegister(); gEM.endRegister(); - gEM.removeComponents(id0, [ecsID!CFloat].staticArray); + gEM.removeComponents(id0, [becsID!CFloat].staticArray); gEM.commit(); assert(system.add == 2); assert(system.remove == 0); assert(system.change == 0); - gEM.removeComponents(id1, [ecsID!CInt].staticArray); + gEM.removeComponents(id1, [becsID!CInt].staticArray); gEM.commit(); assert(system.add == 2); assert(system.remove == 0); assert(system.change == 1); - gEM.removeComponents(id2, [ecsID!CShort].staticArray); + gEM.removeComponents(id2, [becsID!CShort].staticArray); gEM.commit(); assert(system.add == 3); assert(system.remove == 0); @@ -889,7 +889,7 @@ unittest } assert(gEM.getSystem!TestSystem is null); - assert(gEM.getSystem(ecsID!TestSystem) is null); + assert(gEM.getSystem(becsID!TestSystem) is null); } @("MultithreadedUpdate") @@ -961,10 +961,10 @@ unittest TestSystem* system = gEM.getSystem!TestSystem; TestEmptySystem* empty_system = gEM.getSystem!TestEmptySystem; - ushort[2] ids = [ecsID!CLong,ecsID!CFloat]; + ushort[2] ids = [becsID!CLong,becsID!CFloat]; EntityTemplate* tmpl = gEM.allocateTemplate(ids); scope (exit) gEM.freeTemplate(tmpl); - EntityTemplate* tmpl2 = gEM.allocateTemplate([ecsID!CLong,ecsID!CInt,ecsID!CShort,ecsID!CFloat].staticArray); + EntityTemplate* tmpl2 = gEM.allocateTemplate([becsID!CLong,becsID!CInt,becsID!CShort,becsID!CFloat].staticArray); scope (exit) gEM.freeTemplate(tmpl2); gEM.begin(); @@ -1059,7 +1059,7 @@ unittest @("AddRemoveEntities") unittest { - ushort[3] ids = [ecsID!CLong,ecsID!CFloat,ecsID!CShort]; + ushort[3] ids = [becsID!CLong,becsID!CFloat,becsID!CShort]; EntityTemplate* tmpl = gEM.allocateTemplate(ids); scope (exit) gEM.freeTemplate(tmpl); @@ -1089,7 +1089,7 @@ unittest gEM.endRegister(); - ushort[1] ids = [ecsID!CLong]; + ushort[1] ids = [becsID!CLong]; EntityTemplate* tmpl = gEM.allocateTemplate(ids); scope (exit) gEM.freeTemplate(tmpl); @@ -1118,7 +1118,7 @@ unittest assert(*entity.getComponent!CShort == 15); assert(*entity.getComponent!CFloat == 13); - ushort[3] ids2 = [ecsID!CFloat, ecsID!CLong, ecsID!CUnregistered]; + ushort[3] ids2 = [becsID!CFloat, becsID!CLong, becsID!CUnregistered]; gEM.removeComponents(id, ids2); gEM.commit(); @@ -1253,10 +1253,10 @@ unittest gEM.endRegister(); - ushort[1] ids = [ecsID!CLong]; + ushort[1] ids = [becsID!CLong]; EntityTemplate* tmpl = gEM.allocateTemplate(ids); scope (exit) gEM.freeTemplate(tmpl); - ushort[1] ids2 = [ecsID!CShort]; + ushort[1] ids2 = [becsID!CShort]; EntityTemplate* tmpl2 = gEM.allocateTemplate(ids2); scope (exit) gEM.freeTemplate(tmpl2); @@ -1348,11 +1348,11 @@ unittest gEM.endRegister(); - EntityTemplate* tmpl = gEM.allocateTemplate([ecsID!CInt].staticArray); + EntityTemplate* tmpl = gEM.allocateTemplate([becsID!CInt].staticArray); scope (exit) gEM.freeTemplate(tmpl); EntityID id1 = gEM.addEntity(tmpl).id; - EntityTemplate* tmpl2 = gEM.allocateTemplate([ecsID!CInt, ecsID!CLong].staticArray); + EntityTemplate* tmpl2 = gEM.allocateTemplate([becsID!CInt, becsID!CLong].staticArray); scope (exit) gEM.freeTemplate(tmpl2); EntityID id2 = gEM.addEntity(tmpl2).id; @@ -1471,22 +1471,22 @@ unittest const (EntityManager.UpdatePass)* pass = gEM.getPass("update"); assert(pass != null); assert(pass.system_callers.length == 5); - assert(pass.system_callers[0].system_id == ecsID!TestSystem); - assert(pass.system_callers[1].system_id == ecsID!TestSystem2); - assert(pass.system_callers[2].system_id == ecsID!TestSystem3); - assert(pass.system_callers[3].system_id == ecsID!TestSystem4); - assert(pass.system_callers[4].system_id == ecsID!TestSystem5); + assert(pass.system_callers[0].system_id == becsID!TestSystem); + assert(pass.system_callers[1].system_id == becsID!TestSystem2); + assert(pass.system_callers[2].system_id == becsID!TestSystem3); + assert(pass.system_callers[3].system_id == becsID!TestSystem4); + assert(pass.system_callers[4].system_id == becsID!TestSystem5); assert(pass.system_callers[0].dependencies.length == 0); assert(pass.system_callers[1].dependencies.length == 1); assert(pass.system_callers[2].dependencies.length == 1); assert(pass.system_callers[3].dependencies.length == 3); assert(pass.system_callers[4].dependencies.length == 1); - assert(pass.system_callers[1].dependencies[0].system_id == ecsID!TestSystem); - assert(pass.system_callers[2].dependencies[0].system_id == ecsID!TestSystem2); - assert(pass.system_callers[3].dependencies[0].system_id == ecsID!TestSystem); - assert(pass.system_callers[3].dependencies[1].system_id == ecsID!TestSystem2); - assert(pass.system_callers[3].dependencies[2].system_id == ecsID!TestSystem3); - assert(pass.system_callers[4].dependencies[0].system_id == ecsID!TestSystem4); + assert(pass.system_callers[1].dependencies[0].system_id == becsID!TestSystem); + assert(pass.system_callers[2].dependencies[0].system_id == becsID!TestSystem2); + assert(pass.system_callers[3].dependencies[0].system_id == becsID!TestSystem); + assert(pass.system_callers[3].dependencies[1].system_id == becsID!TestSystem2); + assert(pass.system_callers[3].dependencies[2].system_id == becsID!TestSystem3); + assert(pass.system_callers[4].dependencies[0].system_id == becsID!TestSystem4); } @("ExternalSystemDependencies") @@ -1598,21 +1598,21 @@ unittest const (EntityManager.UpdatePass)* pass = gEM.getPass("update"); assert(pass != null); assert(pass.system_callers.length == 5); - assert(pass.system_callers[0].system_id == ecsID!TestSystem); - assert(pass.system_callers[1].system_id == ecsID!TestSystem2); - assert(pass.system_callers[2].system_id == ecsID!TestSystem3); - assert(pass.system_callers[3].system_id == ecsID!TestSystem4); - assert(pass.system_callers[4].system_id == ecsID!TestSystem5); + assert(pass.system_callers[0].system_id == becsID!TestSystem); + assert(pass.system_callers[1].system_id == becsID!TestSystem2); + assert(pass.system_callers[2].system_id == becsID!TestSystem3); + assert(pass.system_callers[3].system_id == becsID!TestSystem4); + assert(pass.system_callers[4].system_id == becsID!TestSystem5); assert(pass.system_callers[0].dependencies.length == 0); assert(pass.system_callers[1].dependencies.length == 1); assert(pass.system_callers[2].dependencies.length == 1); assert(pass.system_callers[3].dependencies.length == 3); assert(pass.system_callers[4].dependencies.length == 2); - assert(pass.system_callers[1].dependencies[0].system_id == ecsID!TestSystem); - assert(pass.system_callers[2].dependencies[0].system_id == ecsID!TestSystem2); - assert(pass.system_callers[3].dependencies[0].system_id == ecsID!TestSystem); - assert(pass.system_callers[3].dependencies[1].system_id == ecsID!TestSystem2); - assert(pass.system_callers[3].dependencies[2].system_id == ecsID!TestSystem3); - assert(pass.system_callers[4].dependencies[0].system_id == ecsID!TestSystem2); - assert(pass.system_callers[4].dependencies[1].system_id == ecsID!TestSystem4); + assert(pass.system_callers[1].dependencies[0].system_id == becsID!TestSystem); + assert(pass.system_callers[2].dependencies[0].system_id == becsID!TestSystem2); + assert(pass.system_callers[3].dependencies[0].system_id == becsID!TestSystem); + assert(pass.system_callers[3].dependencies[1].system_id == becsID!TestSystem2); + assert(pass.system_callers[3].dependencies[2].system_id == becsID!TestSystem3); + assert(pass.system_callers[4].dependencies[0].system_id == becsID!TestSystem2); + assert(pass.system_callers[4].dependencies[1].system_id == becsID!TestSystem4); } \ No newline at end of file diff --git a/tests/bugs.d b/tests/bugs.d index 4a97c03..25f2ad1 100644 --- a/tests/bugs.d +++ b/tests/bugs.d @@ -45,7 +45,7 @@ unittest void onCreate() { - tmpl = gEM.allocateTemplate([ecsID!CInt, ecsID!CLong].staticArray); + tmpl = gEM.allocateTemplate([becsID!CInt, becsID!CLong].staticArray); } void onDestroy() @@ -118,7 +118,7 @@ unittest gEM.endRegister(); - EntityTemplate* tmpl = gEM.allocateTemplate([ecsID!CInt, ecsID!CLong].staticArray); + EntityTemplate* tmpl = gEM.allocateTemplate([becsID!CInt, becsID!CLong].staticArray); EntityID id = gEM.addEntity(tmpl,[CLong(10).ref_, CInt(6).ref_].staticArray).id; EntityID id2 = gEM.addEntity(tmpl,[CInt(4).ref_].staticArray).id; gEM.freeTemplate(tmpl); @@ -126,13 +126,13 @@ unittest gEM.sendEvent(id2, Event1(id)); - gEM.getSystem(ecsID!System2).disable(); + gEM.getSystem(becsID!System2).disable(); gEM.begin(); gEM.update(); gEM.end(); - gEM.getSystem(ecsID!System2).enable(); + gEM.getSystem(becsID!System2).enable(); gEM.begin(); gEM.update(); diff --git a/tests/perf.d b/tests/perf.d index fcf3ab4..cc6be94 100644 --- a/tests/perf.d +++ b/tests/perf.d @@ -86,22 +86,22 @@ void afterEveryTest() void smallTmpl() { - tmpl = gEM.allocateTemplate([ecsID!CShort].staticArray); + tmpl = gEM.allocateTemplate([becsID!CShort].staticArray); } void bigTmpl() { - tmpl = gEM.allocateTemplate([ecsID!CBig].staticArray); + tmpl = gEM.allocateTemplate([becsID!CBig].staticArray); } void multiSmallTmpl() { - tmpl = gEM.allocateTemplate([ecsID!CShort, ecsID!CLong, ecsID!CInt, ecsID!CUInt].staticArray); + tmpl = gEM.allocateTemplate([becsID!CShort, becsID!CLong, becsID!CInt, becsID!CUInt].staticArray); } void multiBigTmpl() { - tmpl = gEM.allocateTemplate([ecsID!CLong, ecsID!CInt, ecsID!CUInt, ecsID!CBig].staticArray); + tmpl = gEM.allocateTemplate([becsID!CLong, becsID!CInt, becsID!CUInt, becsID!CBig].staticArray); } @("AddEntities100k1comp2b") @(before, &smallTmpl) @@ -138,25 +138,25 @@ void allocDealloc100k() void smallTmplPreAlloc() { - tmpl = gEM.allocateTemplate([ecsID!CShort].staticArray); + tmpl = gEM.allocateTemplate([becsID!CShort].staticArray); allocDealloc100k(); } void bigTmplPreAlloc() { - tmpl = gEM.allocateTemplate([ecsID!CBig].staticArray); + tmpl = gEM.allocateTemplate([becsID!CBig].staticArray); allocDealloc100k(); } void multiSmallTmplPreAlloc() { - tmpl = gEM.allocateTemplate([ecsID!CShort, ecsID!CLong, ecsID!CInt, ecsID!CUInt].staticArray); + tmpl = gEM.allocateTemplate([becsID!CShort, becsID!CLong, becsID!CInt, becsID!CUInt].staticArray); allocDealloc100k(); } void multiBigTmplPreAlloc() { - tmpl = gEM.allocateTemplate([ecsID!CLong, ecsID!CInt, ecsID!CUInt, ecsID!CBig].staticArray); + tmpl = gEM.allocateTemplate([becsID!CLong, becsID!CInt, becsID!CUInt, becsID!CBig].staticArray); allocDealloc100k(); } From 56f870bac618941b6986cae2eeb35edb5734b379 Mon Sep 17 00:00:00 2001 From: Mergul Date: Mon, 1 Mar 2021 12:16:02 +0100 Subject: [PATCH 178/217] -updated README.md -fixed shaders for GL2 -added Entity selection tool -throw out tools from "Demo" window to "Tools" window -change ComboBox to Tabs for Tools -Added more verbose tips -Improved and fixed BrickBreaker collisions -fixed simple DUB issue --- README.md | 12 +- demos/assets/shaders/additive_particles.fp | 9 +- demos/assets/shaders/additive_particles.vp | 9 +- demos/assets/shaders/base.fp | 12 +- demos/assets/shaders/base.vp | 9 +- demos/assets/shaders/circle.fp | 9 +- demos/assets/shaders/circle.vp | 9 +- demos/source/app.d | 190 ++++++++++++++++++--- demos/source/demos/brick_breaker.d | 75 ++++---- demos/source/demos/particles.d | 16 +- demos/source/demos/sandbox.d | 3 +- demos/source/demos/simple.d | 30 +++- demos/source/demos/snake.d | 9 +- demos/source/demos/space_invaders.d | 11 +- demos/source/game_core/basic.d | 4 + demos/source/game_core/collision.d | 8 +- demos/source/gui/manager.d | 22 ++- demos/utils/dub.json | 2 +- demos/utils/source/ecs_utils/gfx/shader.d | 2 +- dub.json | 2 +- tests/tests.d | 22 +-- 21 files changed, 332 insertions(+), 133 deletions(-) diff --git a/README.md b/README.md index b223f72..d70058c 100644 --- a/README.md +++ b/README.md @@ -57,7 +57,6 @@ There are some assumptions that should be considered when developing application * Better EventManager - there are several optimization and improvements that can be added in the future. * More demos and examples - demo appliaction is very basic now, but in future more minigames and sanbox mode (opportunity to mix many components and systems) are planned. * C API - in highly depends on amount of work required. Makes possible to use library from different languages. - * GPU compute - idea in draft stage. Special components and systems whose data wolud be on GPU memory. * More smaller improvements... For more information about design and usage feel free to read [documentation](https://mergul.gitlab.io/bubel-ecs/ecs.html)**(WIP)** and [WIKI](https://gitlab.com/Mergul/bubel-ecs/-/wikis/home). @@ -104,14 +103,12 @@ Online demo support multithreading and page tries to check if client support WAS struct Position { - mixin ECS.Components; //makes struct component float x; float y; } struct Velocity { - mixin ECS.Components; //default values works float x = 0.1; float y = 1; @@ -119,7 +116,6 @@ struct Velocity struct StaticFlag { - mixin ECS.Components; } struct UpdateSystem @@ -132,7 +128,7 @@ struct UpdateSystem { int length; //entities count @readonly Entity[] entities; //entities arrays, entity contain ID only - Position[] positions; //positions array + Position[] positions; //positions array, by default components are considered to has write access (used for multithreading dependencies) @readonly Velocity[] velocities; //veocities array, readonly (Multithreading tag) } @@ -158,7 +154,7 @@ void main() manager.endRegister(); //allocate template - EntityTemplate* tmpl = manager.allocateEmplate([Velocity.component_id, Position.component_id].staticArray); + EntityTemplate* tmpl = manager.allocateEmplate([becsID!Velocity, becsID!Position].staticArray); scope (exit) manager.freeTemplate(tmpl); //gets pointer to template component data @@ -170,9 +166,9 @@ void main() manager.addEntity(tmpl); } - manager.begin(); //start frame + manager.begin(); //start frame, inside system onBegin callbacks are called manager.update(); //update all systems, there onUpdate callbacks are called - manager.end(); //end frame + manager.end(); //end frame, inside system onEnd callbacks are called } ``` diff --git a/demos/assets/shaders/additive_particles.fp b/demos/assets/shaders/additive_particles.fp index 047f647..df711a2 100644 --- a/demos/assets/shaders/additive_particles.fp +++ b/demos/assets/shaders/additive_particles.fp @@ -1,10 +1,9 @@ -precision mediump int; -precision mediump float; -precision lowp sampler2D; -precision lowp samplerCube; - #ifdef GLES + precision mediump int; + precision mediump float; + precision lowp sampler2D; + precision lowp samplerCube; #define TEX(x,y) texture2D(x,y) #if __VERSION__ >290 #define M_IN in mediump diff --git a/demos/assets/shaders/additive_particles.vp b/demos/assets/shaders/additive_particles.vp index 2777a24..cf90081 100644 --- a/demos/assets/shaders/additive_particles.vp +++ b/demos/assets/shaders/additive_particles.vp @@ -1,8 +1,9 @@ -precision highp float; -precision highp int; -precision lowp sampler2D; -precision lowp samplerCube; + #ifdef GLES + precision highp float; + precision highp int; + precision lowp sampler2D; + precision lowp samplerCube; #if __VERSION__ >290 #define LOC(x) layout(location = x) #define ATT in diff --git a/demos/assets/shaders/base.fp b/demos/assets/shaders/base.fp index d86e92e..efc5210 100644 --- a/demos/assets/shaders/base.fp +++ b/demos/assets/shaders/base.fp @@ -1,10 +1,9 @@ -precision mediump int; -precision mediump float; -precision lowp sampler2D; -precision lowp samplerCube; - #ifdef GLES + precision mediump int; + precision mediump float; + precision lowp sampler2D; + precision lowp samplerCube #define TEX(x,y) texture2D(x,y) #if __VERSION__ >290 #define M_IN in mediump @@ -14,11 +13,12 @@ precision lowp samplerCube; #define L_IN varying lowp #endif #else - #define TEX(x,y) texture(x,y) #if __VERSION__ > 320 + #define TEX(x,y) texture(x,y) #define M_IN in #define L_IN in #else + #define TEX(x,y) texture2D(x,y) #define M_IN varying #define L_IN varying #endif diff --git a/demos/assets/shaders/base.vp b/demos/assets/shaders/base.vp index 6c4c183..333ae59 100644 --- a/demos/assets/shaders/base.vp +++ b/demos/assets/shaders/base.vp @@ -1,8 +1,9 @@ -precision highp float; -precision highp int; -precision lowp sampler2D; -precision lowp samplerCube; + #ifdef GLES + precision highp float; + precision highp int; + precision lowp sampler2D; + precision lowp samplerCube; #if __VERSION__ >290 #define LOC(x) layout(location = x) #define ATT in diff --git a/demos/assets/shaders/circle.fp b/demos/assets/shaders/circle.fp index 15f46fd..dd0449c 100644 --- a/demos/assets/shaders/circle.fp +++ b/demos/assets/shaders/circle.fp @@ -1,10 +1,9 @@ -precision mediump int; -precision mediump float; -precision lowp sampler2D; -precision lowp samplerCube; - #ifdef GLES + precision mediump int; + precision mediump float; + precision lowp sampler2D; + precision lowp samplerCube; #define TEX(x,y) texture2D(x,y) #if __VERSION__ >290 #define M_IN in mediump diff --git a/demos/assets/shaders/circle.vp b/demos/assets/shaders/circle.vp index 6997121..9c1b85c 100644 --- a/demos/assets/shaders/circle.vp +++ b/demos/assets/shaders/circle.vp @@ -1,8 +1,9 @@ -precision highp float; -precision highp int; -precision lowp sampler2D; -precision lowp samplerCube; + #ifdef GLES + precision highp float; + precision highp int; + precision lowp sampler2D; + precision lowp samplerCube; #if __VERSION__ >290 #define LOC(x) layout(location = x) #define ATT in diff --git a/demos/source/app.d b/demos/source/app.d index 08c154c..fa77aac 100644 --- a/demos/source/app.d +++ b/demos/source/app.d @@ -75,6 +75,7 @@ struct Launcher double delta_time; uint fps; vec2 render_position; + bool play = true; Tool used_tool; int tool_size = 100; @@ -85,6 +86,7 @@ struct Launcher bool tool_mode = true; ToolCircle* tool_circle; bool show_filtered; + EntityID selected_entity; bool swap_interval = true; @@ -95,6 +97,7 @@ struct Launcher bool show_stat_wnd = true; bool show_tips = true; bool show_demo_wnd = true; + bool show_tools_wnd = true; bool show_virtual_keys_wnd = false; bool show_profile_wnd = true; @@ -110,10 +113,16 @@ struct Launcher float draw_time = 0; } + double deltaTime() + { + return delta_time * play; + } + DemoCallbacks demo; void switchDemo(DemoCallbacks callbacks)//void function() start, bool function() loop, void function() end, void function(SDL_Event*) event, const (char)* tips) { + show_tips = true; gui_manager.clear(); //launcher.ent @@ -164,6 +173,7 @@ struct Launcher ComponentRef[] add_comps; ushort[] rem_comps; ushort[] filter; + float distance = float.max; bool filterEntity(ref const Entity entity) { @@ -222,6 +232,21 @@ struct Launcher if(length < size2)gEM.removeComponents(data.entity[i].id, rem_comps); } } + + void selectEntity(IteratorSystem.EntitiesData data) + { + if(!filterEntity(data.entity[0]))return; + foreach(i;0..data.length) + { + vec2 rel_vec = data.location[i] - position; + float length = rel_vec.x * rel_vec.x + rel_vec.y * rel_vec.y; + if(length < distance) + { + distance = length; + launcher.selected_entity = data.entity[i].id; + } + } + } } float half_size = tool_size * 0.5; @@ -276,6 +301,10 @@ struct Launcher } } break; + case Tool.selector: + iterator.distance = size2; + manager.callEntitiesFunction!IteratorSystem(&iterator.selectEntity); + break; default: break; } @@ -717,12 +746,14 @@ void mainLoop(void* arg) if(launcher.show_tips) { - igSetNextWindowPos(ImVec2(launcher.window_size.x - 550, 80), ImGuiCond_Once, ImVec2(0,0)); - igSetNextWindowSize(ImVec2(300, 0), ImGuiCond_Once); - igSetNextWindowBgAlpha(launcher.windows_alpha); + igSetNextWindowPos(ImVec2(launcher.window_size.x /2 -250, 100), ImGuiCond_Once, ImVec2(0,0)); + igSetNextWindowSize(ImVec2(500, -1), ImGuiCond_Once); + igSetNextWindowBgAlpha(0.95); if(igBegin("Tips",&launcher.show_tips,ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoSavedSettings)) { + // igBeginChild("",ImVec2(0,0),0,0); igTextWrapped(launcher.demo.tips); + // igEndChild(); } igEnd(); } @@ -730,9 +761,10 @@ void mainLoop(void* arg) if(launcher.show_demo_wnd) { igSetNextWindowPos(ImVec2(launcher.window_size.x - 260, 30), ImGuiCond_Once, ImVec2(0,0)); - igSetNextWindowSize(ImVec2(250, launcher.window_size.y - 60), ImGuiCond_Once); + igSetNextWindowSize(ImVec2(250, 300), ImGuiCond_Once); if(igBegin("Demo",&launcher.show_demo_wnd,0)) { + igCheckbox("Play",&launcher.play); ImDrawList* draw_list = igGetWindowDrawList(); igBeginGroup(); launcher.gui_manager.gui(); @@ -742,11 +774,11 @@ void mainLoop(void* arg) //ImDrawList_AddRect(draw_list, igGetItemRectMin(), igGetItemRectMax(), igColorConvertFloat4ToU32(ImVec4(0.4,0.4,0.4,0.4)), -1, 0, 1); //igBeginChildFrame(1,ImVec2(0,-1),ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_ChildWindow); //igBeginChild("Tool frame",ImVec2(-1,-1),true,0); - igBeginGroup(); - if(igCollapsingHeader("Tool##ToolHeader", ImGuiTreeNodeFlags_SpanAvailWidth | ImGuiTreeNodeFlags_DefaultOpen)) - { - igIndent(8); - if(igBeginCombo("Tool",tool_strings[launcher.used_tool],0)) + // igBeginGroup(); + // if(igCollapsingHeader("Tool##ToolHeader", ImGuiTreeNodeFlags_SpanAvailWidth | ImGuiTreeNodeFlags_DefaultOpen)) + // { + // igIndent(8); + /*if(igBeginCombo("Tool",tool_strings[launcher.used_tool],0)) { if(igSelectable("Entity spawner",false,0,ImVec2(0,0))) { @@ -761,8 +793,48 @@ void mainLoop(void* arg) launcher.used_tool = Tool.selector; } igEndCombo(); + }*/ + /*if(igSelectable("Entity spawner",false,0,ImVec2(0,0))) + { + launcher.used_tool = Tool.entity_spawner; } - if(igIsItemHovered(0))igSetTooltip("Select tool (CTRL + 1,2,3)"); + if(igSelectable("Component manipulator",false,0,ImVec2(0,0))) + { + launcher.used_tool = Tool.component_manipulator; + } + if(igSelectable("Selector",false,0,ImVec2(0,0))) + { + launcher.used_tool = Tool.selector; + }*/ + /*if(igBeginTabBar("Tool",ImGuiTabBarFlags_NoCloseWithMiddleMouseButton)) + { + if(igIsItemHovered(0))igSetTooltip("Select tool (CTRL + 1,2,3)"); + bool a = 1; + //this is used as hack to make CTRL+1/2/3 tab selection possible + static Tool prev_tool = Tool.entity_spawner; + bool different = prev_tool != launcher.used_tool; + Tool tool; + if(igBeginTabItem("Entity spawner", &a, launcher.used_tool == Tool.entity_spawner && different ? ImGuiTabItemFlags_SetSelected : 0)) + { + tool = Tool.entity_spawner; + igEndTabItem(); + } + if(igBeginTabItem("Component manipulator", &a, launcher.used_tool == Tool.component_manipulator && different ? ImGuiTabItemFlags_SetSelected : 0)) + { + tool = Tool.component_manipulator; + igEndTabItem(); + } + if(igBeginTabItem("Selector", &a, launcher.used_tool == Tool.selector && different ? ImGuiTabItemFlags_SetSelected : 0)) + { + tool = Tool.selector; + igEndTabItem(); + } + launcher.used_tool = tool; + prev_tool = launcher.used_tool; + } + igEndTabBar(); + + igCheckbox("Show Tool", &launcher.tool_show); if(igIsItemHovered(0))igSetTooltip("Show/hide graphical tool representation"); igSameLine(0,4); @@ -785,10 +857,11 @@ void mainLoop(void* arg) igSliderInt("Tool size", &launcher.tool_size, 0, 256, null); igSliderFloat("Tool repeat", &launcher.tool_repeat, 0, 1024, null, 4); - launcher.gui_manager.toolGui(); - igUnindent(8); - } - igEndGroup(); + launcher.gui_manager.toolGui();*/ + + // igUnindent(8); + // } + // igEndGroup(); ImDrawList_AddRect(draw_list, igGetItemRectMin(), ImVec2(igGetWindowPos().x+igGetWindowWidth()-2,igGetItemRectMax().y), igColorConvertFloat4ToU32(ImVec4(0.4,0.4,0.4,0.4)), 2, ImDrawCornerFlags_All, 1); //igBeginGroup(); @@ -813,6 +886,75 @@ void mainLoop(void* arg) igEnd(); } + if(launcher.show_tools_wnd) + { + + igSetNextWindowPos(ImVec2(launcher.window_size.x - 300, 340), ImGuiCond_Once, ImVec2(0,0)); + igSetNextWindowSize(ImVec2(300, launcher.window_size.y - 370), ImGuiCond_Once); + if(igBegin("Tools", &launcher.show_tools_wnd, ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoScrollWithMouse)) + { + if(igIsItemHovered(0))igSetTooltip("Select tool (CTRL + 1,2,3)"); + + if(igBeginTabBar("Tool",ImGuiTabBarFlags_NoCloseWithMiddleMouseButton)) + { + bool a = 1; + //this is used as hack to make CTRL+1/2/3 tab selection possible + static Tool prev_tool = Tool.entity_spawner; + bool different = prev_tool != launcher.used_tool; + Tool tool; + if(igBeginTabItem("Entity spawner", &a, launcher.used_tool == Tool.entity_spawner && different ? ImGuiTabItemFlags_SetSelected : 0)) + { + tool = Tool.entity_spawner; + igEndTabItem(); + } + if(igBeginTabItem("Component manipulator", &a, launcher.used_tool == Tool.component_manipulator && different ? ImGuiTabItemFlags_SetSelected : 0)) + { + tool = Tool.component_manipulator; + igEndTabItem(); + } + if(igBeginTabItem("Selector", &a, launcher.used_tool == Tool.selector && different ? ImGuiTabItemFlags_SetSelected : 0)) + { + tool = Tool.selector; + igEndTabItem(); + } + launcher.used_tool = tool; + prev_tool = launcher.used_tool; + } + igEndTabBar(); + + + igCheckbox("Show Tool", &launcher.tool_show); + if(igIsItemHovered(0))igSetTooltip("Show/hide graphical tool representation"); + igSameLine(0,4); + igCheckbox("Show Filtered", &launcher.show_filtered); + if(igIsItemHovered(0))igSetTooltip("Show/hide filtered entities"); + if(launcher.used_tool == Tool.component_manipulator) + { + igCheckbox("Override", &launcher.override_); + } + + //igSelectable("Selectabe",false,ImGuiSelectableFlags_None,ImVec2(0,0)); + if(launcher.used_tool != Tool.selector) + { + if(igRadioButtonBool("Add", launcher.tool_mode))launcher.tool_mode = true; + if(igIsItemHovered(0))igSetTooltip("Tool should adding (Entities or components)"); + igSameLine(0,4); + if(igRadioButtonBool("Remove", !launcher.tool_mode))launcher.tool_mode = false; + if(igIsItemHovered(0))igSetTooltip("Tool should removing (Entities or components)"); + } + + igSliderInt("Tool size", &launcher.tool_size, 0, 256, null); + igSliderFloat("Tool repeat", &launcher.tool_repeat, 0, 1024, null, 4); + + if(igBeginChild("",ImVec2(0,0),1,0)) + { + launcher.gui_manager.toolGui(); + } + igEndChild(); + } + igEnd(); + } + if(launcher.show_profile_wnd) { //igSetNextWindowPos(ImVec2(launcher.window_size.x - 260, launcher.window_size.y - 280), ImGuiCond_Once, ImVec2(0,0)); @@ -864,10 +1006,20 @@ void mainLoop(void* arg) double loop_time = launcher.getTime(); launcher.job_updater.pool.tryWaitCount = 10000; - if(launcher.demo.loop && !launcher.demo.loop()) - { - quit(); - *cast(bool*)arg = false; + if(launcher.play) + { + if(launcher.demo.loop && !launcher.demo.loop()) + { + quit(); + *cast(bool*)arg = false; + } + } + else + { + launcher.manager.begin(); + import game_core.rendering; + launcher.manager.callEntitiesFunction!DrawSystem(&(launcher.manager.getSystem!DrawSystem).onUpdate); + launcher.manager.end(); } launcher.job_updater.pool.tryWaitCount = 0; @@ -1119,7 +1271,7 @@ int app_main(int argc, char** argv) // launcher.switchDemo(&simpleStart,&simpleLoop,&simpleEnd,&simpleEvent,Simple.tips); // launcher.switchDemo(getParticlesDemo()); // launcher.switchDemo(getSimpleDemo()); - launcher.switchDemo(getBrickBreakerDemo()); + launcher.switchDemo(getSimpleDemo()); } int key_num; diff --git a/demos/source/demos/brick_breaker.d b/demos/source/demos/brick_breaker.d index 3540449..637415c 100644 --- a/demos/source/demos/brick_breaker.d +++ b/demos/source/demos/brick_breaker.d @@ -24,6 +24,13 @@ extern(C): private enum float px = 1.0/512.0; +float clamp(float v, float min, float max) +{ + if(vmax)return max; + else return v; +} + /*####################################################################################################################### ------------------------------------------------ Components ------------------------------------------------------------------ #######################################################################################################################*/ @@ -192,50 +199,32 @@ struct BallCollisionSystem CScale* scale = entity.getComponent!CScale; if(location && scale) { - float radius = data.scale[i].x; + float radius = data.scale[i].x*0.5; vec2 rel_pos = *location - data.location[i]; - vec2 abs_rel_pos = rel_pos; - if(abs_rel_pos.x < 0)abs_rel_pos.x = -abs_rel_pos.x; - if(abs_rel_pos.y < 0)abs_rel_pos.y = -abs_rel_pos.y; - vec2 half_scale = *scale * 0.25f; + vec2 half_scale = *scale * 0.5f; + + vec2 nearest_point; + nearest_point.x = clamp(rel_pos.x, -half_scale.x, half_scale.x); + nearest_point.y = clamp(rel_pos.y, -half_scale.y, half_scale.y); - if(abs_rel_pos.x < half_scale.x + radius && - abs_rel_pos.y < half_scale.y + radius) + vec2 vector; + if(nearest_point == rel_pos) { - if(abs_rel_pos.x < half_scale.x) - { - if(rel_pos.y * data.velocity[i].y > 0) - { - data.velocity[i].y = -data.velocity[i].y; - launcher.manager.sendEvent(id,EDamage(1)); - return false; - } - } - else if(abs_rel_pos.y < half_scale.y) - { - if(rel_pos.x * data.velocity[i].x > 0) - { - data.velocity[i].x = -data.velocity[i].x; - launcher.manager.sendEvent(id,EDamage(1)); - return false; - } - } - else - { - vec2 vector = abs_rel_pos - half_scale; - if(rel_pos.x > 0)vector.x = -vector.x; - if(rel_pos.y > 0)vector.y = -vector.y; + vector = nearest_point; + radius = float.max; + } + else vector = nearest_point - rel_pos; + float pow_dist = dot(vector, vector); - float pow_dist = vector.length2(); - if(pow_dist < radius*radius) - { - vector = vector / sqrtf(pow_dist); - data.velocity[i] = data.velocity[i] - vector * (2 * dot(vector, data.velocity[i])); - launcher.manager.sendEvent(id,EDamage(1)); - return false; - } - } + if(dot(data.velocity[i], vector) > 0.01)return true; + + if(pow_dist < radius*radius) + { + vector = vector / sqrtf(pow_dist); + data.velocity[i] = data.velocity[i] - vector * (2 * dot(vector, data.velocity[i])); + launcher.manager.sendEvent(id,EDamage(1)); + return cast(bool)(hits--); } } } @@ -244,6 +233,7 @@ struct BallCollisionSystem EntitiesData data; uint i; + uint hits; } ShootGrid* grid; @@ -279,6 +269,7 @@ struct BallCollisionSystem foreach(i; 0..data.length) { state.i = i; + state.hits = 1; //float radius = data.scale[i].x; AABB bounding = AABB(data.location[i]-data.scale[i], data.location[i]+data.scale[i]); tree.test(bounding, cast(bool delegate(EntityID id))&state.test); @@ -317,7 +308,10 @@ struct DamageSystem struct BrickBreakerDemo { - __gshared const (char)* tips = "Brick breaker demo. It's a game about destroying evil bricks."; + __gshared const (char)* tips = "Brick breaker demo. It's a game about destroying evil bricks. + +This demo is usnfinished yet but collision works well. Bricks can be destroyed. Spawning thousands of bricks and then thousands of balls is good way to try demo. +Bricks uses StaticBVH, ball don't collide witch each other, paddle is added to dynamic BVH and collide with balls. But nothing keeps you from adding dynamic collision for balls."; //EntityTemplate* tmpl; Texture texture; @@ -418,6 +412,7 @@ void brickBreakerStart() launcher.gui_manager.addComponent(CBall(), "Ball"); launcher.gui_manager.addComponent(CBVH(), "BVH"); launcher.gui_manager.addComponent(CAABB(), "AABB"); + launcher.gui_manager.addComponent(CStatic(), "Static Flag"); launcher.gui_manager.addSystem(becsID!MoveSystem, "Move System"); launcher.gui_manager.addSystem(becsID!EdgeCollisionSystem, "Edge Collision System"); diff --git a/demos/source/demos/particles.d b/demos/source/demos/particles.d index b976308..bbb68ee 100644 --- a/demos/source/demos/particles.d +++ b/demos/source/demos/particles.d @@ -180,7 +180,7 @@ struct DrawSystem // { // foreach(i; 0..data.length) // { -// data.locations[i] += data.velocity[i] * launcher.delta_time; +// data.locations[i] += data.velocity[i] * launcher.deltaTime; // } // } // } @@ -208,7 +208,7 @@ struct MouseAttractSystem void onUpdate(EntitiesData data) { - float speed = launcher.delta_time * 0.01; + float speed = launcher.deltaTime * 0.01; foreach(i;0..data.length) { vec2 rel_pos = mouse_pos - data.locations[i]; @@ -236,7 +236,7 @@ struct AttractSystem void onUpdate(AttractorIterator.EntitiesData adata) { - float speed = launcher.delta_time * 0.00004; + float speed = launcher.deltaTime * 0.00004; if(adata.vortex) { foreach(i;0..data.length) @@ -365,7 +365,7 @@ struct PlayAreaSystem // { // foreach(i;0..10) // { -// damp[i] = powf((0.99 - cast(float)i * 0.01),launcher.delta_time*0.1); +// damp[i] = powf((0.99 - cast(float)i * 0.01),launcher.deltaTime*0.1); // } // return true; @@ -395,7 +395,7 @@ struct ParticleLifeSystem bool onBegin() { - delta_time = cast(int)(launcher.delta_time * 1000); + delta_time = cast(int)(launcher.deltaTime * 1000); return true; } @@ -423,7 +423,7 @@ struct GravitySystem void onUpdate(EntitiesData data) { - float delta_time = launcher.delta_time * 0.00_092; + float delta_time = launcher.deltaTime * 0.00_092; foreach(i; 0..data.length) { data.velocity[i].y -= delta_time; @@ -437,7 +437,8 @@ struct GravitySystem struct ParticlesDemo { - __gshared const (char)* tips = "Use \"space\" to spwan entities.\n\nSystems can be enabled/disabled from \"Simple\" window."; + __gshared const (char)* tips = "Particles by default have no velocity. You can spawn \"Attractor\" which attract particles, or \"Vortex\" which attracts and spin particles. +Please do not spawn to many of them as every \"Attractor\" iterate over all particles (brute force)."; Texture texture; } @@ -471,6 +472,7 @@ void particlesRegister() launcher.manager.registerComponent!CParticleLife; launcher.manager.registerComponent!CForceRange; launcher.manager.registerComponent!CMaterialIndex; + launcher.manager.registerComponent!CVelocityFactor; launcher.manager.registerSystem!MoveSystem(0); launcher.manager.registerSystem!DrawSystem(100); diff --git a/demos/source/demos/sandbox.d b/demos/source/demos/sandbox.d index e7abb06..c59b432 100644 --- a/demos/source/demos/sandbox.d +++ b/demos/source/demos/sandbox.d @@ -98,6 +98,7 @@ DemoCallbacks getSanboxDemo() demo.initialize = &sandboxStart; demo.deinitialize = &sandboxEnd; demo.loop = &sandboxLoop; - demo.tips = "tips"; + demo.tips = "This demo contains all components, systems and events from previous demos. They was not designed for that kind of coexisting. Some system collide with other making some weird things. +This gives biggest opportunities. You can add tower on top of snake, or lasers to paddle from BrickBreaker. This will be improved in next versions of ECS demo."; return demo; } \ No newline at end of file diff --git a/demos/source/demos/simple.d b/demos/source/demos/simple.d index 7a8357a..bfbb74c 100644 --- a/demos/source/demos/simple.d +++ b/demos/source/demos/simple.d @@ -99,7 +99,32 @@ struct MoveSystem struct Simple { - __gshared const (char)* tips = "Use \"space\" to spwan entities.\n\nSystems can be enabled/disabled from \"Simple\" window."; + __gshared const (char)* tips = "Use \"space\" to spwan entities.\n\nSystems can be enabled/disabled from \"Demo\" window. +\"Tools\" window exists of three tools which can be used to manipulate game. +Options: + * Show Tool - enable/disable rendering of blue circle around cursor + * Show Filtered - enable/disable higliting filtered entities. For \"Component manipulator\" tool it shows entities which has selected component. + * Add/Remove - select primary action. LMB - primary action, RMB - secondary action + * Tools size - size of tool + * Tool repeat - how many times in one second tool should take action (e.g. 1000 means every second \"Entity spawner\" will spawn 1000 enties) + * Override - enabled means that \"Component manipulator\" will override components data if entity already has that component +Tools: + * Entity spawner - used to spawn new entities + * Component manipulator - used to add/remove components to/from entities + * Selector - allow to select entity, show and modify his data. Only one entity can be selected, selector selects entity nearest co cursor. + +ShortCuts: + * CRTL*1/2/3 - change tool + * Mouse wheel - change tool size + * SHIFT + Mouse wheel - change entity/component in tool list + * LBM - primary action (default: add entity / add component) + * RMB - secondary action (default: remove entity / remove component) + +\"Statistic\" windows shows FPS and entities count. + +From top menu bar (upper left corner) you can select different demos or change some options. Multihtreading is highly recommended, but it can not working on mobile phones or Firefox browser. + +Demo is capable rendering of hundreds of thousands of entities. Playable area is heavily too small to show that count of entities, but you can try it :)"; EntityTemplate* tmpl; Texture texture; @@ -137,6 +162,9 @@ void simpleStart() launcher.gui_manager.addSystem(becsID!MoveSystem,"Move Up System"); launcher.gui_manager.addSystem(becsID!DrawSystem,"Draw System"); + launcher.gui_manager.addComponent(CLocation(), "Location"); + launcher.gui_manager.addComponent(CDrawDefault(), "DrawDefault"); + simple.tmpl = launcher.manager.allocateTemplate([becsID!CLocation, becsID!CDrawDefault].staticArray); //*simple.tmpl.getComponent!CTexCoordsIndex = TexCoordsManager.instance.getCoordIndex(vec4(0,48,16,16)*px); //CLocation* loc_comp = simple.tmpl.getComponent!CLocation; diff --git a/demos/source/demos/snake.d b/demos/source/demos/snake.d index 7591978..395f283 100644 --- a/demos/source/demos/snake.d +++ b/demos/source/demos/snake.d @@ -58,7 +58,8 @@ enum SnakePart : ubyte struct Snake { - __gshared const (char)* tips = "Use \"WASD\" keys to move."; + __gshared const (char)* tips = "Use \"WASD\" keys to move. If you loose you can always spawn new snake... or several snakes. +This demo is an example that in ECS you can make very \"non-ECS\" game"; EntityTemplate* apple_tmpl; EntityTemplate* snake_tmpl; @@ -286,7 +287,7 @@ struct ParticleSystem { foreach(i;0..data.length) { - data.particle[i].life -= launcher.delta_time; + data.particle[i].life -= launcher.deltaTime; if(data.particle[i].life < 0)launcher.manager.removeEntity(data.entities[i].id); } } @@ -328,7 +329,7 @@ struct AnimationSystem { foreach(i;0..data.length) { - data.animation[i].time += launcher.delta_time * 0.01; + data.animation[i].time += launcher.deltaTime * 0.01; while(data.animation[i].time >= data.animation[i].frames.length)data.animation[i].time -= cast(float)data.animation[i].frames.length; } } @@ -971,7 +972,7 @@ bool snakeLoop() launcher.manager.begin(); - float delta_time = launcher.delta_time; + float delta_time = launcher.deltaTime; if(delta_time > 2000)delta_time = 2000; __gshared float time = 0; diff --git a/demos/source/demos/space_invaders.d b/demos/source/demos/space_invaders.d index 67332f8..c3decc2 100644 --- a/demos/source/demos/space_invaders.d +++ b/demos/source/demos/space_invaders.d @@ -36,7 +36,9 @@ extern(C): struct SpaceInvaders { - __gshared const (char)* tips = "Use \"WASD\" keys to move and \"Space\" for shooting."; + __gshared const (char)* tips = "Use \"WASD\" keys to move and \"Space\" for shooting. +On start there is not to much to do. But you can spawn thousands of entities. You can even change guild for enemies to make them kilking themselves. +You can add any component to any entity which sometimes can give fun results. This demo wasn't created with such combination in mind, but that is something which comes naturally with ECS."; EntityTemplate* enemy_tmpl; EntityTemplate* ship_tmpl; @@ -1019,7 +1021,7 @@ struct ShootingSystem foreach(i;0..data.length) { CWeapon* laser = &data.laser[i]; - laser.shoot_time += launcher.delta_time; + laser.shoot_time += launcher.deltaTime; while(laser.shoot_time > CWeapon.levels[laser.level - 1].reload_time) { CVelocity laser_velocity; @@ -1824,7 +1826,7 @@ struct AnimationSystem void onUpdate(EntitiesData data) { - float dt = launcher.delta_time * 0.01; + float dt = launcher.deltaTime * 0.01; if(data.looped) { foreach(i;0..data.length) @@ -1865,7 +1867,7 @@ struct ParticleSystem { foreach(i;0..data.length) { - data.particle[i].life -= launcher.delta_time; + data.particle[i].life -= launcher.deltaTime; if(data.particle[i].life < 0)launcher.manager.removeEntity(data.entitiy[i].id); } } @@ -2086,6 +2088,7 @@ void spaceInvadersRegister() launcher.manager.registerComponent!CTargetPlayerShip; launcher.manager.registerComponent!CChildren; launcher.manager.registerComponent!CWeaponLocation; + launcher.manager.registerComponent!CVelocityFactor; launcher.manager.registerComponent!CInit; launcher.manager.registerComponent!CBoss; launcher.manager.registerComponent!CParts; diff --git a/demos/source/game_core/basic.d b/demos/source/game_core/basic.d index b47ba52..ec32d87 100644 --- a/demos/source/game_core/basic.d +++ b/demos/source/game_core/basic.d @@ -97,6 +97,10 @@ struct CVelocityFactor vec2 value = vec2(1); } +struct CStatic +{ + mixin ECS.Component; +} struct DampingSystem { diff --git a/demos/source/game_core/collision.d b/demos/source/game_core/collision.d index 794f8d8..647bfdb 100644 --- a/demos/source/game_core/collision.d +++ b/demos/source/game_core/collision.d @@ -49,11 +49,6 @@ struct CBVH uint index; } -struct CStatic -{ - mixin ECS.Component; -} - struct CAABB { mixin ECS.Component; @@ -1003,6 +998,7 @@ struct AABBUpdater @readonly CLocation[] location; @readonly CScale[] scale; @optional @readonly CRotation[] rotation; + @optional @readonly CStatic[] static_flag; } void onAddEntity(EntitiesData data) @@ -1015,6 +1011,8 @@ struct AABBUpdater void onUpdate(EntitiesData data) { + if(data.static_flag)return; + foreach(i; 0..data.length) { data.bounding[i] = AABB(data.location[i]-data.scale[i],data.location[i]+data.scale[i]); diff --git a/demos/source/gui/manager.d b/demos/source/gui/manager.d index b172ffc..26eba2b 100644 --- a/demos/source/gui/manager.d +++ b/demos/source/gui/manager.d @@ -395,7 +395,7 @@ struct GUIManager } } - void entityComponentsGUI() + void templateComponentsGUI() { if(selected_template >= templates.length)return; EntityTemplate* tmpl = templates[selected_template].tmpl; @@ -408,6 +408,19 @@ struct GUIManager } } + void entityComponentsGUI(Entity* entity) + { + if(!entity)return; + EntityMeta meta = entity.getMeta(); + EntityManager.EntityInfo* info = meta.block.type_info; + foreach(comp_id; info.components) + { + // void* data_ptr = tmpl.entity_data.ptr; + void* comp_ptr = meta.getComponent(comp_id);//data_ptr + info.tmpl_deltas[comp_id]; + componentGUI(comp_id, comp_ptr); + } + } + void toolGui() { ImGuiStyle * style = igGetStyle(); @@ -436,7 +449,7 @@ struct GUIManager if(igIsItemHovered(0))igSetTooltip("Select entity to spawn (SHIFT + Scroll)"); } style.Colors[ImGuiCol_Header] = col; - entityComponentsGUI(); + templateComponentsGUI(); break; case Tool.component_manipulator: if(components.length) @@ -458,6 +471,11 @@ struct GUIManager if(selected_component < components.length)componentGUI(components[selected_component].component_id, components[selected_component].data); break; case Tool.selector: + { + Entity* entity = gEM.getEntity(launcher.selected_entity); + style.Colors[ImGuiCol_Header] = col; + entityComponentsGUI(entity); + } break; } diff --git a/demos/utils/dub.json b/demos/utils/dub.json index 5302fd8..d47af9e 100644 --- a/demos/utils/dub.json +++ b/demos/utils/dub.json @@ -16,7 +16,7 @@ ], "dependencies": { "bindbc-sdl":"0.19.0", - "ecs":{"path":"../../"} + "bubel_ecs":{"path":"../../"} }, "versions": [ "BindSDL_Image", diff --git a/demos/utils/source/ecs_utils/gfx/shader.d b/demos/utils/source/ecs_utils/gfx/shader.d index e941289..c3d656a 100644 --- a/demos/utils/source/ecs_utils/gfx/shader.d +++ b/demos/utils/source/ecs_utils/gfx/shader.d @@ -70,7 +70,7 @@ struct Shader version(WebAssembly)const char* glsl = "#version 100\n"; else version(Android)const char* glsl = "#version 100\n"; - else const char* glsl = "#version 330\n"; + else const char* glsl = "#version 120\n"; const char* buffer = data.code.ptr; char* ver; version(WebAssembly)ver = cast(char*)"#define ver1 1\n#define GLES\n".ptr; diff --git a/dub.json b/dub.json index 1a99040..8e2a1b3 100755 --- a/dub.json +++ b/dub.json @@ -1,6 +1,6 @@ { "name": "bubel_ecs", - "targetName" : "ecs", + "targetName" : "bubel_ecs", "authors": [ "Michał Masiukiewicz", "Dawid Masiukiewicz" ], diff --git a/tests/tests.d b/tests/tests.d index d539f89..f82519d 100644 --- a/tests/tests.d +++ b/tests/tests.d @@ -102,7 +102,7 @@ static struct CPosition static struct TestComp { - mixin ECS.Component; //__gshared ushort component_id; + mixin ECS.Component; //__gshared becsID!ushort; int a = 1; ulong b = 2; @@ -119,7 +119,7 @@ static struct TestComp static struct TestComp2 { - mixin ECS.Component; //__gshared ushort component_id; + mixin ECS.Component; //__gshared becsID!ushort; int b = 3; int a = 4; @@ -136,7 +136,7 @@ static struct TestComp2 static struct TestComp3 { - mixin ECS.Component; //__gshared ushort component_id; + mixin ECS.Component; //__gshared becsID!ushort; uint gg = 5; //good game uint bg = 6; //bad game @@ -153,7 +153,7 @@ static struct TestComp3 static struct TestComp4 { - mixin ECS.Component; //__gshared ushort component_id; + mixin ECS.Component; //__gshared becsID!ushort; uint gg = 7; //good game uint bg = 8; //bad game ulong a = 9; @@ -174,7 +174,7 @@ static struct TestComp4 static struct TestComp5 { - mixin ECS.Component; //__gshared ushort component_id; + mixin ECS.Component; //__gshared becsID!ushort; uint gg = 7; //good game uint bg = 8; //bad game ulong a = 9; @@ -735,12 +735,12 @@ else: printf("Systems register: %f usecs\n", cast(float)(Time.getUSecTime() - time)); time = Time.getUSecTime(); - //ushort[3] ids = [TestComp2.component_id, TestComp.component_id, TestComp4.component_id]; - ushort[2] ids = [TestComp2.component_id, TestComp.component_id]; + //ushort[3] ids = [becsID!TestComp2, becsID!TestComp, becsID!TestComp4]; + ushort[2] ids = [becsID!TestComp2, becsID!TestComp]; EntityTemplate* tmpl = gEM.allocateTemplate(ids); - //ushort[3] ids2 = [TestComp3.component_id, TestComp.component_id, TestComp4.component_id]; - ushort[2] ids2 = [TestComp3.component_id, TestComp.component_id]; + //ushort[3] ids2 = [becsID!TestComp3, becsID!TestComp, becsID!TestComp4]; + ushort[2] ids2 = [becsID!TestComp3, becsID!TestComp]; EntityTemplate* tmpl2 = gEM.allocateTemplate(ids2); ////writeln(tmpl.info.components[]); //*cast(EntityID*) tmpl.entity_data.ptr = EntityID(1, 1); @@ -751,7 +751,7 @@ else: time = Time.getUSecTime(); - ushort[1] empty_ids = [CPosition.component_id]; + ushort[1] empty_ids = [becsID!CPosition]; EntityTemplate* tmpl_empty = gEM.allocateTemplate(empty_ids); gEM.commit(); @@ -1003,7 +1003,7 @@ else: gEM.commit(); - System* sys = EntityManager.instance.getSystem(TestSystem2.system_id); + System* sys = EntityManager.instance.getSystem(becsID!TestSystem2); ExternalUpdateCallTest external_update_test; From 9c402140bdd2946a64db147f10aadc8bf8a87251 Mon Sep 17 00:00:00 2001 From: Mergul Date: Mon, 1 Mar 2021 12:25:52 +0100 Subject: [PATCH 179/217] -fixed BrickBreaker issue with self collision --- demos/source/demos/brick_breaker.d | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/demos/source/demos/brick_breaker.d b/demos/source/demos/brick_breaker.d index 637415c..51e213c 100644 --- a/demos/source/demos/brick_breaker.d +++ b/demos/source/demos/brick_breaker.d @@ -192,6 +192,7 @@ struct BallCollisionSystem { bool test(EntityID id) { + if(id == data.entity[i].id)return true; Entity* entity = launcher.manager.getEntity(id); if(entity) { @@ -311,7 +312,8 @@ struct BrickBreakerDemo __gshared const (char)* tips = "Brick breaker demo. It's a game about destroying evil bricks. This demo is usnfinished yet but collision works well. Bricks can be destroyed. Spawning thousands of bricks and then thousands of balls is good way to try demo. -Bricks uses StaticBVH, ball don't collide witch each other, paddle is added to dynamic BVH and collide with balls. But nothing keeps you from adding dynamic collision for balls."; +Bricks uses StaticBVH, ball don't collide witch each other, paddle is added to dynamic BVH and collide with balls. But nothing keeps you from adding dynamic collision for balls. +Currently dynamic collisions are pretty slow as dynamic BVH is rebuilded every frame on single thread."; //EntityTemplate* tmpl; Texture texture; From 997f6181c82cd9e633418b14df625886dbbc0f11 Mon Sep 17 00:00:00 2001 From: Mergul Date: Mon, 1 Mar 2021 12:35:31 +0100 Subject: [PATCH 180/217] -change target name for unittests to "ecs" --- dub.json | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/dub.json b/dub.json index 8e2a1b3..8cf891d 100755 --- a/dub.json +++ b/dub.json @@ -50,7 +50,8 @@ ], "dflags": [ "-unittest" - ] + ], + "targetName" : "ecs" }, { "name": "unittest-runner-cov", @@ -64,7 +65,8 @@ "dflags": [ "-unittest", "-cov" - ] + ], + "targetName" : "ecs" }, { "name" : "library-betterC", @@ -127,7 +129,8 @@ "excludedSourceFiles":[ "source\/win_dll.d", "tests/tests.d" - ] + ], + "targetName" : "ecs" } ] } \ No newline at end of file From d1c48e4c5fbeab45ea9ffee52ba1138cb2889feb Mon Sep 17 00:00:00 2001 From: Mergul Date: Mon, 1 Mar 2021 12:58:57 +0100 Subject: [PATCH 181/217] -added missing ';' in shader --- demos/assets/shaders/base.fp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/demos/assets/shaders/base.fp b/demos/assets/shaders/base.fp index efc5210..d667b24 100644 --- a/demos/assets/shaders/base.fp +++ b/demos/assets/shaders/base.fp @@ -3,7 +3,7 @@ precision mediump int; precision mediump float; precision lowp sampler2D; - precision lowp samplerCube + precision lowp samplerCube; #define TEX(x,y) texture2D(x,y) #if __VERSION__ >290 #define M_IN in mediump From 3b954b732bfd76b29e8d1a1bd330dbf6ad65c698 Mon Sep 17 00:00:00 2001 From: Mergul Date: Tue, 2 Mar 2021 19:44:18 +0100 Subject: [PATCH 182/217] -update README code example (to one that compile) -remove Entity.instance and gEM, global manager is now gEntityManager --- README.md | 43 +- demos/source/app.d | 12 +- demos/source/game_core/collision.d | 4 +- demos/source/gui/manager.d | 6 +- source/bubel/ecs/entity.d | 12 +- source/bubel/ecs/manager.d | 44 +- tests/access_perf.d | 30 +- tests/basic.d | 660 ++++++++++++++--------------- tests/bugs.d | 70 +-- tests/perf.d | 60 +-- tests/tests.d | 280 ++++++------ 11 files changed, 617 insertions(+), 604 deletions(-) diff --git a/README.md b/README.md index d70058c..e4c2d77 100644 --- a/README.md +++ b/README.md @@ -101,6 +101,11 @@ Online demo support multithreading and page tries to check if client support WAS ```d +import bubel.ecs.core; +import bubel.ecs.manager; +import bubel.ecs.attributes; +import std.array : staticArray; + struct Position { float x; @@ -122,7 +127,7 @@ struct UpdateSystem { mixin ECS.System; //makes struct system - ECS.ExcludedComponents!(StaticFlag); //prevents static entities from update + mixin ECS.ExcludedComponents!(StaticFlag); //prevents static entities from update struct EntitiesData { @@ -136,26 +141,31 @@ struct UpdateSystem { foreach(i; 0..data.length) //iterate over entities { - data.positions[i].x += data.velocities[i].x * dt; - data.positions[i].y += data.velocities[i].y * dt; + data.positions[i].x += data.velocities[i].x; + data.positions[i].y += data.velocities[i].y; } } } void main() { - manager.beginRegister(); + //initialize ECS + EntityManager.initialize(); + + //begin registering process + gEntityManager.beginRegister(); //register components - manager.registerComponent!Position; - manager.registerComponent!Velocity; - manager.registerComponent!StaticFlag; + gEntityManager.registerComponent!Position; + gEntityManager.registerComponent!Velocity; + gEntityManager.registerComponent!StaticFlag; //register system with priority 0 - manager.registerSystem!UpdateSystem(0); - manager.endRegister(); + gEntityManager.registerSystem!UpdateSystem(0); + //end registering process + gEntityManager.endRegister(); //allocate template - EntityTemplate* tmpl = manager.allocateEmplate([becsID!Velocity, becsID!Position].staticArray); - scope (exit) manager.freeTemplate(tmpl); + EntityTemplate* tmpl = gEntityManager.allocateTemplate([becsID!Velocity, becsID!Position].staticArray); + scope (exit) gEntityManager.freeTemplate(tmpl); //gets pointer to template component data Position* position = tmpl.getComponent!Position; @@ -163,12 +173,15 @@ void main() { position.x = i % 10; position.y = i / 10; - manager.addEntity(tmpl); + gEntityManager.addEntity(tmpl); } - manager.begin(); //start frame, inside system onBegin callbacks are called - manager.update(); //update all systems, there onUpdate callbacks are called - manager.end(); //end frame, inside system onEnd callbacks are called + gEntityManager.begin(); //start frame, inside system onBegin callbacks are called + gEntityManager.update(); //update all systems, there onUpdate callbacks are called + gEntityManager.end(); //end frame, inside system onEnd callbacks are called*/ + + //free ECS data + EntityManager.destroy(); } ``` diff --git a/demos/source/app.d b/demos/source/app.d index fa77aac..2c324ec 100644 --- a/demos/source/app.d +++ b/demos/source/app.d @@ -192,7 +192,7 @@ struct Launcher { vec2 rel_vec = data.location[i] - position; float length = rel_vec.x * rel_vec.x + rel_vec.y * rel_vec.y; - if(length < size2)gEM.removeEntity(data.entity[i].id); + if(length < size2)gEntityManager.removeEntity(data.entity[i].id); } } @@ -203,7 +203,7 @@ struct Launcher { vec2 rel_vec = data.location[i] - position; float length = rel_vec.x * rel_vec.x + rel_vec.y * rel_vec.y; - if(length < size2)gEM.addComponents(data.entity[i].id, add_comps); + if(length < size2)gEntityManager.addComponents(data.entity[i].id, add_comps); } } @@ -216,8 +216,8 @@ struct Launcher float length = rel_vec.x * rel_vec.x + rel_vec.y * rel_vec.y; if(length < size2) { - gEM.removeComponents(data.entity[i].id, rem_comps); - gEM.addComponents(data.entity[i].id, add_comps); + gEntityManager.removeComponents(data.entity[i].id, rem_comps); + gEntityManager.addComponents(data.entity[i].id, add_comps); } } } @@ -229,7 +229,7 @@ struct Launcher { vec2 rel_vec = data.location[i] - position; float length = rel_vec.x * rel_vec.x + rel_vec.y * rel_vec.y; - if(length < size2)gEM.removeComponents(data.entity[i].id, rem_comps); + if(length < size2)gEntityManager.removeComponents(data.entity[i].id, rem_comps); } } @@ -1231,7 +1231,7 @@ int app_main(int argc, char** argv) //launcher.job_updater.onCreate(); EntityManager.initialize(32, 1<<16); - launcher.manager = EntityManager.instance; + launcher.manager = gEntityManager; //launcher.manager.m_thread_id_func = &launcher.job_updater.getThreadID; //launcher.manager.setJobDispachFunc(&launcher.job_updater.dispatch); diff --git a/demos/source/game_core/collision.d b/demos/source/game_core/collision.d index 647bfdb..ba81a4f 100644 --- a/demos/source/game_core/collision.d +++ b/demos/source/game_core/collision.d @@ -188,7 +188,7 @@ struct ShootGridCleaner bool onBegin() { - grid = gEM.getSystem!ShootGridManager().grid; + grid = gEntityManager.getSystem!ShootGridManager().grid; if(grid != null)return true; else return false; } @@ -964,7 +964,7 @@ struct BVHBuilder2 void onCreate() { - tree = gEM.getSystem!BVHBuilder().tree; + tree = gEntityManager.getSystem!BVHBuilder().tree; } bool onBegin() diff --git a/demos/source/gui/manager.d b/demos/source/gui/manager.d index 26eba2b..b3f758b 100644 --- a/demos/source/gui/manager.d +++ b/demos/source/gui/manager.d @@ -119,7 +119,7 @@ struct GUIManager // void addComponent(ComponentRef comp, const (char)* name) // { - // uint size = EntityManager.instance.components[becsID(comp)].size; + // uint size = gEntityManager.components[becsID(comp)].size; // void* data = malloc(size); // memcpy(data, comp.ptr, size); // components.add(ComponentGUI(name, data, becsID(comp))); @@ -127,7 +127,7 @@ struct GUIManager void addComponent(T)(T comp, const (char)* name) { - uint size = EntityManager.instance.components[becsID(comp)].size; + uint size = gEntityManager.components[becsID(comp)].size; void* data = malloc(size); memcpy(data, &comp, size); components.add(ComponentGUI(name, data, becsID(comp))); @@ -472,7 +472,7 @@ struct GUIManager break; case Tool.selector: { - Entity* entity = gEM.getEntity(launcher.selected_entity); + Entity* entity = gEntityManager.getEntity(launcher.selected_entity); style.Colors[ImGuiCol_Header] = col; entityComponentsGUI(entity); } diff --git a/source/bubel/ecs/entity.d b/source/bubel/ecs/entity.d index 11c5edc..cb3f752 100644 --- a/source/bubel/ecs/entity.d +++ b/source/bubel/ecs/entity.d @@ -35,7 +35,7 @@ struct Entity */ T* getComponent(T)() const { - /*EntityManager.EntitiesBlock* block = gEM.getMetaData(&this); + /*EntityManager.EntitiesBlock* block = gEntityManager.getMetaData(&this); EntityManager.EntityInfo* info = block.type_info; if (T.component_id >= info.deltas.length || info.deltas[T.component_id] == 0) return null; @@ -46,17 +46,17 @@ struct Entity void* getComponent(ushort component_id) const { - EntityManager.EntitiesBlock* block = gEM.getMetaData(&this); + EntityManager.EntitiesBlock* block = gEntityManager.getMetaData(&this); EntityManager.EntityInfo* info = block.type_info; if (component_id >= info.deltas.length || info.deltas[component_id] == 0) return null; - return (cast(void*)block + info.deltas[component_id] + block.entityIndex(&this) * gEM.components[component_id].size); + return (cast(void*)block + info.deltas[component_id] + block.entityIndex(&this) * gEntityManager.components[component_id].size); } bool hasComponent(ushort component_id) const { - EntityManager.EntitiesBlock* block = gEM.getMetaData(&this); + EntityManager.EntitiesBlock* block = gEntityManager.getMetaData(&this); EntityManager.EntityInfo* info = block.type_info; if (component_id >= info.deltas.length || info.deltas[component_id] == 0)return false; return true; @@ -65,7 +65,7 @@ struct Entity EntityMeta getMeta() const { EntityMeta meta; - meta.block = gEM.getMetaData(&this); + meta.block = gEntityManager.getMetaData(&this); meta.index = meta.block.entityIndex(&this); return meta; } @@ -92,7 +92,7 @@ struct EntityMeta if (component_id >= info.deltas.length || info.deltas[component_id] == 0) return null; - return (cast(void*)block + info.deltas[component_id] + index * gEM.components[component_id].size); + return (cast(void*)block + info.deltas[component_id] + index * gEntityManager.components[component_id].size); } bool hasComponent(ushort component_id) const diff --git a/source/bubel/ecs/manager.d b/source/bubel/ecs/manager.d index 6afdca9..2dfbd58 100644 --- a/source/bubel/ecs/manager.d +++ b/source/bubel/ecs/manager.d @@ -26,10 +26,11 @@ import bubel.ecs.traits; import bubel.ecs.vector; import bubel.ecs.atomic; -export alias gEM = EntityManager.instance; -export alias gEntityManager = EntityManager.instance; alias SerializeVector = bubel.ecs.vector.Vector!ubyte; +///Global EntityManager used for everything. +export __gshared EntityManager* gEntityManager = null; + /************************************************************************************************************************ Entity manager is responsible for everything. @@ -40,7 +41,7 @@ Entity manager can be in three states: Manager can be only in one state simultaneously. -Manager must be initialized before use. There is global instance of EntityManager: EntityManager.instance or gEM as alias. +Manager must be initialized before use. There is global instance of EntityManager: gEntityManager or gEntityManager as alias. Registration process consist of registration of passes, systems, entities and events. @@ -64,15 +65,15 @@ export struct EntityManager /************************************************************************************************************************ Initialize ECS. */ - export static void initialize(uint threads_count, uint page_size = 32768, + export static void initialize(uint threads_count = 1, uint page_size = 32768, uint block_pages_count = 128) { - if (instance is null) + if (gEntityManager is null) { - //instance = Mallocator.make!EntityManager(threads_count); - instance = Mallocator.make!EntityManager(threads_count, page_size, block_pages_count); + //gEntityManager = Mallocator.make!EntityManager(threads_count); + gEntityManager = Mallocator.make!EntityManager(threads_count, page_size, block_pages_count); - with (instance) + with (gEntityManager) { UpdatePass* pass = Mallocator.make!UpdatePass; pass.name = Mallocator.makeArray(cast(char[]) "update"); @@ -89,10 +90,10 @@ export struct EntityManager */ export static void destroy() { - if (instance is null) + if (gEntityManager is null) return; - with (instance) + with (gEntityManager) { foreach (ref system; systems) { @@ -131,8 +132,8 @@ export struct EntityManager } } - Mallocator.dispose(instance); - instance = null; + Mallocator.dispose(gEntityManager); + gEntityManager = null; } /************************************************************************************************************************ @@ -1904,8 +1905,8 @@ export struct EntityManager addSystemCaller(*info, cast(uint) i); } - info.comp_add_info = Mallocator.makeArray!(EntityInfo*)(instance.components.length); - //info.comp_rem_info = Mallocator.makeArray!(EntityInfo*)(instance.components.length); + info.comp_add_info = Mallocator.makeArray!(EntityInfo*)(gEntityManager.components.length); + //info.comp_rem_info = Mallocator.makeArray!(EntityInfo*)(gEntityManager.components.length); info.comp_rem_info = Mallocator.makeArray!(EntityInfo*)(info.deltas.length); foreach (comp; info.components) @@ -3406,7 +3407,7 @@ export struct EntityManager if (comp_add_info.length <= id) { EntityInfo*[] new_infos = Mallocator.makeArray!(EntityInfo*)( - instance.components.length); + gEntityManager.components.length); if (comp_add_info !is null) { //new_infos[0 .. comp_add_info.length] = comp_add_info[0 .. $]; @@ -3445,7 +3446,7 @@ export struct EntityManager assert(len == components.length + 1); - EntityInfo* new_info = instance.getEntityInfo(ids); + EntityInfo* new_info = gEntityManager.getEntityInfo(ids); comp_add_info[id] = new_info; return new_info; @@ -3456,7 +3457,7 @@ export struct EntityManager /*if (comp_rem_info.length <= id) { EntityInfo*[] new_infos = Mallocator.makeArray!(EntityInfo*)( - instance.components.length, &this); + gEntityManager.components.length, &this); if (comp_rem_info !is null) { //new_infos[0 .. comp_rem_info.length] = comp_rem_info[0 .. $]; @@ -3486,7 +3487,7 @@ export struct EntityManager assert(len == components.length - 1); - EntityInfo* new_info = instance.getEntityInfo(ids[0 .. len]); + EntityInfo* new_info = gEntityManager.getEntityInfo(ids[0 .. len]); comp_rem_info[id] = new_info; return new_info; @@ -3646,10 +3647,10 @@ export struct EntityManager export void execute() nothrow @nogc { - //EntityManager.instance.getThreadID(); + //gEntityManager.getThreadID(); foreach (ref caller; callers) { - caller.thread_id = EntityManager.instance.threadID(); + caller.thread_id = gEntityManager.threadID(); caller.job_id = id; caller.update(); } @@ -3866,6 +3867,5 @@ export struct EntityManager return ret; } } - - export __gshared EntityManager* instance = null; + } diff --git a/tests/access_perf.d b/tests/access_perf.d index b1b16bf..87a0a75 100644 --- a/tests/access_perf.d +++ b/tests/access_perf.d @@ -54,26 +54,26 @@ EntityTemplate* tmpl; void beforeEveryTest() { - gEM.initialize(0); + gEntityManager.initialize(0); - gEM.beginRegister(); + gEntityManager.beginRegister(); - gEM.registerComponent!CLong; - gEM.registerComponent!CInt; - gEM.registerComponent!CUInt; - gEM.registerComponent!CBig; + gEntityManager.registerComponent!CLong; + gEntityManager.registerComponent!CInt; + gEntityManager.registerComponent!CUInt; + gEntityManager.registerComponent!CBig; - gEM.endRegister(); + gEntityManager.endRegister(); - tmpl = gEM.allocateTemplate([becsID!CLong, becsID!CInt, becsID!CUInt, becsID!CBig].staticArray); - foreach(i; 0 .. 100_000)gEM.addEntity(tmpl); + tmpl = gEntityManager.allocateTemplate([becsID!CLong, becsID!CInt, becsID!CUInt, becsID!CBig].staticArray); + foreach(i; 0 .. 100_000)gEntityManager.addEntity(tmpl); } void afterEveryTest() { - if(tmpl)gEM.freeTemplate(tmpl); + if(tmpl)gEntityManager.freeTemplate(tmpl); tmpl = null; - gEM.destroy(); + gEntityManager.destroy(); } @("DirectAccess100k1comp") @@ -81,7 +81,7 @@ unittest { foreach(i;0..25000) { - Entity* entity = gEM.getEntity(EntityID(i*4+1,0)); + Entity* entity = gEntityManager.getEntity(EntityID(i*4+1,0)); CUInt* comp1 = entity.getComponent!CUInt; comp1.value = 4; } @@ -92,7 +92,7 @@ unittest { foreach(i;0..25000) { - Entity* entity = gEM.getEntity(EntityID(i*4+1,0)); + Entity* entity = gEntityManager.getEntity(EntityID(i*4+1,0)); CUInt* comp1 = entity.getComponent!CUInt; comp1.value = 4; CInt* comp2 = entity.getComponent!CInt; @@ -109,7 +109,7 @@ unittest { foreach(i;0..25000) { - Entity* entity = gEM.getEntity(EntityID(i*4+1,0)); + Entity* entity = gEntityManager.getEntity(EntityID(i*4+1,0)); EntityMeta meta = entity.getMeta(); CUInt* comp1 = meta.getComponent!CUInt; comp1.value = 4; @@ -121,7 +121,7 @@ unittest { foreach(i;0..25000) { - Entity* entity = gEM.getEntity(EntityID(i*4+1,0)); + Entity* entity = gEntityManager.getEntity(EntityID(i*4+1,0)); EntityMeta meta = entity.getMeta(); CUInt* comp1 = meta.getComponent!CUInt; comp1.value = 4; diff --git a/tests/basic.d b/tests/basic.d index 026fe20..aa730ea 100644 --- a/tests/basic.d +++ b/tests/basic.d @@ -116,31 +116,31 @@ struct EmptySystem void beforeEveryTest() { becsID!CUnregistered = ushort.max; - gEM.initialize(0); + gEntityManager.initialize(0); - gEM.beginRegister(); + gEntityManager.beginRegister(); - gEM.registerComponent!CInt; - gEM.registerComponent!CFloat; - gEM.registerComponent!CDouble; - gEM.registerComponent!CLong; - gEM.registerComponent!CShort; - gEM.registerComponent!CFlag; + gEntityManager.registerComponent!CInt; + gEntityManager.registerComponent!CFloat; + gEntityManager.registerComponent!CDouble; + gEntityManager.registerComponent!CLong; + gEntityManager.registerComponent!CShort; + gEntityManager.registerComponent!CFlag; - gEM.endRegister(); + gEntityManager.endRegister(); } void afterEveryTest() { - gEM.destroy(); + gEntityManager.destroy(); } @("EntityMeta") unittest { - EntityTemplate* tmpl_ = gEM.allocateTemplate([becsID!CInt, becsID!CFloat, becsID!CFlag].staticArray); - scope(exit)gEM.freeTemplate(tmpl_); - Entity* entity = gEM.addEntity(tmpl_); + EntityTemplate* tmpl_ = gEntityManager.allocateTemplate([becsID!CInt, becsID!CFloat, becsID!CFlag].staticArray); + scope(exit)gEntityManager.freeTemplate(tmpl_); + Entity* entity = gEntityManager.addEntity(tmpl_); EntityMeta meta = entity.getMeta(); assert(meta.hasComponent(becsID!CInt)); assert(meta.getComponent!CInt); @@ -157,8 +157,8 @@ unittest @("AddEntity") unittest { - EntityTemplate* tmpl_ = gEM.allocateTemplate([becsID!CInt, becsID!CFloat, becsID!CFlag].staticArray); - scope(exit)gEM.freeTemplate(tmpl_); + EntityTemplate* tmpl_ = gEntityManager.allocateTemplate([becsID!CInt, becsID!CFloat, becsID!CFlag].staticArray); + scope(exit)gEntityManager.freeTemplate(tmpl_); assert(tmpl_.info.components.length == 3); assert(tmpl_.info.size == (CInt.sizeof + CFloat.sizeof + EntityID.sizeof)); assert(tmpl_.getComponent!CInt); @@ -169,14 +169,14 @@ unittest assert(*tmpl_.getComponent!CInt == 1); assert(*tmpl_.getComponent!CFloat == 2.0); - Entity* entity = gEM.addEntity(tmpl_); + Entity* entity = gEntityManager.addEntity(tmpl_); assert(entity.getComponent!CInt); assert(entity.getComponent!CFloat); assert(*entity.getComponent!CInt == 1); assert(*entity.getComponent!CFloat == 2.0); *entity.getComponent!CInt = 2; - Entity* entity2 = gEM.addEntityCopy(entity.id); + Entity* entity2 = gEntityManager.addEntityCopy(entity.id); assert(entity2.getComponent!CInt); assert(entity2.getComponent!CFloat); assert(*entity2.getComponent!CInt == 2); @@ -184,17 +184,17 @@ unittest //CInt cint = CInt(10); //CLong clong; - //Entity* entity3 = gEM.addEntity(tmpl_, [cint.ref_, clong.ref_].staticArray); - Entity* entity3 = gEM.addEntity(tmpl_, [CInt(10).ref_, CLong().ref_, CFlag().ref_].staticArray); + //Entity* entity3 = gEntityManager.addEntity(tmpl_, [cint.ref_, clong.ref_].staticArray); + Entity* entity3 = gEntityManager.addEntity(tmpl_, [CInt(10).ref_, CLong().ref_, CFlag().ref_].staticArray); EntityID id = entity3.id; assert(entity3.hasComponent(becsID!CInt)); assert(entity3.hasComponent(becsID!CFloat)); assert(*entity3.getComponent!CInt == 10); assert(*entity3.getComponent!CFloat == 2.0); - gEM.addComponents(entity3.id, [CFlag().ref_,CShort(2).ref_].staticArray); - gEM.commit(); - entity3 = gEM.getEntity(id); + gEntityManager.addComponents(entity3.id, [CFlag().ref_,CShort(2).ref_].staticArray); + gEntityManager.commit(); + entity3 = gEntityManager.getEntity(id); assert(entity3.getComponent!CInt); assert(entity3.getComponent!CFloat); assert(entity3.getComponent!CFlag); @@ -203,9 +203,9 @@ unittest assert(*entity3.getComponent!CFloat == 2.0); assert(*entity3.getComponent!CShort == 2); - gEM.removeComponents(entity3.id, [becsID!CFlag,becsID!CShort].staticArray); - gEM.commit(); - entity3 = gEM.getEntity(id); + gEntityManager.removeComponents(entity3.id, [becsID!CFlag,becsID!CShort].staticArray); + gEntityManager.commit(); + entity3 = gEntityManager.getEntity(id); assert(entity3.getComponent!CInt); assert(entity3.getComponent!CFloat); assert(!entity3.getComponent!CFlag); @@ -213,10 +213,10 @@ unittest assert(*entity3.getComponent!CInt == 10); assert(*entity3.getComponent!CFloat == 2.0); - gEM.addComponents(entity3.id, [CFlag().ref_,CShort(2).ref_].staticArray); - gEM.removeComponents(entity3.id, [becsID!CUnregistered].staticArray); - gEM.commit(); - entity3 = gEM.getEntity(id); + gEntityManager.addComponents(entity3.id, [CFlag().ref_,CShort(2).ref_].staticArray); + gEntityManager.removeComponents(entity3.id, [becsID!CUnregistered].staticArray); + gEntityManager.commit(); + entity3 = gEntityManager.getEntity(id); assert(entity3.getComponent!CInt); assert(entity3.getComponent!CFloat); assert(entity3.getComponent!CFlag); @@ -225,21 +225,21 @@ unittest assert(*entity3.getComponent!CFloat == 2.0); assert(*entity3.getComponent!CShort == 2); - gEM.beginRegister(); + gEntityManager.beginRegister(); - gEM.registerComponent!CUnregistered; + gEntityManager.registerComponent!CUnregistered; - gEM.endRegister(); + gEntityManager.endRegister(); - gEM.addComponents(entity3.id, [CUnregistered(4).ref_].staticArray); - gEM.commit(); - entity3 = gEM.getEntity(id); + gEntityManager.addComponents(entity3.id, [CUnregistered(4).ref_].staticArray); + gEntityManager.commit(); + entity3 = gEntityManager.getEntity(id); assert(entity3.getComponent!CUnregistered); assert(*entity3.getComponent!CUnregistered == 4); - gEM.removeComponents(entity3.id, [becsID!CUnregistered].staticArray); - gEM.commit(); - entity3 = gEM.getEntity(id); + gEntityManager.removeComponents(entity3.id, [becsID!CUnregistered].staticArray); + gEntityManager.commit(); + entity3 = gEntityManager.getEntity(id); assert(!entity3.getComponent!CUnregistered); } @@ -250,9 +250,9 @@ unittest { //basic template allocation ushort[2] ids = [becsID!CInt, becsID!CFloat]; - EntityTemplate* tmpl_ = gEM.allocateTemplate(ids); - EntityTemplate* tmpl_d = gEM.allocateTemplate([becsID!CFloat, becsID!CInt, becsID!CFloat].staticArray); - EntityTemplate* tmpl_cp = gEM.allocateTemplate(tmpl_); + EntityTemplate* tmpl_ = gEntityManager.allocateTemplate(ids); + EntityTemplate* tmpl_d = gEntityManager.allocateTemplate([becsID!CFloat, becsID!CInt, becsID!CFloat].staticArray); + EntityTemplate* tmpl_cp = gEntityManager.allocateTemplate(tmpl_); assert(tmpl_d.info == tmpl_.info); assert(tmpl_cp.info == tmpl_cp.info); assert(tmpl_.info.components.length == 2); @@ -271,7 +271,7 @@ unittest //allocate template from template with additional components ushort[2] ids2 = [becsID!CDouble,becsID!CFlag]; - EntityTemplate* tmpl_2 = gEM.allocateTemplate(tmpl_, ids2); + EntityTemplate* tmpl_2 = gEntityManager.allocateTemplate(tmpl_, ids2); assert(tmpl_2.info.components.length == 4); assert(tmpl_2.getComponent!CInt); assert(tmpl_2.getComponent!CFloat); @@ -283,19 +283,19 @@ unittest assert(tmpl_.info.blocksCount() == 0); - Entity* entity = gEM.addEntity(tmpl_); - gEM.addComponents(entity.id, CFloat(100)); - gEM.addComponents(entity.id, CDouble(8.0), CFloat(100)); + Entity* entity = gEntityManager.addEntity(tmpl_); + gEntityManager.addComponents(entity.id, CFloat(100)); + gEntityManager.addComponents(entity.id, CDouble(8.0), CFloat(100)); assert(tmpl_.info.blocksCount() == 1); //apply entity changes - gEM.commit(); + gEntityManager.commit(); assert(tmpl_.info.blocksCount() == 0); //allocate template as entity copy - EntityTemplate* tmpl_3 = gEM.allocateTemplate(entity.id); + EntityTemplate* tmpl_3 = gEntityManager.allocateTemplate(entity.id); assert(tmpl_3.info.components.length == 3); assert(tmpl_3.getComponent!CInt); assert(tmpl_3.getComponent!CFloat); @@ -305,7 +305,7 @@ unittest assert(*tmpl_3.getComponent!CDouble == 8.0); //allocate template with entity data but default values - EntityTemplate* tmpl_4 = gEM.allocateTemplate(entity.id, true); + EntityTemplate* tmpl_4 = gEntityManager.allocateTemplate(entity.id, true); assert(tmpl_4.info.components.length == 3); assert(tmpl_4.getComponent!CInt); assert(tmpl_4.getComponent!CFloat); @@ -316,7 +316,7 @@ unittest //allocate template from template with three additional component ushort[3] ids3 = [becsID!CDouble, becsID!CLong, becsID!CShort]; - EntityTemplate* tmpl_5 = gEM.allocateTemplate(tmpl_2, ids3); + EntityTemplate* tmpl_5 = gEntityManager.allocateTemplate(tmpl_2, ids3); assert(tmpl_5.info.components.length == 6); assert(tmpl_5.getComponent!CInt); assert(tmpl_5.getComponent!CFloat); @@ -331,13 +331,13 @@ unittest //allocate template from template without one component ushort[1] rem_ids = [becsID!CFloat]; - EntityTemplate* tmpl_6 = gEM.allocateTemplate(tmpl_, null, rem_ids); + EntityTemplate* tmpl_6 = gEntityManager.allocateTemplate(tmpl_, null, rem_ids); assert(tmpl_6.info.components.length == 1); assert(tmpl_6.getComponent!CInt); assert(*tmpl_6.getComponent!CInt == 4); //allocate template from template without one component and two additional - EntityTemplate* tmpl_7 = gEM.allocateTemplate(tmpl_, ids3, rem_ids); + EntityTemplate* tmpl_7 = gEntityManager.allocateTemplate(tmpl_, ids3, rem_ids); assert(tmpl_7.info.components.length == 4); assert(tmpl_7.getComponent!CInt); assert(tmpl_7.getComponent!CDouble); @@ -346,15 +346,15 @@ unittest assert(*tmpl_7.getComponent!CDouble == 3.0); assert(*tmpl_7.getComponent!CLong == 10); - gEM.freeTemplate(tmpl_d); - gEM.freeTemplate(tmpl_cp); - gEM.freeTemplate(tmpl_); - gEM.freeTemplate(tmpl_2); - gEM.freeTemplate(tmpl_3); - gEM.freeTemplate(tmpl_4); - gEM.freeTemplate(tmpl_5); - gEM.freeTemplate(tmpl_6); - gEM.freeTemplate(tmpl_7); + gEntityManager.freeTemplate(tmpl_d); + gEntityManager.freeTemplate(tmpl_cp); + gEntityManager.freeTemplate(tmpl_); + gEntityManager.freeTemplate(tmpl_2); + gEntityManager.freeTemplate(tmpl_3); + gEntityManager.freeTemplate(tmpl_4); + gEntityManager.freeTemplate(tmpl_5); + gEntityManager.freeTemplate(tmpl_6); + gEntityManager.freeTemplate(tmpl_7); } @("UnsortedComponentIDs") @@ -363,56 +363,56 @@ unittest //basic template allocation ushort[2] ids = [becsID!CFloat, becsID!CInt]; ushort[2] ids2 = [becsID!CInt, becsID!CFloat]; - EntityTemplate* tmpl_ = gEM.allocateTemplate(ids); - EntityTemplate* tmpl_2 = gEM.allocateTemplate(ids2); + EntityTemplate* tmpl_ = gEntityManager.allocateTemplate(ids); + EntityTemplate* tmpl_2 = gEntityManager.allocateTemplate(ids2); assert(tmpl_.info.components.length == 2); assert(tmpl_.getComponent!CInt); assert(tmpl_.getComponent!CFloat); assert(*tmpl_.getComponent!CInt == 1); assert(*tmpl_.getComponent!CFloat == 2.0); assert(tmpl_.info == tmpl_2.info); - gEM.freeTemplate(tmpl_); - gEM.freeTemplate(tmpl_2); + gEntityManager.freeTemplate(tmpl_); + gEntityManager.freeTemplate(tmpl_2); } @("MultiRegister") unittest { - gEM.beginRegister(); + gEntityManager.beginRegister(); - gEM.endRegister(); + gEntityManager.endRegister(); - gEM.beginRegister(); + gEntityManager.beginRegister(); - gEM.registerComponent!CLong; - gEM.registerComponent!CShort; + gEntityManager.registerComponent!CLong; + gEntityManager.registerComponent!CShort; - gEM.endRegister(); + gEntityManager.endRegister(); } @("EmptySystem") unittest { - gEM.beginRegister(); + gEntityManager.beginRegister(); - gEM.registerSystem!EmptySystem(0); + gEntityManager.registerSystem!EmptySystem(0); - gEM.endRegister(); + gEntityManager.endRegister(); - EmptySystem* system = gEM.getSystem!EmptySystem; + EmptySystem* system = gEntityManager.getSystem!EmptySystem; assert(system !is null); assert(system.count == 0); - System* ecs_system = gEM.getSystem(becsID!EmptySystem); + System* ecs_system = gEntityManager.getSystem(becsID!EmptySystem); assert(ecs_system !is null); assert(ecs_system.id == becsID!EmptySystem); assert(ecs_system.name == "tests.basic.EmptySystem"); - gEM.begin(); + gEntityManager.begin(); - gEM.update(); + gEntityManager.update(); - gEM.end(); + gEntityManager.end(); assert(system.count == 1); } @@ -480,23 +480,23 @@ unittest bool pass = true; } - gEM.beginRegister(); + gEntityManager.beginRegister(); - gEM.registerSystem!TestSystem(0); + gEntityManager.registerSystem!TestSystem(0); - gEM.endRegister(); + gEntityManager.endRegister(); - TestSystem* system = gEM.getSystem!TestSystem; + TestSystem* system = gEntityManager.getSystem!TestSystem; int destroy = 0; system.destroy = &destroy; - gEM.beginRegister(); + gEntityManager.beginRegister(); - gEM.registerSystem!TestSystem(0); + gEntityManager.registerSystem!TestSystem(0); - gEM.endRegister(); + gEntityManager.endRegister(); - system = gEM.getSystem!TestSystem; + system = gEntityManager.getSystem!TestSystem; system.destroy = &destroy; assert(system !is null); assert(system.create == 1); @@ -507,7 +507,7 @@ unittest //FIXME: currently destroy is only called with Manager.destory which is bug, but there is no workaround for this by now //assert(destroy == 1); - System* ecs_system = gEM.getSystem(system.becsID); + System* ecs_system = gEntityManager.getSystem(system.becsID); ecs_system.enable(); assert(system.enable == 1); @@ -519,70 +519,70 @@ unittest ushort[2] ids = [becsID!CLong,becsID!CFloat]; - EntityTemplate* tmpl = gEM.allocateTemplate(ids); - scope (exit) gEM.freeTemplate(tmpl); - gEM.addEntity(tmpl); + EntityTemplate* tmpl = gEntityManager.allocateTemplate(ids); + scope (exit) gEntityManager.freeTemplate(tmpl); + gEntityManager.addEntity(tmpl); - gEM.begin(); + gEntityManager.begin(); assert(system.begin == 1); - gEM.update(); + gEntityManager.update(); assert(system.update == 1); - gEM.end(); + gEntityManager.end(); assert(system.end == 1); ushort[2] ids2 = [becsID!CLong, becsID!CInt]; - EntityTemplate* tmpl2 = gEM.allocateTemplate(ids2); - scope (exit) gEM.freeTemplate(tmpl2); - gEM.addEntity(tmpl2); - gEM.addEntity(tmpl2); + EntityTemplate* tmpl2 = gEntityManager.allocateTemplate(ids2); + scope (exit) gEntityManager.freeTemplate(tmpl2); + gEntityManager.addEntity(tmpl2); + gEntityManager.addEntity(tmpl2); - gEM.begin(); + gEntityManager.begin(); assert(system.begin == 2); - gEM.update(); + gEntityManager.update(); assert(system.update == 2);//system is updated number of entity blocks times - gEM.end(); + gEntityManager.end(); assert(system.end == 2); ushort[2] ids3 = [becsID!CLong, becsID!CShort]; - EntityTemplate* tmpl3 = gEM.allocateTemplate(ids3); - scope (exit) gEM.freeTemplate(tmpl3); - gEM.addEntity(tmpl3); + EntityTemplate* tmpl3 = gEntityManager.allocateTemplate(ids3); + scope (exit) gEntityManager.freeTemplate(tmpl3); + gEntityManager.addEntity(tmpl3); //entity with excluded component shouldn't be updated - gEM.begin(); + gEntityManager.begin(); assert(system.begin == 3); - gEM.update(); + gEntityManager.update(); assert(system.update == 2); - gEM.end(); + gEntityManager.end(); assert(system.end == 3); //system can be disable form update in onBegin() callback, onEnd() callback is called system.pass = false; - gEM.begin(); + gEntityManager.begin(); assert(system.begin == 4); - gEM.update(); + gEntityManager.update(); assert(system.update == 0); - gEM.end(); + gEntityManager.end(); assert(system.end == 4); system.pass = true; //disabled system is't called ecs_system.disable(); - gEM.begin(); + gEntityManager.begin(); assert(system.begin == 4); - gEM.update(); + gEntityManager.update(); assert(system.update == 0); - gEM.end(); + gEntityManager.end(); assert(system.end == 4); ecs_system.enable(); system.destroy = null; @@ -591,40 +591,40 @@ unittest @("CustomPass") unittest { - gEM.beginRegister(); + gEntityManager.beginRegister(); - gEM.registerPass("custom"); - gEM.registerSystem!LongAddSystem(-1,"custom"); + gEntityManager.registerPass("custom"); + gEntityManager.registerSystem!LongAddSystem(-1,"custom"); - gEM.endRegister(); + gEntityManager.endRegister(); - assert(gEM.getPass("custom")); - assert(!gEM.getPass("custommm")); + assert(gEntityManager.getPass("custom")); + assert(!gEntityManager.getPass("custommm")); - LongAddSystem* system = gEM.getSystem!LongAddSystem; + LongAddSystem* system = gEntityManager.getSystem!LongAddSystem; assert(system !is null); assert(system.updates_count == 0); - System* ecs_system = gEM.getSystem(becsID!LongAddSystem); + System* ecs_system = gEntityManager.getSystem(becsID!LongAddSystem); assert(ecs_system !is null); assert(ecs_system.id == becsID!LongAddSystem); assert(ecs_system.priority == -1); assert(ecs_system.name == "tests.basic.LongAddSystem"); ushort[1] ids = [becsID!CLong]; - EntityTemplate* tmpl = gEM.allocateTemplate(ids); - scope (exit) gEM.freeTemplate(tmpl); - gEM.addEntity(tmpl); + EntityTemplate* tmpl = gEntityManager.allocateTemplate(ids); + scope (exit) gEntityManager.freeTemplate(tmpl); + gEntityManager.addEntity(tmpl); - gEM.begin(); + gEntityManager.begin(); - gEM.update(); + gEntityManager.update(); assert(system.updates_count == 0); - gEM.update("custom"); + gEntityManager.update("custom"); assert(system.updates_count == 1); - gEM.end(); + gEntityManager.end(); } @("SystemEntityCallbacks") @@ -748,91 +748,91 @@ unittest } } - gEM.beginRegister(); + gEntityManager.beginRegister(); - gEM.registerSystem!TestSystem3(-1); - gEM.registerSystem!TestSystem(0); - gEM.registerSystem!TestSystem2(1); + gEntityManager.registerSystem!TestSystem3(-1); + gEntityManager.registerSystem!TestSystem(0); + gEntityManager.registerSystem!TestSystem2(1); - gEM.endRegister(); + gEntityManager.endRegister(); - TestSystem* system = gEM.getSystem!TestSystem; + TestSystem* system = gEntityManager.getSystem!TestSystem; assert(system !is null); assert(system.add == 0); assert(system.remove == 0); assert(system.change == 0); - EntityTemplate* tmpl = gEM.allocateTemplate([becsID!CLong,becsID!CFloat].staticArray); - scope (exit) gEM.freeTemplate(tmpl); - EntityID id0 = gEM.addEntity(tmpl).id; - gEM.commit(); + EntityTemplate* tmpl = gEntityManager.allocateTemplate([becsID!CLong,becsID!CFloat].staticArray); + scope (exit) gEntityManager.freeTemplate(tmpl); + EntityID id0 = gEntityManager.addEntity(tmpl).id; + gEntityManager.commit(); assert(system.add == 1); - EntityTemplate* tmpl2 = gEM.allocateTemplate([becsID!CLong, becsID!CInt].staticArray); - scope (exit) gEM.freeTemplate(tmpl2); - EntityID id1 = gEM.addEntity(tmpl2).id; - gEM.commit(); + EntityTemplate* tmpl2 = gEntityManager.allocateTemplate([becsID!CLong, becsID!CInt].staticArray); + scope (exit) gEntityManager.freeTemplate(tmpl2); + EntityID id1 = gEntityManager.addEntity(tmpl2).id; + gEntityManager.commit(); assert(system.add == 2); - EntityTemplate* tmpl3 = gEM.allocateTemplate([becsID!CLong, becsID!CShort].staticArray); - scope (exit) gEM.freeTemplate(tmpl3); - EntityID id2 = gEM.addEntity(tmpl3).id; - gEM.commit(); + EntityTemplate* tmpl3 = gEntityManager.allocateTemplate([becsID!CLong, becsID!CShort].staticArray); + scope (exit) gEntityManager.freeTemplate(tmpl3); + EntityID id2 = gEntityManager.addEntity(tmpl3).id; + gEntityManager.commit(); assert(system.add == 2); - gEM.beginRegister(); - gEM.endRegister(); + gEntityManager.beginRegister(); + gEntityManager.endRegister(); - gEM.removeComponents(id0, [becsID!CFloat].staticArray); - gEM.commit(); + gEntityManager.removeComponents(id0, [becsID!CFloat].staticArray); + gEntityManager.commit(); assert(system.add == 2); assert(system.remove == 0); assert(system.change == 0); - gEM.removeComponents(id1, [becsID!CInt].staticArray); - gEM.commit(); + gEntityManager.removeComponents(id1, [becsID!CInt].staticArray); + gEntityManager.commit(); assert(system.add == 2); assert(system.remove == 0); assert(system.change == 1); - gEM.removeComponents(id2, [becsID!CShort].staticArray); - gEM.commit(); + gEntityManager.removeComponents(id2, [becsID!CShort].staticArray); + gEntityManager.commit(); assert(system.add == 3); assert(system.remove == 0); assert(system.change == 1); - gEM.addComponents(id2, CShort(1)); - gEM.commit(); + gEntityManager.addComponents(id2, CShort(1)); + gEntityManager.commit(); assert(system.add == 3); assert(system.remove == 1); assert(system.change == 1); - gEM.removeEntity(id0); - gEM.commit(); + gEntityManager.removeEntity(id0); + gEntityManager.commit(); assert(system.add == 3); assert(system.remove == 2); assert(system.change == 1); - gEM.addComponents(id1, CInt(1)); - gEM.commit(); + gEntityManager.addComponents(id1, CInt(1)); + gEntityManager.commit(); assert(system.add == 3); assert(system.remove == 2); assert(system.change == 2); - gEM.addComponents(id0, CFloat(1)); - gEM.commit(); + gEntityManager.addComponents(id0, CFloat(1)); + gEntityManager.commit(); assert(system.add == 3); assert(system.remove == 2); assert(system.change == 2); - gEM.removeEntity(id1); - gEM.commit(); + gEntityManager.removeEntity(id1); + gEntityManager.commit(); assert(system.add == 3); assert(system.remove == 3); assert(system.change == 2); - gEM.removeEntity(id2); - gEM.commit(); + gEntityManager.removeEntity(id2); + gEntityManager.commit(); assert(system.add == 3); assert(system.remove == 3); assert(system.change == 2); @@ -862,13 +862,13 @@ unittest } } - gEM.beginRegister(); + gEntityManager.beginRegister(); - gEM.registerComponent!CUnregistered; + gEntityManager.registerComponent!CUnregistered; - gEM.registerSystem!TestSystem(0); + gEntityManager.registerSystem!TestSystem(0); - gEM.endRegister(); + gEntityManager.endRegister(); } @("UnregisteredSystem") @@ -893,8 +893,8 @@ unittest } } - assert(gEM.getSystem!TestSystem is null); - assert(gEM.getSystem(becsID!TestSystem) is null); + assert(gEntityManager.getSystem!TestSystem is null); + assert(gEntityManager.getSystem(becsID!TestSystem) is null); } @("MultithreadedUpdate") @@ -953,68 +953,68 @@ unittest return 0; } - gEM.setMultithreadingCallbacks(&dispatch, &getID); + gEntityManager.setMultithreadingCallbacks(&dispatch, &getID); - gEM.beginRegister(); + gEntityManager.beginRegister(); - gEM.registerPass("custom"); - gEM.registerSystem!TestSystem(-1,"custom"); - gEM.registerSystem!TestEmptySystem(1,"custom"); + gEntityManager.registerPass("custom"); + gEntityManager.registerSystem!TestSystem(-1,"custom"); + gEntityManager.registerSystem!TestEmptySystem(1,"custom"); - gEM.endRegister(); + gEntityManager.endRegister(); - TestSystem* system = gEM.getSystem!TestSystem; - TestEmptySystem* empty_system = gEM.getSystem!TestEmptySystem; + TestSystem* system = gEntityManager.getSystem!TestSystem; + TestEmptySystem* empty_system = gEntityManager.getSystem!TestEmptySystem; ushort[2] ids = [becsID!CLong,becsID!CFloat]; - EntityTemplate* tmpl = gEM.allocateTemplate(ids); - scope (exit) gEM.freeTemplate(tmpl); - EntityTemplate* tmpl2 = gEM.allocateTemplate([becsID!CLong,becsID!CInt,becsID!CShort,becsID!CFloat].staticArray); - scope (exit) gEM.freeTemplate(tmpl2); + EntityTemplate* tmpl = gEntityManager.allocateTemplate(ids); + scope (exit) gEntityManager.freeTemplate(tmpl); + EntityTemplate* tmpl2 = gEntityManager.allocateTemplate([becsID!CLong,becsID!CInt,becsID!CShort,becsID!CFloat].staticArray); + scope (exit) gEntityManager.freeTemplate(tmpl2); - gEM.begin(); + gEntityManager.begin(); - gEM.updateMT("custom"); + gEntityManager.updateMT("custom"); - gEM.end(); + gEntityManager.end(); assert(system.update == 0); assert(system.entities == 0); assert(empty_system.update == 1); - gEM.addEntity(tmpl); + gEntityManager.addEntity(tmpl); - gEM.begin(); + gEntityManager.begin(); - gEM.updateMT("custom"); + gEntityManager.updateMT("custom"); - gEM.end(); + gEntityManager.end(); assert(system.update == 1); assert(system.entities == 1); assert(empty_system.update == 2); system.entities = 0; - foreach(i;0..2000)gEM.addEntity(tmpl); + foreach(i;0..2000)gEntityManager.addEntity(tmpl); - gEM.begin(); + gEntityManager.begin(); - gEM.updateMT("custom"); + gEntityManager.updateMT("custom"); - gEM.end(); + gEntityManager.end(); assert(system.update > 2); assert(system.entities == 2001); assert(empty_system.update == 3); system.entities = 0; - // foreach(i;0..10000)gEM.addEntity(tmpl); + // foreach(i;0..10000)gEntityManager.addEntity(tmpl); - // gEM.begin(); + // gEntityManager.begin(); - // gEM.updateMT("custom"); + // gEntityManager.updateMT("custom"); - // gEM.end(); + // gEntityManager.end(); // assert(system.entities == 12001); @@ -1022,33 +1022,33 @@ unittest { foreach(i;0..data.length) { - gEM.removeEntity(data.entity[i].id); + gEntityManager.removeEntity(data.entity[i].id); } } - gEM.callEntitiesFunction!TestSystem(&clearEntities); - gEM.commit(); + gEntityManager.callEntitiesFunction!TestSystem(&clearEntities); + gEntityManager.commit(); foreach(i;0..2000) { - gEM.addEntity(tmpl); + gEntityManager.addEntity(tmpl); - gEM.begin(); - gEM.updateMT("custom"); - gEM.end(); + gEntityManager.begin(); + gEntityManager.updateMT("custom"); + gEntityManager.end(); assert(system.entities == i+1); system.entities = 0; } - foreach(i;0..90000)gEM.addEntity(tmpl); + foreach(i;0..90000)gEntityManager.addEntity(tmpl); foreach(i;0..2000) { - gEM.addEntity(tmpl); + gEntityManager.addEntity(tmpl); - gEM.begin(); - gEM.updateMT("custom"); - gEM.end(); + gEntityManager.begin(); + gEntityManager.updateMT("custom"); + gEntityManager.end(); assert(system.entities == i+92001); system.entities = 0; @@ -1057,16 +1057,16 @@ unittest unittest { - assert(gEM.pageSize == 32768); - assert(gEM.pagesInBlock == 128); + assert(gEntityManager.pageSize == 32768); + assert(gEntityManager.pagesInBlock == 128); } @("AddRemoveEntities") unittest { ushort[3] ids = [becsID!CLong,becsID!CFloat,becsID!CShort]; - EntityTemplate* tmpl = gEM.allocateTemplate(ids); - scope (exit) gEM.freeTemplate(tmpl); + EntityTemplate* tmpl = gEntityManager.allocateTemplate(ids); + scope (exit) gEntityManager.freeTemplate(tmpl); EntityID[5000] entities; @@ -1074,33 +1074,33 @@ unittest { foreach(j;0..5000) { - entities[j] = gEM.addEntity(tmpl).id; + entities[j] = gEntityManager.addEntity(tmpl).id; } - gEM.commit(); + gEntityManager.commit(); foreach(j;0..5000) { - gEM.removeEntity(entities[j]); + gEntityManager.removeEntity(entities[j]); } - gEM.commit(); + gEntityManager.commit(); } } @("ChangeEntityComponents") unittest { - gEM.beginRegister(); + gEntityManager.beginRegister(); - gEM.registerComponent!CUnregistered; + gEntityManager.registerComponent!CUnregistered; - gEM.endRegister(); + gEntityManager.endRegister(); ushort[1] ids = [becsID!CLong]; - EntityTemplate* tmpl = gEM.allocateTemplate(ids); - scope (exit) gEM.freeTemplate(tmpl); + EntityTemplate* tmpl = gEntityManager.allocateTemplate(ids); + scope (exit) gEntityManager.freeTemplate(tmpl); - EntityID id = gEM.addEntity(tmpl).id; - gEM.commit(); - Entity* entity = gEM.getEntity(id); + EntityID id = gEntityManager.addEntity(tmpl).id; + gEntityManager.commit(); + Entity* entity = gEntityManager.getEntity(id); assert(entity.id == id); assert(entity.getComponent!CLong !is null); assert(entity.getComponent!CFloat is null); @@ -1109,10 +1109,10 @@ unittest assert(entity.getComponent!CInt is null); assert(*entity.getComponent!CLong == 10); - gEM.addComponents(id, CShort(15), CFloat(13)); - gEM.commit(); + gEntityManager.addComponents(id, CShort(15), CFloat(13)); + gEntityManager.commit(); - entity = gEM.getEntity(id); + entity = gEntityManager.getEntity(id); assert(entity.id == id); assert(entity.getComponent!CLong !is null); assert(entity.getComponent!CFloat !is null); @@ -1124,10 +1124,10 @@ unittest assert(*entity.getComponent!CFloat == 13); ushort[3] ids2 = [becsID!CFloat, becsID!CLong, becsID!CUnregistered]; - gEM.removeComponents(id, ids2); - gEM.commit(); + gEntityManager.removeComponents(id, ids2); + gEntityManager.commit(); - entity = gEM.getEntity(id); + entity = gEntityManager.getEntity(id); assert(entity.id == id); assert(entity.getComponent!CLong is null); assert(entity.getComponent!CFloat is null); @@ -1136,11 +1136,11 @@ unittest assert(entity.getComponent!CInt is null); assert(*entity.getComponent!CShort == 15); - gEM.removeComponents(id, ids2); - gEM.addComponents(id, CShort(11), CLong(2)); //wrong order of components - gEM.commit(); + gEntityManager.removeComponents(id, ids2); + gEntityManager.addComponents(id, CShort(11), CLong(2)); //wrong order of components + gEntityManager.commit(); - entity = gEM.getEntity(id); + entity = gEntityManager.getEntity(id); assert(entity.id == id); assert(entity.getComponent!CLong !is null); assert(entity.getComponent!CFloat is null); @@ -1150,14 +1150,14 @@ unittest assert(*entity.getComponent!CLong == 2); assert(*entity.getComponent!CShort == 15); - gEM.removeEntity(id); + gEntityManager.removeEntity(id); - entity = gEM.getEntity(id); + entity = gEntityManager.getEntity(id); assert(entity !is null); assert(entity.id == id); - gEM.commit(); - entity = gEM.getEntity(id); + gEntityManager.commit(); + entity = gEntityManager.getEntity(id); assert(entity is null); } @@ -1245,52 +1245,52 @@ unittest } } - gEM.beginRegister(); + gEntityManager.beginRegister(); - gEM.registerEvent!ETest; - gEM.registerEvent!ETest2; + gEntityManager.registerEvent!ETest; + gEntityManager.registerEvent!ETest2; - gEM.registerEvent!ETest; - gEM.registerEvent!ETest2; + gEntityManager.registerEvent!ETest; + gEntityManager.registerEvent!ETest2; - gEM.registerSystem!TestSystem2(1); - gEM.registerSystem!TestSystem(0); + gEntityManager.registerSystem!TestSystem2(1); + gEntityManager.registerSystem!TestSystem(0); - gEM.endRegister(); + gEntityManager.endRegister(); ushort[1] ids = [becsID!CLong]; - EntityTemplate* tmpl = gEM.allocateTemplate(ids); - scope (exit) gEM.freeTemplate(tmpl); + EntityTemplate* tmpl = gEntityManager.allocateTemplate(ids); + scope (exit) gEntityManager.freeTemplate(tmpl); ushort[1] ids2 = [becsID!CShort]; - EntityTemplate* tmpl2 = gEM.allocateTemplate(ids2); - scope (exit) gEM.freeTemplate(tmpl2); + EntityTemplate* tmpl2 = gEntityManager.allocateTemplate(ids2); + scope (exit) gEntityManager.freeTemplate(tmpl2); - Entity* entity = gEM.addEntity(tmpl); + Entity* entity = gEntityManager.addEntity(tmpl); EntityID id = entity.id; assert(*entity.getComponent!CLong == 10); - Entity* entity2 = gEM.addEntity(tmpl2); + Entity* entity2 = gEntityManager.addEntity(tmpl2); EntityID id2 = entity2.id; assert(*entity2.getComponent!CShort == 12); - gEM.sendEvent(id,ETest()); - gEM.sendEvent(id,ETest2(10)); - gEM.sendEvent(id2,ETest()); - gEM.sendEvent(id2,ETest2(12)); - gEM.commit(); + gEntityManager.sendEvent(id,ETest()); + gEntityManager.sendEvent(id,ETest2(10)); + gEntityManager.sendEvent(id2,ETest()); + gEntityManager.sendEvent(id2,ETest2(12)); + gEntityManager.commit(); assert(ETest2.destory == 2); - entity = gEM.getEntity(id); - entity2 = gEM.getEntity(id2); + entity = gEntityManager.getEntity(id); + entity2 = gEntityManager.getEntity(id2); assert(*entity.getComponent!CLong == 46); assert(*entity2.getComponent!CShort == 32); - gEM.addComponents(id, CInt(2), CShort(1)); - gEM.sendEvent(id,ETest()); - gEM.sendEvent(id,ETest2(2)); - gEM.commit(); + gEntityManager.addComponents(id, CInt(2), CShort(1)); + gEntityManager.sendEvent(id,ETest()); + gEntityManager.sendEvent(id,ETest2(2)); + gEntityManager.commit(); assert(ETest2.destory == 3); - entity = gEM.getEntity(id); + entity = gEntityManager.getEntity(id); assert(*entity.getComponent!CLong == 66); assert(*entity.getComponent!CInt == 2);//36); @@ -1298,18 +1298,18 @@ unittest long result = *entity.getComponent!CLong; foreach(i;0..10000) { - gEM.sendEvent(id,ETest()); - gEM.sendEvent(id,ETest2(4)); + gEntityManager.sendEvent(id,ETest()); + gEntityManager.sendEvent(id,ETest2(4)); result += 16; result += 8; } - gEM.commit(); + gEntityManager.commit(); assert(ETest2.destory == 10003); - entity = gEM.getEntity(id); + entity = gEntityManager.getEntity(id); assert(*entity.getComponent!CLong == result); //cover funcion to clearEvents before destroying manager - gEM.sendEvent(id,ETest()); + gEntityManager.sendEvent(id,ETest()); } @("EntitiesFunction") @@ -1347,36 +1347,36 @@ unittest } } - gEM.beginRegister(); + gEntityManager.beginRegister(); - gEM.registerSystem!TestSystem(1); + gEntityManager.registerSystem!TestSystem(1); - gEM.endRegister(); + gEntityManager.endRegister(); - EntityTemplate* tmpl = gEM.allocateTemplate([becsID!CInt].staticArray); - scope (exit) gEM.freeTemplate(tmpl); - EntityID id1 = gEM.addEntity(tmpl).id; + EntityTemplate* tmpl = gEntityManager.allocateTemplate([becsID!CInt].staticArray); + scope (exit) gEntityManager.freeTemplate(tmpl); + EntityID id1 = gEntityManager.addEntity(tmpl).id; - EntityTemplate* tmpl2 = gEM.allocateTemplate([becsID!CInt, becsID!CLong].staticArray); - scope (exit) gEM.freeTemplate(tmpl2); - EntityID id2 = gEM.addEntity(tmpl2).id; + EntityTemplate* tmpl2 = gEntityManager.allocateTemplate([becsID!CInt, becsID!CLong].staticArray); + scope (exit) gEntityManager.freeTemplate(tmpl2); + EntityID id2 = gEntityManager.addEntity(tmpl2).id; - gEM.begin(); + gEntityManager.begin(); - Entity* entity1 = gEM.getEntity(id1); - Entity* entity2 = gEM.getEntity(id2); + Entity* entity1 = gEntityManager.getEntity(id1); + Entity* entity2 = gEntityManager.getEntity(id2); assert(*entity1.getComponent!CInt == 1); assert(*entity2.getComponent!CInt == 1); - gEM.callEntitiesFunction!TestSystem(&func2); + gEntityManager.callEntitiesFunction!TestSystem(&func2); assert(*entity1.getComponent!CInt == 9); assert(*entity2.getComponent!CInt == 9); - gEM.callEntitiesFunction!TestSystem(&func1); + gEntityManager.callEntitiesFunction!TestSystem(&func1); assert(*entity1.getComponent!CInt == 13); assert(*entity2.getComponent!CInt == 13); - gEM.end(); + gEntityManager.end(); } @("SystemDependencies") @@ -1463,17 +1463,17 @@ unittest } } - gEM.beginRegister(); + gEntityManager.beginRegister(); - gEM.registerSystem!TestSystem(0); - gEM.registerSystem!TestSystem2(1); - gEM.registerSystem!TestSystem3(2); - gEM.registerSystem!TestSystem4(3); - gEM.registerSystem!TestSystem5(4); + gEntityManager.registerSystem!TestSystem(0); + gEntityManager.registerSystem!TestSystem2(1); + gEntityManager.registerSystem!TestSystem3(2); + gEntityManager.registerSystem!TestSystem4(3); + gEntityManager.registerSystem!TestSystem5(4); - gEM.endRegister(); + gEntityManager.endRegister(); - const (EntityManager.UpdatePass)* pass = gEM.getPass("update"); + const (EntityManager.UpdatePass)* pass = gEntityManager.getPass("update"); assert(pass != null); assert(pass.system_callers.length == 5); assert(pass.system_callers[0].system_id == becsID!TestSystem); @@ -1588,19 +1588,19 @@ unittest } } - gEM.beginRegister(); + gEntityManager.beginRegister(); - gEM.registerDependency(TestDependency); + gEntityManager.registerDependency(TestDependency); - gEM.registerSystem!TestSystem(0); - gEM.registerSystem!TestSystem2(1); - gEM.registerSystem!TestSystem3(2); - gEM.registerSystem!TestSystem4(3); - gEM.registerSystem!TestSystem5(4); + gEntityManager.registerSystem!TestSystem(0); + gEntityManager.registerSystem!TestSystem2(1); + gEntityManager.registerSystem!TestSystem3(2); + gEntityManager.registerSystem!TestSystem4(3); + gEntityManager.registerSystem!TestSystem5(4); - gEM.endRegister(); + gEntityManager.endRegister(); - const (EntityManager.UpdatePass)* pass = gEM.getPass("update"); + const (EntityManager.UpdatePass)* pass = gEntityManager.getPass("update"); assert(pass != null); assert(pass.system_callers.length == 5); assert(pass.system_callers[0].system_id == becsID!TestSystem); @@ -1686,40 +1686,40 @@ unittest uint updates = 0; } - gEM.beginRegister(); + gEntityManager.beginRegister(); - gEM.registerSystem!TestSystem(0); - gEM.registerSystem!TestSystem2(1); + gEntityManager.registerSystem!TestSystem(0); + gEntityManager.registerSystem!TestSystem2(1); - gEM.endRegister(); + gEntityManager.endRegister(); - EntityTemplate* tmpl_ = gEM.allocateTemplate([becsID!CInt, becsID!CLong, becsID!CFloat, becsID!CDouble].staticArray); - scope(exit)gEM.freeTemplate(tmpl_); - EntityTemplate* tmpl_2 = gEM.allocateTemplate([becsID!CInt, becsID!CFloat].staticArray); - scope(exit)gEM.freeTemplate(tmpl_2); - EntityTemplate* tmpl_3 = gEM.allocateTemplate([becsID!CLong, becsID!CDouble].staticArray); - scope(exit)gEM.freeTemplate(tmpl_3); - EntityTemplate* tmpl_4 = gEM.allocateTemplate([becsID!CInt, becsID!CLong, becsID!CDouble].staticArray); - scope(exit)gEM.freeTemplate(tmpl_4); - EntityTemplate* tmpl_5 = gEM.allocateTemplate([becsID!CInt, becsID!CDouble].staticArray); - scope(exit)gEM.freeTemplate(tmpl_5); - EntityTemplate* tmpl_6 = gEM.allocateTemplate([becsID!CDouble].staticArray); - scope(exit)gEM.freeTemplate(tmpl_6); + EntityTemplate* tmpl_ = gEntityManager.allocateTemplate([becsID!CInt, becsID!CLong, becsID!CFloat, becsID!CDouble].staticArray); + scope(exit)gEntityManager.freeTemplate(tmpl_); + EntityTemplate* tmpl_2 = gEntityManager.allocateTemplate([becsID!CInt, becsID!CFloat].staticArray); + scope(exit)gEntityManager.freeTemplate(tmpl_2); + EntityTemplate* tmpl_3 = gEntityManager.allocateTemplate([becsID!CLong, becsID!CDouble].staticArray); + scope(exit)gEntityManager.freeTemplate(tmpl_3); + EntityTemplate* tmpl_4 = gEntityManager.allocateTemplate([becsID!CInt, becsID!CLong, becsID!CDouble].staticArray); + scope(exit)gEntityManager.freeTemplate(tmpl_4); + EntityTemplate* tmpl_5 = gEntityManager.allocateTemplate([becsID!CInt, becsID!CDouble].staticArray); + scope(exit)gEntityManager.freeTemplate(tmpl_5); + EntityTemplate* tmpl_6 = gEntityManager.allocateTemplate([becsID!CDouble].staticArray); + scope(exit)gEntityManager.freeTemplate(tmpl_6); - gEM.addEntity(tmpl_); - gEM.addEntity(tmpl_2); - gEM.addEntity(tmpl_3); - gEM.addEntity(tmpl_4); - gEM.addEntity(tmpl_5); - gEM.addEntity(tmpl_6); + gEntityManager.addEntity(tmpl_); + gEntityManager.addEntity(tmpl_2); + gEntityManager.addEntity(tmpl_3); + gEntityManager.addEntity(tmpl_4); + gEntityManager.addEntity(tmpl_5); + gEntityManager.addEntity(tmpl_6); - TestSystem* test_system = gEM.getSystem!TestSystem; - TestSystem2* test_system2 = gEM.getSystem!TestSystem2; + TestSystem* test_system = gEntityManager.getSystem!TestSystem; + TestSystem2* test_system2 = gEntityManager.getSystem!TestSystem2; - gEM.begin(); - gEM.update(); - gEM.end(); + gEntityManager.begin(); + gEntityManager.update(); + gEntityManager.end(); assert(test_system.updates == 2); assert(test_system2.updates == 2); diff --git a/tests/bugs.d b/tests/bugs.d index 25f2ad1..3c5f426 100644 --- a/tests/bugs.d +++ b/tests/bugs.d @@ -45,23 +45,23 @@ unittest void onCreate() { - tmpl = gEM.allocateTemplate([becsID!CInt, becsID!CLong].staticArray); + tmpl = gEntityManager.allocateTemplate([becsID!CInt, becsID!CLong].staticArray); } void onDestroy() { - gEM.freeTemplate(tmpl); + gEntityManager.freeTemplate(tmpl); } void handleEvent(Entity* entity, Event1 event) { - gEM.removeEntity(event.id); - gEM.sendEvent(entity.id,Event2()); + gEntityManager.removeEntity(event.id); + gEntityManager.sendEvent(entity.id,Event2()); } void handleEvent(Entity* entity, Event2 event) { - id = gEM.addEntity(tmpl).id; + id = gEntityManager.addEntity(tmpl).id; } } @@ -94,49 +94,49 @@ unittest ///remove every entity void onUpdate(EntitiesData data) { - foreach(i;0..data.length)gEM.removeEntity(data.entity[i].id); + foreach(i;0..data.length)gEntityManager.removeEntity(data.entity[i].id); } } - gEM.initialize(0); + gEntityManager.initialize(0); - gEM.beginRegister(); + gEntityManager.beginRegister(); - gEM.registerComponent!CInt; - gEM.registerComponent!CFloat; - gEM.registerComponent!CDouble; - gEM.registerComponent!CLong; - gEM.registerComponent!CShort; - gEM.registerComponent!CFlag; + gEntityManager.registerComponent!CInt; + gEntityManager.registerComponent!CFloat; + gEntityManager.registerComponent!CDouble; + gEntityManager.registerComponent!CLong; + gEntityManager.registerComponent!CShort; + gEntityManager.registerComponent!CFlag; - gEM.registerEvent!Event1; - gEM.registerEvent!Event2; + gEntityManager.registerEvent!Event1; + gEntityManager.registerEvent!Event2; - gEM.registerSystem!System1(0); - gEM.registerSystem!System2(-200); - gEM.registerSystem!System3(-200); + gEntityManager.registerSystem!System1(0); + gEntityManager.registerSystem!System2(-200); + gEntityManager.registerSystem!System3(-200); - gEM.endRegister(); + gEntityManager.endRegister(); - EntityTemplate* tmpl = gEM.allocateTemplate([becsID!CInt, becsID!CLong].staticArray); - EntityID id = gEM.addEntity(tmpl,[CLong(10).ref_, CInt(6).ref_].staticArray).id; - EntityID id2 = gEM.addEntity(tmpl,[CInt(4).ref_].staticArray).id; - gEM.freeTemplate(tmpl); - gEM.commit(); + EntityTemplate* tmpl = gEntityManager.allocateTemplate([becsID!CInt, becsID!CLong].staticArray); + EntityID id = gEntityManager.addEntity(tmpl,[CLong(10).ref_, CInt(6).ref_].staticArray).id; + EntityID id2 = gEntityManager.addEntity(tmpl,[CInt(4).ref_].staticArray).id; + gEntityManager.freeTemplate(tmpl); + gEntityManager.commit(); - gEM.sendEvent(id2, Event1(id)); + gEntityManager.sendEvent(id2, Event1(id)); - gEM.getSystem(becsID!System2).disable(); + gEntityManager.getSystem(becsID!System2).disable(); - gEM.begin(); - gEM.update(); - gEM.end(); + gEntityManager.begin(); + gEntityManager.update(); + gEntityManager.end(); - gEM.getSystem(becsID!System2).enable(); + gEntityManager.getSystem(becsID!System2).enable(); - gEM.begin(); - gEM.update(); - gEM.end(); + gEntityManager.begin(); + gEntityManager.update(); + gEntityManager.end(); - gEM.destroy(); + gEntityManager.destroy(); } \ No newline at end of file diff --git a/tests/perf.d b/tests/perf.d index cc6be94..695b46e 100644 --- a/tests/perf.d +++ b/tests/perf.d @@ -63,123 +63,123 @@ EntityTemplate* tmpl; void beforeEveryTest() { - gEM.initialize(0); + gEntityManager.initialize(0); - gEM.beginRegister(); + gEntityManager.beginRegister(); - gEM.registerComponent!CLong; - gEM.registerComponent!CShort; - gEM.registerComponent!CInt; - gEM.registerComponent!CUInt; - gEM.registerComponent!CBig; + gEntityManager.registerComponent!CLong; + gEntityManager.registerComponent!CShort; + gEntityManager.registerComponent!CInt; + gEntityManager.registerComponent!CUInt; + gEntityManager.registerComponent!CBig; - gEM.endRegister(); + gEntityManager.endRegister(); tmpl = null; } void afterEveryTest() { - if(tmpl)gEM.freeTemplate(tmpl); + if(tmpl)gEntityManager.freeTemplate(tmpl); tmpl = null; - gEM.destroy(); + gEntityManager.destroy(); } void smallTmpl() { - tmpl = gEM.allocateTemplate([becsID!CShort].staticArray); + tmpl = gEntityManager.allocateTemplate([becsID!CShort].staticArray); } void bigTmpl() { - tmpl = gEM.allocateTemplate([becsID!CBig].staticArray); + tmpl = gEntityManager.allocateTemplate([becsID!CBig].staticArray); } void multiSmallTmpl() { - tmpl = gEM.allocateTemplate([becsID!CShort, becsID!CLong, becsID!CInt, becsID!CUInt].staticArray); + tmpl = gEntityManager.allocateTemplate([becsID!CShort, becsID!CLong, becsID!CInt, becsID!CUInt].staticArray); } void multiBigTmpl() { - tmpl = gEM.allocateTemplate([becsID!CLong, becsID!CInt, becsID!CUInt, becsID!CBig].staticArray); + tmpl = gEntityManager.allocateTemplate([becsID!CLong, becsID!CInt, becsID!CUInt, becsID!CBig].staticArray); } @("AddEntities100k1comp2b") @(before, &smallTmpl) unittest { - foreach(i; 0..100_000)gEM.addEntity(tmpl); + foreach(i; 0..100_000)gEntityManager.addEntity(tmpl); } @("AddEntities100k1comp128b") @(before, &bigTmpl) unittest { - foreach(i; 0..100_000)gEM.addEntity(tmpl); + foreach(i; 0..100_000)gEntityManager.addEntity(tmpl); } @("AddEntities100k4comp18b") @(before, &multiSmallTmpl) unittest { - foreach(i; 0..100_000)gEM.addEntity(tmpl); + foreach(i; 0..100_000)gEntityManager.addEntity(tmpl); } @("AddEntities100k4comp144b") @(before, &multiBigTmpl) unittest { - foreach(i; 0..100_000)gEM.addEntity(tmpl); + foreach(i; 0..100_000)gEntityManager.addEntity(tmpl); } void allocDealloc100k() { - foreach(i; 0..100_000)gEM.addEntity(tmpl); - gEM.commit(); - foreach(i; 0..100_000)gEM.removeEntity(EntityID(i + 1,0)); - gEM.commit(); + foreach(i; 0..100_000)gEntityManager.addEntity(tmpl); + gEntityManager.commit(); + foreach(i; 0..100_000)gEntityManager.removeEntity(EntityID(i + 1,0)); + gEntityManager.commit(); } void smallTmplPreAlloc() { - tmpl = gEM.allocateTemplate([becsID!CShort].staticArray); + tmpl = gEntityManager.allocateTemplate([becsID!CShort].staticArray); allocDealloc100k(); } void bigTmplPreAlloc() { - tmpl = gEM.allocateTemplate([becsID!CBig].staticArray); + tmpl = gEntityManager.allocateTemplate([becsID!CBig].staticArray); allocDealloc100k(); } void multiSmallTmplPreAlloc() { - tmpl = gEM.allocateTemplate([becsID!CShort, becsID!CLong, becsID!CInt, becsID!CUInt].staticArray); + tmpl = gEntityManager.allocateTemplate([becsID!CShort, becsID!CLong, becsID!CInt, becsID!CUInt].staticArray); allocDealloc100k(); } void multiBigTmplPreAlloc() { - tmpl = gEM.allocateTemplate([becsID!CLong, becsID!CInt, becsID!CUInt, becsID!CBig].staticArray); + tmpl = gEntityManager.allocateTemplate([becsID!CLong, becsID!CInt, becsID!CUInt, becsID!CBig].staticArray); allocDealloc100k(); } @("AddEntities100k1comp2bPreAlloc") @(before, &smallTmplPreAlloc) unittest { - foreach(i; 0..100_000)gEM.addEntity(tmpl); + foreach(i; 0..100_000)gEntityManager.addEntity(tmpl); } @("AddEntities100k1comp128bPreAlloc") @(before, &bigTmplPreAlloc) unittest { - foreach(i; 0..100_000)gEM.addEntity(tmpl); + foreach(i; 0..100_000)gEntityManager.addEntity(tmpl); } @("AddEntities100k4comp18bPreAlloc") @(before, &multiSmallTmplPreAlloc) unittest { - foreach(i; 0..100_000)gEM.addEntity(tmpl); + foreach(i; 0..100_000)gEntityManager.addEntity(tmpl); } @("AddEntities100k4comp144bPreAlloc") @(before, &multiBigTmplPreAlloc) unittest { - foreach(i; 0..100_000)gEM.addEntity(tmpl); + foreach(i; 0..100_000)gEntityManager.addEntity(tmpl); } \ No newline at end of file diff --git a/tests/tests.d b/tests/tests.d index f82519d..164eb30 100644 --- a/tests/tests.d +++ b/tests/tests.d @@ -226,7 +226,7 @@ struct EverySystem { foreach(i;0..data.length) { - gEM.removeEntity(data.entity[i].id); + gEntityManager.removeEntity(data.entity[i].id); } } @@ -234,7 +234,7 @@ struct EverySystem { foreach(i;0..data.length) { - gEM.addComponents(data.entity[i].id, TestComp2()); + gEntityManager.addComponents(data.entity[i].id, TestComp2()); } } } @@ -566,7 +566,7 @@ struct TestSystem2 test.bg = event.a; TestEvent2 event2; event2.a = event.a + 8; - gEM.sendEvent(entity.id, event2); + gEntityManager.sendEvent(entity.id, event2); } void handleEvent(Entity* entity, TestEvent2 event) @@ -601,12 +601,12 @@ struct TestSystem2 data.test[i].gg += 14; TestEvent event; event.a = data.test[i].gg + 4; - gEM.sendEvent(data.entity[i].id, event); //*/ + gEntityManager.sendEvent(data.entity[i].id, event); //*/ /*TestEvent2 event2; event2.a = data.test[i].gg + 8; - gEM.sendEvent(data.entity[i].id, event2);//*/ - //gEM.sendEvent!(TestEvent)(data.entity[i].id, event); - //gEM.sendSelfEvent!(TestEvent)(data.entity[i].id, TestEvent()); + gEntityManager.sendEvent(data.entity[i].id, event2);//*/ + //gEntityManager.sendEvent!(TestEvent)(data.entity[i].id, event); + //gEntityManager.sendSelfEvent!(TestEvent)(data.entity[i].id, TestEvent()); } } @@ -615,7 +615,7 @@ struct TestSystem2 foreach (i; 0 .. data.test.length) { data.test[i].gg -= 1; - //gEM.sendSelfEvent!(TestEvent)(data.entity[i].id, TestEvent()); + //gEntityManager.sendSelfEvent!(TestEvent)(data.entity[i].id, TestEvent()); } } @@ -686,25 +686,25 @@ else: EntityManager.initialize(1); - //gEM.setJobDispachFunc(&dispatch); - gEM.setMultithreadingCallbacks(&dispatch, &getID); - //assert(gEM !is null); + //gEntityManager.setJobDispachFunc(&dispatch); + gEntityManager.setMultithreadingCallbacks(&dispatch, &getID); + //assert(gEntityManager !is null); - gEM.beginRegister(); - gEM.registerPass("fixed"); + gEntityManager.beginRegister(); + gEntityManager.registerPass("fixed"); //MonoTime time = MonoTime.currTime; long time = Time.getUSecTime(); - gEM.registerComponent!TestComp2; - gEM.registerComponent!TestComp4; - gEM.registerComponent!TestComp; - gEM.registerComponent!TestComp3; - gEM.registerComponent!TestComp5; - gEM.registerComponent!CPosition; + gEntityManager.registerComponent!TestComp2; + gEntityManager.registerComponent!TestComp4; + gEntityManager.registerComponent!TestComp; + gEntityManager.registerComponent!TestComp3; + gEntityManager.registerComponent!TestComp5; + gEntityManager.registerComponent!CPosition; - gEM.registerEvent!TestEvent; - gEM.registerEvent!TestEvent2; + gEntityManager.registerEvent!TestEvent; + gEntityManager.registerEvent!TestEvent2; /*ulong dur = (MonoTime.currTime - time).total!"usecs"; //writeln("Components register: ", dur, " usecs"); @@ -714,19 +714,19 @@ else: printf("Components register: %f usecs\n", cast(float)(Time.getUSecTime() - time)); time = Time.getUSecTime(); - gEM.registerSystem!TestSystemWithHighPriority(100, "fixed"); - gEM.registerSystem!TestSystem(0); - gEM.registerSystem!ChangeTestSystem(0); - gEM.registerSystem!Sys1(10); - gEM.registerSystem!Sys2(-100); - gEM.registerSystem!Sys3(-2); - gEM.registerSystem!EmptySystem(2); - gEM.registerSystem!EmptyEventSystem(2); - gEM.registerSystem!EventSystem(2); - gEM.registerSystem!EverySystem(0); - //gEM.registerSystem!TestSystemWithHighPriority(100); - //gEM.registerSystem!TestSystem2(0); - gEM.endRegister(); + gEntityManager.registerSystem!TestSystemWithHighPriority(100, "fixed"); + gEntityManager.registerSystem!TestSystem(0); + gEntityManager.registerSystem!ChangeTestSystem(0); + gEntityManager.registerSystem!Sys1(10); + gEntityManager.registerSystem!Sys2(-100); + gEntityManager.registerSystem!Sys3(-2); + gEntityManager.registerSystem!EmptySystem(2); + gEntityManager.registerSystem!EmptyEventSystem(2); + gEntityManager.registerSystem!EventSystem(2); + gEntityManager.registerSystem!EverySystem(0); + //gEntityManager.registerSystem!TestSystemWithHighPriority(100); + //gEntityManager.registerSystem!TestSystem2(0); + gEntityManager.endRegister(); /*dur = (MonoTime.currTime - time).total!"usecs"; //writeln("Systems register: ", dur, " usecs"); @@ -737,11 +737,11 @@ else: //ushort[3] ids = [becsID!TestComp2, becsID!TestComp, becsID!TestComp4]; ushort[2] ids = [becsID!TestComp2, becsID!TestComp]; - EntityTemplate* tmpl = gEM.allocateTemplate(ids); + EntityTemplate* tmpl = gEntityManager.allocateTemplate(ids); //ushort[3] ids2 = [becsID!TestComp3, becsID!TestComp, becsID!TestComp4]; ushort[2] ids2 = [becsID!TestComp3, becsID!TestComp]; - EntityTemplate* tmpl2 = gEM.allocateTemplate(ids2); + EntityTemplate* tmpl2 = gEntityManager.allocateTemplate(ids2); ////writeln(tmpl.info.components[]); //*cast(EntityID*) tmpl.entity_data.ptr = EntityID(1, 1); @@ -752,67 +752,67 @@ else: time = Time.getUSecTime(); ushort[1] empty_ids = [becsID!CPosition]; - EntityTemplate* tmpl_empty = gEM.allocateTemplate(empty_ids); + EntityTemplate* tmpl_empty = gEntityManager.allocateTemplate(empty_ids); - gEM.commit(); + gEntityManager.commit(); time = Time.getUSecTime(); - foreach(i;0..4_000_000)gEM.addEntity(tmpl_empty); - gEM.commit(); - foreach(i;0..4_000_000)gEM.addEntity(tmpl_empty); - gEM.commit(); - foreach(i;0..2_000_000)gEM.addEntity(tmpl_empty); - gEM.commit(); + foreach(i;0..4_000_000)gEntityManager.addEntity(tmpl_empty); + gEntityManager.commit(); + foreach(i;0..4_000_000)gEntityManager.addEntity(tmpl_empty); + gEntityManager.commit(); + foreach(i;0..2_000_000)gEntityManager.addEntity(tmpl_empty); + gEntityManager.commit(); printf("Adding 1M entities: %f usecs\n", cast(float)(Time.getUSecTime() - time)); - gEM.commit(); + gEntityManager.commit(); time = Time.getUSecTime(); - gEM.callEntitiesFunction!EverySystem(&gEM.getSystem!EverySystem().iterate); + gEntityManager.callEntitiesFunction!EverySystem(&gEntityManager.getSystem!EverySystem().iterate); printf("Iterate 1M entities: %f usecs\n", cast(float)(Time.getUSecTime() - time)); - gEM.begin(); + gEntityManager.begin(); time = Time.getUSecTime(); - gEM.update(); + gEntityManager.update(); printf("Iterate 1M entities (update): %f usecs\n", cast(float)(Time.getUSecTime() - time)); - gEM.end(); + gEntityManager.end(); time = Time.getUSecTime(); - gEM.callEntitiesFunction!EverySystem(&gEM.getSystem!EverySystem().free); - gEM.commit(); + gEntityManager.callEntitiesFunction!EverySystem(&gEntityManager.getSystem!EverySystem().free); + gEntityManager.commit(); printf("Deleting 1M entities: %f usecs\n", cast(float)(Time.getUSecTime() - time)); time = Time.getUSecTime(); - foreach(i;0..4_000_000)gEM.addEntity(tmpl_empty); - gEM.commit(); - foreach(i;0..4_000_000)gEM.addEntity(tmpl_empty); - gEM.commit(); - foreach(i;0..2_000_000)gEM.addEntity(tmpl_empty); - gEM.commit(); + foreach(i;0..4_000_000)gEntityManager.addEntity(tmpl_empty); + gEntityManager.commit(); + foreach(i;0..4_000_000)gEntityManager.addEntity(tmpl_empty); + gEntityManager.commit(); + foreach(i;0..2_000_000)gEntityManager.addEntity(tmpl_empty); + gEntityManager.commit(); printf("Adding 1M entities (prealloc): %f usecs\n", cast(float)(Time.getUSecTime() - time)); - gEM.commit(); + gEntityManager.commit(); time = Time.getUSecTime(); - gEM.callEntitiesFunction!EverySystem(&gEM.getSystem!EverySystem().addOne); - gEM.commit(); + gEntityManager.callEntitiesFunction!EverySystem(&gEntityManager.getSystem!EverySystem().addOne); + gEntityManager.commit(); printf("Adding 1M component: %f usecs\n", cast(float)(Time.getUSecTime() - time)); - gEM.commit(); - gEM.callEntitiesFunction!EverySystem(&gEM.getSystem!EverySystem().free); - gEM.commit(); + gEntityManager.commit(); + gEntityManager.callEntitiesFunction!EverySystem(&gEntityManager.getSystem!EverySystem().free); + gEntityManager.commit(); time = Time.getUSecTime(); EntityID entity; { - entity = gEM.addEntity(tmpl).id; - writeEntityComponents(gEM.getEntity(entity)); - EntityManager.EntitiesBlock* block = EntityManager.instance.getMetaData( - gEM.getEntity(entity)); + entity = gEntityManager.addEntity(tmpl).id; + writeEntityComponents(gEntityManager.getEntity(entity)); + EntityManager.EntitiesBlock* block = gEntityManager.getMetaData( + gEntityManager.getEntity(entity)); EntityManager.EntityInfo* info = block.type_info; //writeln(info.add_listeners); //if(info)assert(0); @@ -821,9 +821,9 @@ else: //time = MonoTime.currTime; time = Time.getUSecTime(); - //foreach(i; 0..1_000_000)gEM.addEntity(tmpl); + //foreach(i; 0..1_000_000)gEntityManager.addEntity(tmpl); - //foreach(i; 0..1_000_000)gEM.removeEntity(gEM.addEntity(tmpl).id); + //foreach(i; 0..1_000_000)gEntityManager.removeEntity(gEntityManager.addEntity(tmpl).id); import bubel.ecs.std; @@ -832,14 +832,14 @@ else: foreach (i; 0 .. 200) { - gEM.begin(); + gEntityManager.begin(); foreach (j; 0 .. 5_000) - idss[j] = gEM.addEntity(tmpl).id; + idss[j] = gEntityManager.addEntity(tmpl).id; foreach (j; 0 .. 5_000) - gEM.removeEntity(idss[j]); - gEM.end(); + gEntityManager.removeEntity(idss[j]); + gEntityManager.end(); } - gEM.commit(); + gEntityManager.commit(); //dur = (MonoTime.currTime - time).total!"usecs"; //writeln("Entities adding: ", dur, " usecs"); @@ -847,7 +847,7 @@ else: time = Time.getUSecTime(); uint blocks = 0; - foreach (info; &gEM.entities_infos.byValue) + foreach (info; &gEntityManager.entities_infos.byValue) { EntityManager.EntitiesBlock* block = info.first_block; while (block !is null) @@ -859,13 +859,13 @@ else: //writeln("Entities blocks: ", blocks); printf("Entities blocks: %u\n", blocks); - //foreach(j; 0..1_000)gEM.addEntity(tmpl); + //foreach(j; 0..1_000)gEntityManager.addEntity(tmpl); - gEM.beginRegister(); - gEM.registerSystem!TestSystem2(0); - gEM.endRegister(); + gEntityManager.beginRegister(); + gEntityManager.registerSystem!TestSystem2(0); + gEntityManager.endRegister(); - //gEM.generateDependencies(); + //gEntityManager.generateDependencies(); //assert(*(cast(EntityID*)(cast(void*)tmpl.info.first_block+24)) == EntityID(1,1)); //assert(*(cast(EntityID*)(cast(void*)tmpl.info.first_block+48)) == EntityID(1,1)); @@ -878,12 +878,12 @@ else: EntityID[] entities = Mallocator.makeArray!EntityID(1_000_000); foreach (i; 0 .. 500_000) { - entity2 = gEM.addEntity(tmpl).id; + entity2 = gEntityManager.addEntity(tmpl).id; entities[i * 2] = entity2; - entities[i * 2 + 1] = gEM.addEntity(tmpl2).id; + entities[i * 2 + 1] = gEntityManager.addEntity(tmpl2).id; } - gEM.commit(); + gEntityManager.commit(); //dur = (MonoTime.currTime - time).total!"usecs"; //writeln("Entities adding2: ", dur, " usecs"); @@ -893,12 +893,12 @@ else: foreach (i; 0 .. 1_000_000) { - EntityManager.instance.addComponents(entities[i], TestComp5()); + gEntityManager.addComponents(entities[i], TestComp5()); if ((i & 0x00FFFF) == 0) - gEM.commit(); + gEntityManager.commit(); } - gEM.commit(); + gEntityManager.commit(); //dur = (MonoTime.currTime - time).total!"usecs"; //writeln("Components adding: ", dur, " usecs"); @@ -908,11 +908,11 @@ else: foreach (i; 0 .. 1_000_000) { - EntityManager.instance.removeComponents!TestComp5(entities[i]); - //if((i & 0x00FFFF) == 0)gEM.commit(); + gEntityManager.removeComponents!TestComp5(entities[i]); + //if((i & 0x00FFFF) == 0)gEntityManager.commit(); } - gEM.commit(); + gEntityManager.commit(); //dur = (MonoTime.currTime - time).total!"usecs"; //writeln("Components removing: ", dur, " usecs"); printf("Components removing: %f usecs\n", cast(float)(Time.getUSecTime() - time)); @@ -923,102 +923,102 @@ else: //time = MonoTime.currTime; time = Time.getUSecTime(); - gEM.begin(); - //gEM.updateMT(); - gEM.update(); - gEM.end(); + gEntityManager.begin(); + //gEntityManager.updateMT(); + gEntityManager.update(); + gEntityManager.end(); //dur = (MonoTime.currTime - time).total!"usecs"; //writeln("Update: ", dur, " usecs"); printf("Update: %f usecs\n", cast(float)(Time.getUSecTime() - time)); - writeEntityComponents(gEM.getEntity(entity2)); + writeEntityComponents(gEntityManager.getEntity(entity2)); //time = MonoTime.currTime; time = Time.getUSecTime(); - gEM.begin(); - gEM.updateMT(); - //gEM.update(); - gEM.end(); + gEntityManager.begin(); + gEntityManager.updateMT(); + //gEntityManager.update(); + gEntityManager.end(); //dur = (MonoTime.currTime - time).total!"usecs"; //writeln("Update: ", dur, " usecs"); printf("Update: %f usecs\n", cast(float)(Time.getUSecTime() - time)); - writeEntityComponents(gEM.getEntity(entity2)); + writeEntityComponents(gEntityManager.getEntity(entity2)); //time = MonoTime.currTime; time = Time.getUSecTime(); - gEM.begin(); - gEM.updateMT(); - //gEM.update(); - gEM.end(); + gEntityManager.begin(); + gEntityManager.updateMT(); + //gEntityManager.update(); + gEntityManager.end(); //dur = (MonoTime.currTime - time).total!"usecs"; //writeln("Update: ", dur, " usecs"); printf("Update: %f usecs\n", cast(float)(Time.getUSecTime() - time)); - writeEntityComponents(gEM.getEntity(entity2)); + writeEntityComponents(gEntityManager.getEntity(entity2)); - entity = gEM.addEntity(tmpl).id; + entity = gEntityManager.addEntity(tmpl).id; - gEM.begin(); - gEM.update(); - gEM.end(); + gEntityManager.begin(); + gEntityManager.update(); + gEntityManager.end(); - //Entity* pp;// = gEM.getEntity(entity.id); + //Entity* pp;// = gEntityManager.getEntity(entity.id); ////writeln((cast(uint*) pp)[0 .. 14], " ", pp); - writeEntityComponents(gEM.getEntity(entity)); + writeEntityComponents(gEntityManager.getEntity(entity)); //writeln("Entity, its copy, and template, and default filled tempalte"); - gEM.addEntity(tmpl); - writeEntityComponents(gEM.getEntity(entity)); - writeEntityComponents(gEM.addEntityCopy(entity)); - EntityTemplate* copy_tempalte = gEM.allocateTemplate(entity); - writeEntityComponents(gEM.addEntity(copy_tempalte)); - EntityTemplate* copy_default_tempalte = gEM.allocateTemplate(entity, true); - writeEntityComponents(gEM.addEntity(copy_default_tempalte)); + gEntityManager.addEntity(tmpl); + writeEntityComponents(gEntityManager.getEntity(entity)); + writeEntityComponents(gEntityManager.addEntityCopy(entity)); + EntityTemplate* copy_tempalte = gEntityManager.allocateTemplate(entity); + writeEntityComponents(gEntityManager.addEntity(copy_tempalte)); + EntityTemplate* copy_default_tempalte = gEntityManager.allocateTemplate(entity, true); + writeEntityComponents(gEntityManager.addEntity(copy_default_tempalte)); - gEM.addComponents(entity, TestComp4()); - gEM.addComponents(entity, TestComp3()); + gEntityManager.addComponents(entity, TestComp4()); + gEntityManager.addComponents(entity, TestComp3()); - gEM.begin(); - gEM.update(); - gEM.end(); + gEntityManager.begin(); + gEntityManager.update(); + gEntityManager.end(); - writeEntityComponents(gEM.getEntity(entity)); + writeEntityComponents(gEntityManager.getEntity(entity)); - gEM.removeComponents!(TestComp)(entity); - gEM.addComponents(entity, TestComp()); - gEM.addComponents(entity, TestComp5()); + gEntityManager.removeComponents!(TestComp)(entity); + gEntityManager.addComponents(entity, TestComp()); + gEntityManager.addComponents(entity, TestComp5()); - gEM.begin(); - gEM.update(); - gEM.update("fixed"); - gEM.end(); + gEntityManager.begin(); + gEntityManager.update(); + gEntityManager.update("fixed"); + gEntityManager.end(); - gEM.removeComponents!(TestComp4)(entity); + gEntityManager.removeComponents!(TestComp4)(entity); - gEM.commit(); + gEntityManager.commit(); - System* sys = EntityManager.instance.getSystem(becsID!TestSystem2); + System* sys = gEntityManager.getSystem(becsID!TestSystem2); ExternalUpdateCallTest external_update_test; - EntityManager.instance.callEntitiesFunction!TestSystem2(&external_update_test.update); + gEntityManager.callEntitiesFunction!TestSystem2(&external_update_test.update); printf("pre end\n"); - writeEntityComponents(gEM.getEntity(entity)); + writeEntityComponents(gEntityManager.getEntity(entity)); //import std.stdio; ////writeln((cast(uint*)tmpl.info.first_block)[0..48]); - gEM.freeTemplate(tmpl_empty); - gEM.freeTemplate(tmpl); - gEM.freeTemplate(tmpl2); - gEM.freeTemplate(copy_tempalte); - gEM.freeTemplate(copy_default_tempalte); + gEntityManager.freeTemplate(tmpl_empty); + gEntityManager.freeTemplate(tmpl); + gEntityManager.freeTemplate(tmpl2); + gEntityManager.freeTemplate(copy_tempalte); + gEntityManager.freeTemplate(copy_default_tempalte); EntityManager.destroy(); Mallocator.dispose(idss); From 27154c809e190707bd8864b65996a626603611a9 Mon Sep 17 00:00:00 2001 From: Mergul Date: Tue, 2 Mar 2021 21:05:05 +0100 Subject: [PATCH 183/217] -removed launcher.manager (gEntityManager used instead) -removed somee comments, unneded code -added some comments/documentation --- demos/source/app.d | 66 ++-- demos/source/demos/brick_breaker.d | 95 +++--- demos/source/demos/particles.d | 201 +++-------- demos/source/demos/sandbox.d | 16 +- demos/source/demos/simple.d | 89 +++-- demos/source/demos/snake.d | 123 +++---- demos/source/demos/space_invaders.d | 482 ++++++++++++--------------- demos/source/game_core/basic.d | 61 ++-- demos/source/game_core/job_updater.d | 130 ++++---- demos/source/gui/manager.d | 8 +- 10 files changed, 583 insertions(+), 688 deletions(-) diff --git a/demos/source/app.d b/demos/source/app.d index 2c324ec..6f2322b 100644 --- a/demos/source/app.d +++ b/demos/source/app.d @@ -58,7 +58,6 @@ struct Launcher ImGuiContext* context; SDL_Window* window; SDL_GLContext gl_context; - EntityManager* manager; /*bool function() loop; void function() end; void function(SDL_Event*) event;*/ @@ -126,19 +125,19 @@ struct Launcher gui_manager.clear(); //launcher.ent - manager.begin(); - manager.update("clean"); - manager.end(); + gEntityManager.begin(); + gEntityManager.update("clean"); + gEntityManager.end(); if(this.demo.deinitialize)this.demo.deinitialize(); - foreach(ref system; manager.systems) + foreach(ref system; gEntityManager.systems) { if(system.id != becsID!CountSystem && system.id != becsID!CleanSystem)system.disable(); } - /*launcher.manager.getSystem(becsID!CountSystem).enable(); - launcher.manager.getSystem(becsID!CleanSystem).enable();//*/ + /*gEntityManager.getSystem(becsID!CountSystem).enable(); + gEntityManager.getSystem(becsID!CleanSystem).enable();//*/ if(callbacks.register)callbacks.register(); if(callbacks.initialize)callbacks.initialize(); @@ -271,11 +270,11 @@ struct Launcher //else if(position.y > 299)position.y = 299; *location = position; } - manager.addEntity(tmpl); + gEntityManager.addEntity(tmpl); } else { - manager.callEntitiesFunction!IteratorSystem(&iterator.removeEntity); + gEntityManager.callEntitiesFunction!IteratorSystem(&iterator.removeEntity); } break; case Tool.component_manipulator: @@ -289,21 +288,21 @@ struct Launcher { ushort[1] rcomps = [gui_manager.getSelectedComponent().component_id]; iterator.rem_comps = rcomps; - manager.callEntitiesFunction!IteratorSystem(&iterator.overrideComponent); + gEntityManager.callEntitiesFunction!IteratorSystem(&iterator.overrideComponent); } - else manager.callEntitiesFunction!IteratorSystem(&iterator.addComponent); + else gEntityManager.callEntitiesFunction!IteratorSystem(&iterator.addComponent); } else { ushort[1] comps = [gui_manager.getSelectedComponent().component_id]; iterator.rem_comps = comps; - manager.callEntitiesFunction!IteratorSystem(&iterator.removeComponent); + gEntityManager.callEntitiesFunction!IteratorSystem(&iterator.removeComponent); } } break; case Tool.selector: iterator.distance = size2; - manager.callEntitiesFunction!IteratorSystem(&iterator.selectEntity); + gEntityManager.callEntitiesFunction!IteratorSystem(&iterator.selectEntity); break; default: break; @@ -369,7 +368,7 @@ struct CleanSystem { foreach(i; 0..data.length) { - launcher.manager.removeEntity(data.entities[i].id); + gEntityManager.removeEntity(data.entities[i].id); } } } @@ -878,9 +877,9 @@ void mainLoop(void* arg) //igEndChildFrame(); if(igButton("Clear",ImVec2(-1,0))) { - launcher.manager.begin(); - launcher.manager.update("clean"); - launcher.manager.end(); + gEntityManager.begin(); + gEntityManager.update("clean"); + gEntityManager.end(); } } igEnd(); @@ -1016,10 +1015,11 @@ void mainLoop(void* arg) } else { - launcher.manager.begin(); + gEntityManager.begin(); import game_core.rendering; - launcher.manager.callEntitiesFunction!DrawSystem(&(launcher.manager.getSystem!DrawSystem).onUpdate); - launcher.manager.end(); + DrawSystem* draw_system = gEntityManager.getSystem!DrawSystem; + gEntityManager.callEntitiesFunction!DrawSystem(&draw_system.onUpdate); + gEntityManager.end(); } launcher.job_updater.pool.tryWaitCount = 0; @@ -1104,8 +1104,8 @@ void quit() if(launcher.demo.deinitialize)launcher.demo.deinitialize(); - launcher.manager.destroy(); - launcher.manager = null; + gEntityManager.destroy(); + gEntityManager = null; TexCoordsManager.destroy(); @@ -1231,23 +1231,23 @@ int app_main(int argc, char** argv) //launcher.job_updater.onCreate(); EntityManager.initialize(32, 1<<16); - launcher.manager = gEntityManager; + //gEntityManager = gEntityManager; - //launcher.manager.m_thread_id_func = &launcher.job_updater.getThreadID; - //launcher.manager.setJobDispachFunc(&launcher.job_updater.dispatch); - launcher.manager.setMultithreadingCallbacks(&launcher.job_updater.dispatch, &launcher.job_updater.getThreadID); + //gEntityManager.m_thread_id_func = &launcher.job_updater.getThreadID; + //gEntityManager.setJobDispachFunc(&launcher.job_updater.dispatch); + gEntityManager.setMultithreadingCallbacks(&launcher.job_updater.dispatch, &launcher.job_updater.getThreadID); - launcher.manager.beginRegister(); + gEntityManager.beginRegister(); - launcher.manager.registerPass("clean"); + gEntityManager.registerPass("clean"); - launcher.manager.registerComponent!CLocation; + gEntityManager.registerComponent!CLocation; - launcher.manager.registerSystem!CountSystem(10000); - launcher.manager.registerSystem!CleanSystem(0,"clean"); - launcher.manager.registerSystem!IteratorSystem(0,"clean"); + gEntityManager.registerSystem!CountSystem(10000); + gEntityManager.registerSystem!CleanSystem(0,"clean"); + gEntityManager.registerSystem!IteratorSystem(0,"clean"); - launcher.manager.endRegister(); + gEntityManager.endRegister(); loadGFX(); diff --git a/demos/source/demos/brick_breaker.d b/demos/source/demos/brick_breaker.d index 51e213c..05e31f7 100644 --- a/demos/source/demos/brick_breaker.d +++ b/demos/source/demos/brick_breaker.d @@ -193,7 +193,7 @@ struct BallCollisionSystem bool test(EntityID id) { if(id == data.entity[i].id)return true; - Entity* entity = launcher.manager.getEntity(id); + Entity* entity = gEntityManager.getEntity(id); if(entity) { CLocation* location = entity.getComponent!CLocation; @@ -224,7 +224,7 @@ struct BallCollisionSystem { vector = vector / sqrtf(pow_dist); data.velocity[i] = data.velocity[i] - vector * (2 * dot(vector, data.velocity[i])); - launcher.manager.sendEvent(id,EDamage(1)); + gEntityManager.sendEvent(id,EDamage(1)); return cast(bool)(hits--); } } @@ -243,35 +243,20 @@ struct BallCollisionSystem bool onBegin() { - //grid = launcher.manager.getSystem!ShootGridManager().grid; - tree = launcher.manager.getSystem!BVHBuilder().tree; - static_tree = launcher.manager.getSystem!StaticBVHBuilder().tree; - //if(grid is null)return false; + tree = gEntityManager.getSystem!BVHBuilder().tree; + static_tree = gEntityManager.getSystem!StaticBVHBuilder().tree; if(tree is null || static_tree is null)return false; else return true; } void onUpdate(EntitiesData data) { - // State state; - // state.data = data; - // EntityID id; - // foreach(i; 0..data.length) - // { - // state.i = i; - // float radius = data.scale[i].x; - // if(grid.test(id, data.location[i] - radius, data.location[i] + radius, ubyte.max)) - // { - // state.test(id); - // } - // } State state; state.data = data; foreach(i; 0..data.length) { state.i = i; state.hits = 1; - //float radius = data.scale[i].x; AABB bounding = AABB(data.location[i]-data.scale[i], data.location[i]+data.scale[i]); tree.test(bounding, cast(bool delegate(EntityID id))&state.test); static_tree.test(bounding, cast(bool delegate(EntityID id))&state.test); @@ -298,7 +283,7 @@ struct DamageSystem EntityMeta meta = entity.getMeta(); CHitPoints* hp = meta.getComponent!CHitPoints; hp.value -= event.damage; - if(hp.value < 0)launcher.manager.removeEntity(entity.id); + if(hp.value < 0)gEntityManager.removeEntity(entity.id); } } @@ -328,46 +313,46 @@ void brickBreakerRegister() demo.texture.create(); demo.texture.load("assets/textures/atlas.png"); - launcher.manager.beginRegister(); + gEntityManager.beginRegister(); - registerRenderingModule(launcher.manager); - registerCollisionModule(launcher.manager); + registerRenderingModule(gEntityManager); + registerCollisionModule(gEntityManager); - launcher.manager.registerComponent!CLocation; - launcher.manager.registerComponent!CRotation; - launcher.manager.registerComponent!CScale; - launcher.manager.registerComponent!CTexCoords; - launcher.manager.registerComponent!CTexCoordsIndex; - launcher.manager.registerComponent!CVelocity; - launcher.manager.registerComponent!CInput; - launcher.manager.registerComponent!CPaddle; - launcher.manager.registerComponent!CDamping; - launcher.manager.registerComponent!CVelocityFactor; - launcher.manager.registerComponent!CBall; - launcher.manager.registerComponent!CHitPoints; + gEntityManager.registerComponent!CLocation; + gEntityManager.registerComponent!CRotation; + gEntityManager.registerComponent!CScale; + gEntityManager.registerComponent!CTexCoords; + gEntityManager.registerComponent!CTexCoordsIndex; + gEntityManager.registerComponent!CVelocity; + gEntityManager.registerComponent!CInput; + gEntityManager.registerComponent!CPaddle; + gEntityManager.registerComponent!CDamping; + gEntityManager.registerComponent!CVelocityFactor; + gEntityManager.registerComponent!CBall; + gEntityManager.registerComponent!CHitPoints; - launcher.manager.registerEvent!EDamage; + gEntityManager.registerEvent!EDamage; - launcher.manager.registerSystem!MoveSystem(-100); - launcher.manager.registerSystem!EdgeCollisionSystem(-99); - launcher.manager.registerSystem!BallCollisionSystem(-79); - launcher.manager.registerSystem!InputMovementSystem(-120); - launcher.manager.registerSystem!DampingSystem(-120); - launcher.manager.registerSystem!DamageSystem(-120); + gEntityManager.registerSystem!MoveSystem(-100); + gEntityManager.registerSystem!EdgeCollisionSystem(-99); + gEntityManager.registerSystem!BallCollisionSystem(-79); + gEntityManager.registerSystem!InputMovementSystem(-120); + gEntityManager.registerSystem!DampingSystem(-120); + gEntityManager.registerSystem!DamageSystem(-120); - launcher.manager.endRegister(); + gEntityManager.endRegister(); } void brickBreakerStart() { - DrawSystem* draw_system = launcher.manager.getSystem!DrawSystem; + DrawSystem* draw_system = gEntityManager.getSystem!DrawSystem; draw_system.default_data.color = 0x80808080; draw_system.default_data.texture = demo.texture; draw_system.default_data.size = vec2(16,16); draw_system.default_data.coords = vec4(246,64,2,2)*px; draw_system.default_data.material_id = 0; - EntityTemplate* brick_tmpl = launcher.manager.allocateTemplate( + EntityTemplate* brick_tmpl = gEntityManager.allocateTemplate( [becsID!CLocation, becsID!CScale, becsID!CColor, becsID!CTexCoordsIndex, becsID!CBVH, becsID!CHitPoints, becsID!CAABB, becsID!CStatic].staticArray @@ -378,11 +363,11 @@ void brickBreakerStart() brick_tmpl.getComponent!CHitPoints().value = 2; //brick_tmpl.getComponent!CAABB().bounding = AABB(vec2(),vec2()); - EntityTemplate* big_brick_tmpl = launcher.manager.allocateTemplate(brick_tmpl); + EntityTemplate* big_brick_tmpl = gEntityManager.allocateTemplate(brick_tmpl); big_brick_tmpl.getComponent!CTexCoordsIndex().value = TexCoordsManager.instance.getCoordIndex(vec4(320,32,16,16)*px); big_brick_tmpl.getComponent!CScale().value = vec2(16,16); - EntityTemplate* paddle_tmpl = launcher.manager.allocateTemplate( + EntityTemplate* paddle_tmpl = gEntityManager.allocateTemplate( [becsID!CLocation, becsID!CScale, becsID!CInput, becsID!CTexCoordsIndex, becsID!CPaddle, becsID!CVelocity, becsID!CDamping, becsID!CVelocityFactor, becsID!CBVH, @@ -393,7 +378,7 @@ void brickBreakerStart() paddle_tmpl.getComponent!CDamping().value = 14; paddle_tmpl.getComponent!CVelocityFactor().value = vec2(1,0); - EntityTemplate* ball_tmpl = launcher.manager.allocateTemplate( + EntityTemplate* ball_tmpl = gEntityManager.allocateTemplate( [becsID!CLocation, becsID!CScale, //becsID!CDamping, becsID!CTexCoordsIndex, becsID!CBall, becsID!CVelocity].staticArray ); @@ -446,12 +431,12 @@ void brickBreakerStart() } foreach (j; 0..20) { - launcher.manager.addEntity(brick_tmpl,[CLocation(vec2(j*18,300-i*10)).ref_, color.ref_].staticArray); + gEntityManager.addEntity(brick_tmpl,[CLocation(vec2(j*18,300-i*10)).ref_, color.ref_].staticArray); } } - launcher.manager.addEntity(paddle_tmpl,[CLocation(vec2(190,20)).ref_].staticArray); - launcher.manager.addEntity(ball_tmpl,[CLocation(vec2(190,40)).ref_].staticArray); + gEntityManager.addEntity(paddle_tmpl,[CLocation(vec2(190,20)).ref_].staticArray); + gEntityManager.addEntity(ball_tmpl,[CLocation(vec2(190,40)).ref_].staticArray); } @@ -470,18 +455,18 @@ bool brickBreakerLoop() { launcher.render_position = (vec2(launcher.window_size.x,launcher.window_size.y)*launcher.scalling - vec2(400,300)) * 0.5; - launcher.manager.begin(); + gEntityManager.begin(); if(launcher.multithreading) { launcher.job_updater.begin(); - launcher.manager.updateMT(); + gEntityManager.updateMT(); launcher.job_updater.call(); } else { - launcher.manager.update(); + gEntityManager.update(); } - launcher.manager.end(); + gEntityManager.end(); return true; } diff --git a/demos/source/demos/particles.d b/demos/source/demos/particles.d index bbb68ee..963491c 100644 --- a/demos/source/demos/particles.d +++ b/demos/source/demos/particles.d @@ -116,74 +116,6 @@ struct CParticleLife /*####################################################################################################################### ------------------------------------------------ Systems ------------------------------------------------------------------ #######################################################################################################################*/ -/* -struct DrawSystem -{ - mixin ECS.System!32; - - struct EntitiesData - { - uint length; - //uint thread_id; - uint job_id; - //@readonly CTexCoords[] coords; - @readonly CLocation[] locations; - - @optional @readonly CColor[] color; - } - - void onUpdate(EntitiesData data) - { - if(launcher.renderer.prepared_items >= launcher.renderer.MaxObjects)return;//simple leave loop if max visible objects count was reached - import ecs_utils.gfx.renderer; - Renderer.DrawData draw_data; - draw_data.size = vec2(2,2); - draw_data.coords = vec4(246,64,2,2)*px; - draw_data.color = 0x80808080; - draw_data.material_id = 2; - draw_data.thread_id = data.job_id; - draw_data.texture = particles_demo.texture; - - if(!data.color) - { - foreach(i; 0..data.length) - { - draw_data.position = data.locations[i]; - launcher.renderer.draw(draw_data);//particles_demo.texture, data.locations[i], vec2(2,2), vec4(246,64,2,2)*px, 0, 0x80808080, 0, 2, 0, data.job_id); - } - } - else - { - foreach(i; 0..data.length) - { - draw_data.position = data.locations[i]; - draw_data.color = data.color[i].value; - launcher.renderer.draw(draw_data);//particles_demo.texture, data.locations[i], vec2(2,2), vec4(246,64,2,2)*px, 0, data.color[i].value, 0, 2, 0, data.job_id); - } - } - - } -}*/ - -// struct MoveSystem -// { -// mixin ECS.System!64; - -// struct EntitiesData -// { -// uint length; -// CLocation[] locations; -// @readonly CVelocity[] velocity; -// } - -// void onUpdate(EntitiesData data) -// { -// foreach(i; 0..data.length) -// { -// data.locations[i] += data.velocity[i] * launcher.deltaTime; -// } -// } -// } struct MouseAttractSystem { @@ -296,7 +228,7 @@ struct AttractSystem { Updater updater; updater.data = data; - launcher.manager.callEntitiesFunction!AttractorIterator(&updater.onUpdate); + gEntityManager.callEntitiesFunction!AttractorIterator(&updater.onUpdate); } } @@ -339,47 +271,14 @@ struct PlayAreaSystem { foreach(i; 0..data.length) { - if(data.locations[i].x > 440)launcher.manager.removeEntity(data.entity[i].id); - else if(data.locations[i].x < -40)launcher.manager.removeEntity(data.entity[i].id); - if(data.locations[i].y > 340)launcher.manager.removeEntity(data.entity[i].id); - else if(data.locations[i].y < -40)launcher.manager.removeEntity(data.entity[i].id); + if(data.locations[i].x > 440)gEntityManager.removeEntity(data.entity[i].id); + else if(data.locations[i].x < -40)gEntityManager.removeEntity(data.entity[i].id); + if(data.locations[i].y > 340)gEntityManager.removeEntity(data.entity[i].id); + else if(data.locations[i].y < -40)gEntityManager.removeEntity(data.entity[i].id); } } } -// struct DampingSystem -// { -// mixin ECS.System!32; - -// struct EntitiesData -// { -// uint length; -// const (Entity)[] entity; -// @readonly CDamping[] damping; -// CVelocity[] velocity; -// } - -// float[10] damp = 0; - -// bool onBegin() -// { -// foreach(i;0..10) -// { -// damp[i] = powf((0.99 - cast(float)i * 0.01),launcher.deltaTime*0.1); -// } - -// return true; -// } - -// void onUpdate(EntitiesData data) -// { -// foreach(i; 0..data.length) -// { -// data.velocity[i] = data.velocity[i] * damp[data.damping[i]]; -// } -// } -// } - struct ParticleLifeSystem { mixin ECS.System!32; @@ -404,7 +303,7 @@ struct ParticleLifeSystem foreach(i; 0..data.length) { data.life[i] -= delta_time; - if(data.life[i] < 0)launcher.manager.removeEntity(data.entity[i].id); + if(data.life[i] < 0)gEntityManager.removeEntity(data.entity[i].id); } } } @@ -452,45 +351,45 @@ void particlesRegister() particles_demo.texture.create(); particles_demo.texture.load("assets/textures/atlas.png"); - launcher.manager.beginRegister(); + gEntityManager.beginRegister(); - registerRenderingModule(launcher.manager); + registerRenderingModule(gEntityManager); - launcher.manager.registerComponent!CLocation; - //launcher.manager.registerComponent!CTexCoords; - launcher.manager.registerComponent!CColor; - launcher.manager.registerComponent!CVelocity; - launcher.manager.registerComponent!CScale; - launcher.manager.registerComponent!CTexCoords; - launcher.manager.registerComponent!CTexCoordsIndex; - launcher.manager.registerComponent!CRotation; - launcher.manager.registerComponent!CDepth; - launcher.manager.registerComponent!CAttractor; - launcher.manager.registerComponent!CDamping; - launcher.manager.registerComponent!CGravity; - launcher.manager.registerComponent!CVortex; - launcher.manager.registerComponent!CParticleLife; - launcher.manager.registerComponent!CForceRange; - launcher.manager.registerComponent!CMaterialIndex; - launcher.manager.registerComponent!CVelocityFactor; + gEntityManager.registerComponent!CLocation; + //gEntityManager.registerComponent!CTexCoords; + gEntityManager.registerComponent!CColor; + gEntityManager.registerComponent!CVelocity; + gEntityManager.registerComponent!CScale; + gEntityManager.registerComponent!CTexCoords; + gEntityManager.registerComponent!CTexCoordsIndex; + gEntityManager.registerComponent!CRotation; + gEntityManager.registerComponent!CDepth; + gEntityManager.registerComponent!CAttractor; + gEntityManager.registerComponent!CDamping; + gEntityManager.registerComponent!CGravity; + gEntityManager.registerComponent!CVortex; + gEntityManager.registerComponent!CParticleLife; + gEntityManager.registerComponent!CForceRange; + gEntityManager.registerComponent!CMaterialIndex; + gEntityManager.registerComponent!CVelocityFactor; - launcher.manager.registerSystem!MoveSystem(0); - launcher.manager.registerSystem!DrawSystem(100); - launcher.manager.registerSystem!PlayAreaSystem(102); - launcher.manager.registerSystem!AttractSystem(-1); - launcher.manager.registerSystem!MouseAttractSystem(1); - launcher.manager.registerSystem!DampingSystem(101); - launcher.manager.registerSystem!ParticleLifeSystem(-10); - launcher.manager.registerSystem!GravitySystem(-2); + gEntityManager.registerSystem!MoveSystem(0); + gEntityManager.registerSystem!DrawSystem(100); + gEntityManager.registerSystem!PlayAreaSystem(102); + gEntityManager.registerSystem!AttractSystem(-1); + gEntityManager.registerSystem!MouseAttractSystem(1); + gEntityManager.registerSystem!DampingSystem(101); + gEntityManager.registerSystem!ParticleLifeSystem(-10); + gEntityManager.registerSystem!GravitySystem(-2); - launcher.manager.registerSystem!AttractorIterator(-1); + gEntityManager.registerSystem!AttractorIterator(-1); - launcher.manager.endRegister(); + gEntityManager.endRegister(); } void particlesStart() { - DrawSystem* draw_system = launcher.manager.getSystem!DrawSystem; + DrawSystem* draw_system = gEntityManager.getSystem!DrawSystem; draw_system.default_data.size = vec2(2,2); draw_system.default_data.coords = vec4(246,64,2,2)*px; draw_system.default_data.material_id = 2; @@ -518,32 +417,32 @@ void particlesStart() launcher.gui_manager.addComponent(CGravity(),"Gravity"); EntityTemplate* tmpl; - EntityTemplate* base_tmpl = launcher.manager.allocateTemplate([becsID!CTexCoords, becsID!CLocation, becsID!CColor, becsID!CVelocity, becsID!CDamping, becsID!CScale, becsID!CMaterialIndex].staticArray); + EntityTemplate* base_tmpl = gEntityManager.allocateTemplate([becsID!CTexCoords, becsID!CLocation, becsID!CColor, becsID!CVelocity, becsID!CDamping, becsID!CScale, becsID!CMaterialIndex].staticArray); base_tmpl.getComponent!CColor().value = 0xFF251010; base_tmpl.getComponent!CScale().value = vec2(2); base_tmpl.getComponent!CTexCoords().value = vec4(246,64,2,2)*px; base_tmpl.getComponent!CMaterialIndex().value = 2; launcher.gui_manager.addTemplate(base_tmpl,"Particle"); - // tmpl = launcher.manager.allocateTemplate(base_tmpl); + // tmpl = gEntityManager.allocateTemplate(base_tmpl); // tmpl.getComponent!CColor().value = 0xFF251010; // launcher.gui_manager.addTemplate(tmpl,"Particle (blue)"); - // tmpl = launcher.manager.allocateTemplate(base_tmpl); + // tmpl = gEntityManager.allocateTemplate(base_tmpl); // tmpl.getComponent!CColor().value = 0xFF102010; // launcher.gui_manager.addTemplate(tmpl,"Particle (green)"); - // tmpl = launcher.manager.allocateTemplate(base_tmpl); + // tmpl = gEntityManager.allocateTemplate(base_tmpl); // tmpl.getComponent!CColor().value = 0xFF101540; // launcher.gui_manager.addTemplate(tmpl,"Particle (red)"); - // tmpl = launcher.manager.allocateTemplate(tmpl, [becsID!CDamping].staticArray); + // tmpl = gEntityManager.allocateTemplate(tmpl, [becsID!CDamping].staticArray); // launcher.gui_manager.addTemplate(tmpl,"Particle (damping)"); - // tmpl = launcher.manager.allocateTemplate(tmpl); + // tmpl = gEntityManager.allocateTemplate(tmpl); // tmpl.getComponent!CDamping().power = 4; // launcher.gui_manager.addTemplate(tmpl,"Particle (damping!)"); - tmpl = launcher.manager.allocateTemplate([becsID!CAttractor, becsID!CLocation, becsID!CForceRange, becsID!CScale].staticArray); + tmpl = gEntityManager.allocateTemplate([becsID!CAttractor, becsID!CLocation, becsID!CForceRange, becsID!CScale].staticArray); tmpl.getComponent!CScale().value = vec2(4); launcher.gui_manager.addTemplate(tmpl,"Attractor"); - tmpl = launcher.manager.allocateTemplate(tmpl, [becsID!CVortex].staticArray); + tmpl = gEntityManager.allocateTemplate(tmpl, [becsID!CVortex].staticArray); launcher.gui_manager.addTemplate(tmpl,"Vortex"); - // tmpl = launcher.manager.allocateTemplate(tmpl); + // tmpl = gEntityManager.allocateTemplate(tmpl); // tmpl.getComponent!CVortex().strength = -0.6; // launcher.gui_manager.addTemplate(tmpl,"Vortex (reversed)"); @@ -553,7 +452,7 @@ void particlesEnd() { particles_demo.texture.destroy(); - //launcher.manager.freeTemplate(simple.tmpl); + //gEntityManager.freeTemplate(simple.tmpl); Mallocator.dispose(particles_demo); } @@ -565,18 +464,18 @@ bool particlesLoop() { launcher.render_position = (vec2(launcher.window_size.x,launcher.window_size.y)*launcher.scalling - vec2(400,300)) * 0.5; - launcher.manager.begin(); + gEntityManager.begin(); if(launcher.multithreading) { launcher.job_updater.begin(); - launcher.manager.updateMT(); + gEntityManager.updateMT(); launcher.job_updater.call(); } else { - launcher.manager.update(); + gEntityManager.update(); } - launcher.manager.end(); + gEntityManager.end(); return true; } diff --git a/demos/source/demos/sandbox.d b/demos/source/demos/sandbox.d index c59b432..878684c 100644 --- a/demos/source/demos/sandbox.d +++ b/demos/source/demos/sandbox.d @@ -32,15 +32,15 @@ void sandboxStart() particlesStart(); brickBreakerStart(); - DrawSystem* draw_system = launcher.manager.getSystem!DrawSystem; + DrawSystem* draw_system = gEntityManager.getSystem!DrawSystem; draw_system.default_data.size = vec2(16,16); draw_system.default_data.coords = vec4(0,48,16,16)*demos.simple.px; draw_system.default_data.material_id = 0; draw_system.default_data.texture = particles_demo.texture; draw_system.default_data.color = 0x80808080; - launcher.manager.getSystem(becsID!MouseAttractSystem).disable(); - launcher.manager.getSystem(becsID!(demos.simple.MoveSystem)).disable(); + gEntityManager.getSystem(becsID!MouseAttractSystem).disable(); + gEntityManager.getSystem(becsID!(demos.simple.MoveSystem)).disable(); } @@ -60,7 +60,7 @@ bool sandboxLoop() { launcher.render_position = (vec2(launcher.window_size.x,launcher.window_size.y)*launcher.scalling - vec2(400,300)) * 0.5; - launcher.manager.begin(); + gEntityManager.begin(); float delta_time = launcher.delta_time; if(delta_time > 2000)delta_time = 2000; @@ -74,20 +74,20 @@ bool sandboxLoop() { time -= 200; - launcher.manager.update("fixed"); + gEntityManager.update("fixed"); } if(launcher.multithreading) { launcher.job_updater.begin(); - launcher.manager.updateMT(); + gEntityManager.updateMT(); launcher.job_updater.call(); } else { - launcher.manager.update(); + gEntityManager.update(); } - launcher.manager.end(); + gEntityManager.end(); return true; } diff --git a/demos/source/demos/simple.d b/demos/source/demos/simple.d index bfbb74c..010bae4 100644 --- a/demos/source/demos/simple.d +++ b/demos/source/demos/simple.d @@ -23,10 +23,22 @@ extern(C): enum float px = 1.0/512.0; +/************************************************** +All demos uses same patten. Every demo is self contained except systems and components which was splitted into different files to enable sharing them between demos. +Every demo has same functions: + * register - called on start for registering proces + * initialize - called after register to initialize demo data + * deinitiliaze - called when demo is switching. There data is deisposed + * loop - it's called every frame + + Demos uses some non-ECS functions to register components, systems and templates into GUI. Then components are showing by GUI and can be added to entities. +*/ + /*####################################################################################################################### ------------------------------------------------ Components ------------------------------------------------------------------ #######################################################################################################################*/ +//CLocation component was moved to game_code.basic /*struct CLocation { mixin ECS.Component; @@ -39,6 +51,7 @@ enum float px = 1.0/512.0; /*####################################################################################################################### ------------------------------------------------ Systems ------------------------------------------------------------------ #######################################################################################################################*/ +//DrawSystem was moved to game_code.basic /* struct DrawSystem { @@ -73,21 +86,29 @@ struct DrawSystem } }*/ +//simple system which moves entities struct MoveSystem { + //system will generate up to 64 jobs for multithreaded extecution mixin ECS.System!64; + //structe contains components used by system struct EntitiesData { uint length; + //system will use one component which is required. Only entities with CLocation component will be processed by this system CLocation[] locations; } + //onUpdate is called several times and covers all entities void onUpdate(EntitiesData data) { + //loop over entities in batch foreach(i; 0..data.length) { + //inscrease entity position in 'y' coordinate data.locations[i].y = data.locations[i].y + 1; + //move entity to 0 if exceeded 300 if(data.locations[i].y > 300)data.locations[i].y = 0; } } @@ -99,6 +120,7 @@ struct MoveSystem struct Simple { + //tips showed in GUI __gshared const (char)* tips = "Use \"space\" to spwan entities.\n\nSystems can be enabled/disabled from \"Demo\" window. \"Tools\" window exists of three tools which can be used to manipulate game. Options: @@ -132,61 +154,77 @@ Demo is capable rendering of hundreds of thousands of entities. Playable area is __gshared Simple* simple; +//called when demo starts void simpleRegister() { simple = Mallocator.make!Simple; + //load texture (atlas) simple.texture.create(); simple.texture.load("assets/textures/atlas.png"); - launcher.manager.beginRegister(); + //start registering process + gEntityManager.beginRegister(); - registerRenderingModule(launcher.manager); + //register basic components and systems + registerRenderingModule(gEntityManager); - launcher.manager.registerComponent!CLocation; + //register location component. It also registered inside registerRenderingModule() function, but it's there for clarity + gEntityManager.registerComponent!CLocation; - launcher.manager.registerSystem!MoveSystem(0); - // launcher.manager.registerSystem!DrawSystem(1); + gEntityManager.registerSystem!MoveSystem(0); + // DrawSystem is registered as RenderingModule + // gEntityManager.registerSystem!DrawSystem(1); - launcher.manager.endRegister(); + //end registering process + gEntityManager.endRegister(); } +//called after simpleRegister void simpleStart() { - DrawSystem* draw_system = launcher.manager.getSystem!DrawSystem; + //get DrawSystem instance and change some data + DrawSystem* draw_system = gEntityManager.getSystem!DrawSystem; draw_system.default_data.color = 0x80808080; draw_system.default_data.texture = simple.texture; draw_system.default_data.size = vec2(16,16); draw_system.default_data.coords = vec4(0,48,16,16)*px;//vec4(0,0,1,1); + //add systems to GUI. It's non ECS part launcher.gui_manager.addSystem(becsID!MoveSystem,"Move Up System"); launcher.gui_manager.addSystem(becsID!DrawSystem,"Draw System"); + //add components to GUI. It's non ECS part launcher.gui_manager.addComponent(CLocation(), "Location"); launcher.gui_manager.addComponent(CDrawDefault(), "DrawDefault"); - simple.tmpl = launcher.manager.allocateTemplate([becsID!CLocation, becsID!CDrawDefault].staticArray); - //*simple.tmpl.getComponent!CTexCoordsIndex = TexCoordsManager.instance.getCoordIndex(vec4(0,48,16,16)*px); - //CLocation* loc_comp = simple.tmpl.getComponent!CLocation; + //allocate new template with two components + simple.tmpl = gEntityManager.allocateTemplate([becsID!CLocation, becsID!CDrawDefault].staticArray); + //add template to GUI. It's non ECS part launcher.gui_manager.addTemplate(simple.tmpl, "Basic"); + //add 100 entities foreach(i; 0..10) foreach(j; 0..10) { - //loc_comp.value = vec2(i*16+64,j*16+64); - launcher.manager.addEntity(simple.tmpl,[CLocation(vec2(i*16+64,j*16+64)).ref_].staticArray); + //add entities in grid locations. "ref_" return ComponentRef structure. I'm not sure if adding component inside array generation isn't undefined behaviour but it works on tested platforms + gEntityManager.addEntity(simple.tmpl,[CLocation(vec2(i*16+64,j*16+64)).ref_].staticArray); } } +//called when demo is switched to different one void simpleEnd() { - launcher.manager.getSystem(becsID!MoveSystem).disable(); - launcher.manager.getSystem(becsID!DrawSystem).disable(); + //disable systems used by this demo. + gEntityManager.getSystem(becsID!MoveSystem).disable(); + gEntityManager.getSystem(becsID!DrawSystem).disable(); + //free texture memory simple.texture.destroy(); - //launcher.manager.freeTemplate(simple.tmpl); + //GUI manager will free template + //gEntityManager.freeTemplate(simple.tmpl); Mallocator.dispose(simple); } @@ -196,9 +234,8 @@ void simpleEvent(SDL_Event* event) void spawnEntity() { - //CLocation* loc_comp = simple.tmpl.getComponent!CLocation; - //loc_comp.value = vec2(randomf() * 400,0); - launcher.manager.addEntity(simple.tmpl,[CLocation(vec2(randomf() * 400,0)).ref_].staticArray); + //spawn entity in random location + gEntityManager.addEntity(simple.tmpl,[CLocation(vec2(randomf() * 400,0)).ref_].staticArray); } bool simpleLoop() @@ -210,18 +247,26 @@ bool simpleLoop() foreach(i;0..20)spawnEntity(); } - launcher.manager.begin(); + //begin frame + gEntityManager.begin(); + //if multithreading is enabled different path is used if(launcher.multithreading) { + //prepare data for multithreading. Clear previous jobs data. launcher.job_updater.begin(); - launcher.manager.updateMT(); + //generate jobs + gEntityManager.updateMT(); + //call jobs in multithreaded fashion launcher.job_updater.call(); } else { - launcher.manager.update(); + //update call will call inUpdate for all systems + gEntityManager.update(); + } - launcher.manager.end(); + //end ECS frame + gEntityManager.end(); return true; } diff --git a/demos/source/demos/snake.d b/demos/source/demos/snake.d index 395f283..31f2423 100644 --- a/demos/source/demos/snake.d +++ b/demos/source/demos/snake.d @@ -25,6 +25,7 @@ enum float px = 1.0/512.0; extern(C): +//Map is simple grid. Every cell has type and id to entity. struct MapElement { enum Type @@ -38,6 +39,7 @@ struct MapElement EntityID id; } +//snake part is corresponding to graphical representation of snake enum SnakePart : ubyte { head_up = 0, @@ -81,9 +83,9 @@ This demo is an example that in ECS you can make very \"non-ECS\" game"; { if(snake_destroy_particle_frames)Mallocator.dispose(snake_destroy_particle_frames); if(smoke_frames)Mallocator.dispose(smoke_frames); - if(apple_tmpl)launcher.manager.freeTemplate(apple_tmpl); - if(snake_tmpl)launcher.manager.freeTemplate(snake_tmpl); - if(snake_destroy_particle)launcher.manager.freeTemplate(snake_destroy_particle); + if(apple_tmpl)gEntityManager.freeTemplate(apple_tmpl); + if(snake_tmpl)gEntityManager.freeTemplate(snake_tmpl); + if(snake_destroy_particle)gEntityManager.freeTemplate(snake_destroy_particle); texture.destroy(); } @@ -116,7 +118,7 @@ This demo is an example that in ECS you can make very \"non-ECS\" game"; } if(base_pos.x == random_pos.x && base_pos.y == random_pos.y)return; } - launcher.manager.addEntity(apple_tmpl,[CLocation(cast(vec2)(random_pos)*16).ref_].staticArray); + gEntityManager.addEntity(apple_tmpl,[CLocation(cast(vec2)(random_pos)*16).ref_].staticArray); } } @@ -125,6 +127,7 @@ struct Animation } +//component has array of frames (texture coordinates) and time used for selection frames struct CAnimation { mixin ECS.Component; @@ -133,6 +136,7 @@ struct CAnimation float time = 0; } +//CIlocation is integer location used as grid cell coordination struct CILocation { mixin ECS.Component; @@ -202,11 +206,13 @@ struct CSnake CMovement.Direction direction; } +//flag for apple struct CApple { mixin ECS.Component; } +//particle is removed when life drops below 0 struct CParticle { mixin ECS.Component; @@ -214,6 +220,7 @@ struct CParticle float life = 0; } +//vector for particle movement struct CParticleVector { mixin ECS.Component; @@ -221,6 +228,7 @@ struct CParticleVector vec2 velocity = vec2(0,0); } +//contains current movement direction for snake struct CMovement { mixin ECS.Component; @@ -241,6 +249,7 @@ struct CMovement // mixin ECS.Component; // } +//this system has no onUpdate and only processing events. It responsible for adding and removing applce from grid. struct AppleSystem { mixin ECS.System!1; @@ -253,15 +262,17 @@ struct AppleSystem @readonly CILocation[] location; } + //called when entity was created void onAddEntity(EntitiesData data) { foreach(i;0..data.length) { if(snake.element(data.location[i]).id == EntityID())snake.element(MapElement(MapElement.Type.apple,data.entity[i].id),data.location[i]); - else launcher.manager.removeEntity(data.entity[i].id); + else gEntityManager.removeEntity(data.entity[i].id); } } + //called when entity was removed void onRemoveEntity(EntitiesData data) { foreach(i;0..data.length) @@ -272,6 +283,7 @@ struct AppleSystem } } +//system is responsible for killing particles when their life drops below 0 struct ParticleSystem { mixin ECS.System!1; @@ -288,11 +300,12 @@ struct ParticleSystem foreach(i;0..data.length) { data.particle[i].life -= launcher.deltaTime; - if(data.particle[i].life < 0)launcher.manager.removeEntity(data.entities[i].id); + if(data.particle[i].life < 0)gEntityManager.removeEntity(data.entities[i].id); } } } +//system responsible for moving particles struct ParticleMovementSystem { mixin ECS.System!1; @@ -363,7 +376,6 @@ struct AnimationRenderSystem draw_data.position = data.location[i]; draw_data.coords = data.animation[i].frames[cast(int)(data.animation[i].time)]; launcher.renderer.draw(draw_data); - //launcher.renderer.draw(snake.texture, cast(vec2)cast(ivec2)data.location[i], vec2(16,16), data.animation[i].frames[cast(int)(data.animation[i].time)], -1, 0x80808080); } } } @@ -373,8 +385,6 @@ struct MoveSystem mixin ECS.System!64; EntityTemplate* destroy_template; - //CLocation* destroy_location; - //CParticleVector* destroy_vector; struct EntitiesData { @@ -387,9 +397,8 @@ struct MoveSystem void setTemplates() { + //template is used for adding particles when snake will collide with himself destroy_template = snake.snake_destroy_particle; - //destroy_location = destroy_template.getComponent!CLocation; - //destroy_vector = destroy_template.getComponent!CParticleVector; } void moveLocation(ref CILocation location, CMovement.Direction direction) @@ -446,7 +455,7 @@ struct MoveSystem //destroy_location.x = loc.x * 16; //destroy_location.y = loc.y * 16; snake.element(MapElement(MapElement.Type.empty, EntityID()),loc); - launcher.manager.addEntity(snake.snake_destroy_particle,[CLocation(cast(vec2)(loc * 16)).ref_].staticArray); + gEntityManager.addEntity(snake.snake_destroy_particle,[CLocation(cast(vec2)(loc * 16)).ref_].staticArray); CLocation destroy_location; foreach(j;0..10) @@ -455,15 +464,15 @@ struct MoveSystem destroy_location.y = loc.y * 16 + randomf() * 8 - 4; //destroy_vector.velocity = vec2(randomf(),randomf())*0.4-0.2; snake.element(MapElement(MapElement.Type.empty, EntityID()),loc); - launcher.manager.addEntity(snake.snake_destroy_particle, [destroy_location.ref_, CParticleVector(vec2(randomf(),randomf())*0.4-0.2).ref_].staticArray); + gEntityManager.addEntity(snake.snake_destroy_particle, [destroy_location.ref_, CParticleVector(vec2(randomf(),randomf())*0.4-0.2).ref_].staticArray); } } //destroy_location.x = new_location.x * 16; //destroy_location.y = new_location.y * 16; snake.element(MapElement(MapElement.Type.empty, EntityID()),new_location); - launcher.manager.addEntity(snake.snake_destroy_particle,[CLocation(cast(vec2)(new_location * 16)).ref_].staticArray); - launcher.manager.removeEntity(data.entities[i].id); + gEntityManager.addEntity(snake.snake_destroy_particle,[CLocation(cast(vec2)(new_location * 16)).ref_].staticArray); + gEntityManager.removeEntity(data.entities[i].id); break; case MapElement.Type.wall:break; @@ -482,7 +491,7 @@ struct MoveSystem } break; case MapElement.Type.apple: - launcher.manager.removeEntity(snake.element(data.location[i].location).id); + gEntityManager.removeEntity(snake.element(data.location[i].location).id); if(data.snakes[i].parts.length >= 99) { snake.addApple(); @@ -537,7 +546,7 @@ struct SnakeSystem foreach(i;0..data.length) { if(snake.element(data.location[i]).id == EntityID())snake.element(MapElement(MapElement.Type.snake,data.entity[i].id),data.location[i]); - else launcher.manager.removeEntity(data.entity[i].id); + else gEntityManager.removeEntity(data.entity[i].id); } } @@ -814,7 +823,7 @@ struct CleanSystem { foreach(i; 0..data.length) { - launcher.manager.removeEntity(data.entities[i].id); + gEntityManager.removeEntity(data.entities[i].id); } } } @@ -859,38 +868,38 @@ void snakeRegister() snake.texture.create(); snake.texture.load("assets/textures/atlas.png"); - launcher.manager.beginRegister(); + gEntityManager.beginRegister(); - launcher.manager.registerPass("fixed"); + gEntityManager.registerPass("fixed"); - registerRenderingModule(launcher.manager); + registerRenderingModule(gEntityManager); - launcher.manager.registerComponent!CLocation; - launcher.manager.registerComponent!CILocation; - launcher.manager.registerComponent!CSnake; - launcher.manager.registerComponent!CApple; - launcher.manager.registerComponent!CParticle; - launcher.manager.registerComponent!CParticleVector; - launcher.manager.registerComponent!CMovement; - launcher.manager.registerComponent!CInput; - launcher.manager.registerComponent!CAnimation; + gEntityManager.registerComponent!CLocation; + gEntityManager.registerComponent!CILocation; + gEntityManager.registerComponent!CSnake; + gEntityManager.registerComponent!CApple; + gEntityManager.registerComponent!CParticle; + gEntityManager.registerComponent!CParticleVector; + gEntityManager.registerComponent!CMovement; + gEntityManager.registerComponent!CInput; + gEntityManager.registerComponent!CAnimation; - launcher.manager.registerSystem!MoveSystem(0,"fixed"); - launcher.manager.registerSystem!InputSystem(-100); - launcher.manager.registerSystem!FixSnakeDirectionSystem(-1,"fixed"); - launcher.manager.registerSystem!AnimationRenderSystem(100); - launcher.manager.registerSystem!AnimationSystem(-1); - launcher.manager.registerSystem!ParticleSystem(-1); - launcher.manager.registerSystem!ParticleMovementSystem(-1); - launcher.manager.registerSystem!DrawAppleSystem(99); - launcher.manager.registerSystem!DrawSnakeSystem(101); + gEntityManager.registerSystem!MoveSystem(0,"fixed"); + gEntityManager.registerSystem!InputSystem(-100); + gEntityManager.registerSystem!FixSnakeDirectionSystem(-1,"fixed"); + gEntityManager.registerSystem!AnimationRenderSystem(100); + gEntityManager.registerSystem!AnimationSystem(-1); + gEntityManager.registerSystem!ParticleSystem(-1); + gEntityManager.registerSystem!ParticleMovementSystem(-1); + gEntityManager.registerSystem!DrawAppleSystem(99); + gEntityManager.registerSystem!DrawSnakeSystem(101); - launcher.manager.registerSystem!CopyLocationSystem(100); - //launcher.manager.registerSystem!AppleRemoveSystem(100); - launcher.manager.registerSystem!AppleSystem(101); - launcher.manager.registerSystem!SnakeSystem(101); + gEntityManager.registerSystem!CopyLocationSystem(100); + //gEntityManager.registerSystem!AppleRemoveSystem(100); + gEntityManager.registerSystem!AppleSystem(101); + gEntityManager.registerSystem!SnakeSystem(101); - launcher.manager.endRegister(); + gEntityManager.endRegister(); } void snakeStart() @@ -918,12 +927,12 @@ void snakeStart() { ushort[5] components = [becsID!CILocation, becsID!CSnake, becsID!CMovement, becsID!CInput, becsID!CLocation]; - snake.snake_tmpl = launcher.manager.allocateTemplate(components); - launcher.manager.addEntity(snake.snake_tmpl,[CILocation(ivec2(2,2)).ref_].staticArray); + snake.snake_tmpl = gEntityManager.allocateTemplate(components); + gEntityManager.addEntity(snake.snake_tmpl,[CILocation(ivec2(2,2)).ref_].staticArray); } { - snake.snake_destroy_particle = launcher.manager.allocateTemplate([becsID!CLocation, becsID!CParticle, becsID!CParticleVector, becsID!CAnimation, becsID!CLocation].staticArray); + snake.snake_destroy_particle = gEntityManager.allocateTemplate([becsID!CLocation, becsID!CParticle, becsID!CParticleVector, becsID!CAnimation, becsID!CLocation].staticArray); CAnimation* canim = snake.snake_destroy_particle.getComponent!CAnimation; canim.frames = snake.snake_destroy_particle_frames; CParticle* particle = snake.snake_destroy_particle.getComponent!CParticle; @@ -932,21 +941,21 @@ void snakeStart() { ushort[3] components = [becsID!CILocation, becsID!CApple, becsID!CLocation]; - snake.apple_tmpl = launcher.manager.allocateTemplate(components); + snake.apple_tmpl = gEntityManager.allocateTemplate(components); snake.addApple(); } - launcher.gui_manager.addTemplate(launcher.manager.allocateTemplate(snake.snake_tmpl), "Snake"); - launcher.gui_manager.addTemplate(launcher.manager.allocateTemplate(snake.apple_tmpl), "Apple"); - launcher.gui_manager.addTemplate(launcher.manager.allocateTemplate(snake.snake_destroy_particle), "Particle"); + launcher.gui_manager.addTemplate(gEntityManager.allocateTemplate(snake.snake_tmpl), "Snake"); + launcher.gui_manager.addTemplate(gEntityManager.allocateTemplate(snake.apple_tmpl), "Apple"); + launcher.gui_manager.addTemplate(gEntityManager.allocateTemplate(snake.snake_destroy_particle), "Particle"); - MoveSystem* move_system = launcher.manager.getSystem!MoveSystem(); + MoveSystem* move_system = gEntityManager.getSystem!MoveSystem(); move_system.setTemplates(); } void snakeEnd() { - //launcher.manager.freeTemplate(simple.tmpl); + //gEntityManager.freeTemplate(simple.tmpl); Mallocator.dispose(snake); } @@ -970,7 +979,7 @@ bool snakeLoop() // igEnd(); // } - launcher.manager.begin(); + gEntityManager.begin(); float delta_time = launcher.deltaTime; if(delta_time > 2000)delta_time = 2000; @@ -983,12 +992,12 @@ bool snakeLoop() { time -= 200; - launcher.manager.update("fixed"); + gEntityManager.update("fixed"); } - launcher.manager.update(); + gEntityManager.update(); - launcher.manager.end(); + gEntityManager.end(); return true; } diff --git a/demos/source/demos/space_invaders.d b/demos/source/demos/space_invaders.d index c3decc2..48af134 100644 --- a/demos/source/demos/space_invaders.d +++ b/demos/source/demos/space_invaders.d @@ -20,11 +20,6 @@ import game_core.basic; import game_core.rendering; import game_core.collision; -//import std.math : PI; - - -//import std.array : staticArray; - private enum float px = 1.0/512.0; @@ -59,12 +54,12 @@ You can add any component to any entity which sometimes can give fun results. Th ~this() @nogc nothrow { // if(shoot_grid)Mallocator.dispose(shoot_grid); - if(enemy_tmpl)launcher.manager.freeTemplate(enemy_tmpl); - if(ship_tmpl)launcher.manager.freeTemplate(ship_tmpl); - if(laser_tmpl)launcher.manager.freeTemplate(laser_tmpl); + if(enemy_tmpl)gEntityManager.freeTemplate(enemy_tmpl); + if(ship_tmpl)gEntityManager.freeTemplate(ship_tmpl); + if(laser_tmpl)gEntityManager.freeTemplate(laser_tmpl); foreach (EntityTemplate* tmpl; bullet_tmpl) { - if(tmpl)launcher.manager.freeTemplate(tmpl); + if(tmpl)gEntityManager.freeTemplate(tmpl); } texture.destroy(); } @@ -503,7 +498,7 @@ struct ParentOwnerSystem //currently EntitiesData always has only one element foreach(child; data.children[0].childern) { - launcher.manager.removeEntity(child); + gEntityManager.removeEntity(child); } if(data.children[0].childern.length)Mallocator.dispose(data.children[0].childern); } @@ -536,28 +531,28 @@ struct ShipWeaponSystem laser1_tmpl.getComponent!CTargetParent().parent = entity.id; laser2_tmpl.getComponent!CTargetParent().parent = entity.id; main_weapon_tmpl.getComponent!CTargetParent().parent = entity.id; - weapons[0] = launcher.manager.addEntity(laser1_tmpl).id; - weapons[1] = launcher.manager.addEntity(laser2_tmpl).id; - weapons[2] = launcher.manager.addEntity(main_weapon_tmpl).id; + weapons[0] = gEntityManager.addEntity(laser1_tmpl).id; + weapons[1] = gEntityManager.addEntity(laser2_tmpl).id; + weapons[2] = gEntityManager.addEntity(main_weapon_tmpl).id; children.childern = Mallocator.makeArray(weapons); } void create() { - laser1_tmpl = launcher.manager.allocateTemplate([becsID!CWeapon, becsID!CLocation, becsID!CShootDirection, becsID!CTargetParent, becsID!CGuild, becsID!CVelocity].staticArray); - main_weapon_tmpl = launcher.manager.allocateTemplate([becsID!CLocation, becsID!CShootDirection, becsID!CTargetParent, becsID!CGuild, becsID!CVelocity].staticArray); + laser1_tmpl = gEntityManager.allocateTemplate([becsID!CWeapon, becsID!CLocation, becsID!CShootDirection, becsID!CTargetParent, becsID!CGuild, becsID!CVelocity].staticArray); + main_weapon_tmpl = gEntityManager.allocateTemplate([becsID!CLocation, becsID!CShootDirection, becsID!CTargetParent, becsID!CGuild, becsID!CVelocity].staticArray); *laser1_tmpl.getComponent!CWeapon = CWeapon(0,CWeapon.Type.laser,3); laser1_tmpl.getComponent!CTargetParent().rel_pos = vec2(10,13); main_weapon_tmpl.getComponent!CTargetParent().rel_pos = vec2(0,4); - laser2_tmpl = launcher.manager.allocateTemplate(laser1_tmpl); + laser2_tmpl = gEntityManager.allocateTemplate(laser1_tmpl); laser2_tmpl.getComponent!CTargetParent().rel_pos = vec2(-10,13); } ~this() { - launcher.manager.freeTemplate(laser1_tmpl); - launcher.manager.freeTemplate(laser2_tmpl); - launcher.manager.freeTemplate(main_weapon_tmpl); + gEntityManager.freeTemplate(laser1_tmpl); + gEntityManager.freeTemplate(laser2_tmpl); + gEntityManager.freeTemplate(main_weapon_tmpl); } } @@ -579,14 +574,14 @@ struct ShipWeaponSystem if(depth)top_tmpl.getComponent!CDepth().value = cast(short)(depth.value - 2); else top_tmpl.getComponent!CDepth().value = -2; - weapons[0] = launcher.manager.addEntity(weapon_tmpl).id; - weapons[1] = launcher.manager.addEntity(top_tmpl).id; + weapons[0] = gEntityManager.addEntity(weapon_tmpl).id; + weapons[1] = gEntityManager.addEntity(top_tmpl).id; children.childern = Mallocator.makeArray(weapons); } void create() { - weapon_tmpl = launcher.manager.allocateTemplate( + weapon_tmpl = gEntityManager.allocateTemplate( [becsID!CWeapon, becsID!CLocation, becsID!CShootDirection, becsID!CTargetParent, becsID!CGuild, becsID!CVelocity, becsID!CAutoShoot, becsID!CTarget, becsID!CTargetPlayerShip, @@ -602,7 +597,7 @@ struct ShipWeaponSystem weapon_tmpl.getComponent!CTexCoords().value = vec4(136,96,4,16)*px; weapon_tmpl.getComponent!CWeaponLocation().rel_pos = vec2(0,12); - top_tmpl = launcher.manager.allocateTemplate( + top_tmpl = gEntityManager.allocateTemplate( [becsID!CLocation, becsID!CTargetParent, becsID!CScale, becsID!CTexCoords, becsID!CDepth].staticArray); top_tmpl.getComponent!CTargetParent().rel_pos = vec2(0,1); @@ -614,8 +609,8 @@ struct ShipWeaponSystem ~this() { - launcher.manager.freeTemplate(weapon_tmpl); - launcher.manager.freeTemplate(top_tmpl); + gEntityManager.freeTemplate(weapon_tmpl); + gEntityManager.freeTemplate(top_tmpl); } } @@ -637,16 +632,16 @@ struct ShipWeaponSystem tower2_tmpl.getComponent!CTargetParent().parent = entity.id; tower3_tmpl.getComponent!CTargetParent().parent = entity.id; tower4_tmpl.getComponent!CTargetParent().parent = entity.id; - towers[0] = launcher.manager.addEntity(tower1_tmpl).id; - towers[1] = launcher.manager.addEntity(tower2_tmpl).id; - towers[2] = launcher.manager.addEntity(tower3_tmpl).id; - towers[3] = launcher.manager.addEntity(tower4_tmpl).id; + towers[0] = gEntityManager.addEntity(tower1_tmpl).id; + towers[1] = gEntityManager.addEntity(tower2_tmpl).id; + towers[2] = gEntityManager.addEntity(tower3_tmpl).id; + towers[3] = gEntityManager.addEntity(tower4_tmpl).id; children.childern = Mallocator.makeArray(towers); } void create() { - tower1_tmpl = launcher.manager.allocateTemplate( + tower1_tmpl = gEntityManager.allocateTemplate( [becsID!CColor, becsID!CHitMark, becsID!CHitPoints, becsID!CLocation, becsID!CTexCoords, becsID!CScale, becsID!CEnemy, becsID!CShootGrid, becsID!CGuild, becsID!CInit, @@ -654,11 +649,6 @@ struct ShipWeaponSystem becsID!CSpawnUponDeath, becsID!CShootWaveUponDeath, becsID!CShootGridMask].staticArray ); - /*CTexCoords* tex_comp = tower1_tmpl.getComponent!CTexCoords; - //tex_comp.tex = space_invaders.texture;//ship_tex; - tex_comp.coords = vec4(96*px,96*px,16*px,16*px); - CLocation* loc_comp = tower1_tmpl.getComponent!CLocation; - loc_comp.value = vec2(64,space_invaders.map_size.y - 16);*/ tower1_tmpl.getComponent!CTexCoords().value = vec4(96*px,96*px,16*px,16*px); tower1_tmpl.getComponent!CLocation().value = vec2(64,space_invaders.map_size.y - 16); tower1_tmpl.getComponent!CGuild().guild = 1; @@ -668,24 +658,24 @@ struct ShipWeaponSystem tower1_tmpl.getComponent!CShootWaveUponDeath().bullet_type = CWeapon.Type.canon; tower1_tmpl.getComponent!CTargetParent().rel_pos = vec2(-33,2); - tower2_tmpl = launcher.manager.allocateTemplate(tower1_tmpl); + tower2_tmpl = gEntityManager.allocateTemplate(tower1_tmpl); tower2_tmpl.getComponent!CTargetParent().rel_pos = vec2(33,2); - tower3_tmpl = launcher.manager.allocateTemplate(tower1_tmpl); + tower3_tmpl = gEntityManager.allocateTemplate(tower1_tmpl); tower3_tmpl.getComponent!CDepth().value = 0; tower3_tmpl.getComponent!CTargetParent().rel_pos = vec2(-40,-15); - tower4_tmpl = launcher.manager.allocateTemplate(tower1_tmpl); + tower4_tmpl = gEntityManager.allocateTemplate(tower1_tmpl); tower4_tmpl.getComponent!CDepth().value = 0; tower4_tmpl.getComponent!CTargetParent().rel_pos = vec2(40,-15); } ~this() { - launcher.manager.freeTemplate(tower1_tmpl); - launcher.manager.freeTemplate(tower2_tmpl); - launcher.manager.freeTemplate(tower3_tmpl); - launcher.manager.freeTemplate(tower4_tmpl); + gEntityManager.freeTemplate(tower1_tmpl); + gEntityManager.freeTemplate(tower2_tmpl); + gEntityManager.freeTemplate(tower3_tmpl); + gEntityManager.freeTemplate(tower4_tmpl); } } @@ -698,21 +688,11 @@ struct ShipWeaponSystem ship.create(); tower.create(); boss.create(); - /*ship.laser1_tmpl = launcher.manager.allocateTemplate([becsID!CWeapon, becsID!CLocation, becsID!CShootDirection, becsID!CTargetParent, becsID!CGuild, becsID!CVelocity].staticArray); - ship.main_weapon_tmpl = launcher.manager.allocateTemplate([becsID!CLocation, becsID!CShootDirection, becsID!CTargetParent, becsID!CGuild, becsID!CVelocity].staticArray); - *ship.laser1_tmpl.getComponent!CWeapon = CWeapon(3,0.0); - ship.laser1_tmpl.getComponent!CTargetParent().rel_pos = vec2(10,13); - ship.main_weapon_tmpl.getComponent!CTargetParent().rel_pos = vec2(0,4); - ship.laser2_tmpl = launcher.manager.allocateTemplate(ship.laser1_tmpl); - ship.laser2_tmpl.getComponent!CTargetParent().rel_pos = vec2(-10,13);*/ } void onDestroy() { __xdtor(); - /*launcher.manager.freeTemplate(laser1_tmpl); - launcher.manager.freeTemplate(laser2_tmpl); - launcher.manager.freeTemplate(main_weapon_tmpl);*/ } void onAddEntity(EntitiesData data) @@ -747,7 +727,7 @@ struct MoveToParentTargetSystem { foreach(i;0..data.length) { - Entity* target = launcher.manager.getEntity(data.target[i].parent); + Entity* target = gEntityManager.getEntity(data.target[i].parent); if(target) { CLocation* target_loc = target.getComponent!CLocation; @@ -766,7 +746,7 @@ struct MoveToParentTargetSystem else foreach(i;0..data.length) { - Entity* target = launcher.manager.getEntity(data.target[i].parent); + Entity* target = gEntityManager.getEntity(data.target[i].parent); if(target) { CLocation* target_loc = target.getComponent!CLocation; @@ -951,34 +931,12 @@ struct ShootingSystem @optional @readonly CRotation[] rotation; } - //EntityTemplate* laser_tmpl; EntityTemplate* fire_tmpl; - //EntityTemplate*[5] bullet_tmpl; - ///Called inside "registerSystem" function void onCreate() { - /*bullet_tmpl[0] = launcher.manager.allocateTemplate( - [becsID!CLocation, becsID!CTexCoords, becsID!CVelocity, - becsID!CScale, becsID!CBullet, becsID!CGuild].staticArray - ); - bullet_tmpl[0].getComponent!CTexCoords().value = vec4(0,24,2,8)*px; - bullet_tmpl[0].getComponent!CScale().value = vec2(2,8); - - bullet_tmpl[1] = launcher.manager.allocateTemplate(bullet_tmpl[0]); - bullet_tmpl[2] = launcher.manager.allocateTemplate(bullet_tmpl[0]); - bullet_tmpl[2].getComponent!CTexCoords().value = vec4(64,32,8,16)*px; - bullet_tmpl[2].getComponent!CScale().value = vec2(8,16); - bullet_tmpl[3] = launcher.manager.allocateTemplate(bullet_tmpl[0]); - bullet_tmpl[3].getComponent!CTexCoords().value = vec4(56,32,2,2)*px; - bullet_tmpl[3].getComponent!CScale().value = vec2(2,2); - // bullet_tmpl[3].getComponent!CTexCoords().value = vec4(48,32,8,8)*px; - // bullet_tmpl[3].getComponent!CScale().value = vec2(8,8); - bullet_tmpl[4] = launcher.manager.allocateTemplate(bullet_tmpl[0]);*/ - - - fire_tmpl = launcher.manager.allocateTemplate( + fire_tmpl = gEntityManager.allocateTemplate( [becsID!CLocation, becsID!CTexCoords, becsID!CScale, becsID!CAnimation, becsID!CParticle, becsID!CRotation, becsID!CVelocity, becsID!CDamping].staticArray @@ -992,19 +950,11 @@ struct ShootingSystem void onDestroy() { - //launcher.manager.freeTemplate(laser_tmpl); - /*foreach (EntityTemplate* tmpl; bullet_tmpl) - { - launcher.manager.freeTemplate(tmpl); - }*/ - launcher.manager.freeTemplate(fire_tmpl); + gEntityManager.freeTemplate(fire_tmpl); } bool onBegin() { - /*laser_location = space_invaders.laser_tmpl.getComponent!CLocation; - laser_velocity = space_invaders.laser_tmpl.getComponent!CVelocity; - laser_guild = space_invaders.laser_tmpl.getComponent!CGuild;*/ if(launcher.getKeyState(SDL_SCANCODE_SPACE)) { shoot = true; @@ -1081,8 +1031,8 @@ struct ShootingSystem fire_location.value += data.weapon_location[i].rel_pos; } - launcher.manager.addEntity(space_invaders.bullet_tmpl[data.laser[i].type],[laser_velocity.ref_, laser_guild.ref_, laser_location.ref_].staticArray); - launcher.manager.addEntity(fire_tmpl,[fire_location.ref_, fire_rotation.ref_, fire_velocity.ref_].staticArray); + gEntityManager.addEntity(space_invaders.bullet_tmpl[data.laser[i].type],[laser_velocity.ref_, laser_guild.ref_, laser_location.ref_].staticArray); + gEntityManager.addEntity(fire_tmpl,[fire_location.ref_, fire_rotation.ref_, fire_velocity.ref_].staticArray); } } } @@ -1122,8 +1072,8 @@ struct BulletsCollisionSystem { if(space_invaders.shoot_grid.test(id, data.location[i], cast(ubyte)(~(1 << data.guild[i].guild)))) { - launcher.manager.sendEvent(id, EBulletHit(data.entity[i].id,data.bullet[i].damage)); - //launcher.manager.removeEntity(data.entity[i].id); + gEntityManager.sendEvent(id, EBulletHit(data.entity[i].id,data.bullet[i].damage)); + //gEntityManager.removeEntity(data.entity[i].id); } } } @@ -1175,7 +1125,7 @@ struct ParticleEmittingSystem void onCreate() { - templates[0] = launcher.manager.allocateTemplate( + templates[0] = gEntityManager.allocateTemplate( [becsID!CLocation, becsID!CTexCoords, becsID!CScale, becsID!CAnimation, becsID!CParticle, becsID!CRotation, becsID!CVelocity, becsID!CDamping, becsID!CDepth].staticArray); @@ -1188,7 +1138,7 @@ struct ParticleEmittingSystem { foreach(tmpl; templates) { - launcher.manager.freeTemplate(tmpl); + gEntityManager.freeTemplate(tmpl); } } @@ -1215,7 +1165,7 @@ struct ParticleEmittingSystem depth.value = data.depth[i]; } - launcher.manager.addEntity(templates[0],[data.location[i].ref_,velocity.ref_,depth.ref_].staticArray); + gEntityManager.addEntity(templates[0],[data.location[i].ref_,velocity.ref_,depth.ref_].staticArray); } } } @@ -1243,11 +1193,11 @@ struct UpgradeCollisionSystem { if(space_invaders.shoot_grid.test(id, data.location[i], cast(ubyte)(0xFF))) { - Entity* entity = launcher.manager.getEntity(id); + Entity* entity = gEntityManager.getEntity(id); if(entity && entity.hasComponent(becsID!CShip)) { - launcher.manager.sendEvent(id, EUpgrade()); - launcher.manager.removeEntity(data.entity[i].id); + gEntityManager.sendEvent(id, EUpgrade()); + gEntityManager.removeEntity(data.entity[i].id); } } } @@ -1279,7 +1229,7 @@ struct UpgradeSystem { foreach(child;children.childern) { - launcher.manager.sendEvent(child,EUpgrade()); + gEntityManager.sendEvent(child,EUpgrade()); } } } @@ -1472,7 +1422,7 @@ struct HitPointsSystem void onCreate() { - upgrade_tmpl = launcher.manager.allocateTemplate( + upgrade_tmpl = gEntityManager.allocateTemplate( [becsID!CVelocity, becsID!CLocation, becsID!CTexCoords, becsID!CScale, becsID!CUpgrade, becsID!CAnimation, becsID!CAnimationLooped].staticArray); @@ -1481,7 +1431,7 @@ struct HitPointsSystem *upgrade_tmpl.getComponent!CAnimation = CAnimation(upgrade_laser_frames, 0, 1); upgrade_tmpl.getComponent!CVelocity().value = vec2(0,-0.05); - explosion_tmpl = launcher.manager.allocateTemplate( + explosion_tmpl = gEntityManager.allocateTemplate( [becsID!CDepth, becsID!CParticle, becsID!CLocation, becsID!CTexCoords, becsID!CScale, becsID!CAnimation].staticArray); //explosion_tmpl.getComponent!(CTexCoords).tex = space_invaders.texture; @@ -1492,8 +1442,8 @@ struct HitPointsSystem void onDestroy() { - launcher.manager.freeTemplate(upgrade_tmpl); - launcher.manager.freeTemplate(explosion_tmpl); + gEntityManager.freeTemplate(upgrade_tmpl); + gEntityManager.freeTemplate(explosion_tmpl); } /*void handleEvent(Entity* entity, EDamage event) @@ -1503,8 +1453,8 @@ struct HitPointsSystem *hp -= event.damage; if(*hp <= 0) { - launcher.manager.sendEvent(entity.id, EDeath()); - //launcher.manager.removeEntity(entity.id); + gEntityManager.sendEvent(entity.id, EDeath()); + //gEntityManager.removeEntity(entity.id); } CHitMark* hit_mark = entity.getComponent!CHitMark; if(hit_mark)hit_mark.value = 127; @@ -1514,12 +1464,12 @@ struct HitPointsSystem { CHitPoints* hp = entity.getComponent!CHitPoints; if(*hp <= 0)return; - launcher.manager.removeEntity(event.id); + gEntityManager.removeEntity(event.id); *hp -= event.damage; if(*hp <= 0) { - launcher.manager.sendEvent(entity.id, EDeath()); - //launcher.manager.removeEntity(entity.id); + gEntityManager.sendEvent(entity.id, EDeath()); + //gEntityManager.removeEntity(entity.id); } CHitMark* hit_mark = entity.getComponent!CHitMark; if(hit_mark)hit_mark.value = 127; @@ -1535,12 +1485,12 @@ struct HitPointsSystem { if(randomRange(0, 1000) < 5) { - launcher.manager.addEntity(upgrade_tmpl,[location.ref_].staticArray); + gEntityManager.addEntity(upgrade_tmpl,[location.ref_].staticArray); } - launcher.manager.addEntity(explosion_tmpl,[location.ref_].staticArray); + gEntityManager.addEntity(explosion_tmpl,[location.ref_].staticArray); } } - launcher.manager.removeEntity(entity.id); + gEntityManager.removeEntity(entity.id); } } @@ -1558,7 +1508,7 @@ struct ChildDestroySystem CTargetParent* parent = entity.getComponent!CTargetParent; if(parent) { - launcher.manager.sendEvent(parent.parent, EDestroyedChild(entity.id)); + gEntityManager.sendEvent(parent.parent, EDestroyedChild(entity.id)); } } } @@ -1603,12 +1553,12 @@ struct ShootWaveSystem EntityTemplate* tmpl = space_invaders.bullet_tmpl[wave.bullet_type]; foreach(dir;dirs) { - if(guild)launcher.manager.addEntity(tmpl,[location.ref_,guild.ref_,CVelocity(dir).ref_].staticArray); - else launcher.manager.addEntity(tmpl,[location.ref_,CVelocity(dir).ref_].staticArray); + if(guild)gEntityManager.addEntity(tmpl,[location.ref_,guild.ref_,CVelocity(dir).ref_].staticArray); + else gEntityManager.addEntity(tmpl,[location.ref_,CVelocity(dir).ref_].staticArray); } - //launcher.manager.addEntity(tmpl);//,[location.ref_].staticArray); + //gEntityManager.addEntity(tmpl);//,[location.ref_].staticArray); - //launcher.manager.addEntity(space_invaders.bullet_tmpl[0]); + //gEntityManager.addEntity(space_invaders.bullet_tmpl[0]); } } @@ -1627,7 +1577,7 @@ struct PartsDestroySystem void onCreate() { - flashes_emitter = launcher.manager.allocateTemplate( + flashes_emitter = gEntityManager.allocateTemplate( [ becsID!CVelocity, becsID!CLocation, becsID!CParticleEmitter, becsID!CParticleEmitterTime, becsID!CTargetParent, becsID!CDepth @@ -1637,7 +1587,7 @@ struct PartsDestroySystem void onDestroy() { - launcher.manager.freeTemplate(flashes_emitter); + gEntityManager.freeTemplate(flashes_emitter); } void handleEvent(Entity* entity, EDestroyedChild event) @@ -1653,7 +1603,7 @@ struct PartsDestroySystem { if(child == event.id) { - Entity* child_entity = launcher.manager.getEntity(child); + Entity* child_entity = gEntityManager.getEntity(child); if(child_entity) { CLocation location; @@ -1665,8 +1615,8 @@ struct PartsDestroySystem if(target_location)location = *target_location; *flashes_emitter.getComponent!CTargetParent() = *target_parent; - if(target_depth)child = launcher.manager.addEntity(flashes_emitter, [target_depth.ref_, location.ref_].staticArray).id; - else child = launcher.manager.addEntity(flashes_emitter, [location.ref_].staticArray).id; + if(target_depth)child = gEntityManager.addEntity(flashes_emitter, [target_depth.ref_, location.ref_].staticArray).id; + else child = gEntityManager.addEntity(flashes_emitter, [location.ref_].staticArray).id; } break; } @@ -1677,7 +1627,7 @@ struct PartsDestroySystem { if(init.type == CInit.Type.boss) { - launcher.manager.addComponents(entity.id, CHitPoints(100), CShootGrid()); + gEntityManager.addComponents(entity.id, CHitPoints(100), CShootGrid()); } } } @@ -1712,7 +1662,7 @@ struct ClampPositionSystem foreach(i;0..data.length) { if(data.locations[i].x < 0 || data.locations[i].x > space_invaders.map_size.x || - data.locations[i].y < 0 || data.locations[i].y > space_invaders.map_size.y)launcher.manager.removeEntity(data.entities[i].id); + data.locations[i].y < 0 || data.locations[i].y > space_invaders.map_size.y)gEntityManager.removeEntity(data.entities[i].id); } } /*else if(data.side_move) @@ -1722,7 +1672,7 @@ struct ClampPositionSystem if(data.locations[i].x < 0) { //data.locations[i].x = 0; - //launcher.manager.sendEvent(data.entities[i].id,EChangeDirection(Direction.right)); + //gEntityManager.sendEvent(data.entities[i].id,EChangeDirection(Direction.right)); if(data.side_move[i].group == -1) { if(data.velocity[i].x < 0)data.velocity[i].x = -data.velocity[i].x; @@ -1735,7 +1685,7 @@ struct ClampPositionSystem else if(data.locations[i].x > space_invaders.map_size.x) { //data.locations[i].x = space_invaders.map_size.x; - //launcher.manager.sendEvent(data.entities[i].id,EChangeDirection(Direction.left)); + //gEntityManager.sendEvent(data.entities[i].id,EChangeDirection(Direction.left)); if(data.side_move[i].group == -1) { if(data.velocity[i].x > 0)data.velocity[i].x = -data.velocity[i].x; @@ -1868,7 +1818,7 @@ struct ParticleSystem foreach(i;0..data.length) { data.particle[i].life -= launcher.deltaTime; - if(data.particle[i].life < 0)launcher.manager.removeEntity(data.entitiy[i].id); + if(data.particle[i].life < 0)gEntityManager.removeEntity(data.entitiy[i].id); } } } @@ -1889,7 +1839,7 @@ struct RotateToTargetSystem { foreach(i;0..data.length) { - Entity* target = launcher.manager.getEntity(data.target[i].target); + Entity* target = gEntityManager.getEntity(data.target[i].target); if(target) { CLocation* target_loc = target.getComponent!CLocation; @@ -1937,11 +1887,11 @@ struct ShipTargetSystem bool onBegin() { - Entity* ship = launcher.manager.getEntity(player_ship); + Entity* ship = gEntityManager.getEntity(player_ship); if(ship is null) { - launcher.manager.callEntitiesFunction!CShipIterator(&iterateShips); - ship = launcher.manager.getEntity(player_ship); + gEntityManager.callEntitiesFunction!CShipIterator(&iterateShips); + ship = gEntityManager.getEntity(player_ship); if(ship is null)return false; return true; } @@ -1992,7 +1942,7 @@ struct CShipIterator void onCreate() { - flashes_emitter = launcher.manager.allocateTemplate( + flashes_emitter = gEntityManager.allocateTemplate( [ becsID!CVelocity, becsID!CLocation, becsID!CParticleEmitter, becsID!CParticleEmitterTime, becsID!CTargetParent @@ -2002,7 +1952,7 @@ struct CShipIterator void onDestroy() { - launcher.manager.freeTemplate(flashes_emitter); + gEntityManager.freeTemplate(flashes_emitter); } void onRemoveEntity(EntitiesData data) @@ -2013,18 +1963,18 @@ struct CShipIterator case CSpawnUponDeath.Type.flashes_emitter: if(data.parent) { - /*Entity* parent_entity = launcher.manager.getEntity(data.parent[0].parent); + /*Entity* parent_entity = gEntityManager.getEntity(data.parent[0].parent); CChildren* children = entity.getComponent!CChildren; foreach(ref EntityID child; children.childern) { if(child == event.id) { - Entity* child_entity = launcher.manager.getEntity(child); + Entity* child_entity = gEntityManager.getEntity(child); if(child_entity) { *flashes_emitter.getComponent!CTargetParent = data.parent[0]; - launcher.manager.addEntity(flashes_emitter); - //child = launcher.manager.addEntity(flashes_emitter); + gEntityManager.addEntity(flashes_emitter); + //child = gEntityManager.addEntity(flashes_emitter); } break; } @@ -2052,92 +2002,92 @@ void spaceInvadersRegister() space_invaders.texture.create(); space_invaders.texture.load("assets/textures/atlas.png"); - launcher.manager.beginRegister(); + gEntityManager.beginRegister(); - launcher.manager.registerDependency(ShootGridDependency); + gEntityManager.registerDependency(ShootGridDependency); - registerRenderingModule(launcher.manager); + registerRenderingModule(gEntityManager); - launcher.manager.registerComponent!CLocation; - launcher.manager.registerComponent!CTexCoords; - //launcher.manager.registerComponent!CTexture; - launcher.manager.registerComponent!CInput; - launcher.manager.registerComponent!CShip; - launcher.manager.registerComponent!CEnemy; - launcher.manager.registerComponent!CScale; - launcher.manager.registerComponent!CShootDirection; - launcher.manager.registerComponent!CAutoShoot; - launcher.manager.registerComponent!CWeapon; - launcher.manager.registerComponent!CVelocity; - launcher.manager.registerComponent!CBullet; - launcher.manager.registerComponent!CSideMove; - launcher.manager.registerComponent!CDepth; - launcher.manager.registerComponent!CShootGrid; - launcher.manager.registerComponent!CGuild; - launcher.manager.registerComponent!CHitPoints; - launcher.manager.registerComponent!CHitMark; - launcher.manager.registerComponent!CUpgrade; - launcher.manager.registerComponent!CParticle; - launcher.manager.registerComponent!CMaxHitPoints; - launcher.manager.registerComponent!CAnimation; - launcher.manager.registerComponent!CRotation; - launcher.manager.registerComponent!CAnimationLooped; - launcher.manager.registerComponent!CDamping; - launcher.manager.registerComponent!CTargetParent; - launcher.manager.registerComponent!CTarget; - launcher.manager.registerComponent!CTargetPlayerShip; - launcher.manager.registerComponent!CChildren; - launcher.manager.registerComponent!CWeaponLocation; - launcher.manager.registerComponent!CVelocityFactor; - launcher.manager.registerComponent!CInit; - launcher.manager.registerComponent!CBoss; - launcher.manager.registerComponent!CParts; - launcher.manager.registerComponent!CColliderScale; - launcher.manager.registerComponent!CParticleEmitter; - launcher.manager.registerComponent!CParticleEmitterTime; - launcher.manager.registerComponent!CSpawnUponDeath; - launcher.manager.registerComponent!CShootWaveUponDeath; - launcher.manager.registerComponent!CShootGridMask; + gEntityManager.registerComponent!CLocation; + gEntityManager.registerComponent!CTexCoords; + //gEntityManager.registerComponent!CTexture; + gEntityManager.registerComponent!CInput; + gEntityManager.registerComponent!CShip; + gEntityManager.registerComponent!CEnemy; + gEntityManager.registerComponent!CScale; + gEntityManager.registerComponent!CShootDirection; + gEntityManager.registerComponent!CAutoShoot; + gEntityManager.registerComponent!CWeapon; + gEntityManager.registerComponent!CVelocity; + gEntityManager.registerComponent!CBullet; + gEntityManager.registerComponent!CSideMove; + gEntityManager.registerComponent!CDepth; + gEntityManager.registerComponent!CShootGrid; + gEntityManager.registerComponent!CGuild; + gEntityManager.registerComponent!CHitPoints; + gEntityManager.registerComponent!CHitMark; + gEntityManager.registerComponent!CUpgrade; + gEntityManager.registerComponent!CParticle; + gEntityManager.registerComponent!CMaxHitPoints; + gEntityManager.registerComponent!CAnimation; + gEntityManager.registerComponent!CRotation; + gEntityManager.registerComponent!CAnimationLooped; + gEntityManager.registerComponent!CDamping; + gEntityManager.registerComponent!CTargetParent; + gEntityManager.registerComponent!CTarget; + gEntityManager.registerComponent!CTargetPlayerShip; + gEntityManager.registerComponent!CChildren; + gEntityManager.registerComponent!CWeaponLocation; + gEntityManager.registerComponent!CVelocityFactor; + gEntityManager.registerComponent!CInit; + gEntityManager.registerComponent!CBoss; + gEntityManager.registerComponent!CParts; + gEntityManager.registerComponent!CColliderScale; + gEntityManager.registerComponent!CParticleEmitter; + gEntityManager.registerComponent!CParticleEmitterTime; + gEntityManager.registerComponent!CSpawnUponDeath; + gEntityManager.registerComponent!CShootWaveUponDeath; + gEntityManager.registerComponent!CShootGridMask; - launcher.manager.registerEvent!EChangeDirection; - launcher.manager.registerEvent!EDamage; - launcher.manager.registerEvent!EUpgrade; - launcher.manager.registerEvent!EDeath; - launcher.manager.registerEvent!EDestroyedChild; - launcher.manager.registerEvent!EBulletHit; + gEntityManager.registerEvent!EChangeDirection; + gEntityManager.registerEvent!EDamage; + gEntityManager.registerEvent!EUpgrade; + gEntityManager.registerEvent!EDeath; + gEntityManager.registerEvent!EDestroyedChild; + gEntityManager.registerEvent!EBulletHit; - //launcher.manager.registerSystem!MoveSystem(0); - launcher.manager.registerSystem!DrawSystem(100); - launcher.manager.registerSystem!InputMovementSystem(-100); - //launcher.manager.registerSystem!MovementSystem(-99); - launcher.manager.registerSystem!MoveSystem(-99); - launcher.manager.registerSystem!ClampPositionSystem(-90); - launcher.manager.registerSystem!ShootingSystem(0); - launcher.manager.registerSystem!ChangeDirectionSystem(0); - launcher.manager.registerSystem!BulletsCollisionSystem(-70); - launcher.manager.registerSystem!ShootGridManager(-80); - launcher.manager.registerSystem!ShootGridCleaner(-101); - launcher.manager.registerSystem!HitPointsSystem(0); - launcher.manager.registerSystem!HitMarkingSystem(-100); - launcher.manager.registerSystem!UpgradeCollisionSystem(-70); - launcher.manager.registerSystem!UpgradeSystem(-100); - launcher.manager.registerSystem!ParticleSystem(-100); - launcher.manager.registerSystem!AnimationSystem(-100); - launcher.manager.registerSystem!DampingSystem(-101); - launcher.manager.registerSystem!MoveToParentTargetSystem(-98); - launcher.manager.registerSystem!ParentOwnerSystem(-101); - launcher.manager.registerSystem!ShipWeaponSystem(-100); - launcher.manager.registerSystem!ParticleEmittingSystem(-95); - launcher.manager.registerSystem!RotateToTargetSystem(-100); - launcher.manager.registerSystem!ShipTargetSystem(-110); - launcher.manager.registerSystem!CShipIterator(-100); - launcher.manager.registerSystem!PartsDestroySystem(-80); - launcher.manager.registerSystem!ChildDestroySystem(-110); - launcher.manager.registerSystem!ShootWaveSystem(-100); - //launcher.manager.registerSystem!SpawnUponDeathSystem(-110); - launcher.manager.registerSystem!CollisionMaskSystem(-100); + //gEntityManager.registerSystem!MoveSystem(0); + gEntityManager.registerSystem!DrawSystem(100); + gEntityManager.registerSystem!InputMovementSystem(-100); + //gEntityManager.registerSystem!MovementSystem(-99); + gEntityManager.registerSystem!MoveSystem(-99); + gEntityManager.registerSystem!ClampPositionSystem(-90); + gEntityManager.registerSystem!ShootingSystem(0); + gEntityManager.registerSystem!ChangeDirectionSystem(0); + gEntityManager.registerSystem!BulletsCollisionSystem(-70); + gEntityManager.registerSystem!ShootGridManager(-80); + gEntityManager.registerSystem!ShootGridCleaner(-101); + gEntityManager.registerSystem!HitPointsSystem(0); + gEntityManager.registerSystem!HitMarkingSystem(-100); + gEntityManager.registerSystem!UpgradeCollisionSystem(-70); + gEntityManager.registerSystem!UpgradeSystem(-100); + gEntityManager.registerSystem!ParticleSystem(-100); + gEntityManager.registerSystem!AnimationSystem(-100); + gEntityManager.registerSystem!DampingSystem(-101); + gEntityManager.registerSystem!MoveToParentTargetSystem(-98); + gEntityManager.registerSystem!ParentOwnerSystem(-101); + gEntityManager.registerSystem!ShipWeaponSystem(-100); + gEntityManager.registerSystem!ParticleEmittingSystem(-95); + gEntityManager.registerSystem!RotateToTargetSystem(-100); + gEntityManager.registerSystem!ShipTargetSystem(-110); + gEntityManager.registerSystem!CShipIterator(-100); + gEntityManager.registerSystem!PartsDestroySystem(-80); + gEntityManager.registerSystem!ChildDestroySystem(-110); + gEntityManager.registerSystem!ShootWaveSystem(-100); + //gEntityManager.registerSystem!SpawnUponDeathSystem(-110); + gEntityManager.registerSystem!CollisionMaskSystem(-100); - launcher.manager.endRegister(); + gEntityManager.endRegister(); } void spaceInvadersStart() @@ -2146,9 +2096,9 @@ void spaceInvadersStart() // space_invaders.shoot_grid = Mallocator.make!ShootGrid; // space_invaders.shoot_grid.create(ivec2(80,60), vec2(5,5)); - space_invaders.shoot_grid = launcher.manager.getSystem!ShootGridManager().grid; + space_invaders.shoot_grid = gEntityManager.getSystem!ShootGridManager().grid; - DrawSystem* draw_system = launcher.manager.getSystem!DrawSystem; + DrawSystem* draw_system = gEntityManager.getSystem!DrawSystem; draw_system.default_data.color = 0x80808080; draw_system.default_data.texture = space_invaders.texture; @@ -2216,9 +2166,9 @@ void spaceInvadersStart() launcher.gui_manager.addSystem(becsID!ShootWaveSystem,"Shoot Wave System"); //launcher.gui_manager.addSystem(becsID!SpawnUponDeathSystem,"Child Destroy System"); - //launcher.manager.getSystem(becsID!CleanSystem).disable(); + //gEntityManager.getSystem(becsID!CleanSystem).disable(); { - space_invaders.ship_tmpl = launcher.manager.allocateTemplate( + space_invaders.ship_tmpl = gEntityManager.allocateTemplate( [becsID!CVelocity, becsID!CColor, becsID!CHitMark, becsID!CHitPoints, becsID!CLocation, becsID!CTexCoords, becsID!CInput, becsID!CShip, becsID!CScale, becsID!CColliderScale, @@ -2234,12 +2184,12 @@ void spaceInvadersStart() space_invaders.ship_tmpl.getComponent!CColliderScale().value = vec2(26,24); space_invaders.ship_tmpl.getComponent!CVelocityFactor().value = vec2(0.5,0.5); - launcher.manager.addEntity(space_invaders.ship_tmpl,[CLocation(vec2(64,64)).ref_].staticArray); + gEntityManager.addEntity(space_invaders.ship_tmpl,[CLocation(vec2(64,64)).ref_].staticArray); } { ushort[6] components = [becsID!CLocation, becsID!CTexCoords, becsID!CVelocity, becsID!CScale, becsID!CBullet, becsID!CGuild]; - space_invaders.laser_tmpl = launcher.manager.allocateTemplate(components); + space_invaders.laser_tmpl = gEntityManager.allocateTemplate(components); space_invaders.laser_tmpl.getComponent!CTexCoords().value = vec4(0,24,2,8)*px; space_invaders.laser_tmpl.getComponent!CScale().value = vec2(2,8); @@ -2255,7 +2205,7 @@ void spaceInvadersStart() EntityID grouped_id; { - boss_tmpl = launcher.manager.allocateTemplate( + boss_tmpl = gEntityManager.allocateTemplate( [becsID!CColor, becsID!CHitMark, becsID!CParts, becsID!CLocation, becsID!CTexCoords, becsID!CScale, becsID!CEnemy, becsID!CBoss, becsID!CGuild, becsID!CInit, @@ -2278,7 +2228,7 @@ void spaceInvadersStart() } { - tower_tmpl = launcher.manager.allocateTemplate( + tower_tmpl = gEntityManager.allocateTemplate( [becsID!CColor, becsID!CHitMark, becsID!CHitPoints, becsID!CLocation, becsID!CTexCoords, becsID!CScale, becsID!CEnemy, becsID!CShootGrid, becsID!CGuild, becsID!CInit, @@ -2292,7 +2242,7 @@ void spaceInvadersStart() } { - space_invaders.enemy_tmpl = launcher.manager.allocateTemplate( + space_invaders.enemy_tmpl = gEntityManager.allocateTemplate( [becsID!CWeaponLocation, becsID!CColor, becsID!CHitMark, becsID!CHitPoints, becsID!CVelocity, becsID!CAutoShoot, becsID!CLocation, becsID!CTexCoords, becsID!CScale, becsID!CWeapon, @@ -2308,81 +2258,81 @@ void spaceInvadersStart() Entity* current_entity; - current_entity = launcher.manager.addEntity(space_invaders.enemy_tmpl,[CLocation(vec2(32,space_invaders.map_size.y - 16)).ref_].staticArray); - launcher.manager.addComponents(current_entity.id,CSideMove(0)); + current_entity = gEntityManager.addEntity(space_invaders.enemy_tmpl,[CLocation(vec2(32,space_invaders.map_size.y - 16)).ref_].staticArray); + gEntityManager.addComponents(current_entity.id,CSideMove(0)); //loc_comp.value = vec2(128,space_invaders.map_size.y - 16); - current_entity = launcher.manager.addEntity(space_invaders.enemy_tmpl,[CLocation(vec2(128,space_invaders.map_size.y - 16)).ref_].staticArray); - launcher.manager.addComponents(current_entity.id,CSideMove(-1)); + current_entity = gEntityManager.addEntity(space_invaders.enemy_tmpl,[CLocation(vec2(128,space_invaders.map_size.y - 16)).ref_].staticArray); + gEntityManager.addComponents(current_entity.id,CSideMove(-1)); enemy_id = current_entity.id; - //enemy_tmpl = launcher.manager.allocateTemplate(current_entity.id); + //enemy_tmpl = gEntityManager.allocateTemplate(current_entity.id); //loc_comp.value = vec2(256,space_invaders.map_size.y - 16); - launcher.manager.addEntity(space_invaders.enemy_tmpl,[CLocation(vec2(256,space_invaders.map_size.y - 16)).ref_].staticArray); + gEntityManager.addEntity(space_invaders.enemy_tmpl,[CLocation(vec2(256,space_invaders.map_size.y - 16)).ref_].staticArray); //loc_comp.value = vec2(0,space_invaders.map_size.y - 16); - current_entity = launcher.manager.addEntity(space_invaders.enemy_tmpl,[CLocation(vec2(0,space_invaders.map_size.y - 16)).ref_].staticArray); - launcher.manager.addComponents(current_entity.id,CSideMove(0)); + current_entity = gEntityManager.addEntity(space_invaders.enemy_tmpl,[CLocation(vec2(0,space_invaders.map_size.y - 16)).ref_].staticArray); + gEntityManager.addComponents(current_entity.id,CSideMove(0)); grouped_id = current_entity.id; - //grouped_tmpl = launcher.manager.allocateTemplate(current_entity.id); + //grouped_tmpl = gEntityManager.allocateTemplate(current_entity.id); } EntityTemplate* upgrade_tmpl; { - upgrade_tmpl = launcher.manager.allocateTemplate([becsID!CVelocity, becsID!CLocation, becsID!CTexCoords, becsID!CScale, becsID!CUpgrade, becsID!CAnimationLooped, becsID!CAnimation].staticArray); + upgrade_tmpl = gEntityManager.allocateTemplate([becsID!CVelocity, becsID!CLocation, becsID!CTexCoords, becsID!CScale, becsID!CUpgrade, becsID!CAnimationLooped, becsID!CAnimation].staticArray); upgrade_tmpl.getComponent!CTexCoords().value = vec4(0,32,16,16)*px; upgrade_tmpl.getComponent!CVelocity().value = vec2(0,-0.05); *upgrade_tmpl.getComponent!CAnimation = CAnimation(HitPointsSystem.upgrade_laser_frames, 0, 0.75); } - launcher.manager.commit(); + gEntityManager.commit(); - enemy_tmpl = launcher.manager.allocateTemplate(enemy_id); - grouped_tmpl = launcher.manager.allocateTemplate(grouped_id); + enemy_tmpl = gEntityManager.allocateTemplate(enemy_id); + grouped_tmpl = gEntityManager.allocateTemplate(grouped_id); - space_invaders.bullet_tmpl[0] = launcher.manager.allocateTemplate( + space_invaders.bullet_tmpl[0] = gEntityManager.allocateTemplate( [becsID!CLocation, becsID!CTexCoords, becsID!CVelocity, becsID!CScale, becsID!CBullet, becsID!CGuild].staticArray ); space_invaders.bullet_tmpl[0].getComponent!CTexCoords().value = vec4(0,24,2,8)*px; space_invaders.bullet_tmpl[0].getComponent!CScale().value = vec2(2,8); - space_invaders.bullet_tmpl[1] = launcher.manager.allocateTemplate(space_invaders.bullet_tmpl[0]); - space_invaders.bullet_tmpl[2] = launcher.manager.allocateTemplate(space_invaders.bullet_tmpl[0]); + space_invaders.bullet_tmpl[1] = gEntityManager.allocateTemplate(space_invaders.bullet_tmpl[0]); + space_invaders.bullet_tmpl[2] = gEntityManager.allocateTemplate(space_invaders.bullet_tmpl[0]); space_invaders.bullet_tmpl[2].getComponent!CTexCoords().value = vec4(64,32,8,16)*px; space_invaders.bullet_tmpl[2].getComponent!CScale().value = vec2(8,16); - space_invaders.bullet_tmpl[3] = launcher.manager.allocateTemplate(space_invaders.bullet_tmpl[0]); + space_invaders.bullet_tmpl[3] = gEntityManager.allocateTemplate(space_invaders.bullet_tmpl[0]); space_invaders.bullet_tmpl[3].getComponent!CTexCoords().value = vec4(56,32,2,2)*px; space_invaders.bullet_tmpl[3].getComponent!CScale().value = vec2(2,2); // bullet_tmpl[3].getComponent!CTexCoords().value = vec4(48,32,8,8)*px; // bullet_tmpl[3].getComponent!CScale().value = vec2(8,8); - space_invaders.bullet_tmpl[4] = launcher.manager.allocateTemplate(space_invaders.bullet_tmpl[0]); + space_invaders.bullet_tmpl[4] = gEntityManager.allocateTemplate(space_invaders.bullet_tmpl[0]); launcher.gui_manager.addTemplate(enemy_tmpl,"Enemy"); launcher.gui_manager.addTemplate(grouped_tmpl,"Grouped enemy"); - launcher.gui_manager.addTemplate(launcher.manager.allocateTemplate(space_invaders.ship_tmpl),"Ship"); - launcher.gui_manager.addTemplate(launcher.manager.allocateTemplate(space_invaders.laser_tmpl),"Laser"); + launcher.gui_manager.addTemplate(gEntityManager.allocateTemplate(space_invaders.ship_tmpl),"Ship"); + launcher.gui_manager.addTemplate(gEntityManager.allocateTemplate(space_invaders.laser_tmpl),"Laser"); launcher.gui_manager.addTemplate(upgrade_tmpl,"Upgrade"); launcher.gui_manager.addTemplate(tower_tmpl,"Tower"); launcher.gui_manager.addTemplate(boss_tmpl,"Boss"); - launcher.gui_manager.addTemplate(launcher.manager.allocateTemplate(space_invaders.bullet_tmpl[3]),"Cannon bullet"); - //launcher.gui_manager.addTemplate(launcher.manager.allocateTemplate(space_invaders.bullet_tmpl[4]),"Laser"); - //launcher.gui_manager.addTemplate(launcher.manager.allocateTemplate(space_invaders.bullet_tmpl[5]),"Laser"); + launcher.gui_manager.addTemplate(gEntityManager.allocateTemplate(space_invaders.bullet_tmpl[3]),"Cannon bullet"); + //launcher.gui_manager.addTemplate(gEntityManager.allocateTemplate(space_invaders.bullet_tmpl[4]),"Laser"); + //launcher.gui_manager.addTemplate(gEntityManager.allocateTemplate(space_invaders.bullet_tmpl[5]),"Laser"); } void spaceInvadersEnd() { - /*launcher.manager.getSystem(becsID!DrawSystem).disable(); - launcher.manager.getSystem(becsID!InputMovementSystem).disable(); - launcher.manager.getSystem(becsID!ShootingSystem).disable(); - launcher.manager.getSystem(becsID!MovementSystem).disable(); - launcher.manager.getSystem(becsID!ClampPositionSystem).disable(); - launcher.manager.getSystem(becsID!ShootGridCleaner).disable();*/ + /*gEntityManager.getSystem(becsID!DrawSystem).disable(); + gEntityManager.getSystem(becsID!InputMovementSystem).disable(); + gEntityManager.getSystem(becsID!ShootingSystem).disable(); + gEntityManager.getSystem(becsID!MovementSystem).disable(); + gEntityManager.getSystem(becsID!ClampPositionSystem).disable(); + gEntityManager.getSystem(becsID!ShootGridCleaner).disable();*/ - //launcher.manager.freeTemplate(space_invaders.enemy_tmpl); + //gEntityManager.freeTemplate(space_invaders.enemy_tmpl); Mallocator.dispose(space_invaders); space_invaders = null; } @@ -2404,13 +2354,13 @@ bool spaceInvadersLoop() { if(igCheckbox("Move system",&simple.move_system)) { - if(simple.move_system)launcher.manager.getSystem(becsID!MoveSystem).enable(); - else launcher.manager.getSystem(becsID!MoveSystem).disable(); + if(simple.move_system)gEntityManager.getSystem(becsID!MoveSystem).enable(); + else gEntityManager.getSystem(becsID!MoveSystem).disable(); } if(igCheckbox("Draw system",&simple.draw_system)) { - if(simple.draw_system)launcher.manager.getSystem(becsID!DrawSystem).enable(); - else launcher.manager.getSystem(becsID!DrawSystem).disable(); + if(simple.draw_system)gEntityManager.getSystem(becsID!DrawSystem).enable(); + else gEntityManager.getSystem(becsID!DrawSystem).disable(); } igPushButtonRepeat(true); igColumns(3,null,0); @@ -2432,11 +2382,11 @@ bool spaceInvadersLoop() igColumns(1,null,0); if(igButton("Clear",ImVec2(-1,0))) { - launcher.manager.getSystem(becsID!CleanSystem).enable(); - launcher.manager.begin(); - launcher.manager.update(); - launcher.manager.end(); - launcher.manager.getSystem(becsID!CleanSystem).disable(); + gEntityManager.getSystem(becsID!CleanSystem).enable(); + gEntityManager.begin(); + gEntityManager.update(); + gEntityManager.end(); + gEntityManager.getSystem(becsID!CleanSystem).disable(); } } igEnd(); @@ -2453,18 +2403,18 @@ bool spaceInvadersLoop() igEnd(); }*/ - launcher.manager.begin(); + gEntityManager.begin(); if(launcher.multithreading) { launcher.job_updater.begin(); - launcher.manager.updateMT(); + gEntityManager.updateMT(); launcher.job_updater.call(); } else { - launcher.manager.update(); + gEntityManager.update(); } - launcher.manager.end(); + gEntityManager.end(); /*foreach(i;0..1000)//13000) { diff --git a/demos/source/game_core/basic.d b/demos/source/game_core/basic.d index ec32d87..feaa9ed 100644 --- a/demos/source/game_core/basic.d +++ b/demos/source/game_core/basic.d @@ -13,33 +13,39 @@ import app : launcher; import bindbc.sdl; +//position component struct CLocation { + //adds some extra functionality. Not required. Will be probably removed from library in the future. mixin ECS.Component; - alias value this; + alias value this;//use component as it value + //default values work properly vec2 value = vec2(0); } +//scale component struct CScale { mixin ECS.Component; - alias value this;///use component as it value + alias value this;//use component as it value vec2 value = vec2(16,16); } +//rotation component struct CRotation { mixin ECS.Component; - alias value this;///use component as it value + alias value this;//use component as it value float value = 0; } +//depth component. Entity with higher depth will be rendered on top struct CDepth { mixin ECS.Component; @@ -49,6 +55,7 @@ struct CDepth short value; } +//color component struct CColor { mixin ECS.Component; @@ -58,6 +65,7 @@ struct CColor @GUIColor uint value; } +//component used for selection struct CSelected { mixin ECS.Component; @@ -65,11 +73,13 @@ struct CSelected bool value = false; } +//component indicating that entity should receive input from mouse, keyboard, etc. struct CInput { mixin ECS.Component; } +//component with damping value struct CDamping { mixin ECS.Component; @@ -79,6 +89,7 @@ struct CDamping @GUIRange(0,9) byte value = 1; } +//velocity component struct CVelocity { mixin ECS.Component; @@ -88,6 +99,7 @@ struct CVelocity vec2 value = vec2(0,0); } +//factor which is used for velocity masking struct CVelocityFactor { mixin ECS.Component; @@ -97,30 +109,35 @@ struct CVelocityFactor vec2 value = vec2(1); } +//flag indicating that entity is static and shouldn't be updated by most systems in every frame struct CStatic { mixin ECS.Component; } +//system which slowing down entities struct DampingSystem { + //system will generate up to 32 jobs mixin ECS.System!32; struct EntitiesData { uint length; - const (Entity)[] entity; - @readonly CDamping[] damping; - CVelocity[] velocity; + const (Entity)[] entity; //entity is readonly + @readonly CDamping[] damping;//damping is readonly. Marking with @readonly will help multithreading algorithm + CVelocity[] velocity;//velocity is wirtable as it will be modified for entities in this system } + //20 predefined damping speeds. Gives possibility to store damping as single byte. float[20] damp = 0; bool onBegin() { + //calculate damping values foreach(i;0..20) { - damp[i] = powf((0.99 - cast(float)i * 0.01),launcher.delta_time*0.1); + damp[i] = powf((0.99 - cast(float)i * 0.01),launcher.deltaTime*0.1); } return true; @@ -130,11 +147,13 @@ struct DampingSystem { foreach(i; 0..data.length) { + //constantly slow down entity data.velocity[i] = data.velocity[i] * damp[data.damping[i]]; } } } +//system used for entity movement struct MoveSystem { mixin ECS.System!64; @@ -144,23 +163,24 @@ struct MoveSystem uint length; CLocation[] location; @readonly CVelocity[] velocity; - @optional @readonly CVelocityFactor[] vel_factor; + @optional @readonly CVelocityFactor[] vel_factor;//CVeclocityFactor is not required so entites without this component will be also updated } void onUpdate(EntitiesData data) { + //split into two loops for two types of entities. Doing it in "normal" way by testing data.vel_factor inside loop in every iteration will be probably compiled as same machine code in release build (it works in LDC) if(data.vel_factor) { foreach(i; 0..data.length) { - data.location[i] += data.velocity[i] * data.vel_factor[i] * launcher.delta_time; + data.location[i] += data.velocity[i] * data.vel_factor[i] * launcher.deltaTime; } } else { foreach(i; 0..data.length) { - data.location[i] += data.velocity[i] * launcher.delta_time; + data.location[i] += data.velocity[i] * launcher.deltaTime; } } } @@ -228,32 +248,13 @@ struct InputMovementSystem */ void onUpdate(EntitiesData data) { - /*if(move_vector.x == 0) - { - foreach(i; 0..data.length) - { - data.textures[i].coords = vec4(0*px,80*px,48*px,32*px); - } - //return; - }*/ - //move every entity using movement vector - //if(move_vector.x != 0 || move_vector.y != 0) foreach(i; 0..data.length) { - data.velocity[i] += move_vector * launcher.delta_time * 0.005; + data.velocity[i] += move_vector * launcher.deltaTime * 0.005; if(data.velocity[i].x > 0.5)data.velocity[i].x = 0.5; else if(data.velocity[i].x < -0.5)data.velocity[i].x = -0.5; if(data.velocity[i].y > 0.5)data.velocity[i].y = 0.5; else if(data.velocity[i].y < -0.5)data.velocity[i].y = -0.5; - //data.locations[i].x += move_vector.x * launcher.delta_time * 0.25; - //data.locations[i].y += move_vector.y * launcher.delta_time * 0.25; - //if(move_vector.x > 0)data.textures[i].coords = vec4(48*px,80*px,48*px,32*px); - //else data.textures[i].coords = vec4(0*px,80*px,48*px,32*px); } - /*else - foreach(i; 0..data.length) - { - data.velocity[i] = vec2(0,0); - }*/ } } \ No newline at end of file diff --git a/demos/source/game_core/job_updater.d b/demos/source/game_core/job_updater.d index 025da6e..1389c45 100644 --- a/demos/source/game_core/job_updater.d +++ b/demos/source/game_core/job_updater.d @@ -3,11 +3,8 @@ module game_core.job_updater; import bubel.ecs.std; import bubel.ecs.vector; import bubel.ecs.atomic; - -import ecs_utils.utils; - -//import core.time; import bubel.ecs.manager; + import mmutils.thread_pool; version(LDC) @@ -21,8 +18,6 @@ else } } -//import supre.core.call_graph_generator; - struct ECSJobUpdater { @@ -33,30 +28,15 @@ struct ECSJobUpdater ~this() { + //wait for end of jobs pool.waitThreads(); - //pool.unregistExternalThread(thread_data); + //dispose jobs array if(jobs)Mallocator.dispose(jobs); + //free TLS data version(WebAssembly)pthread_key_delete(tls_key); else version(Android)pthread_key_delete(tls_key); } - version(WebAssembly) - { - __gshared pthread_key_t tls_key; - } - else version(Android) - { - __gshared pthread_key_t tls_key; - } - else static uint thread_id = 0; - - ThreadPool pool; - ThreadData* thread_data; - - int job_id = 0; - int no_dep_count = 0; - //static uint thread_id = 0; - struct Group { ~this() nothrow @@ -65,33 +45,40 @@ struct ECSJobUpdater } JobsGroup group; - JobData[1024] jobs; - JobCaller[1024] callers; + //each group can have up to 128 jobs + JobData[128] jobs; + JobCaller[128] callers; uint count = 0; string name; + //mmutils.ThreadPool uses system of dependency where dependencies are added for child groups. + //Parent group has atomic counter and after completition it will add job groups dependant on it. void dependantOn(Group* dependency) { group.dependantOn(&dependency.group); } + //add group to pool void start() { group.thPool.addGroupAsynchronous(&group); } + //add jobs slice to group structure void build(ThreadPool* pool) { group.thPool = pool; group.jobs = jobs[0..count]; } + //clear jobs void clear() { group = JobsGroup("name",null); count = 0; } + //add single job to group void add(JobCaller caller) { callers[count] = caller; @@ -100,15 +87,10 @@ struct ECSJobUpdater } } - Group[] jobs; - Vector!(Group*) call_jobs; - Group last_job; - JobData[1] groupEndJobs; - - //TrackData[32] trackers; - + //initialize thread pool and data void onCreate(uint threads_count) { + //create TLS for Android and WebAsssembly version(WebAssembly)pthread_key_create(&tls_key, null); else version(Android)pthread_key_create(&tls_key, null); @@ -119,6 +101,7 @@ struct ECSJobUpdater jobs = Mallocator.makeArray!Group(256); } + //this function are providingn ThreadID to ECS. BubelECS is expecting ThreadID to be linear ID in range (0;ThreadsCount) uint getThreadID() @nogc nothrow { version(WebAssembly)return cast(int)pthread_getspecific(tls_key); @@ -126,9 +109,9 @@ struct ECSJobUpdater else return thread_id; } + //clear jobs data void begin() { - job_id = 0; call_jobs.clear(); foreach(ref job;jobs) @@ -139,68 +122,57 @@ struct ECSJobUpdater last_job.clear(); } - void clearTracker() - { - //foreach(ref tracker;trackers)tracker.clear(); - } - - @optStrategy("none") - void nop() - { - int i; - i++; - } - - //@optStrategy("none") + //execute jobs void call() { + //if there is no work return if(last_job.group.getDependenciesWaitCount() == 0)return; if(call_jobs.length == 0)return; - //JobData[1] groupEndJobs; + //set last job groupEndJobs[0] = JobData(&releaseMainThread, "Stop Threads", null, null); + //add job to group last_job.group.jobs = groupEndJobs; + //set thread pool pointer last_job.group.thPool = &pool; + //last job should be called on main thread. It prevent some issues with death loops. last_job.group.executeOnThreadNum = 0; + //start jobs without dependencies foreach(job;call_jobs) { job.start(); } - - /*while(atomicLoad(ret) == 1)//!cas(&ret,0,1)) - { - nop(); - version(WebAssembly)//emscripten_main_thread_process_queued_calls(); - }//*/ - + + //add main thread to pool. It will be released in last job. thread_data.threadStartFunc(); } + //callback that will release main thread void releaseMainThread(ThreadData* th_data, JobData* data) { - //atomicStore(ret,0); pool.releaseExternalThreads(); } static struct JobCaller { + //ECS job EntityManager.Job* job; + //pointer to parent ECSJobUpdater* updater; + //job ID uint id; + //called by external thread void callJob(ThreadData* th_data, JobData* data) { - - //uint job_id = updater.getThreadID(); - //updater.trackers[job_id].begin(id); version(WebAssembly) { - //updater.thread_id = th_data.threadId; pthread_setspecific(tls_key, cast(void*)th_data.threadId); if(th_data.threadId == 0) { + //this emscripten call is required to make multithreading working emscripten_main_thread_process_queued_calls(); job.execute(); emscripten_main_thread_process_queued_calls(); @@ -214,23 +186,27 @@ struct ECSJobUpdater } else { + //set thread id updater.thread_id = th_data.threadId; + //execture job. It's the function from BubelECS job.execute(); } - //atomicOp!"-="(updater.jobs_count,1); - //updater.trackers[job_id].end(); } } + //this is callback passed to EntityManager. EntityManager will call this for every jobs group. Every system will generate one group. void dispatch(EntityManager.JobGroup group) { + //check if group isn't empty if(group.jobs.length == 0) { return; } + //add name for job. Used for traces. jobs[group.id].name = cast(string)group.caller.system.name; + //add jobs to group foreach(ref job;group.jobs) { uint index = 0; @@ -242,21 +218,51 @@ struct ECSJobUpdater jobs[group.id].add(caller); } + //build group jobs[group.id].build(&pool); uint deps = cast(uint)group.dependencies.length; + //add dependencies foreach(dep;group.dependencies) { if(jobs[dep.id].count && dep.caller.system.willExecute && dep.caller.system.enabled)jobs[group.id].dependantOn(&jobs[dep.id]); else deps--; } + //set as job without dependencies if it hasn't any if(deps == 0) { call_jobs.add(&jobs[group.id]); } + //last job is dependant on all jobs so it will be called after everything will be finished last_job.dependantOn(&jobs[group.id]); } + + //Webassembly version works properly only when there is no thread local data (static variables). + //Because of that I'm using pthread tls instead of D. TLS is used only for storing ThreadID + version(WebAssembly) + { + __gshared pthread_key_t tls_key; + } + else version(Android) + { + __gshared pthread_key_t tls_key; + } + else static uint thread_id = 0; + + //thread pool + ThreadPool pool; + //thread data used for main thread + ThreadData* thread_data; + + //array of jobs + Group[] jobs; + //list of jobs which should be called on frame start as they have no dependencies + Vector!(Group*) call_jobs; + //last job group is used for releasing main thread from pool + Group last_job; + //last_job group has one job + JobData[1] groupEndJobs; } \ No newline at end of file diff --git a/demos/source/gui/manager.d b/demos/source/gui/manager.d index b3f758b..7720b79 100644 --- a/demos/source/gui/manager.d +++ b/demos/source/gui/manager.d @@ -58,7 +58,7 @@ struct GUIManager { foreach(tmpl; templates) { - launcher.manager.freeTemplate(tmpl.tmpl); + gEntityManager.freeTemplate(tmpl.tmpl); } foreach(comp; components) { @@ -102,14 +102,14 @@ struct GUIManager { if(sys.id == id)return; } - System* system = launcher.manager.getSystem(id); + System* system = gEntityManager.getSystem(id); //const (char)* name = systems.add(SystemGUI(name,id,enabled)); } void addTemplate(ushort[] components, const (char)* name) { - templates.add(TemplateGUI(name, launcher.manager.allocateTemplate(components))); + templates.add(TemplateGUI(name, gEntityManager.allocateTemplate(components))); } void addTemplate(EntityTemplate* tmpl, const (char)* name) @@ -258,7 +258,7 @@ struct GUIManager { if(igCheckbox(system.name,&system.enabled)) { - System* sys = launcher.manager.getSystem(system.id); + System* sys = gEntityManager.getSystem(system.id); if(system.enabled)sys.enable(); else sys.disable(); } From c69d58ed693c890b51cc9d375acd981f671ce4bb Mon Sep 17 00:00:00 2001 From: Mergul Date: Tue, 2 Mar 2021 21:23:06 +0100 Subject: [PATCH 184/217] -deploy only on master commit --- .gitlab-ci.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 376aead..121511c 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -90,12 +90,14 @@ emscripten: pages: stage: deploy image: frolvlad/alpine-glibc + dependencies: + - build_emscripten script: - mkdir public - cp -r wasm/* public/ - cp -r build/public/* public/ rules: - - if: '$CI_MERGE_REQUEST_TARGET_BRANCH_NAME == "master"' + - if: '$CI_COMMIT_BRANCH == "master"' when: always artifacts: expire_in: 1h From efd3d64eac67792e484e4978aba992ca308da712 Mon Sep 17 00:00:00 2001 From: Mergul Date: Tue, 2 Mar 2021 21:26:22 +0100 Subject: [PATCH 185/217] -fixed CI typo --- .gitlab-ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 121511c..3fea314 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -91,7 +91,7 @@ pages: stage: deploy image: frolvlad/alpine-glibc dependencies: - - build_emscripten + - emscripten script: - mkdir public - cp -r wasm/* public/ From 34a1066cfbdbbe7756cdbfdf2b35f36cf1ba518f Mon Sep 17 00:00:00 2001 From: Mergul Date: Tue, 2 Mar 2021 21:35:25 +0100 Subject: [PATCH 186/217] -fixed README formating --- README.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index e4c2d77..00dd00a 100644 --- a/README.md +++ b/README.md @@ -149,10 +149,10 @@ struct UpdateSystem void main() { - //initialize ECS - EntityManager.initialize(); + //initialize ECS + EntityManager.initialize(); - //begin registering process + //begin registering process gEntityManager.beginRegister(); //register components gEntityManager.registerComponent!Position; @@ -160,7 +160,7 @@ void main() gEntityManager.registerComponent!StaticFlag; //register system with priority 0 gEntityManager.registerSystem!UpdateSystem(0); - //end registering process + //end registering process gEntityManager.endRegister(); //allocate template @@ -180,8 +180,8 @@ void main() gEntityManager.update(); //update all systems, there onUpdate callbacks are called gEntityManager.end(); //end frame, inside system onEnd callbacks are called*/ - //free ECS data - EntityManager.destroy(); + //free ECS data + EntityManager.destroy(); } ``` From 83cf803d0b0efb05d139783fab3a55ecdb73cb28 Mon Sep 17 00:00:00 2001 From: Dawid Masiukiewicz Date: Tue, 2 Mar 2021 20:52:10 +0000 Subject: [PATCH 187/217] Update .gitlab-ci.yml --- .gitlab-ci.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 3fea314..bd60ef1 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -68,7 +68,7 @@ build_wasm: paths: - build rules: - - if: '$CI_MERGE_REQUEST_TARGET_BRANCH_NAME == "master"' + - if: '$CI_MERGE_REQUEST_TARGET_BRANCH_NAME == "master" || $CI_COMMIT_BRANCH == "master"' when: always allow_failure: true @@ -80,7 +80,7 @@ emscripten: script: - /bin/bash /build.sh rules: - - if: '$CI_MERGE_REQUEST_TARGET_BRANCH_NAME == "master"' + - if: '$CI_MERGE_REQUEST_TARGET_BRANCH_NAME == "master" || $CI_COMMIT_BRANCH == "master"' when: always artifacts: expire_in: 1h @@ -102,4 +102,4 @@ pages: artifacts: expire_in: 1h paths: - - public \ No newline at end of file + - public From 9b3602b6abe7630154f79bb394916c40037b5ba0 Mon Sep 17 00:00:00 2001 From: Dawid Masiukiewicz Date: Wed, 3 Mar 2021 08:19:37 +0000 Subject: [PATCH 188/217] Update .gitlab-ci.yml --- .gitlab-ci.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index bd60ef1..0cf2092 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -91,6 +91,7 @@ pages: stage: deploy image: frolvlad/alpine-glibc dependencies: + - build_wasm - emscripten script: - mkdir public From 001f6851ee9ce0789c6bbde4ab5316fe488b9831 Mon Sep 17 00:00:00 2001 From: Dawid Masiukiewicz Date: Wed, 3 Mar 2021 09:15:14 +0000 Subject: [PATCH 189/217] Update .gitlab-ci.yml --- .gitlab-ci.yml | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 0cf2092..498f834 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -6,6 +6,7 @@ stages: - build - test - testcov + - build_wasm - build_emscripten - deploy @@ -57,8 +58,8 @@ coverage_test_dmd: after_script: - bash <(curl -s https://codecov.io/bash) -s reports -t 1a0c0169-a721-4085-8252-fed4755dcd8c -build_wasm: - stage: build +wasm: + stage: build_wasm image: "registry.gitlab.com/mergul/bubel-ecs:latest" script: - /bin/bash /compile_wasm.sh @@ -76,7 +77,7 @@ emscripten: stage: build_emscripten image: "registry.gitlab.com/mergul/bubel-ecs/emscripten:latest" dependencies: - - build_wasm + - wasm script: - /bin/bash /build.sh rules: @@ -91,7 +92,7 @@ pages: stage: deploy image: frolvlad/alpine-glibc dependencies: - - build_wasm + - wasm - emscripten script: - mkdir public From 1387011b04d546e4ce008695f730271dfa518067 Mon Sep 17 00:00:00 2001 From: Mergul Date: Wed, 3 Mar 2021 10:34:07 +0100 Subject: [PATCH 190/217] -clear ThreadPool code --- demos/external/sources/mmutils/thread_pool.d | 140 ++----------------- 1 file changed, 15 insertions(+), 125 deletions(-) diff --git a/demos/external/sources/mmutils/thread_pool.d b/demos/external/sources/mmutils/thread_pool.d index bd05fe5..ee02974 100644 --- a/demos/external/sources/mmutils/thread_pool.d +++ b/demos/external/sources/mmutils/thread_pool.d @@ -12,11 +12,10 @@ import std.algorithm : map; version = MM_NO_LOGS; // Disable log creation //version = MM_USE_POSIX_THREADS; // Use posix threads insted of standard library, required for betterC -version (Posix)version = MM_USE_POSIX_THREADS; - version (WebAssembly) { version = MM_NO_LOGS; + version = MM_USE_POSIX_THREADS; extern(C) struct FILE { @@ -33,6 +32,7 @@ else version (D_BetterC) { + version (Posix) version = MM_USE_POSIX_THREADS; import bubel.ecs.std; extern (C) __gshared int _d_eh_personality(int, int, size_t, void*, void*) { @@ -55,9 +55,9 @@ else import core.stdc.string; } -////////////////////////////////////////////// -//////////////////// Alloc /////////////////// -////////////////////////////////////////////// +////////////////////////////////////////////////// +//////////////////// Allocator /////////////////// +////////////////////////////////////////////////// T* makeVar(T)(T init) { T* el = cast(T*) malloc(T.sizeof); @@ -120,21 +120,7 @@ long useconds() { version (WebAssembly) { - //import core.sys.posix.sys.time : gettimeofday, timeval; - - /*timeval t; - gettimeofday(&t, null); - - return t.tv_sec * 1_000_000 + t.tv_usec;*/ - - //time_t time; - //timespec spec; - - //lock_gettime(CLOCK_REALTIME, &spec); return cast(long)(emscripten_get_now() * 1000.0); - - //time = spec.tv_sec; - //return spec.tv_sec * 1000_000 + spec.tv_nsec / 1000; } else version (Posix) { @@ -146,6 +132,7 @@ long useconds() } else version (Windows) { + //TODO: implement timer on windows /*import core.sys.windows.windows : QueryPerformanceFrequency; __gshared double mul = -1; @@ -243,7 +230,7 @@ version (MM_USE_POSIX_THREADS) version (WebAssembly) { extern(C): - //alias uint time_t; + struct pthread_attr_t { union @@ -259,19 +246,11 @@ version (MM_USE_POSIX_THREADS) uint x; } - /*struct timespec - { - time_t tv_sec; - int tv_nsec; - }*/ - // pthread int pthread_create(pthread_t*, in pthread_attr_t*, void* function(void*), void*); int pthread_join(pthread_t, void**); void pthread_exit(void *retval); - // semaphore.h - //alias sem_t = void*; struct sem_t { shared int[4] __val; @@ -282,8 +261,6 @@ version (MM_USE_POSIX_THREADS) int sem_post(sem_t*); int sem_destroy(sem_t*); int sem_timedwait(sem_t* sem, const timespec* abstime); - //import core.sys.posix.pthread; - //import core.sys.posix.semaphore; } else version (Posix) { @@ -347,7 +324,6 @@ version (MM_USE_POSIX_THREADS) bool tryWait() { - //return true; int ret = sem_trywait(&mutex); return (ret == 0); } @@ -411,91 +387,7 @@ version (MM_USE_POSIX_THREADS) } else version(D_BetterC) { - version(Posix) - { - import core.sys.posix.pthread; - import core.sys.posix.semaphore; - - struct Semaphore - { - sem_t mutex; - - void initialize() - { - sem_init(&mutex, 0, 0); - } - - void wait() - { - int ret = sem_wait(&mutex); - assert(ret == 0); - } - - bool tryWait() - { - //return true; - int ret = sem_trywait(&mutex); - return (ret == 0); - } - - bool timedWait(int usecs) - { - timespec tv; - // if there is no such a function look at it: https://stackoverflow.com/questions/5404277/porting-clock-gettime-to-windows - clock_gettime(CLOCK_REALTIME, &tv); - tv.tv_sec += usecs / 1_000_000; - tv.tv_nsec += (usecs % 1_000_000) * 1_000; - - int ret = sem_timedwait(&mutex, &tv); - return (ret == 0); - } - - void post() - { - int ret = sem_post(&mutex); - assert(ret == 0); - } - - void destroy() - { - sem_destroy(&mutex); - } - } - - private extern (C) void* threadRunFunc(void* threadVoid) - { - Thread* th = cast(Thread*) threadVoid; - - th.threadStart(); - - pthread_exit(null); - return null; - } - - struct Thread - { - alias DG = void delegate(); - - DG threadStart; - pthread_t handle; - - void start(DG dg) - { - threadStart = dg; - int ok = pthread_create(&handle, null, &threadRunFunc, cast(void*)&this); - if(!ok)handle = pthread_t(); - //assert(ok == 0); - } - - void join() - { - pthread_join(handle, null); - handle = handle.init; - threadStart = null; - } - } - } - else version(Windows) + version(Windows) { import core.stdc.stdint : uintptr_t; import core.sys.windows.windows; @@ -551,15 +443,13 @@ else version(D_BetterC) case WAIT_TIMEOUT: return false; default: - assert(0);//throw new SyncError( "Unable to wait for semaphore" ); + assert(0, "Unable to wait for semaphore" ); } } void post() { assert(ReleaseSemaphore( handle, 1, null )); - //if ( !ReleaseSemaphore( m_hndl, 1, null ) ) - //throw new SyncError( "Unable to notify semaphore" ); } void destroy() @@ -575,7 +465,6 @@ else version(D_BetterC) th.threadStart(); - //(null); ExitThread(0); return 0; } @@ -591,21 +480,22 @@ else version(D_BetterC) { threadStart = dg; handle = cast(HANDLE) _beginthreadex( null, 0, &threadRunFunc, cast(void*)&this, 0, null ); - //int ok = pthread_create(&handle, null, &threadRunFunc, cast(void*)&this); - //assert(handle != null); } void join() { if ( WaitForSingleObject( handle, INFINITE ) == WAIT_OBJECT_0 )assert(0); CloseHandle( handle ); - //pthread_join(handle, null); + handle = handle.init; threadStart = null; } } } - + else + { + static assert(0, "Platform is unsupported in betterC mode!"); + } } else { @@ -674,7 +564,7 @@ else ///////////////// ThreadPool ///////////////// ////////////////////////////////////////////// -private enum gMaxThreadsNum = 32; +private enum gMaxThreadsNum = 64; alias JobDelegate = void delegate(ThreadData*, JobData*); From a3b33a4935e5dbd52b2972237b725436d637b212 Mon Sep 17 00:00:00 2001 From: Mergul Date: Wed, 3 Mar 2021 12:29:59 +0100 Subject: [PATCH 191/217] -fixed LDC demos compilation -clean ThreadPool code -fixed betterC demos compilation --- demos/dub.json | 3 +-- demos/external/sources/mmutils/thread_pool.d | 12 +++++++++--- demos/utils/dub.json | 4 ++-- 3 files changed, 12 insertions(+), 7 deletions(-) diff --git a/demos/dub.json b/demos/dub.json index 417b831..1c1fe65 100644 --- a/demos/dub.json +++ b/demos/dub.json @@ -19,8 +19,7 @@ "libs-linux-x86_64": ["cimgui","SDL2","SDL2_image"], "lflags-linux-x86_64": ["-rpath=libs/linux/x64/","-Llibs/linux/x64/"], "dflags-ldc" : [ - "--ffast-math", - "-enable-cross-module-inlining" + "--ffast-math" ], "configurations" : [ { diff --git a/demos/external/sources/mmutils/thread_pool.d b/demos/external/sources/mmutils/thread_pool.d index ee02974..fb9f369 100644 --- a/demos/external/sources/mmutils/thread_pool.d +++ b/demos/external/sources/mmutils/thread_pool.d @@ -33,8 +33,14 @@ else version (D_BetterC) { version (Posix) version = MM_USE_POSIX_THREADS; - import bubel.ecs.std; - extern (C) __gshared int _d_eh_personality(int, int, size_t, void*, void*) + + extern (C) void free(void*) @nogc nothrow @system; + extern (C) void* malloc(size_t size) @nogc nothrow @system; + extern (C) void* realloc(void*, size_t size) @nogc nothrow @system; + extern (C) void* memcpy(return void*, scope const void*, size_t size) @nogc nothrow @system; + + //hacks for LDC + /*extern (C) __gshared int _d_eh_personality(int, int, size_t, void*, void*) { return 0; } @@ -47,7 +53,7 @@ version (D_BetterC) extern (C) void* _d_allocmemory(size_t sz) { return malloc(sz); - } + }*/ } else { diff --git a/demos/utils/dub.json b/demos/utils/dub.json index d47af9e..749bd4b 100644 --- a/demos/utils/dub.json +++ b/demos/utils/dub.json @@ -29,7 +29,7 @@ "subConfigurations": { "bindbc-sdl": "static", - "ecs":"library" + "bubel_ecs":"library" } }, { @@ -41,7 +41,7 @@ "subConfigurations": { "bindbc-sdl": "staticBC", - "ecs":"library-betterC" + "bubel_ecs":"library-betterC" } } ] From 18b5942b99156376e594d83dde9832132a8dcc5c Mon Sep 17 00:00:00 2001 From: Mergul Date: Wed, 3 Mar 2021 13:13:57 +0100 Subject: [PATCH 192/217] -removed BECS imports from thread pool -make JobUpdater selfcontaining (dependes only on BECS and ThreadPool) --- demos/external/sources/mmutils/thread_pool.d | 131 ++++++++++++++++++- demos/source/game_core/job_updater.d | 21 +++ 2 files changed, 145 insertions(+), 7 deletions(-) diff --git a/demos/external/sources/mmutils/thread_pool.d b/demos/external/sources/mmutils/thread_pool.d index fb9f369..9156674 100644 --- a/demos/external/sources/mmutils/thread_pool.d +++ b/demos/external/sources/mmutils/thread_pool.d @@ -1,12 +1,5 @@ module mmutils.thread_pool; -import bubel.ecs.atomic; - -//import core.stdc.stdio; -//import core.stdc.stdlib : free, malloc, realloc; -//import core.stdc.string : memcpy; - -//import std.stdio; import std.algorithm : map; version = MM_NO_LOGS; // Disable log creation @@ -61,6 +54,130 @@ else import core.stdc.string; } +////////////////////////////////////////////// +/////////////// Atomics ////////////////////// +////////////////////////////////////////////// + +version (ECSEmscripten) +{ + import std.traits; + + enum MemoryOrder + { + acq, + acq_rel, + raw, + rel, + seq + } + + extern (C) ubyte emscripten_atomic_cas_u8(void* addr, ubyte oldVal, ubyte newVal) @nogc nothrow pure; + extern (C) ushort emscripten_atomic_cas_u16(void* addr, ushort oldVal, ushort newVal) @nogc nothrow pure; + extern (C) uint emscripten_atomic_cas_u32(void* addr, uint oldVal, uint newVal) @nogc nothrow pure; + + extern (C) ubyte emscripten_atomic_load_u8(const void* addr) @nogc nothrow pure; + extern (C) ushort emscripten_atomic_load_u16(const void* addr) @nogc nothrow pure; + extern (C) uint emscripten_atomic_load_u32(const void* addr) @nogc nothrow pure; + + extern (C) ubyte emscripten_atomic_store_u8(void* addr, ubyte val) @nogc nothrow pure; + extern (C) ushort emscripten_atomic_store_u16(void* addr, ushort val) @nogc nothrow pure; + extern (C) uint emscripten_atomic_store_u32(void* addr, uint val) @nogc nothrow pure; + + extern (C) ubyte emscripten_atomic_add_u8(void* addr, ubyte val) @nogc nothrow pure; + extern (C) ushort emscripten_atomic_add_u16(void* addr, ushort val) @nogc nothrow pure; + extern (C) uint emscripten_atomic_add_u32(void* addr, uint val) @nogc nothrow pure; + + extern (C) ubyte emscripten_atomic_sub_u8(void* addr, ubyte val) @nogc nothrow pure; + extern (C) ushort emscripten_atomic_sub_u16(void* addr, ushort val) @nogc nothrow pure; + extern (C) uint emscripten_atomic_sub_u32(void* addr, uint val) @nogc nothrow pure; + + public pure nothrow @nogc Unqual!T atomicOp(string op, T, V1)(ref shared T val, V1 mod) + { + static if (op == "+=") + { + static if (is(T == byte) || is(T == ubyte)) + return cast(Unqual!T)(emscripten_atomic_add_u8(cast(void*)&val, + cast(Unqual!T) mod) + 1); + else static if (is(T == short) || is(T == ushort)) + return cast(Unqual!T)(emscripten_atomic_add_u16(cast(void*)&val, + cast(Unqual!T) mod) + 1); + else static if (is(T == int) || is(T == uint)) + return cast(Unqual!T)(emscripten_atomic_add_u32(cast(void*)&val, + cast(Unqual!T) mod) + 1); + else + static assert(0); + } + else static if (op == "-=") + { + static if (is(T == byte) || is(T == ubyte)) + return cast(Unqual!T)(emscripten_atomic_sub_u8(cast(void*)&val, + cast(Unqual!T) mod) - 1); + else static if (is(T == short) || is(T == ushort)) + return cast(Unqual!T)(emscripten_atomic_sub_u16(cast(void*)&val, + cast(Unqual!T) mod) - 1); + else static if (is(T == int) || is(T == uint)) + return cast(Unqual!T)(emscripten_atomic_sub_u32(cast(void*)&val, + cast(Unqual!T) mod) - 1); + else + static assert(0); + } + } + + public pure nothrow @nogc @trusted void atomicStore(MemoryOrder ms = MemoryOrder.seq, T, V)(ref T val, + V newval) + { + alias UT = Unqual!T; + static if (is(UT == bool) || is(UT == byte) || is(UT == ubyte)) + emscripten_atomic_store_u8(cast(void*)&val, cast(UT) newval); + else static if (is(UT == short) || is(UT == ushort)) + emscripten_atomic_store_u16(cast(void*)&val, cast(UT) newval); + else static if (is(UT == int) || is(UT == uint)) + emscripten_atomic_store_u32(cast(void*)&val, cast(UT) newval); + else + static assert(0); + } + + public pure nothrow @nogc @trusted T atomicLoad(MemoryOrder ms = MemoryOrder.seq, T)( + ref const T val) + { + alias UT = Unqual!T; + static if (is(UT == bool)) + return emscripten_atomic_load_u8(cast(const void*)&val) != 0; + else static if (is(UT == byte) || is(UT == ubyte)) + return emscripten_atomic_load_u8(cast(const void*)&val); + else static if (is(UT == short) || is(UT == ushort)) + return emscripten_atomic_load_u16(cast(const void*)&val); + else static if (is(UT == int) || is(UT == uint)) + return emscripten_atomic_load_u32(cast(const void*)&val); + else + static assert(0); + } + + public pure nothrow @nogc @trusted bool cas(MemoryOrder succ = MemoryOrder.seq, + MemoryOrder fail = MemoryOrder.seq, T, V1, V2)(T* here, V1 ifThis, V2 writeThis) + { + alias UT = Unqual!T; + static if (is(UT == bool)) + return emscripten_atomic_cas_u8(cast(void*) here, + cast(Unqual!T) ifThis, cast(Unqual!T) writeThis) == ifThis; + else static if (is(UT == byte) || is(UT == ubyte)) + return emscripten_atomic_cas_u8(cast(void*) here, + cast(Unqual!T) ifThis, cast(Unqual!T) writeThis) == ifThis; + else static if (is(UT == short) || is(UT == ushort)) + return emscripten_atomic_cas_u16(cast(void*) here, + cast(Unqual!T) ifThis, cast(Unqual!T) writeThis) == ifThis; + else static if (is(UT == int) || is(UT == uint)) + return emscripten_atomic_cas_u32(cast(void*) here, + cast(Unqual!T) ifThis, cast(Unqual!T) writeThis) == ifThis; + else + static assert(0); + } +} +else +{ + public import core.atomic; +} + ////////////////////////////////////////////////// //////////////////// Allocator /////////////////// ////////////////////////////////////////////////// diff --git a/demos/source/game_core/job_updater.d b/demos/source/game_core/job_updater.d index 1389c45..adbae4c 100644 --- a/demos/source/game_core/job_updater.d +++ b/demos/source/game_core/job_updater.d @@ -18,6 +18,27 @@ else } } +version(Android) +{ + alias pthread_key_t = uint; + + extern (C) int pthread_key_create(pthread_key_t *, void* function(void *)) @nogc nothrow; + extern (C) int pthread_key_delete(pthread_key_t) @nogc nothrow; + extern (C) void* pthread_getspecific(pthread_key_t) @nogc nothrow; + extern (C) int pthread_setspecific(pthread_key_t, const void *) @nogc nothrow; +} +else version(WebAssembly) +{ + alias pthread_key_t = uint; + + extern (C) int pthread_key_create(pthread_key_t *, void* function(void *)) @nogc nothrow; + extern (C) int pthread_key_delete(pthread_key_t) @nogc nothrow; + extern (C) void* pthread_getspecific(pthread_key_t) @nogc nothrow; + extern (C) int pthread_setspecific(pthread_key_t, const void *) @nogc nothrow; + + extern (C) void emscripten_main_thread_process_queued_calls(); +} + struct ECSJobUpdater { From 20ac07af7f652149cf28d4f1e648fdb8dd55ac3f Mon Sep 17 00:00:00 2001 From: Mergul Date: Wed, 3 Mar 2021 13:31:41 +0100 Subject: [PATCH 193/217] -fixed dub.json for new docker --- dub.json | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/dub.json b/dub.json index 8cf891d..8e2a1b3 100755 --- a/dub.json +++ b/dub.json @@ -50,8 +50,7 @@ ], "dflags": [ "-unittest" - ], - "targetName" : "ecs" + ] }, { "name": "unittest-runner-cov", @@ -65,8 +64,7 @@ "dflags": [ "-unittest", "-cov" - ], - "targetName" : "ecs" + ] }, { "name" : "library-betterC", @@ -129,8 +127,7 @@ "excludedSourceFiles":[ "source\/win_dll.d", "tests/tests.d" - ], - "targetName" : "ecs" + ] } ] } \ No newline at end of file From dd7af911801c98bfe706a30cf96c990c271fe683 Mon Sep 17 00:00:00 2001 From: Mergul Date: Wed, 3 Mar 2021 16:20:27 +0100 Subject: [PATCH 194/217] -change .gitlab-ci.yml --- .gitlab-ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 3fea314..069dcaa 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -40,7 +40,7 @@ test_dmd_betterC: stage: test image: frolvlad/alpine-glibc script: - - binaries/dmd_release_unittest_bc + - binaries/dmd_debug_unittest_bc artifacts: reports: junit: test_report.xml From 37d15f97d608b26388f7c9946e3a3dd9450728ea Mon Sep 17 00:00:00 2001 From: Mergul Date: Sat, 6 Mar 2021 22:00:08 +0100 Subject: [PATCH 195/217] -fixed some meson issues on windows (becs and tests compilation works. Demos not yet) -now tests compile proper files -added setjmp bindings for Windows. It doesn't work on LDC build (singal API could works) --- meson.build | 6 +++++- meson_options.txt | 1 + tests/meson.build | 12 ++++++++++-- tests/runner.d | 45 +++++++++++++++++++++++++++++++++++---------- 4 files changed, 51 insertions(+), 13 deletions(-) diff --git a/meson.build b/meson.build index d5cb683..0aff444 100644 --- a/meson.build +++ b/meson.build @@ -3,10 +3,12 @@ project('decs', 'd', version : '0.5.0') # Options betterC_opt = get_option('betterC') BuildDemos_opt = get_option('BuildDemos') +BuildTests_opt = get_option('BuildTests') LTO_otp = get_option('LTO') summary('betterC enabled', betterC_opt) summary('build demos', BuildDemos_opt) +summary('build tests', BuildTests_opt) summary('LTO enabled', LTO_otp) meson_minimum_version = '>=0.57.1' @@ -65,7 +67,9 @@ decs_dep = declare_dependency( ) # Tests -subdir('tests') +if BuildTests_opt + subdir('tests') +endif # Demos if BuildDemos_opt diff --git a/meson_options.txt b/meson_options.txt index 1ab62f0..335f32b 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -1,3 +1,4 @@ option('betterC', type: 'boolean', value: false) option('BuildDemos', type: 'boolean', value: false) +option('BuildTests', type: 'boolean', value: false) option('LTO', type: 'boolean', value: false) diff --git a/tests/meson.build b/tests/meson.build index dae8536..cfccaa7 100644 --- a/tests/meson.build +++ b/tests/meson.build @@ -1,10 +1,18 @@ tests_src = files( - 'tests.d', + 'access_perf.d', + 'basic.d', + 'bugs.d', + 'id_manager.d', + 'map.d', + 'perf.d', + 'runner.d', + 'time.d', + 'vector.d' ) exe = executable('decs-tests', tests_src, - include_directories : [inc], + include_directories : [inc, include_directories('..')], d_args : args, link_args : link_args, dependencies : decs_dep, diff --git a/tests/runner.d b/tests/runner.d index 83c2288..b779056 100644 --- a/tests/runner.d +++ b/tests/runner.d @@ -3,7 +3,6 @@ module tests.runner; import core.stdc.stdio; import core.stdc.string; -import core.sys.posix.setjmp; import bubel.ecs.vector; import bubel.ecs.simple_vector; @@ -25,11 +24,36 @@ else enum int ASSERTED = 123; enum string OUT_FILE = "test_report.xml"; -static jmp_buf gEnvBuffer; -static AssertInfo gAssertInfo; - version (D_BetterC) { + version(Posix) + { + import core.sys.posix.setjmp; + } + else version(Windows) + { + version(X86) + alias jmp_buf = ubyte[64]; + else version(X86_64) + alias jmp_buf = ubyte[256]; + else version(IA64) + alias jmp_buf = ubyte[512]; + + extern (C) { + int _setjmp(ref jmp_buf); + void longjmp(ref jmp_buf, int); + } + alias setjmp = _setjmp; + } + + static jmp_buf gEnvBuffer; + static AssertInfo gAssertInfo; + + extern (C) void __assert(const char* msg, const char* file, int line) + { + gAssertInfo = AssertInfo(msg, file, line); + longjmp(gEnvBuffer, ASSERTED); + } } else version = notBetterC; @@ -40,12 +64,6 @@ struct AssertInfo int line; } -extern (C) void __assert(const char* msg, const char* file, int line) -{ - gAssertInfo = AssertInfo(msg, file, line); - longjmp(gEnvBuffer, ASSERTED); -} - struct Test { string file; @@ -427,6 +445,13 @@ extern (C) int main(int argc, char** args) } } + static import tests.id_manager; + static import tests.vector; + static import tests.basic; + static import tests.perf; + static import tests.access_perf; + static import tests.bugs; + static import tests.map; TestRunner!(tests.id_manager, tests.vector, tests.basic, tests.perf, tests.access_perf, tests.bugs, tests.map) runner; runner.runTests(include[], exclude[]); From fa0c196c60e0a7e4d226ee5a602ce0de54d21d52 Mon Sep 17 00:00:00 2001 From: Mergul Date: Sat, 6 Mar 2021 22:02:49 +0100 Subject: [PATCH 196/217] -code cleanup -some documentation improvements -README update --- README.md | 52 +++++++++++++++++++++++--------------- source/bubel/ecs/core.d | 1 + source/bubel/ecs/manager.d | 22 +++------------- 3 files changed, 36 insertions(+), 39 deletions(-) diff --git a/README.md b/README.md index 00dd00a..3f52b93 100644 --- a/README.md +++ b/README.md @@ -2,11 +2,11 @@ [![pipeline status](https://gitlab.com/Mergul/bubel-ecs/badges/master/pipeline.svg)](https://gitlab.com/Mergul/bubel-ecs/-/commits/master) [![codecov](https://codecov.io/gl/Mergul/bubel-ecs/branch/master/graph/badge.svg?token=Unm0TJhFoW)](https://codecov.io/gl/Mergul/bubel-ecs) -BubelECS is Entity-Component-System architectural pattern implementation in D language. +**Bubel ECS** is Entity-Component-System architectural pattern implementation in D language. Library aims to delivery fast and flexible architecture for developing games. Library is **@nogc** and **betterC** compatible. WASM is supported thorugh Emscripten. Project haven't any external dependencies. -BubelECS was tested on Linux, Windows, Android and WASM. +Bubel ECS was tested on Linux, Windows, Android and WASM. **Currently library is in beta stage so some significant API changes can appear.** @@ -16,21 +16,21 @@ For core information about Entity-Component-System architectural pattern please Main design principles are: - * **Data oriented design** - components memory is packed into tight block so iterating over entity components is cache friendly - * **Fast and safe EntityID** - every entity is referenced by its unique ID. Accessing by ID is safe even if entity don'y exist. Access by ID is constant time operation. + * **Data oriented design** - components memory is packed into tight blocks so iterating over entity components is cache friendly + * **Fast and safe EntityID** - every entity is referenced by its unique ID. Accessing by ID is safe even if entity doesn't exists. Accessing by ID is constant time operation. * **Multithreading support** - whole library was developed with multithreading in mind. Adding components is thread-friendly so you get usable EntityID as early as possible. Operations like adding or removing components are deferred to end of frame. Dependencies between systems parallel execution are generated automatically. - * **Good logic separation** - system needs information only about components which it's use, there is no relation between systems. Systems can be compiled as multiple separate libraries and used together. + * **Good logic separation** - system needs information only about components which it uses, there is no relation between systems. Systems can be compiled as multiple separate libraries and used together. * **Flexible execution model** - system iterate over entities which meet specified conditions. Components can be marked as required, optional or excluded. Systems are exectued in specific order determined by system priority. * **Builtin events handling** - library has builtin support for event handlig to makes easier communication between different entities. * **Hot-reload** - hot-reloading for systems should be as easy as possible. In other words library should give functionality to support hot-reload of systems and components with minimal work. **(WIP!)**. There are some assumptions that should be considered when developing application: - * Iterating over components is fastest way of access data so it's should be main way of making calculations. - * Using of direct access and events should be used very wisely and minimized. + * Iterating over components throught system ```onUpdate()``` callback is fastest way of access data so it's should be main way of making calculations. + * Using direct access and events should be used very wisely and minimized. * Direct component access is faster than events, because events must buffer memory and call multiple system handler callbacks. - * Components can be used to marking entities, assingment to systems and changing logic of entity in runtime. Using too much component based marking can lead to memory fragmentation and performence drop. - * Systems give great opporunity to separate game logic. Systems can be enabled and disabled easly in runtime. It's can be used to enabling some debug systems if needed. Additionaly this concept makes game logic changes easier to deal with. If you develop your application wisely it should be trivial to change some core logic by changing only several systems or adding some new systems. Every entity can easily takes some behaviour from different entity type by adding several components. + * Components can be used to marking entities, assingment to systems and changing logic of entity in runtime. Using too much component based marking can lead to memory fragmentation and performence drop. + * Systems give great opporunity to separate game logic. Systems can be enabled and disabled easly in runtime. It's can be used to enabling some debug systems if needed. Additionaly this concept makes game logic changes easier to deal with. If you develop your application wisely it should be trivial to change some core logic by changing only several systems or adding some new. Every entity can easily takes some behaviour from different entity type by adding several components. ### Features @@ -40,26 +40,27 @@ There are some assumptions that should be considered when developing application * EntityTemplates * Basic events handling * Easy systems ordering - * Automatic multithreaded jobs generating * Runtime and fast components adding and removing * Listeners for adding and removing entity components inside systems * Update passes * Calling custom callbacks for system entity groups * betterC compatibility * Emscripten compatibility + * Automatic multithreaded jobs generation + * External dependencies - ability to provide dependencies between systems which aren't related to components + * Compatibility with all big compilers: DMD, LDC, GDC. ### Planned - * Worlds - every world works as separate environment. Entities don't with entities from different world. Systems and components should be registered for every world separately. + * Worlds - every world works as separate environment. Entities don't interact with entities from different world. Systems and components should be registered for every world separately. * Hot-reload support - currently only reloading systems (their functions) works. There is possibility to serialize every entity and system, but it's should be provided by library itself with special callbacks and helpers. Additionaly planned is system which helps with taking new EntityID from serialized identifiers. - * External dependencies - ability to provide dependencies between system which isn't related to components. * Static components - this components will have different memory model and can be accessed only directly. It will be slower to access but won't trigger memory copy when component is added. It should fix problem with big components which isn't needed by systems iteration callbacks or is required rarely. - * Better EventManager - there are several optimization and improvements that can be added in the future. + * Better EventManager - there are several optimization and improvements that can be added in the future (e.g. multithreading). * More demos and examples - demo appliaction is very basic now, but in future more minigames and sanbox mode (opportunity to mix many components and systems) are planned. - * C API - in highly depends on amount of work required. Makes possible to use library from different languages. + * C API - it's highly depends on amount of work required. Makes it possible to use library from different languages. * More smaller improvements... -For more information about design and usage feel free to read [documentation](https://mergul.gitlab.io/bubel-ecs/ecs.html)**(WIP)** and [WIKI](https://gitlab.com/Mergul/bubel-ecs/-/wikis/home). +For more information about design and usage feel free to read [documentation](https://mergul.gitlab.io/bubel-ecs/ecs.html) and [WIKI](https://gitlab.com/Mergul/bubel-ecs/-/wikis/home)**(WIP)**. ## Build Instructions @@ -68,7 +69,7 @@ Supported build systems are DUB and Meson. ##### DUB ```shell -#available configurations: library, dynlib, library-betterC, dynlib-betterC +#available configurations: library, dynlib, library-betterC, dynlib-betterC, unittest-runner, unittest-runner-betterC dub build -c library -b release ``` @@ -90,12 +91,22 @@ python compile_wasm.py -opt adrdox -i source/bubel/ecs/ -o docs/ -s skeleton.html ``` -For more detailed build options please check documentation for used build system. - ## Demos -Repository contain demo application. You can check demo [online](https://mergul.gitlab.io/bubel-ecs/ecs_demo.html) or build it form source code using DUB. \ -Online demo support multithreading and page tries to check if client support WASM multithreading or not and loads properly JS and WASM code. It was tested on Chrome, Firefox, Opera, Brave on Linux and Android. On firefox there is problem with multithreaded version so if demo don't works please try to disable shared_memory in browser flags. +Repository contain demo application. You can check demo [online](https://mergul.gitlab.io/bubel-ecs/ecs_demo.html) or build it form source code using Meson. \ +Online demo support multithreading and page tries to check if client support WASM multithreading or not and loads proper JS and WASM code. It was tested on Chrome, Firefox, Opera, Brave on Linux, Windows and Android. On firefox there is problem with multithreaded version so if demo doesn't work please try to disable shared_memory in browser flags. + +Demos uses these libraries: SDL2, SDL2_Image, bindbc-loader, bindbc-sdl, cimgui, glad, mmutils. \ +C++ compiler is required for building dependencies. + +Meson is preferred way of building demos. It will download and compile dependencies automatically. DUB version is used only for library development. Build instructions: + +```shell +#use '-DbetterC=true ' to build betterC code +meson build . -DBuildDemos=true #add '--buildtype=release' to build release code +cd build +ninja +``` ## Code example @@ -189,4 +200,5 @@ void main() ## Links Documentation: https://mergul.gitlab.io/bubel-ecs/ecs.html \ +Wiki: https://gitlab.com/Mergul/bubel-ecs/-/wikis/home \ Online demo: https://mergul.gitlab.io/bubel-ecs/ecs_demo.html diff --git a/source/bubel/ecs/core.d b/source/bubel/ecs/core.d index eceacf8..1a5e711 100644 --- a/source/bubel/ecs/core.d +++ b/source/bubel/ecs/core.d @@ -6,6 +6,7 @@ $(LIST * Component: make component structure * Event: make event structure ) +This mixins are optional and are used to adding some additional capabilities, e.g. ECS.System is used to configuring default number of jobs for system. --- Struct System1 diff --git a/source/bubel/ecs/manager.d b/source/bubel/ecs/manager.d index 2dfbd58..e3ad7bc 100644 --- a/source/bubel/ecs/manager.d +++ b/source/bubel/ecs/manager.d @@ -59,6 +59,9 @@ grouped by component type so entity can be fracted in big memory chunk. There is two types of update: - update(): function used to call update pass. - updateMT(): function used to call update pass multithreaded. This call only generates jobs which must be called by user. + + WARNING! No fileds from EntityManager should be used directly, they are not private for special, advanced things which are not implemented in library. + So if you don't need anything special, simply use only EntityManager methods. */ export struct EntityManager { @@ -1611,11 +1614,6 @@ export struct EntityManager m_thread_id_func = cast(uint delegate() nothrow @nogc) get_id_callback; } - /*export void setJobDispachFunc(void delegate(JobGroup) @nogc nothrow func) nothrow @nogc - { - m_dispatch_jobs = func; - }*/ - /************************************************************************************************************************ Return size of single page (block). Every entity data block has size of page. */ @@ -3762,20 +3760,6 @@ export struct EntityManager return 0; } - /*uint thread_id() @nogc nothrow - { - if (m_thread_id_func) - return (cast(uint delegate() nothrow @nogc) m_thread_id_func)(); - else - return 0; - } - - void thread_id(uint) @nogc nothrow - { - }*/ - - //static uint thread_id; - ThreadData[] threads; Vector!(UpdatePass*) passes; From 2107f3908c537bc1536ff983e23aa80de6f960ee Mon Sep 17 00:00:00 2001 From: Mergul Date: Sat, 6 Mar 2021 23:39:43 +0100 Subject: [PATCH 197/217] -fixed sp,e demos issues and crashes --- demos/source/demos/brick_breaker.d | 7 +++- demos/source/demos/particles.d | 10 ++++- demos/source/demos/snake.d | 17 +++++--- demos/source/demos/space_invaders.d | 43 ++++++++++++++------- demos/source/game_core/collision.d | 5 ++- demos/source/gui/attributes.d | 27 +++++++------ demos/source/gui/component.d | 1 + demos/source/gui/manager.d | 31 ++++++++++++--- demos/utils/source/ecs_utils/gfx/renderer.d | 1 + 9 files changed, 100 insertions(+), 42 deletions(-) diff --git a/demos/source/demos/brick_breaker.d b/demos/source/demos/brick_breaker.d index 05e31f7..2c84036 100644 --- a/demos/source/demos/brick_breaker.d +++ b/demos/source/demos/brick_breaker.d @@ -58,7 +58,7 @@ struct CBall { mixin ECS.Component; - ubyte radius; + //ubyte radius; } struct CHitPoints @@ -394,12 +394,15 @@ void brickBreakerStart() launcher.gui_manager.addComponent(CTexCoords(), "Tex Coords"); launcher.gui_manager.addComponent(CTexCoordsIndex(), "Tex Coords Index"); launcher.gui_manager.addComponent(CVelocity(), "Velocity"); - launcher.gui_manager.addComponent(CInput(), "Velocity"); + launcher.gui_manager.addComponent(CInput(), "Input"); + launcher.gui_manager.addComponent(CPaddle(), "Paddle"); launcher.gui_manager.addComponent(CDamping(), "Damping"); launcher.gui_manager.addComponent(CBall(), "Ball"); launcher.gui_manager.addComponent(CBVH(), "BVH"); launcher.gui_manager.addComponent(CAABB(), "AABB"); launcher.gui_manager.addComponent(CStatic(), "Static Flag"); + launcher.gui_manager.addComponent(CVelocityFactor(), "Velocity Factor"); + launcher.gui_manager.addComponent(CHitPoints(), "Hit Points"); launcher.gui_manager.addSystem(becsID!MoveSystem, "Move System"); launcher.gui_manager.addSystem(becsID!EdgeCollisionSystem, "Edge Collision System"); diff --git a/demos/source/demos/particles.d b/demos/source/demos/particles.d index 963491c..5fc2a09 100644 --- a/demos/source/demos/particles.d +++ b/demos/source/demos/particles.d @@ -402,12 +402,20 @@ void particlesStart() launcher.gui_manager.addSystem(becsID!MouseAttractSystem,"Mouse Attract System"); launcher.gui_manager.addSystem(becsID!DampingSystem,"Damping System"); launcher.gui_manager.addSystem(becsID!ParticleLifeSystem,"Particle Life System"); + launcher.gui_manager.addSystem(becsID!GravitySystem,"Gravity System"); // launcher.gui_manager.addComponent(CColor(),"Color (white)"); // launcher.gui_manager.addComponent(CColor(0xFF101540),"Color (red)"); // launcher.gui_manager.addComponent(CColor(0xFF251010),"Color (blue)"); // launcher.gui_manager.addComponent(CColor(0xFF102010),"Color (green)"); - launcher.gui_manager.addComponent(CColor(0xFF101540),"Color"); + launcher.gui_manager.addComponent(CLocation(),"Location"); + launcher.gui_manager.addComponent(CScale(),"Scale"); + launcher.gui_manager.addComponent(CTexCoords(),"Texture Coords"); + launcher.gui_manager.addComponent(CTexCoordsIndex(),"Texture Coords Index"); + launcher.gui_manager.addComponent(CRotation(),"Rotation"); + launcher.gui_manager.addComponent(CDepth(),"Depth"); + launcher.gui_manager.addComponent(CMaterialIndex(),"Material ID"); + launcher.gui_manager.addComponent(CVelocityFactor(),"Velocity Factor"); launcher.gui_manager.addComponent(CAttractor(0.1),"Attractor"); launcher.gui_manager.addComponent(CForceRange(vec2(5,40)),"ForceRange"); launcher.gui_manager.addComponent(CVelocity(),"Velocity"); diff --git a/demos/source/demos/snake.d b/demos/source/demos/snake.d index 31f2423..78b6d3e 100644 --- a/demos/source/demos/snake.d +++ b/demos/source/demos/snake.d @@ -19,6 +19,7 @@ import ecs_utils.utils; import game_core.basic; +import gui.attributes; //import std.array : staticArray; enum float px = 1.0/512.0; @@ -133,7 +134,7 @@ struct CAnimation mixin ECS.Component; vec4[] frames; - float time = 0; + @GUIRangeF(0,float.max)float time = 0; } //CIlocation is integer location used as grid cell coordination @@ -203,7 +204,7 @@ struct CSnake } Parts parts; - CMovement.Direction direction; + @GUIRange(0,3)CMovement.Direction direction; } //flag for apple @@ -241,7 +242,7 @@ struct CMovement right } - Direction direction; + @GUIRange(0,3)Direction direction; } // struct CInput @@ -373,8 +374,10 @@ struct AnimationRenderSystem draw_data.depth = -1; foreach(i;0..data.length) { + uint frame = cast(uint)(data.animation[i].time); + if(frame >= data.animation[i].frames.length)frame = cast(uint)data.animation[i].frames.length - 1; draw_data.position = data.location[i]; - draw_data.coords = data.animation[i].frames[cast(int)(data.animation[i].time)]; + draw_data.coords = data.animation[i].frames[frame]; launcher.renderer.draw(draw_data); } } @@ -910,8 +913,9 @@ void snakeStart() launcher.gui_manager.addComponent(CParticleVector(vec2(0,1)),"Particle Vector"); launcher.gui_manager.addComponent(CInput(),"Input"); launcher.gui_manager.addComponent(CMovement(CMovement.Direction.up),"Movement"); - //launcher.gui_manager.addComponent(CAnimation(),"Movement"); + launcher.gui_manager.addComponent(CAnimation(),"Animation"); launcher.gui_manager.addComponent(CILocation(),"Int Location"); + launcher.gui_manager.addComponent(CLocation(),"Location"); launcher.gui_manager.addSystem(becsID!MoveSystem,"Move System"); launcher.gui_manager.addSystem(becsID!InputSystem,"Input System"); @@ -922,6 +926,9 @@ void snakeStart() launcher.gui_manager.addSystem(becsID!ParticleMovementSystem,"Particle Movement System"); launcher.gui_manager.addSystem(becsID!DrawAppleSystem,"Draw Apple System"); launcher.gui_manager.addSystem(becsID!DrawSnakeSystem,"Draw Snake System"); + launcher.gui_manager.addSystem(becsID!CopyLocationSystem,"Copy Location System"); + //launcher.gui_manager.addSystem(becsID!AppleSystem,"Apple System"); + //launcher.gui_manager.addSystem(becsID!SnakeSystem,"Snake System"); snake.snake_destroy_particle_frames = Mallocator.makeArray([vec4(64,144,16,16)*px,vec4(80,144,16,16)*px,vec4(96,144,16,16)*px,vec4(112,144,16,16)*px].staticArray); diff --git a/demos/source/demos/space_invaders.d b/demos/source/demos/space_invaders.d index 48af134..83f1e7a 100644 --- a/demos/source/demos/space_invaders.d +++ b/demos/source/demos/space_invaders.d @@ -20,6 +20,8 @@ import game_core.basic; import game_core.rendering; import game_core.collision; +import gui.attributes; + private enum float px = 1.0/512.0; @@ -222,8 +224,8 @@ struct CWeapon } float shoot_time = 0; - Type type; - ubyte level = 1; + @GUIRange(0, 4) Type type; + @GUIRange(0, 11) ubyte level = 1; } struct CWeaponLocation @@ -237,7 +239,7 @@ struct CShootDirection { mixin ECS.Component; - Direction direction; + @GUIRange(0, 3) Direction direction; } struct CSideMove @@ -304,8 +306,8 @@ struct CAnimation mixin ECS.Component; vec4[] frames; - float time = 0; - float speed = 1; + @GUIRangeF(0, float.max)float time = 0; + @GUIRangeF(0, float.max)float speed = 1; } struct CAnimationLooped @@ -350,7 +352,7 @@ struct CParts { mixin ECS.Component; - ubyte count; + @GUIDisabled ubyte count; } struct CInit @@ -364,7 +366,7 @@ struct CInit boss } - Type type; + @GUIRange(0, 2)Type type; } struct CParticleEmitter @@ -373,9 +375,8 @@ struct CParticleEmitter vec2 range = vec2(0,0); vec2 time_range = vec2(500,1000); - ///due to multithreading there should be separate template for every thread. ///It can be array of tempaltes or (like in this demo) simply index of template; - uint tmpl_id; + //uint tmpl_id; //EntityTemplate* tmpl; } @@ -404,7 +405,7 @@ struct CSpawnUponDeath //EntityID parent; //EntityTemplate* tmpl; - Type type; + @GUIRange(0,0) Type type; } ///This component can be replaced by "CSpawnUponDeath" but I want to gives possibility to add this component to every entity @@ -413,7 +414,7 @@ struct CShootWaveUponDeath { mixin ECS.Component; - CWeapon.Type bullet_type; + @GUIRange(0, 4) CWeapon.Type bullet_type; } /*####################################################################################################################### @@ -1582,7 +1583,7 @@ struct PartsDestroySystem becsID!CVelocity, becsID!CLocation, becsID!CParticleEmitter, becsID!CParticleEmitterTime, becsID!CTargetParent, becsID!CDepth ].staticArray); - *flashes_emitter.getComponent!CParticleEmitter() = CParticleEmitter(vec2(0,0), vec2(800,1600), 0); + *flashes_emitter.getComponent!CParticleEmitter() = CParticleEmitter(vec2(0,0), vec2(800,1600)); } void onDestroy() @@ -1783,7 +1784,8 @@ struct AnimationSystem { data.animation[i].time += dt * data.animation[i].speed; while(cast(uint)data.animation[i].time >= data.animation[i].frames.length)data.animation[i].time -= cast(float)data.animation[i].frames.length; - if(cast(uint)(data.animation[i].time) >= data.animation[i].frames.length)assert(0); + //if(cast(uint)(data.animation[i].time) >= data.animation[i].frames.length)assert(0); + assert(cast(uint)(data.animation[i].time) < data.animation[i].frames.length); uint index = cast(uint)(data.animation[i].time); if(index < data.animation[i].frames.length)data.texcoords[i].value = data.animation[i].frames[index]; } @@ -2102,9 +2104,13 @@ void spaceInvadersStart() draw_system.default_data.color = 0x80808080; draw_system.default_data.texture = space_invaders.texture; + launcher.gui_manager.addComponent(CLocation(),"Location"); + launcher.gui_manager.addComponent(CRotation(),"Rotation"); + launcher.gui_manager.addComponent(CTexCoords(),"TexCoords"); launcher.gui_manager.addComponent(CInput(),"Input"); launcher.gui_manager.addComponent(CShip(),"Ship"); launcher.gui_manager.addComponent(CEnemy(),"Enemy"); + launcher.gui_manager.addComponent(CShootDirection(),"Shoot Direction"); launcher.gui_manager.addComponent(CAutoShoot(),"Auto Shoot"); launcher.gui_manager.addComponent(CWeapon(0, CWeapon.Type.laser),"Weapon (laser)"); launcher.gui_manager.addComponent(CVelocity(vec2(0,0)),"Velocity (0,0)"); @@ -2112,6 +2118,7 @@ void spaceInvadersStart() launcher.gui_manager.addComponent(CSideMove(),"Side Move"); launcher.gui_manager.addComponent(CSideMove(0),"Side Move (g1)"); launcher.gui_manager.addComponent(CSideMove(1),"Side Move (g2)"); + launcher.gui_manager.addComponent(CDepth(),"Depth"); launcher.gui_manager.addComponent(CShootGrid(),"Shoot Grid"); launcher.gui_manager.addComponent(CGuild(),"Guild (Player)"); launcher.gui_manager.addComponent(CGuild(1),"Guild (Enemy)"); @@ -2119,24 +2126,29 @@ void spaceInvadersStart() launcher.gui_manager.addComponent(CHitMark(),"Hit Mark"); launcher.gui_manager.addComponent(CUpgrade(CUpgrade.Upgrade.laser),"Upgrade (laser)"); launcher.gui_manager.addComponent(CParticle(1000),"Particle (1s)"); - //launcher.gui_manager.addComponent(CMaxHitPoints(),"Max Hit Points"); + launcher.gui_manager.addComponent(CMaxHitPoints(),"Max Hit Points"); + launcher.gui_manager.addComponent(CAnimation(),"Animation"); launcher.gui_manager.addComponent(CDamping(0),"Damping (0)"); launcher.gui_manager.addComponent(CDamping(4),"Damping (4)"); launcher.gui_manager.addComponent(CDamping(8),"Damping (8)"); + launcher.gui_manager.addComponent(CAnimationLooped(),"Animation loop flag"); launcher.gui_manager.addComponent(CTargetParent(),"Target Parent"); launcher.gui_manager.addComponent(CTargetPlayerShip(),"Target Player Ship"); launcher.gui_manager.addComponent(CTarget(),"Target"); launcher.gui_manager.addComponent(CChildren(),"Children"); + launcher.gui_manager.addComponent(CVelocityFactor(),"Velocity Factor"); launcher.gui_manager.addComponent(CWeaponLocation(vec2(0,16)),"Weapon Location (0,16)"); launcher.gui_manager.addComponent(CInit(CInit.Type.space_ship),"Init (Ship)"); launcher.gui_manager.addComponent(CInit(CInit.Type.boss),"Init (Boss)"); launcher.gui_manager.addComponent(CInit(CInit.Type.tower),"Init (Tower)"); launcher.gui_manager.addComponent(CBoss(),"Boss"); + launcher.gui_manager.addComponent(CParts(),"Parts"); launcher.gui_manager.addComponent(CColliderScale(),"Collider Scale"); launcher.gui_manager.addComponent(CParticleEmitter(),"Particle Emitter"); launcher.gui_manager.addComponent(CParticleEmitterTime(),"Particle Emitter Time"); - //launcher.gui_manager.addComponent(CSpawnUponDeath(),"Spawn Upon Death"); + launcher.gui_manager.addComponent(CSpawnUponDeath(),"Spawn Upon Death"); launcher.gui_manager.addComponent(CShootWaveUponDeath(CWeapon.Type.canon),"Wave Upon Death"); + launcher.gui_manager.addComponent(CShootGridMask(),"Shoot grid mask"); launcher.gui_manager.addSystem(becsID!DrawSystem,"Draw System"); launcher.gui_manager.addSystem(becsID!InputMovementSystem,"Input Movement"); @@ -2165,6 +2177,7 @@ void spaceInvadersStart() launcher.gui_manager.addSystem(becsID!ChildDestroySystem,"Child Destroy System"); launcher.gui_manager.addSystem(becsID!ShootWaveSystem,"Shoot Wave System"); //launcher.gui_manager.addSystem(becsID!SpawnUponDeathSystem,"Child Destroy System"); + //launcher.gui_manager.addSystem(becsID!CollisionMaskSystem,"Collision Mask"); //gEntityManager.getSystem(becsID!CleanSystem).disable(); { diff --git a/demos/source/game_core/collision.d b/demos/source/game_core/collision.d index ba81a4f..bd82624 100644 --- a/demos/source/game_core/collision.d +++ b/demos/source/game_core/collision.d @@ -11,6 +11,7 @@ import ecs_utils.utils; import game_core.basic; +import gui.attributes; void registerCollisionModule(EntityManager* manager) { @@ -46,7 +47,7 @@ struct CBVH { mixin ECS.Component; - uint index; + @GUIDisabled uint index; } struct CAABB @@ -64,7 +65,7 @@ struct CShootGridMask alias value this; - ubyte value; + @GUIDisabled ubyte value; } struct CColliderScale diff --git a/demos/source/gui/attributes.d b/demos/source/gui/attributes.d index 53605c2..4c4c269 100644 --- a/demos/source/gui/attributes.d +++ b/demos/source/gui/attributes.d @@ -4,17 +4,20 @@ enum GUIColor = "GUIColor"; struct GUIRange { - union + struct { - struct - { - int min; - int max; - } - struct - { - float minf; - float maxf; - } + int min; + int max; } -} \ No newline at end of file +} + +struct GUIRangeF +{ + struct + { + float minf; + float maxf; + } +} + +enum GUIDisabled = "GUIDisabled"; diff --git a/demos/source/gui/component.d b/demos/source/gui/component.d index e65dee4..fdae1c2 100644 --- a/demos/source/gui/component.d +++ b/demos/source/gui/component.d @@ -54,6 +54,7 @@ struct VariableGUI Type type; const (char)* name; ushort offset; + bool disabled = false; union { Int int_; diff --git a/demos/source/gui/manager.d b/demos/source/gui/manager.d index 7720b79..52e7f55 100644 --- a/demos/source/gui/manager.d +++ b/demos/source/gui/manager.d @@ -152,6 +152,7 @@ struct GUIManager //pragma(msg,member_type); //pragma(msg,__traits(getMember, T, member).offsetof); ushort offset = member.offsetof;//cast(ushort)__traits(getMember, T, member).offsetof; + static if(is(member_type == vec2)) { comp_edit.variables[comp_edit.used++] = VariableGUI(VariableGUI.Type.vec2,member_str,offset); @@ -236,14 +237,20 @@ struct GUIManager } static if(hasUDA!(member,GUIRange)) { - comp_edit.variables[comp_edit.used-1].float_.min = getUDAs!(member,GUIRange)[0].minf; - comp_edit.variables[comp_edit.used-1].float_.max = getUDAs!(member,GUIRange)[1].maxf; + comp_edit.variables[comp_edit.used-1].float_.min = getUDAs!(member,GUIRange)[0].min; + comp_edit.variables[comp_edit.used-1].float_.max = getUDAs!(member,GUIRange)[0].max; } + else static if(hasUDA!(member,GUIRangeF)) { + comp_edit.variables[comp_edit.used-1].float_.min = getUDAs!(member,GUIRangeF)[0].minf; + comp_edit.variables[comp_edit.used-1].float_.max = getUDAs!(member,GUIRangeF)[0].maxf; + } + else { comp_edit.variables[comp_edit.used-1].float_.min = -float.max; comp_edit.variables[comp_edit.used-1].float_.max = float.max; } } + static if(hasUDA!(member,GUIDisabled))comp_edit.variables[comp_edit.used - 1].disabled = true; } edit_components[becsID(comp)] = comp_edit; } @@ -256,12 +263,14 @@ struct GUIManager igIndent(8); foreach(ref SystemGUI system;systems) { + igPushIDPtr(&system); if(igCheckbox(system.name,&system.enabled)) { System* sys = gEntityManager.getSystem(system.id); if(system.enabled)sys.enable(); else sys.disable(); } + igPopID(); } igUnindent(8); } @@ -337,13 +346,15 @@ struct GUIManager { vec4 color; if(comp_id >= edit_components.length)return; - if(edit_components[comp_id].used) + //if(edit_components[comp_id].used) + if(edit_components[comp_id].name) { if(igCollapsingHeader(edit_components[comp_id].name, ImGuiTreeNodeFlags_SpanAvailWidth | ImGuiTreeNodeFlags_DefaultOpen)) { igIndent(8); foreach(ref VariableGUI var;edit_components[comp_id].variables[0 .. edit_components[comp_id].used]) { + igPushIDPtr(&var); switch(var.type) { @@ -351,7 +362,12 @@ struct GUIManager igDragScalarClamp(var.name, ImGuiDataType_S8, data_ptr+var.offset, 0.1, cast(void*)&var.int_.min, cast(void*)&var.int_.max, null, 1); break; case VariableGUI.Type.ubyte_: - igDragScalarClamp(var.name, ImGuiDataType_U8, data_ptr+var.offset, 0.1, cast(void*)&var.int_.min, cast(void*)&var.int_.max, null, 1); + if(var.disabled) + { + ubyte v = *cast(ubyte*)(data_ptr+var.offset); + igDragScalarClamp(var.name, ImGuiDataType_U8, &v, 0.1, cast(void*)&var.int_.min, cast(void*)&var.int_.max, null, 1); + } + else igDragScalarClamp(var.name, ImGuiDataType_U8, data_ptr+var.offset, 0.1, cast(void*)&var.int_.min, cast(void*)&var.int_.max, null, 1); break; case VariableGUI.Type.short_: igDragScalarClamp(var.name, ImGuiDataType_S16, data_ptr+var.offset, 0.1, cast(void*)&var.int_.min, cast(void*)&var.int_.max, null, 1); @@ -363,7 +379,12 @@ struct GUIManager igDragScalarClamp(var.name, ImGuiDataType_S32, data_ptr+var.offset, 0.1, cast(void*)&var.int_.min, cast(void*)&var.int_.max, null, 1); break; case VariableGUI.Type.uint_: - igDragScalarClamp(var.name, ImGuiDataType_U32, data_ptr+var.offset, 0.1, cast(void*)&var.int_.min, cast(void*)&var.int_.max, null, 1); + if(var.disabled) + { + uint v = *cast(uint*)(data_ptr+var.offset); + igDragScalarClamp(var.name, ImGuiDataType_U32, &v, 0.1, cast(void*)&var.int_.min, cast(void*)&var.int_.max, null, 1); + } + else igDragScalarClamp(var.name, ImGuiDataType_U32, data_ptr+var.offset, 0.1, cast(void*)&var.int_.min, cast(void*)&var.int_.max, null, 1); break; case VariableGUI.Type.float_: igDragScalarClamp(var.name, ImGuiDataType_Float, data_ptr+var.offset, 0.1, cast(void*)&var.float_.min, cast(void*)&var.float_.max, "%2.2f", 1); diff --git a/demos/utils/source/ecs_utils/gfx/renderer.d b/demos/utils/source/ecs_utils/gfx/renderer.d index b2091cf..6e7bd23 100644 --- a/demos/utils/source/ecs_utils/gfx/renderer.d +++ b/demos/utils/source/ecs_utils/gfx/renderer.d @@ -448,6 +448,7 @@ struct Renderer void draw(scope ref const(DrawData) data) { if(prepared_items >= MaxObjects)return; + if(threads[data.thread_id].blocks.length <= data.material_id)return; __draw(this,data);//tex,pos,size,coords,depth,color,angle,material_id,mesh_id,thread_id); } From cc097dddf0af93b7f1d893d64d2123758c7c069f Mon Sep 17 00:00:00 2001 From: Dawid Masiukiewicz Date: Sun, 9 May 2021 16:46:11 +0000 Subject: [PATCH 198/217] Minor fixes --- meson.build | 4 ++-- source/bubel/ecs/traits.d | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/meson.build b/meson.build index 0aff444..a43783c 100644 --- a/meson.build +++ b/meson.build @@ -49,8 +49,8 @@ if betterC_opt endif endif -add_global_arguments(args, language : 'd') -add_global_link_arguments(link_args, language : 'd') +add_project_arguments(args, language : 'd') +add_project_link_arguments(link_args, language : 'd') # Dependencies threads_dep = dependency('threads') diff --git a/source/bubel/ecs/traits.d b/source/bubel/ecs/traits.d index 3af4b86..849632a 100644 --- a/source/bubel/ecs/traits.d +++ b/source/bubel/ecs/traits.d @@ -66,7 +66,7 @@ static string attachParentName(alias T, string str)() { return attachParentName!(parent, parent_str[7 .. $] ~ '.' ~ str); } - else return parent_str[8 .. $] ~ '.' ~ str; + else return parent_str[7 .. $] ~ '.' ~ str; } else static if(parent_str[0..8] == "package ") { From 85e1f8a76e984ae1c4f7d2c72f6bb1bb7ca9c825 Mon Sep 17 00:00:00 2001 From: Mergul Date: Wed, 17 Nov 2021 15:03:25 +0100 Subject: [PATCH 199/217] Fixed bug with addComponents template -deprecated Comonent.ref_ function -remover Comonent.ref_ usage from addComponents template -updated dub.json --- .gitignore | 7 ++++--- source/bubel/ecs/core.d | 2 +- source/bubel/ecs/manager.d | 25 +------------------------ tests/basic.d | 30 ++++++++++++++++-------------- tests/bugs.d | 8 ++++++-- 5 files changed, 28 insertions(+), 44 deletions(-) diff --git a/.gitignore b/.gitignore index f2e30a3..e0e6fff 100644 --- a/.gitignore +++ b/.gitignore @@ -1,9 +1,8 @@ * -!*/ !source/** !tests/** !README.md -!./dub.json +!dub.json !.gitignore !codecov.yml !skeleton.html @@ -11,4 +10,6 @@ !**/*.wrap !meson_options.txt !compile_wasm.py -!compile_android.py \ No newline at end of file +!compile_android.py +!.gitlab-ci.yml +!LICENSE \ No newline at end of file diff --git a/source/bubel/ecs/core.d b/source/bubel/ecs/core.d index 1a5e711..f8511ea 100644 --- a/source/bubel/ecs/core.d +++ b/source/bubel/ecs/core.d @@ -94,7 +94,7 @@ static struct ECS */ mixin template Component() { - ComponentRef ref_() @nogc nothrow return + deprecated ComponentRef ref_() @nogc nothrow return { return ComponentRef(&this, becsID!(typeof(this))); } diff --git a/source/bubel/ecs/manager.d b/source/bubel/ecs/manager.d index e3ad7bc..1ca7a86 100644 --- a/source/bubel/ecs/manager.d +++ b/source/bubel/ecs/manager.d @@ -2424,29 +2424,11 @@ export struct EntityManager void addComponents(Components...)(const EntityID entity_id, Components comps) nothrow @nogc { const uint num = Components.length; - /*ushort[num] new_ids; - - static foreach (i, comp; Components) - { - new_ids[i] = comp.component_id; - } - - ThreadData* data = &threads[threadID]; - data.changeEntitiesList.add(cast(ubyte) 1u); - data.changeEntitiesList.add((cast(ubyte*)&entity_id)[0 .. EntityID.sizeof]); - data.changeEntitiesList.add((cast(ubyte*)&num)[0 .. uint.sizeof]); - data.changeEntitiesList.add(cast(ubyte[]) new_ids); - static foreach (i, comp; comps) - { - data.changeEntitiesList.add((cast(ubyte*)&comp)[0 .. comp.sizeof]); - }*/ - - //__addComponents(entity_id, new_ids, pointers); ComponentRef[num] _comps; static foreach (i, comp; comps) { - _comps[i] = comp.ref_; + _comps[i] = ComponentRef(&comp, becsID!(typeof(comp))); } addComponents(entity_id, _comps); @@ -2469,11 +2451,6 @@ export struct EntityManager data.changeEntitiesList.add( (cast(ubyte*) ref_.ptr)[0 .. components[ref_.component_id].size]); } - /*data.changeEntitiesList.add(cast(ubyte[]) new_ids); - static foreach (i, comp; comps) - { - data.changeEntitiesList.add((cast(ubyte*)&comp)[0 .. comp.sizeof]); - }*/ } /************************************************************************************************************************ diff --git a/tests/basic.d b/tests/basic.d index aa730ea..084500a 100644 --- a/tests/basic.d +++ b/tests/basic.d @@ -16,7 +16,7 @@ else import std.array : staticArray; struct CInt { - mixin ECS.Component; + // mixin ECS.Component; alias value this; @@ -25,7 +25,7 @@ struct CInt struct CFloat { - mixin ECS.Component; + // mixin ECS.Component; alias value this; @@ -34,7 +34,7 @@ struct CFloat struct CDouble { - mixin ECS.Component; + // mixin ECS.Component; alias value this; @@ -43,7 +43,7 @@ struct CDouble struct CLong { - mixin ECS.Component; + // mixin ECS.Component; alias value this; @@ -52,7 +52,7 @@ struct CLong struct CShort { - mixin ECS.Component; + // mixin ECS.Component; alias value this; @@ -61,7 +61,7 @@ struct CShort struct CUnregistered { - mixin ECS.Component; + // mixin ECS.Component; alias value this; @@ -70,7 +70,7 @@ struct CUnregistered struct CFlag { - mixin ECS.Component; + // mixin ECS.Component; } struct LongAddSystem @@ -182,17 +182,18 @@ unittest assert(*entity2.getComponent!CInt == 2); assert(*entity2.getComponent!CFloat == 2.0); - //CInt cint = CInt(10); - //CLong clong; - //Entity* entity3 = gEntityManager.addEntity(tmpl_, [cint.ref_, clong.ref_].staticArray); - Entity* entity3 = gEntityManager.addEntity(tmpl_, [CInt(10).ref_, CLong().ref_, CFlag().ref_].staticArray); + CInt int1 = CInt(10); + CLong long1 = CLong(); + CFlag flag1 = CFlag(); + Entity* entity3 = gEntityManager.addEntity(tmpl_, [ComponentRef(&int1, becsID(int1)), ComponentRef(&long1, becsID(long1)), ComponentRef(&flag1, becsID(flag1))].staticArray); EntityID id = entity3.id; assert(entity3.hasComponent(becsID!CInt)); assert(entity3.hasComponent(becsID!CFloat)); assert(*entity3.getComponent!CInt == 10); assert(*entity3.getComponent!CFloat == 2.0); - gEntityManager.addComponents(entity3.id, [CFlag().ref_,CShort(2).ref_].staticArray); + CShort short1 = CShort(2); + gEntityManager.addComponents(entity3.id, [ComponentRef(&flag1, becsID(flag1)),ComponentRef(&short1, becsID(short1))].staticArray); gEntityManager.commit(); entity3 = gEntityManager.getEntity(id); assert(entity3.getComponent!CInt); @@ -213,7 +214,7 @@ unittest assert(*entity3.getComponent!CInt == 10); assert(*entity3.getComponent!CFloat == 2.0); - gEntityManager.addComponents(entity3.id, [CFlag().ref_,CShort(2).ref_].staticArray); + gEntityManager.addComponents(entity3.id, [ComponentRef(&flag1, becsID(flag1)),ComponentRef(&short1, becsID(short1))].staticArray); gEntityManager.removeComponents(entity3.id, [becsID!CUnregistered].staticArray); gEntityManager.commit(); entity3 = gEntityManager.getEntity(id); @@ -231,7 +232,8 @@ unittest gEntityManager.endRegister(); - gEntityManager.addComponents(entity3.id, [CUnregistered(4).ref_].staticArray); + CUnregistered unregistered1 = CUnregistered(4); + gEntityManager.addComponents(entity3.id, [ComponentRef(&unregistered1, becsID(unregistered1))].staticArray); gEntityManager.commit(); entity3 = gEntityManager.getEntity(id); assert(entity3.getComponent!CUnregistered); diff --git a/tests/bugs.d b/tests/bugs.d index 3c5f426..1a3968c 100644 --- a/tests/bugs.d +++ b/tests/bugs.d @@ -119,8 +119,12 @@ unittest gEntityManager.endRegister(); EntityTemplate* tmpl = gEntityManager.allocateTemplate([becsID!CInt, becsID!CLong].staticArray); - EntityID id = gEntityManager.addEntity(tmpl,[CLong(10).ref_, CInt(6).ref_].staticArray).id; - EntityID id2 = gEntityManager.addEntity(tmpl,[CInt(4).ref_].staticArray).id; + + CLong clong = CLong(10); + CInt cint = CInt(6); + CInt cint2 = CInt(4); + EntityID id = gEntityManager.addEntity(tmpl,[ComponentRef(&clong, becsID(clong)), ComponentRef(&cint, becsID(cint))].staticArray).id; + EntityID id2 = gEntityManager.addEntity(tmpl,[ComponentRef(&cint2, becsID(cint2))].staticArray).id; gEntityManager.freeTemplate(tmpl); gEntityManager.commit(); From d01ebd960a81f0ea8d64128f3986868b56b46c9a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Masiukiewicz?= Date: Sun, 19 Jun 2022 14:31:49 +0200 Subject: [PATCH 200/217] Allow simpler use of ecs from parent project This allows parent project to find subproject by simple: decs_dep = dependency('decs') --- meson.build | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/meson.build b/meson.build index a43783c..b3770bf 100644 --- a/meson.build +++ b/meson.build @@ -43,7 +43,7 @@ if betterC_opt if comp_id == 'gcc' args += ['-fno-druntime'] link_args += ['-fno-druntime'] - else + else args += '-betterC' link_args += '-betterC' endif @@ -63,9 +63,11 @@ ecs_lib = library('decs', decs_dep = declare_dependency( include_directories : [inc], link_with : ecs_lib, - dependencies : threads_dep, + dependencies : threads_dep, ) +meson.override_dependency('decs', decs_dep) + # Tests if BuildTests_opt subdir('tests') From 24a07a05e5948aeada729de9782611734153e745 Mon Sep 17 00:00:00 2001 From: Dawid Masiukiewicz Date: Sat, 9 Jul 2022 20:27:01 +0000 Subject: [PATCH 201/217] Small fixes --- .gitlab-ci.yml | 6 +++--- demos/meson.build | 2 +- dub.json | 4 ++-- meson.build | 8 ++++---- source/bubel/ecs/events.d | 4 ++++ source/bubel/ecs/hash_map.d | 18 +++++++++++------- source/bubel/ecs/id_manager.d | 4 ++++ source/bubel/ecs/manager.d | 11 ----------- source/bubel/ecs/package.d | 4 ++++ source/bubel/ecs/simple_vector.d | 4 ++++ source/bubel/ecs/traits.d | 4 ++++ source/bubel/ecs/vector.d | 4 ++++ tests/meson.build | 2 +- 13 files changed, 46 insertions(+), 29 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 8fa868a..555e6d5 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -23,7 +23,7 @@ build_code: test_dmd_debug: stage: test - image: frolvlad/alpine-glibc + image: debian:buster-slim script: - binaries/dmd_debug_unittest artifacts: @@ -31,7 +31,7 @@ test_dmd_debug: junit: test_report.xml test_dmd: stage: test - image: frolvlad/alpine-glibc + image: debian:buster-slim script: - binaries/dmd_release_unittest artifacts: @@ -39,7 +39,7 @@ test_dmd: junit: test_report.xml test_dmd_betterC: stage: test - image: frolvlad/alpine-glibc + image: debian:buster-slim script: - binaries/dmd_debug_unittest_bc artifacts: diff --git a/demos/meson.build b/demos/meson.build index 20df64c..deee071 100644 --- a/demos/meson.build +++ b/demos/meson.build @@ -19,7 +19,7 @@ sdl2_image_dep = dependency('SDL2_image') subdir('utils') # Utils library -executable('decs-demos', [demos_src, external_src], +executable('BubelECSDemos', [demos_src, external_src], include_directories : [demos_inc, external_inc], d_module_versions : versions, link_with : [ecs_lib, ecs_utils_lib], diff --git a/dub.json b/dub.json index 8e2a1b3..b3bfa66 100755 --- a/dub.json +++ b/dub.json @@ -1,6 +1,6 @@ { - "name": "bubel_ecs", - "targetName" : "bubel_ecs", + "name": "bubel-ecs", + "targetName" : "BubelECS", "authors": [ "Michał Masiukiewicz", "Dawid Masiukiewicz" ], diff --git a/meson.build b/meson.build index b3770bf..8275cc9 100644 --- a/meson.build +++ b/meson.build @@ -1,4 +1,4 @@ -project('decs', 'd', version : '0.5.0') +project('bubel-ecs', 'd', version : '0.5.0') # Options betterC_opt = get_option('betterC') @@ -55,18 +55,18 @@ add_project_link_arguments(link_args, language : 'd') # Dependencies threads_dep = dependency('threads') -ecs_lib = library('decs', +ecs_lib = library('BubelECS', src, include_directories : [inc], ) -decs_dep = declare_dependency( +bubel_ecs_dep = declare_dependency( include_directories : [inc], link_with : ecs_lib, dependencies : threads_dep, ) -meson.override_dependency('decs', decs_dep) +meson.override_dependency('bubel-ecs', bubel_ecs_dep) # Tests if BuildTests_opt diff --git a/source/bubel/ecs/events.d b/source/bubel/ecs/events.d index 7cb0d0c..f123e86 100644 --- a/source/bubel/ecs/events.d +++ b/source/bubel/ecs/events.d @@ -1,3 +1,7 @@ +/************************************************************************************************************************ +Copyright: Copyright © 2018-2019, Dawid Masiukiewicz, Michał Masiukiewicz +License: BSD 3-clause, see LICENSE file in project root folder. +*/ module bubel.ecs.events; import bubel.ecs.block_allocator; diff --git a/source/bubel/ecs/hash_map.d b/source/bubel/ecs/hash_map.d index 764374c..1af0fd8 100755 --- a/source/bubel/ecs/hash_map.d +++ b/source/bubel/ecs/hash_map.d @@ -1,4 +1,8 @@ -module bubel.ecs.hash_map; +/************************************************************************************************************************ +Copyright: Copyright © 2018-2019, Dawid Masiukiewicz, Michał Masiukiewicz +License: BSD 3-clause, see LICENSE file in project root folder. +*/ +module bubel.ecs.hash_map; import std.traits; @@ -332,36 +336,36 @@ nothrow: return result; } - export int byKey(scope int delegate(Key k) nothrow dg) + export int byKey(scope int delegate(ref Key k) dg) { int result; foreach (ref Key k; this) { - result = dg(k); + result = (cast(int delegate(ref Key k) nothrow)dg)(k); if (result) break; } return result; } - export int byValue(scope int delegate(ref Value k) nothrow dg) + export int byValue(scope int delegate(ref Value v) dg) { int result; foreach (ref Value v; this) { - result = dg(v); + result = (cast(int delegate(ref Value v) nothrow)dg)(v); if (result) break; } return result; } - export int byKeyValue(scope int delegate(ref Key k, ref Value v) nothrow dg) + export int byKeyValue(scope int delegate(ref Key k, ref Value v) dg) { int result; foreach (ref Key k, ref Value v; this) { - result = dg(k, v); + result = (cast(int delegate(ref Key k, ref Value v) nothrow)dg)(k, v); if (result) break; } diff --git a/source/bubel/ecs/id_manager.d b/source/bubel/ecs/id_manager.d index 86a611e..ccb4fac 100644 --- a/source/bubel/ecs/id_manager.d +++ b/source/bubel/ecs/id_manager.d @@ -1,3 +1,7 @@ +/************************************************************************************************************************ +Copyright: Copyright © 2018-2019, Dawid Masiukiewicz, Michał Masiukiewicz +License: BSD 3-clause, see LICENSE file in project root folder. +*/ module bubel.ecs.id_manager; import bubel.ecs.entity; diff --git a/source/bubel/ecs/manager.d b/source/bubel/ecs/manager.d index 1ca7a86..32ba65d 100644 --- a/source/bubel/ecs/manager.d +++ b/source/bubel/ecs/manager.d @@ -80,8 +80,6 @@ export struct EntityManager { UpdatePass* pass = Mallocator.make!UpdatePass; pass.name = Mallocator.makeArray(cast(char[]) "update"); - //pass.name = Mallocator.makeArray!char("update".length); - //pass.name[0..$] = "update"; passes.add(pass); passes_map.add(cast(string) pass.name, cast(ushort)(passes.length - 1)); } @@ -297,7 +295,6 @@ export struct EntityManager if (threads_count == 0) threads_count = 1; threads = Mallocator.makeArray!ThreadData(threads_count); - //foreach(ref thread;threads)thread = ThreadData().init; m_page_size = page_size; m_pages_in_block = block_pages_count; @@ -1253,8 +1250,6 @@ export struct EntityManager { UpdatePass* pass = Mallocator.make!UpdatePass; pass.name = Mallocator.makeArray(cast(char[]) name); - /*pass.name = Mallocator.makeArray!char(name.length); - pass.name[0..$] = name[0..$];*/ passes.add(pass); passes_map.add(name, cast(ushort)(passes.length - 1)); return cast(ushort)(passes.length - 1); @@ -1849,8 +1844,6 @@ export struct EntityManager info = Mallocator.make!EntityInfo; info.components = Mallocator.makeArray(ids); - /*info.components = Mallocator.makeArray!ushort(ids.length); - info.components[0 .. $] = ids[0 .. $];*/ info.deltas = Mallocator.makeArray!ushort(ids[$ - 1] + 1); info.size = EntityID.sizeof; @@ -3226,8 +3219,6 @@ export struct EntityManager if (index > 0) { caller.exclusion = Mallocator.makeArray(exclusion[0 .. index]); - /*caller.exclusion = Mallocator.makeArray!(SystemCaller*)(index); - caller.exclusion[0..$] = exclusion[0 .. index];*/ } else caller.exclusion = null; @@ -3275,8 +3266,6 @@ export struct EntityManager if (index > 0) { caller.dependencies = Mallocator.makeArray(exclusion[0 .. index]); - /*caller.dependencies = Mallocator.makeArray!(SystemCaller*)(index); - caller.dependencies[0..$] = exclusion[0 .. index];*/ caller.job_group.dependencies = Mallocator.makeArray!(JobGroup*)(index); foreach (j, dep; caller.dependencies) diff --git a/source/bubel/ecs/package.d b/source/bubel/ecs/package.d index 51da325..2b3b7f4 100644 --- a/source/bubel/ecs/package.d +++ b/source/bubel/ecs/package.d @@ -1,3 +1,7 @@ +/************************************************************************************************************************ +Copyright: Copyright © 2018-2019, Dawid Masiukiewicz, Michał Masiukiewicz +License: BSD 3-clause, see LICENSE file in project root folder. +*/ module ecs; public import bubel.ecs.core; diff --git a/source/bubel/ecs/simple_vector.d b/source/bubel/ecs/simple_vector.d index acf01ee..02f3f3d 100644 --- a/source/bubel/ecs/simple_vector.d +++ b/source/bubel/ecs/simple_vector.d @@ -1,3 +1,7 @@ +/************************************************************************************************************************ +Copyright: Copyright © 2018-2019, Dawid Masiukiewicz, Michał Masiukiewicz +License: BSD 3-clause, see LICENSE file in project root folder. +*/ module bubel.ecs.simple_vector; import bubel.ecs.std; diff --git a/source/bubel/ecs/traits.d b/source/bubel/ecs/traits.d index 849632a..15880fd 100644 --- a/source/bubel/ecs/traits.d +++ b/source/bubel/ecs/traits.d @@ -1,3 +1,7 @@ +/************************************************************************************************************************ +Copyright: Copyright © 2018-2019, Dawid Masiukiewicz, Michał Masiukiewicz +License: BSD 3-clause, see LICENSE file in project root folder. +*/ module bubel.ecs.traits; import std.traits; diff --git a/source/bubel/ecs/vector.d b/source/bubel/ecs/vector.d index 019673b..e9b061d 100644 --- a/source/bubel/ecs/vector.d +++ b/source/bubel/ecs/vector.d @@ -1,3 +1,7 @@ +/************************************************************************************************************************ +Copyright: Copyright © 2018-2019, Dawid Masiukiewicz, Michał Masiukiewicz +License: BSD 3-clause, see LICENSE file in project root folder. +*/ module bubel.ecs.vector; import core.bitop; diff --git a/tests/meson.build b/tests/meson.build index cfccaa7..ff1a3a1 100644 --- a/tests/meson.build +++ b/tests/meson.build @@ -10,7 +10,7 @@ tests_src = files( 'vector.d' ) -exe = executable('decs-tests', +exe = executable('BubelECSTests', tests_src, include_directories : [inc, include_directories('..')], d_args : args, From 56ce8c3f9c88a8067072a6cafe2cb7ef58b6fd93 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Masiukiewicz?= Date: Tue, 4 Oct 2022 22:18:45 +0200 Subject: [PATCH 202/217] Don't use ForeachType as it don't work if foreach type is not copyable. This fixes compilation error: include/d/std/traits.d:8024: Error: Generating an `inout` copy constructor for `struct game.graphic.manager.Graphic` failed, therefore instances of it are uncopyable --- source/bubel/ecs/manager.d | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/source/bubel/ecs/manager.d b/source/bubel/ecs/manager.d index 32ba65d..fb43f67 100644 --- a/source/bubel/ecs/manager.d +++ b/source/bubel/ecs/manager.d @@ -465,7 +465,7 @@ export struct EntityManager static if (isArray!MemberType) { // Workaround. This code is never called with: not an array type, but compiler prints an error // name = fullyQualifiedName!(Unqual!(ForeachType!MemberType));//.stringof; - name = fullName!(Unqual!(ForeachType!MemberType)); + name = fullName!(Unqual!(typeof(MemberType.init[0]))); } bool is_optional; @@ -691,7 +691,7 @@ export struct EntityManager static if (isArray!MemberType) { // Workaround. This code is never called with: not an array type, but compiler prints an error // name = fullyQualifiedName!(Unqual!(ForeachType!MemberType)); - name = fullName!(Unqual!(ForeachType!MemberType)); + name = fullName!(Unqual!(typeof(MemberType.init[0]))); //name = Unqual!(ForeachType!MemberType).stringof; } @@ -899,10 +899,12 @@ export struct EntityManager static foreach (iii, comp_info; components_info.m_req[0 .. components_info.m_req_counter]) { - __traits(getMember, input_data, comp_info.name) = (cast(ForeachType!(typeof(__traits(getMember, - Sys.EntitiesData, comp_info.name)))*)( - cast(void*) block + info.deltas[system.m_components[iii]]))[offset - .. entities_count]; + __traits(getMember, input_data, comp_info.name) = ( + cast(typeof( + (typeof(__traits(getMember, Sys.EntitiesData, comp_info.name))).init[0] + )*) + (cast(void*) block + info.deltas[system.m_components[iii]]) + )[offset .. entities_count]; } static foreach (iii, comp_info; components_info.m_optional[0 From ce47bfc65aaf410f3088416395b1f19aaddcf3c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Masiukiewicz?= Date: Wed, 5 Oct 2022 18:39:07 +0200 Subject: [PATCH 203/217] Fix wasm compilation --- meson.build | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/meson.build b/meson.build index 8275cc9..3f261f8 100644 --- a/meson.build +++ b/meson.build @@ -55,15 +55,26 @@ add_project_link_arguments(link_args, language : 'd') # Dependencies threads_dep = dependency('threads') +d_versions = [] +deps = [] +if host_machine.cpu_family() == 'wasm32' + d_versions += 'ECSEmscripten' +else + # meson incorectly adds "-s USE_PTHREADS=1" to ldc2 invocation whe pthreads is added as dependency + # add it for non wasm builds + deps += threads_dep +endif + ecs_lib = library('BubelECS', src, + d_module_versions : d_versions, include_directories : [inc], ) bubel_ecs_dep = declare_dependency( include_directories : [inc], link_with : ecs_lib, - dependencies : threads_dep, + dependencies : deps, ) meson.override_dependency('bubel-ecs', bubel_ecs_dep) From c0246ce2af4e287b765ded8a85a015f82deb9f09 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Masiukiewicz?= Date: Thu, 27 Oct 2022 23:29:50 +0200 Subject: [PATCH 204/217] Syntax '*ptr = Structure.init' requires opAssign operator, get rid of this requirement by using malloc. This is useful when component is defined in another shared library and we use '-fvisibility=hidden', in that case opAssign is hidden and we will get 'undefined symbol' --- source/bubel/ecs/manager.d | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/source/bubel/ecs/manager.d b/source/bubel/ecs/manager.d index fb43f67..7861649 100644 --- a/source/bubel/ecs/manager.d +++ b/source/bubel/ecs/manager.d @@ -1307,7 +1307,8 @@ export struct EntityManager info.size = Comp.sizeof; info.alignment = Comp.alignof; //8; info.init_data = Mallocator.makeArray!ubyte(Comp.sizeof); - *cast(Comp*) info.init_data.ptr = Comp.init; // = Comp(); + __gshared Comp init_memory; + memcpy(info.init_data.ptr, &init_memory, Comp.sizeof); ushort comp_id = components_map.get(cast(char[]) ComponentName, ushort.max); if (comp_id < components.length) From 7a614686c8899ef66f99c1136282c33f9922749f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Masiukiewicz?= Date: Tue, 8 Nov 2022 22:05:57 +0100 Subject: [PATCH 205/217] Export id generated by becsID --- source/bubel/ecs/traits.d | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/source/bubel/ecs/traits.d b/source/bubel/ecs/traits.d index 15880fd..42b1753 100644 --- a/source/bubel/ecs/traits.d +++ b/source/bubel/ecs/traits.d @@ -11,8 +11,11 @@ import std.traits; */ ref ushort becsID(T)() { - __gshared ushort id = ushort.max; - return id; + /// Embed id in struct so export can be added to variable definition + static struct LocalStruct { + export __gshared ushort id = ushort.max; + } + return LocalStruct.id; } /************************************************************************************************************************ From 5f4ba90b3e97746f7560ca7ce8b59b07fda8a83c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Masiukiewicz?= Date: Thu, 10 Nov 2022 10:18:46 +0100 Subject: [PATCH 206/217] Add unregisterSystem functionality --- source/bubel/ecs/manager.d | 29 +++++++++++++++++++++++++++++ source/bubel/ecs/system.d | 8 ++++++++ 2 files changed, 37 insertions(+) diff --git a/source/bubel/ecs/manager.d b/source/bubel/ecs/manager.d index 7861649..3140ca2 100644 --- a/source/bubel/ecs/manager.d +++ b/source/bubel/ecs/manager.d @@ -172,6 +172,8 @@ export struct EntityManager foreach (ref system; systems) { + if (system.isAlive() == false) + continue; if (system.m_empty) { if (system.m_update) @@ -236,6 +238,8 @@ export struct EntityManager foreach (ref system; systems) { + if (system.isAlive() == false) + continue; foreach (caller; system.m_event_callers) { event_callers[caller.id]++; @@ -252,6 +256,8 @@ export struct EntityManager foreach (ref system; systems) { + if (system.isAlive() == false) + continue; foreach (caller; system.m_event_callers) { events[caller.id].callers[event_callers[caller.id]].callback = caller.callback; @@ -328,6 +334,21 @@ export struct EntityManager allocator.freeMemory(); } + + /************************************************************************************************************************ + Unregister given system form EntityManager. + */ + void unregisterSystem(Sys)() + { + assert(register_state, "unregisterSystem must be called between beginRegister() and endRegister()."); + ushort system_id = becsID!Sys; + System* system = getSystem(system_id); + assert(system, "System was not registered"); + assert(system.isAlive, "System already unregistered"); + system.destroy(); + *system = System.init; + } + /************************************************************************************************************************ Same as "void registerSystem(Sys)(int priority, int pass = 0)" but use pass name instead of id. */ @@ -1887,6 +1908,8 @@ export struct EntityManager foreach (i, ref system; systems) { + if (system.isAlive() == false) + continue; if (system.m_empty) continue; if (system.m_update is null) @@ -3095,6 +3118,8 @@ export struct EntityManager foreach (ref system; systems) { + if (system.isAlive() == false) + continue; if (system.enabled && system.m_begin) system.m_execute = (cast(bool function(void*)) system.m_begin)( system.m_system_pointer); @@ -3109,6 +3134,10 @@ export struct EntityManager foreach (ref system; systems) { + if (system.isAlive() == false) + { + continue; + } if (system.enabled && system.m_end) (cast(void function(void*)) system.m_end)(system.m_system_pointer); } diff --git a/source/bubel/ecs/system.d b/source/bubel/ecs/system.d index e571e8b..0da2d96 100644 --- a/source/bubel/ecs/system.d +++ b/source/bubel/ecs/system.d @@ -89,6 +89,14 @@ struct System return cast(const(char)[]) m_name; } + /************************************************************************************************************************ + Return false if system was unregistered, true otherwise. + */ + export bool isAlive() nothrow @nogc + { + return m_system_pointer != null; + } + package: void destroy() From c2ba4c632a4767931478380c77c68c73eeb1bfd9 Mon Sep 17 00:00:00 2001 From: Mergul Date: Sat, 12 Nov 2022 12:10:09 +0100 Subject: [PATCH 207/217] Fixes -Assert if callEntitiesFunction is called for system which is not alive -cleanup and formatting --- dub.json | 2 +- source/bubel/ecs/manager.d | 235 +++++++++++++++++++------------------ 2 files changed, 121 insertions(+), 116 deletions(-) diff --git a/dub.json b/dub.json index b3bfa66..1461c9d 100755 --- a/dub.json +++ b/dub.json @@ -63,7 +63,7 @@ ], "dflags": [ "-unittest", - "-cov" + "-cov=ctfe" ] }, { diff --git a/source/bubel/ecs/manager.d b/source/bubel/ecs/manager.d index 3140ca2..323d2ab 100644 --- a/source/bubel/ecs/manager.d +++ b/source/bubel/ecs/manager.d @@ -69,11 +69,10 @@ export struct EntityManager Initialize ECS. */ export static void initialize(uint threads_count = 1, uint page_size = 32768, - uint block_pages_count = 128) + uint block_pages_count = 128) { if (gEntityManager is null) { - //gEntityManager = Mallocator.make!EntityManager(threads_count); gEntityManager = Mallocator.make!EntityManager(threads_count, page_size, block_pages_count); with (gEntityManager) @@ -183,7 +182,7 @@ export struct EntityManager if (system.m_update is null) { if (system.m_add_entity || system.m_remove_entity - || system.m_change_entity || system.m_event_callers.length) + || system.m_change_entity || system.m_event_callers.length) { foreach (info; &entities_infos.byValue) { @@ -281,7 +280,7 @@ export struct EntityManager foreach (ref event; events) { qsort(event.callers.ptr, event.callers.length, - EventCaller.sizeof, &comapreEventCaller); + EventCaller.sizeof, &comapreEventCaller); } //qsort(event_callers.ptr, event_callers.length, EventInfo.sizeof, &compareUShorts); @@ -334,17 +333,19 @@ export struct EntityManager allocator.freeMemory(); } - /************************************************************************************************************************ Unregister given system form EntityManager. */ void unregisterSystem(Sys)() { - assert(register_state, "unregisterSystem must be called between beginRegister() and endRegister()."); + assert(register_state, "unregisterSystem must be called between beginRegister() and endRegister()."); + ushort system_id = becsID!Sys; System* system = getSystem(system_id); + assert(system, "System was not registered"); assert(system.isAlive, "System already unregistered"); + system.destroy(); *system = System.init; } @@ -376,7 +377,7 @@ export struct EntityManager //alias STC = ParameterStorageClass; assert(register_state, - "registerSystem must be called between beginRegister() and endRegister()."); + "registerSystem must be called between beginRegister() and endRegister()."); version (D_BetterC) assert(pass < passes.length, "Update pass doesn't exist."); else @@ -426,7 +427,7 @@ export struct EntityManager // enum EventName = fullyQualifiedName!(Unqual!(EventParamType));//.stringof; ushort evt = events_map.get(cast(char[]) EventName, ushort.max); assert(evt != ushort.max, - "Can't register system \"" ~ SystemName + "Can't register system \"" ~ SystemName ~ "\" due to non existing event \"" ~ EventName ~ "\"."); callers[i].callback = cast(void*)&callEventHandler!(EventParamType); @@ -469,14 +470,14 @@ export struct EntityManager bool checkExcludedComponentsSomething(Sys)() { return __traits(compiles, allSameType!(string, typeof(Sys.ExcludedComponents))) && allSameType!(string, - typeof(Sys.ExcludedComponents)) && isExpressions!(Sys.ExcludedComponents); + typeof(Sys.ExcludedComponents)) && isExpressions!(Sys.ExcludedComponents); } foreach (member; __traits(allMembers, Sys.EntitiesData)) { alias MemberType = typeof(__traits(getMember, Sys.EntitiesData, member)); if (member == "length" || member == "thread_id" || member == "job_id" - || is(MemberType == Entity[]) || is(MemberType == const(Entity)[])) + || is(MemberType == Entity[]) || is(MemberType == const(Entity)[])) { //continue; } @@ -659,7 +660,7 @@ export struct EntityManager } static void allocateSystemComponents(ComponentsIndices!component_counts components_info)( - ref System system) + ref System system) { size_t req = components_info.req.length; size_t opt = components_info.optional.length; @@ -693,14 +694,14 @@ export struct EntityManager bool checkExcludedComponentsSomething(Sys)() { return __traits(compiles, allSameType!(string, typeof(Sys.ExcludedComponents))) && allSameType!(string, - typeof(Sys.ExcludedComponents)) && isExpressions!(Sys.ExcludedComponents); + typeof(Sys.ExcludedComponents)) && isExpressions!(Sys.ExcludedComponents); } foreach (member; __traits(allMembers, Sys.EntitiesData)) { alias MemberType = typeof(__traits(getMember, Sys.EntitiesData, member)); if (member == "length" || member == "thread_id" || member == "job_id" - || is(MemberType == Entity[]) || is(MemberType == const(Entity)[])) + || is(MemberType == Entity[]) || is(MemberType == const(Entity)[])) { if (is(MemberType == Entity[]) || is(MemberType == const(Entity)[])) components_info.entites_array = member; @@ -808,23 +809,23 @@ export struct EntityManager else static if (member == "length") { static assert(isIntegral!(MemberType), - "EntitiesData 'length' member must be integral type."); + "EntitiesData 'length' member must be integral type."); static assert(MemberType.sizeof > 1, - "EntitiesData 'length' member can't be byte or ubyte."); + "EntitiesData 'length' member can't be byte or ubyte."); } else static if (member == "thread_id") { static assert(isIntegral!(MemberType), - "EntitiesData 'thread_id' member must be integral type."); + "EntitiesData 'thread_id' member must be integral type."); static assert(MemberType.sizeof > 1, - "EntitiesData 'thread_id' member can't be byte or ubyte."); + "EntitiesData 'thread_id' member can't be byte or ubyte."); } else static if (member == "job_id") { static assert(isIntegral!(MemberType), - "EntitiesData 'job_id' member must be integral type."); + "EntitiesData 'job_id' member must be integral type."); static assert(MemberType.sizeof > 1, - "EntitiesData 'job_id' member can't be byte or ubyte."); + "EntitiesData 'job_id' member can't be byte or ubyte."); } else static if (!(isArray!(MemberType))) static assert(0, "EntitiesData members should be arrays of elements!"); @@ -838,7 +839,7 @@ export struct EntityManager ushort comp = components_map.get(cast(char[]) comp_info.type, ushort.max); version (D_BetterC) assert(comp != ushort.max, - "Can't register system \"" ~ SystemName + "Can't register system \"" ~ SystemName ~ "\" due to non existing component."); else assert(comp != ushort.max, "Can't register system \"" ~ SystemName @@ -850,7 +851,7 @@ export struct EntityManager ushort comp = components_map.get(cast(char[]) comp_info.type, ushort.max); version (D_BetterC) assert(comp != ushort.max, - "Can't register system \"" ~ SystemName + "Can't register system \"" ~ SystemName ~ "\" due to non existing component."); else assert(comp != ushort.max, "Can't register system \"" ~ SystemName @@ -862,7 +863,7 @@ export struct EntityManager ushort comp = components_map.get(cast(char[]) comp_info.type, ushort.max); version (D_BetterC) assert(comp != ushort.max, - "Can't register system \"" ~ SystemName + "Can't register system \"" ~ SystemName ~ "\" due to non existing component."); else assert(comp != ushort.max, "Can't register system \"" ~ SystemName @@ -874,7 +875,7 @@ export struct EntityManager ushort comp = components_map.get(cast(char[]) comp_info.type, ushort.max); version (D_BetterC) assert(comp != ushort.max, - "Can't register system \"" ~ SystemName + "Can't register system \"" ~ SystemName ~ "\" due to non existing component."); else assert(comp != ushort.max, "Can't register system \"" ~ SystemName @@ -886,7 +887,7 @@ export struct EntityManager ushort comp = components_map.get(cast(char[]) comp_info.type, ushort.max); version (D_BetterC) assert(comp != ushort.max, - "Can't register system \"" ~ SystemName + "Can't register system \"" ~ SystemName ~ "\" due to non existing component."); else assert(comp != ushort.max, "Can't register system \"" ~ SystemName @@ -896,14 +897,14 @@ export struct EntityManager } static void fillInputData(ref Sys.EntitiesData input_data, EntityInfo* info, - EntitiesBlock* block, uint offset, uint entities_count, System* system) + EntitiesBlock* block, uint offset, uint entities_count, System* system) { //enum ComponentsIndices components_info = getComponentsInfo(); static if (components_info.entites_array) { __traits(getMember, input_data, components_info.entites_array) = ( - cast(Entity*) block.dataBegin())[offset .. entities_count]; + cast(Entity*) block.dataBegin())[offset .. entities_count]; } static if (hasMember!(Sys.EntitiesData, "length")) @@ -923,8 +924,7 @@ export struct EntityManager __traits(getMember, input_data, comp_info.name) = ( cast(typeof( (typeof(__traits(getMember, Sys.EntitiesData, comp_info.name))).init[0] - )*) - (cast(void*) block + info.deltas[system.m_components[iii]]) + )*)(cast(void*) block + info.deltas[system.m_components[iii]]) )[offset .. entities_count]; } @@ -932,7 +932,7 @@ export struct EntityManager .. components_info.m_optional_counter]) { if (system.m_optional_components[iii] < info.deltas.length - && info.deltas[system.m_optional_components[iii]] != 0) + && info.deltas[system.m_optional_components[iii]] != 0) { __traits(getMember, input_data, comp_info.name) = (cast(ForeachType!(typeof(__traits(getMember, Sys.EntitiesData, comp_info.name)))*)(cast( @@ -1031,7 +1031,7 @@ export struct EntityManager static if (hasMember!(Sys.EntitiesData, "thread_id")) { input_data.thread_id = cast( - typeof(input_data.thread_id)) data.thread_id; + typeof(input_data.thread_id)) data.thread_id; } static if (hasMember!(Sys.EntitiesData, "job_id")) @@ -1042,7 +1042,7 @@ export struct EntityManager //s.onUpdate(input_data); (cast(typeof(&__traits(getOverloads, s, "onUpdate")[OnUpdateOverloadNum])) data.update_delegate)( - input_data); + input_data); } block = block.next_block; offset = 0; @@ -1112,15 +1112,15 @@ export struct EntityManager foreach (func; __traits(getOverloads, Sys, func_name)) { static if ((Parameters!(func)).length == 1 - && is(Parameters!(func)[0] == Sys.EntitiesData) - && is(ReturnType!(func) == RetType)) + && is(Parameters!(func)[0] == Sys.EntitiesData) + && is(ReturnType!(func) == RetType)) { static RetType callFunc(ref ListenerCallData data) { Sys* s = cast(Sys*) data.system.m_system_pointer; Sys.EntitiesData input_data; fillInputData(input_data, data.block.type_info, - data.block, data.begin, data.end, data.system); + data.block, data.begin, data.end, data.system); static if (is(RetTyp == void)) mixin("s." ~ func_name ~ "(input_data)"); else @@ -1141,8 +1141,8 @@ export struct EntityManager foreach (func; __traits(getOverloads, Sys, func_name)) { static if ((Parameters!(func)).length == 1 - && is(Parameters!(func)[0] == EntityInfo*) - && is(ReturnType!(func) == RetType)) + && is(Parameters!(func)[0] == EntityInfo*) + && is(ReturnType!(func) == RetType)) { static RetType callFunc(void* system_pointer, EntityInfo* info) { @@ -1177,14 +1177,16 @@ export struct EntityManager system.m_priority = priority; //(cast(Sys*) system.m_system_pointer).__ecsInitialize(); //system.jobs = (cast(Sys*) system.m_system_pointer)._ecs_jobs; - static if(__traits(hasMember, Sys ,"__becs_jobs_count"))system.jobs = Mallocator.makeArray!(Job)(Sys.__becs_jobs_count); - else system.jobs = Mallocator.makeArray!(Job)(32); + static if (__traits(hasMember, Sys, "__becs_jobs_count")) + system.jobs = Mallocator.makeArray!(Job)(Sys.__becs_jobs_count); + else + system.jobs = Mallocator.makeArray!(Job)(32); static if (OnUpdateOverloadNum != -1) { Sys* s = cast(Sys*) system.m_system_pointer; system.m_update_delegate = cast(void delegate())&__traits(getOverloads, - s, "onUpdate")[OnUpdateOverloadNum]; + s, "onUpdate")[OnUpdateOverloadNum]; } genCompList(system, components_map); @@ -1192,10 +1194,10 @@ export struct EntityManager foreach (iii, comp_info; components_info.readonlyDeps) { ushort comp = external_dependencies_map.get(cast(const(char)[]) comp_info.type, - ushort.max); + ushort.max); version (D_BetterC) assert(comp != ushort.max, - "Can't register system \"" ~ SystemName + "Can't register system \"" ~ SystemName ~ "\" due to non existing dependency."); else assert(comp != ushort.max, "Can't register system \"" ~ SystemName @@ -1208,7 +1210,7 @@ export struct EntityManager ushort comp = external_dependencies_map.get(cast(char[]) comp_info.type, ushort.max); version (D_BetterC) assert(comp != ushort.max, - "Can't register system \"" ~ SystemName + "Can't register system \"" ~ SystemName ~ "\" due to non existing dependency."); else assert(comp != ushort.max, "Can't register system \"" ~ SystemName @@ -1300,8 +1302,8 @@ export struct EntityManager // } static if (hasMember!(Comp, "onDestroy") && isFunction!(Comp.onDestroy) - && is(ReturnType!(Comp.onDestroy) == void) - && Parameters!(Comp.onDestroy).length == 0) + && is(ReturnType!(Comp.onDestroy) == void) + && Parameters!(Comp.onDestroy).length == 0) { static void callDestroy(void* pointer) nothrow @nogc { @@ -1312,7 +1314,7 @@ export struct EntityManager } static if (hasMember!(Comp, "onCreate") && isFunction!(Comp.onCreate) - && is(ReturnType!(Comp.onCreate) == void) && Parameters!(Comp.onCreate).length == 0) + && is(ReturnType!(Comp.onCreate) == void) && Parameters!(Comp.onCreate).length == 0) { static void callCreate(void* pointer) nothrow @nogc { @@ -1358,7 +1360,7 @@ export struct EntityManager // } static if (hasMember!(Ev, "onDestroy") && isFunction!(Ev.onDestroy) - && is(ReturnType!(Ev.onDestroy) == void) && Parameters!(Ev.onDestroy).length == 0) + && is(ReturnType!(Ev.onDestroy) == void) && Parameters!(Ev.onDestroy).length == 0) { static void callDestroy(void* pointer) { @@ -1392,10 +1394,10 @@ export struct EntityManager Sys* s; static assert(isDelegate!func, "Function must be delegate."); static assert(__traits(hasMember, Sys, "EntitiesData"), - "Can't call function with system which hasn't EntitesData structure."); + "Can't call function with system which hasn't EntitesData structure."); ///TODO: make possibly to call function to group without system with onUpdate function static assert(__traits(hasMember, Sys, "onUpdate"), - "Can't call function with system which hasn't onUpdate function callback."); + "Can't call function with system which hasn't onUpdate function callback."); // static assert(is(SetFunctionAttributes!(T, functionLinkage!(s.onUpdate), // functionAttributes!(s.onUpdate)) == typeof(&s.onUpdate)), // "Function must match system update function."); FIXME: It's lead to crash on android build @@ -1403,7 +1405,9 @@ export struct EntityManager System* system = getSystem(becsID!Sys); assert(system != null, - "System must be registered in EntityManager before any funcion can be called."); + "System must be registered in EntityManager before any funcion can be called."); + assert(system.isAlive(), "System must be alive (registered) in order to call entities function on its entities"); + if (!system.m_any_system_caller) return; @@ -1445,7 +1449,7 @@ export struct EntityManager foreach (info; caller.infos) { CallData data = CallData(caller.system_id, sys, info, - sys.m_update_delegate); + sys.m_update_delegate); data.update(); } } @@ -1467,7 +1471,7 @@ export struct EntityManager assert(!register_state); assert(pass < passes.length); assert(m_dispatch_jobs, - "Can't update with multithreading without JobDispatch function. Please use setJobDispatchFunc()."); + "Can't update with multithreading without JobDispatch function. Please use setJobDispatchFunc()."); Vector!CallData tmp_datas; tmp_datas.reserve(8); @@ -1480,7 +1484,7 @@ export struct EntityManager void nextJob() { CallData[] callers = m_call_data_allocator.getCallData( - cast(uint) tmp_datas.length); + cast(uint) tmp_datas.length); //callers[0 .. $] = tmp_datas[0 .. $]; memcpy(callers.ptr, &tmp_datas[0], CallData.sizeof * tmp_datas.length); tmp_datas.clear(); @@ -1535,7 +1539,7 @@ export struct EntityManager //if this info will fill job if ((blocks_count - 1) * info.max_entities + entities_count - + info.last_block.entities_count - first_elem >= entities_per_job) + + info.last_block.entities_count - first_elem >= entities_per_job) { int reamaining_entities = (entities_per_job - entities_count - ( first_block.entities_count - first_elem)); @@ -1556,9 +1560,9 @@ export struct EntityManager assert(entities_per_job == full_blocks_count * info.max_entities + entities_count + ( first_block.entities_count - first_elem)); CallData data = CallData(caller.system_id, sys, - info, sys.m_update_delegate, first_block, - cast(ushort)(full_blocks_count + 1), - cast(ushort) first_elem, 0); + info, sys.m_update_delegate, first_block, + cast(ushort)(full_blocks_count + 1), + cast(ushort) first_elem, 0); tmp_datas.add(data); first_elem = 0; blocks_count -= full_blocks_count + 1; @@ -1567,14 +1571,14 @@ export struct EntityManager else { entities_count += full_blocks_count * info.max_entities + ( - first_block.entities_count - first_elem); // - first_elem; + first_block.entities_count - first_elem); // - first_elem; uint last_elem = entities_per_job - entities_count; // + first_elem - 1; assert(last_elem > 0); assert(last_elem <= block.entities_count); CallData data = CallData(caller.system_id, sys, - info, sys.m_update_delegate, first_block, - cast(ushort)(full_blocks_count + 2), - cast(ushort) first_elem, cast(ushort) last_elem); + info, sys.m_update_delegate, first_block, + cast(ushort)(full_blocks_count + 2), + cast(ushort) first_elem, cast(ushort) last_elem); tmp_datas.add(data); first_elem = last_elem; blocks_count -= full_blocks_count + 1; @@ -1591,8 +1595,8 @@ export struct EntityManager uint last_elem = entities_per_job - entities_count; assert(last_elem > 0); CallData data = CallData(caller.system_id, sys, - info, sys.m_update_delegate, first_block, 1, - cast(ushort) first_elem, cast(ushort)(first_elem + last_elem)); + info, sys.m_update_delegate, first_block, 1, + cast(ushort) first_elem, cast(ushort)(first_elem + last_elem)); tmp_datas.add(data); first_elem += last_elem; assert(first_elem <= first_block.entities_count); @@ -1612,7 +1616,7 @@ export struct EntityManager { //take whole info blocks CallData data = CallData(caller.system_id, sys, info, sys.m_update_delegate, - first_block, cast(ushort) blocks_count, cast(ushort) first_elem); + first_block, cast(ushort) blocks_count, cast(ushort) first_elem); tmp_datas.add(data); entities_count += (blocks_count - 1) * info.max_entities + info.last_block.entities_count - first_elem; @@ -1627,7 +1631,7 @@ export struct EntityManager } export void setMultithreadingCallbacks(void delegate(JobGroup) dispatch_callback, - uint delegate() get_id_callback) + uint delegate() get_id_callback) { m_dispatch_jobs = cast(void delegate(JobGroup jobs) nothrow @nogc) dispatch_callback; m_thread_id_func = cast(uint delegate() nothrow @nogc) get_id_callback; @@ -1692,7 +1696,7 @@ export struct EntityManager if (components[comp].size == 0) continue; memcpy(temp.entity_data.ptr + info.tmpl_deltas[comp], - components[comp].init_data.ptr, components[comp].size); + components[comp].init_data.ptr, components[comp].size); } } else @@ -1703,8 +1707,8 @@ export struct EntityManager if (components[comp].size == 0) continue; memcpy(cast(void*) temp.entity_data.ptr + info.tmpl_deltas[comp], - cast(void*) block + info.deltas[comp] + components[comp].size * index, - components[comp].size); + cast(void*) block + info.deltas[comp] + components[comp].size * index, + components[comp].size); } } @@ -1753,7 +1757,7 @@ export struct EntityManager if (components[comp].size == 0) continue; memcpy(temp.entity_data.ptr + info.tmpl_deltas[comp], - components[comp].init_data.ptr, components[comp].size); + components[comp].init_data.ptr, components[comp].size); } return temp; @@ -1769,18 +1773,18 @@ export struct EntityManager remove_components_ids = array of components to remove from base template */ export EntityTemplate* allocateTemplate(EntityTemplate* base_tmpl, - ushort[] components_ids, ushort[] remove_components_ids = null) + ushort[] components_ids, ushort[] remove_components_ids = null) { size_t len = base_tmpl.info.components.length + components_ids.length; ushort[] ids = (cast(ushort*) alloca(ushort.sizeof * len))[0 .. len]; memcpy(ids.ptr, base_tmpl.info.components.ptr, - ushort.sizeof * base_tmpl.info.components.length); + ushort.sizeof * base_tmpl.info.components.length); memcpy(ids.ptr + base_tmpl.info.components.length, components_ids.ptr, - ushort.sizeof * components_ids.length); + ushort.sizeof * components_ids.length); qsort(ids.ptr, ids.length, ushort.sizeof, &compareUShorts); qsort(remove_components_ids.ptr, remove_components_ids.length, - ushort.sizeof, &compareUShorts); + ushort.sizeof, &compareUShorts); { uint k = 0; uint j = 1; @@ -1820,20 +1824,20 @@ export struct EntityManager foreach (comp; info.components) { if (comp < base_tmpl.info.tmpl_deltas.length - && base_tmpl.info.tmpl_deltas[comp] != ushort.max) //copy data from base component - { + && base_tmpl.info.tmpl_deltas[comp] != ushort.max) //copy data from base component + { if (components[comp].size == 0) continue; memcpy(temp.entity_data.ptr + info.tmpl_deltas[comp], - base_tmpl.entity_data.ptr + base_tmpl.info.tmpl_deltas[comp], - components[comp].size); + base_tmpl.entity_data.ptr + base_tmpl.info.tmpl_deltas[comp], + components[comp].size); } else //fill with default data { if (components[comp].size == 0) continue; memcpy(temp.entity_data.ptr + info.tmpl_deltas[comp], - components[comp].init_data.ptr, components[comp].size); + components[comp].init_data.ptr, components[comp].size); } } @@ -1887,7 +1891,7 @@ export struct EntityManager alignNum(info.size, info.alignment); uint block_memory = cast(uint)( - m_page_size - EntitiesBlock.sizeof - (info.size - components_size)); + m_page_size - EntitiesBlock.sizeof - (info.size - components_size)); //uint entity_comps_size = EntityID.sizeof; uint mem_begin = EntitiesBlock.sizeof; @@ -1915,15 +1919,14 @@ export struct EntityManager if (system.m_update is null) { if (system.m_add_entity || system.m_remove_entity - || system.m_change_entity || system.m_event_callers.length) + || system.m_change_entity || system.m_event_callers.length) connectListenerToEntityInfo(*info, cast(uint) i); continue; } addSystemCaller(*info, cast(uint) i); } - info.comp_add_info = Mallocator.makeArray!(EntityInfo*)(gEntityManager.components.length); - //info.comp_rem_info = Mallocator.makeArray!(EntityInfo*)(gEntityManager.components.length); + info.comp_add_info = Mallocator.makeArray!(EntityInfo*)(info.deltas.length); info.comp_rem_info = Mallocator.makeArray!(EntityInfo*)(info.deltas.length); foreach (comp; info.components) @@ -2082,7 +2085,9 @@ export struct EntityManager } ///call Custom Entity Filter test if function exists - if(system.m_filter_entity && !(cast(bool function(void* system_pointer, EntityInfo* info) @nogc nothrow)system.m_filter_entity)(system, &entity))return; + if (system.m_filter_entity && !(cast(bool function(void* system_pointer, EntityInfo* info) @nogc nothrow) system + .m_filter_entity)(system, &entity)) + return; entity.systems[system_id] = true; } @@ -2127,7 +2132,8 @@ export struct EntityManager System* system = &systems[system_id]; connectListenerToEntityInfo(info, system_id); - if(!info.systems[system_id])return; + if (!info.systems[system_id]) + return; uint index = 0; for (; index < passes[system.m_pass].system_callers.length; index++) @@ -2236,7 +2242,7 @@ export struct EntityManager if (comp_size == 0) continue; memcpy(cast(void*) new_block + new_info.deltas[comp] + new_block.entities_count * comp_size, - cast(void*) block + info.deltas[comp] + ind * comp_size, comp_size); + cast(void*) block + info.deltas[comp] + ind * comp_size, comp_size); } new_block.entities_count++; @@ -2250,7 +2256,7 @@ export struct EntityManager if (!info.systems[listener]) { callAddEntityListener(&systems[listener], new_info, new_block, - new_block.entities_count - 1, new_block.entities_count); + new_block.entities_count - 1, new_block.entities_count); } } } @@ -2262,7 +2268,7 @@ export struct EntityManager if (info.systems[listener]) { callChangeEntityListener(&systems[listener], new_info, new_block, - new_block.entities_count - 1, new_block.entities_count, del_ids); + new_block.entities_count - 1, new_block.entities_count, del_ids); } } } @@ -2413,7 +2419,7 @@ export struct EntityManager if (!info.systems[listener]) { callAddEntityListener(&systems[listener], new_info, new_block, - new_block.entities_count - 1, new_block.entities_count); + new_block.entities_count - 1, new_block.entities_count); } } } @@ -2425,7 +2431,7 @@ export struct EntityManager if (info.systems[listener]) { callChangeEntityListener(&systems[listener], new_info, new_block, - new_block.entities_count - 1, new_block.entities_count, new_ids); + new_block.entities_count - 1, new_block.entities_count, new_ids); } } } @@ -2468,7 +2474,7 @@ export struct EntityManager { if (components[ref_.component_id].size != 0) data.changeEntitiesList.add( - (cast(ubyte*) ref_.ptr)[0 .. components[ref_.component_id].size]); + (cast(ubyte*) ref_.ptr)[0 .. components[ref_.component_id].size]); } } @@ -2518,12 +2524,12 @@ export struct EntityManager ushort size = components[comp].size; if (size != 0) memcpy(cast(void*) new_block + info.deltas[comp] + new_id * size, - cast(void*) block + info.deltas[comp] + size * index, size); + cast(void*) block + info.deltas[comp] + size * index, size); if (components[comp].create_callback) { components[comp].create_callback( - cast(void*) new_block + info.deltas[comp] + new_id * size); + cast(void*) new_block + info.deltas[comp] + new_id * size); } } @@ -2580,7 +2586,7 @@ export struct EntityManager uint size = components[comp].size; if (size != 0) memcpy(cast(void*) block + info.deltas[comp] + size * id, - tmpl.entity_data.ptr + info.tmpl_deltas[comp], size); + tmpl.entity_data.ptr + info.tmpl_deltas[comp], size); } foreach (comp; replacement) @@ -2602,7 +2608,7 @@ export struct EntityManager if (components[comp].create_callback) { components[comp].create_callback( - cast(void*) block + info.deltas[comp] + id * components[comp].size); + cast(void*) block + info.deltas[comp] + id * components[comp].size); } } @@ -2737,7 +2743,7 @@ export struct EntityManager } private void removeEntityNoID(Entity* entity, EntitiesBlock* block, - bool call_destructors = false) nothrow @nogc + bool call_destructors = false) nothrow @nogc { EntityInfo* info = block.type_info; @@ -2869,7 +2875,7 @@ export struct EntityManager } private static void callAddEntityListener(System* system, EntityInfo* info, - EntitiesBlock* block, int begin, int end) @nogc nothrow + EntitiesBlock* block, int begin, int end) @nogc nothrow { ListenerCallData data; data.system = system; @@ -2880,7 +2886,7 @@ export struct EntityManager } private void callRemoveEntityListeners(EntityInfo* info, EntitiesBlock* block, int begin, - int end) @nogc nothrow + int end) @nogc nothrow { foreach (listener; info.remove_listeners) { @@ -2890,7 +2896,7 @@ export struct EntityManager } private static void callRemoveEntityListener(System* system, - EntityInfo* info, EntitiesBlock* block, int begin, int end) @nogc nothrow + EntityInfo* info, EntitiesBlock* block, int begin, int end) @nogc nothrow { ListenerCallData data; data.system = system; @@ -2901,7 +2907,7 @@ export struct EntityManager } private void callChangeEntityListener(System* system, EntityInfo* info, - EntitiesBlock* block, int begin, int end, ushort[] ch_ids) @nogc nothrow + EntitiesBlock* block, int begin, int end, ushort[] ch_ids) @nogc nothrow { int i = 0; int j = 0; @@ -3055,7 +3061,7 @@ export struct EntityManager foreach (caller; events[i].callers) { if (call_data.block.type_info.systems[caller.system.m_id] == false - || !caller.system.enabled || !caller.system.willExecute) + || !caller.system.enabled || !caller.system.willExecute) continue; call_data.system_pointer = caller.system.m_system_pointer; (cast(void function(ref EventCallData) nothrow @nogc) caller @@ -3122,7 +3128,7 @@ export struct EntityManager continue; if (system.enabled && system.m_begin) system.m_execute = (cast(bool function(void*)) system.m_begin)( - system.m_system_pointer); + system.m_system_pointer); } } @@ -3135,9 +3141,8 @@ export struct EntityManager foreach (ref system; systems) { if (system.isAlive() == false) - { continue; - } + if (system.enabled && system.m_end) (cast(void function(void*)) system.m_end)(system.m_system_pointer); } @@ -3276,7 +3281,7 @@ export struct EntityManager } qsort(pass.system_callers.array.ptr, pass.system_callers.length, - (SystemCaller*).sizeof, &compareSystems); + (SystemCaller*).sizeof, &compareSystems); foreach (i, caller; pass.system_callers) caller.job_group.id = cast(uint) i; @@ -3403,7 +3408,7 @@ export struct EntityManager if (comp_add_info.length <= id) { EntityInfo*[] new_infos = Mallocator.makeArray!(EntityInfo*)( - gEntityManager.components.length); + gEntityManager.components.length); if (comp_add_info !is null) { //new_infos[0 .. comp_add_info.length] = comp_add_info[0 .. $]; @@ -3448,7 +3453,7 @@ export struct EntityManager return new_info; } - EntityInfo* getNewInfoRemove(ushort id) return + EntityInfo* getNewInfoRemove(ushort id) return { /*if (comp_rem_info.length <= id) { @@ -3491,7 +3496,8 @@ export struct EntityManager export bool hasComponent(ushort component_id) { - if(component_id >= deltas.length || !deltas[component_id])return false; + if (component_id >= deltas.length || !deltas[component_id]) + return false; return true; } @@ -3560,7 +3566,7 @@ export struct EntityManager struct EntitiesBlock { ///return pointer to first element in block - export void* dataBegin() nothrow @nogc pure return + export void* dataBegin() nothrow @nogc pure return { ushort dif = EntitiesBlock.sizeof; return cast(void*)&this + dif; @@ -3643,7 +3649,6 @@ export struct EntityManager export void execute() nothrow @nogc { - //gEntityManager.getThreadID(); foreach (ref caller; callers) { caller.thread_id = gEntityManager.threadID(); @@ -3688,32 +3693,32 @@ export struct EntityManager struct ThreadData { - ref Vector!EntityID entitesToRemove() @nogc nothrow return + ref Vector!EntityID entitesToRemove() @nogc nothrow return { return entities_to_remove[data_index]; } - ref SimpleVector changeEntitiesList() @nogc nothrow return + ref SimpleVector changeEntitiesList() @nogc nothrow return { return change_entities_list[data_index]; } - ref Vector!(EntityInfo*) infosToUpdate() @nogc nothrow return + ref Vector!(EntityInfo*) infosToUpdate() @nogc nothrow return { return infos_to_update[data_index]; } - ref Vector!EntityID entitiesToRemovePrev() @nogc nothrow return + ref Vector!EntityID entitiesToRemovePrev() @nogc nothrow return { return entities_to_remove[1 - data_index]; } - ref SimpleVector changeEntitiesListPrev() @nogc nothrow return + ref SimpleVector changeEntitiesListPrev() @nogc nothrow return { return change_entities_list[1 - data_index]; } - ref Vector!(EntityInfo*) infosToUpdatePrev() @nogc nothrow return + ref Vector!(EntityInfo*) infosToUpdatePrev() @nogc nothrow return { return infos_to_update[1 - data_index]; } @@ -3849,5 +3854,5 @@ export struct EntityManager return ret; } } - + } From 6bf8837e8f6f257e8eac4f9ce2558f276a2b6fe2 Mon Sep 17 00:00:00 2001 From: Dawid Masiukiewicz Date: Sat, 12 Nov 2022 11:41:08 +0000 Subject: [PATCH 208/217] Update codecov token --- .gitlab-ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 555e6d5..f1d8ecc 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -56,7 +56,7 @@ coverage_test_dmd: - mkdir reports - binaries/dmd_unittest_cov after_script: - - bash <(curl -s https://codecov.io/bash) -s reports -t 1a0c0169-a721-4085-8252-fed4755dcd8c + - bash <(curl -s https://codecov.io/bash) -s reports -t df87b1d8-85f4-4584-96e3-1315d27ec2c5 wasm: stage: build_wasm From ed0603a67509ce5e846df9eeeec0d52ab22974b6 Mon Sep 17 00:00:00 2001 From: Mergul Date: Wed, 18 Jan 2023 14:40:59 +0100 Subject: [PATCH 209/217] Update copyright notice --- dub.json | 2 +- source/bubel/ecs/atomic.d | 2 +- source/bubel/ecs/attributes.d | 2 +- source/bubel/ecs/block_allocator.d | 2 +- source/bubel/ecs/core.d | 2 +- source/bubel/ecs/entity.d | 2 +- source/bubel/ecs/events.d | 2 +- source/bubel/ecs/hash_map.d | 2 +- source/bubel/ecs/id_manager.d | 2 +- source/bubel/ecs/manager.d | 6 +----- source/bubel/ecs/package.d | 2 +- source/bubel/ecs/simple_vector.d | 2 +- source/bubel/ecs/std.d | 2 +- source/bubel/ecs/system.d | 2 +- source/bubel/ecs/traits.d | 2 +- source/bubel/ecs/vector.d | 2 +- 16 files changed, 16 insertions(+), 20 deletions(-) diff --git a/dub.json b/dub.json index 1461c9d..602117d 100755 --- a/dub.json +++ b/dub.json @@ -5,7 +5,7 @@ "Michał Masiukiewicz", "Dawid Masiukiewicz" ], "description": "Dynamic Entity Component System", - "copyright": "Copyright © 2018-2019, Michał Masiukiewicz, Dawid Masiukiewicz", + "copyright": "Copyright © 2018-2023, Michał Masiukiewicz, Dawid Masiukiewicz", "license": "BSD 3-clause", "sourcePaths" : ["source\/"], "excludedSourceFiles":[ diff --git a/source/bubel/ecs/atomic.d b/source/bubel/ecs/atomic.d index 8ea43df..40f0aa9 100644 --- a/source/bubel/ecs/atomic.d +++ b/source/bubel/ecs/atomic.d @@ -4,7 +4,7 @@ It's internal code. Can be used for atomics if emscripten backend will be used. This module contain atomic operations which include support for emscripten atomics functions. Emscripten functions are contained in API similar to druntime. -Copyright: Copyright © 2018-2019, Dawid Masiukiewicz, Michał Masiukiewicz +Copyright: Copyright © 2018-2023, Dawid Masiukiewicz, Michał Masiukiewicz License: BSD 3-clause, see LICENSE file in project root folder. */ module bubel.ecs.atomic; diff --git a/source/bubel/ecs/attributes.d b/source/bubel/ecs/attributes.d index d094aad..1a041d4 100644 --- a/source/bubel/ecs/attributes.d +++ b/source/bubel/ecs/attributes.d @@ -17,7 +17,7 @@ Struct EntitiesData } --- -Copyright: Copyright © 2018-2019, Dawid Masiukiewicz, Michał Masiukiewicz +Copyright: Copyright © 2018-2023, Dawid Masiukiewicz, Michał Masiukiewicz License: BSD 3-clause, see LICENSE file in project root folder. */ module bubel.ecs.attributes; diff --git a/source/bubel/ecs/block_allocator.d b/source/bubel/ecs/block_allocator.d index 6894a17..0ab735e 100644 --- a/source/bubel/ecs/block_allocator.d +++ b/source/bubel/ecs/block_allocator.d @@ -3,7 +3,7 @@ It's internal code. Module contain memory allocator. -Copyright: Copyright © 2018-2019, Dawid Masiukiewicz, Michał Masiukiewicz +Copyright: Copyright © 2018-2023, Dawid Masiukiewicz, Michał Masiukiewicz License: BSD 3-clause, see LICENSE file in project root folder. */ module bubel.ecs.block_allocator; diff --git a/source/bubel/ecs/core.d b/source/bubel/ecs/core.d index f8511ea..c796423 100644 --- a/source/bubel/ecs/core.d +++ b/source/bubel/ecs/core.d @@ -67,7 +67,7 @@ Struct System1 } --- -Copyright: Copyright © 2018-2019, Dawid Masiukiewicz, Michał Masiukiewicz +Copyright: Copyright © 2018-2023, Dawid Masiukiewicz, Michał Masiukiewicz License: BSD 3-clause, see LICENSE file in project root folder. */ module bubel.ecs.core; diff --git a/source/bubel/ecs/entity.d b/source/bubel/ecs/entity.d index cb3f752..9b42c31 100644 --- a/source/bubel/ecs/entity.d +++ b/source/bubel/ecs/entity.d @@ -1,7 +1,7 @@ /************************************************************************************************************************ Entity module. -Copyright: Copyright © 2018-2019, Dawid Masiukiewicz, Michał Masiukiewicz +Copyright: Copyright © 2018-2023, Dawid Masiukiewicz, Michał Masiukiewicz License: BSD 3-clause, see LICENSE file in project root folder. */ module bubel.ecs.entity; diff --git a/source/bubel/ecs/events.d b/source/bubel/ecs/events.d index f123e86..11816a1 100644 --- a/source/bubel/ecs/events.d +++ b/source/bubel/ecs/events.d @@ -1,5 +1,5 @@ /************************************************************************************************************************ -Copyright: Copyright © 2018-2019, Dawid Masiukiewicz, Michał Masiukiewicz +Copyright: Copyright © 2018-2023, Dawid Masiukiewicz, Michał Masiukiewicz License: BSD 3-clause, see LICENSE file in project root folder. */ module bubel.ecs.events; diff --git a/source/bubel/ecs/hash_map.d b/source/bubel/ecs/hash_map.d index 1af0fd8..0ad4dc5 100755 --- a/source/bubel/ecs/hash_map.d +++ b/source/bubel/ecs/hash_map.d @@ -1,5 +1,5 @@ /************************************************************************************************************************ -Copyright: Copyright © 2018-2019, Dawid Masiukiewicz, Michał Masiukiewicz +Copyright: Copyright © 2018-2023, Dawid Masiukiewicz, Michał Masiukiewicz License: BSD 3-clause, see LICENSE file in project root folder. */ module bubel.ecs.hash_map; diff --git a/source/bubel/ecs/id_manager.d b/source/bubel/ecs/id_manager.d index ccb4fac..2054cbb 100644 --- a/source/bubel/ecs/id_manager.d +++ b/source/bubel/ecs/id_manager.d @@ -1,5 +1,5 @@ /************************************************************************************************************************ -Copyright: Copyright © 2018-2019, Dawid Masiukiewicz, Michał Masiukiewicz +Copyright: Copyright © 2018-2023, Dawid Masiukiewicz, Michał Masiukiewicz License: BSD 3-clause, see LICENSE file in project root folder. */ module bubel.ecs.id_manager; diff --git a/source/bubel/ecs/manager.d b/source/bubel/ecs/manager.d index 323d2ab..a34d81c 100644 --- a/source/bubel/ecs/manager.d +++ b/source/bubel/ecs/manager.d @@ -1,7 +1,7 @@ /************************************************************************************************************************ Most important module. Almost every function is called from EntityManager. -Copyright: Copyright © 2018-2019, Dawid Masiukiewicz, Michał Masiukiewicz +Copyright: Copyright © 2018-2023, Dawid Masiukiewicz, Michał Masiukiewicz License: BSD 3-clause, see LICENSE file in project root folder. */ module bubel.ecs.manager; @@ -10,10 +10,6 @@ import std.algorithm : max; import std.conv : to; import std.traits; -//import core.atomic; -//import core.stdc.stdlib : qsort; -//import core.stdc.string; - import bubel.ecs.system; //not ordered as forward reference bug workaround import bubel.ecs.block_allocator; import bubel.ecs.entity; diff --git a/source/bubel/ecs/package.d b/source/bubel/ecs/package.d index 2b3b7f4..e2d8893 100644 --- a/source/bubel/ecs/package.d +++ b/source/bubel/ecs/package.d @@ -1,5 +1,5 @@ /************************************************************************************************************************ -Copyright: Copyright © 2018-2019, Dawid Masiukiewicz, Michał Masiukiewicz +Copyright: Copyright © 2018-2023, Dawid Masiukiewicz, Michał Masiukiewicz License: BSD 3-clause, see LICENSE file in project root folder. */ module ecs; diff --git a/source/bubel/ecs/simple_vector.d b/source/bubel/ecs/simple_vector.d index 02f3f3d..2fdaf31 100644 --- a/source/bubel/ecs/simple_vector.d +++ b/source/bubel/ecs/simple_vector.d @@ -1,5 +1,5 @@ /************************************************************************************************************************ -Copyright: Copyright © 2018-2019, Dawid Masiukiewicz, Michał Masiukiewicz +Copyright: Copyright © 2018-2023, Dawid Masiukiewicz, Michał Masiukiewicz License: BSD 3-clause, see LICENSE file in project root folder. */ module bubel.ecs.simple_vector; diff --git a/source/bubel/ecs/std.d b/source/bubel/ecs/std.d index d99a05c..8eb0d48 100644 --- a/source/bubel/ecs/std.d +++ b/source/bubel/ecs/std.d @@ -2,7 +2,7 @@ It's internal code! This module contain implementation of standard functionality. -Copyright: Copyright © 2018-2019, Dawid Masiukiewicz, Michał Masiukiewicz +Copyright: Copyright © 2018-2023, Dawid Masiukiewicz, Michał Masiukiewicz License: BSD 3-clause, see LICENSE file in project root folder. */ module bubel.ecs.std; diff --git a/source/bubel/ecs/system.d b/source/bubel/ecs/system.d index 0da2d96..8e9d0ba 100644 --- a/source/bubel/ecs/system.d +++ b/source/bubel/ecs/system.d @@ -1,7 +1,7 @@ /************************************************************************************************************************ System module. -Copyright: Copyright © 2018-2019, Dawid Masiukiewicz, Michał Masiukiewicz +Copyright: Copyright © 2018-2023, Dawid Masiukiewicz, Michał Masiukiewicz License: BSD 3-clause, see LICENSE file in project root folder. */ module bubel.ecs.system; diff --git a/source/bubel/ecs/traits.d b/source/bubel/ecs/traits.d index 42b1753..79901db 100644 --- a/source/bubel/ecs/traits.d +++ b/source/bubel/ecs/traits.d @@ -1,5 +1,5 @@ /************************************************************************************************************************ -Copyright: Copyright © 2018-2019, Dawid Masiukiewicz, Michał Masiukiewicz +Copyright: Copyright © 2018-2023, Dawid Masiukiewicz, Michał Masiukiewicz License: BSD 3-clause, see LICENSE file in project root folder. */ module bubel.ecs.traits; diff --git a/source/bubel/ecs/vector.d b/source/bubel/ecs/vector.d index e9b061d..6cf6274 100644 --- a/source/bubel/ecs/vector.d +++ b/source/bubel/ecs/vector.d @@ -1,5 +1,5 @@ /************************************************************************************************************************ -Copyright: Copyright © 2018-2019, Dawid Masiukiewicz, Michał Masiukiewicz +Copyright: Copyright © 2018-2023, Dawid Masiukiewicz, Michał Masiukiewicz License: BSD 3-clause, see LICENSE file in project root folder. */ module bubel.ecs.vector; From 65c6ea4489b9c9ad819e3bccff336ed69fa2fe27 Mon Sep 17 00:00:00 2001 From: Mergul Date: Wed, 18 Jan 2023 14:53:26 +0100 Subject: [PATCH 210/217] Fix demos compilation (using Meson) --- demos/meson.build | 2 +- demos/utils/meson.build | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/demos/meson.build b/demos/meson.build index deee071..8a3642d 100644 --- a/demos/meson.build +++ b/demos/meson.build @@ -27,7 +27,7 @@ executable('BubelECSDemos', [demos_src, external_src], bindbc_loader_dep, bindbc_sdl_dep, cimgui_dep, - decs_dep, + bubel_ecs_dep, ecs_utils_dep, sdl2_dep, sdl2_image_dep, diff --git a/demos/utils/meson.build b/demos/utils/meson.build index de9e958..708fc85 100644 --- a/demos/utils/meson.build +++ b/demos/utils/meson.build @@ -5,12 +5,12 @@ subdir('source/ecs_utils') utils_inc = include_directories('source/') # Dependencies -ecs_utils_lib = library('ecs_utils', utils_src, +ecs_utils_lib = library('ECSUtils', utils_src, include_directories : [demos_inc, external_inc, utils_inc], link_args : link_args, d_module_versions : versions, dependencies : [ - decs_dep, + bubel_ecs_dep, bindbc_loader_dep, bindbc_sdl_dep, ] From 9bf6f84d45e1eea4574ff95ba5e1d052576c89c6 Mon Sep 17 00:00:00 2001 From: Mergul Date: Wed, 18 Jan 2023 15:09:25 +0100 Subject: [PATCH 211/217] Update README Add information about how to use library with DUB package manager --- README.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/README.md b/README.md index 3f52b93..14e6d75 100644 --- a/README.md +++ b/README.md @@ -10,6 +10,13 @@ Bubel ECS was tested on Linux, Windows, Android and WASM. **Currently library is in beta stage so some significant API changes can appear.** +Package is available on [DUB package repository](https://code.dlang.org/packages/bubel-ecs). Usage: +``` + "dependencies": { + "bubel-ecs": "~>0.1.1" + } +``` + ## Design For core information about Entity-Component-System architectural pattern please read definition described at [Wikipedia](https://en.wikipedia.org/wiki/Entity_component_system). From 0702b007d17546243ca8172ce26148331220d99e Mon Sep 17 00:00:00 2001 From: Mergul Date: Thu, 9 Mar 2023 11:04:12 +0100 Subject: [PATCH 212/217] Fix unregisterSystem function and add function to get m_system_pointer from System --- source/bubel/ecs/hash_map.d | 6 ++-- source/bubel/ecs/manager.d | 26 ++++++++++------ source/bubel/ecs/system.d | 62 ++++++++++++++++++++++++++++++++++--- 3 files changed, 78 insertions(+), 16 deletions(-) diff --git a/source/bubel/ecs/hash_map.d b/source/bubel/ecs/hash_map.d index 0ad4dc5..66a0756 100755 --- a/source/bubel/ecs/hash_map.d +++ b/source/bubel/ecs/hash_map.d @@ -341,7 +341,7 @@ nothrow: int result; foreach (ref Key k; this) { - result = (cast(int delegate(ref Key k) nothrow)dg)(k); + result = (cast(int delegate(ref Key k) nothrow @nogc)dg)(k); if (result) break; } @@ -353,7 +353,7 @@ nothrow: int result; foreach (ref Value v; this) { - result = (cast(int delegate(ref Value v) nothrow)dg)(v); + result = (cast(int delegate(ref Value v) nothrow @nogc)dg)(v); if (result) break; } @@ -365,7 +365,7 @@ nothrow: int result; foreach (ref Key k, ref Value v; this) { - result = (cast(int delegate(ref Key k, ref Value v) nothrow)dg)(k, v); + result = (cast(int delegate(ref Key k, ref Value v) nothrow @nogc)dg)(k, v); if (result) break; } diff --git a/source/bubel/ecs/manager.d b/source/bubel/ecs/manager.d index a34d81c..801068d 100644 --- a/source/bubel/ecs/manager.d +++ b/source/bubel/ecs/manager.d @@ -76,7 +76,7 @@ export struct EntityManager UpdatePass* pass = Mallocator.make!UpdatePass; pass.name = Mallocator.makeArray(cast(char[]) "update"); passes.add(pass); - passes_map.add(cast(string) pass.name, cast(ushort)(passes.length - 1)); + passes_map.add(cast(const(char)[]) pass.name, cast(ushort)(passes.length - 1)); } } } @@ -84,7 +84,7 @@ export struct EntityManager /************************************************************************************************************************ Deinitialize and destroy ECS. This function release whole memory. */ - export static void destroy() + export static void destroy() nothrow @nogc { if (gEntityManager is null) return; @@ -334,16 +334,23 @@ export struct EntityManager */ void unregisterSystem(Sys)() { - assert(register_state, "unregisterSystem must be called between beginRegister() and endRegister()."); - ushort system_id = becsID!Sys; System* system = getSystem(system_id); - assert(system, "System was not registered"); - assert(system.isAlive, "System already unregistered"); + unregisterSystem(system); + } - system.destroy(); - *system = System.init; + /************************************************************************************************************************ + Unregister given system form EntityManager. + */ + export void unregisterSystem(System* system) nothrow @nogc + { + assert(register_state, "unregisterSystem must be called between beginRegister() and endRegister()."); + assert(system !is null, "System was not registered"); + assert(system.isAlive, "System already unregistered"); + + //disable, destroy and dispose user created system but keep name and other data + system.destroySystemData(); } /************************************************************************************************************************ @@ -1248,7 +1255,8 @@ export struct EntityManager } /************************************************************************************************************************ - Return system ECS api by id + Return system ECS api by id. + System pointer might become invalid after registration process. It should be get once again after new systems are registered. */ export System* getSystem(ushort id) nothrow @nogc { diff --git a/source/bubel/ecs/system.d b/source/bubel/ecs/system.d index 8e9d0ba..24098c0 100644 --- a/source/bubel/ecs/system.d +++ b/source/bubel/ecs/system.d @@ -97,38 +97,92 @@ struct System return m_system_pointer != null; } + /************************************************************************************************************************ + Return pointer to user side system object + */ + export void* ptr() nothrow @nogc + { + return m_system_pointer; + } + package: - void destroy() + ///destory system. Dispose all data + void destroy() nothrow @nogc + { + import bubel.ecs.std : Mallocator; + + destroySystemData(); + + if (m_name) + { + Mallocator.dispose(m_name); + m_name = null; + } + } + + ///destroy all system data but keeps name which is used for case of system re-registration + void destroySystemData() nothrow @nogc { import bubel.ecs.std : Mallocator; disable(); if (m_destroy) - (cast(void function(void*)) m_destroy)(m_system_pointer); + { + (cast(void function(void*) nothrow @nogc) m_destroy)(m_system_pointer); + m_destroy = null; + } - if (m_name) - Mallocator.dispose(m_name); if (m_components) + { Mallocator.dispose(m_components); + m_components = null; + } if (m_excluded_components) + { Mallocator.dispose(m_excluded_components); + m_excluded_components = null; + } if (m_optional_components) + { Mallocator.dispose(m_optional_components); + m_optional_components = null; + } if (jobs) + { Mallocator.dispose(jobs); + jobs = null; + } if (m_read_only_components) + { Mallocator.dispose(m_read_only_components); + m_read_only_components = null; + } if (m_writable_components) + { Mallocator.dispose(m_writable_components); + m_writable_components = null; + } if (m_readonly_dependencies) + { Mallocator.dispose(m_readonly_dependencies); + m_readonly_dependencies = null; + } if (m_writable_dependencies) + { Mallocator.dispose(m_writable_dependencies); + m_writable_dependencies = null; + } if (m_event_callers) + { Mallocator.dispose(m_event_callers); + m_event_callers = null; + } if (m_system_pointer) + { Mallocator.dispose(m_system_pointer); + m_system_pointer = null; + } } struct EventCaller From 8ac9fa5dbd9afebf6addbd50debd816fd91d0c8d Mon Sep 17 00:00:00 2001 From: Mergul Date: Mon, 24 Apr 2023 23:46:16 +0200 Subject: [PATCH 213/217] Fix crash in commit() when all components were removed from entity Fix crash from issue #2 and add unittest case for it. Also implements general "empty" entity support --- source/bubel/ecs/manager.d | 98 ++++++++++++++++++++---------------- tests/basic.d | 100 +++++++++++++++++++++++++++++++++++++ tests/bugs.d | 29 +++++++++++ 3 files changed, 185 insertions(+), 42 deletions(-) diff --git a/source/bubel/ecs/manager.d b/source/bubel/ecs/manager.d index 801068d..d6fae94 100644 --- a/source/bubel/ecs/manager.d +++ b/source/bubel/ecs/manager.d @@ -1856,6 +1856,7 @@ export struct EntityManager */ export EntityTemplate* allocateTemplate(EntityTemplate* copy_tmpl) { + assert(copy_tmpl, "copy_tmpl can't be null"); EntityTemplate* tmpl = Mallocator.make!EntityTemplate; tmpl.info = copy_tmpl.info; tmpl.entity_data = Mallocator.makeArray(copy_tmpl.entity_data); @@ -1870,46 +1871,66 @@ export struct EntityManager */ export EntityInfo* getEntityInfo(ushort[] ids) { + if(ids.length == 0)ids = null; EntityInfo* info = entities_infos.get(ids, null); if (info is null) { info = Mallocator.make!EntityInfo; - info.components = Mallocator.makeArray(ids); - info.deltas = Mallocator.makeArray!ushort(ids[$ - 1] + 1); - info.size = EntityID.sizeof; info.alignment = EntityID.alignof; - info.tmpl_deltas = Mallocator.makeArray!ushort(ids[$ - 1] + 1, ushort.max); - uint components_size = EntityID.sizeof; - - foreach (i, id; ids) + if(ids is null) { - info.alignment = max(info.alignment, components[id].alignment); - alignNum(info.size, components[id].alignment); - info.tmpl_deltas[id] = info.size; - info.size += components[id].size; - components_size += components[id].size; + uint block_memory = cast(uint)( + m_page_size - EntitiesBlock.sizeof - info.size); + uint entites_in_block = block_memory / info.size; + info.max_entities = cast(ushort) entites_in_block; } - alignNum(info.size, info.alignment); - - uint block_memory = cast(uint)( - m_page_size - EntitiesBlock.sizeof - (info.size - components_size)); - //uint entity_comps_size = EntityID.sizeof; - uint mem_begin = EntitiesBlock.sizeof; - - uint entites_in_block = block_memory / info.size; //entity_comps_size; - info.max_entities = cast(ushort) entites_in_block; - ushort current_delta = cast(ushort)(mem_begin + entites_in_block * EntityID.sizeof); - - foreach (i, id; ids) + else { - if (current_delta == 0) - current_delta = ushort.max; - alignNum(current_delta, components[id].alignment); - info.deltas[id] = cast(ushort) current_delta; - current_delta += entites_in_block * components[id].size; + uint components_size = EntityID.sizeof; + + info.components = Mallocator.makeArray(ids); + info.deltas = Mallocator.makeArray!ushort(ids[$ - 1] + 1); + info.tmpl_deltas = Mallocator.makeArray!ushort(ids[$ - 1] + 1, ushort.max); + + foreach (i, id; ids) + { + info.alignment = max(info.alignment, components[id].alignment); + alignNum(info.size, components[id].alignment); + info.tmpl_deltas[id] = info.size; + info.size += components[id].size; + components_size += components[id].size; + } + alignNum(info.size, info.alignment); + + uint block_memory = cast(uint)( + m_page_size - EntitiesBlock.sizeof - (info.size - components_size)); + //uint entity_comps_size = EntityID.sizeof; + uint mem_begin = EntitiesBlock.sizeof; + + uint entites_in_block = block_memory / info.size; //entity_comps_size; + info.max_entities = cast(ushort) entites_in_block; + ushort current_delta = cast(ushort)(mem_begin + entites_in_block * EntityID.sizeof); + + foreach (i, id; ids) + { + if (current_delta == 0) + current_delta = ushort.max; + alignNum(current_delta, components[id].alignment); + info.deltas[id] = cast(ushort) current_delta; + current_delta += entites_in_block * components[id].size; + } + + info.comp_add_info = Mallocator.makeArray!(EntityInfo*)(info.deltas.length); + info.comp_rem_info = Mallocator.makeArray!(EntityInfo*)(info.deltas.length); + + foreach (comp; info.components) + { + info.comp_add_info[comp] = info; + info.comp_rem_info[comp] = null; + } } info.systems = Mallocator.makeArray!bool(systems.length); @@ -1930,15 +1951,6 @@ export struct EntityManager addSystemCaller(*info, cast(uint) i); } - info.comp_add_info = Mallocator.makeArray!(EntityInfo*)(info.deltas.length); - info.comp_rem_info = Mallocator.makeArray!(EntityInfo*)(info.deltas.length); - - foreach (comp; info.components) - { - info.comp_add_info[comp] = info; - info.comp_rem_info[comp] = null; - } - entities_infos.add(info.components, info); generateListeners(info); @@ -2552,7 +2564,7 @@ export struct EntityManager use you should save ID instead of pointer. Params: - tmpl = pointer entity template allocated by EntityManager. + tmpl = pointer entity template allocated by EntityManager. Can be null in which case empty entity would be added (entity without components) */ export Entity* addEntity(EntityTemplate* tmpl) { @@ -2564,12 +2576,14 @@ export struct EntityManager use you should save ID instead of pointer. Params: - tmpl = pointer entity template allocated by EntityManager. + tmpl = pointer entity template allocated by EntityManager. Can be null in which case empty entity would be added (entity without components) replacement = list of components references to used. Memory form list replace data from template inside new entity. Should be used only for data which vary between most entities (like 3D position etc.) */ export Entity* addEntity(EntityTemplate* tmpl, ComponentRef[] replacement) { - EntityInfo* info = tmpl.info; + EntityInfo* info = void; + if(tmpl)info = tmpl.info; + else info = getEntityInfo(null); ushort index = 0; EntitiesBlock* block; @@ -3446,7 +3460,7 @@ export struct EntityManager break; } } - if (id > components[$ - 1]) + if (components.length == 0 || id > components[$ - 1]) ids[len++] = id; assert(len == components.length + 1); diff --git a/tests/basic.d b/tests/basic.d index 084500a..ea54382 100644 --- a/tests/basic.d +++ b/tests/basic.d @@ -113,6 +113,31 @@ struct EmptySystem int count = 0; } +struct EntityCounterSystem +{ + mixin ECS.System!1; + + struct EntitiesData + { + int thread_id; + uint length; + Entity[] entity; + } + + bool onBegin() + { + count = 0; + return true; + } + + void onUpdate(EntitiesData data) + { + count += data.length; + } + + int count = 0; +} + void beforeEveryTest() { becsID!CUnregistered = ushort.max; @@ -243,7 +268,82 @@ unittest gEntityManager.commit(); entity3 = gEntityManager.getEntity(id); assert(!entity3.getComponent!CUnregistered); +} +@("AddEmptyEntity") +unittest +{ + struct OnAddRemoveChangeCounter + { + mixin ECS.System!1; + + struct EntitiesData + { + int thread_id; + uint length; + Entity[] entity; + } + + void onAddEntity(EntitiesData data) + { + add += data.length; + } + + void onRemoveEntity(EntitiesData data) + { + assert(0, "It's impossible to remove entity from being updated by system which accept empty entity"); + } + + int add = 0; + } + + gEntityManager.beginRegister(); + + gEntityManager.registerSystem!EntityCounterSystem(0); + gEntityManager.registerSystem!OnAddRemoveChangeCounter(1); + + gEntityManager.endRegister(); + + CLong long_component = CLong(3); + + Entity* entity = null; + EntityID entity_id = gEntityManager.addEntity(null).id; + + EntityCounterSystem* system = gEntityManager.getSystem!EntityCounterSystem; + assert(system !is null); + assert(system.count == 0); + + OnAddRemoveChangeCounter* add_remove_change_system = gEntityManager.getSystem!OnAddRemoveChangeCounter; + assert(add_remove_change_system !is null); + assert(add_remove_change_system.add == 0); + + gEntityManager.commit(); + assert(add_remove_change_system.add == 1); + + entity = gEntityManager.getEntity(entity_id); + assert(!entity.hasComponent(becsID!CLong)); + assert(entity.getComponent(becsID!CLong) is null); + + + gEntityManager.begin(); + gEntityManager.update(); + assert(system.count == 1); + gEntityManager.end(); + + gEntityManager.addEntityCopy(entity_id); + gEntityManager.addEntityCopy(entity_id); + gEntityManager.addComponents(entity_id, [ComponentRef(&long_component, becsID(long_component))].staticArray); + gEntityManager.commit(); + assert(add_remove_change_system.add == 3, "onAddEntity missed"); + + entity = gEntityManager.getEntity(entity_id); + assert(entity.hasComponent(becsID!CLong)); + assert(*entity.getComponent!CLong == 3); + + gEntityManager.begin(); + gEntityManager.update(); + assert(system.count == 3); + gEntityManager.end(); } //allocate templates diff --git a/tests/bugs.d b/tests/bugs.d index 1a3968c..10a3c62 100644 --- a/tests/bugs.d +++ b/tests/bugs.d @@ -142,5 +142,34 @@ unittest gEntityManager.update(); gEntityManager.end(); + gEntityManager.destroy(); +} + +@("2-empty-entity-crash") +unittest +{ + + gEntityManager.initialize(0); + + gEntityManager.beginRegister(); + + gEntityManager.registerComponent!CInt; + gEntityManager.registerComponent!CFloat; + + gEntityManager.endRegister(); + + + EntityTemplate* tmpl = gEntityManager.allocateTemplate([becsID!CInt, becsID!CFloat].staticArray); + scope(exit) gEntityManager.freeTemplate(tmpl); + + EntityID id = gEntityManager.addEntity(tmpl).id; + // EntityID id2 = gEntityManager.addEntity().id; + + gEntityManager.commit(); + + gEntityManager.removeComponents(id, [becsID!CInt, becsID!CFloat].staticArray); + + gEntityManager.commit(); + gEntityManager.destroy(); } \ No newline at end of file From 9b757720395f9b081ba66c4cb966fa9b763aff2d Mon Sep 17 00:00:00 2001 From: Mergul Date: Thu, 10 Apr 2025 13:59:21 +0200 Subject: [PATCH 214/217] Add missing export visibility attributes --- source/bubel/ecs/entity.d | 12 ++++++------ source/bubel/ecs/hash_map.d | 2 +- source/bubel/ecs/manager.d | 10 ++++++++++ source/bubel/ecs/system.d | 2 +- 4 files changed, 18 insertions(+), 8 deletions(-) diff --git a/source/bubel/ecs/entity.d b/source/bubel/ecs/entity.d index 9b42c31..76a8a2f 100644 --- a/source/bubel/ecs/entity.d +++ b/source/bubel/ecs/entity.d @@ -44,7 +44,7 @@ struct Entity return cast(T*)getComponent(becsID!T); } - void* getComponent(ushort component_id) const + export void* getComponent(ushort component_id) const { EntityManager.EntitiesBlock* block = gEntityManager.getMetaData(&this); EntityManager.EntityInfo* info = block.type_info; @@ -54,7 +54,7 @@ struct Entity return (cast(void*)block + info.deltas[component_id] + block.entityIndex(&this) * gEntityManager.components[component_id].size); } - bool hasComponent(ushort component_id) const + export bool hasComponent(ushort component_id) const { EntityManager.EntitiesBlock* block = gEntityManager.getMetaData(&this); EntityManager.EntityInfo* info = block.type_info; @@ -62,7 +62,7 @@ struct Entity return true; } - EntityMeta getMeta() const + export EntityMeta getMeta() const { EntityMeta meta; meta.block = gEntityManager.getMetaData(&this); @@ -85,7 +85,7 @@ struct EntityMeta return cast(T*)getComponent(becsID!T); } - void* getComponent(ushort component_id) const + export void* getComponent(ushort component_id) const { const (EntityManager.EntityInfo)* info = block.type_info; @@ -95,7 +95,7 @@ struct EntityMeta return (cast(void*)block + info.deltas[component_id] + index * gEntityManager.components[component_id].size); } - bool hasComponent(ushort component_id) const + export bool hasComponent(ushort component_id) const { const EntityManager.EntityInfo* info = block.type_info; if (component_id >= info.deltas.length || info.deltas[component_id] == 0)return false; @@ -133,7 +133,7 @@ export struct EntityTemplate /************************************************************************************************************************ Get specified component. If component doesn't exist function return null. Returned pointer is valid during EntityTemplate lifetime. */ - void* getComponent(ushort component_id) const nothrow @nogc + export void* getComponent(ushort component_id) const nothrow @nogc { if(component_id >= info.tmpl_deltas.length || info.tmpl_deltas[component_id] == ushort.max)return null; return cast(void*)(entity_data.ptr + info.tmpl_deltas[component_id]); diff --git a/source/bubel/ecs/hash_map.d b/source/bubel/ecs/hash_map.d index 66a0756..7ba6137 100755 --- a/source/bubel/ecs/hash_map.d +++ b/source/bubel/ecs/hash_map.d @@ -28,7 +28,7 @@ export ulong defaultHashFunc(T)(auto ref T t) nothrow @nogc } } -ulong hash(byte[] array) nothrow @nogc +export ulong hash(byte[] array) nothrow @nogc { ulong hash = 0; diff --git a/source/bubel/ecs/manager.d b/source/bubel/ecs/manager.d index d6fae94..0977786 100644 --- a/source/bubel/ecs/manager.d +++ b/source/bubel/ecs/manager.d @@ -3355,6 +3355,16 @@ export struct EntityManager export ~this() nothrow @nogc { } + + export void opAssign(ComponentInfo c) + { + size = c.size; + alignment = c.alignment; + init_data = c.init_data; + destroy_callback = c.destroy_callback; + create_callback = c.create_callback; + } + ///Component size ushort size; ///Component data alignment diff --git a/source/bubel/ecs/system.d b/source/bubel/ecs/system.d index 24098c0..e6defd9 100644 --- a/source/bubel/ecs/system.d +++ b/source/bubel/ecs/system.d @@ -108,7 +108,7 @@ struct System package: ///destory system. Dispose all data - void destroy() nothrow @nogc + export void destroy() nothrow @nogc { import bubel.ecs.std : Mallocator; From 76a23aa4edffec3db1f233b95a6a52b13567b87f Mon Sep 17 00:00:00 2001 From: Mergul Date: Thu, 10 Apr 2025 14:00:20 +0200 Subject: [PATCH 215/217] Fix typo --- source/bubel/ecs/system.d | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/bubel/ecs/system.d b/source/bubel/ecs/system.d index e6defd9..310b53a 100644 --- a/source/bubel/ecs/system.d +++ b/source/bubel/ecs/system.d @@ -13,14 +13,14 @@ import bubel.ecs.manager; System contain data required to proper glue EntityManager with Systems. System callbacks: $(LIST - * void onUpdate(EntitesData); + * void onUpdate(EntitiesData); * void onEnable() - called inside system.enable() function * void onDisable() - called inside system.disable() function * bool onBegin() - called inside manager.begin() * void onEnd() - called inside manager.end() * void onCreate() - called after registration inside registerSystem function * void onDestroy() - called during re-registration and inside manager destructor - * void onAddEntity(EntitesData) - called for every entity which are assigned to system (by adding new entity or changing its components) + * void onAddEntity(EntitiesData) - called for every entity which are assigned to system (by adding new entity or changing its components) * void onRemoveEntity(EntitiesData) - called for every entity removed from system update process * void onChangeEntity(EntitiesData) - called for every entity which components are changed but it was previously assigned to system * void handleEvent(Entity*, Event) - called for every event supported by system From d77317c8163faa6e95f357542f2b771ca32df15a Mon Sep 17 00:00:00 2001 From: Mergul Date: Thu, 10 Apr 2025 14:00:55 +0200 Subject: [PATCH 216/217] Make it possible to use custom runtime (such as numem) --- source/bubel/ecs/manager.d | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/source/bubel/ecs/manager.d b/source/bubel/ecs/manager.d index 0977786..b5220f4 100644 --- a/source/bubel/ecs/manager.d +++ b/source/bubel/ecs/manager.d @@ -27,6 +27,8 @@ alias SerializeVector = bubel.ecs.vector.Vector!ubyte; ///Global EntityManager used for everything. export __gshared EntityManager* gEntityManager = null; +version(D_BetterC) version = NoDRuntime; + /************************************************************************************************************************ Entity manager is responsible for everything. @@ -359,7 +361,7 @@ export struct EntityManager void registerSystem(Sys)(int priority, const(char)[] pass_name) { ushort pass = passes_map.get(pass_name, ushort.max); - version (D_BetterC) + version (NoDRuntime) assert(pass != ushort.max, "Update pass doesn't exist."); else assert(pass != ushort.max, "Update pass (Name " ~ pass_name ~ ") doesn't exist."); @@ -381,7 +383,7 @@ export struct EntityManager assert(register_state, "registerSystem must be called between beginRegister() and endRegister()."); - version (D_BetterC) + version (NoDRuntime) assert(pass < passes.length, "Update pass doesn't exist."); else assert(pass < passes.length, "Update pass (ID " ~ pass.to!string ~ ") doesn't exist."); @@ -390,7 +392,7 @@ export struct EntityManager enum SystemName = fullName!Sys; //enum SystemName = Sys.stringof; - System system; + System system = System(); system.m_pass = pass; // static if (!(hasMember!(Sys, "system_id")) || !is(typeof(Sys.system_id) == ushort)) @@ -840,7 +842,7 @@ export struct EntityManager foreach (iii, comp_info; components_info.req) { ushort comp = components_map.get(cast(char[]) comp_info.type, ushort.max); - version (D_BetterC) + version (NoDRuntime) assert(comp != ushort.max, "Can't register system \"" ~ SystemName ~ "\" due to non existing component."); @@ -852,7 +854,7 @@ export struct EntityManager foreach (iii, comp_info; components_info.excluded) { ushort comp = components_map.get(cast(char[]) comp_info.type, ushort.max); - version (D_BetterC) + version (NoDRuntime) assert(comp != ushort.max, "Can't register system \"" ~ SystemName ~ "\" due to non existing component."); @@ -864,7 +866,7 @@ export struct EntityManager foreach (iii, comp_info; components_info.optional) { ushort comp = components_map.get(cast(char[]) comp_info.type, ushort.max); - version (D_BetterC) + version (NoDRuntime) assert(comp != ushort.max, "Can't register system \"" ~ SystemName ~ "\" due to non existing component."); @@ -876,7 +878,7 @@ export struct EntityManager foreach (iii, comp_info; components_info.readonly) { ushort comp = components_map.get(cast(char[]) comp_info.type, ushort.max); - version (D_BetterC) + version (NoDRuntime) assert(comp != ushort.max, "Can't register system \"" ~ SystemName ~ "\" due to non existing component."); @@ -888,7 +890,7 @@ export struct EntityManager foreach (iii, comp_info; components_info.mutable) { ushort comp = components_map.get(cast(char[]) comp_info.type, ushort.max); - version (D_BetterC) + version (NoDRuntime) assert(comp != ushort.max, "Can't register system \"" ~ SystemName ~ "\" due to non existing component."); @@ -1198,7 +1200,7 @@ export struct EntityManager { ushort comp = external_dependencies_map.get(cast(const(char)[]) comp_info.type, ushort.max); - version (D_BetterC) + version (NoDRuntime) assert(comp != ushort.max, "Can't register system \"" ~ SystemName ~ "\" due to non existing dependency."); @@ -1211,7 +1213,7 @@ export struct EntityManager foreach (iii, comp_info; components_info.writableDeps) { ushort comp = external_dependencies_map.get(cast(char[]) comp_info.type, ushort.max); - version (D_BetterC) + version (NoDRuntime) assert(comp != ushort.max, "Can't register system \"" ~ SystemName ~ "\" due to non existing dependency."); From f19bce1a57775c0eb995c8603e5ffec97d6634e8 Mon Sep 17 00:00:00 2001 From: Mergul Date: Wed, 14 May 2025 13:26:10 +0200 Subject: [PATCH 217/217] Remove ECSEmscripten as Emscripten version is now supported in LDC (+fix compile scripts) --- compile_wasm.py | 4 +- demos/compile_wasm.py | 10 ++-- meson.build | 2 +- source/bubel/ecs/atomic.d | 121 +------------------------------------- source/bubel/ecs/std.d | 18 ++---- 5 files changed, 15 insertions(+), 140 deletions(-) diff --git a/compile_wasm.py b/compile_wasm.py index 3bd1afd..7214801 100644 --- a/compile_wasm.py +++ b/compile_wasm.py @@ -13,7 +13,7 @@ def compile(sources, output): if file_extension == '.d' and filename != 'package': files.append(os.path.join(r, file)) - ldc_cmd = 'ldc2 ' + shared_flags + ldc_flags + '-oq -mtriple=wasm32-unknown-unknown-wasm -betterC --output-bc --od=.bc --singleobj --checkaction=C --of=' + output + ' ' + ldc_cmd = 'ldc2 ' + shared_flags + ldc_flags + '-oq -mtriple=wasm32-unknown-emscripten -betterC --output-bc --od=.bc --singleobj --checkaction=C --of=' + output + ' ' for path in sources: ldc_cmd += '-I' + path + ' ' @@ -33,7 +33,7 @@ def compile(sources, output): shared_flags = '' clean = 0 emc_flags = '' -ldc_flags = '--d-version=ECSEmscripten ' +ldc_flags = '' import_paths = ['source','tests'] build_tests = 0 diff --git a/demos/compile_wasm.py b/demos/compile_wasm.py index 06d31ac..b178260 100644 --- a/demos/compile_wasm.py +++ b/demos/compile_wasm.py @@ -1,7 +1,6 @@ import os import ntpath import sys -import imp def compile(sources, output): files = [] @@ -14,7 +13,7 @@ def compile(sources, output): if file_extension == '.d' and filename != 'package': files.append(os.path.join(r, file)) - ldc_cmd = compiler + shared_flags + ldc_flags + '-oq -mtriple=wasm32-unknown-unknown-wasm -betterC --output-bc --od=.bc --singleobj --checkaction=C --of=' + output + ' ' + ldc_cmd = compiler + shared_flags + ldc_flags + '-oq -mtriple=wasm32-unknown-emscripten -betterC --output-bc --od=.bc --singleobj --checkaction=C --of=' + output + ' ' for path in sources: ldc_cmd += '-I' + path + ' ' @@ -41,7 +40,7 @@ only_bc = 0 multi = 0 sources = ['tests', 'source'] emc_flags = '-s USE_SDL=2 -s USE_SDL_IMAGE=2 -s SDL2_IMAGE_FORMATS="[\'png\']" ' -ldc_flags = '--d-version=ECSEmscripten --d-version=SDL_209 --d-version=BindSDL_Static --d-version=BindSDL_Image --d-version=MM_USE_POSIX_THREADS ' +ldc_flags = '--d-version=SDL_209 --d-version=BindSDL_Static --d-version=BindSDL_Image --d-version=MM_USE_POSIX_THREADS ' import_paths = ['external/sources', 'external/imports', 'external/wasm_imports', '../source', 'utils/source', 'simple/source'] for arg in sys.argv[1:]: @@ -121,8 +120,9 @@ emcc_cmd += 'demo.bc ' os.system("mkdir build") -emscripten = imp.load_source('', os.path.expanduser("~") + '/.emscripten') -pack_cmd = emscripten.EMSCRIPTEN_ROOT + '/tools/file_packager.py build/assets.data --preload assets --js-output=build/assets.js' +# emscripten = imp.load_source('', os.path.expanduser("~") + '/.emscripten') +# pack_cmd = emscripten.EMSCRIPTEN_ROOT + '/tools/file_packager.py build/assets.data --preload assets --js-output=build/assets.js' +pack_cmd = os.path.expandvars('$EMSDK/upstream/emscripten') + '/tools/file_packager.py build/assets.data --preload assets --js-output=build/assets.js' print('Packafing files: ' + pack_cmd) os.system(pack_cmd) diff --git a/meson.build b/meson.build index 3f261f8..141cb25 100644 --- a/meson.build +++ b/meson.build @@ -58,7 +58,7 @@ threads_dep = dependency('threads') d_versions = [] deps = [] if host_machine.cpu_family() == 'wasm32' - d_versions += 'ECSEmscripten' + else # meson incorectly adds "-s USE_PTHREADS=1" to ldc2 invocation whe pthreads is added as dependency # add it for non wasm builds diff --git a/source/bubel/ecs/atomic.d b/source/bubel/ecs/atomic.d index 40f0aa9..d8995ae 100644 --- a/source/bubel/ecs/atomic.d +++ b/source/bubel/ecs/atomic.d @@ -9,124 +9,5 @@ License: BSD 3-clause, see LICENSE file in project root folder. */ module bubel.ecs.atomic; -version (Emscripten) version = ECSEmscripten; +public import core.atomic; -version (ECSEmscripten) -{ - import std.traits; - - enum MemoryOrder - { - acq, - acq_rel, - raw, - rel, - seq - } - - extern (C) ubyte emscripten_atomic_cas_u8(void* addr, ubyte oldVal, ubyte newVal) @nogc nothrow pure; - extern (C) ushort emscripten_atomic_cas_u16(void* addr, ushort oldVal, ushort newVal) @nogc nothrow pure; - extern (C) uint emscripten_atomic_cas_u32(void* addr, uint oldVal, uint newVal) @nogc nothrow pure; - - extern (C) ubyte emscripten_atomic_load_u8(const void* addr) @nogc nothrow pure; - extern (C) ushort emscripten_atomic_load_u16(const void* addr) @nogc nothrow pure; - extern (C) uint emscripten_atomic_load_u32(const void* addr) @nogc nothrow pure; - - extern (C) ubyte emscripten_atomic_store_u8(void* addr, ubyte val) @nogc nothrow pure; - extern (C) ushort emscripten_atomic_store_u16(void* addr, ushort val) @nogc nothrow pure; - extern (C) uint emscripten_atomic_store_u32(void* addr, uint val) @nogc nothrow pure; - - extern (C) ubyte emscripten_atomic_add_u8(void* addr, ubyte val) @nogc nothrow pure; - extern (C) ushort emscripten_atomic_add_u16(void* addr, ushort val) @nogc nothrow pure; - extern (C) uint emscripten_atomic_add_u32(void* addr, uint val) @nogc nothrow pure; - - extern (C) ubyte emscripten_atomic_sub_u8(void* addr, ubyte val) @nogc nothrow pure; - extern (C) ushort emscripten_atomic_sub_u16(void* addr, ushort val) @nogc nothrow pure; - extern (C) uint emscripten_atomic_sub_u32(void* addr, uint val) @nogc nothrow pure; - - public pure nothrow @nogc Unqual!T atomicOp(string op, T, V1)(ref shared T val, V1 mod) - { - static if (op == "+=") - { - static if (is(T == byte) || is(T == ubyte)) - return cast(Unqual!T)(emscripten_atomic_add_u8(cast(void*)&val, - cast(Unqual!T) mod) + 1); - else static if (is(T == short) || is(T == ushort)) - return cast(Unqual!T)(emscripten_atomic_add_u16(cast(void*)&val, - cast(Unqual!T) mod) + 1); - else static if (is(T == int) || is(T == uint)) - return cast(Unqual!T)(emscripten_atomic_add_u32(cast(void*)&val, - cast(Unqual!T) mod) + 1); - else - static assert(0); - } - else static if (op == "-=") - { - static if (is(T == byte) || is(T == ubyte)) - return cast(Unqual!T)(emscripten_atomic_sub_u8(cast(void*)&val, - cast(Unqual!T) mod) - 1); - else static if (is(T == short) || is(T == ushort)) - return cast(Unqual!T)(emscripten_atomic_sub_u16(cast(void*)&val, - cast(Unqual!T) mod) - 1); - else static if (is(T == int) || is(T == uint)) - return cast(Unqual!T)(emscripten_atomic_sub_u32(cast(void*)&val, - cast(Unqual!T) mod) - 1); - else - static assert(0); - } - } - - public pure nothrow @nogc @trusted void atomicStore(MemoryOrder ms = MemoryOrder.seq, T, V)(ref T val, - V newval) - { - alias UT = Unqual!T; - static if (is(UT == bool) || is(UT == byte) || is(UT == ubyte)) - emscripten_atomic_store_u8(cast(void*)&val, cast(UT) newval); - else static if (is(UT == short) || is(UT == ushort)) - emscripten_atomic_store_u16(cast(void*)&val, cast(UT) newval); - else static if (is(UT == int) || is(UT == uint)) - emscripten_atomic_store_u32(cast(void*)&val, cast(UT) newval); - else - static assert(0); - } - - public pure nothrow @nogc @trusted T atomicLoad(MemoryOrder ms = MemoryOrder.seq, T)( - ref const T val) - { - alias UT = Unqual!T; - static if (is(UT == bool)) - return emscripten_atomic_load_u8(cast(const void*)&val) != 0; - else static if (is(UT == byte) || is(UT == ubyte)) - return emscripten_atomic_load_u8(cast(const void*)&val); - else static if (is(UT == short) || is(UT == ushort)) - return emscripten_atomic_load_u16(cast(const void*)&val); - else static if (is(UT == int) || is(UT == uint)) - return emscripten_atomic_load_u32(cast(const void*)&val); - else - static assert(0); - } - - public pure nothrow @nogc @trusted bool cas(MemoryOrder succ = MemoryOrder.seq, - MemoryOrder fail = MemoryOrder.seq, T, V1, V2)(T* here, V1 ifThis, V2 writeThis) - { - alias UT = Unqual!T; - static if (is(UT == bool)) - return emscripten_atomic_cas_u8(cast(void*) here, - cast(Unqual!T) ifThis, cast(Unqual!T) writeThis) == ifThis; - else static if (is(UT == byte) || is(UT == ubyte)) - return emscripten_atomic_cas_u8(cast(void*) here, - cast(Unqual!T) ifThis, cast(Unqual!T) writeThis) == ifThis; - else static if (is(UT == short) || is(UT == ushort)) - return emscripten_atomic_cas_u16(cast(void*) here, - cast(Unqual!T) ifThis, cast(Unqual!T) writeThis) == ifThis; - else static if (is(UT == int) || is(UT == uint)) - return emscripten_atomic_cas_u32(cast(void*) here, - cast(Unqual!T) ifThis, cast(Unqual!T) writeThis) == ifThis; - else - static assert(0); - } -} -else -{ - public import core.atomic; -} diff --git a/source/bubel/ecs/std.d b/source/bubel/ecs/std.d index 8eb0d48..8a3e207 100644 --- a/source/bubel/ecs/std.d +++ b/source/bubel/ecs/std.d @@ -7,11 +7,9 @@ License: BSD 3-clause, see LICENSE file in project root folder. */ module bubel.ecs.std; -version (Emscripten) version = ECSEmscripten; - import std.traits; -version (ECSEmscripten) +version (Emscripten) { extern (C) struct pthread_mutex_t { @@ -29,10 +27,6 @@ version (ECSEmscripten) extern (C) int memcmp(const void* s1, const void* s2, size_t size); extern (C) void exit(int status) nothrow @nogc; - extern (C) void __assert(const(char)* msg, const(char)* file, uint line) - { - exit(-20); - } extern (C) void free(void*) @nogc nothrow @system; extern (C) void* malloc(size_t size) @nogc nothrow @system; @@ -60,7 +54,7 @@ else public import core.stdc.stdlib : qsort; } -version (ECSEmscripten) +version (Emscripten) { } else version (Windows) @@ -89,7 +83,7 @@ else version (Posix) import core.sys.posix.stdlib : posix_memalign; } -version (ECSEmscripten) +version (Emscripten) { private const uint max_alloca = 10000; private __gshared byte[max_alloca] alloca_array; @@ -294,7 +288,7 @@ static struct Mallocator posix_memalign(&ret, alignment, length); //ret = aligned_alloc(alignment, length); else version (Windows) ret = _aligned_malloc(length, alignment); - else version (ECSEmscripten) + else version (Emscripten) posix_memalign(&ret, alignment, length); //malloc(length); else static assert(0, "Unimplemented platform!"); @@ -341,7 +335,7 @@ static struct Mallocator free(cast(void*) object); else version (Windows) _aligned_free(cast(void*) object); - else version (ECSEmscripten) + else version (Emscripten) free(cast(void*) object); else static assert(0, "Unimplemented platform!"); @@ -351,7 +345,7 @@ static struct Mallocator struct Mutex { - version (ECSEmscripten) + version (Emscripten) { void initialize() nothrow @nogc {

    T{QVL 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 dh85dZG_KgW!mRAPGGk@;mCCr|@BeNM{2zk|q^ get_proc(x)); + close_gl(); + } + + return status; +} + +static struct GLVersion { static int major = 0; static int minor = 0; } +private extern(C) char* strstr(const(char)*, const(char)*) @nogc; +private extern(C) int strcmp(const(char)*, const(char)*) @nogc; +private extern(C) int strncmp(const(char)*, const(char)*, size_t) @nogc; +private extern(C) size_t strlen(const(char)*) @nogc; +private bool has_ext(const(char)* ext) @nogc { + if(GLVersion.major < 3) { + const(char)* extensions = cast(const(char)*)glGetString(GL_EXTENSIONS); + const(char)* loc; + const(char)* terminator; + + if(extensions is null || ext is null) { + return false; + } + + while(1) { + loc = strstr(extensions, ext); + if(loc is null) { + return false; + } + + terminator = loc + strlen(ext); + if((loc is extensions || *(loc - 1) == ' ') && + (*terminator == ' ' || *terminator == '\0')) { + return true; + } + extensions = terminator; + } + } else { + int num; + glGetIntegerv(GL_NUM_EXTENSIONS, &num); + + for(uint i=0; i < cast(uint)num; i++) { + if(strcmp(cast(const(char)*)glGetStringi(GL_EXTENSIONS, i), ext) == 0) { + return true; + } + } + } + + return false; +} +bool gladLoadGL(Loader load) { + glGetString = cast(typeof(glGetString))load("glGetString"); + if(glGetString is null) { return false; } + if(glGetString(GL_VERSION) is null) { return false; } + + find_coreGL(); + load_GL_VERSION_1_0(load); + load_GL_VERSION_1_1(load); + load_GL_VERSION_1_2(load); + load_GL_VERSION_1_3(load); + load_GL_VERSION_1_4(load); + load_GL_VERSION_1_5(load); + load_GL_VERSION_2_0(load); + load_GL_VERSION_2_1(load); + load_GL_VERSION_3_0(load); + load_GL_VERSION_3_1(load); + load_GL_VERSION_3_2(load); + load_GL_VERSION_3_3(load); + + find_extensionsGL(); + return GLVersion.major != 0 || GLVersion.minor != 0; +} + +private { + +void find_coreGL() { + + // Thank you @elmindreda + // https://github.com/elmindreda/greg/blob/master/templates/greg.c.in#L176 + // https://github.com/glfw/glfw/blob/master/src/context.c#L36 + int i; + const(char)* glversion; + const(char)*[3] prefixes = [ + "OpenGL ES-CM ".ptr, + "OpenGL ES-CL ".ptr, + "OpenGL ES ".ptr, + ]; + + glversion = cast(const(char)*)glGetString(GL_VERSION); + if (glversion is null) return; + + foreach(prefix; prefixes) { + size_t length = strlen(prefix); + if (strncmp(glversion, prefix, length) == 0) { + glversion += length; + break; + } + } + + int major = glversion[0] - '0'; + int minor = glversion[2] - '0'; + GLVersion.major = major; GLVersion.minor = minor; + GL_VERSION_1_0 = (major == 1 && minor >= 0) || major > 1; + GL_VERSION_1_1 = (major == 1 && minor >= 1) || major > 1; + GL_VERSION_1_2 = (major == 1 && minor >= 2) || major > 1; + GL_VERSION_1_3 = (major == 1 && minor >= 3) || major > 1; + GL_VERSION_1_4 = (major == 1 && minor >= 4) || major > 1; + GL_VERSION_1_5 = (major == 1 && minor >= 5) || major > 1; + GL_VERSION_2_0 = (major == 2 && minor >= 0) || major > 2; + GL_VERSION_2_1 = (major == 2 && minor >= 1) || major > 2; + GL_VERSION_3_0 = (major == 3 && minor >= 0) || major > 3; + GL_VERSION_3_1 = (major == 3 && minor >= 1) || major > 3; + GL_VERSION_3_2 = (major == 3 && minor >= 2) || major > 3; + GL_VERSION_3_3 = (major == 3 && minor >= 3) || major > 3; + return; +} + +void find_extensionsGL() { + return; +} + +void load_GL_VERSION_1_0(Loader load) { + if(!GL_VERSION_1_0) return; + glCullFace = cast(typeof(glCullFace))load("glCullFace"); + glFrontFace = cast(typeof(glFrontFace))load("glFrontFace"); + glHint = cast(typeof(glHint))load("glHint"); + glLineWidth = cast(typeof(glLineWidth))load("glLineWidth"); + glPointSize = cast(typeof(glPointSize))load("glPointSize"); + glPolygonMode = cast(typeof(glPolygonMode))load("glPolygonMode"); + glScissor = cast(typeof(glScissor))load("glScissor"); + glTexParameterf = cast(typeof(glTexParameterf))load("glTexParameterf"); + glTexParameterfv = cast(typeof(glTexParameterfv))load("glTexParameterfv"); + glTexParameteri = cast(typeof(glTexParameteri))load("glTexParameteri"); + glTexParameteriv = cast(typeof(glTexParameteriv))load("glTexParameteriv"); + glTexImage1D = cast(typeof(glTexImage1D))load("glTexImage1D"); + glTexImage2D = cast(typeof(glTexImage2D))load("glTexImage2D"); + glDrawBuffer = cast(typeof(glDrawBuffer))load("glDrawBuffer"); + glClear = cast(typeof(glClear))load("glClear"); + glClearColor = cast(typeof(glClearColor))load("glClearColor"); + glClearStencil = cast(typeof(glClearStencil))load("glClearStencil"); + glClearDepth = cast(typeof(glClearDepth))load("glClearDepth"); + glStencilMask = cast(typeof(glStencilMask))load("glStencilMask"); + glColorMask = cast(typeof(glColorMask))load("glColorMask"); + glDepthMask = cast(typeof(glDepthMask))load("glDepthMask"); + glDisable = cast(typeof(glDisable))load("glDisable"); + glEnable = cast(typeof(glEnable))load("glEnable"); + glFinish = cast(typeof(glFinish))load("glFinish"); + glFlush = cast(typeof(glFlush))load("glFlush"); + glBlendFunc = cast(typeof(glBlendFunc))load("glBlendFunc"); + glLogicOp = cast(typeof(glLogicOp))load("glLogicOp"); + glStencilFunc = cast(typeof(glStencilFunc))load("glStencilFunc"); + glStencilOp = cast(typeof(glStencilOp))load("glStencilOp"); + glDepthFunc = cast(typeof(glDepthFunc))load("glDepthFunc"); + glPixelStoref = cast(typeof(glPixelStoref))load("glPixelStoref"); + glPixelStorei = cast(typeof(glPixelStorei))load("glPixelStorei"); + glReadBuffer = cast(typeof(glReadBuffer))load("glReadBuffer"); + glReadPixels = cast(typeof(glReadPixels))load("glReadPixels"); + glGetBooleanv = cast(typeof(glGetBooleanv))load("glGetBooleanv"); + glGetDoublev = cast(typeof(glGetDoublev))load("glGetDoublev"); + glGetError = cast(typeof(glGetError))load("glGetError"); + glGetFloatv = cast(typeof(glGetFloatv))load("glGetFloatv"); + glGetIntegerv = cast(typeof(glGetIntegerv))load("glGetIntegerv"); + glGetString = cast(typeof(glGetString))load("glGetString"); + glGetTexImage = cast(typeof(glGetTexImage))load("glGetTexImage"); + glGetTexParameterfv = cast(typeof(glGetTexParameterfv))load("glGetTexParameterfv"); + glGetTexParameteriv = cast(typeof(glGetTexParameteriv))load("glGetTexParameteriv"); + glGetTexLevelParameterfv = cast(typeof(glGetTexLevelParameterfv))load("glGetTexLevelParameterfv"); + glGetTexLevelParameteriv = cast(typeof(glGetTexLevelParameteriv))load("glGetTexLevelParameteriv"); + glIsEnabled = cast(typeof(glIsEnabled))load("glIsEnabled"); + glDepthRange = cast(typeof(glDepthRange))load("glDepthRange"); + glViewport = cast(typeof(glViewport))load("glViewport"); + glNewList = cast(typeof(glNewList))load("glNewList"); + glEndList = cast(typeof(glEndList))load("glEndList"); + glCallList = cast(typeof(glCallList))load("glCallList"); + glCallLists = cast(typeof(glCallLists))load("glCallLists"); + glDeleteLists = cast(typeof(glDeleteLists))load("glDeleteLists"); + glGenLists = cast(typeof(glGenLists))load("glGenLists"); + glListBase = cast(typeof(glListBase))load("glListBase"); + glBegin = cast(typeof(glBegin))load("glBegin"); + glBitmap = cast(typeof(glBitmap))load("glBitmap"); + glColor3b = cast(typeof(glColor3b))load("glColor3b"); + glColor3bv = cast(typeof(glColor3bv))load("glColor3bv"); + glColor3d = cast(typeof(glColor3d))load("glColor3d"); + glColor3dv = cast(typeof(glColor3dv))load("glColor3dv"); + glColor3f = cast(typeof(glColor3f))load("glColor3f"); + glColor3fv = cast(typeof(glColor3fv))load("glColor3fv"); + glColor3i = cast(typeof(glColor3i))load("glColor3i"); + glColor3iv = cast(typeof(glColor3iv))load("glColor3iv"); + glColor3s = cast(typeof(glColor3s))load("glColor3s"); + glColor3sv = cast(typeof(glColor3sv))load("glColor3sv"); + glColor3ub = cast(typeof(glColor3ub))load("glColor3ub"); + glColor3ubv = cast(typeof(glColor3ubv))load("glColor3ubv"); + glColor3ui = cast(typeof(glColor3ui))load("glColor3ui"); + glColor3uiv = cast(typeof(glColor3uiv))load("glColor3uiv"); + glColor3us = cast(typeof(glColor3us))load("glColor3us"); + glColor3usv = cast(typeof(glColor3usv))load("glColor3usv"); + glColor4b = cast(typeof(glColor4b))load("glColor4b"); + glColor4bv = cast(typeof(glColor4bv))load("glColor4bv"); + glColor4d = cast(typeof(glColor4d))load("glColor4d"); + glColor4dv = cast(typeof(glColor4dv))load("glColor4dv"); + glColor4f = cast(typeof(glColor4f))load("glColor4f"); + glColor4fv = cast(typeof(glColor4fv))load("glColor4fv"); + glColor4i = cast(typeof(glColor4i))load("glColor4i"); + glColor4iv = cast(typeof(glColor4iv))load("glColor4iv"); + glColor4s = cast(typeof(glColor4s))load("glColor4s"); + glColor4sv = cast(typeof(glColor4sv))load("glColor4sv"); + glColor4ub = cast(typeof(glColor4ub))load("glColor4ub"); + glColor4ubv = cast(typeof(glColor4ubv))load("glColor4ubv"); + glColor4ui = cast(typeof(glColor4ui))load("glColor4ui"); + glColor4uiv = cast(typeof(glColor4uiv))load("glColor4uiv"); + glColor4us = cast(typeof(glColor4us))load("glColor4us"); + glColor4usv = cast(typeof(glColor4usv))load("glColor4usv"); + glEdgeFlag = cast(typeof(glEdgeFlag))load("glEdgeFlag"); + glEdgeFlagv = cast(typeof(glEdgeFlagv))load("glEdgeFlagv"); + glEnd = cast(typeof(glEnd))load("glEnd"); + glIndexd = cast(typeof(glIndexd))load("glIndexd"); + glIndexdv = cast(typeof(glIndexdv))load("glIndexdv"); + glIndexf = cast(typeof(glIndexf))load("glIndexf"); + glIndexfv = cast(typeof(glIndexfv))load("glIndexfv"); + glIndexi = cast(typeof(glIndexi))load("glIndexi"); + glIndexiv = cast(typeof(glIndexiv))load("glIndexiv"); + glIndexs = cast(typeof(glIndexs))load("glIndexs"); + glIndexsv = cast(typeof(glIndexsv))load("glIndexsv"); + glNormal3b = cast(typeof(glNormal3b))load("glNormal3b"); + glNormal3bv = cast(typeof(glNormal3bv))load("glNormal3bv"); + glNormal3d = cast(typeof(glNormal3d))load("glNormal3d"); + glNormal3dv = cast(typeof(glNormal3dv))load("glNormal3dv"); + glNormal3f = cast(typeof(glNormal3f))load("glNormal3f"); + glNormal3fv = cast(typeof(glNormal3fv))load("glNormal3fv"); + glNormal3i = cast(typeof(glNormal3i))load("glNormal3i"); + glNormal3iv = cast(typeof(glNormal3iv))load("glNormal3iv"); + glNormal3s = cast(typeof(glNormal3s))load("glNormal3s"); + glNormal3sv = cast(typeof(glNormal3sv))load("glNormal3sv"); + glRasterPos2d = cast(typeof(glRasterPos2d))load("glRasterPos2d"); + glRasterPos2dv = cast(typeof(glRasterPos2dv))load("glRasterPos2dv"); + glRasterPos2f = cast(typeof(glRasterPos2f))load("glRasterPos2f"); + glRasterPos2fv = cast(typeof(glRasterPos2fv))load("glRasterPos2fv"); + glRasterPos2i = cast(typeof(glRasterPos2i))load("glRasterPos2i"); + glRasterPos2iv = cast(typeof(glRasterPos2iv))load("glRasterPos2iv"); + glRasterPos2s = cast(typeof(glRasterPos2s))load("glRasterPos2s"); + glRasterPos2sv = cast(typeof(glRasterPos2sv))load("glRasterPos2sv"); + glRasterPos3d = cast(typeof(glRasterPos3d))load("glRasterPos3d"); + glRasterPos3dv = cast(typeof(glRasterPos3dv))load("glRasterPos3dv"); + glRasterPos3f = cast(typeof(glRasterPos3f))load("glRasterPos3f"); + glRasterPos3fv = cast(typeof(glRasterPos3fv))load("glRasterPos3fv"); + glRasterPos3i = cast(typeof(glRasterPos3i))load("glRasterPos3i"); + glRasterPos3iv = cast(typeof(glRasterPos3iv))load("glRasterPos3iv"); + glRasterPos3s = cast(typeof(glRasterPos3s))load("glRasterPos3s"); + glRasterPos3sv = cast(typeof(glRasterPos3sv))load("glRasterPos3sv"); + glRasterPos4d = cast(typeof(glRasterPos4d))load("glRasterPos4d"); + glRasterPos4dv = cast(typeof(glRasterPos4dv))load("glRasterPos4dv"); + glRasterPos4f = cast(typeof(glRasterPos4f))load("glRasterPos4f"); + glRasterPos4fv = cast(typeof(glRasterPos4fv))load("glRasterPos4fv"); + glRasterPos4i = cast(typeof(glRasterPos4i))load("glRasterPos4i"); + glRasterPos4iv = cast(typeof(glRasterPos4iv))load("glRasterPos4iv"); + glRasterPos4s = cast(typeof(glRasterPos4s))load("glRasterPos4s"); + glRasterPos4sv = cast(typeof(glRasterPos4sv))load("glRasterPos4sv"); + glRectd = cast(typeof(glRectd))load("glRectd"); + glRectdv = cast(typeof(glRectdv))load("glRectdv"); + glRectf = cast(typeof(glRectf))load("glRectf"); + glRectfv = cast(typeof(glRectfv))load("glRectfv"); + glRecti = cast(typeof(glRecti))load("glRecti"); + glRectiv = cast(typeof(glRectiv))load("glRectiv"); + glRects = cast(typeof(glRects))load("glRects"); + glRectsv = cast(typeof(glRectsv))load("glRectsv"); + glTexCoord1d = cast(typeof(glTexCoord1d))load("glTexCoord1d"); + glTexCoord1dv = cast(typeof(glTexCoord1dv))load("glTexCoord1dv"); + glTexCoord1f = cast(typeof(glTexCoord1f))load("glTexCoord1f"); + glTexCoord1fv = cast(typeof(glTexCoord1fv))load("glTexCoord1fv"); + glTexCoord1i = cast(typeof(glTexCoord1i))load("glTexCoord1i"); + glTexCoord1iv = cast(typeof(glTexCoord1iv))load("glTexCoord1iv"); + glTexCoord1s = cast(typeof(glTexCoord1s))load("glTexCoord1s"); + glTexCoord1sv = cast(typeof(glTexCoord1sv))load("glTexCoord1sv"); + glTexCoord2d = cast(typeof(glTexCoord2d))load("glTexCoord2d"); + glTexCoord2dv = cast(typeof(glTexCoord2dv))load("glTexCoord2dv"); + glTexCoord2f = cast(typeof(glTexCoord2f))load("glTexCoord2f"); + glTexCoord2fv = cast(typeof(glTexCoord2fv))load("glTexCoord2fv"); + glTexCoord2i = cast(typeof(glTexCoord2i))load("glTexCoord2i"); + glTexCoord2iv = cast(typeof(glTexCoord2iv))load("glTexCoord2iv"); + glTexCoord2s = cast(typeof(glTexCoord2s))load("glTexCoord2s"); + glTexCoord2sv = cast(typeof(glTexCoord2sv))load("glTexCoord2sv"); + glTexCoord3d = cast(typeof(glTexCoord3d))load("glTexCoord3d"); + glTexCoord3dv = cast(typeof(glTexCoord3dv))load("glTexCoord3dv"); + glTexCoord3f = cast(typeof(glTexCoord3f))load("glTexCoord3f"); + glTexCoord3fv = cast(typeof(glTexCoord3fv))load("glTexCoord3fv"); + glTexCoord3i = cast(typeof(glTexCoord3i))load("glTexCoord3i"); + glTexCoord3iv = cast(typeof(glTexCoord3iv))load("glTexCoord3iv"); + glTexCoord3s = cast(typeof(glTexCoord3s))load("glTexCoord3s"); + glTexCoord3sv = cast(typeof(glTexCoord3sv))load("glTexCoord3sv"); + glTexCoord4d = cast(typeof(glTexCoord4d))load("glTexCoord4d"); + glTexCoord4dv = cast(typeof(glTexCoord4dv))load("glTexCoord4dv"); + glTexCoord4f = cast(typeof(glTexCoord4f))load("glTexCoord4f"); + glTexCoord4fv = cast(typeof(glTexCoord4fv))load("glTexCoord4fv"); + glTexCoord4i = cast(typeof(glTexCoord4i))load("glTexCoord4i"); + glTexCoord4iv = cast(typeof(glTexCoord4iv))load("glTexCoord4iv"); + glTexCoord4s = cast(typeof(glTexCoord4s))load("glTexCoord4s"); + glTexCoord4sv = cast(typeof(glTexCoord4sv))load("glTexCoord4sv"); + glVertex2d = cast(typeof(glVertex2d))load("glVertex2d"); + glVertex2dv = cast(typeof(glVertex2dv))load("glVertex2dv"); + glVertex2f = cast(typeof(glVertex2f))load("glVertex2f"); + glVertex2fv = cast(typeof(glVertex2fv))load("glVertex2fv"); + glVertex2i = cast(typeof(glVertex2i))load("glVertex2i"); + glVertex2iv = cast(typeof(glVertex2iv))load("glVertex2iv"); + glVertex2s = cast(typeof(glVertex2s))load("glVertex2s"); + glVertex2sv = cast(typeof(glVertex2sv))load("glVertex2sv"); + glVertex3d = cast(typeof(glVertex3d))load("glVertex3d"); + glVertex3dv = cast(typeof(glVertex3dv))load("glVertex3dv"); + glVertex3f = cast(typeof(glVertex3f))load("glVertex3f"); + glVertex3fv = cast(typeof(glVertex3fv))load("glVertex3fv"); + glVertex3i = cast(typeof(glVertex3i))load("glVertex3i"); + glVertex3iv = cast(typeof(glVertex3iv))load("glVertex3iv"); + glVertex3s = cast(typeof(glVertex3s))load("glVertex3s"); + glVertex3sv = cast(typeof(glVertex3sv))load("glVertex3sv"); + glVertex4d = cast(typeof(glVertex4d))load("glVertex4d"); + glVertex4dv = cast(typeof(glVertex4dv))load("glVertex4dv"); + glVertex4f = cast(typeof(glVertex4f))load("glVertex4f"); + glVertex4fv = cast(typeof(glVertex4fv))load("glVertex4fv"); + glVertex4i = cast(typeof(glVertex4i))load("glVertex4i"); + glVertex4iv = cast(typeof(glVertex4iv))load("glVertex4iv"); + glVertex4s = cast(typeof(glVertex4s))load("glVertex4s"); + glVertex4sv = cast(typeof(glVertex4sv))load("glVertex4sv"); + glClipPlane = cast(typeof(glClipPlane))load("glClipPlane"); + glColorMaterial = cast(typeof(glColorMaterial))load("glColorMaterial"); + glFogf = cast(typeof(glFogf))load("glFogf"); + glFogfv = cast(typeof(glFogfv))load("glFogfv"); + glFogi = cast(typeof(glFogi))load("glFogi"); + glFogiv = cast(typeof(glFogiv))load("glFogiv"); + glLightf = cast(typeof(glLightf))load("glLightf"); + glLightfv = cast(typeof(glLightfv))load("glLightfv"); + glLighti = cast(typeof(glLighti))load("glLighti"); + glLightiv = cast(typeof(glLightiv))load("glLightiv"); + glLightModelf = cast(typeof(glLightModelf))load("glLightModelf"); + glLightModelfv = cast(typeof(glLightModelfv))load("glLightModelfv"); + glLightModeli = cast(typeof(glLightModeli))load("glLightModeli"); + glLightModeliv = cast(typeof(glLightModeliv))load("glLightModeliv"); + glLineStipple = cast(typeof(glLineStipple))load("glLineStipple"); + glMaterialf = cast(typeof(glMaterialf))load("glMaterialf"); + glMaterialfv = cast(typeof(glMaterialfv))load("glMaterialfv"); + glMateriali = cast(typeof(glMateriali))load("glMateriali"); + glMaterialiv = cast(typeof(glMaterialiv))load("glMaterialiv"); + glPolygonStipple = cast(typeof(glPolygonStipple))load("glPolygonStipple"); + glShadeModel = cast(typeof(glShadeModel))load("glShadeModel"); + glTexEnvf = cast(typeof(glTexEnvf))load("glTexEnvf"); + glTexEnvfv = cast(typeof(glTexEnvfv))load("glTexEnvfv"); + glTexEnvi = cast(typeof(glTexEnvi))load("glTexEnvi"); + glTexEnviv = cast(typeof(glTexEnviv))load("glTexEnviv"); + glTexGend = cast(typeof(glTexGend))load("glTexGend"); + glTexGendv = cast(typeof(glTexGendv))load("glTexGendv"); + glTexGenf = cast(typeof(glTexGenf))load("glTexGenf"); + glTexGenfv = cast(typeof(glTexGenfv))load("glTexGenfv"); + glTexGeni = cast(typeof(glTexGeni))load("glTexGeni"); + glTexGeniv = cast(typeof(glTexGeniv))load("glTexGeniv"); + glFeedbackBuffer = cast(typeof(glFeedbackBuffer))load("glFeedbackBuffer"); + glSelectBuffer = cast(typeof(glSelectBuffer))load("glSelectBuffer"); + glRenderMode = cast(typeof(glRenderMode))load("glRenderMode"); + glInitNames = cast(typeof(glInitNames))load("glInitNames"); + glLoadName = cast(typeof(glLoadName))load("glLoadName"); + glPassThrough = cast(typeof(glPassThrough))load("glPassThrough"); + glPopName = cast(typeof(glPopName))load("glPopName"); + glPushName = cast(typeof(glPushName))load("glPushName"); + glClearAccum = cast(typeof(glClearAccum))load("glClearAccum"); + glClearIndex = cast(typeof(glClearIndex))load("glClearIndex"); + glIndexMask = cast(typeof(glIndexMask))load("glIndexMask"); + glAccum = cast(typeof(glAccum))load("glAccum"); + glPopAttrib = cast(typeof(glPopAttrib))load("glPopAttrib"); + glPushAttrib = cast(typeof(glPushAttrib))load("glPushAttrib"); + glMap1d = cast(typeof(glMap1d))load("glMap1d"); + glMap1f = cast(typeof(glMap1f))load("glMap1f"); + glMap2d = cast(typeof(glMap2d))load("glMap2d"); + glMap2f = cast(typeof(glMap2f))load("glMap2f"); + glMapGrid1d = cast(typeof(glMapGrid1d))load("glMapGrid1d"); + glMapGrid1f = cast(typeof(glMapGrid1f))load("glMapGrid1f"); + glMapGrid2d = cast(typeof(glMapGrid2d))load("glMapGrid2d"); + glMapGrid2f = cast(typeof(glMapGrid2f))load("glMapGrid2f"); + glEvalCoord1d = cast(typeof(glEvalCoord1d))load("glEvalCoord1d"); + glEvalCoord1dv = cast(typeof(glEvalCoord1dv))load("glEvalCoord1dv"); + glEvalCoord1f = cast(typeof(glEvalCoord1f))load("glEvalCoord1f"); + glEvalCoord1fv = cast(typeof(glEvalCoord1fv))load("glEvalCoord1fv"); + glEvalCoord2d = cast(typeof(glEvalCoord2d))load("glEvalCoord2d"); + glEvalCoord2dv = cast(typeof(glEvalCoord2dv))load("glEvalCoord2dv"); + glEvalCoord2f = cast(typeof(glEvalCoord2f))load("glEvalCoord2f"); + glEvalCoord2fv = cast(typeof(glEvalCoord2fv))load("glEvalCoord2fv"); + glEvalMesh1 = cast(typeof(glEvalMesh1))load("glEvalMesh1"); + glEvalPoint1 = cast(typeof(glEvalPoint1))load("glEvalPoint1"); + glEvalMesh2 = cast(typeof(glEvalMesh2))load("glEvalMesh2"); + glEvalPoint2 = cast(typeof(glEvalPoint2))load("glEvalPoint2"); + glAlphaFunc = cast(typeof(glAlphaFunc))load("glAlphaFunc"); + glPixelZoom = cast(typeof(glPixelZoom))load("glPixelZoom"); + glPixelTransferf = cast(typeof(glPixelTransferf))load("glPixelTransferf"); + glPixelTransferi = cast(typeof(glPixelTransferi))load("glPixelTransferi"); + glPixelMapfv = cast(typeof(glPixelMapfv))load("glPixelMapfv"); + glPixelMapuiv = cast(typeof(glPixelMapuiv))load("glPixelMapuiv"); + glPixelMapusv = cast(typeof(glPixelMapusv))load("glPixelMapusv"); + glCopyPixels = cast(typeof(glCopyPixels))load("glCopyPixels"); + glDrawPixels = cast(typeof(glDrawPixels))load("glDrawPixels"); + glGetClipPlane = cast(typeof(glGetClipPlane))load("glGetClipPlane"); + glGetLightfv = cast(typeof(glGetLightfv))load("glGetLightfv"); + glGetLightiv = cast(typeof(glGetLightiv))load("glGetLightiv"); + glGetMapdv = cast(typeof(glGetMapdv))load("glGetMapdv"); + glGetMapfv = cast(typeof(glGetMapfv))load("glGetMapfv"); + glGetMapiv = cast(typeof(glGetMapiv))load("glGetMapiv"); + glGetMaterialfv = cast(typeof(glGetMaterialfv))load("glGetMaterialfv"); + glGetMaterialiv = cast(typeof(glGetMaterialiv))load("glGetMaterialiv"); + glGetPixelMapfv = cast(typeof(glGetPixelMapfv))load("glGetPixelMapfv"); + glGetPixelMapuiv = cast(typeof(glGetPixelMapuiv))load("glGetPixelMapuiv"); + glGetPixelMapusv = cast(typeof(glGetPixelMapusv))load("glGetPixelMapusv"); + glGetPolygonStipple = cast(typeof(glGetPolygonStipple))load("glGetPolygonStipple"); + glGetTexEnvfv = cast(typeof(glGetTexEnvfv))load("glGetTexEnvfv"); + glGetTexEnviv = cast(typeof(glGetTexEnviv))load("glGetTexEnviv"); + glGetTexGendv = cast(typeof(glGetTexGendv))load("glGetTexGendv"); + glGetTexGenfv = cast(typeof(glGetTexGenfv))load("glGetTexGenfv"); + glGetTexGeniv = cast(typeof(glGetTexGeniv))load("glGetTexGeniv"); + glIsList = cast(typeof(glIsList))load("glIsList"); + glFrustum = cast(typeof(glFrustum))load("glFrustum"); + glLoadIdentity = cast(typeof(glLoadIdentity))load("glLoadIdentity"); + glLoadMatrixf = cast(typeof(glLoadMatrixf))load("glLoadMatrixf"); + glLoadMatrixd = cast(typeof(glLoadMatrixd))load("glLoadMatrixd"); + glMatrixMode = cast(typeof(glMatrixMode))load("glMatrixMode"); + glMultMatrixf = cast(typeof(glMultMatrixf))load("glMultMatrixf"); + glMultMatrixd = cast(typeof(glMultMatrixd))load("glMultMatrixd"); + glOrtho = cast(typeof(glOrtho))load("glOrtho"); + glPopMatrix = cast(typeof(glPopMatrix))load("glPopMatrix"); + glPushMatrix = cast(typeof(glPushMatrix))load("glPushMatrix"); + glRotated = cast(typeof(glRotated))load("glRotated"); + glRotatef = cast(typeof(glRotatef))load("glRotatef"); + glScaled = cast(typeof(glScaled))load("glScaled"); + glScalef = cast(typeof(glScalef))load("glScalef"); + glTranslated = cast(typeof(glTranslated))load("glTranslated"); + glTranslatef = cast(typeof(glTranslatef))load("glTranslatef"); + return; +} + +void load_GL_VERSION_1_1(Loader load) { + if(!GL_VERSION_1_1) return; + glDrawArrays = cast(typeof(glDrawArrays))load("glDrawArrays"); + glDrawElements = cast(typeof(glDrawElements))load("glDrawElements"); + glGetPointerv = cast(typeof(glGetPointerv))load("glGetPointerv"); + glPolygonOffset = cast(typeof(glPolygonOffset))load("glPolygonOffset"); + glCopyTexImage1D = cast(typeof(glCopyTexImage1D))load("glCopyTexImage1D"); + glCopyTexImage2D = cast(typeof(glCopyTexImage2D))load("glCopyTexImage2D"); + glCopyTexSubImage1D = cast(typeof(glCopyTexSubImage1D))load("glCopyTexSubImage1D"); + glCopyTexSubImage2D = cast(typeof(glCopyTexSubImage2D))load("glCopyTexSubImage2D"); + glTexSubImage1D = cast(typeof(glTexSubImage1D))load("glTexSubImage1D"); + glTexSubImage2D = cast(typeof(glTexSubImage2D))load("glTexSubImage2D"); + glBindTexture = cast(typeof(glBindTexture))load("glBindTexture"); + glDeleteTextures = cast(typeof(glDeleteTextures))load("glDeleteTextures"); + glGenTextures = cast(typeof(glGenTextures))load("glGenTextures"); + glIsTexture = cast(typeof(glIsTexture))load("glIsTexture"); + glArrayElement = cast(typeof(glArrayElement))load("glArrayElement"); + glColorPointer = cast(typeof(glColorPointer))load("glColorPointer"); + glDisableClientState = cast(typeof(glDisableClientState))load("glDisableClientState"); + glEdgeFlagPointer = cast(typeof(glEdgeFlagPointer))load("glEdgeFlagPointer"); + glEnableClientState = cast(typeof(glEnableClientState))load("glEnableClientState"); + glIndexPointer = cast(typeof(glIndexPointer))load("glIndexPointer"); + glInterleavedArrays = cast(typeof(glInterleavedArrays))load("glInterleavedArrays"); + glNormalPointer = cast(typeof(glNormalPointer))load("glNormalPointer"); + glTexCoordPointer = cast(typeof(glTexCoordPointer))load("glTexCoordPointer"); + glVertexPointer = cast(typeof(glVertexPointer))load("glVertexPointer"); + glAreTexturesResident = cast(typeof(glAreTexturesResident))load("glAreTexturesResident"); + glPrioritizeTextures = cast(typeof(glPrioritizeTextures))load("glPrioritizeTextures"); + glIndexub = cast(typeof(glIndexub))load("glIndexub"); + glIndexubv = cast(typeof(glIndexubv))load("glIndexubv"); + glPopClientAttrib = cast(typeof(glPopClientAttrib))load("glPopClientAttrib"); + glPushClientAttrib = cast(typeof(glPushClientAttrib))load("glPushClientAttrib"); + return; +} + +void load_GL_VERSION_1_2(Loader load) { + if(!GL_VERSION_1_2) return; + glDrawRangeElements = cast(typeof(glDrawRangeElements))load("glDrawRangeElements"); + glTexImage3D = cast(typeof(glTexImage3D))load("glTexImage3D"); + glTexSubImage3D = cast(typeof(glTexSubImage3D))load("glTexSubImage3D"); + glCopyTexSubImage3D = cast(typeof(glCopyTexSubImage3D))load("glCopyTexSubImage3D"); + return; +} + +void load_GL_VERSION_1_3(Loader load) { + if(!GL_VERSION_1_3) return; + glActiveTexture = cast(typeof(glActiveTexture))load("glActiveTexture"); + glSampleCoverage = cast(typeof(glSampleCoverage))load("glSampleCoverage"); + glCompressedTexImage3D = cast(typeof(glCompressedTexImage3D))load("glCompressedTexImage3D"); + glCompressedTexImage2D = cast(typeof(glCompressedTexImage2D))load("glCompressedTexImage2D"); + glCompressedTexImage1D = cast(typeof(glCompressedTexImage1D))load("glCompressedTexImage1D"); + glCompressedTexSubImage3D = cast(typeof(glCompressedTexSubImage3D))load("glCompressedTexSubImage3D"); + glCompressedTexSubImage2D = cast(typeof(glCompressedTexSubImage2D))load("glCompressedTexSubImage2D"); + glCompressedTexSubImage1D = cast(typeof(glCompressedTexSubImage1D))load("glCompressedTexSubImage1D"); + glGetCompressedTexImage = cast(typeof(glGetCompressedTexImage))load("glGetCompressedTexImage"); + glClientActiveTexture = cast(typeof(glClientActiveTexture))load("glClientActiveTexture"); + glMultiTexCoord1d = cast(typeof(glMultiTexCoord1d))load("glMultiTexCoord1d"); + glMultiTexCoord1dv = cast(typeof(glMultiTexCoord1dv))load("glMultiTexCoord1dv"); + glMultiTexCoord1f = cast(typeof(glMultiTexCoord1f))load("glMultiTexCoord1f"); + glMultiTexCoord1fv = cast(typeof(glMultiTexCoord1fv))load("glMultiTexCoord1fv"); + glMultiTexCoord1i = cast(typeof(glMultiTexCoord1i))load("glMultiTexCoord1i"); + glMultiTexCoord1iv = cast(typeof(glMultiTexCoord1iv))load("glMultiTexCoord1iv"); + glMultiTexCoord1s = cast(typeof(glMultiTexCoord1s))load("glMultiTexCoord1s"); + glMultiTexCoord1sv = cast(typeof(glMultiTexCoord1sv))load("glMultiTexCoord1sv"); + glMultiTexCoord2d = cast(typeof(glMultiTexCoord2d))load("glMultiTexCoord2d"); + glMultiTexCoord2dv = cast(typeof(glMultiTexCoord2dv))load("glMultiTexCoord2dv"); + glMultiTexCoord2f = cast(typeof(glMultiTexCoord2f))load("glMultiTexCoord2f"); + glMultiTexCoord2fv = cast(typeof(glMultiTexCoord2fv))load("glMultiTexCoord2fv"); + glMultiTexCoord2i = cast(typeof(glMultiTexCoord2i))load("glMultiTexCoord2i"); + glMultiTexCoord2iv = cast(typeof(glMultiTexCoord2iv))load("glMultiTexCoord2iv"); + glMultiTexCoord2s = cast(typeof(glMultiTexCoord2s))load("glMultiTexCoord2s"); + glMultiTexCoord2sv = cast(typeof(glMultiTexCoord2sv))load("glMultiTexCoord2sv"); + glMultiTexCoord3d = cast(typeof(glMultiTexCoord3d))load("glMultiTexCoord3d"); + glMultiTexCoord3dv = cast(typeof(glMultiTexCoord3dv))load("glMultiTexCoord3dv"); + glMultiTexCoord3f = cast(typeof(glMultiTexCoord3f))load("glMultiTexCoord3f"); + glMultiTexCoord3fv = cast(typeof(glMultiTexCoord3fv))load("glMultiTexCoord3fv"); + glMultiTexCoord3i = cast(typeof(glMultiTexCoord3i))load("glMultiTexCoord3i"); + glMultiTexCoord3iv = cast(typeof(glMultiTexCoord3iv))load("glMultiTexCoord3iv"); + glMultiTexCoord3s = cast(typeof(glMultiTexCoord3s))load("glMultiTexCoord3s"); + glMultiTexCoord3sv = cast(typeof(glMultiTexCoord3sv))load("glMultiTexCoord3sv"); + glMultiTexCoord4d = cast(typeof(glMultiTexCoord4d))load("glMultiTexCoord4d"); + glMultiTexCoord4dv = cast(typeof(glMultiTexCoord4dv))load("glMultiTexCoord4dv"); + glMultiTexCoord4f = cast(typeof(glMultiTexCoord4f))load("glMultiTexCoord4f"); + glMultiTexCoord4fv = cast(typeof(glMultiTexCoord4fv))load("glMultiTexCoord4fv"); + glMultiTexCoord4i = cast(typeof(glMultiTexCoord4i))load("glMultiTexCoord4i"); + glMultiTexCoord4iv = cast(typeof(glMultiTexCoord4iv))load("glMultiTexCoord4iv"); + glMultiTexCoord4s = cast(typeof(glMultiTexCoord4s))load("glMultiTexCoord4s"); + glMultiTexCoord4sv = cast(typeof(glMultiTexCoord4sv))load("glMultiTexCoord4sv"); + glLoadTransposeMatrixf = cast(typeof(glLoadTransposeMatrixf))load("glLoadTransposeMatrixf"); + glLoadTransposeMatrixd = cast(typeof(glLoadTransposeMatrixd))load("glLoadTransposeMatrixd"); + glMultTransposeMatrixf = cast(typeof(glMultTransposeMatrixf))load("glMultTransposeMatrixf"); + glMultTransposeMatrixd = cast(typeof(glMultTransposeMatrixd))load("glMultTransposeMatrixd"); + return; +} + +void load_GL_VERSION_1_4(Loader load) { + if(!GL_VERSION_1_4) return; + glBlendFuncSeparate = cast(typeof(glBlendFuncSeparate))load("glBlendFuncSeparate"); + glMultiDrawArrays = cast(typeof(glMultiDrawArrays))load("glMultiDrawArrays"); + glMultiDrawElements = cast(typeof(glMultiDrawElements))load("glMultiDrawElements"); + glPointParameterf = cast(typeof(glPointParameterf))load("glPointParameterf"); + glPointParameterfv = cast(typeof(glPointParameterfv))load("glPointParameterfv"); + glPointParameteri = cast(typeof(glPointParameteri))load("glPointParameteri"); + glPointParameteriv = cast(typeof(glPointParameteriv))load("glPointParameteriv"); + glFogCoordf = cast(typeof(glFogCoordf))load("glFogCoordf"); + glFogCoordfv = cast(typeof(glFogCoordfv))load("glFogCoordfv"); + glFogCoordd = cast(typeof(glFogCoordd))load("glFogCoordd"); + glFogCoorddv = cast(typeof(glFogCoorddv))load("glFogCoorddv"); + glFogCoordPointer = cast(typeof(glFogCoordPointer))load("glFogCoordPointer"); + glSecondaryColor3b = cast(typeof(glSecondaryColor3b))load("glSecondaryColor3b"); + glSecondaryColor3bv = cast(typeof(glSecondaryColor3bv))load("glSecondaryColor3bv"); + glSecondaryColor3d = cast(typeof(glSecondaryColor3d))load("glSecondaryColor3d"); + glSecondaryColor3dv = cast(typeof(glSecondaryColor3dv))load("glSecondaryColor3dv"); + glSecondaryColor3f = cast(typeof(glSecondaryColor3f))load("glSecondaryColor3f"); + glSecondaryColor3fv = cast(typeof(glSecondaryColor3fv))load("glSecondaryColor3fv"); + glSecondaryColor3i = cast(typeof(glSecondaryColor3i))load("glSecondaryColor3i"); + glSecondaryColor3iv = cast(typeof(glSecondaryColor3iv))load("glSecondaryColor3iv"); + glSecondaryColor3s = cast(typeof(glSecondaryColor3s))load("glSecondaryColor3s"); + glSecondaryColor3sv = cast(typeof(glSecondaryColor3sv))load("glSecondaryColor3sv"); + glSecondaryColor3ub = cast(typeof(glSecondaryColor3ub))load("glSecondaryColor3ub"); + glSecondaryColor3ubv = cast(typeof(glSecondaryColor3ubv))load("glSecondaryColor3ubv"); + glSecondaryColor3ui = cast(typeof(glSecondaryColor3ui))load("glSecondaryColor3ui"); + glSecondaryColor3uiv = cast(typeof(glSecondaryColor3uiv))load("glSecondaryColor3uiv"); + glSecondaryColor3us = cast(typeof(glSecondaryColor3us))load("glSecondaryColor3us"); + glSecondaryColor3usv = cast(typeof(glSecondaryColor3usv))load("glSecondaryColor3usv"); + glSecondaryColorPointer = cast(typeof(glSecondaryColorPointer))load("glSecondaryColorPointer"); + glWindowPos2d = cast(typeof(glWindowPos2d))load("glWindowPos2d"); + glWindowPos2dv = cast(typeof(glWindowPos2dv))load("glWindowPos2dv"); + glWindowPos2f = cast(typeof(glWindowPos2f))load("glWindowPos2f"); + glWindowPos2fv = cast(typeof(glWindowPos2fv))load("glWindowPos2fv"); + glWindowPos2i = cast(typeof(glWindowPos2i))load("glWindowPos2i"); + glWindowPos2iv = cast(typeof(glWindowPos2iv))load("glWindowPos2iv"); + glWindowPos2s = cast(typeof(glWindowPos2s))load("glWindowPos2s"); + glWindowPos2sv = cast(typeof(glWindowPos2sv))load("glWindowPos2sv"); + glWindowPos3d = cast(typeof(glWindowPos3d))load("glWindowPos3d"); + glWindowPos3dv = cast(typeof(glWindowPos3dv))load("glWindowPos3dv"); + glWindowPos3f = cast(typeof(glWindowPos3f))load("glWindowPos3f"); + glWindowPos3fv = cast(typeof(glWindowPos3fv))load("glWindowPos3fv"); + glWindowPos3i = cast(typeof(glWindowPos3i))load("glWindowPos3i"); + glWindowPos3iv = cast(typeof(glWindowPos3iv))load("glWindowPos3iv"); + glWindowPos3s = cast(typeof(glWindowPos3s))load("glWindowPos3s"); + glWindowPos3sv = cast(typeof(glWindowPos3sv))load("glWindowPos3sv"); + glBlendColor = cast(typeof(glBlendColor))load("glBlendColor"); + glBlendEquation = cast(typeof(glBlendEquation))load("glBlendEquation"); + return; +} + +void load_GL_VERSION_1_5(Loader load) { + if(!GL_VERSION_1_5) return; + glGenQueries = cast(typeof(glGenQueries))load("glGenQueries"); + glDeleteQueries = cast(typeof(glDeleteQueries))load("glDeleteQueries"); + glIsQuery = cast(typeof(glIsQuery))load("glIsQuery"); + glBeginQuery = cast(typeof(glBeginQuery))load("glBeginQuery"); + glEndQuery = cast(typeof(glEndQuery))load("glEndQuery"); + glGetQueryiv = cast(typeof(glGetQueryiv))load("glGetQueryiv"); + glGetQueryObjectiv = cast(typeof(glGetQueryObjectiv))load("glGetQueryObjectiv"); + glGetQueryObjectuiv = cast(typeof(glGetQueryObjectuiv))load("glGetQueryObjectuiv"); + glBindBuffer = cast(typeof(glBindBuffer))load("glBindBuffer"); + glDeleteBuffers = cast(typeof(glDeleteBuffers))load("glDeleteBuffers"); + glGenBuffers = cast(typeof(glGenBuffers))load("glGenBuffers"); + glIsBuffer = cast(typeof(glIsBuffer))load("glIsBuffer"); + glBufferData = cast(typeof(glBufferData))load("glBufferData"); + glBufferSubData = cast(typeof(glBufferSubData))load("glBufferSubData"); + glGetBufferSubData = cast(typeof(glGetBufferSubData))load("glGetBufferSubData"); + glMapBuffer = cast(typeof(glMapBuffer))load("glMapBuffer"); + glUnmapBuffer = cast(typeof(glUnmapBuffer))load("glUnmapBuffer"); + glGetBufferParameteriv = cast(typeof(glGetBufferParameteriv))load("glGetBufferParameteriv"); + glGetBufferPointerv = cast(typeof(glGetBufferPointerv))load("glGetBufferPointerv"); + return; +} + +void load_GL_VERSION_2_0(Loader load) { + if(!GL_VERSION_2_0) return; + glBlendEquationSeparate = cast(typeof(glBlendEquationSeparate))load("glBlendEquationSeparate"); + glDrawBuffers = cast(typeof(glDrawBuffers))load("glDrawBuffers"); + glStencilOpSeparate = cast(typeof(glStencilOpSeparate))load("glStencilOpSeparate"); + glStencilFuncSeparate = cast(typeof(glStencilFuncSeparate))load("glStencilFuncSeparate"); + glStencilMaskSeparate = cast(typeof(glStencilMaskSeparate))load("glStencilMaskSeparate"); + glAttachShader = cast(typeof(glAttachShader))load("glAttachShader"); + glBindAttribLocation = cast(typeof(glBindAttribLocation))load("glBindAttribLocation"); + glCompileShader = cast(typeof(glCompileShader))load("glCompileShader"); + glCreateProgram = cast(typeof(glCreateProgram))load("glCreateProgram"); + glCreateShader = cast(typeof(glCreateShader))load("glCreateShader"); + glDeleteProgram = cast(typeof(glDeleteProgram))load("glDeleteProgram"); + glDeleteShader = cast(typeof(glDeleteShader))load("glDeleteShader"); + glDetachShader = cast(typeof(glDetachShader))load("glDetachShader"); + glDisableVertexAttribArray = cast(typeof(glDisableVertexAttribArray))load("glDisableVertexAttribArray"); + glEnableVertexAttribArray = cast(typeof(glEnableVertexAttribArray))load("glEnableVertexAttribArray"); + glGetActiveAttrib = cast(typeof(glGetActiveAttrib))load("glGetActiveAttrib"); + glGetActiveUniform = cast(typeof(glGetActiveUniform))load("glGetActiveUniform"); + glGetAttachedShaders = cast(typeof(glGetAttachedShaders))load("glGetAttachedShaders"); + glGetAttribLocation = cast(typeof(glGetAttribLocation))load("glGetAttribLocation"); + glGetProgramiv = cast(typeof(glGetProgramiv))load("glGetProgramiv"); + glGetProgramInfoLog = cast(typeof(glGetProgramInfoLog))load("glGetProgramInfoLog"); + glGetShaderiv = cast(typeof(glGetShaderiv))load("glGetShaderiv"); + glGetShaderInfoLog = cast(typeof(glGetShaderInfoLog))load("glGetShaderInfoLog"); + glGetShaderSource = cast(typeof(glGetShaderSource))load("glGetShaderSource"); + glGetUniformLocation = cast(typeof(glGetUniformLocation))load("glGetUniformLocation"); + glGetUniformfv = cast(typeof(glGetUniformfv))load("glGetUniformfv"); + glGetUniformiv = cast(typeof(glGetUniformiv))load("glGetUniformiv"); + glGetVertexAttribdv = cast(typeof(glGetVertexAttribdv))load("glGetVertexAttribdv"); + glGetVertexAttribfv = cast(typeof(glGetVertexAttribfv))load("glGetVertexAttribfv"); + glGetVertexAttribiv = cast(typeof(glGetVertexAttribiv))load("glGetVertexAttribiv"); + glGetVertexAttribPointerv = cast(typeof(glGetVertexAttribPointerv))load("glGetVertexAttribPointerv"); + glIsProgram = cast(typeof(glIsProgram))load("glIsProgram"); + glIsShader = cast(typeof(glIsShader))load("glIsShader"); + glLinkProgram = cast(typeof(glLinkProgram))load("glLinkProgram"); + glShaderSource = cast(typeof(glShaderSource))load("glShaderSource"); + glUseProgram = cast(typeof(glUseProgram))load("glUseProgram"); + glUniform1f = cast(typeof(glUniform1f))load("glUniform1f"); + glUniform2f = cast(typeof(glUniform2f))load("glUniform2f"); + glUniform3f = cast(typeof(glUniform3f))load("glUniform3f"); + glUniform4f = cast(typeof(glUniform4f))load("glUniform4f"); + glUniform1i = cast(typeof(glUniform1i))load("glUniform1i"); + glUniform2i = cast(typeof(glUniform2i))load("glUniform2i"); + glUniform3i = cast(typeof(glUniform3i))load("glUniform3i"); + glUniform4i = cast(typeof(glUniform4i))load("glUniform4i"); + glUniform1fv = cast(typeof(glUniform1fv))load("glUniform1fv"); + glUniform2fv = cast(typeof(glUniform2fv))load("glUniform2fv"); + glUniform3fv = cast(typeof(glUniform3fv))load("glUniform3fv"); + glUniform4fv = cast(typeof(glUniform4fv))load("glUniform4fv"); + glUniform1iv = cast(typeof(glUniform1iv))load("glUniform1iv"); + glUniform2iv = cast(typeof(glUniform2iv))load("glUniform2iv"); + glUniform3iv = cast(typeof(glUniform3iv))load("glUniform3iv"); + glUniform4iv = cast(typeof(glUniform4iv))load("glUniform4iv"); + glUniformMatrix2fv = cast(typeof(glUniformMatrix2fv))load("glUniformMatrix2fv"); + glUniformMatrix3fv = cast(typeof(glUniformMatrix3fv))load("glUniformMatrix3fv"); + glUniformMatrix4fv = cast(typeof(glUniformMatrix4fv))load("glUniformMatrix4fv"); + glValidateProgram = cast(typeof(glValidateProgram))load("glValidateProgram"); + glVertexAttrib1d = cast(typeof(glVertexAttrib1d))load("glVertexAttrib1d"); + glVertexAttrib1dv = cast(typeof(glVertexAttrib1dv))load("glVertexAttrib1dv"); + glVertexAttrib1f = cast(typeof(glVertexAttrib1f))load("glVertexAttrib1f"); + glVertexAttrib1fv = cast(typeof(glVertexAttrib1fv))load("glVertexAttrib1fv"); + glVertexAttrib1s = cast(typeof(glVertexAttrib1s))load("glVertexAttrib1s"); + glVertexAttrib1sv = cast(typeof(glVertexAttrib1sv))load("glVertexAttrib1sv"); + glVertexAttrib2d = cast(typeof(glVertexAttrib2d))load("glVertexAttrib2d"); + glVertexAttrib2dv = cast(typeof(glVertexAttrib2dv))load("glVertexAttrib2dv"); + glVertexAttrib2f = cast(typeof(glVertexAttrib2f))load("glVertexAttrib2f"); + glVertexAttrib2fv = cast(typeof(glVertexAttrib2fv))load("glVertexAttrib2fv"); + glVertexAttrib2s = cast(typeof(glVertexAttrib2s))load("glVertexAttrib2s"); + glVertexAttrib2sv = cast(typeof(glVertexAttrib2sv))load("glVertexAttrib2sv"); + glVertexAttrib3d = cast(typeof(glVertexAttrib3d))load("glVertexAttrib3d"); + glVertexAttrib3dv = cast(typeof(glVertexAttrib3dv))load("glVertexAttrib3dv"); + glVertexAttrib3f = cast(typeof(glVertexAttrib3f))load("glVertexAttrib3f"); + glVertexAttrib3fv = cast(typeof(glVertexAttrib3fv))load("glVertexAttrib3fv"); + glVertexAttrib3s = cast(typeof(glVertexAttrib3s))load("glVertexAttrib3s"); + glVertexAttrib3sv = cast(typeof(glVertexAttrib3sv))load("glVertexAttrib3sv"); + glVertexAttrib4Nbv = cast(typeof(glVertexAttrib4Nbv))load("glVertexAttrib4Nbv"); + glVertexAttrib4Niv = cast(typeof(glVertexAttrib4Niv))load("glVertexAttrib4Niv"); + glVertexAttrib4Nsv = cast(typeof(glVertexAttrib4Nsv))load("glVertexAttrib4Nsv"); + glVertexAttrib4Nub = cast(typeof(glVertexAttrib4Nub))load("glVertexAttrib4Nub"); + glVertexAttrib4Nubv = cast(typeof(glVertexAttrib4Nubv))load("glVertexAttrib4Nubv"); + glVertexAttrib4Nuiv = cast(typeof(glVertexAttrib4Nuiv))load("glVertexAttrib4Nuiv"); + glVertexAttrib4Nusv = cast(typeof(glVertexAttrib4Nusv))load("glVertexAttrib4Nusv"); + glVertexAttrib4bv = cast(typeof(glVertexAttrib4bv))load("glVertexAttrib4bv"); + glVertexAttrib4d = cast(typeof(glVertexAttrib4d))load("glVertexAttrib4d"); + glVertexAttrib4dv = cast(typeof(glVertexAttrib4dv))load("glVertexAttrib4dv"); + glVertexAttrib4f = cast(typeof(glVertexAttrib4f))load("glVertexAttrib4f"); + glVertexAttrib4fv = cast(typeof(glVertexAttrib4fv))load("glVertexAttrib4fv"); + glVertexAttrib4iv = cast(typeof(glVertexAttrib4iv))load("glVertexAttrib4iv"); + glVertexAttrib4s = cast(typeof(glVertexAttrib4s))load("glVertexAttrib4s"); + glVertexAttrib4sv = cast(typeof(glVertexAttrib4sv))load("glVertexAttrib4sv"); + glVertexAttrib4ubv = cast(typeof(glVertexAttrib4ubv))load("glVertexAttrib4ubv"); + glVertexAttrib4uiv = cast(typeof(glVertexAttrib4uiv))load("glVertexAttrib4uiv"); + glVertexAttrib4usv = cast(typeof(glVertexAttrib4usv))load("glVertexAttrib4usv"); + glVertexAttribPointer = cast(typeof(glVertexAttribPointer))load("glVertexAttribPointer"); + return; +} + +void load_GL_VERSION_2_1(Loader load) { + if(!GL_VERSION_2_1) return; + glUniformMatrix2x3fv = cast(typeof(glUniformMatrix2x3fv))load("glUniformMatrix2x3fv"); + glUniformMatrix3x2fv = cast(typeof(glUniformMatrix3x2fv))load("glUniformMatrix3x2fv"); + glUniformMatrix2x4fv = cast(typeof(glUniformMatrix2x4fv))load("glUniformMatrix2x4fv"); + glUniformMatrix4x2fv = cast(typeof(glUniformMatrix4x2fv))load("glUniformMatrix4x2fv"); + glUniformMatrix3x4fv = cast(typeof(glUniformMatrix3x4fv))load("glUniformMatrix3x4fv"); + glUniformMatrix4x3fv = cast(typeof(glUniformMatrix4x3fv))load("glUniformMatrix4x3fv"); + return; +} + +void load_GL_VERSION_3_0(Loader load) { + if(!GL_VERSION_3_0) return; + glColorMaski = cast(typeof(glColorMaski))load("glColorMaski"); + glGetBooleani_v = cast(typeof(glGetBooleani_v))load("glGetBooleani_v"); + glGetIntegeri_v = cast(typeof(glGetIntegeri_v))load("glGetIntegeri_v"); + glEnablei = cast(typeof(glEnablei))load("glEnablei"); + glDisablei = cast(typeof(glDisablei))load("glDisablei"); + glIsEnabledi = cast(typeof(glIsEnabledi))load("glIsEnabledi"); + glBeginTransformFeedback = cast(typeof(glBeginTransformFeedback))load("glBeginTransformFeedback"); + glEndTransformFeedback = cast(typeof(glEndTransformFeedback))load("glEndTransformFeedback"); + glBindBufferRange = cast(typeof(glBindBufferRange))load("glBindBufferRange"); + glBindBufferBase = cast(typeof(glBindBufferBase))load("glBindBufferBase"); + glTransformFeedbackVaryings = cast(typeof(glTransformFeedbackVaryings))load("glTransformFeedbackVaryings"); + glGetTransformFeedbackVarying = cast(typeof(glGetTransformFeedbackVarying))load("glGetTransformFeedbackVarying"); + glClampColor = cast(typeof(glClampColor))load("glClampColor"); + glBeginConditionalRender = cast(typeof(glBeginConditionalRender))load("glBeginConditionalRender"); + glEndConditionalRender = cast(typeof(glEndConditionalRender))load("glEndConditionalRender"); + glVertexAttribIPointer = cast(typeof(glVertexAttribIPointer))load("glVertexAttribIPointer"); + glGetVertexAttribIiv = cast(typeof(glGetVertexAttribIiv))load("glGetVertexAttribIiv"); + glGetVertexAttribIuiv = cast(typeof(glGetVertexAttribIuiv))load("glGetVertexAttribIuiv"); + glVertexAttribI1i = cast(typeof(glVertexAttribI1i))load("glVertexAttribI1i"); + glVertexAttribI2i = cast(typeof(glVertexAttribI2i))load("glVertexAttribI2i"); + glVertexAttribI3i = cast(typeof(glVertexAttribI3i))load("glVertexAttribI3i"); + glVertexAttribI4i = cast(typeof(glVertexAttribI4i))load("glVertexAttribI4i"); + glVertexAttribI1ui = cast(typeof(glVertexAttribI1ui))load("glVertexAttribI1ui"); + glVertexAttribI2ui = cast(typeof(glVertexAttribI2ui))load("glVertexAttribI2ui"); + glVertexAttribI3ui = cast(typeof(glVertexAttribI3ui))load("glVertexAttribI3ui"); + glVertexAttribI4ui = cast(typeof(glVertexAttribI4ui))load("glVertexAttribI4ui"); + glVertexAttribI1iv = cast(typeof(glVertexAttribI1iv))load("glVertexAttribI1iv"); + glVertexAttribI2iv = cast(typeof(glVertexAttribI2iv))load("glVertexAttribI2iv"); + glVertexAttribI3iv = cast(typeof(glVertexAttribI3iv))load("glVertexAttribI3iv"); + glVertexAttribI4iv = cast(typeof(glVertexAttribI4iv))load("glVertexAttribI4iv"); + glVertexAttribI1uiv = cast(typeof(glVertexAttribI1uiv))load("glVertexAttribI1uiv"); + glVertexAttribI2uiv = cast(typeof(glVertexAttribI2uiv))load("glVertexAttribI2uiv"); + glVertexAttribI3uiv = cast(typeof(glVertexAttribI3uiv))load("glVertexAttribI3uiv"); + glVertexAttribI4uiv = cast(typeof(glVertexAttribI4uiv))load("glVertexAttribI4uiv"); + glVertexAttribI4bv = cast(typeof(glVertexAttribI4bv))load("glVertexAttribI4bv"); + glVertexAttribI4sv = cast(typeof(glVertexAttribI4sv))load("glVertexAttribI4sv"); + glVertexAttribI4ubv = cast(typeof(glVertexAttribI4ubv))load("glVertexAttribI4ubv"); + glVertexAttribI4usv = cast(typeof(glVertexAttribI4usv))load("glVertexAttribI4usv"); + glGetUniformuiv = cast(typeof(glGetUniformuiv))load("glGetUniformuiv"); + glBindFragDataLocation = cast(typeof(glBindFragDataLocation))load("glBindFragDataLocation"); + glGetFragDataLocation = cast(typeof(glGetFragDataLocation))load("glGetFragDataLocation"); + glUniform1ui = cast(typeof(glUniform1ui))load("glUniform1ui"); + glUniform2ui = cast(typeof(glUniform2ui))load("glUniform2ui"); + glUniform3ui = cast(typeof(glUniform3ui))load("glUniform3ui"); + glUniform4ui = cast(typeof(glUniform4ui))load("glUniform4ui"); + glUniform1uiv = cast(typeof(glUniform1uiv))load("glUniform1uiv"); + glUniform2uiv = cast(typeof(glUniform2uiv))load("glUniform2uiv"); + glUniform3uiv = cast(typeof(glUniform3uiv))load("glUniform3uiv"); + glUniform4uiv = cast(typeof(glUniform4uiv))load("glUniform4uiv"); + glTexParameterIiv = cast(typeof(glTexParameterIiv))load("glTexParameterIiv"); + glTexParameterIuiv = cast(typeof(glTexParameterIuiv))load("glTexParameterIuiv"); + glGetTexParameterIiv = cast(typeof(glGetTexParameterIiv))load("glGetTexParameterIiv"); + glGetTexParameterIuiv = cast(typeof(glGetTexParameterIuiv))load("glGetTexParameterIuiv"); + glClearBufferiv = cast(typeof(glClearBufferiv))load("glClearBufferiv"); + glClearBufferuiv = cast(typeof(glClearBufferuiv))load("glClearBufferuiv"); + glClearBufferfv = cast(typeof(glClearBufferfv))load("glClearBufferfv"); + glClearBufferfi = cast(typeof(glClearBufferfi))load("glClearBufferfi"); + glGetStringi = cast(typeof(glGetStringi))load("glGetStringi"); + glIsRenderbuffer = cast(typeof(glIsRenderbuffer))load("glIsRenderbuffer"); + glBindRenderbuffer = cast(typeof(glBindRenderbuffer))load("glBindRenderbuffer"); + glDeleteRenderbuffers = cast(typeof(glDeleteRenderbuffers))load("glDeleteRenderbuffers"); + glGenRenderbuffers = cast(typeof(glGenRenderbuffers))load("glGenRenderbuffers"); + glRenderbufferStorage = cast(typeof(glRenderbufferStorage))load("glRenderbufferStorage"); + glGetRenderbufferParameteriv = cast(typeof(glGetRenderbufferParameteriv))load("glGetRenderbufferParameteriv"); + glIsFramebuffer = cast(typeof(glIsFramebuffer))load("glIsFramebuffer"); + glBindFramebuffer = cast(typeof(glBindFramebuffer))load("glBindFramebuffer"); + glDeleteFramebuffers = cast(typeof(glDeleteFramebuffers))load("glDeleteFramebuffers"); + glGenFramebuffers = cast(typeof(glGenFramebuffers))load("glGenFramebuffers"); + glCheckFramebufferStatus = cast(typeof(glCheckFramebufferStatus))load("glCheckFramebufferStatus"); + glFramebufferTexture1D = cast(typeof(glFramebufferTexture1D))load("glFramebufferTexture1D"); + glFramebufferTexture2D = cast(typeof(glFramebufferTexture2D))load("glFramebufferTexture2D"); + glFramebufferTexture3D = cast(typeof(glFramebufferTexture3D))load("glFramebufferTexture3D"); + glFramebufferRenderbuffer = cast(typeof(glFramebufferRenderbuffer))load("glFramebufferRenderbuffer"); + glGetFramebufferAttachmentParameteriv = cast(typeof(glGetFramebufferAttachmentParameteriv))load("glGetFramebufferAttachmentParameteriv"); + glGenerateMipmap = cast(typeof(glGenerateMipmap))load("glGenerateMipmap"); + glBlitFramebuffer = cast(typeof(glBlitFramebuffer))load("glBlitFramebuffer"); + glRenderbufferStorageMultisample = cast(typeof(glRenderbufferStorageMultisample))load("glRenderbufferStorageMultisample"); + glFramebufferTextureLayer = cast(typeof(glFramebufferTextureLayer))load("glFramebufferTextureLayer"); + glMapBufferRange = cast(typeof(glMapBufferRange))load("glMapBufferRange"); + glFlushMappedBufferRange = cast(typeof(glFlushMappedBufferRange))load("glFlushMappedBufferRange"); + glBindVertexArray = cast(typeof(glBindVertexArray))load("glBindVertexArray"); + glDeleteVertexArrays = cast(typeof(glDeleteVertexArrays))load("glDeleteVertexArrays"); + glGenVertexArrays = cast(typeof(glGenVertexArrays))load("glGenVertexArrays"); + glIsVertexArray = cast(typeof(glIsVertexArray))load("glIsVertexArray"); + return; +} + +void load_GL_VERSION_3_1(Loader load) { + if(!GL_VERSION_3_1) return; + glDrawArraysInstanced = cast(typeof(glDrawArraysInstanced))load("glDrawArraysInstanced"); + glDrawElementsInstanced = cast(typeof(glDrawElementsInstanced))load("glDrawElementsInstanced"); + glTexBuffer = cast(typeof(glTexBuffer))load("glTexBuffer"); + glPrimitiveRestartIndex = cast(typeof(glPrimitiveRestartIndex))load("glPrimitiveRestartIndex"); + glCopyBufferSubData = cast(typeof(glCopyBufferSubData))load("glCopyBufferSubData"); + glGetUniformIndices = cast(typeof(glGetUniformIndices))load("glGetUniformIndices"); + glGetActiveUniformsiv = cast(typeof(glGetActiveUniformsiv))load("glGetActiveUniformsiv"); + glGetActiveUniformName = cast(typeof(glGetActiveUniformName))load("glGetActiveUniformName"); + glGetUniformBlockIndex = cast(typeof(glGetUniformBlockIndex))load("glGetUniformBlockIndex"); + glGetActiveUniformBlockiv = cast(typeof(glGetActiveUniformBlockiv))load("glGetActiveUniformBlockiv"); + glGetActiveUniformBlockName = cast(typeof(glGetActiveUniformBlockName))load("glGetActiveUniformBlockName"); + glUniformBlockBinding = cast(typeof(glUniformBlockBinding))load("glUniformBlockBinding"); + glBindBufferRange = cast(typeof(glBindBufferRange))load("glBindBufferRange"); + glBindBufferBase = cast(typeof(glBindBufferBase))load("glBindBufferBase"); + glGetIntegeri_v = cast(typeof(glGetIntegeri_v))load("glGetIntegeri_v"); + return; +} + +void load_GL_VERSION_3_2(Loader load) { + if(!GL_VERSION_3_2) return; + glDrawElementsBaseVertex = cast(typeof(glDrawElementsBaseVertex))load("glDrawElementsBaseVertex"); + glDrawRangeElementsBaseVertex = cast(typeof(glDrawRangeElementsBaseVertex))load("glDrawRangeElementsBaseVertex"); + glDrawElementsInstancedBaseVertex = cast(typeof(glDrawElementsInstancedBaseVertex))load("glDrawElementsInstancedBaseVertex"); + glMultiDrawElementsBaseVertex = cast(typeof(glMultiDrawElementsBaseVertex))load("glMultiDrawElementsBaseVertex"); + glProvokingVertex = cast(typeof(glProvokingVertex))load("glProvokingVertex"); + glFenceSync = cast(typeof(glFenceSync))load("glFenceSync"); + glIsSync = cast(typeof(glIsSync))load("glIsSync"); + glDeleteSync = cast(typeof(glDeleteSync))load("glDeleteSync"); + glClientWaitSync = cast(typeof(glClientWaitSync))load("glClientWaitSync"); + glWaitSync = cast(typeof(glWaitSync))load("glWaitSync"); + glGetInteger64v = cast(typeof(glGetInteger64v))load("glGetInteger64v"); + glGetSynciv = cast(typeof(glGetSynciv))load("glGetSynciv"); + glGetInteger64i_v = cast(typeof(glGetInteger64i_v))load("glGetInteger64i_v"); + glGetBufferParameteri64v = cast(typeof(glGetBufferParameteri64v))load("glGetBufferParameteri64v"); + glFramebufferTexture = cast(typeof(glFramebufferTexture))load("glFramebufferTexture"); + glTexImage2DMultisample = cast(typeof(glTexImage2DMultisample))load("glTexImage2DMultisample"); + glTexImage3DMultisample = cast(typeof(glTexImage3DMultisample))load("glTexImage3DMultisample"); + glGetMultisamplefv = cast(typeof(glGetMultisamplefv))load("glGetMultisamplefv"); + glSampleMaski = cast(typeof(glSampleMaski))load("glSampleMaski"); + return; +} + +void load_GL_VERSION_3_3(Loader load) { + if(!GL_VERSION_3_3) return; + glBindFragDataLocationIndexed = cast(typeof(glBindFragDataLocationIndexed))load("glBindFragDataLocationIndexed"); + glGetFragDataIndex = cast(typeof(glGetFragDataIndex))load("glGetFragDataIndex"); + glGenSamplers = cast(typeof(glGenSamplers))load("glGenSamplers"); + glDeleteSamplers = cast(typeof(glDeleteSamplers))load("glDeleteSamplers"); + glIsSampler = cast(typeof(glIsSampler))load("glIsSampler"); + glBindSampler = cast(typeof(glBindSampler))load("glBindSampler"); + glSamplerParameteri = cast(typeof(glSamplerParameteri))load("glSamplerParameteri"); + glSamplerParameteriv = cast(typeof(glSamplerParameteriv))load("glSamplerParameteriv"); + glSamplerParameterf = cast(typeof(glSamplerParameterf))load("glSamplerParameterf"); + glSamplerParameterfv = cast(typeof(glSamplerParameterfv))load("glSamplerParameterfv"); + glSamplerParameterIiv = cast(typeof(glSamplerParameterIiv))load("glSamplerParameterIiv"); + glSamplerParameterIuiv = cast(typeof(glSamplerParameterIuiv))load("glSamplerParameterIuiv"); + glGetSamplerParameteriv = cast(typeof(glGetSamplerParameteriv))load("glGetSamplerParameteriv"); + glGetSamplerParameterIiv = cast(typeof(glGetSamplerParameterIiv))load("glGetSamplerParameterIiv"); + glGetSamplerParameterfv = cast(typeof(glGetSamplerParameterfv))load("glGetSamplerParameterfv"); + glGetSamplerParameterIuiv = cast(typeof(glGetSamplerParameterIuiv))load("glGetSamplerParameterIuiv"); + glQueryCounter = cast(typeof(glQueryCounter))load("glQueryCounter"); + glGetQueryObjecti64v = cast(typeof(glGetQueryObjecti64v))load("glGetQueryObjecti64v"); + glGetQueryObjectui64v = cast(typeof(glGetQueryObjectui64v))load("glGetQueryObjectui64v"); + glVertexAttribDivisor = cast(typeof(glVertexAttribDivisor))load("glVertexAttribDivisor"); + glVertexAttribP1ui = cast(typeof(glVertexAttribP1ui))load("glVertexAttribP1ui"); + glVertexAttribP1uiv = cast(typeof(glVertexAttribP1uiv))load("glVertexAttribP1uiv"); + glVertexAttribP2ui = cast(typeof(glVertexAttribP2ui))load("glVertexAttribP2ui"); + glVertexAttribP2uiv = cast(typeof(glVertexAttribP2uiv))load("glVertexAttribP2uiv"); + glVertexAttribP3ui = cast(typeof(glVertexAttribP3ui))load("glVertexAttribP3ui"); + glVertexAttribP3uiv = cast(typeof(glVertexAttribP3uiv))load("glVertexAttribP3uiv"); + glVertexAttribP4ui = cast(typeof(glVertexAttribP4ui))load("glVertexAttribP4ui"); + glVertexAttribP4uiv = cast(typeof(glVertexAttribP4uiv))load("glVertexAttribP4uiv"); + glVertexP2ui = cast(typeof(glVertexP2ui))load("glVertexP2ui"); + glVertexP2uiv = cast(typeof(glVertexP2uiv))load("glVertexP2uiv"); + glVertexP3ui = cast(typeof(glVertexP3ui))load("glVertexP3ui"); + glVertexP3uiv = cast(typeof(glVertexP3uiv))load("glVertexP3uiv"); + glVertexP4ui = cast(typeof(glVertexP4ui))load("glVertexP4ui"); + glVertexP4uiv = cast(typeof(glVertexP4uiv))load("glVertexP4uiv"); + glTexCoordP1ui = cast(typeof(glTexCoordP1ui))load("glTexCoordP1ui"); + glTexCoordP1uiv = cast(typeof(glTexCoordP1uiv))load("glTexCoordP1uiv"); + glTexCoordP2ui = cast(typeof(glTexCoordP2ui))load("glTexCoordP2ui"); + glTexCoordP2uiv = cast(typeof(glTexCoordP2uiv))load("glTexCoordP2uiv"); + glTexCoordP3ui = cast(typeof(glTexCoordP3ui))load("glTexCoordP3ui"); + glTexCoordP3uiv = cast(typeof(glTexCoordP3uiv))load("glTexCoordP3uiv"); + glTexCoordP4ui = cast(typeof(glTexCoordP4ui))load("glTexCoordP4ui"); + glTexCoordP4uiv = cast(typeof(glTexCoordP4uiv))load("glTexCoordP4uiv"); + glMultiTexCoordP1ui = cast(typeof(glMultiTexCoordP1ui))load("glMultiTexCoordP1ui"); + glMultiTexCoordP1uiv = cast(typeof(glMultiTexCoordP1uiv))load("glMultiTexCoordP1uiv"); + glMultiTexCoordP2ui = cast(typeof(glMultiTexCoordP2ui))load("glMultiTexCoordP2ui"); + glMultiTexCoordP2uiv = cast(typeof(glMultiTexCoordP2uiv))load("glMultiTexCoordP2uiv"); + glMultiTexCoordP3ui = cast(typeof(glMultiTexCoordP3ui))load("glMultiTexCoordP3ui"); + glMultiTexCoordP3uiv = cast(typeof(glMultiTexCoordP3uiv))load("glMultiTexCoordP3uiv"); + glMultiTexCoordP4ui = cast(typeof(glMultiTexCoordP4ui))load("glMultiTexCoordP4ui"); + glMultiTexCoordP4uiv = cast(typeof(glMultiTexCoordP4uiv))load("glMultiTexCoordP4uiv"); + glNormalP3ui = cast(typeof(glNormalP3ui))load("glNormalP3ui"); + glNormalP3uiv = cast(typeof(glNormalP3uiv))load("glNormalP3uiv"); + glColorP3ui = cast(typeof(glColorP3ui))load("glColorP3ui"); + glColorP3uiv = cast(typeof(glColorP3uiv))load("glColorP3uiv"); + glColorP4ui = cast(typeof(glColorP4ui))load("glColorP4ui"); + glColorP4uiv = cast(typeof(glColorP4uiv))load("glColorP4uiv"); + glSecondaryColorP3ui = cast(typeof(glSecondaryColorP3ui))load("glSecondaryColorP3ui"); + glSecondaryColorP3uiv = cast(typeof(glSecondaryColorP3uiv))load("glSecondaryColorP3uiv"); + return; +} + + +} /* private */ + +bool gladLoadGLES2(Loader load) { + glGetString = cast(typeof(glGetString))load("glGetString"); + if(glGetString is null) { return false; } + if(glGetString(GL_VERSION) is null) { return false; } + + find_coreGLES2(); + load_GL_ES_VERSION_2_0(load); + load_GL_ES_VERSION_3_0(load); + + find_extensionsGLES2(); + return GLVersion.major != 0 || GLVersion.minor != 0; +} + +private { + +void find_coreGLES2() { + + // Thank you @elmindreda + // https://github.com/elmindreda/greg/blob/master/templates/greg.c.in#L176 + // https://github.com/glfw/glfw/blob/master/src/context.c#L36 + int i; + const(char)* glversion; + const(char)*[3] prefixes = [ + "OpenGL ES-CM ".ptr, + "OpenGL ES-CL ".ptr, + "OpenGL ES ".ptr, + ]; + + glversion = cast(const(char)*)glGetString(GL_VERSION); + if (glversion is null) return; + + foreach(prefix; prefixes) { + size_t length = strlen(prefix); + if (strncmp(glversion, prefix, length) == 0) { + glversion += length; + break; + } + } + + int major = glversion[0] - '0'; + int minor = glversion[2] - '0'; + GLVersion.major = major; GLVersion.minor = minor; + GL_ES_VERSION_2_0 = (major == 2 && minor >= 0) || major > 2; + GL_ES_VERSION_3_0 = (major == 3 && minor >= 0) || major > 3; + return; +} + +void find_extensionsGLES2() { + return; +} + +void load_GL_ES_VERSION_2_0(Loader load) { + if(!GL_ES_VERSION_2_0) return; + glActiveTexture = cast(typeof(glActiveTexture))load("glActiveTexture"); + glAttachShader = cast(typeof(glAttachShader))load("glAttachShader"); + glBindAttribLocation = cast(typeof(glBindAttribLocation))load("glBindAttribLocation"); + glBindBuffer = cast(typeof(glBindBuffer))load("glBindBuffer"); + glBindFramebuffer = cast(typeof(glBindFramebuffer))load("glBindFramebuffer"); + glBindRenderbuffer = cast(typeof(glBindRenderbuffer))load("glBindRenderbuffer"); + glBindTexture = cast(typeof(glBindTexture))load("glBindTexture"); + glBlendColor = cast(typeof(glBlendColor))load("glBlendColor"); + glBlendEquation = cast(typeof(glBlendEquation))load("glBlendEquation"); + glBlendEquationSeparate = cast(typeof(glBlendEquationSeparate))load("glBlendEquationSeparate"); + glBlendFunc = cast(typeof(glBlendFunc))load("glBlendFunc"); + glBlendFuncSeparate = cast(typeof(glBlendFuncSeparate))load("glBlendFuncSeparate"); + glBufferData = cast(typeof(glBufferData))load("glBufferData"); + glBufferSubData = cast(typeof(glBufferSubData))load("glBufferSubData"); + glCheckFramebufferStatus = cast(typeof(glCheckFramebufferStatus))load("glCheckFramebufferStatus"); + glClear = cast(typeof(glClear))load("glClear"); + glClearColor = cast(typeof(glClearColor))load("glClearColor"); + glClearDepthf = cast(typeof(glClearDepthf))load("glClearDepthf"); + glClearStencil = cast(typeof(glClearStencil))load("glClearStencil"); + glColorMask = cast(typeof(glColorMask))load("glColorMask"); + glCompileShader = cast(typeof(glCompileShader))load("glCompileShader"); + glCompressedTexImage2D = cast(typeof(glCompressedTexImage2D))load("glCompressedTexImage2D"); + glCompressedTexSubImage2D = cast(typeof(glCompressedTexSubImage2D))load("glCompressedTexSubImage2D"); + glCopyTexImage2D = cast(typeof(glCopyTexImage2D))load("glCopyTexImage2D"); + glCopyTexSubImage2D = cast(typeof(glCopyTexSubImage2D))load("glCopyTexSubImage2D"); + glCreateProgram = cast(typeof(glCreateProgram))load("glCreateProgram"); + glCreateShader = cast(typeof(glCreateShader))load("glCreateShader"); + glCullFace = cast(typeof(glCullFace))load("glCullFace"); + glDeleteBuffers = cast(typeof(glDeleteBuffers))load("glDeleteBuffers"); + glDeleteFramebuffers = cast(typeof(glDeleteFramebuffers))load("glDeleteFramebuffers"); + glDeleteProgram = cast(typeof(glDeleteProgram))load("glDeleteProgram"); + glDeleteRenderbuffers = cast(typeof(glDeleteRenderbuffers))load("glDeleteRenderbuffers"); + glDeleteShader = cast(typeof(glDeleteShader))load("glDeleteShader"); + glDeleteTextures = cast(typeof(glDeleteTextures))load("glDeleteTextures"); + glDepthFunc = cast(typeof(glDepthFunc))load("glDepthFunc"); + glDepthMask = cast(typeof(glDepthMask))load("glDepthMask"); + glDepthRangef = cast(typeof(glDepthRangef))load("glDepthRangef"); + glDetachShader = cast(typeof(glDetachShader))load("glDetachShader"); + glDisable = cast(typeof(glDisable))load("glDisable"); + glDisableVertexAttribArray = cast(typeof(glDisableVertexAttribArray))load("glDisableVertexAttribArray"); + glDrawArrays = cast(typeof(glDrawArrays))load("glDrawArrays"); + glDrawElements = cast(typeof(glDrawElements))load("glDrawElements"); + glEnable = cast(typeof(glEnable))load("glEnable"); + glEnableVertexAttribArray = cast(typeof(glEnableVertexAttribArray))load("glEnableVertexAttribArray"); + glFinish = cast(typeof(glFinish))load("glFinish"); + glFlush = cast(typeof(glFlush))load("glFlush"); + glFramebufferRenderbuffer = cast(typeof(glFramebufferRenderbuffer))load("glFramebufferRenderbuffer"); + glFramebufferTexture2D = cast(typeof(glFramebufferTexture2D))load("glFramebufferTexture2D"); + glFrontFace = cast(typeof(glFrontFace))load("glFrontFace"); + glGenBuffers = cast(typeof(glGenBuffers))load("glGenBuffers"); + glGenerateMipmap = cast(typeof(glGenerateMipmap))load("glGenerateMipmap"); + glGenFramebuffers = cast(typeof(glGenFramebuffers))load("glGenFramebuffers"); + glGenRenderbuffers = cast(typeof(glGenRenderbuffers))load("glGenRenderbuffers"); + glGenTextures = cast(typeof(glGenTextures))load("glGenTextures"); + glGetActiveAttrib = cast(typeof(glGetActiveAttrib))load("glGetActiveAttrib"); + glGetActiveUniform = cast(typeof(glGetActiveUniform))load("glGetActiveUniform"); + glGetAttachedShaders = cast(typeof(glGetAttachedShaders))load("glGetAttachedShaders"); + glGetAttribLocation = cast(typeof(glGetAttribLocation))load("glGetAttribLocation"); + glGetBooleanv = cast(typeof(glGetBooleanv))load("glGetBooleanv"); + glGetBufferParameteriv = cast(typeof(glGetBufferParameteriv))load("glGetBufferParameteriv"); + glGetError = cast(typeof(glGetError))load("glGetError"); + glGetFloatv = cast(typeof(glGetFloatv))load("glGetFloatv"); + glGetFramebufferAttachmentParameteriv = cast(typeof(glGetFramebufferAttachmentParameteriv))load("glGetFramebufferAttachmentParameteriv"); + glGetIntegerv = cast(typeof(glGetIntegerv))load("glGetIntegerv"); + glGetProgramiv = cast(typeof(glGetProgramiv))load("glGetProgramiv"); + glGetProgramInfoLog = cast(typeof(glGetProgramInfoLog))load("glGetProgramInfoLog"); + glGetRenderbufferParameteriv = cast(typeof(glGetRenderbufferParameteriv))load("glGetRenderbufferParameteriv"); + glGetShaderiv = cast(typeof(glGetShaderiv))load("glGetShaderiv"); + glGetShaderInfoLog = cast(typeof(glGetShaderInfoLog))load("glGetShaderInfoLog"); + glGetShaderPrecisionFormat = cast(typeof(glGetShaderPrecisionFormat))load("glGetShaderPrecisionFormat"); + glGetShaderSource = cast(typeof(glGetShaderSource))load("glGetShaderSource"); + glGetString = cast(typeof(glGetString))load("glGetString"); + glGetTexParameterfv = cast(typeof(glGetTexParameterfv))load("glGetTexParameterfv"); + glGetTexParameteriv = cast(typeof(glGetTexParameteriv))load("glGetTexParameteriv"); + glGetUniformfv = cast(typeof(glGetUniformfv))load("glGetUniformfv"); + glGetUniformiv = cast(typeof(glGetUniformiv))load("glGetUniformiv"); + glGetUniformLocation = cast(typeof(glGetUniformLocation))load("glGetUniformLocation"); + glGetVertexAttribfv = cast(typeof(glGetVertexAttribfv))load("glGetVertexAttribfv"); + glGetVertexAttribiv = cast(typeof(glGetVertexAttribiv))load("glGetVertexAttribiv"); + glGetVertexAttribPointerv = cast(typeof(glGetVertexAttribPointerv))load("glGetVertexAttribPointerv"); + glHint = cast(typeof(glHint))load("glHint"); + glIsBuffer = cast(typeof(glIsBuffer))load("glIsBuffer"); + glIsEnabled = cast(typeof(glIsEnabled))load("glIsEnabled"); + glIsFramebuffer = cast(typeof(glIsFramebuffer))load("glIsFramebuffer"); + glIsProgram = cast(typeof(glIsProgram))load("glIsProgram"); + glIsRenderbuffer = cast(typeof(glIsRenderbuffer))load("glIsRenderbuffer"); + glIsShader = cast(typeof(glIsShader))load("glIsShader"); + glIsTexture = cast(typeof(glIsTexture))load("glIsTexture"); + glLineWidth = cast(typeof(glLineWidth))load("glLineWidth"); + glLinkProgram = cast(typeof(glLinkProgram))load("glLinkProgram"); + glPixelStorei = cast(typeof(glPixelStorei))load("glPixelStorei"); + glPolygonOffset = cast(typeof(glPolygonOffset))load("glPolygonOffset"); + glReadPixels = cast(typeof(glReadPixels))load("glReadPixels"); + glReleaseShaderCompiler = cast(typeof(glReleaseShaderCompiler))load("glReleaseShaderCompiler"); + glRenderbufferStorage = cast(typeof(glRenderbufferStorage))load("glRenderbufferStorage"); + glSampleCoverage = cast(typeof(glSampleCoverage))load("glSampleCoverage"); + glScissor = cast(typeof(glScissor))load("glScissor"); + glShaderBinary = cast(typeof(glShaderBinary))load("glShaderBinary"); + glShaderSource = cast(typeof(glShaderSource))load("glShaderSource"); + glStencilFunc = cast(typeof(glStencilFunc))load("glStencilFunc"); + glStencilFuncSeparate = cast(typeof(glStencilFuncSeparate))load("glStencilFuncSeparate"); + glStencilMask = cast(typeof(glStencilMask))load("glStencilMask"); + glStencilMaskSeparate = cast(typeof(glStencilMaskSeparate))load("glStencilMaskSeparate"); + glStencilOp = cast(typeof(glStencilOp))load("glStencilOp"); + glStencilOpSeparate = cast(typeof(glStencilOpSeparate))load("glStencilOpSeparate"); + glTexImage2D = cast(typeof(glTexImage2D))load("glTexImage2D"); + glTexParameterf = cast(typeof(glTexParameterf))load("glTexParameterf"); + glTexParameterfv = cast(typeof(glTexParameterfv))load("glTexParameterfv"); + glTexParameteri = cast(typeof(glTexParameteri))load("glTexParameteri"); + glTexParameteriv = cast(typeof(glTexParameteriv))load("glTexParameteriv"); + glTexSubImage2D = cast(typeof(glTexSubImage2D))load("glTexSubImage2D"); + glUniform1f = cast(typeof(glUniform1f))load("glUniform1f"); + glUniform1fv = cast(typeof(glUniform1fv))load("glUniform1fv"); + glUniform1i = cast(typeof(glUniform1i))load("glUniform1i"); + glUniform1iv = cast(typeof(glUniform1iv))load("glUniform1iv"); + glUniform2f = cast(typeof(glUniform2f))load("glUniform2f"); + glUniform2fv = cast(typeof(glUniform2fv))load("glUniform2fv"); + glUniform2i = cast(typeof(glUniform2i))load("glUniform2i"); + glUniform2iv = cast(typeof(glUniform2iv))load("glUniform2iv"); + glUniform3f = cast(typeof(glUniform3f))load("glUniform3f"); + glUniform3fv = cast(typeof(glUniform3fv))load("glUniform3fv"); + glUniform3i = cast(typeof(glUniform3i))load("glUniform3i"); + glUniform3iv = cast(typeof(glUniform3iv))load("glUniform3iv"); + glUniform4f = cast(typeof(glUniform4f))load("glUniform4f"); + glUniform4fv = cast(typeof(glUniform4fv))load("glUniform4fv"); + glUniform4i = cast(typeof(glUniform4i))load("glUniform4i"); + glUniform4iv = cast(typeof(glUniform4iv))load("glUniform4iv"); + glUniformMatrix2fv = cast(typeof(glUniformMatrix2fv))load("glUniformMatrix2fv"); + glUniformMatrix3fv = cast(typeof(glUniformMatrix3fv))load("glUniformMatrix3fv"); + glUniformMatrix4fv = cast(typeof(glUniformMatrix4fv))load("glUniformMatrix4fv"); + glUseProgram = cast(typeof(glUseProgram))load("glUseProgram"); + glValidateProgram = cast(typeof(glValidateProgram))load("glValidateProgram"); + glVertexAttrib1f = cast(typeof(glVertexAttrib1f))load("glVertexAttrib1f"); + glVertexAttrib1fv = cast(typeof(glVertexAttrib1fv))load("glVertexAttrib1fv"); + glVertexAttrib2f = cast(typeof(glVertexAttrib2f))load("glVertexAttrib2f"); + glVertexAttrib2fv = cast(typeof(glVertexAttrib2fv))load("glVertexAttrib2fv"); + glVertexAttrib3f = cast(typeof(glVertexAttrib3f))load("glVertexAttrib3f"); + glVertexAttrib3fv = cast(typeof(glVertexAttrib3fv))load("glVertexAttrib3fv"); + glVertexAttrib4f = cast(typeof(glVertexAttrib4f))load("glVertexAttrib4f"); + glVertexAttrib4fv = cast(typeof(glVertexAttrib4fv))load("glVertexAttrib4fv"); + glVertexAttribPointer = cast(typeof(glVertexAttribPointer))load("glVertexAttribPointer"); + glViewport = cast(typeof(glViewport))load("glViewport"); + return; +} + +void load_GL_ES_VERSION_3_0(Loader load) { + if(!GL_ES_VERSION_3_0) return; + glReadBuffer = cast(typeof(glReadBuffer))load("glReadBuffer"); + glDrawRangeElements = cast(typeof(glDrawRangeElements))load("glDrawRangeElements"); + glTexImage3D = cast(typeof(glTexImage3D))load("glTexImage3D"); + glTexSubImage3D = cast(typeof(glTexSubImage3D))load("glTexSubImage3D"); + glCopyTexSubImage3D = cast(typeof(glCopyTexSubImage3D))load("glCopyTexSubImage3D"); + glCompressedTexImage3D = cast(typeof(glCompressedTexImage3D))load("glCompressedTexImage3D"); + glCompressedTexSubImage3D = cast(typeof(glCompressedTexSubImage3D))load("glCompressedTexSubImage3D"); + glGenQueries = cast(typeof(glGenQueries))load("glGenQueries"); + glDeleteQueries = cast(typeof(glDeleteQueries))load("glDeleteQueries"); + glIsQuery = cast(typeof(glIsQuery))load("glIsQuery"); + glBeginQuery = cast(typeof(glBeginQuery))load("glBeginQuery"); + glEndQuery = cast(typeof(glEndQuery))load("glEndQuery"); + glGetQueryiv = cast(typeof(glGetQueryiv))load("glGetQueryiv"); + glGetQueryObjectuiv = cast(typeof(glGetQueryObjectuiv))load("glGetQueryObjectuiv"); + glUnmapBuffer = cast(typeof(glUnmapBuffer))load("glUnmapBuffer"); + glGetBufferPointerv = cast(typeof(glGetBufferPointerv))load("glGetBufferPointerv"); + glDrawBuffers = cast(typeof(glDrawBuffers))load("glDrawBuffers"); + glUniformMatrix2x3fv = cast(typeof(glUniformMatrix2x3fv))load("glUniformMatrix2x3fv"); + glUniformMatrix3x2fv = cast(typeof(glUniformMatrix3x2fv))load("glUniformMatrix3x2fv"); + glUniformMatrix2x4fv = cast(typeof(glUniformMatrix2x4fv))load("glUniformMatrix2x4fv"); + glUniformMatrix4x2fv = cast(typeof(glUniformMatrix4x2fv))load("glUniformMatrix4x2fv"); + glUniformMatrix3x4fv = cast(typeof(glUniformMatrix3x4fv))load("glUniformMatrix3x4fv"); + glUniformMatrix4x3fv = cast(typeof(glUniformMatrix4x3fv))load("glUniformMatrix4x3fv"); + glBlitFramebuffer = cast(typeof(glBlitFramebuffer))load("glBlitFramebuffer"); + glRenderbufferStorageMultisample = cast(typeof(glRenderbufferStorageMultisample))load("glRenderbufferStorageMultisample"); + glFramebufferTextureLayer = cast(typeof(glFramebufferTextureLayer))load("glFramebufferTextureLayer"); + glMapBufferRange = cast(typeof(glMapBufferRange))load("glMapBufferRange"); + glFlushMappedBufferRange = cast(typeof(glFlushMappedBufferRange))load("glFlushMappedBufferRange"); + glBindVertexArray = cast(typeof(glBindVertexArray))load("glBindVertexArray"); + glDeleteVertexArrays = cast(typeof(glDeleteVertexArrays))load("glDeleteVertexArrays"); + glGenVertexArrays = cast(typeof(glGenVertexArrays))load("glGenVertexArrays"); + glIsVertexArray = cast(typeof(glIsVertexArray))load("glIsVertexArray"); + glGetIntegeri_v = cast(typeof(glGetIntegeri_v))load("glGetIntegeri_v"); + glBeginTransformFeedback = cast(typeof(glBeginTransformFeedback))load("glBeginTransformFeedback"); + glEndTransformFeedback = cast(typeof(glEndTransformFeedback))load("glEndTransformFeedback"); + glBindBufferRange = cast(typeof(glBindBufferRange))load("glBindBufferRange"); + glBindBufferBase = cast(typeof(glBindBufferBase))load("glBindBufferBase"); + glTransformFeedbackVaryings = cast(typeof(glTransformFeedbackVaryings))load("glTransformFeedbackVaryings"); + glGetTransformFeedbackVarying = cast(typeof(glGetTransformFeedbackVarying))load("glGetTransformFeedbackVarying"); + glVertexAttribIPointer = cast(typeof(glVertexAttribIPointer))load("glVertexAttribIPointer"); + glGetVertexAttribIiv = cast(typeof(glGetVertexAttribIiv))load("glGetVertexAttribIiv"); + glGetVertexAttribIuiv = cast(typeof(glGetVertexAttribIuiv))load("glGetVertexAttribIuiv"); + glVertexAttribI4i = cast(typeof(glVertexAttribI4i))load("glVertexAttribI4i"); + glVertexAttribI4ui = cast(typeof(glVertexAttribI4ui))load("glVertexAttribI4ui"); + glVertexAttribI4iv = cast(typeof(glVertexAttribI4iv))load("glVertexAttribI4iv"); + glVertexAttribI4uiv = cast(typeof(glVertexAttribI4uiv))load("glVertexAttribI4uiv"); + glGetUniformuiv = cast(typeof(glGetUniformuiv))load("glGetUniformuiv"); + glGetFragDataLocation = cast(typeof(glGetFragDataLocation))load("glGetFragDataLocation"); + glUniform1ui = cast(typeof(glUniform1ui))load("glUniform1ui"); + glUniform2ui = cast(typeof(glUniform2ui))load("glUniform2ui"); + glUniform3ui = cast(typeof(glUniform3ui))load("glUniform3ui"); + glUniform4ui = cast(typeof(glUniform4ui))load("glUniform4ui"); + glUniform1uiv = cast(typeof(glUniform1uiv))load("glUniform1uiv"); + glUniform2uiv = cast(typeof(glUniform2uiv))load("glUniform2uiv"); + glUniform3uiv = cast(typeof(glUniform3uiv))load("glUniform3uiv"); + glUniform4uiv = cast(typeof(glUniform4uiv))load("glUniform4uiv"); + glClearBufferiv = cast(typeof(glClearBufferiv))load("glClearBufferiv"); + glClearBufferuiv = cast(typeof(glClearBufferuiv))load("glClearBufferuiv"); + glClearBufferfv = cast(typeof(glClearBufferfv))load("glClearBufferfv"); + glClearBufferfi = cast(typeof(glClearBufferfi))load("glClearBufferfi"); + glGetStringi = cast(typeof(glGetStringi))load("glGetStringi"); + glCopyBufferSubData = cast(typeof(glCopyBufferSubData))load("glCopyBufferSubData"); + glGetUniformIndices = cast(typeof(glGetUniformIndices))load("glGetUniformIndices"); + glGetActiveUniformsiv = cast(typeof(glGetActiveUniformsiv))load("glGetActiveUniformsiv"); + glGetUniformBlockIndex = cast(typeof(glGetUniformBlockIndex))load("glGetUniformBlockIndex"); + glGetActiveUniformBlockiv = cast(typeof(glGetActiveUniformBlockiv))load("glGetActiveUniformBlockiv"); + glGetActiveUniformBlockName = cast(typeof(glGetActiveUniformBlockName))load("glGetActiveUniformBlockName"); + glUniformBlockBinding = cast(typeof(glUniformBlockBinding))load("glUniformBlockBinding"); + glDrawArraysInstanced = cast(typeof(glDrawArraysInstanced))load("glDrawArraysInstanced"); + glDrawElementsInstanced = cast(typeof(glDrawElementsInstanced))load("glDrawElementsInstanced"); + glFenceSync = cast(typeof(glFenceSync))load("glFenceSync"); + glIsSync = cast(typeof(glIsSync))load("glIsSync"); + glDeleteSync = cast(typeof(glDeleteSync))load("glDeleteSync"); + glClientWaitSync = cast(typeof(glClientWaitSync))load("glClientWaitSync"); + glWaitSync = cast(typeof(glWaitSync))load("glWaitSync"); + glGetInteger64v = cast(typeof(glGetInteger64v))load("glGetInteger64v"); + glGetSynciv = cast(typeof(glGetSynciv))load("glGetSynciv"); + glGetInteger64i_v = cast(typeof(glGetInteger64i_v))load("glGetInteger64i_v"); + glGetBufferParameteri64v = cast(typeof(glGetBufferParameteri64v))load("glGetBufferParameteri64v"); + glGenSamplers = cast(typeof(glGenSamplers))load("glGenSamplers"); + glDeleteSamplers = cast(typeof(glDeleteSamplers))load("glDeleteSamplers"); + glIsSampler = cast(typeof(glIsSampler))load("glIsSampler"); + glBindSampler = cast(typeof(glBindSampler))load("glBindSampler"); + glSamplerParameteri = cast(typeof(glSamplerParameteri))load("glSamplerParameteri"); + glSamplerParameteriv = cast(typeof(glSamplerParameteriv))load("glSamplerParameteriv"); + glSamplerParameterf = cast(typeof(glSamplerParameterf))load("glSamplerParameterf"); + glSamplerParameterfv = cast(typeof(glSamplerParameterfv))load("glSamplerParameterfv"); + glGetSamplerParameteriv = cast(typeof(glGetSamplerParameteriv))load("glGetSamplerParameteriv"); + glGetSamplerParameterfv = cast(typeof(glGetSamplerParameterfv))load("glGetSamplerParameterfv"); + glVertexAttribDivisor = cast(typeof(glVertexAttribDivisor))load("glVertexAttribDivisor"); + glBindTransformFeedback = cast(typeof(glBindTransformFeedback))load("glBindTransformFeedback"); + glDeleteTransformFeedbacks = cast(typeof(glDeleteTransformFeedbacks))load("glDeleteTransformFeedbacks"); + glGenTransformFeedbacks = cast(typeof(glGenTransformFeedbacks))load("glGenTransformFeedbacks"); + glIsTransformFeedback = cast(typeof(glIsTransformFeedback))load("glIsTransformFeedback"); + glPauseTransformFeedback = cast(typeof(glPauseTransformFeedback))load("glPauseTransformFeedback"); + glResumeTransformFeedback = cast(typeof(glResumeTransformFeedback))load("glResumeTransformFeedback"); + glGetProgramBinary = cast(typeof(glGetProgramBinary))load("glGetProgramBinary"); + glProgramBinary = cast(typeof(glProgramBinary))load("glProgramBinary"); + glProgramParameteri = cast(typeof(glProgramParameteri))load("glProgramParameteri"); + glInvalidateFramebuffer = cast(typeof(glInvalidateFramebuffer))load("glInvalidateFramebuffer"); + glInvalidateSubFramebuffer = cast(typeof(glInvalidateSubFramebuffer))load("glInvalidateSubFramebuffer"); + glTexStorage2D = cast(typeof(glTexStorage2D))load("glTexStorage2D"); + glTexStorage3D = cast(typeof(glTexStorage3D))load("glTexStorage3D"); + glGetInternalformativ = cast(typeof(glGetInternalformativ))load("glGetInternalformativ"); + return; +} + + +} /* private */ + diff --git a/demos/external/sources/glad/gl/types.d b/demos/external/sources/glad/gl/types.d new file mode 100644 index 0000000..043a2a1 --- /dev/null +++ b/demos/external/sources/glad/gl/types.d @@ -0,0 +1,46 @@ +module glad.gl.types; + + +alias GLvoid = void; +alias GLintptr = ptrdiff_t; +alias GLsizei = int; +alias GLchar = char; +alias GLcharARB = byte; +alias GLushort = ushort; +alias GLint64EXT = long; +alias GLshort = short; +alias GLuint64 = ulong; +alias GLhalfARB = ushort; +alias GLubyte = ubyte; +alias GLdouble = double; +alias GLhandleARB = uint; +alias GLint64 = long; +alias GLenum = uint; +alias GLeglImageOES = void*; +alias GLintptrARB = ptrdiff_t; +alias GLsizeiptr = ptrdiff_t; +alias GLint = int; +alias GLboolean = ubyte; +alias GLbitfield = uint; +alias GLsizeiptrARB = ptrdiff_t; +alias GLfloat = float; +alias GLuint64EXT = ulong; +alias GLclampf = float; +alias GLbyte = byte; +alias GLclampd = double; +alias GLuint = uint; +alias GLvdpauSurfaceNV = ptrdiff_t; +alias GLfixed = int; +alias GLhalf = ushort; +alias GLclampx = int; +alias GLhalfNV = ushort; +struct ___GLsync; alias __GLsync = ___GLsync*; +alias GLsync = __GLsync*; +struct __cl_context; alias _cl_context = __cl_context*; +struct __cl_event; alias _cl_event = __cl_event*; +extern(System) { +alias GLDEBUGPROC = void function(GLenum, GLenum, GLuint, GLenum, GLsizei, in GLchar*, GLvoid*); +alias GLDEBUGPROCARB = GLDEBUGPROC; +alias GLDEBUGPROCKHR = GLDEBUGPROC; +alias GLDEBUGPROCAMD = void function(GLuint, GLenum, GLenum, GLsizei, in GLchar*, GLvoid*); +} diff --git a/demos/external/sources/mmutils/thread_pool.d b/demos/external/sources/mmutils/thread_pool.d new file mode 100644 index 0000000..a986048 --- /dev/null +++ b/demos/external/sources/mmutils/thread_pool.d @@ -0,0 +1,1694 @@ +module mmutils.thread_pool; + +import core.atomic; +//import core.stdc.stdio; +//import core.stdc.stdlib : free, malloc, realloc; +//import core.stdc.string : memcpy; + + + +//import std.stdio; +import std.algorithm : map; + +version = MM_NO_LOGS; // Disable log creation +//version = MM_USE_POSIX_THREADS; // Use posix threads insted of standard library, required for betterC + +version (WebAssembly) +{ + extern(C) struct FILE + { + + } +} +else +{ + import core.stdc.stdio; +} + +////////////////////////////////////////////// +/////////////// BetterC Support ////////////// +////////////////////////////////////////////// + +version (D_BetterC) +{ + import ecs.std; + extern (C) __gshared int _d_eh_personality(int, int, size_t, void*, void*) + { + return 0; + } + + extern (C) __gshared void _d_eh_resume_unwind(void*) + { + return; + } + + extern (C) void* _d_allocmemory(size_t sz) + { + return malloc(sz); + } +} +else +{ + import core.stdc.stdlib; + import core.stdc.string; +} + +////////////////////////////////////////////// +//////////////////// Alloc /////////////////// +////////////////////////////////////////////// +T* makeVar(T)(T init) +{ + T* el = cast(T*) malloc(T.sizeof); + memcpy(el, &init, T.sizeof); + return el; +} + +T* makeVar(T)() +{ + T init; + T* el = cast(T*) malloc(T.sizeof); + memcpy(el, &init, T.sizeof); + return el; +} + +T[] makeVarArray(T)(int num, T init = T.init) +{ + T* ptr = cast(T*) malloc(num * (T.sizeof + T.sizeof % T.alignof)); + T[] arr = ptr[0 .. num]; + foreach (ref el; arr) + { + memcpy(&el, &init, T.sizeof); + } + return arr; +} + +void disposeVar(T)(T* var) +{ + free(var); +} + +void disposeArray(T)(T[] var) +{ + free(var.ptr); +} +////////////////////////////////////////////// +//////////////////// Timer /////////////////// +////////////////////////////////////////////// + +version (WebAssembly) +{ + alias int time_t; + alias int clockid_t; + enum CLOCK_REALTIME = 0; + + struct timespec + { + time_t tv_sec; + int tv_nsec; + } + + extern(C) int clock_gettime(clockid_t, timespec*) @nogc nothrow @system; +} + +/// High precison timer +long useconds() +{ + version (WebAssembly) + { + //import core.sys.posix.sys.time : gettimeofday, timeval; + + /*timeval t; + gettimeofday(&t, null); + + return t.tv_sec * 1_000_000 + t.tv_usec;*/ + + time_t time; + timespec spec; + + clock_gettime(CLOCK_REALTIME, &spec); + + //time = spec.tv_sec; + return spec.tv_sec * 1000_000 + spec.tv_nsec / 1000; + } + else version (Posix) + { + import core.sys.posix.sys.time : gettimeofday, timeval; + + timeval t; + gettimeofday(&t, null); + return t.tv_sec * 1_000_000 + t.tv_usec; + } + else version (Windows) + { + /*import core.sys.windows.windows : QueryPerformanceFrequency; + + __gshared double mul = -1; + if (mul < 0) + { + long frequency; + int ok = QueryPerformanceFrequency(&frequency); + assert(ok); + mul = 1_000_000.0 / frequency; + } + long ticks; + int ok = QueryPerformanceCounter(&ticks); + assert(ok); + return cast(long)(ticks * mul);*/ + return 0; + } + else + { + static assert("OS not supported."); + } +} + +////////////////////////////////////////////// +//////////////////// Pause /////////////////// +////////////////////////////////////////////// + +void instructionPause() +{ + version (X86_64) + { + version (LDC) + { + import ldc.gccbuiltins_x86 : __builtin_ia32_pause; + + __builtin_ia32_pause(); + } + else version (DigitalMars) + { + asm + { + rep; + nop; + } + + } + else + { + static assert(0); + } + } +} + +////////////////////////////////////////////// +///////////// Semaphore + Thread ///////////// +////////////////////////////////////////////// + +version (MM_USE_POSIX_THREADS) +{ + version (Posix) + { + import core.sys.posix.pthread; + import core.sys.posix.semaphore; + } + else version (WebAssembly) + { + extern(C): + //alias uint time_t; + struct pthread_attr_t + { + + } + + struct pthread_t + { + void* p; + uint x; + } + + /*struct timespec + { + time_t tv_sec; + int tv_nsec; + }*/ + + // pthread + int pthread_create(pthread_t*, in pthread_attr_t*, void* function(void*), void*); + int pthread_join(pthread_t, void**); + void pthread_exit(void *retval); + + // semaphore.h + alias sem_t = void*; + int sem_init(sem_t*, int, uint); + int sem_wait(sem_t*); + int sem_trywait(sem_t*); + int sem_post(sem_t*); + int sem_destroy(sem_t*); + int sem_timedwait(sem_t* sem, const timespec* abstime); + //import core.sys.posix.pthread; + //import core.sys.posix.semaphore; + } + else version (Windows) + { + extern (C): + alias uint time_t; + struct pthread_attr_t + { + + } + + struct pthread_t + { + void* p; + uint x; + } + + struct timespec + { + time_t tv_sec; + int tv_nsec; + } + + // pthread + int pthread_create(pthread_t*, in pthread_attr_t*, void* function(void*), void*); + int pthread_join(pthread_t, void**); + void pthread_exit(void *retval); + + // semaphore.h + alias sem_t = void*; + int sem_init(sem_t*, int, uint); + int sem_wait(sem_t*); + int sem_trywait(sem_t*); + int sem_post(sem_t*); + int sem_destroy(sem_t*); + int sem_timedwait(sem_t* sem, const timespec* abstime); + } + else + { + static assert(false); + } + + struct Semaphore + { + sem_t mutex; + + void initialize() + { + sem_init(&mutex, 0, 0); + } + + void wait() + { + int ret = sem_wait(&mutex); + assert(ret == 0); + } + + bool tryWait() + { + //return true; + int ret = sem_trywait(&mutex); + return (ret == 0); + } + + bool timedWait(int usecs) + { + timespec tv; + // if there is no such a function look at it: https://stackoverflow.com/questions/5404277/porting-clock-gettime-to-windows + clock_gettime(CLOCK_REALTIME, &tv); + tv.tv_sec += usecs / 1_000_000; + tv.tv_nsec += (usecs % 1_000_000) * 1_000; + + int ret = sem_timedwait(&mutex, &tv); + return (ret == 0); + } + + void post() + { + int ret = sem_post(&mutex); + assert(ret == 0); + } + + void destroy() + { + sem_destroy(&mutex); + } + } + + private extern (C) void* threadRunFunc(void* threadVoid) + { + Thread* th = cast(Thread*) threadVoid; + + th.threadStart(); + + pthread_exit(null); + return null; + } + + struct Thread + { + alias DG = void delegate(); + + DG threadStart; + pthread_t handle; + + void start(DG dg) + { + threadStart = dg; + int ok = pthread_create(&handle, null, &threadRunFunc, cast(void*)&this); + assert(ok == 0); + } + + void join() + { + pthread_join(handle, null); + handle = handle.init; + threadStart = null; + } + } +} +else version(D_BetterC) +{ + version(Posix) + { + struct Semaphore + { + sem_t mutex; + + void initialize() + { + sem_init(&mutex, 0, 0); + } + + void wait() + { + int ret = sem_wait(&mutex); + assert(ret == 0); + } + + bool tryWait() + { + //return true; + int ret = sem_trywait(&mutex); + return (ret == 0); + } + + bool timedWait(int usecs) + { + timespec tv; + // if there is no such a function look at it: https://stackoverflow.com/questions/5404277/porting-clock-gettime-to-windows + clock_gettime(CLOCK_REALTIME, &tv); + tv.tv_sec += usecs / 1_000_000; + tv.tv_nsec += (usecs % 1_000_000) * 1_000; + + int ret = sem_timedwait(&mutex, &tv); + return (ret == 0); + } + + void post() + { + int ret = sem_post(&mutex); + assert(ret == 0); + } + + void destroy() + { + sem_destroy(&mutex); + } + } + + private extern (C) void* threadRunFunc(void* threadVoid) + { + Thread* th = cast(Thread*) threadVoid; + + th.threadStart(); + + pthread_exit(null); + return null; + } + + struct Thread + { + alias DG = void delegate(); + + DG threadStart; + pthread_t handle; + + void start(DG dg) + { + threadStart = dg; + int ok = pthread_create(&handle, null, &threadRunFunc, cast(void*)&this); + assert(ok == 0); + } + + void join() + { + pthread_join(handle, null); + handle = handle.init; + threadStart = null; + } + } + } + else version(Windows) + { + import core.stdc.stdint : uintptr_t; + import core.sys.windows.windows; + extern (Windows) alias btex_fptr = uint function(void*); + extern (C) uintptr_t _beginthreadex(void*, uint, btex_fptr, void*, uint, uint*) nothrow @nogc; + + struct Semaphore + { + HANDLE handle; + + void initialize() + { + handle = CreateSemaphoreA( null, 0, int.max, null ); + assert ( handle != handle.init ); + //throw new SyncError( "Unable to create semaphore" ); + } + + void wait() + { + DWORD rc = WaitForSingleObject( handle, INFINITE ); + //int ret = sem_wait(&mutex); + assert(rc == WAIT_OBJECT_0); + } + + bool tryWait() + { + switch ( WaitForSingleObject( handle, 0 ) ) + { + case WAIT_OBJECT_0: + return true; + case WAIT_TIMEOUT: + return false; + default: + assert(0);//throw new SyncError( "Unable to wait for semaphore" ); + } + } + + bool timedWait(int usecs) + { + /*timespec tv; + // if there is no such a function look at it: https://stackoverflow.com/questions/5404277/porting-clock-gettime-to-windows + clock_gettime(CLOCK_REALTIME, &tv); + tv.tv_sec += usecs / 1_000_000; + tv.tv_nsec += (usecs % 1_000_000) * 1_000; + + int ret = sem_timedwait(&mutex, &tv); + return (ret == 0);*/ + + switch ( WaitForSingleObject( handle, cast(uint) usecs / 1000 ) ) + { + case WAIT_OBJECT_0: + return true; + case WAIT_TIMEOUT: + return false; + default: + assert(0);//throw new SyncError( "Unable to wait for semaphore" ); + } + } + + void post() + { + assert(ReleaseSemaphore( handle, 1, null )); + //if ( !ReleaseSemaphore( m_hndl, 1, null ) ) + //throw new SyncError( "Unable to notify semaphore" ); + } + + void destroy() + { + BOOL rc = CloseHandle( handle ); + assert( rc, "Unable to destroy semaphore" ); + } + } + + private extern (Windows) uint threadRunFunc(void* threadVoid) + { + Thread* th = cast(Thread*) threadVoid; + + th.threadStart(); + + //(null); + ExitThread(0); + return 0; + } + + struct Thread + { + alias DG = void delegate(); + + DG threadStart; + HANDLE handle; + + void start(DG dg) + { + threadStart = dg; + handle = cast(HANDLE) _beginthreadex( null, 0, &threadRunFunc, cast(void*)&this, 0, null ); + //int ok = pthread_create(&handle, null, &threadRunFunc, cast(void*)&this); + assert(handle == null); + } + + void join() + { + if ( WaitForSingleObject( handle, INFINITE ) == WAIT_OBJECT_0 )assert(0); + CloseHandle( handle ); + //pthread_join(handle, null); + handle = handle.init; + threadStart = null; + } + } + } + +} +else +{ + import core.thread : D_Thread = Thread; + import core.sync.semaphore : D_Semaphore = Semaphore; + import core.time : dur; + import std.experimental.allocator; + import std.experimental.allocator.mallocator; + + struct Semaphore + { + D_Semaphore sem; + + void initialize() + { + sem = Mallocator.instance.make!D_Semaphore(); + } + + void wait() + { + sem.wait(); + } + + bool tryWait() + { + return sem.tryWait(); + } + + bool timedWait(int usecs) + { + return sem.wait(dur!"usecs"(usecs)); + } + + void post() + { + sem.notify(); + } + + void destroy() + { + Mallocator.instance.dispose(sem); + } + } + + struct Thread + { + alias DG = void delegate(); + + DG threadStart; + D_Thread thread; + + void start(DG dg) + { + thread = Mallocator.instance.make!D_Thread(dg); + thread.start(); + } + + void join() + { + thread.join(); + } + } +} + +////////////////////////////////////////////// +///////////////// ThreadPool ///////////////// +////////////////////////////////////////////// + +private enum gMaxThreadsNum = 128; + +alias JobDelegate = void delegate(ThreadData*, JobData*); + +// Structure to store job start and end time +struct JobLog +{ + string name; /// Name of job + ulong time; /// Time started (us) + ulong duration; /// Took time (us) +} + +/// First in first out queue with atomic lock +struct JobQueue +{ + alias LockType = long; + align(64) shared LockType lock; /// Lock for accesing list of Jobs + align(64) JobData* first; /// Fist element in list of Jobs + + /// Check if empty without locking, doesn't give guarantee that list is truly empty + bool emptyRaw() + { + bool isEmpty = first == null; + return isEmpty; + } + + /// Check if empty + bool empty() + { + while (!cas(&lock, cast(LockType) false, cast(LockType) true)) + instructionPause(); + + bool isEmpty = first == null; + atomicStore!(MemoryOrder.rel)(lock, cast(LockType) false); + return isEmpty; + } + + /// Add job to queue + void add(JobData* t) + { + while (!cas(&lock, cast(LockType) false, cast(LockType) true)) + instructionPause(); + + t.next = first; + first = t; + + atomicStore!(MemoryOrder.rel)(lock, cast(LockType) false); + } + + /// Add range of jobs to queue + void addRange(Range)(Range arr) + { + if (arr.length == 0) + return; + + JobData* start = arr[0]; + JobData* last = start; + + foreach (t; arr[1 .. $]) + { + last.next = t; + last = t; + } + + while (!cas(&lock, cast(LockType) false, cast(LockType) true)) + instructionPause(); + last.next = first; + first = start; + atomicStore!(MemoryOrder.rel)(lock, cast(LockType) false); + } + + /// Pop job from queue + JobData* pop() + { + while (!cas(&lock, cast(LockType) false, cast(LockType) true)) + instructionPause(); + + if (first == null) + { + atomicStore!(MemoryOrder.rel)(lock, cast(LockType) false); + return null; + } + + JobData* result = first; + first = first.next; + + atomicStore!(MemoryOrder.rel)(lock, cast(LockType) false); + return result; + } + +} + +/// Structure containing job data +/// JobData memory is allocated by user +/// JobData lifetime is managed by user +/// JobData has to live as long as it's group or end of job execution +/// JobData fields can be changed in del delegate and job can be added to thread pool again, to continue execution (call same function again or another if del was changed) +struct JobData +{ + JobDelegate del; /// Delegate to execute + string name; /// Name of job + private JobsGroup* group; /// Group to which this job belongs + private align(64) JobData* next; /// JobData makes a list of jobs to be done by thread +} + +/// Structure responsible for thread in thread pool +/// Stores jobs to be executed by this thread (jobs can be stolen by another thread) +/// Stores cache for logs +struct ThreadData +{ +public: + ThreadPool* threadPool; /// Pool this thread belongs to + int threadId; /// Thread id. Valid only for this thread pool + + /// Function starting execution of thread main loop + /// External threads can call this function to start executing jobs + void threadStartFunc() + { + //end = false; + threadFunc(&this); + } + +private: + JobQueue jobsQueue; /// Queue of jobs to be done, jobs can be stolen from another thread + JobQueue jobsExclusiveQueue; /// Queue of jobs to be done, jobs can't be stolen + align(64) Semaphore semaphore; /// Semaphore to wake/sleep this thread + align(64) Thread thread; /// Systemn thread handle + JobLog[] logs; /// Logs cache + int lastLogIndex = -1; /// Last created log index + int jobsDoneCount; + + shared bool end; /// Check if thread has to exit. Thread will exit only if end is true and jobsToDo is empty + shared bool acceptJobs; /// Check if thread should accept new jobs, If false thread won't steal jobs from other threads and will sleep longer if queue js empty + bool externalThread; /// Thread not allocated by thread pool + +} + +/// Thread Pool +/// Manages bounch of threads to execute given jobs as quickly as possible +/// There are no priorities beetween jobs. Jobs added to queues in same order as they are in slices, but due to job stealing and uneven speed of execution beetween threads jobs execution order is unspecified. +/// Number of threads executing jobs can be dynamically changed in any time. Threads removed from execution will work until the end of the program but shouldn't accept new jobs. +struct ThreadPool +{ + alias FlushLogsDelegaste = void delegate(ThreadData* threadData, JobLog[] logs); /// Type of delegate to flush logs + FlushLogsDelegaste onFlushLogs; /// User custom delegate to flush logs, if overriden defaultFlushLogs will be used. Can be sset after initialize() call + int logsCacheNum; /// Number of log cache entries. Should be set before setThreadsNum is called +private: + ThreadData*[gMaxThreadsNum] threadsData; /// Data for threads + align(64) shared int threadsNum; /// Number of threads currentlu accepting jobs + align(64) shared bool threadsDataLock; /// Any modification of threadsData array (change in size or pointer modification) had to be locked + align(64) shared int threadSelector; /// Index of thread to which add next job + FILE* logFile; /// File handle for defaultFlushLogs log file + JobData[4] resumeJobs; /// Dummu jobs to resume some thread + +public: + int jobsDoneCount() + { + int sum; + foreach (i, ref ThreadData* th; threadsData) + { + if (th is null) + continue; + + sum += th.jobsDoneCount; + } + return sum; + } + + void jobsDoneCountReset() + { + foreach (i, ref ThreadData* th; threadsData) + { + if (th is null) + continue; + th.jobsDoneCount = 0; + } + } + /// Initialize thread pool + void initialize() + { + + foreach (ref JobData j; resumeJobs) + j = JobData(&dummyJob, "Dummy-Resume"); + + version (MM_NO_LOGS) + { + logsCacheNum = 0; + } + else + { + onFlushLogs = &defaultFlushLogs; + logsCacheNum = 1024; + + logFile = fopen("trace.json", "w"); + fprintf(logFile, "["); + fclose(logFile); + logFile = fopen("trace.json", "a"); + assert(logFile !is null); + } + } + + /// Clean ups ThreadPool + ~this() + { + version (MM_NO_LOGS) + { + + } + else if (logFile) + { + fclose(logFile); + logFile = null; + } + + + } + + /// Registers external thread to thread pool array. There will be allocated data for this thread and it will have specified id + /// External threads are not joined at the end of thread pool execution + /// Returns ThreadData corresponding to external thread. To acually start executing, external thread had to call threadStartFunc() from returned variable + ThreadData* registerExternalThread() + { + lockThreadsData(); + //scope (exit) + + + ThreadData* threadData = makeThreadData(); + threadData.threadPool = &this; + threadData.semaphore.initialize(); + threadData.externalThread = true; + threadData.acceptJobs = true; + + int threadNum = atomicOp!"+="(threadsNum, 1) - 1; + + threadData.threadId = threadNum; + + threadsData[threadNum] = threadData; + + unlockThreadsData(); + + return threadData; + } + + /// Unregisters external thread. Can be called only when external thread have left the thread pool + void unregistExternalThread(ThreadData* threadData) + { + lockThreadsData(); + scope (exit) + unlockThreadsData(); + + disposeThreadData(threadData); + } + + /// Allows external threads to return from threadStartFunc + void releaseExternalThreads() + { + lockThreadsData(); + scope (exit) + unlockThreadsData(); + + // Release external threads (including main thread) + foreach (i, ref ThreadData* th; threadsData) + { + if (th is null) + continue; + if (!th.externalThread) + continue; + + auto rng = resumeJobs[].map!((ref a) => &a); + addJobsRange(rng, cast(int) i); + atomicStore(th.end, true); + } + } + + /// Waits for all threads to finish and joins them (excluding external threads) + void waitThreads() + { + lockThreadsData(); + scope (exit) + unlockThreadsData(); + foreach (i, ref ThreadData* th; threadsData) + { + if (th is null) + continue; + + atomicStore(th.acceptJobs, false); + atomicStore(th.end, true); + } + foreach (i, ref ThreadData* th; threadsData) + { + if (th is null || th.externalThread) + continue; + + th.thread.join(); + disposeThreadData(th); + } + } + + /// Sets number of threads to accept new jobs + /// If there were never so much threads created, they will be created + /// If number of threads set is smaller than there was threads before, they are not joined but they stop getting new jobs, they stop stealing jobs and they sleep longer + /// Locking operation + void setThreadsNum(int num) + { + assert(num <= gMaxThreadsNum); + assert(num > 0); + + lockThreadsData(); + scope (exit) + unlockThreadsData(); + + foreach (i, ref ThreadData* th; threadsData) + { + if (th) + { + // Exists but has to be disabled + atomicStore(th.acceptJobs, i < num); + continue; + } + else if (i >= num) + { + // Doesn't exist and is not required + continue; + } + // Doesn't exist and is required + th = makeThreadData(); + th.threadPool = &this; + th.threadId = cast(int) i; + th.acceptJobs = true; + th.semaphore.initialize(); + + th.thread.start(&th.threadStartFunc); + } + + atomicStore(threadsNum, num); + + } + + /// Adds job to be executed by thread pool, such a job won't be synchronized with any group or job + /// If threadNum is different than -1 only thread with threadNum will be able to execute given job + /// It is advised to use synchronized group of jobs + void addJobAsynchronous(JobData* data, int threadNum = -1) + { + if (threadNum == -1) + { + ThreadData* threadData = getThreadDataToAddJobTo(); + threadData.jobsQueue.add(data); + threadData.semaphore.post(); + return; + } + ThreadData* threadData = threadsData[threadNum]; + assert(threadData !is null); + threadData.jobsExclusiveQueue.add(data); + threadData.semaphore.post(); + } + + /// Adds job to be executed by thread pool, group specified in group data won't be finished until this job ends + /// If threadNum is different than -1 only thread with threadNum will be able to execute given job + void addJob(JobData* data, int threadNum = -1) + { + assert(data.group); + atomicOp!"+="(data.group.jobsToBeDoneCount, 1); + addJobAsynchronous(data, threadNum); + } + + /// Adds multiple jobs at once + /// Range has to return JobData* + /// Range has to have length property + /// Range is used so there is no need to allocate JobData*[] + /// All jobs has to belong to one group + /// If threadNum is different than -1 only thread with threadNum will be able to execute given jobs + void addJobsRange(Range)(Range rng, int threadNum = -1) + { + if (threadNum != -1) + { + ThreadData* threadData = threadsData[threadNum]; + assert(threadData !is null); + threadData.jobsExclusiveQueue.addRange(rng); + foreach (sInc; 0 .. rng.length) + threadData.semaphore.post(); + + return; + } + + if (rng.length == 0) + { + return; + } + + foreach (JobData* threadData; rng) + { + assert(rng[0].group == threadData.group); + } + atomicOp!"+="(rng[0].group.jobsToBeDoneCount, cast(int) rng.length); + int threadsNumLocal = threadsNum; + int part = cast(int) rng.length / threadsNumLocal; + if (part > 0) + { + foreach (i, ThreadData* threadData; threadsData[0 .. threadsNumLocal]) + { + auto slice = rng[i * part .. (i + 1) * part]; + threadData.jobsQueue.addRange(slice); + + foreach (sInc; 0 .. part) + threadData.semaphore.post(); + + } + rng = rng[part * threadsNumLocal .. $]; + } + foreach (i, ThreadData* threadData; threadsData[0 .. rng.length]) + { + threadData.jobsQueue.add(rng[i]); + threadData.semaphore.post(); + } + + } + + /// Adds group of jobs to threadPool, group won't be synchronized + void addGroupAsynchronous(JobsGroup* group) + { + group.thPool = &this; + if (group.jobs.length == 0) + { + // Immediately call group end + group.onGroupFinish(); + return; + } + + group.setUpJobs(); + auto rng = group.jobs[].map!((ref a) => &a); + addJobsRange(rng, group.executeOnThreadNum); + } + + /// Adds group of jobs to threadPool + /// Spwaning group will finish after this group have finished + void addGroup(JobsGroup* group, JobsGroup* spawnedByGroup) + { + assert(spawnedByGroup); + group.spawnedByGroup = spawnedByGroup; + atomicOp!"+="(spawnedByGroup.jobsToBeDoneCount, 1); // Increase by one, so 'spawning group' will wait for 'newly added group' to finish + addGroupAsynchronous(group); // Synchronized by jobsToBeDoneCount atomic variable + } + + /// Explicitly calls onFlushLogs on all threads + void flushAllLogs() + { + lockThreadsData(); + scope (exit) + unlockThreadsData(); + foreach (thNum; 0 .. atomicLoad(threadsNum)) + { + ThreadData* th = threadsData[thNum]; + onThreadFlushLogs(th); + } + + foreach (i, ref ThreadData* th; threadsData) + { + if (th is null) + continue; + + onThreadFlushLogs(th); + } + } + + /// Default implementation of flushing logs + /// Saves logs to trace.json file in format acceptable by Google Chrome tracking tool chrome://tracing/ + /// Logs can be watched even if apllication crashed, but might require removing last log entry from trace.json + void defaultFlushLogs(ThreadData* threadData, JobLog[] logs) + { + version (MM_NO_LOGS) + { + } + else + { + // (log rows num) * (static json length * time length * duration length) + long start = useconds(); + size_t size = (logs.length + 1) * (128 + 20 + 20); + size_t used = 0; + + foreach (ref log; logs) + { + size += log.name.length; // size of name + } + + char* buffer = cast(char*) malloc(size); + + foreach (ref log; logs) + { + + size_t charWritten = snprintf(buffer + used, size - used, + `{"name":"%s", "pid":1, "tid":%lld, "ph":"X", "ts":%lld, "dur":%lld }, %s`, + log.name.ptr, threadData.threadId + 1, log.time, log.duration, "\n".ptr); + used += charWritten; + } + + long end = useconds(); + size_t charWritten = snprintf(buffer + used, size - used, + `{"name":"logFlush", "pid":1, "tid":%lld, "ph":"X", "ts":%lld, "dur":%lld }, %s`, + threadData.threadId + 1, start, end - start, "\n".ptr); + used += charWritten; + fwrite(buffer, 1, used, logFile); + } + } + +private: + /// Atomic lock + void lockThreadsData() + { + // Only one thread at a time can change threads number in a threadpool + while (!cas(&threadsDataLock, false, true)) + { + } + } + + /// Atomic unlock + void unlockThreadsData() + { + atomicStore(threadsDataLock, false); + } + + /// Allocate ThreadData + ThreadData* makeThreadData() + { + ThreadData* threadData = makeVar!ThreadData(); + threadData.logs = makeVarArray!(JobLog)(logsCacheNum); + return threadData; + } + + /// Dispose ThreadData + void disposeThreadData(ThreadData* threadData) + { + disposeArray(threadData.logs); + return disposeVar(threadData); + } + + /// Get thread most suiting to add job to + ThreadData* getThreadDataToAddJobTo() + { + int threadNum = atomicOp!"+="(threadSelector, 1); + + foreach (i; 0 .. 1_000) + { + if (threadNum >= threadsNum) + { + threadNum = 0; + atomicStore(threadSelector, 0); + } + ThreadData* threadData = threadsData[threadNum]; + if (threadData != null) + { + return threadData; + } + threadNum++; + } + assert(0); + } + + /// Create log on start of job + void onStartJob(JobData* data, ThreadData* threadData) + { + + threadData.jobsDoneCount++; + version (MM_NO_LOGS) + { + } + else + { + if (cast(int) threadData.logs.length <= 0) + { + return; + } + if (threadData.lastLogIndex >= cast(int) threadData.logs.length - 1) + { + onThreadFlushLogs(threadData); + } + + threadData.lastLogIndex++; + + JobLog log; + log.name = data.name; + log.time = useconds(); + threadData.logs[threadData.lastLogIndex] = log; + } + } + + /// Set log finish time on end of job + void onEndJob(JobData* data, ThreadData* threadData) + { + version (MM_NO_LOGS) + { + } + else + { + if (cast(int) threadData.logs.length <= 0) + { + return; + } + assert(threadData.lastLogIndex < threadData.logs.length); + JobLog* log = &threadData.logs[threadData.lastLogIndex]; + log.duration = useconds() - log.time; + } + } + + /// Flush logs + void onThreadFlushLogs(ThreadData* threadData) + { + /*scope (exit) + { + threadData.lastLogIndex = -1; + }*/ + + assert(threadData); + + if (threadData.lastLogIndex < 0 || onFlushLogs is null) + { + return; + } + + onFlushLogs(threadData, threadData.logs[0 .. threadData.lastLogIndex + 1]); + + threadData.lastLogIndex = -1; + } + + /// Does nothing + void dummyJob(ThreadData* threadData, JobData* data) + { + + } + + /// Steal job from another thread + JobData* stealJob(int threadNum) + { + foreach (thSteal; 0 .. atomicLoad(threadsNum)) + { + if (thSteal == threadNum) + continue; // Do not steal from requesting thread + + ThreadData* threadData = threadsData[thSteal]; + + if (threadData is null || !threadData.semaphore.tryWait()) + continue; + + JobData* data = threadData.jobsQueue.pop(); + + if (data is null) + threadData.semaphore.post(); + + return data; + } + return null; + } +} + +/// Adding groups of jobs is faster and groups can have dependencies between each other +struct JobsGroup +{ +public: + string name; /// Name of group + JobData[] jobs; /// Jobs to be executed by this group, jobs have to live as long as group lives + void delegate(JobsGroup* group) onFinish; // Delegate called when group will finish, can be used to free memory + ThreadPool* thPool; /// Thread pool of this group + int executeOnThreadNum = -1; /// Thread num to execute jobs on + + this(string name, JobData[] jobs = [], int executeOnThreadNum = -1) + { + this.name = name; + this.jobs = jobs; + this.executeOnThreadNum = executeOnThreadNum; + jobsToBeDoneCount = 0; + } + + ~this() nothrow + { + free(children.ptr); + children = null; + } + + /// Make this group dependant from another group + /// Dependant group won't start untill its dependencies will be fulfilled + void dependantOn(JobsGroup* parent) + { + size_t newLen = parent.children.length + 1; + JobsGroup** ptr = cast(JobsGroup**) realloc(parent.children.ptr, + newLen * (JobsGroup*).sizeof); + parent.children = ptr[0 .. newLen]; + parent.children[$ - 1] = &this; + // parent.children ~= &this; + atomicOp!"+="(dependenciesWaitCount, 1); + } + + /// Returns number of dependencies this group is waiting for + int getDependenciesWaitCount() + { + return atomicLoad(dependenciesWaitCount); + } + +private: + JobsGroup* spawnedByGroup; /// Group which spawned this group, if present spwaning group is waiting for this group to finish + JobsGroup*[] children; /// Groups depending on this group + align(64) shared int dependenciesWaitCount; /// Count of dependencies this group waits for + align(64) shared int jobsToBeDoneCount; /// Number of this group jobs still executing + + /// Checks if depending groups or spawning group have to be started + /// Executes user onFinish function + void onGroupFinish() + { + + decrementChildrendependencies(); + if (spawnedByGroup) + { + auto num = atomicOp!"-="(spawnedByGroup.jobsToBeDoneCount, 1); + if (num == 0) + { + spawnedByGroup.onGroupFinish(); + } + } + if (onFinish) + onFinish(&this); + } + + /// Check if decrement dependencies counter and start them if theirs dependencies are fulfilled + void decrementChildrendependencies() + { + foreach (JobsGroup* group; children) + { + auto num = atomicOp!"-="(group.dependenciesWaitCount, 1); + assert(num >= 0); + if (num == 0) + { + thPool.addGroupAsynchronous(group); // All dependencies of this group are fulfilled, so is already synchronized + } + } + } + /// Prepare jobs data for adding to thread pool + void setUpJobs() + { + foreach (i; 0 .. jobs.length) + { + jobs[i].group = &this; + } + } + +} + +/// Main function executed by thread present in thread pool +/// Executes functions from its own queue +/// If there are no jobs in its queue, steals from another thread +/// If there is nothing to steal, sleeps on its semaphore for a while (stage when cpu is not used) +/// Sleep time is longer for jobs not accepting jobs, they don't exit because it is hard to guarantee that nobody is adding to them some job (thread might exit but job will be added anyway and application will malfunctio +/// Thread end only when it's queue is empty. Jobs shouldn't be added to queue after ThreadPool.waitThreads() call +private void threadFunc(ThreadData* threadData) +{ + ThreadPool* threadPool = threadData.threadPool; + int threadNum = threadData.threadId; + + while (!atomicLoad!(MemoryOrder.raw)(threadData.end) + || !threadData.jobsQueue.empty() || !threadData.jobsExclusiveQueue.empty()) + { + JobData* data; + if (threadData.semaphore.tryWait()) + { + if (!threadData.jobsExclusiveQueue.emptyRaw()) + data = threadData.jobsExclusiveQueue.pop(); + + if (data is null) + data = threadData.jobsQueue.pop(); + + if (data is null) + threadData.semaphore.post(); + + assert(data !is null); + } + else + { + bool acceptJobs = atomicLoad!(MemoryOrder.raw)(threadData.acceptJobs); + if (acceptJobs) + { + data = threadPool.stealJob(threadNum); + } + + if (data is null) + { + // Thread does not have own job and can not steal it, so wait for a job + bool ok = threadData.semaphore.timedWait(1_000 + !acceptJobs * 10_000); + if (ok) + { + + if (!threadData.jobsExclusiveQueue.emptyRaw()) + data = threadData.jobsExclusiveQueue.pop(); + + if (data is null) + data = threadData.jobsQueue.pop(); + + if (data is null) + threadData.semaphore.post(); + } + } + } + + // Nothing to do + if (data is null) + { + continue; + } + + // Do the job + threadPool.onStartJob(data, threadData); + data.del(threadData, data); + threadPool.onEndJob(data, threadData); + if (data.group) + { + auto num = atomicOp!"-="(data.group.jobsToBeDoneCount, 1); + if (num == 0) + { + data.group.onGroupFinish(); + } + } + + } + threadData.end = false; + assert(threadData.jobsQueue.empty()); +} + +////////////////////////////////////////////// +//////////////////// Test //////////////////// +////////////////////////////////////////////// +/* +void testThreadPool() +{ + enum jobsNum = 1024 * 4; + + ThreadPool thPool; + thPool.initialize(); + + ThreadData* mainThread = thPool.registerExternalThread(); // Register main thread as thread 0 + JobData startFrameJobData; // Variable to store job starting the TestApp + + JobData[jobsNum] frameJobs; // Array to store jobs created in TestApp.continueFrameInOtherJob + shared int frameNum; // Simulate game loop, run jobs for few frames and exit + + // App starts as one job &startFrame + // Then using own JobData memory spawns 'continueFrameInOtherJob' job + // 'continueFrameInOtherJob' job fills frameJobs array with &importantTask jobs. Group created to run this jobs is freed using JobsGroup.onFinish delegate + // 'importantTask' allocate new jobs (&importantTaskSubTask) and group, they all deallocated using JobsGroup.onFinish delegate + // 'continueFrameInOtherJob' waits for all 'importantTask'. All 'importantTask' wait for all 'importantTaskSubTask'. + // So after all 'importantTaskSubTask' and 'importantTask' are done 'continueFrameInOtherJob' ends and spawns &finishFrame + // 'finishFrame' spawn new frame or exits application + struct TestApp + { + // First job in frame + // Do some stuff and spawn some other job + // 1 - Number of jobs of this kind in frame + void startFrame(ThreadData* threadData, JobData* startFrameJobData) + { + startFrameJobData.del = &continueFrameInOtherJobAAA; + startFrameJobData.name = "cont frmAAA"; + thPool.addJobAsynchronous(startFrameJobData, thPool.threadsNum - 1); /// startFrame is the only job in thread pool no synchronization is required + } + + void continueFrameInOtherJobAAA(ThreadData* threadData, JobData* startFrameJobData) + { + + static struct JobGroupMemory + { + JobsGroup[6] groups; + JobData[1][6] groupsJobs; + TestApp* app; + JobData* startFrameJobData; + + void spawnCont(JobsGroup* group) + { + // startFrameJobData.del = &continueFrameInOtherJob; + startFrameJobData.del = &app.finishFrame; + startFrameJobData.name = "cont frm"; + group.thPool.addJobAsynchronous(startFrameJobData); /// startFrame is the only job in thread pool no synchronization is required + + } + } + + JobGroupMemory* memory = makeVar!JobGroupMemory(); + memory.app = &this; + memory.startFrameJobData = startFrameJobData; + + with (memory) + { + groups[0] = JobsGroup("dependant 0", groupsJobs[0]); + groups[1] = JobsGroup("dependant 1", groupsJobs[1]); + groups[2] = JobsGroup("dependant 2", groupsJobs[2]); + groups[3] = JobsGroup("dependant 3", groupsJobs[3]); + groups[4] = JobsGroup("dependant 4", groupsJobs[4]); + groups[5] = JobsGroup("dependant 5", groupsJobs[5]); + groups[5].onFinish = &spawnCont; + + groups[2].dependantOn(&groups[0]); + groups[2].dependantOn(&groups[1]); + + groups[3].dependantOn(&groups[0]); + groups[3].dependantOn(&groups[1]); + groups[3].dependantOn(&groups[2]); + + groups[4].dependantOn(&groups[1]); + groups[4].dependantOn(&groups[3]); + + groups[5].dependantOn(&groups[0]); + groups[5].dependantOn(&groups[1]); + groups[5].dependantOn(&groups[2]); + groups[5].dependantOn(&groups[3]); + groups[5].dependantOn(&groups[4]); + + foreach (ref jobs; groupsJobs) + foreach (ref j; jobs) + j = JobData(&this.importantTaskSubTask, "n"); + + thPool.addGroupAsynchronous(&groups[0]); + thPool.addGroupAsynchronous(&groups[1]); + } + } + + // Job for some big system + // Spawns some jobs and when they are done spawns finishFrame job + // 1 - Number of jobs of this kind in frame + void continueFrameInOtherJob(ThreadData* threadData, JobData* startFrameJobData) + { + static struct JobGroupMemory + { + JobsGroup group; + TestApp* app; + JobData* startFrameJobData; + + void freeAndContinue(JobsGroup* group) + { + startFrameJobData.del = &app.finishFrame; + startFrameJobData.name = "finishFrame"; + group.thPool.addJobAsynchronous(startFrameJobData, group.thPool.threadsNum - 1); /// startFrameJobData is continuation of 'startFrame data', all important jobs finished so it is the only job, no synchronization required. Always spawn on last thread + disposeVar!(JobGroupMemory)(&this); + } + } + + JobGroupMemory* important = makeVar!JobGroupMemory(); + important.app = &this; + important.startFrameJobData = startFrameJobData; + + foreach (ref j; frameJobs) + j = JobData(&this.importantTask, "vip"); + + important.group = JobsGroup("a lot of jobs", frameJobs[]); + important.group.onFinish = &important.freeAndContinue; + + thPool.addGroupAsynchronous(&important.group); // No Synchronization required continueFrameInOtherJob is the only job + } + + // Some task which by itself does a lot of computation so it spawns few more jobs + // jobsNum - Number of jobs of this kind in frame + void importantTask(ThreadData* threadData, JobData* data) + { + // All tasks created here will, make 'importantTask' wait with finish untill this jobs will finish + + /// Add 10 tasks in group + static struct JobGroupMemory + { + JobsGroup group; + JobData[128] jobs; + + void freeMee(JobsGroup* group) + { + disposeVar!(JobGroupMemory)(&this); + } + } + + JobGroupMemory* subGroup = makeVar!JobGroupMemory(); + + foreach (ref j; subGroup.jobs) + j = JobData(&this.importantTaskSubTask, "vip sub"); + + subGroup.group = JobsGroup("128 jobs", subGroup.jobs[]); + subGroup.group.onFinish = &subGroup.freeMee; + thPool.addGroup(&subGroup.group, data.group); + + /// Add single tasks + data.del = &importantTaskSubTask; + data.name = "sub"; + thPool.addJob(data); + } + + // Job which simply does some work + // jobsNum * 128 - Number of jobs of this kind in frame + void importantTaskSubTask(ThreadData* threadData, JobData* data) + { + } + + // Finish frame + // 1 - Number of jobs of this kind in frame + void finishFrame(ThreadData* threadData, JobData* startFrameJobData) + { + auto num = atomicOp!"+="(frameNum, 1); + if (num == 10) + { + thPool.releaseExternalThreads(); // After 10 frames exit application + return; + } + *startFrameJobData = JobData(&startFrame, "StartFrame"); // + thPool.addJobAsynchronous(startFrameJobData); // Start next frame, there should't be any other tasks execept of this one, so no synchronization is required + + } + + // Func to test if dynamic changing of threads number works + // void changeThreadsNum() + // { + // import std.random : uniform; + + // bool change = uniform(0, 100) == 3; + // if (!change) + // return; + + // int threadsNum = uniform(3, 5); + // thPool.setThreadsNum(threadsNum); + + // } + } + + void testThreadsNum(int threadsNum) + { + frameNum = 0; + thPool.jobsDoneCountReset(); + thPool.setThreadsNum(threadsNum); + + TestApp testApp = TestApp(); + startFrameJobData = JobData(&testApp.startFrame, "StartFrame"); // Start first frame, will live as long as main thread won't exit from threadStartFunc() + + ulong start = useconds(); + thPool.addJobAsynchronous(&startFrameJobData); // Synchronization is made by groupEnd (last job in pool) which calls thPool.releaseExternalThreads(); + mainThread.threadStartFunc(); + ulong end = useconds(); + printf("Threads Num: %2d. Jobs: %d. Time: %5.2f ms. jobs/ms: %5.2f\n", threadsNum, thPool.jobsDoneCount, + (end - start) / 1000.0f, thPool.jobsDoneCount / ((end - start) / 1000.0f)); + } + + while (1) + { + // foreach (i; 1 .. 32) + // testThreadsNum(i); + + testThreadsNum(1); + testThreadsNum(4); + testThreadsNum(16); + } + thPool.flushAllLogs(); + thPool.waitThreads(); + thPool.unregistExternalThread(mainThread); +} + +version (D_BetterC) +{ + + extern (C) int main(int argc, char*[] argv) // for betterC + { + testThreadPool(); + return 0; + } +} +else +{ + int main() + { + testThreadPool(); + return 0; + } +}//*/ +// Compile +// -fsanitize=address +// rdmd -g -of=thread_pool src/mmutils/thread_pool.d && ./thread_pool +// ldmd2 -release -inline -checkaction=C -g -of=thread_pool src/mmutils/thread_pool.d && ./thread_pool +// ldmd2 -checkaction=C -g -of=thread_pool src/mmutils/thread_pool.d && ./thread_pool \ No newline at end of file diff --git a/demos/external/imports/bindbc/sdl/bind/package.d b/demos/external/wasm_imports/bindbc/sdl/bind/package.d similarity index 100% rename from demos/external/imports/bindbc/sdl/bind/package.d rename to demos/external/wasm_imports/bindbc/sdl/bind/package.d diff --git a/demos/external/imports/bindbc/sdl/bind/sdl.d b/demos/external/wasm_imports/bindbc/sdl/bind/sdl.d similarity index 100% rename from demos/external/imports/bindbc/sdl/bind/sdl.d rename to demos/external/wasm_imports/bindbc/sdl/bind/sdl.d diff --git a/demos/external/imports/bindbc/sdl/bind/sdlassert.d b/demos/external/wasm_imports/bindbc/sdl/bind/sdlassert.d similarity index 100% rename from demos/external/imports/bindbc/sdl/bind/sdlassert.d rename to demos/external/wasm_imports/bindbc/sdl/bind/sdlassert.d diff --git a/demos/external/imports/bindbc/sdl/bind/sdlaudio.d b/demos/external/wasm_imports/bindbc/sdl/bind/sdlaudio.d similarity index 100% rename from demos/external/imports/bindbc/sdl/bind/sdlaudio.d rename to demos/external/wasm_imports/bindbc/sdl/bind/sdlaudio.d diff --git a/demos/external/imports/bindbc/sdl/bind/sdlblendmode.d b/demos/external/wasm_imports/bindbc/sdl/bind/sdlblendmode.d similarity index 100% rename from demos/external/imports/bindbc/sdl/bind/sdlblendmode.d rename to demos/external/wasm_imports/bindbc/sdl/bind/sdlblendmode.d diff --git a/demos/external/imports/bindbc/sdl/bind/sdlclipboard.d b/demos/external/wasm_imports/bindbc/sdl/bind/sdlclipboard.d similarity index 100% rename from demos/external/imports/bindbc/sdl/bind/sdlclipboard.d rename to demos/external/wasm_imports/bindbc/sdl/bind/sdlclipboard.d diff --git a/demos/external/imports/bindbc/sdl/bind/sdlcpuinfo.d b/demos/external/wasm_imports/bindbc/sdl/bind/sdlcpuinfo.d similarity index 100% rename from demos/external/imports/bindbc/sdl/bind/sdlcpuinfo.d rename to demos/external/wasm_imports/bindbc/sdl/bind/sdlcpuinfo.d diff --git a/demos/external/imports/bindbc/sdl/bind/sdlerror.d b/demos/external/wasm_imports/bindbc/sdl/bind/sdlerror.d similarity index 100% rename from demos/external/imports/bindbc/sdl/bind/sdlerror.d rename to demos/external/wasm_imports/bindbc/sdl/bind/sdlerror.d diff --git a/demos/external/imports/bindbc/sdl/bind/sdlevents.d b/demos/external/wasm_imports/bindbc/sdl/bind/sdlevents.d similarity index 100% rename from demos/external/imports/bindbc/sdl/bind/sdlevents.d rename to demos/external/wasm_imports/bindbc/sdl/bind/sdlevents.d diff --git a/demos/external/imports/bindbc/sdl/bind/sdlfilesystem.d b/demos/external/wasm_imports/bindbc/sdl/bind/sdlfilesystem.d similarity index 100% rename from demos/external/imports/bindbc/sdl/bind/sdlfilesystem.d rename to demos/external/wasm_imports/bindbc/sdl/bind/sdlfilesystem.d diff --git a/demos/external/imports/bindbc/sdl/bind/sdlgamecontroller.d b/demos/external/wasm_imports/bindbc/sdl/bind/sdlgamecontroller.d similarity index 100% rename from demos/external/imports/bindbc/sdl/bind/sdlgamecontroller.d rename to demos/external/wasm_imports/bindbc/sdl/bind/sdlgamecontroller.d diff --git a/demos/external/imports/bindbc/sdl/bind/sdlgesture.d b/demos/external/wasm_imports/bindbc/sdl/bind/sdlgesture.d similarity index 100% rename from demos/external/imports/bindbc/sdl/bind/sdlgesture.d rename to demos/external/wasm_imports/bindbc/sdl/bind/sdlgesture.d diff --git a/demos/external/imports/bindbc/sdl/bind/sdlhaptic.d b/demos/external/wasm_imports/bindbc/sdl/bind/sdlhaptic.d similarity index 100% rename from demos/external/imports/bindbc/sdl/bind/sdlhaptic.d rename to demos/external/wasm_imports/bindbc/sdl/bind/sdlhaptic.d diff --git a/demos/external/imports/bindbc/sdl/bind/sdlhints.d b/demos/external/wasm_imports/bindbc/sdl/bind/sdlhints.d similarity index 100% rename from demos/external/imports/bindbc/sdl/bind/sdlhints.d rename to demos/external/wasm_imports/bindbc/sdl/bind/sdlhints.d diff --git a/demos/external/imports/bindbc/sdl/bind/sdljoystick.d b/demos/external/wasm_imports/bindbc/sdl/bind/sdljoystick.d similarity index 100% rename from demos/external/imports/bindbc/sdl/bind/sdljoystick.d rename to demos/external/wasm_imports/bindbc/sdl/bind/sdljoystick.d diff --git a/demos/external/imports/bindbc/sdl/bind/sdlkeyboard.d b/demos/external/wasm_imports/bindbc/sdl/bind/sdlkeyboard.d similarity index 100% rename from demos/external/imports/bindbc/sdl/bind/sdlkeyboard.d rename to demos/external/wasm_imports/bindbc/sdl/bind/sdlkeyboard.d diff --git a/demos/external/imports/bindbc/sdl/bind/sdlkeycode.d b/demos/external/wasm_imports/bindbc/sdl/bind/sdlkeycode.d similarity index 100% rename from demos/external/imports/bindbc/sdl/bind/sdlkeycode.d rename to demos/external/wasm_imports/bindbc/sdl/bind/sdlkeycode.d diff --git a/demos/external/imports/bindbc/sdl/bind/sdlloadso.d b/demos/external/wasm_imports/bindbc/sdl/bind/sdlloadso.d similarity index 100% rename from demos/external/imports/bindbc/sdl/bind/sdlloadso.d rename to demos/external/wasm_imports/bindbc/sdl/bind/sdlloadso.d diff --git a/demos/external/imports/bindbc/sdl/bind/sdllog.d b/demos/external/wasm_imports/bindbc/sdl/bind/sdllog.d similarity index 100% rename from demos/external/imports/bindbc/sdl/bind/sdllog.d rename to demos/external/wasm_imports/bindbc/sdl/bind/sdllog.d diff --git a/demos/external/imports/bindbc/sdl/bind/sdlmessagebox.d b/demos/external/wasm_imports/bindbc/sdl/bind/sdlmessagebox.d similarity index 100% rename from demos/external/imports/bindbc/sdl/bind/sdlmessagebox.d rename to demos/external/wasm_imports/bindbc/sdl/bind/sdlmessagebox.d diff --git a/demos/external/imports/bindbc/sdl/bind/sdlmouse.d b/demos/external/wasm_imports/bindbc/sdl/bind/sdlmouse.d similarity index 100% rename from demos/external/imports/bindbc/sdl/bind/sdlmouse.d rename to demos/external/wasm_imports/bindbc/sdl/bind/sdlmouse.d diff --git a/demos/external/imports/bindbc/sdl/bind/sdlpixels.d b/demos/external/wasm_imports/bindbc/sdl/bind/sdlpixels.d similarity index 100% rename from demos/external/imports/bindbc/sdl/bind/sdlpixels.d rename to demos/external/wasm_imports/bindbc/sdl/bind/sdlpixels.d diff --git a/demos/external/imports/bindbc/sdl/bind/sdlplatform.d b/demos/external/wasm_imports/bindbc/sdl/bind/sdlplatform.d similarity index 100% rename from demos/external/imports/bindbc/sdl/bind/sdlplatform.d rename to demos/external/wasm_imports/bindbc/sdl/bind/sdlplatform.d diff --git a/demos/external/imports/bindbc/sdl/bind/sdlpower.d b/demos/external/wasm_imports/bindbc/sdl/bind/sdlpower.d similarity index 100% rename from demos/external/imports/bindbc/sdl/bind/sdlpower.d rename to demos/external/wasm_imports/bindbc/sdl/bind/sdlpower.d diff --git a/demos/external/imports/bindbc/sdl/bind/sdlrect.d b/demos/external/wasm_imports/bindbc/sdl/bind/sdlrect.d similarity index 100% rename from demos/external/imports/bindbc/sdl/bind/sdlrect.d rename to demos/external/wasm_imports/bindbc/sdl/bind/sdlrect.d diff --git a/demos/external/imports/bindbc/sdl/bind/sdlrender.d b/demos/external/wasm_imports/bindbc/sdl/bind/sdlrender.d similarity index 100% rename from demos/external/imports/bindbc/sdl/bind/sdlrender.d rename to demos/external/wasm_imports/bindbc/sdl/bind/sdlrender.d diff --git a/demos/external/imports/bindbc/sdl/bind/sdlrwops.d b/demos/external/wasm_imports/bindbc/sdl/bind/sdlrwops.d similarity index 100% rename from demos/external/imports/bindbc/sdl/bind/sdlrwops.d rename to demos/external/wasm_imports/bindbc/sdl/bind/sdlrwops.d diff --git a/demos/external/imports/bindbc/sdl/bind/sdlscancode.d b/demos/external/wasm_imports/bindbc/sdl/bind/sdlscancode.d similarity index 100% rename from demos/external/imports/bindbc/sdl/bind/sdlscancode.d rename to demos/external/wasm_imports/bindbc/sdl/bind/sdlscancode.d diff --git a/demos/external/imports/bindbc/sdl/bind/sdlshape.d b/demos/external/wasm_imports/bindbc/sdl/bind/sdlshape.d similarity index 100% rename from demos/external/imports/bindbc/sdl/bind/sdlshape.d rename to demos/external/wasm_imports/bindbc/sdl/bind/sdlshape.d diff --git a/demos/external/imports/bindbc/sdl/bind/sdlstdinc.d b/demos/external/wasm_imports/bindbc/sdl/bind/sdlstdinc.d similarity index 100% rename from demos/external/imports/bindbc/sdl/bind/sdlstdinc.d rename to demos/external/wasm_imports/bindbc/sdl/bind/sdlstdinc.d diff --git a/demos/external/imports/bindbc/sdl/bind/sdlsurface.d b/demos/external/wasm_imports/bindbc/sdl/bind/sdlsurface.d similarity index 100% rename from demos/external/imports/bindbc/sdl/bind/sdlsurface.d rename to demos/external/wasm_imports/bindbc/sdl/bind/sdlsurface.d diff --git a/demos/external/imports/bindbc/sdl/bind/sdlsystem.d b/demos/external/wasm_imports/bindbc/sdl/bind/sdlsystem.d similarity index 100% rename from demos/external/imports/bindbc/sdl/bind/sdlsystem.d rename to demos/external/wasm_imports/bindbc/sdl/bind/sdlsystem.d diff --git a/demos/external/imports/bindbc/sdl/bind/sdlsyswm.d b/demos/external/wasm_imports/bindbc/sdl/bind/sdlsyswm.d similarity index 100% rename from demos/external/imports/bindbc/sdl/bind/sdlsyswm.d rename to demos/external/wasm_imports/bindbc/sdl/bind/sdlsyswm.d diff --git a/demos/external/imports/bindbc/sdl/bind/sdltimer.d b/demos/external/wasm_imports/bindbc/sdl/bind/sdltimer.d similarity index 100% rename from demos/external/imports/bindbc/sdl/bind/sdltimer.d rename to demos/external/wasm_imports/bindbc/sdl/bind/sdltimer.d diff --git a/demos/external/imports/bindbc/sdl/bind/sdltouch.d b/demos/external/wasm_imports/bindbc/sdl/bind/sdltouch.d similarity index 100% rename from demos/external/imports/bindbc/sdl/bind/sdltouch.d rename to demos/external/wasm_imports/bindbc/sdl/bind/sdltouch.d diff --git a/demos/external/imports/bindbc/sdl/bind/sdlversion.d b/demos/external/wasm_imports/bindbc/sdl/bind/sdlversion.d similarity index 100% rename from demos/external/imports/bindbc/sdl/bind/sdlversion.d rename to demos/external/wasm_imports/bindbc/sdl/bind/sdlversion.d diff --git a/demos/external/imports/bindbc/sdl/bind/sdlvideo.d b/demos/external/wasm_imports/bindbc/sdl/bind/sdlvideo.d similarity index 100% rename from demos/external/imports/bindbc/sdl/bind/sdlvideo.d rename to demos/external/wasm_imports/bindbc/sdl/bind/sdlvideo.d diff --git a/demos/external/imports/bindbc/sdl/bind/sdlvulkan.d b/demos/external/wasm_imports/bindbc/sdl/bind/sdlvulkan.d similarity index 100% rename from demos/external/imports/bindbc/sdl/bind/sdlvulkan.d rename to demos/external/wasm_imports/bindbc/sdl/bind/sdlvulkan.d diff --git a/demos/external/imports/bindbc/sdl/config.d b/demos/external/wasm_imports/bindbc/sdl/config.d similarity index 100% rename from demos/external/imports/bindbc/sdl/config.d rename to demos/external/wasm_imports/bindbc/sdl/config.d diff --git a/demos/external/imports/bindbc/sdl/dynload.d b/demos/external/wasm_imports/bindbc/sdl/dynload.d similarity index 100% rename from demos/external/imports/bindbc/sdl/dynload.d rename to demos/external/wasm_imports/bindbc/sdl/dynload.d diff --git a/demos/external/imports/bindbc/sdl/image.d b/demos/external/wasm_imports/bindbc/sdl/image.d similarity index 100% rename from demos/external/imports/bindbc/sdl/image.d rename to demos/external/wasm_imports/bindbc/sdl/image.d diff --git a/demos/external/imports/bindbc/sdl/mixer.d b/demos/external/wasm_imports/bindbc/sdl/mixer.d similarity index 100% rename from demos/external/imports/bindbc/sdl/mixer.d rename to demos/external/wasm_imports/bindbc/sdl/mixer.d diff --git a/demos/external/imports/bindbc/sdl/package.d b/demos/external/wasm_imports/bindbc/sdl/package.d similarity index 100% rename from demos/external/imports/bindbc/sdl/package.d rename to demos/external/wasm_imports/bindbc/sdl/package.d diff --git a/demos/external/imports/bindbc/sdl/ttf.d b/demos/external/wasm_imports/bindbc/sdl/ttf.d similarity index 100% rename from demos/external/imports/bindbc/sdl/ttf.d rename to demos/external/wasm_imports/bindbc/sdl/ttf.d diff --git a/demos/simple/source/app.d b/demos/simple/source/app.d deleted file mode 100644 index d8d61f5..0000000 --- a/demos/simple/source/app.d +++ /dev/null @@ -1,216 +0,0 @@ -module source.app; - -import ecs.std; -import ecs.core; -import ecs.manager; -import ecs.attributes; -import ecs.entity; - -import bindbc.sdl; - -import utils.utils; -import utils.texture; - -import ecs_utils.math.vector; - -version (WebAssembly) -{ - extern (C) void _start() - { - } -} - -SDL_Renderer *renderer; -SDL_Window* window; -Texture texture; -EntityManager* manager; - -struct CLocation -{ - mixin ECS.Component; - - alias location this; - - vec2 location; -} - -struct CTexture -{ - mixin ECS.Component; - - Texture tex; -} - -struct DrawSystem -{ - mixin ECS.System; - - struct EntitiesData - { - uint length; - @readonly CTexture[] textures; - @readonly CLocation[] locations; - } - - void onUpdate(EntitiesData data) - { - foreach(i; 0..data.length) - { - draw(renderer, data.textures[i].tex, data.locations[i], vec2(32,32), vec4(0,0,1,1)); - } - } -} - -struct MoveSystem -{ - mixin ECS.System; - - struct EntitiesData - { - uint length; - CLocation[] locations; - } - - void onUpdate(EntitiesData data) - { - foreach(i; 0..data.length) - { - data.locations[i].location.y = data.locations[i].location.y + 1; - if(data.locations[i].location.y > 400)data.locations[i].location.y = 0; - } - } -} - -extern (C) int main(int argc, char** argv) -{ - fps = 0; - time = 0; - - if (SDL_Init(SDL_INIT_VIDEO) < 0) - { - printf("SDL could not initialize! SDL_Error: %s", SDL_GetError()); - return -1; - } - - SDL_version sdl_version; - SDL_GetVersion(&sdl_version); - printf("SDL version: %u.%u.%u\n",cast(uint)sdl_version.major,cast(uint)sdl_version.minor,cast(uint)sdl_version.patch); - - SDL_Window* window = SDL_CreateWindow("Simple", SDL_WINDOWPOS_CENTERED, - SDL_WINDOWPOS_CENTERED, 600, 400, SDL_WINDOW_SHOWN); - //SDL_CreateWindowAndRenderer(600, 400, SDL_RENDERER_ACCELERATED, &window, &renderer); - renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC); - SDL_SetRenderDrawColor(renderer, 1, 255, 255, 255); - - texture.create(); - texture.load(renderer, "assets/textures/buckler.png"); - - EntityManager.initialize(8); - manager = EntityManager.instance; - - manager.beginRegister(); - - manager.registerComponent!CLocation; - manager.registerComponent!CTexture; - - manager.registerSystem!MoveSystem(64); - manager.registerSystem!DrawSystem(64); - - manager.endRegister(); - - ushort[2] components = [CLocation.component_id, CTexture.component_id]; - EntityTemplate* tmpl = manager.allocateTemplate(components); - CTexture* tex_comp = tmpl.getComponent!CTexture; - tex_comp.tex = texture; - CLocation* loc_comp = tmpl.getComponent!CLocation; - // loc_comp.location = vec2(64,64); - - foreach(i; 0..10) - foreach(j; 0..10) - { - loc_comp.location = vec2(i*32+64,j*32+64); - manager.addEntity(tmpl); - } - - - manager.freeTemplate(tmpl); - - /*image = IMG_Load("assets/owl.png"); - tex = SDL_CreateTextureFromSurface(renderer, image);*/ - - version(WebAssembly) - { - emscripten_set_main_loop_arg(&loop, null, -1, 1); - } - - bool arg = true; - while(arg == true) - { - loop(&arg); - } - - if (window !is null) { - SDL_DestroyWindow(window); - } - - end(); - - return 0; -} - -long time; -uint fps; - -extern(C) void loop(void *arg = null) -{ - static float fps_time = 0; - float delta_time = cast(float)(Time.getUSecTime() - time); - if(delta_time > 1000_000)delta_time = 1000; - time = Time.getUSecTime(); - - if(fps_time < 0)fps_time = 0; - - fps++; - fps_time += delta_time; - if(fps_time > 1000_000) - { - - printf("FPS: %u\n",fps); - fps = 0; - fps_time -= 1000_000; - } - - SDL_Event event; - while (SDL_PollEvent(&event)) - { - if (event.type == SDL_QUIT) { - version(WebAssembly)emscripten_cancel_main_loop(); - *cast(bool*)arg = false; - //return false; - } - - if (event.type == SDL_KEYDOWN) { - version(WebAssembly)emscripten_cancel_main_loop(); - *cast(bool*)arg = false; - //return false; - } - } - - SDL_RenderClear(renderer); - - manager.begin(); - manager.update(); - manager.end(); - - draw(renderer,texture,vec2(32,32),vec2(32,32),vec4(0,0,1,1)); - //SDL_RenderCopy(ctx->renderer, ctx->owl_tex, NULL, &ctx->dest); - SDL_RenderPresent(renderer); - - //return true; -} - -void end() -{ - EntityManager.destroy(); - SDL_Quit(); -} \ No newline at end of file diff --git a/demos/simple/source/utils/texture.d b/demos/simple/source/utils/texture.d deleted file mode 100644 index 5b49390..0000000 --- a/demos/simple/source/utils/texture.d +++ /dev/null @@ -1,49 +0,0 @@ -module utils.texture; - -import ecs.std; - -import bindbc.sdl; -import bindbc.sdl.image; - -import ecs_utils.math.vector; - -struct Texture -{ - - void create() - { - data = Mallocator.make!Data; - } - - bool load(SDL_Renderer* renderer, const char[] path) - { - char[] cpath = (cast(char*)alloca(path.length+1))[0..path.length+1]; - //cpath[0..$-1] = path[0..$]; - memcpy(cpath.ptr, path.ptr, path.length); - cpath[$-1] = 0; - - SDL_Surface* surf = IMG_Load(cpath.ptr); - if(!surf)return false; - - data.size = ivec2(surf.w,surf.h); - - data.texture = SDL_CreateTextureFromSurface(renderer,surf); - SDL_FreeSurface(surf); - - if(!data.texture)return false; - - return true; - } - - struct Data - { - ubyte[] data; - - ivec2 size; - uint bpp; - - SDL_Texture* texture; - } - - Data* data; -} \ No newline at end of file diff --git a/demos/simple/source/utils/utils.d b/demos/simple/source/utils/utils.d deleted file mode 100644 index c7d3e9d..0000000 --- a/demos/simple/source/utils/utils.d +++ /dev/null @@ -1,110 +0,0 @@ -module utils.utils; - -extern(C) int printf(scope const char* format, ...) @nogc nothrow @system; - -version(WebAssembly) -{ - - extern (C) alias em_callback_func = void function(); - extern (C) alias em_arg_callback_func = void function(void*); - extern (C) void emscripten_set_main_loop(em_callback_func func, int fps, int simulate_infinite_loop); - extern (C) void emscripten_set_main_loop_arg(em_arg_callback_func func, void *arg, int fps, int simulate_infinite_loop); - extern (C) int emscripten_set_main_loop_timing(int mode, int value); - extern (C) void emscripten_cancel_main_loop(); - - alias int time_t; - alias int clockid_t; - enum CLOCK_REALTIME = 0; - - struct timespec - { - time_t tv_sec; - int tv_nsec; - } - - extern(C) int clock_gettime(clockid_t, timespec*) @nogc nothrow @system; - - struct Time - { - - - static long getUSecTime() - { - time_t time; - timespec spec; - - clock_gettime(CLOCK_REALTIME, &spec); - - //time = spec.tv_sec; - return spec.tv_sec * 1000_000 + spec.tv_nsec / 1000;//time / 1000_000; - - /*LARGE_INTEGER time, freq; - QueryPerformanceFrequency(&freq); - QueryPerformanceCounter(&time); - return time.QuadPart / (freq.QuadPart / 1000_000);*/ - } - } -} -else version(Windows) -{ - import core.stdc.stdio : printf; - import core.sys.windows.windows; - struct Time - { - static long getUSecTime() - { - LARGE_INTEGER time, freq; - QueryPerformanceFrequency(&freq); - QueryPerformanceCounter(&time); - return time.QuadPart / (freq.QuadPart / 1000_000); - } - } -} -else version(Posix) -{ - import core.stdc.stdio : printf; - import core.sys.posix.time; - struct Time - { - static long getUSecTime() - { - time_t time; - timespec spec; - - clock_gettime(CLOCK_REALTIME, &spec); - - //time = spec.tv_sec; - return spec.tv_sec * 1000_000 + spec.tv_nsec / 1000;//time / 1000_000; - - /*LARGE_INTEGER time, freq; - QueryPerformanceFrequency(&freq); - QueryPerformanceCounter(&time); - return time.QuadPart / (freq.QuadPart / 1000_000);*/ - } - } -} - -import bindbc.sdl; -import utils.texture; -import ecs_utils.math.vector; - -ivec2 resolution = ivec2(600, 400); - -void draw(SDL_Renderer* renderer, Texture tex, vec2 pos, vec2 size, vec4 coords, float angle = 0) -{ - - SDL_Rect rect = SDL_Rect(cast(int)(coords.x*tex.data.size.x),cast(int)(coords.y*tex.data.size.y),cast(int)(coords.z*tex.data.size.x),cast(int)(coords.w*tex.data.size.y)); - SDL_Rect rect2 = SDL_Rect(cast(int)((pos.x-size.x*0.5)), - cast(int)(resolution.y - pos.y - size.y*0.5), - cast(int)(size.x), - cast(int)(size.y)); - - SDL_RenderCopyEx(renderer, - tex.data.texture, - &rect, - &rect2, - angle*360, - null, - SDL_FLIP_NONE); - -} \ No newline at end of file diff --git a/demos/utils/dub.json b/demos/utils/dub.json index 14298cb..2f7d1bb 100644 --- a/demos/utils/dub.json +++ b/demos/utils/dub.json @@ -5,21 +5,19 @@ ], "description": "Dynamic Entity Component System examples utils", "copyright": "Copyright © 2018-2019, Michał Masiukiewicz, Dawid Masiukiewicz", - "license": "BSD", + "license": "BSD 3-clause", "sourcePaths" : [ - "source\/" + "source", + "../external/sources" ], "importPaths": [ - "source" - ], - "dflags-posix-ldc": [ - "-defaultlib=phobos2-ldc,druntime-ldc" - ], - "dflagss": [ - "-betterC" + "source", + "../external/imports", + "../external/sources" ], "dependencies": { - "bindbc-sdl":"0.10.1" + "bindbc-sdl":"0.13.0", + "ecs":{"path":"../../"} }, "versions": [ "BindSDL_Image", @@ -32,7 +30,8 @@ "targetType" : "library", "subConfigurations": { - "bindbc-sdl": "static" + "bindbc-sdl": "static", + "ecs":"library" } }, { @@ -43,7 +42,8 @@ ], "subConfigurations": { - "bindbc-sdl": "staticBC" + "bindbc-sdl": "staticBC", + "ecs":"library-betterC" } } ] diff --git a/demos/utils/source/ecs_utils/gfx/buffer.d b/demos/utils/source/ecs_utils/gfx/buffer.d new file mode 100644 index 0000000..1f38624 --- /dev/null +++ b/demos/utils/source/ecs_utils/gfx/buffer.d @@ -0,0 +1,134 @@ +module ecs_utils.gfx.buffer; + +import ecs.std; + +import glad.gl.gl; +import glad.gl.gles2; + +extern(C): + +struct Buffer +{ + + void create() nothrow + { + data = Mallocator.make!Data; + data.gl_handle = 0; + glGenBuffers(1,&data.gl_handle); + data.elem_size = 0; + } + + //--------------------------------------------------------------------------------------------------------------------------------------------------- + + void destroy() nothrow + { + if(data.gl_handle)glDeleteBuffers(1,&data.gl_handle); + } + + //--------------------------------------------------------------------------------------------------------------------------------------------------- + + void bind(BindTarget target) nothrow + { + //if(vbo != this)glBindBuffer(GL_ARRAY_BUFFER,data.gl_handle); + //vbo = this; + glBindBuffer(target,data.gl_handle); + } + + void bindRange(BindTarget target, uint index, uint offset, uint size) nothrow + { + glBindBufferRange(target, index, data.gl_handle, offset, size); + } + + //--------------------------------------------------------------------------------------------------------------------------------------------------- + + void bufferData(BindTarget target, uint size, uint count, uint usage, void* data) nothrow + { + bind(target); + this.data.elem_size = size; + glBufferData(target,size*count,data,usage); + } + + /*void bufferStorage(uint size, uint count, void* data, uint flags = StorageFlagBits.write) + { + bind(BindTarget.array); + this.data.elem_size = size; + glBufferStorage(GL_ARRAY_BUFFER,size*count,data, flags); + }*/ + + void bufferSubData(uint size, uint offset, void* data) nothrow + { + bind(BindTarget.array); + glBufferSubData(GL_ARRAY_BUFFER,offset,size,data); + } + + void map(BindTarget target) nothrow + { + bind(target); + data.map_ptr = glMapBuffer(target,GL_WRITE_ONLY); + } + + void map(uint offset, uint size, BindTarget target, uint flags = MapFlagBits.write | MapFlagBits.flush_explict | MapFlagBits.invalidate_buffer) nothrow + { + bind(target); + data.map_ptr = glMapBufferRange(target,offset,size,flags); + } + + void flush(uint offset, uint size, BindTarget target) nothrow + { + glFlushMappedBufferRange(target, offset, size); + } + + void unmap(BindTarget target) nothrow + { + bind(target); + glUnmapBuffer(target); + data.map_ptr = null; + } + + void* mappedPointer() nothrow + { + return data.map_ptr; + } + + //--------------------------------------------------------------------------------------------------------------------------------------------------- + + static void unbind(BindTarget target) nothrow + { + //vbo = 0; + glBindBuffer(target,0); + } + + enum BindTarget + { + array = GL_ARRAY_BUFFER, + element_array = GL_ELEMENT_ARRAY_BUFFER, + uniform = GL_UNIFORM_BUFFER, + //shader_storage = GL_SHADER_STORAGE_BUFFER, + //indirect = GL_DRAW_INDIRECT_BUFFER + } + + enum MapFlagBits + { + write = GL_MAP_WRITE_BIT, + invalidate_buffer = GL_MAP_INVALIDATE_BUFFER_BIT, + flush_explict = GL_MAP_FLUSH_EXPLICIT_BIT, + //coherent = GL_MAP_COHERENT_BIT, + //persistent = GL_MAP_PERSISTENT_BIT + } + + enum StorageFlagBits + { + write = GL_MAP_WRITE_BIT, + //coherent = GL_MAP_COHERENT_BIT, + //persistent = GL_MAP_PERSISTENT_BIT + } + + struct Data + { + uint elem_size; + uint gl_handle; + void* map_ptr; + } + + Data* data; +} \ No newline at end of file diff --git a/demos/utils/source/ecs_utils/gfx/config.d b/demos/utils/source/ecs_utils/gfx/config.d new file mode 100644 index 0000000..de5528a --- /dev/null +++ b/demos/utils/source/ecs_utils/gfx/config.d @@ -0,0 +1,102 @@ +module ecs_utils.gfx.config; + +import bindbc.sdl; + +import ecs.std; + +import ecs_utils.gfx.material; +import ecs_utils.gfx.mesh; +import ecs_utils.gfx.texture; + +//import mutils.serializer.json; + +extern(C): + +enum LayerType +{ + normal, + sorted +} + +import ecs.vector; + +static struct GfxConfig +{ + extern(C): + __gshared: + Vector!LayerType layers; + //Vector!Mesh meshes; + //Vector!Material materials; + Mesh[] meshes; + Material[] materials; + + static bool load(const (char)[] path) nothrow + { + struct LoadData + { + struct Str + { + @("malloc") string str; + } + + @("malloc") Str[] materials; + @("malloc") Str[] meshes; + int inter; + + void dispose() nothrow + { + /*if(blend_mode)Mallocator.instance.dispose(cast(char[])blend_mode); + if(vertex)Mallocator.instance.dispose(cast(char[])vertex); + if(fragment)Mallocator.instance.dispose(cast(char[])fragment);*/ + } + } + + char[] cpath = (cast(char*)alloca(path.length+1))[0..path.length+1]; + cpath[0..$-1] = path[0..$]; + cpath[$-1] = 0; + + SDL_RWops* file = SDL_RWFromFile(cpath.ptr,"r"); + if(file) + { + size_t size = cast(size_t)SDL_RWsize(file); + char[] buffer = Mallocator.makeArray!char(size); + SDL_RWread(file,buffer.ptr,size,1); + + LoadData load_data; + scope(exit)load_data.dispose(); + + /*JSONSerializer serializer = Mallocator.make!JSONSerializer; + scope(exit)Mallocator.dispose(serializer); + serializer.serialize!(Load.yes, true)(load_data,buffer);*/ + + //if(__ecs_used_backend == Backend.opengl) + { + meshes = Mallocator.makeArray!Mesh(load_data.meshes.length); + foreach(i,ref mesh; meshes) + { + mesh.load(load_data.meshes[i].str); + mesh.uploadData(); + } + } + + materials = Mallocator.makeArray!Material(load_data.materials.length); + foreach(i,ref material; materials) + { + material.create(); + material.load(load_data.materials[i].str); + material.compile(); + } + + SDL_RWclose(file); + load_data.dispose(); + return true; + } + else return false; + } + + static int addLayer(LayerType type) + { + layers.add(type); + return cast(int)(layers.length-1); + } +} \ No newline at end of file diff --git a/demos/utils/source/ecs_utils/gfx/material.d b/demos/utils/source/ecs_utils/gfx/material.d new file mode 100644 index 0000000..b697992 --- /dev/null +++ b/demos/utils/source/ecs_utils/gfx/material.d @@ -0,0 +1,198 @@ +module ecs_utils.gfx.material; + +import bindbc.sdl; + +import ecs.std; + +import ecs_utils.gfx.shader; + +import glad.gl.gl; + +//import mutils.serializer.json; + +struct Material +{ + + void create() nothrow + { + data = Mallocator.make!Data; + } + + bool load(const char[] path) nothrow + { + struct LoadData + { + @("malloc") string blend_mode; + @("malloc") string vertex; + @("malloc") string fragment; + + void dispose() nothrow + { + //if(blend_mode)Mallocator.instance.dispose(cast(char[])blend_mode); + //if(vertex)Mallocator.instance.dispose(cast(char[])vertex); + //if(fragment)Mallocator.instance.dispose(cast(char[])fragment); + } + } + + char[] cpath = (cast(char*)alloca(path.length+1))[0..path.length+1]; + cpath[0..$-1] = path[0..$]; + cpath[$-1] = 0; + + SDL_RWops* file = SDL_RWFromFile(cpath.ptr,"r"); + if(file) + { + size_t size = cast(size_t)SDL_RWsize(file); + char[] buffer = Mallocator.makeArray!char(size); + SDL_RWread(file,buffer.ptr,size,1); + + LoadData load_data; + scope(exit)load_data.dispose(); + + /*JSONSerializer serializer = Mallocator.make!JSONSerializer; + scope(exit)Mallocator.dispose(serializer); + serializer.serialize!(Load.yes, true)(load_data,buffer);*/ + + //if(__ecs_used_backend == Backend.opengl) + { + Shader vsh; + vsh.load(load_data.vertex); + vsh.compile(); + + Shader fsh; + fsh.load(load_data.fragment); + fsh.compile(); + + Material.ShaderModule[1] modules = [Material.ShaderModule(vsh,fsh)]; + + attachModules(modules); + } + + SDL_RWclose(file); + load_data.dispose(); + return true; + } + else return false; + } + + void bind() nothrow + { + glUseProgram(data.modules[0].gl_handle); + } + + enum BlendMode + { + opaque, + additive, + mixed + } + + enum TransformMode + { + position, + matrix + } + + struct ShaderModule + { + Shader fragment_shader; + Shader vertex_shader; + uint gl_handle; + } + + void attachModules(scope ShaderModule[] modules) nothrow + { + data.modules = Mallocator.makeArray(modules); + } + + bool compile() nothrow + { + foreach(ref module_;data.modules) + { + module_.gl_handle = glCreateProgram(); + glAttachShader(module_.gl_handle, module_.vertex_shader.data.gl_handle); + glAttachShader(module_.gl_handle, module_.fragment_shader.data.gl_handle); + } + + return true; + } + + void bindAttribLocation(const char* name, uint location) nothrow + { + foreach(ref module_;data.modules) + { + glBindAttribLocation(module_.gl_handle, location, name); + } + } + + bool link() nothrow + { + foreach(ref module_;data.modules) + { + glLinkProgram(module_.gl_handle); + + GLint ok = 0; + glGetProgramiv(module_.gl_handle, GL_LINK_STATUS, &ok); + if(!ok) + { + SDL_Log("Program link error!"); + return false; + } + } + + return true; + } + + int getLocation(const char* name) + { + foreach(ref module_;data.modules) + { + int location = glGetUniformLocation(module_.gl_handle,name); + if(location != -1)return location; + } + return -1; + } + + void pushBindings() + { + foreach(i;0..data.bindings.length) + { + glUniform1i(data.bindings[i],cast(int)i); + } + } + + void pushUniforms(void* ptr) + { + foreach(ref Uniform uniform; data.uniforms) + { + void* local_ptr = ptr + uniform.offset; + glUniform4fv(uniform.location,1,cast(float*)local_ptr); + } + } + + enum Type + { + float_, + float4 + } + + struct Uniform + { + Type type; + int location; + uint offset; + } + + struct Data + { + BlendMode blend_mode = BlendMode.opaque; + + ShaderModule[] modules; + + TransformMode mode; + + Uniform[] uniforms; + int[] bindings; + } + + Data* data; +} \ No newline at end of file diff --git a/demos/utils/source/ecs_utils/gfx/mesh.d b/demos/utils/source/ecs_utils/gfx/mesh.d new file mode 100644 index 0000000..346226f --- /dev/null +++ b/demos/utils/source/ecs_utils/gfx/mesh.d @@ -0,0 +1,121 @@ +module ecs_utils.gfx.mesh; + +import bindbc.sdl; + +import ecs.std; + +import ecs_utils.gfx.buffer; + +import glad.gl.gl; +//import mutils.serializer.json; + +extern(C): + +struct Mesh +{ + bool load(const char[] path) nothrow + { + struct LoadData + { + /*struct Vertex + { + struct Binding + { + @("malloc") string type; + uint stride; + } + @("malloc") Binding[] bindings; + } + Vertex vertex;*/ + @("malloc") ushort[] indices; + @("malloc") float[] vertices; + //int i; + + void dispose() nothrow + { + if(indices)Mallocator.dispose(indices); + if(vertices)Mallocator.dispose(vertices); + + /*foreach(binding; vertex.bindings)Mallocator.instance.dispose(cast(char[])binding.type); + + if(vertex.bindings)Mallocator.instance.dispose(vertex.bindings);*/ + } + } + + char[] cpath = (cast(char*)alloca(path.length+1))[0..path.length+1]; + cpath[0..$-1] = path[0..$]; + cpath[$-1] = 0; + + SDL_RWops* file = SDL_RWFromFile(cpath.ptr,"r");//SDL_LoadFile(cpath.ptr,); + if(file) + { + size_t size = cast(size_t)SDL_RWsize(file); + //data.code = Mallocator.instance.makeArray!char(size); + //data.code[$-1] = 0; + char[] buffer = Mallocator.makeArray!char(size); + SDL_RWread(file,buffer.ptr,size,1); + + LoadData load_data; + scope(exit)load_data.dispose(); + + /*JSONSerializer serializer = Mallocator.make!JSONSerializer; + scope(exit)Mallocator.dispose(serializer); + serializer.serialize!(Load.yes, true)(load_data,buffer);*/ + + indices = Mallocator.makeArray(load_data.indices); + /*vertex.create(); + Vertex.Binding[] bindings = (cast(Vertex.Binding*)alloca(Vertex.Binding.sizeof*load_data.vertex.bindings.length))[0..load_data.vertex.bindings.length]; + uint vertex_size = 0; + uint alignment = 4; + foreach(i, binding;load_data.vertex.bindings) + { + uint new_size = binding.stride; + bindings[i].stride = binding.stride; + if(binding.type == "float_rg") + { + bindings[i].type = Vertex.Type.float_rg; + new_size += 8; + } + if(new_size > vertex_size)vertex_size = new_size; + //new_size = new_size + (3 - (new_size)%alignment) + } + vertex.data.size = vertex_size; + vertex.attachBindings(bindings);*/ + + vertices = Mallocator.makeArray(load_data.vertices); + /*vertices = Mallocator.instance.makeArray!ubyte(vertex_size * load_data.vertices.length); + { + foreach() + }*/ + + SDL_RWclose(file); + load_data.dispose(); + return true; + } + else return false; + } + + void uploadData() nothrow + { + vbo.create(); + vbo.bufferData(Buffer.BindTarget.array,16,cast(uint)vertices.length,GL_STATIC_DRAW,vertices.ptr); + + ibo.create(); + ibo.bufferData(Buffer.BindTarget.element_array,2,cast(uint)indices.length,GL_STATIC_DRAW,indices.ptr); + } + + void bind() nothrow + { + vbo.bind(Buffer.BindTarget.array); + ibo.bind(Buffer.BindTarget.element_array); + + glVertexAttribPointer(0,2,GL_FLOAT,false,16,null); + glVertexAttribPointer(1,2,GL_FLOAT,false,16,cast(void*)8); + } + + float[] vertices; + ushort[] indices; + Buffer vbo; + Buffer ibo; + //Vertex vertex; +} \ No newline at end of file diff --git a/demos/utils/source/ecs_utils/gfx/mesh_module.d b/demos/utils/source/ecs_utils/gfx/mesh_module.d new file mode 100644 index 0000000..ecb4a3a --- /dev/null +++ b/demos/utils/source/ecs_utils/gfx/mesh_module.d @@ -0,0 +1,12 @@ +module ecs_utils.gfx.mesh_module; + +import ecs_utils.gfx.material; +import ecs_utils.gfx.texture; +import ecs_utils.gfx.mesh; + +struct MeshModule +{ + Mesh* mesh; + Material* material; + Texture texture; +} \ No newline at end of file diff --git a/demos/utils/source/ecs_utils/gfx/render_list.d b/demos/utils/source/ecs_utils/gfx/render_list.d new file mode 100644 index 0000000..f5ffabf --- /dev/null +++ b/demos/utils/source/ecs_utils/gfx/render_list.d @@ -0,0 +1,29 @@ +module ecs_utils.gfx.render_list; + +import ecs_utils.gfx.mesh_module; +import ecs_utils.math.vector; +import ecs_utils.math.matrix; +import ecs_utils.gfx.config; + +struct RenderList +{ + struct Data + { + MeshModule* module_; + uint index; + } + + struct LocScale + { + vec2 location; + vec2 scale; + } + + struct Layer + { + LayerType type; + Data[] list; + LocScale[] loc_scale; + mat3[] matrices; + } +} \ No newline at end of file diff --git a/demos/utils/source/ecs_utils/gfx/renderer.d b/demos/utils/source/ecs_utils/gfx/renderer.d new file mode 100644 index 0000000..5b151bc --- /dev/null +++ b/demos/utils/source/ecs_utils/gfx/renderer.d @@ -0,0 +1,817 @@ +module ecs_utils.gfx.renderer; + +import bindbc.sdl; + +import ecs.std; + +//import ecs_utils.core : Backend; +import ecs_utils.gfx.buffer; +import ecs_utils.gfx.texture; +import ecs_utils.math.vector; + +import glad.gl.gl; + +version = ver1; +/*version(ver5)version = vv2; +else version(ver6)version = vv2;*/ + +extern(C) float sinf(float); +extern(C) float cosf(float); + +enum RenderTechnique +{ + simple,//1 + simple_array,//2 + vbo_batch,//3 + instanced_attrib_divisor,//4 + uniform_buffer,//5 + uniform_buffer_indexed,//6 + uniform_buffer_multi_draw,//7 + uniform_buffer_instanced,//8 + uniform_buffer_instanced_mapped_gl2,//9 + uniform_buffer_instanced_mapped,//10 + uniform_buffer_instanced_persistent_mapped,//11 + uniform_buffer_instanced_persistent_mapped_coherent,//12 + ssbo_instanced,//13 + uniform_buffer_draw_indirect,//14 + uniform_buffer_multi_draw_indirect,//15 + uniform_buffer_multi_draw_indirect_arb_draw_parameters//16 +} + +struct Renderer +{ + //static SDL_Renderer* main_sdl_renderer; + + enum MaxObjects = 1024 * 64 * 4; + enum BufferUsage = GL_STATIC_DRAW; + + //SDL_Window* sdl_window; + //SDL_Renderer* sdl_renderer; + ivec2 resolution; + vec2 dres; + vec4 sdl_transform; + vec2 view_pos = vec2(-1,-1); + vec2 view_size = vec2(1,1); + + //uint[2] time_queries; + + Buffer[2] ubos; + int block_alignment = 1; + int block_max_size = 16384; + + struct IndirectDraw + { + uint count = 6; + uint instances = 1; + uint first_index = 0; + uint base_vertex = 0; + uint base_instance = 0; + } + + Buffer[2] batch_vbo; + Buffer[2] batch_ibo; + + float[] batch_vertices; + ushort[] batch_indices; + + Buffer indirect_buffer; + IndirectDraw[] indirect_block; + + Buffer id_buffer; + + int data_offset = 48; + int data_index; + ubyte[] uniform_block; + + struct RenderData + { + Texture texture; + uint material_id; + uint mesh_id; + } + + RenderData[] render_list; + uint item_id; + + uint[] multi_count; + uint[] multi_offset; + + alias Technique = RenderTechnique; + + __gshared Technique technique = Technique.simple; + void* data_ptr; + + //import ecs_utils.core : RenderTechnique; + + + + void initialize() + { + //this.technique = __ecs_used_technique; + __initialize(this); + } + + private static void __initialize_gl(ref Renderer this_) + { + with(this_) + { + //glGenQueries(2, time_queries.ptr); + + version(WebAssembly) + { + + } + else + { + glGetIntegerv(GL_MAX_UNIFORM_BLOCK_SIZE, &block_max_size); + glGetIntegerv(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, &block_alignment); + } + + //ubos[0].bufferStorage(1,64*MaxObjects,null); + + switch(technique) + { + case Technique.simple: + uniform_block = Mallocator.makeArray!ubyte(64*MaxObjects); + data_ptr = uniform_block.ptr; + data_offset = cast(ushort)((data_offset + block_alignment - 1) & (-cast(int) block_alignment)); + break; + case Technique.simple_array: + goto case(Technique.simple); + case Technique.vbo_batch: + batch_vbo[0].create(); + batch_ibo[0].create(); + batch_vbo[0].bufferData(Buffer.BindTarget.array,16,4*MaxObjects,BufferUsage,null); + batch_ibo[0].bufferData(Buffer.BindTarget.element_array,2,6*MaxObjects,BufferUsage,null); + + batch_vbo[1].create(); + batch_ibo[1].create(); + batch_vbo[1].bufferData(Buffer.BindTarget.array,16,4*MaxObjects,BufferUsage,null); + batch_ibo[1].bufferData(Buffer.BindTarget.element_array,2,6*MaxObjects,BufferUsage,null); + + batch_vertices = Mallocator.makeArray!float(16*MaxObjects); + batch_indices = Mallocator.makeArray!ushort(6*MaxObjects); + break; + case Technique.instanced_attrib_divisor: + goto case(Technique.uniform_buffer_indexed); + case Technique.uniform_buffer: + ubos[0].create(); + ubos[0].bufferData(Buffer.BindTarget.uniform,1,64*MaxObjects,BufferUsage,null); + ubos[1].create(); + ubos[1].bufferData(Buffer.BindTarget.uniform,1,64*MaxObjects,BufferUsage,null); + goto case(Technique.simple); + case Technique.uniform_buffer_indexed: + ubos[0].create(); + ubos[0].bufferData(Buffer.BindTarget.uniform,1,64*MaxObjects,BufferUsage,null); + ubos[1].create(); + ubos[1].bufferData(Buffer.BindTarget.uniform,1,64*MaxObjects,BufferUsage,null); + uniform_block = Mallocator.makeArray!ubyte(64*MaxObjects); + data_ptr = uniform_block.ptr; + break; + /*case Technique.uniform_buffer_multi_draw: + multi_count = Mallocator.makeArray!uint(992,6); + multi_offset = Mallocator.makeArray!uint(992,0); + + { + uint[] indices = Mallocator.makeArray!uint(992); + scope(exit)Mallocator.dispose(indices); + foreach(i;0..992)indices[i]=i; + id_buffer.create(); + id_buffer.bufferData(uint.sizeof,992,BufferUsage,indices.ptr); + } + goto case(Technique.uniform_buffer_multi_draw_indirect_arb_draw_parameters);*/ + case Technique.uniform_buffer_instanced: + goto case(Technique.uniform_buffer_indexed); + case Technique.uniform_buffer_instanced_mapped_gl2: + ubos[0].create(); + ubos[0].bufferData(Buffer.BindTarget.uniform,1,512*MaxObjects,BufferUsage,null); + ubos[0].map(Buffer.BindTarget.uniform); + ubos[1].create(); + ubos[1].bufferData(Buffer.BindTarget.uniform,1,512*MaxObjects,BufferUsage,null); + ubos[1].map(Buffer.BindTarget.uniform); + data_ptr = ubos[0].mappedPointer(); + break; + case Technique.uniform_buffer_instanced_mapped: + ubos[0].create(); + ubos[0].bufferData(Buffer.BindTarget.uniform,1,64*MaxObjects,BufferUsage,null); + ubos[0].map(0, 64*MaxObjects, Buffer.BindTarget.uniform); + ubos[1].create(); + ubos[1].bufferData(Buffer.BindTarget.uniform,1,64*MaxObjects,BufferUsage,null); + ubos[1].map(0, 64*MaxObjects, Buffer.BindTarget.uniform); + data_ptr = ubos[0].mappedPointer(); + break; + /*case Technique.uniform_buffer_instanced_persistent_mapped: + ubos[0].create(); + ubos[0].bufferStorage(1,64*MaxObjects,null,Buffer.StorageFlagBits.write|Buffer.StorageFlagBits.persistent); + ubos[0].map(0, 64*MaxObjects, Buffer.BindTarget.uniform, Buffer.MapFlagBits.write | Buffer.MapFlagBits.persistent | Buffer.MapFlagBits.flush_explict); + data_ptr = ubos[0].mappedPointer(); + break; + case Technique.uniform_buffer_instanced_persistent_mapped_coherent: + ubos[0].create(); + ubos[0].bufferStorage(1,64*MaxObjects,null,Buffer.StorageFlagBits.write|Buffer.StorageFlagBits.persistent|Buffer.StorageFlagBits.coherent); + ubos[0].map(0, 64*MaxObjects, Buffer.BindTarget.uniform, Buffer.MapFlagBits.write | Buffer.MapFlagBits.persistent | Buffer.MapFlagBits.flush_explict | Buffer.MapFlagBits.coherent); + ubos[1].create(); + ubos[1].bufferStorage(1,64*MaxObjects,null,Buffer.StorageFlagBits.write|Buffer.StorageFlagBits.persistent|Buffer.StorageFlagBits.coherent); + ubos[1].map(0, 64*MaxObjects, Buffer.BindTarget.uniform, Buffer.MapFlagBits.write | Buffer.MapFlagBits.persistent | Buffer.MapFlagBits.flush_explict | Buffer.MapFlagBits.coherent); + data_ptr = ubos[0].mappedPointer(); + break; + case Technique.ssbo_instanced: + goto case(Technique.uniform_buffer_indexed); + case Technique.uniform_buffer_draw_indirect: + indirect_block = Mallocator.makeArray!IndirectDraw(1); + indirect_buffer.create(); + indirect_buffer.bufferData(IndirectDraw.sizeof,1,BufferUsage,indirect_block.ptr); + indirect_buffer.bind(Buffer.BindTarget.indirect); + goto case(Technique.uniform_buffer); + case Technique.uniform_buffer_multi_draw_indirect: + goto case(Technique.uniform_buffer_multi_draw_indirect_arb_draw_parameters); + case Technique.uniform_buffer_multi_draw_indirect_arb_draw_parameters: + indirect_block = Mallocator.makeArray!IndirectDraw(992); + foreach(i;0..992) + { + IndirectDraw* idraw = &indirect_block[i]; + idraw.base_instance = i; + } + indirect_buffer.create(); + indirect_buffer.bufferData(IndirectDraw.sizeof,992,BufferUsage,indirect_block.ptr); + indirect_buffer.bind(Buffer.BindTarget.indirect); + goto case(Technique.uniform_buffer_indexed);*/ + default:break; + }//*/ + + // if(batching)data_offset = cast(ushort)((data_offset + block_alignment - 1) & (-cast(int) block_alignment)); + //data_offset = cast(ushort)((data_offset + block_alignment - 1) & (-cast(int) block_alignment)); + + /*version(ver4){} + else version(ver5){} + else version(ver6){} + else data_offset = cast(ushort)((data_offset + block_alignment - 1) & (-cast(int) block_alignment));//*/ + //data_offset = (data_offset + block_alignment - 1) - data_offset % block_alignment; + + render_list = Mallocator.makeArray!RenderData(MaxObjects); + + SDL_Log("Uniform block alignment: %u",block_alignment); + SDL_Log("Uniform block max size: %u",block_max_size); + SDL_Log("Data offset: %u",data_offset); + } + } + + private static void __initialize_sdl(ref Renderer this_) + { + + } + + void draw(Texture tex, vec2 pos, vec2 size, vec4 coords, float angle = 0, uint material_id = 0, uint mesh_id = 0) + { + __draw(this,tex,pos,size,coords,angle,material_id,mesh_id); + } + + private static void __draw_sdl(ref Renderer this_, Texture tex, vec2 pos, vec2 size, vec4 coords, float angle, uint material_id, uint mesh_id) + { + /*with(this_) + { + SDL_Rect rect = SDL_Rect(cast(int)(coords.x*tex.data.size.x),cast(int)(coords.y*tex.data.size.y),cast(int)(coords.z*tex.data.size.x),cast(int)(coords.w*tex.data.size.y)); + SDL_Rect rect2 = SDL_Rect(cast(int)((pos.x-size.x*0.5)), + cast(int)(resolution.y - pos.y - size.y*0.5), + cast(int)(size.x), + cast(int)(size.y)); + + SDL_RenderCopyEx(sdl_renderer, + tex.data.texture, + &rect, + &rect2, + angle*360, + null, + SDL_FLIP_NONE); + }*/ + } + + private static void __draw_gl(ref Renderer this_, Texture tex, vec2 pos, vec2 size, vec4 coords, float angle, uint material_id, uint mesh_id) + { + //import core.stdc.string; + with(this_) + { + //pos += view_pos; + size.x *= view_size.x; + size.y *= view_size.y; + pos.x = pos.x * view_size.x + view_pos.x; + pos.y = pos.y * view_size.y + view_pos.y;//*/ + + /*version(ver6)void* ptr = ubos[0].mappedPointer() + data_index; + else void* ptr = uniform_block.ptr + data_index;*/ + if(data_ptr is null)return; + void* ptr = data_ptr + data_index; + if(angle == 0) + { + *cast(float*)ptr = size.x; + *cast(float*)(ptr+4) = 0; + *cast(float*)(ptr+8) = 0; + *cast(float*)(ptr+12) = size.y; + } + else + { + //import core.stdc.math; + float sinn = sinf(angle); + float coss = cosf(angle); + *cast(float*)ptr = coss * size.x; + *cast(float*)(ptr+4) = -sinn * size.y; + *cast(float*)(ptr+8) = sinn * size.x; + *cast(float*)(ptr+12) = coss * size.y; + } + + //memcpy(ptr,); + memcpy(ptr+16,pos.data.ptr,8); + memcpy(ptr+32,coords.data.ptr,16); + + //render_list[item_id] = RenderData(tex,material_id,mesh_id); + render_list[item_id].texture = tex; + render_list[item_id].material_id = material_id; + render_list[item_id].mesh_id = mesh_id; + + data_index += data_offset; + item_id++; + } + } + + private static void __draw_gl_vbo_batch(ref Renderer this_, Texture tex, vec2 pos, vec2 size, vec4 coords, float angle, uint material_id, uint mesh_id) + { + import ecs_utils.gfx.config; + //import core.stdc.string; + with(this_) + { + //pos += view_pos; + size.x *= view_size.x; + size.y *= view_size.y; + pos.x = pos.x * view_size.x + view_pos.x; + pos.y = pos.y * view_size.y + view_pos.y;//*/ + + /*void* ptr = data_ptr + data_index; + *cast(float*)ptr = size.x; + *cast(float*)(ptr+4) = 0; + *cast(float*)(ptr+8) = 0; + *cast(float*)(ptr+12) = size.y; + //memcpy(ptr,); + memcpy(ptr+16,pos.data.ptr,8); + memcpy(ptr+32,coords.data.ptr,16);*/ + + if(angle == 0) + { + batch_vertices[item_id*16] = GfxConfig.meshes[mesh_id].vertices[0] * size.x + pos.x; + batch_vertices[item_id*16+1] = GfxConfig.meshes[mesh_id].vertices[1] * size.y + pos.y; + batch_vertices[item_id*16+4] = GfxConfig.meshes[mesh_id].vertices[4] * size.x + pos.x; + batch_vertices[item_id*16+5] = GfxConfig.meshes[mesh_id].vertices[5] * size.y + pos.y; + batch_vertices[item_id*16+8] = GfxConfig.meshes[mesh_id].vertices[8] * size.x + pos.x; + batch_vertices[item_id*16+9] = GfxConfig.meshes[mesh_id].vertices[9] * size.y + pos.y; + batch_vertices[item_id*16+12] = GfxConfig.meshes[mesh_id].vertices[12] * size.x + pos.x; + batch_vertices[item_id*16+13] = GfxConfig.meshes[mesh_id].vertices[13] * size.y + pos.y; + } + else + { + //import core.stdc.math; + float sinn = sinf(angle); + float coss = cosf(angle); + + /*batch_vertices[item_id*16] = GfxConfig.meshes[mesh_id].vertices[0] * size.x; + batch_vertices[item_id*16+1] = GfxConfig.meshes[mesh_id].vertices[1] * size.y; + batch_vertices[item_id*16+4] = GfxConfig.meshes[mesh_id].vertices[4] * size.x; + batch_vertices[item_id*16+5] = GfxConfig.meshes[mesh_id].vertices[5] * size.y; + batch_vertices[item_id*16+8] = GfxConfig.meshes[mesh_id].vertices[8] * size.x; + batch_vertices[item_id*16+9] = GfxConfig.meshes[mesh_id].vertices[9] * size.y; + batch_vertices[item_id*16+12] = GfxConfig.meshes[mesh_id].vertices[12] * size.x; + batch_vertices[item_id*16+13] = GfxConfig.meshes[mesh_id].vertices[13] * size.y;*/ + + batch_vertices[item_id*16] = (GfxConfig.meshes[mesh_id].vertices[0] * coss + GfxConfig.meshes[mesh_id].vertices[1] * sinn) * size.x + pos.x; + batch_vertices[item_id*16+1] = (GfxConfig.meshes[mesh_id].vertices[1] * coss - GfxConfig.meshes[mesh_id].vertices[0] * sinn) * size.y + pos.y; + batch_vertices[item_id*16+4] = (GfxConfig.meshes[mesh_id].vertices[4] * coss + GfxConfig.meshes[mesh_id].vertices[5] * sinn) * size.x + pos.x; + batch_vertices[item_id*16+5] = (GfxConfig.meshes[mesh_id].vertices[5] * coss - GfxConfig.meshes[mesh_id].vertices[4] * sinn) * size.y + pos.y; + batch_vertices[item_id*16+8] = (GfxConfig.meshes[mesh_id].vertices[8] * coss + GfxConfig.meshes[mesh_id].vertices[9] * sinn) * size.x + pos.x; + batch_vertices[item_id*16+9] = (GfxConfig.meshes[mesh_id].vertices[9] * coss - GfxConfig.meshes[mesh_id].vertices[8] * sinn) * size.y + pos.y; + batch_vertices[item_id*16+12] = (GfxConfig.meshes[mesh_id].vertices[12] * coss + GfxConfig.meshes[mesh_id].vertices[13] * sinn) * size.x + pos.x; + batch_vertices[item_id*16+13] = (GfxConfig.meshes[mesh_id].vertices[13] * coss - GfxConfig.meshes[mesh_id].vertices[12] * sinn) * size.y + pos.y; + } + + batch_vertices[item_id*16+2] = GfxConfig.meshes[mesh_id].vertices[2] * coords.z + coords.x; + batch_vertices[item_id*16+3] = GfxConfig.meshes[mesh_id].vertices[3] * coords.w + coords.y; + batch_vertices[item_id*16+6] = GfxConfig.meshes[mesh_id].vertices[6] * coords.z + coords.x; + batch_vertices[item_id*16+7] = GfxConfig.meshes[mesh_id].vertices[7] * coords.w + coords.y; + batch_vertices[item_id*16+10] = GfxConfig.meshes[mesh_id].vertices[10] * coords.z + coords.x; + batch_vertices[item_id*16+11] = GfxConfig.meshes[mesh_id].vertices[11] * coords.w + coords.y; + batch_vertices[item_id*16+14] = GfxConfig.meshes[mesh_id].vertices[14] * coords.z + coords.x; + batch_vertices[item_id*16+15] = GfxConfig.meshes[mesh_id].vertices[15] * coords.w + coords.y; + + uint ind_id = item_id % 16_384; + + batch_indices[item_id*6] = cast(ushort)(GfxConfig.meshes[mesh_id].indices[0] + ind_id*4); + batch_indices[item_id*6+1] = cast(ushort)(GfxConfig.meshes[mesh_id].indices[1] + ind_id*4); + batch_indices[item_id*6+2] = cast(ushort)(GfxConfig.meshes[mesh_id].indices[2] + ind_id*4); + batch_indices[item_id*6+3] = cast(ushort)(GfxConfig.meshes[mesh_id].indices[3] + ind_id*4); + batch_indices[item_id*6+4] = cast(ushort)(GfxConfig.meshes[mesh_id].indices[4] + ind_id*4); + batch_indices[item_id*6+5] = cast(ushort)(GfxConfig.meshes[mesh_id].indices[5] + ind_id*4); + + //render_list[item_id] = RenderData(tex,material_id,mesh_id); + render_list[item_id].texture = tex; + render_list[item_id].material_id = material_id; + render_list[item_id].mesh_id = mesh_id; + + //data_index += 1;//data_offset; + item_id++; + } + } + + void clear() + { + __clear(this); + } + + private static void __clear_sdl(ref Renderer this_) + { + //SDL_RenderClear(this_.sdl_renderer); + } + + private static void __clear_gl(ref Renderer this_) + { + glClearColor(0,0,0,0); + glViewport(0,0,this_.resolution.x,this_.resolution.y); + glClear(GL_COLOR_BUFFER_BIT);// | GL_DEPTH_BUFFER_BIT); + glDisable(GL_DEPTH_TEST); + glDisable(GL_CULL_FACE); + } + + void present() + { + __present(this); + } + + private static void __present_sdl(ref Renderer this_) + { + //+SDL_RenderPresent(this_.sdl_renderer); + } + + private static void __present_gl(ref Renderer this_) + { + glViewport(0,0,this_.resolution.x,this_.resolution.y); + //glEnable(GL_ALPHA_TEST); + //glAlphaFunc(GL_GREATER, 0.01); + glEnableVertexAttribArray(0); + glEnableVertexAttribArray(1); + import ecs_utils.gfx.config; + with(this_) + { + bool instanced = false; + bool indirect = false; + bool multi_draw = false; + Buffer.BindTarget buffer_target = Buffer.BindTarget.uniform; + + switch(technique) + { + case Technique.simple: + break; + case Technique.simple_array: + break; + case Technique.vbo_batch: + //if(data_index){ + batch_vbo[0].bufferSubData(item_id*4*16,0,batch_vertices.ptr); + batch_ibo[0].bufferSubData(item_id*6*2,0,batch_indices.ptr); + + batch_vbo[0].bind(Buffer.BindTarget.array); + batch_ibo[0].bind(Buffer.BindTarget.element_array); + + glVertexAttribPointer(0,2,GL_FLOAT,false,16,null); + glVertexAttribPointer(1,2,GL_FLOAT,false,16,cast(void*)8);//} + break; + case Technique.instanced_attrib_divisor: + ubos[0].bufferSubData(data_index,0,uniform_block.ptr); + ubos[0].bind(Buffer.BindTarget.array); + glEnableVertexAttribArray(2); + glEnableVertexAttribArray(3); + glEnableVertexAttribArray(4); + + glVertexAttribPointer(2,4,GL_FLOAT,false,48,null); + glVertexAttribPointer(3,4,GL_FLOAT,false,48,cast(void*)16); + glVertexAttribPointer(4,4,GL_FLOAT,false,48,cast(void*)32); + glVertexAttribDivisor(2,1); + glVertexAttribDivisor(3,1); + glVertexAttribDivisor(4,1); + //ubos[0].bindRange(Buffer.BindTarget.uniform,0,0,block_max_size); + break; + case Technique.uniform_buffer: + //ubos[0].bufferData(1,64*MaxObjects,BufferUsage,null); + /*if(data_index)*/ubos[0].bufferSubData(data_index,0,uniform_block.ptr); + break; + case Technique.uniform_buffer_indexed: + ubos[0].bindRange(Buffer.BindTarget.uniform,0,0,block_max_size); + goto case(Technique.uniform_buffer); + case Technique.uniform_buffer_multi_draw: + id_buffer.bind(Buffer.BindTarget.array); + glEnableVertexAttribArray(2); + + glVertexAttribIPointer(2,1,GL_UNSIGNED_INT,cast(uint)uint.sizeof,cast(void*)0); + glVertexAttribDivisor(2,1); + multi_draw = true; + goto case(Technique.uniform_buffer_instanced); + case Technique.uniform_buffer_instanced: + instanced = true; + goto case(Technique.uniform_buffer); + case Technique.uniform_buffer_instanced_mapped_gl2: + instanced = true; + ubos[0].unmap(Buffer.BindTarget.uniform); + break; + case Technique.uniform_buffer_instanced_mapped: + instanced = true; + ubos[0].flush(0,data_index,Buffer.BindTarget.uniform); + ubos[0].unmap(Buffer.BindTarget.uniform); + break; + /*case Technique.uniform_buffer_instanced_persistent_mapped: + instanced = true; + ubos[0].flush(0,data_index,Buffer.BindTarget.uniform); + //glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT); + break; + case Technique.uniform_buffer_instanced_persistent_mapped_coherent: + instanced = true; + break; + //ubos[0].flush(0,data_index,Buffer.BindTarget.uniform); + //goto case(Technique.uniform_buffer_instanced_mapped); + case Technique.ssbo_instanced: + //buffer_target = Buffer.BindTarget.shader_storage; + ubos[0].bindRange(Buffer.BindTarget.shader_storage,0,0,48*MaxObjects); + goto case(Technique.uniform_buffer_instanced); + case Technique.uniform_buffer_draw_indirect: + goto case(Technique.uniform_buffer); + case Technique.uniform_buffer_multi_draw_indirect: + indirect_buffer.bind(Buffer.BindTarget.array); + glEnableVertexAttribArray(2); + + glVertexAttribIPointer(2,1,GL_UNSIGNED_INT,cast(uint)IndirectDraw.sizeof,cast(void*)(4*uint.sizeof)); + glVertexAttribDivisor(2,1); + goto case(Technique.uniform_buffer_multi_draw_indirect_arb_draw_parameters); + case Technique.uniform_buffer_multi_draw_indirect_arb_draw_parameters: + indirect = true; + goto case(Technique.uniform_buffer_instanced);*/ + default:break; + } + + data_index = 0; + + int mesh_id = -1; + int material_id = -1; + int ubo_start = -1; + Texture texture; + uint item_ubo_id = 0; + + /*Buffer tmpb = ubos[0]; + ubos[0] = ubos[1]; + ubos[1] = tmpb; + + tmpb = batch_vbo[0]; + batch_vbo[0] = batch_vbo[1]; + batch_vbo[1] = tmpb; + + tmpb = batch_ibo[0]; + batch_ibo[0] = batch_ibo[1]; + batch_ibo[1] = tmpb;//*/ + //glFinish(); + + //glBeginQuery(GL_TIME_ELAPSED, time_queries[0]); + if(technique == Technique.vbo_batch) + { + uint items = item_id/16_384+1; + foreach(i; 0..items) + { + if(material_id != render_list[i].material_id) + { + material_id = render_list[i].material_id; + GfxConfig.materials[material_id].bind(); + } + if(texture.data != render_list[i].texture.data) + { + texture.data = render_list[i].texture.data; + render_list[i].texture.bind(); + } + + uint instance_count = 16_384; + if(i*16_384 > item_id) + { + instance_count = i*16_384 - item_id; + } + + /*glVertexAttribPointer(0,2,GL_FLOAT,false,16,cast(void*)(i*16_384*4*16)); + glVertexAttribPointer(1,2,GL_FLOAT,false,16,cast(void*)(i*16_384*4*16+8)); + + glDrawElements(GL_TRIANGLES,instance_count*6,GL_UNSIGNED_SHORT,cast(void*)(i*16_384*6*2));*/ + + glDrawElementsBaseVertex(GL_TRIANGLES,instance_count*6,GL_UNSIGNED_SHORT,cast(void*)(i*16_384*6*2),i*16_384*4); + } + } + else if(technique == Technique.ssbo_instanced || technique == Technique.instanced_attrib_divisor) + { + if(mesh_id != render_list[0].mesh_id) + { + mesh_id = render_list[0].mesh_id; + GfxConfig.meshes[mesh_id].bind(); + } + if(material_id != render_list[0].material_id) + { + material_id = render_list[0].material_id; + GfxConfig.materials[material_id].bind(); + } + if(texture.data != render_list[0].texture.data) + { + texture.data = render_list[0].texture.data; + render_list[0].texture.bind(); + } + glDrawArraysInstanced(GL_TRIANGLE_STRIP,0,4,item_id); + //glDrawElementsInstanced(GL_TRIANGLES,6,GL_UNSIGNED_SHORT,null,item_id); + } + else if(instanced) + { + uint items = item_id/992+1; + foreach(i; 0..items) + { + if(mesh_id != render_list[i].mesh_id) + { + mesh_id = render_list[i].mesh_id; + GfxConfig.meshes[mesh_id].bind(); + } + if(material_id != render_list[i].material_id) + { + material_id = render_list[i].material_id; + GfxConfig.materials[material_id].bind(); + } + if(texture.data != render_list[i].texture.data) + { + texture.data = render_list[0].texture.data; + render_list[i].texture.bind(); + } + ubos[0].bindRange(buffer_target,0,data_index,block_max_size); + + uint instance_count = 992; + if(i*992 > item_id) + { + instance_count = i*992 - item_id; + } + + /*if(indirect)glMultiDrawElementsIndirect(GL_TRIANGLES, GL_UNSIGNED_SHORT, cast(void*)0, instance_count, 0); + else if(multi_draw)glMultiDrawElements(GL_TRIANGLES,cast(int*)multi_count.ptr,GL_UNSIGNED_SHORT,cast(void**)multi_offset.ptr,instance_count); + //glMultiDrawElementsBaseVertex(GL_TRIANGLES,cast(int*)multi_count.ptr,GL_UNSIGNED_SHORT,cast(void**)multi_offset.ptr,instance_count,cast(int*)multi_offset.ptr); + else */glDrawElementsInstanced(GL_TRIANGLES,6,GL_UNSIGNED_SHORT,null,instance_count); + //glDrawArraysInstanced(GL_TRIANGLES,0,6,instance_count); + data_index += data_offset * 992; + } + } + else + foreach(item; render_list[0..item_id]) + { + if(mesh_id != item.mesh_id) + { + mesh_id = item.mesh_id; + GfxConfig.meshes[mesh_id].bind(); + } + if(material_id != item.material_id) + { + material_id = item.material_id; + GfxConfig.materials[material_id].bind(); + GfxConfig.materials[material_id].pushBindings(); + } + if(texture.data != item.texture.data) + { + texture.data = render_list[0].texture.data; + item.texture.bind(); + } + + switch(technique) + { + case Technique.simple: + /*glUniform4f(0, *cast(float*)&uniform_block[data_index], *cast(float*)&uniform_block[data_index+4], *cast(float*)&uniform_block[data_index+8], *cast(float*)&uniform_block[data_index+12]); + glUniform4f(1, *cast(float*)&uniform_block[data_index+16], *cast(float*)&uniform_block[data_index+20], *cast(float*)&uniform_block[data_index+24], *cast(float*)&uniform_block[data_index+28]); + glUniform4f(2, *cast(float*)&uniform_block[data_index+32], *cast(float*)&uniform_block[data_index+36], *cast(float*)&uniform_block[data_index+40], *cast(float*)&uniform_block[data_index+44]); + */ + GfxConfig.materials[material_id].pushUniforms(&uniform_block[data_index]);break; + case Technique.simple_array: + glUniform4fv(0,12,cast(float*)(uniform_block.ptr+data_index)); + break; + case Technique.uniform_buffer: + ubos[0].bindRange(Buffer.BindTarget.uniform,0,data_index,data_offset); + break; + /*case Technique.uniform_buffer_draw_indirect: + ubos[0].bindRange(Buffer.BindTarget.uniform,0,data_index,data_offset); + glDrawElementsIndirect(GL_TRIANGLES,GL_UNSIGNED_SHORT,null); + data_index += data_offset; + continue;*/ + case Technique.uniform_buffer_indexed: + if(item_ubo_id >= 992) + { + item_ubo_id = 0; + ubo_start = data_index; + ubos[0].bindRange(Buffer.BindTarget.uniform,0,ubo_start,block_max_size); + } + glUniform1i(0,item_ubo_id++); + break; + default:break; + }//*/ + + /*version(ver3)ubos[0].bindRange(Buffer.BindTarget.uniform,0,data_index,data_offset); + else version(ver1) + { + glUniform4f(0, *cast(float*)&uniform_block[data_index], *cast(float*)&uniform_block[data_index+4], *cast(float*)&uniform_block[data_index+8], *cast(float*)&uniform_block[data_index+12]); + glUniform4f(1, *cast(float*)&uniform_block[data_index+16], *cast(float*)&uniform_block[data_index+20], *cast(float*)&uniform_block[data_index+24], *cast(float*)&uniform_block[data_index+28]); + glUniform4f(2, *cast(float*)&uniform_block[data_index+32], *cast(float*)&uniform_block[data_index+36], *cast(float*)&uniform_block[data_index+40], *cast(float*)&uniform_block[data_index+44]); + } + else version(ver2)glUniform4fv(0,12,cast(float*)(uniform_block.ptr+data_index)); + else version(ver4) + { + if(item_ubo_id >= 992) + { + item_ubo_id = 0; + ubo_start = data_index; + ubos[0].bindRange(Buffer.BindTarget.uniform,0,ubo_start,block_max_size); + } + glUniform1i(0,item_ubo_id++); + }//*/ + + glDrawElements(GL_TRIANGLES,6,GL_UNSIGNED_SHORT,null); + //glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); + data_index += data_offset; + } + //glEndQuery(GL_TIME_ELAPSED); + //uint tmpq = time_queries[0]; + //time_queries[0] = time_queries[1]; + //time_queries[1] = tmpq; + /*Buffer tmpb = ubos[0]; + ubos[0] = ubos[1]; + ubos[1] = tmpb;//*/ + + data_index = 0; + //data_offset = 0; + item_id = 0; + //SDL_GL_SwapWindow(sdl_window); + //glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT); + //version(ver6)ubos[0].map(0, 64*MaxObjects, Buffer.BindTarget.uniform); + //ubos[0].map(Buffer.BindTarget.uniform); + + switch(technique) + { + case Technique.uniform_buffer_instanced_mapped_gl2: + ubos[0].map(Buffer.BindTarget.uniform); + //data_ptr = ubos[0].mappedPointer(); + break; + case Technique.uniform_buffer_instanced_mapped: + ubos[0].map(0, 64*MaxObjects, Buffer.BindTarget.uniform); + //data_ptr = ubos[0].mappedPointer(); + break; + default:break; + } + + if(ubos[0].data && ubos[0].mappedPointer) + { + data_ptr = ubos[0].mappedPointer; + } + + /*switch(technique) + { + case Technique.simple: + case Technique.simple_array: + case Technique.uniform_buffer: + case Technique.uniform_buffer_indexed: + case Technique.uniform_buffer_instanced: + case Technique.uniform_buffer_instanced_mapped: + case Technique.uniform_buffer_instanced_persistent_mapped: + default:break; + }*/ + } + glDisableVertexAttribArray(0); + glDisableVertexAttribArray(1); + /*glUseProgram(0); + glBindBuffer(GL_ARRAY_BUFFER, 0); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);*/ + //glDisable(GL_ALPHA_TEST); + } + + void resize(ivec2 size) + { + resolution = size; + dres = vec2(1.0/cast(float)size.x,1.0/cast(float)size.y); + } + + void view(vec2 pos, vec2 size) + { + view_pos = pos * size - 1; + view_size = vec2(2/size.x,2/size.y); + sdl_transform = vec4(0,0,1.0/size.x,1.0/size.y); + } + + static void function(ref Renderer this_, Texture tex, vec2 pos, vec2 size, vec4 coords, float angle, uint material_id, uint mesh_id) __draw; + static void function(ref Renderer this_) __present; + static void function(ref Renderer this_) __clear; + static void function(ref Renderer this_) __initialize; + + static void __loadBackend() + { + //this.technique = __ecs_used_technique; + if(technique == Technique.vbo_batch)__draw = &__draw_gl_vbo_batch; + else __draw = &__draw_gl; + __present = &__present_gl; + __clear = &__clear_gl; + __initialize = &__initialize_gl; + } + +} \ No newline at end of file diff --git a/demos/utils/source/ecs_utils/gfx/shader.d b/demos/utils/source/ecs_utils/gfx/shader.d new file mode 100644 index 0000000..f7cd21a --- /dev/null +++ b/demos/utils/source/ecs_utils/gfx/shader.d @@ -0,0 +1,171 @@ +module ecs_utils.gfx.shader; + +import bindbc.sdl; + +import ecs.std; + +import glad.gl.gl; + +//version = ver1; + +struct Shader +{ + + void create() nothrow + { + data = Mallocator.make!Data; + } + + bool load(const char[] path) nothrow + { + if(data is null)data = Mallocator.make!Data; + + char[] cpath = (cast(char*)alloca(path.length+1))[0..path.length+1]; + cpath[0..$-1] = path[0..$]; + cpath[$-1] = 0; + + int ind = cast(int)path.length - 1; + for(;ind>0;ind--) + { + if(path[ind] == '.')break; + } + if(ind < 0)return false; + ind++; + if(ind + 2 > path.length)return false; + + char[2] ext = path[ind .. ind + 2]; + if(ext[0] == 'v' && ext[1] == 'p')data.type = Type.vertex; + else if(ext[0] == 'f' && ext[1] == 'p')data.type = Type.fragment; + else return false; + + SDL_RWops* file = SDL_RWFromFile(cpath.ptr,"r");//SDL_LoadFile(cpath.ptr,); + if(file) + { + size_t size = cast(size_t)SDL_RWsize(file); + data.code = Mallocator.makeArray!char(size+1); + data.code[$-1] = 0; + SDL_RWread(file,data.code.ptr,size,1); + + SDL_RWclose(file); + return true; + } + else return false; + + } + + bool compile() nothrow + { + switch(data.type) + { + case Type.vertex: + data.gl_handle = glCreateShader(GL_VERTEX_SHADER); + break; + case Type.fragment: + data.gl_handle = glCreateShader(GL_FRAGMENT_SHADER); + break; + default: return false; + } + + version(WebAssembly)const char* glsl = "#version 100\n"; + else const char* glsl = "#version 450\n"; + const char* buffer = data.code.ptr; + char* ver; + version(WebAssembly)ver = cast(char*)"#define ver1 1\n#define GLES\n".ptr; + else ver = cast(char*)"#define ver1 1\n".ptr; + /*switch(__ecs_used_technique) + { + case RenderTechnique.simple: + ver = cast(char*)"#define ver1 1\n".ptr; + break; + case RenderTechnique.simple_array: + ver = cast(char*)"#define ver2 1\n".ptr; + break; + case RenderTechnique.vbo_batch: + ver = cast(char*)"#define ver10 1\n".ptr; + break; + case RenderTechnique.instanced_attrib_divisor: + ver = cast(char*)"#define ver8 1\n".ptr; + break; + case RenderTechnique.uniform_buffer: + ver = cast(char*)"#define ver3 1\n".ptr; + break; + case RenderTechnique.uniform_buffer_indexed: + ver = cast(char*)"#define ver4 1\n".ptr; + break; + case RenderTechnique.uniform_buffer_multi_draw: + goto case(RenderTechnique.uniform_buffer_multi_draw_indirect); + case RenderTechnique.uniform_buffer_instanced: + ver = cast(char*)"#define ver5 1\n".ptr; + break; + case RenderTechnique.uniform_buffer_instanced_mapped_gl2: + goto case(RenderTechnique.uniform_buffer_instanced); + case RenderTechnique.uniform_buffer_instanced_mapped: + goto case(RenderTechnique.uniform_buffer_instanced); + case RenderTechnique.uniform_buffer_instanced_persistent_mapped: + goto case(RenderTechnique.uniform_buffer_instanced); + case RenderTechnique.uniform_buffer_instanced_persistent_mapped_coherent: + goto case(RenderTechnique.uniform_buffer_instanced); + case RenderTechnique.ssbo_instanced: + ver = cast(char*)"#define ver6 1\n".ptr; + break; + case RenderTechnique.uniform_buffer_draw_indirect: + goto case(RenderTechnique.uniform_buffer); + case RenderTechnique.uniform_buffer_multi_draw_indirect: + ver = cast(char*)"#define ver9 1\n".ptr; + break; + case RenderTechnique.uniform_buffer_multi_draw_indirect_arb_draw_parameters: + ver = cast(char*)"#define ver7 1\n".ptr; + break; + default:break; + }*/ + /*version(ver1)const char* ver = "#define ver1 1\n"; + version(ver2)const char* ver = "#define ver2 1\n"; + version(ver3)const char* ver = "#define ver3 1\n"; + version(ver4)const char* ver = "#define ver4 1\n"; + version(ver5)const char* ver = "#define ver5 1\n"; + version(ver6)const char* ver = "#define ver5 1\n";*/ + + const char*[3] input = [glsl,ver,buffer]; + + glShaderSource(data.gl_handle,3,input.ptr,null); + + glCompileShader(data.gl_handle); + + int compile; + glGetShaderiv(data.gl_handle,GL_COMPILE_STATUS,&compile); + if(compile == GL_FALSE) + { + SDL_Log("Shader compile error! %u %s",data.type,glsl); + return false; + } + + return true; + } + + void destroy() nothrow + { + if(data) + { + if(data.gl_handle)glDeleteShader(data.gl_handle); + Mallocator.dispose(data); + data = null; + } + } + + enum Type + { + vertex, + fragment, + geometry + } + + struct Data + { + char[] code; + Type type; + + uint gl_handle; + } + + Data* data; +} \ No newline at end of file diff --git a/demos/utils/source/ecs_utils/gfx/sprite.d b/demos/utils/source/ecs_utils/gfx/sprite.d new file mode 100644 index 0000000..06c0804 --- /dev/null +++ b/demos/utils/source/ecs_utils/gfx/sprite.d @@ -0,0 +1,11 @@ +module ecs_utils.gfx.sprite; + +import ecs_utils.math.matrix; +import ecs_utils.gfx.mesh_module; + +struct sprite +{ + MeshModule* mesh; + + mat3 matrix; +} \ No newline at end of file diff --git a/demos/utils/source/ecs_utils/gfx/texture.d b/demos/utils/source/ecs_utils/gfx/texture.d new file mode 100644 index 0000000..6f41fe2 --- /dev/null +++ b/demos/utils/source/ecs_utils/gfx/texture.d @@ -0,0 +1,118 @@ +module ecs_utils.gfx.texture; + +import bindbc.sdl; + +import ecs.std; + +import ecs_utils.math.vector; + +import glad.gl.gl; + +extern(C): + +struct Texture +{ + + void create() + { + data = Mallocator.make!Data; + } + + bool load(const char[] path) + { + char[] cpath = (cast(char*)alloca(path.length+1))[0..path.length+1]; + cpath[0..$-1] = path[0..$]; + cpath[$-1] = 0; + + return __load(this, cpath); + } + + /*static bool __load_sdl(ref Texture this_, const char[] path) + { + import ecs_utils.gfx.renderer; + SDL_Surface* surf = IMG_Load(path.ptr); + if(!surf)return false; + + this_.data.size = ivec2(surf.w,surf.h); + + this_.data.texture = SDL_CreateTextureFromSurface(Renderer.main_sdl_renderer,surf); + if(!this_.data.texture)return false; + //this_.data.texture = surf; + + return true; + }*/ + + static bool __load_gl(ref Texture this_, const char[] path) + { + SDL_Surface* surf = IMG_Load(path.ptr); + if(!surf)return false; + + with(this_) + { + data.size = ivec2(surf.w,surf.h); + data.bpp = surf.format.BytesPerPixel; + data.data = Mallocator.makeArray!ubyte(surf.w*surf.h*surf.format.BytesPerPixel); + data.data[0..$] = (cast(ubyte*)surf.pixels)[0..data.data.length]; + + glGenTextures(1, &data.gl_handle); + glBindTexture(GL_TEXTURE_2D,data.gl_handle); + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + + if(data.bpp == 3)glTexImage2D(GL_TEXTURE_2D,0,GL_RGB,surf.w,surf.h,0,GL_RGB,GL_UNSIGNED_BYTE,data.data.ptr); + else if(data.bpp == 4)glTexImage2D(GL_TEXTURE_2D,0,GL_RGBA,surf.w,surf.h,0,GL_RGBA,GL_UNSIGNED_BYTE,data.data.ptr); + else return false; + } + + + return true; + } + + void bind() + { + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, data.gl_handle); + } + + void destory() + { + if(data) + { + glDeleteTextures(1, &data.gl_handle); + Mallocator.dispose(data); + data = null; + } + } + + static bool function(ref Texture this_, const char[] path) __load; + + struct Data + { + ubyte[] data; + + ivec2 size; + uint bpp; + + union + { + SDL_Texture* texture; + uint gl_handle; + } + } + + static void __loadBackend() + { + __load = &__load_gl; + /*switch(backend) + { + case Backend.opengl:__load = &__load_gl;break; + case Backend.sdl:__load = &__load_sdl;break; + default:goto case(Backend.opengl); + }*/ + } + + Data* data; +} \ No newline at end of file diff --git a/demos/utils/source/ecs_utils/gfx/vertex.d b/demos/utils/source/ecs_utils/gfx/vertex.d new file mode 100644 index 0000000..1d11fdd --- /dev/null +++ b/demos/utils/source/ecs_utils/gfx/vertex.d @@ -0,0 +1,64 @@ +module ecs_utils.gfx.vertex; + +import ecs.std; + +struct Vertex +{ + void create() + { + data = Mallocator.make!Data; + } + + void bind() + { + + } + + void enableStates() + { + + } + + void attachBindings(scope Binding[] bindings) + { + data.bindings = Mallocator.makeArray(bindings); + } + + enum Type + { + byte_r_snorm, + byte_r_unorm, + byte_rg_snorm, + byte_rg_unorm, + byte_rgb_snorm, + byte_rgb_unorm, + byte_rgba_snorm, + byte_rgba_unorm, + short_r_snorm, + short_r_unorm, + short_rg_snorm, + short_rg_unorm, + short_rgb_snorm, + short_rgb_unorm, + short_rgba_snorm, + short_rgba_unorm, + float_r, + float_rg, + float_rgb, + float_rgba + } + + struct Binding + { + Type type; + uint stride; + } + + struct Data + { + Binding[] bindings; + uint size; + } + + Data* data; +} \ No newline at end of file diff --git a/demos/utils/source/ecs_utils/imgui_bind.d b/demos/utils/source/ecs_utils/imgui_bind.d new file mode 100644 index 0000000..3e84328 --- /dev/null +++ b/demos/utils/source/ecs_utils/imgui_bind.d @@ -0,0 +1,508 @@ +module ecs_utils.imgui_bind; + +import bindbc.sdl; +import cimgui.cimgui; + +version(WebAssembly) +{ + extern(C): + bool ImGui_ImplOpenGL3_Init(const char* glsl_version = null); + void ImGui_ImplOpenGL3_Shutdown(); + void ImGui_ImplOpenGL3_NewFrame(); + void ImGui_ImplOpenGL3_RenderDrawData(ImDrawData* draw_data); + + bool ImGui_ImplSDL2_InitForOpenGL(SDL_Window* window, void* sdl_gl_context); + bool ImGui_ImplSDL2_InitForVulkan(SDL_Window* window); + bool ImGui_ImplSDL2_InitForD3D(SDL_Window* window); + void ImGui_ImplSDL2_Shutdown(); + void ImGui_ImplSDL2_NewFrame(SDL_Window* window); + bool ImGui_ImplSDL2_ProcessEvent(const SDL_Event* event); +} +else : + +import bindbc.sdl; + +import glad.gl.gl; + +import cimgui.cimgui; + +extern(C): + +SDL_Window* g_Window; +ulong g_Time; +bool[3] g_MousePressed; +SDL_Cursor*[ImGuiMouseCursor_COUNT] g_MouseCursors; +char* g_ClipboardTextData; +GLuint g_FontTexture = 0; + +const (char)* ImGuiImplSDL2GetClipboardText(void*) +{ + if (g_ClipboardTextData) + SDL_free(g_ClipboardTextData); + g_ClipboardTextData = SDL_GetClipboardText(); + return g_ClipboardTextData; +} + +void ImGuiImplSDL2SetClipboardText(void*, const char* text) +{ + SDL_SetClipboardText(text); +} + +bool ImGui_ImplSDL2_ProcessEvent(const SDL_Event* event) +{ + ImGuiIO* io = igGetIO(); + switch (event.type) + { + case SDL_MOUSEWHEEL: + { + if (event.wheel.x > 0) io.MouseWheelH += 1; + if (event.wheel.x < 0) io.MouseWheelH -= 1; + if (event.wheel.y > 0) io.MouseWheel += 1; + if (event.wheel.y < 0) io.MouseWheel -= 1; + return true; + } + case SDL_MOUSEBUTTONDOWN: + { + if (event.button.button == SDL_BUTTON_LEFT) g_MousePressed[0] = true; + if (event.button.button == SDL_BUTTON_RIGHT) g_MousePressed[1] = true; + if (event.button.button == SDL_BUTTON_MIDDLE) g_MousePressed[2] = true; + return true; + } + case SDL_TEXTINPUT: + { + ImGuiIO_AddInputCharactersUTF8(io,event.text.text.ptr); + return true; + } + case SDL_KEYDOWN: + case SDL_KEYUP: + { + int key = event.key.keysym.scancode; + //IM_ASSERT(key >= 0 && key < IM_ARRAYSIZE(io.KeysDown)); + io.KeysDown[key] = (event.type == SDL_KEYDOWN); + io.KeyShift = ((SDL_GetModState() & KMOD_SHIFT) != 0); + io.KeyCtrl = ((SDL_GetModState() & KMOD_CTRL) != 0); + io.KeyAlt = ((SDL_GetModState() & KMOD_ALT) != 0); + io.KeySuper = ((SDL_GetModState() & KMOD_GUI) != 0); + return true; + } + default:break; + } + return false; +} + +bool ImGuiImplSDL2Init(SDL_Window* window) +{ + g_Window = window; + + // Setup back-end capabilities flags + ImGuiIO* io = igGetIO(); + io.BackendFlags |= ImGuiBackendFlags_HasMouseCursors; // We can honor GetMouseCursor() values (optional) + io.BackendFlags |= ImGuiBackendFlags_HasSetMousePos; // We can honor io.WantSetMousePos requests (optional, rarely used) + io.BackendPlatformName = "imgui_impl_sdl"; + + // Keyboard mapping. ImGui will use those indices to peek into the io.KeysDown[] array. + io.KeyMap[ImGuiKey_Tab] = SDL_SCANCODE_TAB; + io.KeyMap[ImGuiKey_LeftArrow] = SDL_SCANCODE_LEFT; + io.KeyMap[ImGuiKey_RightArrow] = SDL_SCANCODE_RIGHT; + io.KeyMap[ImGuiKey_UpArrow] = SDL_SCANCODE_UP; + io.KeyMap[ImGuiKey_DownArrow] = SDL_SCANCODE_DOWN; + io.KeyMap[ImGuiKey_PageUp] = SDL_SCANCODE_PAGEUP; + io.KeyMap[ImGuiKey_PageDown] = SDL_SCANCODE_PAGEDOWN; + io.KeyMap[ImGuiKey_Home] = SDL_SCANCODE_HOME; + io.KeyMap[ImGuiKey_End] = SDL_SCANCODE_END; + io.KeyMap[ImGuiKey_Insert] = SDL_SCANCODE_INSERT; + io.KeyMap[ImGuiKey_Delete] = SDL_SCANCODE_DELETE; + io.KeyMap[ImGuiKey_Backspace] = SDL_SCANCODE_BACKSPACE; + io.KeyMap[ImGuiKey_Space] = SDL_SCANCODE_SPACE; + io.KeyMap[ImGuiKey_Enter] = SDL_SCANCODE_RETURN; + io.KeyMap[ImGuiKey_Escape] = SDL_SCANCODE_ESCAPE; + io.KeyMap[ImGuiKey_KeyPadEnter] = SDL_SCANCODE_RETURN2; + io.KeyMap[ImGuiKey_A] = SDL_SCANCODE_A; + io.KeyMap[ImGuiKey_C] = SDL_SCANCODE_C; + io.KeyMap[ImGuiKey_V] = SDL_SCANCODE_V; + io.KeyMap[ImGuiKey_X] = SDL_SCANCODE_X; + io.KeyMap[ImGuiKey_Y] = SDL_SCANCODE_Y; + io.KeyMap[ImGuiKey_Z] = SDL_SCANCODE_Z; + + io.SetClipboardTextFn = &ImGuiImplSDL2SetClipboardText; + io.GetClipboardTextFn = &ImGuiImplSDL2GetClipboardText; + io.ClipboardUserData = null; + + g_MouseCursors[ImGuiMouseCursor_Arrow] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_ARROW); + g_MouseCursors[ImGuiMouseCursor_TextInput] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_IBEAM); + g_MouseCursors[ImGuiMouseCursor_ResizeAll] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZEALL); + g_MouseCursors[ImGuiMouseCursor_ResizeNS] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZENS); + g_MouseCursors[ImGuiMouseCursor_ResizeEW] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZEWE); + g_MouseCursors[ImGuiMouseCursor_ResizeNESW] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZENESW); + g_MouseCursors[ImGuiMouseCursor_ResizeNWSE] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZENWSE); + g_MouseCursors[ImGuiMouseCursor_Hand] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_HAND); + + //#ifdef _WIN32 + version(WebAssembly) + { + + } + else version(Windows) + { + SDL_SysWMinfo wmInfo; + SDL_VERSION(&wmInfo.version_); + SDL_GetWindowWMInfo(window, &wmInfo); + io.ImeWindowHandle = wmInfo.info.win.window; + } + //#else + //(void)window; + //#endif + + return true; +} + +bool ImGuiImplSDL2InitForOpenGL(SDL_Window* window, void* sdl_gl_context) +{ + //(void)sdl_gl_context; // Viewport branch will need this. + return ImGuiImplSDL2Init(window); +} + +void ImGuiImplSDL2Shutdown() +{ + g_Window = null; + + // Destroy last known clipboard data + if (g_ClipboardTextData) + SDL_free(g_ClipboardTextData); + g_ClipboardTextData = null; + + // Destroy SDL mouse cursors + for (ImGuiMouseCursor cursor_n = 0; cursor_n < ImGuiMouseCursor_COUNT; cursor_n++) + SDL_FreeCursor(g_MouseCursors[cursor_n]); + //memset(g_MouseCursors, 0, sizeof(g_MouseCursors)); +} + +static void ImGui_ImplSDL2_UpdateMousePosAndButtons() +{ + ImGuiIO* io = igGetIO(); + + // Set OS mouse position if requested (rarely used, only when ImGuiConfigFlags_NavEnableSetMousePos is enabled by user) + if (io.WantSetMousePos) + SDL_WarpMouseInWindow(g_Window, cast(int)io.MousePos.x, cast(int)io.MousePos.y); + else + io.MousePos = ImVec2(-float.max, -float.max); + + int mx, my; + Uint32 mouse_buttons = SDL_GetMouseState(&mx, &my); + io.MouseDown[0] = g_MousePressed[0] || (mouse_buttons & (SDL_PRESSED<<(SDL_BUTTON_LEFT-1))) != 0; // If a mouse press event came, always pass it as "mouse held this frame", so we don't miss click-release events that are shorter than 1 frame. + io.MouseDown[1] = g_MousePressed[1] || (mouse_buttons & (SDL_PRESSED<<(SDL_BUTTON_RIGHT-1))) != 0; + io.MouseDown[2] = g_MousePressed[2] || (mouse_buttons & (SDL_PRESSED<<(SDL_BUTTON_MIDDLE-1))) != 0; + g_MousePressed[0] = g_MousePressed[1] = g_MousePressed[2] = false; + + //#if SDL_HAS_CAPTURE_AND_GLOBAL_MOUSE && !defined(__EMSCRIPTEN__) && !defined(__ANDROID__) && !(defined(__APPLE__) && TARGET_OS_IOS) + /*SDL_Window* focused_window = SDL_GetKeyboardFocus(); + if (g_Window == focused_window) + { + // SDL_GetMouseState() gives mouse position seemingly based on the last window entered/focused(?) + // The creation of a new windows at runtime and SDL_CaptureMouse both seems to severely mess up with that, so we retrieve that position globally. + int wx, wy; + SDL_GetWindowPosition(focused_window, &wx, &wy); + SDL_GetGlobalMouseState(&mx, &my); + mx -= wx; + my -= wy; + io.MousePos = ImVec2((float)mx, (float)my); + } + + // SDL_CaptureMouse() let the OS know e.g. that our imgui drag outside the SDL window boundaries shouldn't e.g. trigger the OS window resize cursor. + // The function is only supported from SDL 2.0.4 (released Jan 2016) + bool any_mouse_button_down = ImGui::IsAnyMouseDown(); + SDL_CaptureMouse(any_mouse_button_down ? SDL_TRUE : SDL_FALSE); +//#else*/ + if (SDL_GetWindowFlags(g_Window) & SDL_WINDOW_INPUT_FOCUS) + io.MousePos = ImVec2(cast(float)mx, cast(float)my); +//#endif +} + +static void ImGui_ImplSDL2_UpdateMouseCursor() +{ + ImGuiIO* io = igGetIO(); + if (io.ConfigFlags & ImGuiConfigFlags_NoMouseCursorChange) + return; + + ImGuiMouseCursor imgui_cursor = igGetMouseCursor(); + if (io.MouseDrawCursor || imgui_cursor == ImGuiMouseCursor_None) + { + // Hide OS mouse cursor if imgui is drawing it or if it wants no cursor + SDL_ShowCursor(SDL_FALSE); + } + else + { + // Show OS mouse cursor + SDL_SetCursor(g_MouseCursors[imgui_cursor] ? g_MouseCursors[imgui_cursor] : g_MouseCursors[ImGuiMouseCursor_Arrow]); + SDL_ShowCursor(SDL_TRUE); + } +} + +static void ImGui_ImplSDL2_UpdateGamepads() +{ + ImGuiIO* io = igGetIO(); + //memset(io.NavInputs, 0, sizeof(io.NavInputs)); + if ((io.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad) == 0) + return; + + // Get gamepad + SDL_GameController* game_controller = SDL_GameControllerOpen(0); + if (!game_controller) + { + io.BackendFlags &= ~ImGuiBackendFlags_HasGamepad; + return; + } + + // Update gamepad inputs + /*#define MAP_BUTTON(NAV_NO, BUTTON_NO) { io.NavInputs[NAV_NO] = (SDL_GameControllerGetButton(game_controller, BUTTON_NO) != 0) ? 1.0f : 0.0f; } + #define MAP_ANALOG(NAV_NO, AXIS_NO, V0, V1) { float vn = (float)(SDL_GameControllerGetAxis(game_controller, AXIS_NO) - V0) / (float)(V1 - V0); if (vn > 1.0f) vn = 1.0f; if (vn > 0.0f && io.NavInputs[NAV_NO] < vn) io.NavInputs[NAV_NO] = vn; } + const int thumb_dead_zone = 8000; // SDL_gamecontroller.h suggests using this value. + MAP_BUTTON(ImGuiNavInput_Activate, SDL_CONTROLLER_BUTTON_A); // Cross / A + MAP_BUTTON(ImGuiNavInput_Cancel, SDL_CONTROLLER_BUTTON_B); // Circle / B + MAP_BUTTON(ImGuiNavInput_Menu, SDL_CONTROLLER_BUTTON_X); // Square / X + MAP_BUTTON(ImGuiNavInput_Input, SDL_CONTROLLER_BUTTON_Y); // Triangle / Y + MAP_BUTTON(ImGuiNavInput_DpadLeft, SDL_CONTROLLER_BUTTON_DPAD_LEFT); // D-Pad Left + MAP_BUTTON(ImGuiNavInput_DpadRight, SDL_CONTROLLER_BUTTON_DPAD_RIGHT); // D-Pad Right + MAP_BUTTON(ImGuiNavInput_DpadUp, SDL_CONTROLLER_BUTTON_DPAD_UP); // D-Pad Up + MAP_BUTTON(ImGuiNavInput_DpadDown, SDL_CONTROLLER_BUTTON_DPAD_DOWN); // D-Pad Down + MAP_BUTTON(ImGuiNavInput_FocusPrev, SDL_CONTROLLER_BUTTON_LEFTSHOULDER); // L1 / LB + MAP_BUTTON(ImGuiNavInput_FocusNext, SDL_CONTROLLER_BUTTON_RIGHTSHOULDER); // R1 / RB + MAP_BUTTON(ImGuiNavInput_TweakSlow, SDL_CONTROLLER_BUTTON_LEFTSHOULDER); // L1 / LB + MAP_BUTTON(ImGuiNavInput_TweakFast, SDL_CONTROLLER_BUTTON_RIGHTSHOULDER); // R1 / RB + MAP_ANALOG(ImGuiNavInput_LStickLeft, SDL_CONTROLLER_AXIS_LEFTX, -thumb_dead_zone, -32768); + MAP_ANALOG(ImGuiNavInput_LStickRight, SDL_CONTROLLER_AXIS_LEFTX, +thumb_dead_zone, +32767); + MAP_ANALOG(ImGuiNavInput_LStickUp, SDL_CONTROLLER_AXIS_LEFTY, -thumb_dead_zone, -32767); + MAP_ANALOG(ImGuiNavInput_LStickDown, SDL_CONTROLLER_AXIS_LEFTY, +thumb_dead_zone, +32767); + + io.BackendFlags |= ImGuiBackendFlags_HasGamepad; + #undef MAP_BUTTON + #undef MAP_ANALOG*/ +} + + +private long frequency; + +void ImGuiImplSDL2NewFrame(SDL_Window* window) +{ + ImGuiIO* io = igGetIO(); + assert(ImFontAtlas_IsBuilt(io.Fonts), "Font atlas not built! It is generally built by the renderer back-end. Missing call to renderer _NewFrame() function? e.g. ImGui_ImplOpenGL3_NewFrame()."); + + // Setup display size (every frame to accommodate for window resizing) + int w, h; + int display_w, display_h; + SDL_GetWindowSize(window, &w, &h); + SDL_GL_GetDrawableSize(window, &display_w, &display_h); + io.DisplaySize = ImVec2(cast(float)w, cast(float)h); + if (w > 0 && h > 0) + io.DisplayFramebufferScale = ImVec2(cast(float)display_w / w, cast(float)display_h / h); + + // Setup time step (we don't use SDL_GetTicks() because it is using millisecond resolution) + frequency = SDL_GetPerformanceFrequency(); + long current_time = SDL_GetPerformanceCounter(); + io.DeltaTime = g_Time > 0 ? cast(float)(cast(double)(current_time - g_Time) / frequency) : cast(float)(1.0f / 60.0f); + g_Time = current_time; + + ImGui_ImplSDL2_UpdateMousePosAndButtons(); + ImGui_ImplSDL2_UpdateMouseCursor(); + + // Update game controllers (if enabled and available) + ImGui_ImplSDL2_UpdateGamepads(); +} + + + + + + + + + + +bool ImGuiImplOpenGL2Init() +{ + // Setup back-end capabilities flags + ImGuiIO* io = igGetIO(); + io.BackendRendererName = "imgui_impl_opengl2"; + return true; +} + +void ImGuiImplOpenGL2Shutdown() +{ + ImGuiImplOpenGL2DestroyDeviceObjects(); +} + +void ImGuiImplOpenGL2NewFrame() +{ + if (!g_FontTexture) + ImGuiImplOpenGL2CreateDeviceObjects(); +} + +static void ImGuiImplOpenGL2SetupRenderState(ImDrawData* draw_data, int fb_width, int fb_height) +{ + // Setup render state: alpha-blending enabled, no face culling, no depth testing, scissor enabled, vertex/texcoord/color pointers, polygon fill. + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glDisable(GL_CULL_FACE); + glDisable(GL_DEPTH_TEST); + //glDisable(GL_LIGHTING); + //glDisable(GL_COLOR_MATERIAL); + glEnable(GL_SCISSOR_TEST); + glEnableClientState(GL_VERTEX_ARRAY); + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + glEnableClientState(GL_COLOR_ARRAY); + glEnable(GL_TEXTURE_2D); + glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + + // If you are using this code with non-legacy OpenGL header/contexts (which you should not, prefer using imgui_impl_opengl3.cpp!!), + // you may need to backup/reset/restore current shader using the lines below. DO NOT MODIFY THIS FILE! Add the code in your calling function: + // GLint last_program; + // glGetIntegerv(GL_CURRENT_PROGRAM, &last_program); + // glUseProgram(0); + // ImGui_ImplOpenGL2_RenderDrawData(...); + // glUseProgram(last_program) + + // Setup viewport, orthographic projection matrix + // Our visible imgui space lies from draw_data.DisplayPos (top left) to draw_data.DisplayPos+data_data.DisplaySize (bottom right). DisplayPos is (0,0) for single viewport apps. + glViewport(0, 0, cast(GLsizei)fb_width, cast(GLsizei)fb_height); + glMatrixMode(GL_PROJECTION); + glPushMatrix(); + glLoadIdentity(); + glOrtho(draw_data.DisplayPos.x, draw_data.DisplayPos.x + draw_data.DisplaySize.x, draw_data.DisplayPos.y + draw_data.DisplaySize.y, draw_data.DisplayPos.y, -1.0f, +1.0f); + glMatrixMode(GL_MODELVIEW); + glPushMatrix(); + glLoadIdentity(); +} + +// OpenGL2 Render function. +// (this used to be set in io.RenderDrawListsFn and called by ImGui::Render(), but you can now call this directly from your main loop) +// Note that this implementation is little overcomplicated because we are saving/setting up/restoring every OpenGL state explicitly, in order to be able to run within any OpenGL engine that doesn't do so. +void ImGuiImplOpenGL2RenderDrawData(ImDrawData* draw_data) +{ + // Avoid rendering when minimized, scale coordinates for retina displays (screen coordinates != framebuffer coordinates) + int fb_width = cast(int)(draw_data.DisplaySize.x * draw_data.FramebufferScale.x); + int fb_height = cast(int)(draw_data.DisplaySize.y * draw_data.FramebufferScale.y); + if (fb_width == 0 || fb_height == 0) + return; + + // Backup GL state + GLint last_texture; glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture); + GLint[2] last_polygon_mode; glGetIntegerv(GL_POLYGON_MODE, last_polygon_mode.ptr); + GLint[4] last_viewport; glGetIntegerv(GL_VIEWPORT, last_viewport.ptr); + GLint[4] last_scissor_box; glGetIntegerv(GL_SCISSOR_BOX, last_scissor_box.ptr); + glPushAttrib(GL_ENABLE_BIT | GL_COLOR_BUFFER_BIT | GL_TRANSFORM_BIT); + + // Setup desired GL state + ImGuiImplOpenGL2SetupRenderState(draw_data, fb_width, fb_height); + + // Will project scissor/clipping rectangles into framebuffer space + ImVec2 clip_off = draw_data.DisplayPos; // (0,0) unless using multi-viewports + ImVec2 clip_scale = draw_data.FramebufferScale; // (1,1) unless using retina display which are often (2,2) + + // Render command lists + for (int n = 0; n < draw_data.CmdListsCount; n++) + { + ImDrawList* cmd_list = draw_data.CmdLists[n]; + ImDrawVert* vtx_buffer = cmd_list.VtxBuffer.Data; + ImDrawIdx* idx_buffer = cmd_list.IdxBuffer.Data; + glVertexPointer(2, GL_FLOAT, ImDrawVert.sizeof, cast(const GLvoid*)(cast(const char*)vtx_buffer + ImDrawVert.pos.offsetof)); + glTexCoordPointer(2, GL_FLOAT, ImDrawVert.sizeof, cast(const GLvoid*)(cast(const char*)vtx_buffer + ImDrawVert.uv.offsetof)); + glColorPointer(4, GL_UNSIGNED_BYTE, ImDrawVert.sizeof, cast(const GLvoid*)(cast(const char*)vtx_buffer + ImDrawVert.col.offsetof)); + + for (int cmd_i = 0; cmd_i < cmd_list.CmdBuffer.Size; cmd_i++) + { + const ImDrawCmd* pcmd = &cmd_list.CmdBuffer.Data[cmd_i]; + if (pcmd.UserCallback) + { + // User callback, registered via ImDrawList::AddCallback() + // (ImDrawCallback_ResetRenderState is a special callback value used by the user to request the renderer to reset render state.) + /*if (pcmd.UserCallback == &ImDrawCallback_ResetRenderState) + ImGui_ImplOpenGL2_SetupRenderState(draw_data, fb_width, fb_height); + else*/ + pcmd.UserCallback(cmd_list, pcmd); + } + else + { + // Project scissor/clipping rectangles into framebuffer space + ImVec4 clip_rect = ImVec4(0,0,0,0); + clip_rect.x = (pcmd.ClipRect.x - clip_off.x) * clip_scale.x; + clip_rect.y = (pcmd.ClipRect.y - clip_off.y) * clip_scale.y; + clip_rect.z = (pcmd.ClipRect.z - clip_off.x) * clip_scale.x; + clip_rect.w = (pcmd.ClipRect.w - clip_off.y) * clip_scale.y; + + if (clip_rect.x < fb_width && clip_rect.y < fb_height && clip_rect.z >= 0.0f && clip_rect.w >= 0.0f) + { + // Apply scissor/clipping rectangle + glScissor(cast(int)clip_rect.x, cast(int)(fb_height - clip_rect.w), cast(int)(clip_rect.z - clip_rect.x), cast(int)(clip_rect.w - clip_rect.y)); + + // Bind texture, Draw + glBindTexture(GL_TEXTURE_2D, cast(GLuint)pcmd.TextureId); + glDrawElements(GL_TRIANGLES, cast(GLsizei)pcmd.ElemCount, ImDrawIdx.sizeof == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT, idx_buffer); + } + } + idx_buffer += pcmd.ElemCount; + } + } + + // Restore modified GL state + glDisableClientState(GL_COLOR_ARRAY); + glDisableClientState(GL_TEXTURE_COORD_ARRAY); + glDisableClientState(GL_VERTEX_ARRAY); + glBindTexture(GL_TEXTURE_2D, cast(GLuint)last_texture); + glMatrixMode(GL_MODELVIEW); + glPopMatrix(); + glMatrixMode(GL_PROJECTION); + glPopMatrix(); + glPopAttrib(); + glPolygonMode(GL_FRONT, cast(GLenum)last_polygon_mode[0]); glPolygonMode(GL_BACK, cast(GLenum)last_polygon_mode[1]); + glViewport(last_viewport[0], last_viewport[1], cast(GLsizei)last_viewport[2], cast(GLsizei)last_viewport[3]); + glScissor(last_scissor_box[0], last_scissor_box[1], cast(GLsizei)last_scissor_box[2], cast(GLsizei)last_scissor_box[3]); +} + +bool ImGuiImplOpenGL2CreateFontsTexture() +{ + // Build texture atlas + ImGuiIO* io = igGetIO(); + ubyte* pixels; + int width, height; + int bpp; + ImFontAtlas_GetTexDataAsRGBA32(io.Fonts, &pixels, &width, &height, &bpp); // Load as RGBA 32-bits (75% of the memory is wasted, but default font is so small) because it is more likely to be compatible with user's existing shaders. If your ImTextureId represent a higher-level concept than just a GL texture id, consider calling GetTexDataAsAlpha8() instead to save on GPU memory. + + // Upload texture to graphics system + GLint last_texture; + glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture); + glGenTextures(1, &g_FontTexture); + glBindTexture(GL_TEXTURE_2D, g_FontTexture); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels); + + // Store our identifier + io.Fonts.TexID = cast(ImTextureID)g_FontTexture; + + // Restore state + glBindTexture(GL_TEXTURE_2D, last_texture); + + return true; +} + +void ImGuiImplOpenGL2DestroyFontsTexture() +{ + if (g_FontTexture) + { + ImGuiIO* io = igGetIO(); + glDeleteTextures(1, &g_FontTexture); + io.Fonts.TexID = null; + g_FontTexture = 0; + } +} + +bool ImGuiImplOpenGL2CreateDeviceObjects() +{ + return ImGuiImplOpenGL2CreateFontsTexture(); +} + +void ImGuiImplOpenGL2DestroyDeviceObjects() +{ + ImGuiImplOpenGL2DestroyFontsTexture(); +} \ No newline at end of file diff --git a/demos/utils/source/ecs_utils/imgui_styles.d b/demos/utils/source/ecs_utils/imgui_styles.d new file mode 100644 index 0000000..0520ec6 --- /dev/null +++ b/demos/utils/source/ecs_utils/imgui_styles.d @@ -0,0 +1,95 @@ +module ecs_utils.imgui_styles; + +import cimgui.cimgui; + +void setStyle(uint index) +{ + ImGuiStyle * style = igGetStyle(); + ImVec4 * colors = style.Colors.ptr; + + switch(index) + { + case 0: + igStyleColorsClassic(style); + break; + case 1: + igStyleColorsDark(style); + break; + case 2: + igStyleColorsLight(style); + break; + case 3: + colors[ImGuiCol_Text] = ImVec4(0.95f, 0.96f, 0.98f, 1.00f); + colors[ImGuiCol_TextDisabled] = ImVec4(0.36f, 0.42f, 0.47f, 1.00f); + colors[ImGuiCol_WindowBg] = ImVec4(0.11f, 0.15f, 0.17f, 1.00f); + colors[ImGuiCol_ChildBg] = ImVec4(0.15f, 0.18f, 0.22f, 1.00f); + colors[ImGuiCol_PopupBg] = ImVec4(0.08f, 0.08f, 0.08f, 0.94f); + colors[ImGuiCol_Border] = ImVec4(0.08f, 0.10f, 0.12f, 1.00f); + colors[ImGuiCol_BorderShadow] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f); + colors[ImGuiCol_FrameBg] = ImVec4(0.20f, 0.25f, 0.29f, 1.00f); + colors[ImGuiCol_FrameBgHovered] = ImVec4(0.12f, 0.20f, 0.28f, 1.00f); + colors[ImGuiCol_FrameBgActive] = ImVec4(0.09f, 0.12f, 0.14f, 1.00f); + colors[ImGuiCol_TitleBg] = ImVec4(0.09f, 0.12f, 0.14f, 0.65f); + colors[ImGuiCol_TitleBgActive] = ImVec4(0.08f, 0.10f, 0.12f, 1.00f); + colors[ImGuiCol_TitleBgCollapsed] = ImVec4(0.00f, 0.00f, 0.00f, 0.51f); + colors[ImGuiCol_MenuBarBg] = ImVec4(0.15f, 0.18f, 0.22f, 1.00f); + colors[ImGuiCol_ScrollbarBg] = ImVec4(0.02f, 0.02f, 0.02f, 0.39f); + colors[ImGuiCol_ScrollbarGrab] = ImVec4(0.20f, 0.25f, 0.29f, 1.00f); + colors[ImGuiCol_ScrollbarGrabHovered] = ImVec4(0.18f, 0.22f, 0.25f, 1.00f); + colors[ImGuiCol_ScrollbarGrabActive] = ImVec4(0.09f, 0.21f, 0.31f, 1.00f); + colors[ImGuiCol_CheckMark] = ImVec4(0.28f, 0.56f, 1.00f, 1.00f); + colors[ImGuiCol_SliderGrab] = ImVec4(0.28f, 0.56f, 1.00f, 1.00f); + colors[ImGuiCol_SliderGrabActive] = ImVec4(0.37f, 0.61f, 1.00f, 1.00f); + colors[ImGuiCol_Button] = ImVec4(0.20f, 0.25f, 0.29f, 1.00f); + colors[ImGuiCol_ButtonHovered] = ImVec4(0.28f, 0.56f, 1.00f, 1.00f); + colors[ImGuiCol_ButtonActive] = ImVec4(0.06f, 0.53f, 0.98f, 1.00f); + colors[ImGuiCol_Header] = ImVec4(0.20f, 0.25f, 0.29f, 0.55f); + colors[ImGuiCol_HeaderHovered] = ImVec4(0.26f, 0.59f, 0.98f, 0.80f); + colors[ImGuiCol_HeaderActive] = ImVec4(0.26f, 0.59f, 0.98f, 1.00f); + colors[ImGuiCol_Separator] = ImVec4(0.20f, 0.25f, 0.29f, 1.00f); + colors[ImGuiCol_SeparatorHovered] = ImVec4(0.10f, 0.40f, 0.75f, 0.78f); + colors[ImGuiCol_SeparatorActive] = ImVec4(0.10f, 0.40f, 0.75f, 1.00f); + colors[ImGuiCol_ResizeGrip] = ImVec4(0.26f, 0.59f, 0.98f, 0.25f); + colors[ImGuiCol_ResizeGripHovered] = ImVec4(0.26f, 0.59f, 0.98f, 0.67f); + colors[ImGuiCol_ResizeGripActive] = ImVec4(0.26f, 0.59f, 0.98f, 0.95f); + colors[ImGuiCol_Tab] = ImVec4(0.11f, 0.15f, 0.17f, 1.00f); + colors[ImGuiCol_TabHovered] = ImVec4(0.26f, 0.59f, 0.98f, 0.80f); + colors[ImGuiCol_TabActive] = ImVec4(0.20f, 0.25f, 0.29f, 1.00f); + colors[ImGuiCol_TabUnfocused] = ImVec4(0.11f, 0.15f, 0.17f, 1.00f); + colors[ImGuiCol_TabUnfocusedActive] = ImVec4(0.11f, 0.15f, 0.17f, 1.00f); + colors[ImGuiCol_PlotLines] = ImVec4(0.61f, 0.61f, 0.61f, 1.00f); + colors[ImGuiCol_PlotLinesHovered] = ImVec4(1.00f, 0.43f, 0.35f, 1.00f); + colors[ImGuiCol_PlotHistogram] = ImVec4(0.90f, 0.70f, 0.00f, 1.00f); + colors[ImGuiCol_PlotHistogramHovered] = ImVec4(1.00f, 0.60f, 0.00f, 1.00f); + colors[ImGuiCol_TextSelectedBg] = ImVec4(0.26f, 0.59f, 0.98f, 0.35f); + colors[ImGuiCol_DragDropTarget] = ImVec4(1.00f, 1.00f, 0.00f, 0.90f); + colors[ImGuiCol_NavHighlight] = ImVec4(0.26f, 0.59f, 0.98f, 1.00f); + colors[ImGuiCol_NavWindowingHighlight] = ImVec4(1.00f, 1.00f, 1.00f, 0.70f); + colors[ImGuiCol_NavWindowingDimBg] = ImVec4(0.80f, 0.80f, 0.80f, 0.20f); + colors[ImGuiCol_ModalWindowDimBg] = ImVec4(0.80f, 0.80f, 0.80f, 0.35f); + + style.PopupRounding = 3; + + style.WindowPadding = ImVec2(4, 4); + style.FramePadding = ImVec2(6, 4); + style.ItemSpacing = ImVec2(6, 2); + + style.ScrollbarSize = 18; + + style.WindowBorderSize = 1; + style.ChildBorderSize = 1; + style.PopupBorderSize = 1; + style.FrameBorderSize = 0; + + style.WindowRounding = 3; + style.ChildRounding = 3; + style.FrameRounding = 4; + style.ScrollbarRounding = 2; + style.GrabRounding = 4; + break; + default: + igStyleColorsClassic(style); + break; + } + +} \ No newline at end of file diff --git a/demos/utils/source/ecs_utils/utils.d b/demos/utils/source/ecs_utils/utils.d new file mode 100644 index 0000000..aa223eb --- /dev/null +++ b/demos/utils/source/ecs_utils/utils.d @@ -0,0 +1,183 @@ +module ecs_utils.utils; + +extern(C): + +int randomRange(int min, int max) +{ + int range = max - min; + return rand() % range - min; +} + +float randomf() +{ + const float scale = 1.0 / 32_767.0; + return cast(float)(rand() & 0x007FFF) * scale; +} + +/* +float randomRangef(float min, float max) +{ + //int range = max - min; + return rand()%4096; +}*/ + +extern(C) int printf(scope const char* format, ...) @nogc nothrow @system; +extern(C) int rand(); + +version(D_BetterC) +{ + version(LDC) + { + extern(C) bool _d_enter_cleanup(void*) + { + return true; + } + + extern(C) void _d_leave_cleanup(void*) + { + + } + + extern(C) void _d_array_slice_copy(void* dst, size_t dstlen, void* src, size_t srclen, size_t elemsz) + { + import ldc.intrinsics : llvm_memcpy; + llvm_memcpy!size_t(dst, src, dstlen * elemsz, 0); + } + } +} + + + +version(WebAssembly) +{ + + enum EMSCRIPTEN_RESULT_SUCCESS = 0; + enum EMSCRIPTEN_RESULT_DEFERRED = 1; + enum EMSCRIPTEN_RESULT_NOT_SUPPORTED = -1; + enum EMSCRIPTEN_RESULT_FAILED_NOT_DEFERRED = -2; + enum EMSCRIPTEN_RESULT_INVALID_TARGET = -3; + enum EMSCRIPTEN_RESULT_UNKNOWN_TARGET = -4; + enum EMSCRIPTEN_RESULT_INVALID_PARAM = -5; + enum EMSCRIPTEN_RESULT_FAILED = -6; + enum EMSCRIPTEN_RESULT_NO_DATA = -7; + enum EMSCRIPTEN_RESULT_TIMED_OUT = -8; + + alias EMSCRIPTEN_FULLSCREEN_SCALE = int; + enum EMSCRIPTEN_FULLSCREEN_SCALE_DEFAULT = 0; + enum EMSCRIPTEN_FULLSCREEN_SCALE_STRETCH = 1; + enum EMSCRIPTEN_FULLSCREEN_SCALE_ASPECT = 2; + enum EMSCRIPTEN_FULLSCREEN_SCALE_CENTER = 3; + + alias EMSCRIPTEN_FULLSCREEN_CANVAS_SCALE = int; + enum EMSCRIPTEN_FULLSCREEN_CANVAS_SCALE_NONE = 0; + enum EMSCRIPTEN_FULLSCREEN_CANVAS_SCALE_STDDEF = 1; + enum EMSCRIPTEN_FULLSCREEN_CANVAS_SCALE_HIDEF = 2; + + alias EMSCRIPTEN_FULLSCREEN_FILTERING = int; + enum EMSCRIPTEN_FULLSCREEN_FILTERING_DEFAULT = 0; + enum EMSCRIPTEN_FULLSCREEN_FILTERING_NEAREST = 1; + enum EMSCRIPTEN_FULLSCREEN_FILTERING_BILINEAR = 2; + + alias em_canvasresized_callback_func = extern(C) bool function (int eventType, const void *reserved, void *userData); + + struct EmscriptenFullscreenStrategy { + EMSCRIPTEN_FULLSCREEN_SCALE scaleMode; + EMSCRIPTEN_FULLSCREEN_CANVAS_SCALE canvasResolutionScaleMode; + EMSCRIPTEN_FULLSCREEN_FILTERING filteringMode; + em_canvasresized_callback_func canvasResizedCallback; + void *canvasResizedCallbackUserData; + } + + extern (C) const (char)* emscripten_result_to_string(int result) { + if (result == EMSCRIPTEN_RESULT_SUCCESS) return "EMSCRIPTEN_RESULT_SUCCESS"; + if (result == EMSCRIPTEN_RESULT_DEFERRED) return "EMSCRIPTEN_RESULT_DEFERRED"; + if (result == EMSCRIPTEN_RESULT_NOT_SUPPORTED) return "EMSCRIPTEN_RESULT_NOT_SUPPORTED"; + if (result == EMSCRIPTEN_RESULT_FAILED_NOT_DEFERRED) return "EMSCRIPTEN_RESULT_FAILED_NOT_DEFERRED"; + if (result == EMSCRIPTEN_RESULT_INVALID_TARGET) return "EMSCRIPTEN_RESULT_INVALID_TARGET"; + if (result == EMSCRIPTEN_RESULT_UNKNOWN_TARGET) return "EMSCRIPTEN_RESULT_UNKNOWN_TARGET"; + if (result == EMSCRIPTEN_RESULT_INVALID_PARAM) return "EMSCRIPTEN_RESULT_INVALID_PARAM"; + if (result == EMSCRIPTEN_RESULT_FAILED) return "EMSCRIPTEN_RESULT_FAILED"; + if (result == EMSCRIPTEN_RESULT_NO_DATA) return "EMSCRIPTEN_RESULT_NO_DATA"; + return "Unknown EMSCRIPTEN_RESULT!"; + } + + extern (C) alias em_callback_func = void function(); + extern (C) alias em_arg_callback_func = void function(void*); + extern (C) void emscripten_set_main_loop(em_callback_func func, int fps, int simulate_infinite_loop); + extern (C) void emscripten_set_main_loop_arg(em_arg_callback_func func, void *arg, int fps, int simulate_infinite_loop); + extern (C) int emscripten_set_main_loop_timing(int mode, int value); + extern (C) void emscripten_cancel_main_loop(); + extern (C) int emscripten_request_fullscreen_strategy(const char *target, bool deferUntilInEventHandler, const EmscriptenFullscreenStrategy *fullscreenStrategy); + extern (C) int emscripten_enter_soft_fullscreen(const char *target, const EmscriptenFullscreenStrategy *fullscreenStrategy); + + alias int time_t; + alias int clockid_t; + enum CLOCK_REALTIME = 0; + + struct timespec + { + time_t tv_sec; + int tv_nsec; + } + + extern(C) int clock_gettime(clockid_t, timespec*) @nogc nothrow @system; + + struct Time + { + + + static long getUSecTime() + { + time_t time; + timespec spec; + + clock_gettime(CLOCK_REALTIME, &spec); + + //time = spec.tv_sec; + return spec.tv_sec * 1000_000 + spec.tv_nsec / 1000;//time / 1000_000; + + /*LARGE_INTEGER time, freq; + QueryPerformanceFrequency(&freq); + QueryPerformanceCounter(&time); + return time.QuadPart / (freq.QuadPart / 1000_000);*/ + } + } +} +else version(Windows) +{ + import core.stdc.stdio : printf; + import core.sys.windows.windows; + struct Time + { + static long getUSecTime() + { + LARGE_INTEGER time, freq; + QueryPerformanceFrequency(&freq); + QueryPerformanceCounter(&time); + return time.QuadPart / (freq.QuadPart / 1000_000); + } + } +} +else version(Posix) +{ + import core.stdc.stdio : printf; + import core.sys.posix.time; + struct Time + { + static long getUSecTime() + { + time_t time; + timespec spec; + + clock_gettime(CLOCK_REALTIME, &spec); + + //time = spec.tv_sec; + return spec.tv_sec * 1000_000 + spec.tv_nsec / 1000;//time / 1000_000; + + /*LARGE_INTEGER time, freq; + QueryPerformanceFrequency(&freq); + QueryPerformanceCounter(&time); + return time.QuadPart / (freq.QuadPart / 1000_000);*/ + } + } +} \ No newline at end of file diff --git a/dub.json b/dub.json index e4d9704..87b9b7b 100755 --- a/dub.json +++ b/dub.json @@ -10,6 +10,9 @@ "dflagss": [ "-betterC" ], + "excludedSourceFiles":[ + "source\/ecs\/traits.d" + ], "configurations" : [ { "name" : "library", diff --git a/source/ecs/vector.d b/source/ecs/vector.d index 84ecc51..fa616ed 100644 --- a/source/ecs/vector.d +++ b/source/ecs/vector.d @@ -29,7 +29,7 @@ public: } - /*static if (isCopyable!T) { + static if (isCopyable!T) { export this(this) { T[] tmp = array[0 .. used]; array = null; @@ -38,9 +38,9 @@ public: } } else { @disable this(this); - }*/ + } - @disable this(this); + //@disable this(this); export ~this() { clear(); From 5894e7654090e0208ea6c25c07cce60815126175 Mon Sep 17 00:00:00 2001 From: Mergul Date: Tue, 19 Nov 2019 10:37:34 +0100 Subject: [PATCH 081/217] -updated wasm build scripts -multitheaded wasm tests -updated dub.json -fixed thread pool assert issue -added windows libraries -added demos: *launcher *simple *snake *space invaders (WIP) *statistics window *changable gui styles *tips window *profile window *demo window with automatic generation *multithreaded job updater --- compile_wasm.py | 10 +- demos/.gitignore | 3 +- demos/compile_wasm.py | 13 +- demos/dub.json | 6 +- demos/external/sources/mmutils/thread_pool.d | 2 +- demos/libs/windows/x64/SDL2.lib | Bin 0 -> 145280 bytes demos/libs/windows/x64/SDL2_image.lib | Bin 0 -> 10120 bytes demos/libs/windows/x64/SDL2main.lib | Bin 0 -> 41244 bytes demos/libs/windows/x64/SDL2test.lib | Bin 0 -> 924400 bytes demos/libs/windows/x64/cimgui.lib | Bin 0 -> 136730 bytes demos/source/app.d | 716 +++++++++++++++++ demos/source/demos/bullet_madnes.d | 19 + demos/source/demos/chipmunk2d.d | 19 + demos/source/demos/events.d | 19 + demos/source/demos/flag_component.d | 19 + demos/source/demos/physics.d | 19 + demos/source/demos/simple.d | 171 +++++ demos/source/demos/snake.d | 522 +++++++++++++ demos/source/demos/space_invaders.d | 764 +++++++++++++++++++ demos/source/game_core/job_updater.d | 199 +++++ demos/source/gui/component.d | 6 + demos/source/gui/manager.d | 49 ++ demos/source/gui/system.d | 11 + demos/utils/dub.json | 1 - demos/utils/source/ecs_utils/gfx/renderer.d | 8 +- source/ecs/vector.d | 6 +- 26 files changed, 2562 insertions(+), 20 deletions(-) create mode 100644 demos/libs/windows/x64/SDL2.lib create mode 100644 demos/libs/windows/x64/SDL2_image.lib create mode 100644 demos/libs/windows/x64/SDL2main.lib create mode 100644 demos/libs/windows/x64/SDL2test.lib create mode 100644 demos/libs/windows/x64/cimgui.lib create mode 100644 demos/source/app.d create mode 100644 demos/source/demos/bullet_madnes.d create mode 100644 demos/source/demos/chipmunk2d.d create mode 100644 demos/source/demos/events.d create mode 100644 demos/source/demos/flag_component.d create mode 100644 demos/source/demos/physics.d create mode 100644 demos/source/demos/simple.d create mode 100644 demos/source/demos/snake.d create mode 100644 demos/source/demos/space_invaders.d create mode 100644 demos/source/game_core/job_updater.d create mode 100644 demos/source/gui/component.d create mode 100644 demos/source/gui/manager.d create mode 100644 demos/source/gui/system.d diff --git a/compile_wasm.py b/compile_wasm.py index da42783..e808354 100644 --- a/compile_wasm.py +++ b/compile_wasm.py @@ -13,7 +13,7 @@ def compile(sources, output): if file_extension == '.d' and filename != 'package': files.append(os.path.join(r, file)) - ldc_cmd = 'ldc2 ' + shared_flags + ldc_flags + '-oq -mtriple=wasm32-unknown-unknown-wasm -betterC -L-allow-undefined --output-bc --od=.bc --singleobj --checkaction=C --of=' + output + ' ' + ldc_cmd = 'ldc2 ' + shared_flags + ldc_flags + '-oq -mtriple=wasm32-unknown-unknown-wasm -betterC --output-bc --od=.bc --singleobj --checkaction=C --of=' + output + ' ' for path in sources: ldc_cmd += '-I' + path + ' ' @@ -56,6 +56,9 @@ for arg in sys.argv[1:]: shared_flags += '-Oz ' elif(arg == '-g'): shared_flags += '-g ' + elif(arg == '-g4'): + ldc_flags += '-g ' + emc_flags += '-g4 ' elif(arg == '--build-tests'): build_tests = 1 elif(arg == '--llvm-lto'): @@ -77,8 +80,9 @@ if build_tests == 0: compile(['tests'], 'tests.bc') -emcc_cmd = 'emcc -v ' + shared_flags + emc_flags + '-s ALLOW_MEMORY_GROWTH=1 -s MALLOC=dlmalloc -s WASM=1 -o index.html ' - +emcc_cmd = 'emcc -v ' + shared_flags + emc_flags + '-s ALLOW_MEMORY_GROWTH=1 -s WASM_MEM_MAX=1024MB -s MALLOC=dlmalloc -s WASM=1 -o index.html ' +#-s ALLOW_MEMORY_GROWTH=1 + emcc_cmd += 'ecs.bc tests.bc' print emcc_cmd diff --git a/demos/.gitignore b/demos/.gitignore index e6f937c..7ccfc2f 100644 --- a/demos/.gitignore +++ b/demos/.gitignore @@ -3,8 +3,9 @@ !**/dub.json !libs/ !*.dll +!libs/** !utils/**/*.d -!simple/**/*.d +!source/**/*.d !launcher/**/*.d !assets/** !external/**/*.d diff --git a/demos/compile_wasm.py b/demos/compile_wasm.py index b34b5c6..06845cf 100644 --- a/demos/compile_wasm.py +++ b/demos/compile_wasm.py @@ -13,7 +13,7 @@ def compile(sources, output): if file_extension == '.d' and filename != 'package': files.append(os.path.join(r, file)) - ldc_cmd = 'ldc2 ' + shared_flags + ldc_flags + '-oq -mtriple=wasm32-unknown-unknown-wasm -betterC -L-allow-undefined --output-bc --od=.bc --singleobj --checkaction=C --of=' + output + ' ' + ldc_cmd = 'ldc2 ' + shared_flags + ldc_flags + '-oq -mtriple=wasm32-unknown-unknown-wasm -betterC --output-bc --od=.bc --singleobj --checkaction=C --of=' + output + ' ' for path in sources: ldc_cmd += '-I' + path + ' ' @@ -58,6 +58,9 @@ for arg in sys.argv[1:]: shared_flags += '-Oz ' elif(arg == '-g'): shared_flags += '-g ' + elif(arg == '-g4'): + ldc_flags += '-g ' + emc_flags += '-g4 ' elif(arg == '--llvm-lto'): emc_flags += '--llvm-lto 3 ' elif(arg == '--simd'): @@ -68,6 +71,10 @@ for arg in sys.argv[1:]: emc_flags += '--llvm-lto 3 -s SIMD=1 ' elif(arg == '--clean'): clean = 1 + elif(arg == '-pthread'): + shared_flags += '-O3 ' + ldc_flags += '-release -enable-inlining ' + emc_flags += '-s PTHREAD_POOL_SIZE=16 -Wl,--no-check-features -s USE_PTHREADS=1 ' elif(arg == '--demo=simple'): demo = 0 else: @@ -83,14 +90,14 @@ compile(['source'], 'demo.bc') if clean or os.path.exists('../ecs.bc') == 0 or os.path.isfile('../ecs.bc') == 0: compile(['../source'], '../ecs.bc') -emcc_cmd = 'emcc -v ' + shared_flags + emc_flags + '-s ALLOW_MEMORY_GROWTH=1 -s MALLOC=dlmalloc -s FULL_ES2=1 -s WASM=1 -o index.html ' +emcc_cmd = 'emcc -v ' + shared_flags + emc_flags + '-s ERROR_ON_UNDEFINED_SYMBOLS=0 -s DISABLE_DEPRECATED_FIND_EVENT_TARGET_BEHAVIOR=1 -s TOTAL_MEMORY=256MB -s WASM_MEM_MAX=1024MB -s MALLOC=dlmalloc -s WASM=1 -o index.html ' +#-s ALLOW_MEMORY_GROWTH=1 -s PROXY_TO_PTHREAD=1 emcc_cmd += '../ecs.bc ' emcc_cmd += 'utils.bc ' emcc_cmd += 'bindbc-sdl.bc ' emcc_cmd += 'glad.bc ' emcc_cmd += 'cimgui.bc ' -emcc_cmd += 'nuklear.bc ' emcc_cmd += 'mmutils.bc ' emcc_cmd += 'demo.bc ' diff --git a/demos/dub.json b/demos/dub.json index 0bda382..009bf9e 100644 --- a/demos/dub.json +++ b/demos/dub.json @@ -22,7 +22,7 @@ "targetType" : "executable", "subConfigurations": { - "ecs":"library" + "ecs_utils":"default" } }, { @@ -33,9 +33,7 @@ ], "subConfigurations": { - "bindbc-sdl":"staticBC", - "ecs_utils":"betterC", - "ecs":"library-betterC" + "ecs_utils":"betterC" } } ] diff --git a/demos/external/sources/mmutils/thread_pool.d b/demos/external/sources/mmutils/thread_pool.d index a986048..eb4d53f 100644 --- a/demos/external/sources/mmutils/thread_pool.d +++ b/demos/external/sources/mmutils/thread_pool.d @@ -537,7 +537,7 @@ else version(D_BetterC) threadStart = dg; handle = cast(HANDLE) _beginthreadex( null, 0, &threadRunFunc, cast(void*)&this, 0, null ); //int ok = pthread_create(&handle, null, &threadRunFunc, cast(void*)&this); - assert(handle == null); + assert(handle != null); } void join() diff --git a/demos/libs/windows/x64/SDL2.lib b/demos/libs/windows/x64/SDL2.lib new file mode 100644 index 0000000000000000000000000000000000000000..89f7d37fcc07c69aa0ff58679a6aa19e5cc0f7b8 GIT binary patch literal 145280 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 literal 0 HcmV?d00001 diff --git a/demos/libs/windows/x64/SDL2_image.lib b/demos/libs/windows/x64/SDL2_image.lib new file mode 100644 index 0000000000000000000000000000000000000000..6d00aed6db965856cea7c53bb15df7462c90b6e9 GIT binary patch literal 10120 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 literal 0 HcmV?d00001 diff --git a/demos/libs/windows/x64/cimgui.lib b/demos/libs/windows/x64/cimgui.lib new file mode 100644 index 0000000000000000000000000000000000000000..3a6b57ca678656b7f7849b1973c942e8a37f666e GIT binary patch literal 136730 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 1000)launcher.delta_time = 1000; + + static uint temp_fps = 0; + static double fps_time = 0; + temp_fps++; + fps_time += launcher.delta_time; + while(fps_time > 1000) + { + fps_time -= 1000; + launcher.fps = temp_fps; + temp_fps = 0; + } + + + SDL_Event event; + while (SDL_PollEvent(&event)) + { + version(WebAssembly)ImGui_ImplSDL2_ProcessEvent(&event); + else ImGui_ImplSDL2_ProcessEvent(&event); + if(launcher.event)launcher.event(&event); + if (event.type == SDL_QUIT || (event.type == SDL_KEYDOWN && event.key.keysym.scancode == SDL_SCANCODE_ESCAPE)) { + quit(); + *cast(bool*)arg = false; + return; + } + else if(event.type == SDL_WINDOWEVENT) + { + switch(event.window.event) + { + case SDL_WINDOWEVENT_RESIZED: + //launcher.renderer.resize(ivec2(event.window.data1,event.window.data2)); + launcher.window_size = ivec2(event.window.data1,event.window.data2); + break; + case SDL_WINDOWEVENT_SIZE_CHANGED: + //launcher.renderer.resize(ivec2(event.window.data1,event.window.data2)); + launcher.window_size = ivec2(event.window.data1,event.window.data2); + break; + default:break; + } + } + } + + version(WebAssembly) + { + ImGui_ImplOpenGL3_NewFrame(); + ImGui_ImplSDL2_NewFrame(launcher.window); + } + else + { + ImGuiImplOpenGL2NewFrame(); + ImGuiImplSDL2NewFrame(launcher.window); + } + + igNewFrame(); + + if(igBeginMainMenuBar()) + { + if(igBeginMenu("File",true)) + { + if(igMenuItemBool("Close","esc",false,true)) + { + quit(); + *cast(bool*)arg = false; + return; + } + igEndMenu(); + } + if(igBeginMenu("Demos",true)) + { + if(igMenuItemBool("Simpe",null,false,true)) + { + import demos.simple; + launcher.switchDemo(&simpleStart,&simpleLoop,&simpleEnd,&simpleEvent,Simple.tips); + } + if(igMenuItemBool("Snake",null,false,true)) + { + import demos.snake; + launcher.switchDemo(&snakeStart,&snakeLoop,&snakeEnd,&snakeEvent,Snake.tips); + } + if(igMenuItemBool("Space invaders",null,false,true)) + { + import demos.space_invaders; + launcher.switchDemo(&spaceInvadersStart,&spaceInvadersLoop,&spaceInvadersEnd,&spaceInvadersEvent,SpaceInvaders.tips); + } + igEndMenu(); + } + if(igBeginMenu("Options",true)) + { + if(igMenuItemBool("VSync", null, launcher.swap_interval, true)) + { + launcher.swap_interval = !launcher.swap_interval; + SDL_GL_SetSwapInterval(launcher.swap_interval); + } + if(igMenuItemBool("Multithreading", null, launcher.multithreading, true)) + { + launcher.multithreading = !launcher.multithreading; + } + if(igBeginMenu("Show",true)) + { + if(igMenuItemBool("Statistics",null,launcher.show_stat_wnd,true)) + { + launcher.show_stat_wnd = !launcher.show_stat_wnd; + } + else if(igMenuItemBool("Demo",null,launcher.show_demo_wnd,true)) + { + launcher.show_demo_wnd = !launcher.show_demo_wnd; + } + else if(igMenuItemBool("Tips",null,launcher.show_tips,true)) + { + launcher.show_tips = !launcher.show_tips; + } + else if(igMenuItemBool("Virual keys",null,launcher.show_virtual_keys_wnd,true)) + { + launcher.show_virtual_keys_wnd = !launcher.show_virtual_keys_wnd; + } + igEndMenu(); + } + if(igBeginMenu("Style",true)) + { + if(igMenuItemBool("Classic",null,launcher.style == 0,true)) + { + launcher.setStyle(0); + } + else if(igMenuItemBool("Dark",null,launcher.style == 1,true)) + { + launcher.setStyle(1); + } + else if(igMenuItemBool("Light",null,launcher.style == 2,true)) + { + launcher.setStyle(2); + } + else if(igMenuItemBool("Super",null,launcher.style == 3,true)) + { + launcher.setStyle(3); + } + igEndMenu(); + } + igEndMenu(); + } + igEndMainMenuBar(); + } + + if(launcher.show_virtual_keys_wnd) + { + igSetNextWindowPos(ImVec2(launcher.window_size.x - 400, launcher.window_size.y - 200), ImGuiCond_Once, ImVec2(0,0)); + igSetNextWindowSize(ImVec2(64*4+128, 168), ImGuiCond_Once); + igSetNextWindowBgAlpha(launcher.windows_alpha); + ImGuiStyle * style = igGetStyle(); + style.Colors[ImGuiCol_Button].w = 0.8; + if(igBegin("Virtual keys",&launcher.show_virtual_keys_wnd, 0)) + { + igColumns(2,null,0); + igSetColumnWidth(0,64*3+16); + igIndent(64+4); + if(igButton("W",ImVec2(64,64)) || igIsItemDeactivated()) + { + launcher.keys[SDL_SCANCODE_W] = false; + } + else if(igIsItemActive()) + { + launcher.keys[SDL_SCANCODE_W] = true; + } + igUnindent(64+4); + if(igButton("A",ImVec2(64,64)) || igIsItemDeactivated()) + { + launcher.keys[SDL_SCANCODE_A] = false; + } + else if(igIsItemActive()) + { + launcher.keys[SDL_SCANCODE_A] = true; + } + igSameLine(0,4); + if(igButton("S",ImVec2(64,64)) || igIsItemDeactivated()) + { + launcher.keys[SDL_SCANCODE_S] = false; + } + else if(igIsItemActive()) + { + launcher.keys[SDL_SCANCODE_S] = true; + } + igSameLine(0,4); + if(igButton("D",ImVec2(64,64)) || igIsItemDeactivated()) + { + launcher.keys[SDL_SCANCODE_D] = false; + } + else if(igIsItemActive()) + { + launcher.keys[SDL_SCANCODE_D] = true; + } + igNextColumn(); + if(igButton("Space",ImVec2(-1,128)) || igIsItemDeactivated()) + { + launcher.keys[SDL_SCANCODE_SPACE] = false; + } + else if(igIsItemActive()) + { + launcher.keys[SDL_SCANCODE_SPACE] = true; + } + igColumns(1,null,0); + } + igEnd(); + style.Colors[ImGuiCol_Button].w = 1.0; + } + + if(launcher.show_tips) + { + igSetNextWindowPos(ImVec2(launcher.window_size.x - 550, 80), ImGuiCond_Once, ImVec2(0,0)); + igSetNextWindowSize(ImVec2(300, 0), ImGuiCond_Once); + igSetNextWindowBgAlpha(launcher.windows_alpha); + if(igBegin("Tips",&launcher.show_tips,ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoSavedSettings)) + { + igTextWrapped(launcher.tips); + } + igEnd(); + } + + if(launcher.show_demo_wnd) + { + igSetNextWindowPos(ImVec2(launcher.window_size.x - 260, 30), ImGuiCond_Once, ImVec2(0,0)); + igSetNextWindowSize(ImVec2(250, 250), ImGuiCond_Once); + if(igBegin("Demo",&launcher.show_demo_wnd,0)) + { + launcher.gui_manager.gui(); + if(igBeginCombo("Tool",tool_strings[launcher.used_tool],0)) + { + if(igSelectable("Entity spawner",false,0,ImVec2(0,0))) + { + launcher.used_tool = Tool.entity_spawner; + } + if(igSelectable("Component manipulator",false,0,ImVec2(0,0))) + { + launcher.used_tool = Tool.component_manipulator; + } + if(igSelectable("Selector",false,0,ImVec2(0,0))) + { + launcher.used_tool = Tool.selector; + } + igEndCombo(); + } + if(igButton("Clear",ImVec2(-1,0))) + { + launcher.manager.begin(); + launcher.manager.update("clean"); + launcher.manager.end(); + } + } + igEnd(); + } + + if(launcher.show_profile_wnd) + { + igSetNextWindowPos(ImVec2(launcher.window_size.x - 260, launcher.window_size.y - 280), ImGuiCond_Once, ImVec2(0,0)); + igSetNextWindowSize(ImVec2(250, 250), ImGuiCond_Once); + if(igBegin("Profile",&launcher.show_profile_wnd,0)) + { + if(igBeginTabBar("ProfileTabBar",ImGuiTabBarFlags_FittingPolicyScroll)) + { + + if(igBeginTabItem("Plots", null, 0)) + { + if(igBeginChild("ProfileChild",ImVec2(-1,-1),0,0)) + { + igPlotLines("Delta time",&launcher.plot_values[0].delta_time,100,launcher.plot_index,"Delta time",0,float.max,ImVec2(0,64),Launcher.PlotStruct.sizeof); + igPlotLines("Loop time",&launcher.plot_values[0].loop_time,100,launcher.plot_index,"Loop time",0,float.max,ImVec2(0,64),Launcher.PlotStruct.sizeof); + igPlotLines("Draw time",&launcher.plot_values[0].draw_time,100,launcher.plot_index,"Draw time",0,float.max,ImVec2(0,64),Launcher.PlotStruct.sizeof); + } + igEndChild(); + igEndTabItem(); + } + if(igBeginTabItem("Multithreading graph", null, 0)) + { + if(igBeginChild("ProfileChild",ImVec2(-1,-1),0,0)) + { + igText("Work in proggress"); + } + igEndChild(); + igEndTabItem(); + } + + igEndTabBar(); + } + } + igEnd(); + } + + launcher.renderer.resize(launcher.window_size); + launcher.renderer.view(vec2(0,0),vec2(launcher.window_size.x,launcher.window_size.y)); + //glClear(GL_COLOR_BUFFER_BIT); + launcher.renderer.clear(); + + double loop_time = launcher.getTime(); + if(launcher.loop && !launcher.loop()) + { + quit(); + *cast(bool*)arg = false; + } + loop_time = launcher.getTime() - loop_time; + + double draw_time = launcher.getTime(); + launcher.renderer.present(); + draw_time = launcher.getTime() - draw_time; + + static float plot_time = 0; + static uint plot_samples = 0; + plot_time += launcher.delta_time; + plot_samples++; + launcher.plot_values[100].delta_time += launcher.delta_time; + launcher.plot_values[100].loop_time += loop_time; + launcher.plot_values[100].draw_time += draw_time; + if(plot_time > 100) + { + launcher.plot_values[launcher.plot_index].delta_time = launcher.plot_values[100].delta_time / cast(float)plot_samples; + launcher.plot_values[launcher.plot_index].loop_time = launcher.plot_values[100].loop_time / cast(float)plot_samples; + launcher.plot_values[launcher.plot_index].draw_time = launcher.plot_values[100].draw_time / cast(float)plot_samples; + launcher.plot_values[100].delta_time = 0; + launcher.plot_values[100].loop_time = 0; + launcher.plot_values[100].draw_time = 0; + + plot_samples = 0; + plot_time -= 100; + launcher.plot_index++; + if(launcher.plot_index >= 100)launcher.plot_index = 0; + } + + if(launcher.show_stat_wnd) + { + igSetNextWindowPos(ImVec2(10, 30), ImGuiCond_Appearing, ImVec2(0,0)); + igSetNextWindowContentSize(ImVec2(150, 0.0f)); + igSetNextWindowBgAlpha(launcher.windows_alpha); + if(igBegin("Statistics", &launcher.show_stat_wnd, ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_AlwaysAutoResize)) + { + igColumns(2,null,0); + igSetColumnWidth(0,100); + igText("FPS: "); + igText("Entities: "); + igText("Loop time: "); + igText("Draw time: "); + igText("Delta time: "); + igNextColumn(); + igText("%u",launcher.fps); + igText("%u",launcher.entities_count); + igText("%2.2fms",loop_time); + igText("%2.2fms",draw_time); + igText("%2.2fms",launcher.delta_time); + igColumns(1,null,0); + } + igEnd(); + } + + glUseProgram(0); + import ecs_utils.gfx.buffer; + Buffer.unbind(Buffer.BindTarget.array); + Buffer.unbind(Buffer.BindTarget.element_array); + + igRender(); + version(WebAssembly)ImGui_ImplOpenGL3_RenderDrawData(igGetDrawData()); + else ImGuiImplOpenGL2RenderDrawData(igGetDrawData()); + + //launcher.renderer.clear(); + //launcher.renderer.present(); + + SDL_GL_SwapWindow(launcher.window); + +} + +void quit() +{ + launcher.gui_manager.clear(); + Mallocator.dispose(launcher.gui_manager); + + launcher.manager.destroy(); + launcher.manager = null; + + version(WebAssembly)emscripten_cancel_main_loop(); +} + +int main(int argc, char** argv) +{ + + if (SDL_Init(SDL_INIT_VIDEO) < 0) + { + printf("SDL could not initialize! SDL_Error: %s", SDL_GetError()); + return -1; + } + + SDL_version sdl_version; + SDL_GetVersion(&sdl_version); + printf("SDL version: %u.%u.%u\n",cast(uint)sdl_version.major,cast(uint)sdl_version.minor,cast(uint)sdl_version.patch); + + SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2); + SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0); + launcher.window = SDL_CreateWindow("Simple", SDL_WINDOWPOS_CENTERED, + SDL_WINDOWPOS_CENTERED, launcher.window_size.x, launcher.window_size.y, SDL_WINDOW_SHOWN | SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE); + + launcher.gl_context = SDL_GL_CreateContext(launcher.window); + launcher.context = igCreateContext(null); + launcher.timer_freq = SDL_GetPerformanceFrequency(); + + launcher.plot_values = Mallocator.makeArray!(Launcher.PlotStruct)(101); + + SDL_GetWindowSize(launcher.window, &launcher.window_size.x, &launcher.window_size.y); + + version(WebAssembly) + { + gladLoadGLES2(x => SDL_GL_GetProcAddress(x)); + if(!ImGui_ImplSDL2_InitForOpenGL(launcher.window,launcher.gl_context)) + { + printf("ImGui initialization failed!"); + return -2; + } + if(!ImGui_ImplOpenGL3_Init()) + { + printf("ImGui OpenGL initialization failed!"); + return -3; + } + } + else + { + gladLoadGL(); + if(!ImGuiImplSDL2InitForOpenGL(launcher.window,launcher.gl_context)) + { + printf("ImGui initialization failed!"); + return -2; + } + if(!ImGuiImplOpenGL2Init()) + { + printf("ImGui OpenGL initialization failed!"); + return -3; + } + } + + ImFontConfig* config = ImFontConfig_ImFontConfig(); + ImGuiIO* io = igGetIO(); + const ushort* font_ranges = ImFontAtlas_GetGlyphRangesDefault(io.Fonts); + ImFontAtlas_AddFontFromFileTTF(io.Fonts,"assets/fonts/Ruda-Bold.ttf", 15.0f, config, font_ranges); + + setStyle(3); + + launcher.job_updater = Mallocator.make!ECSJobUpdater(8); + //launcher.job_updater.onCreate(); + + EntityManager.initialize(8); + launcher.manager = EntityManager.instance; + + launcher.manager.m_thread_id_func = &launcher.job_updater.getThreadID; + launcher.manager.setJobDispachFunc(&launcher.job_updater.dispatch); + + launcher.manager.beginRegister(); + + launcher.manager.registerPass("clean"); + + launcher.manager.registerSystem!CountSystem(10000); + launcher.manager.registerSystem!CleanSystem(0,"clean"); + + launcher.manager.endRegister(); + + loadGFX(); + + launcher.renderer.initialize(); + + launcher.gui_manager = Mallocator.make!GUIManager(); + + { + import demos.simple; + launcher.switchDemo(&simpleStart,&simpleLoop,&simpleEnd,&simpleEvent,Simple.tips); + } + + int key_num; + ubyte* keys = SDL_GetKeyboardState(&key_num); + launcher.keys = keys[0..key_num]; + + version(WebAssembly) + { + /*EmscriptenFullscreenStrategy strategy; + strategy.scaleMode = EMSCRIPTEN_FULLSCREEN_SCALE_STRETCH; + strategy.canvasResolutionScaleMode = EMSCRIPTEN_FULLSCREEN_CANVAS_SCALE_STDDEF; + strategy.filteringMode = EMSCRIPTEN_FULLSCREEN_FILTERING_NEAREST;*/ + + //int result = emscripten_request_fullscreen_strategy(null, true, &strategy); + //emscripten_enter_soft_fullscreen(null, &strategy); + //printf("Fullscreen request: %s.\n", emscripten_result_to_string(result)); + emscripten_set_main_loop_arg(&mainLoop, null, -1, 1); + } + else + { + bool arg = true; + while(arg == true) + { + mainLoop(&arg); + } + } + + return 0; +} + +void loadGFX() +{ + import ecs_utils.gfx.texture; + import ecs_utils.gfx.vertex; + import ecs_utils.gfx.shader; + import ecs_utils.gfx.material; + import ecs_utils.gfx.config; + import ecs_utils.gfx.mesh; + + Texture.__loadBackend(); + Renderer.__loadBackend(); + + GfxConfig.materials = Mallocator.makeArray!Material(1); + GfxConfig.meshes = Mallocator.makeArray!Mesh(1); + + float[16] vertices = [-0.5,-0.5, 0,0, -0.5,0.5, 0,1, 0.5,-0.5, 1,0, 0.5,0.5, 1,1]; + GfxConfig.meshes[0].vertices = Mallocator.makeArray(vertices); + ushort[6] indices = [0,1,2,1,2,3]; + GfxConfig.meshes[0].indices = Mallocator.makeArray(indices); + GfxConfig.meshes[0].uploadData(); + + Shader vsh; + vsh.create(); + vsh.load("assets/shaders/base.vp"); + vsh.compile(); + + Shader fsh; + fsh.create(); + fsh.load("assets/shaders/base.fp"); + fsh.compile(); + + GfxConfig.materials[0].create(); + GfxConfig.materials[0].data.blend_mode = Material.BlendMode.opaque; + GfxConfig.materials[0].data.mode = Material.TransformMode.position; + Material.ShaderModule[1] modules = [Material.ShaderModule(vsh,fsh)]; + GfxConfig.materials[0].attachModules(modules); + //GfxConfig.materials[0]. + //GfxConfig.materials[0].load(load_data.materials[i].str); + GfxConfig.materials[0].compile(); + GfxConfig.materials[0].bindAttribLocation("positions",0); + GfxConfig.materials[0].bindAttribLocation("tex_coords",1); + GfxConfig.materials[0].link(); + + GfxConfig.materials[0].data.uniforms = Mallocator.makeArray!(Material.Uniform)(3); + GfxConfig.materials[0].data.uniforms[0] = Material.Uniform(Material.Type.float4, GfxConfig.materials[0].getLocation("matrix_1"), 0); + GfxConfig.materials[0].data.uniforms[1] = Material.Uniform(Material.Type.float4, GfxConfig.materials[0].getLocation("matrix_2"), 16); + GfxConfig.materials[0].data.uniforms[2] = Material.Uniform(Material.Type.float4, GfxConfig.materials[0].getLocation("uv_transform"), 32); + GfxConfig.materials[0].data.bindings = Mallocator.makeArray!(int)(1); + GfxConfig.materials[0].data.bindings[0] = GfxConfig.materials[0].getLocation("tex"); + + + /*glUseProgram(0); + glBindBuffer(GL_ARRAY_BUFFER, 0); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);*/ +} \ No newline at end of file diff --git a/demos/source/demos/bullet_madnes.d b/demos/source/demos/bullet_madnes.d new file mode 100644 index 0000000..0996e2e --- /dev/null +++ b/demos/source/demos/bullet_madnes.d @@ -0,0 +1,19 @@ +module demos.bullet_madnes; + +import app; + +import bindbc.sdl; + +import cimgui.cimgui; + +import ecs.attributes; +import ecs.core; +import ecs.entity; +import ecs.manager; +import ecs.std; + +import ecs_utils.gfx.texture; +import ecs_utils.math.vector; +import ecs_utils.utils; + +extern(C): \ No newline at end of file diff --git a/demos/source/demos/chipmunk2d.d b/demos/source/demos/chipmunk2d.d new file mode 100644 index 0000000..25b9c66 --- /dev/null +++ b/demos/source/demos/chipmunk2d.d @@ -0,0 +1,19 @@ +module demos.chipmunk2d; + +import app; + +import bindbc.sdl; + +import cimgui.cimgui; + +import ecs.attributes; +import ecs.core; +import ecs.entity; +import ecs.manager; +import ecs.std; + +import ecs_utils.gfx.texture; +import ecs_utils.math.vector; +import ecs_utils.utils; + +extern(C): \ No newline at end of file diff --git a/demos/source/demos/events.d b/demos/source/demos/events.d new file mode 100644 index 0000000..620ff4d --- /dev/null +++ b/demos/source/demos/events.d @@ -0,0 +1,19 @@ +module demos.events; + +import app; + +import bindbc.sdl; + +import cimgui.cimgui; + +import ecs.attributes; +import ecs.core; +import ecs.entity; +import ecs.manager; +import ecs.std; + +import ecs_utils.gfx.texture; +import ecs_utils.math.vector; +import ecs_utils.utils; + +extern(C): \ No newline at end of file diff --git a/demos/source/demos/flag_component.d b/demos/source/demos/flag_component.d new file mode 100644 index 0000000..a1863b9 --- /dev/null +++ b/demos/source/demos/flag_component.d @@ -0,0 +1,19 @@ +module demos.flag_component; + +import app; + +import bindbc.sdl; + +import cimgui.cimgui; + +import ecs.attributes; +import ecs.core; +import ecs.entity; +import ecs.manager; +import ecs.std; + +import ecs_utils.gfx.texture; +import ecs_utils.math.vector; +import ecs_utils.utils; + +extern(C): \ No newline at end of file diff --git a/demos/source/demos/physics.d b/demos/source/demos/physics.d new file mode 100644 index 0000000..6e9ba4a --- /dev/null +++ b/demos/source/demos/physics.d @@ -0,0 +1,19 @@ +module demos.physics; + +import app; + +import bindbc.sdl; + +import cimgui.cimgui; + +import ecs.attributes; +import ecs.core; +import ecs.entity; +import ecs.manager; +import ecs.std; + +import ecs_utils.gfx.texture; +import ecs_utils.math.vector; +import ecs_utils.utils; + +extern(C): \ No newline at end of file diff --git a/demos/source/demos/simple.d b/demos/source/demos/simple.d new file mode 100644 index 0000000..9340458 --- /dev/null +++ b/demos/source/demos/simple.d @@ -0,0 +1,171 @@ +module demos.simple; + +import app; + +import bindbc.sdl; + +import cimgui.cimgui; + +import ecs.attributes; +import ecs.core; +import ecs.entity; +import ecs.manager; +import ecs.std; + +import ecs_utils.gfx.texture; +import ecs_utils.math.vector; +import ecs_utils.utils; + +extern(C): + +struct Simple +{ + __gshared const (char)* tips = "Use \"space\" to spwan entities.\n\nSystems can be enabled/disabled from \"Simple\" window."; + + EntityTemplate* tmpl; + Texture texture; + + bool move_system = true; + bool draw_system = true; +} + +struct CLocation +{ + mixin ECS.Component; + + alias location this; + + vec2 location; +} + +struct CTexture +{ + mixin ECS.Component; + + Texture tex; +} + +struct DrawSystem +{ + mixin ECS.System!1; + + struct EntitiesData + { + uint length; + @readonly CTexture[] textures; + @readonly CLocation[] locations; + } + + void onUpdate(EntitiesData data) + { + foreach(i; 0..data.length) + { + launcher.renderer.draw(data.textures[i].tex, data.locations[i].location, vec2(32,32), vec4(0,0,1,1), 0, 0 , 0); + //draw(renderer, data.textures[i].tex, data.locations[i], vec2(32,32), vec4(0,0,1,1)); + } + } +} + +struct MoveSystem +{ + mixin ECS.System!64; + + struct EntitiesData + { + uint length; + CLocation[] locations; + } + + void onUpdate(EntitiesData data) + { + foreach(i; 0..data.length) + { + data.locations[i].location.y = data.locations[i].location.y + 1; + if(data.locations[i].location.y > 400)data.locations[i].location.y = 0; + } + } +} + +Simple* simple; + +void simpleStart() +{ + simple = Mallocator.make!Simple; + + simple.texture.create(); + simple.texture.load("assets/textures/buckler.png"); + + launcher.manager.beginRegister(); + + launcher.manager.registerComponent!CLocation; + launcher.manager.registerComponent!CTexture; + + launcher.manager.registerSystem!MoveSystem(0); + launcher.manager.registerSystem!DrawSystem(1); + + launcher.manager.endRegister(); + + launcher.gui_manager.addSystem(MoveSystem.system_id,"Move System"); + launcher.gui_manager.addSystem(DrawSystem.system_id,"Draw System"); + + ushort[2] components = [CLocation.component_id, CTexture.component_id]; + simple.tmpl = launcher.manager.allocateTemplate(components); + CTexture* tex_comp = simple.tmpl.getComponent!CTexture; + tex_comp.tex = simple.texture; + CLocation* loc_comp = simple.tmpl.getComponent!CLocation; + + foreach(i; 0..10) + foreach(j; 0..10) + { + loc_comp.location = vec2(i*32+64,j*32+64); + launcher.manager.addEntity(simple.tmpl); + } +} + +void simpleEnd() +{ + launcher.manager.getSystem(MoveSystem.system_id).disable(); + launcher.manager.getSystem(DrawSystem.system_id).disable(); + + simple.texture.destroy(); + + launcher.manager.freeTemplate(simple.tmpl); + Mallocator.dispose(simple); +} + +void simpleEvent(SDL_Event* event) +{ + +} + +void spawnEntity() +{ + CLocation* loc_comp = simple.tmpl.getComponent!CLocation; + loc_comp.location = vec2(randomf() * 600,0); + launcher.manager.addEntity(simple.tmpl); +} + +bool simpleLoop() +{ + if(launcher.getKeyState(SDL_SCANCODE_SPACE)) + { + spawnEntity(); + } + + + launcher.manager.begin(); + if(launcher.multithreading) + { + launcher.job_updater.begin(); + launcher.manager.updateMT(); + launcher.job_updater.call(); + launcher.multithreading = false; + } + else + { + launcher.manager.update(); + } + launcher.manager.end(); + + return true; +} \ No newline at end of file diff --git a/demos/source/demos/snake.d b/demos/source/demos/snake.d new file mode 100644 index 0000000..19f08ad --- /dev/null +++ b/demos/source/demos/snake.d @@ -0,0 +1,522 @@ +module demos.snake; + +import app; + +import bindbc.sdl; + +import cimgui.cimgui; + +import ecs.attributes; +import ecs.core; +import ecs.entity; +import ecs.manager; +import ecs.std; +import ecs.vector; + +import ecs_utils.gfx.texture; +import ecs_utils.math.vector; +import ecs_utils.utils; + +extern(C): + +struct MapElement +{ + enum Type + { + empty = 0, + snake = 1, + apple = 2, + wall = 3 + } + Type type; + EntityID id; +} + +struct Snake +{ + __gshared const (char)* tips = "Use \"WASD\" keys to move."; + + EntityTemplate* apple_tmpl; + EntityTemplate* snake_tmpl; + Texture snake_texture; + Texture wall_texture; + Texture apple_texture; + + bool move_system = true; + bool draw_system = true; + + const int map_size = 18; + + MapElement[map_size * map_size] map; + + MapElement element(ivec2 pos) + { + return map[pos.x + pos.y * map_size]; + } + + void element(MapElement el, ivec2 pos) + { + map[pos.x + pos.y * map_size] = el; + } + + void addApple() + { + ivec2 random_pos = ivec2(rand()%map_size,rand()%map_size); + while(element(random_pos).type != MapElement.Type.empty) + { + random_pos.x += 1; + if(random_pos.x > map_size) + { + random_pos.y = 0; + random_pos.y += 1; + if(random_pos.y > map_size)random_pos.y = 0; + } + } + Entity* apple = launcher.manager.addEntity(apple_tmpl); + element(MapElement(MapElement.Type.apple,apple.id),random_pos); + } + + void drawMap() + { + foreach(x; 0 .. map_size) + { + foreach(y; 0 .. map_size) + { + switch(element(ivec2(x,y)).type) + { + case MapElement.Type.apple:launcher.renderer.draw(apple_texture, vec2(x*32,y*32), vec2(32,32), vec4(0,0,1,1), 0, 0 , 0);break; + case MapElement.Type.snake:launcher.renderer.draw(snake_texture, vec2(x*32,y*32), vec2(32,32), vec4(0,0,1,1), 0, 0 , 0);break; + case MapElement.Type.wall:launcher.renderer.draw(wall_texture, vec2(x*32,y*32), vec2(32,32), vec4(0,0,1,1), 0, 0 , 0);break; + default:break; + } + } + } + } + +} + +struct CILocation +{ + mixin ECS.Component; + + alias location this; + + ivec2 location; +} + +struct CLocation +{ + mixin ECS.Component; + + alias location this; + + vec2 location; +} + +struct CSnake +{ + void onCreate() + { + parts.array = Mallocator.makeArray!ivec2(100); + } + + void onDestroy() + { + Mallocator.dispose(parts.array); + } + + mixin ECS.Component; + + struct Parts + { + uint length = 0; + ivec2[] array; + + ivec2 opIndex(size_t ind) const + { + return array[ind]; + } + + ivec2[] opSlice() + { + return array[0 .. length]; + } + + void opIndexAssign(ivec2 vec, size_t ind) + { + array[ind] = vec; + } + + size_t opDollar() const + { + return length; + } + + void add(ivec2 v) + { + length++; + array[length-1] = v; + } + } + + Parts parts; +} + +struct CApple +{ + mixin ECS.Component; +} + +struct CParticle +{ + mixin ECS.Component; +} + +struct CParticleVector +{ + mixin ECS.Component; + + vec2 velocity; +} + +struct CMovement +{ + mixin ECS.Component; + + enum Direction : byte + { + up, + down, + left, + right + } + + Direction direction; +} + +struct CInput +{ + mixin ECS.Component; +} + +struct MoveSystem +{ + mixin ECS.System!64; + + struct EntitiesData + { + uint length; + @readonly Entity[] entities; + @readonly CMovement[] movement; + @optional CSnake[] snakes; + CILocation[] location; + } + + void moveLocation(ref CILocation location, CMovement.Direction direction) + { + final switch(direction) + { + case CMovement.Direction.down: + location.y -= 1; + if(location.y < 0)location.y = snake.map_size - 1; + break; + case CMovement.Direction.up: + location.y += 1; + if(location.y >= snake.map_size)location.y = 0; + break; + case CMovement.Direction.left: + location.x -= 1; + if(location.x < 0)location.x = snake.map_size - 1; + break; + case CMovement.Direction.right: + location.x += 1; + if(location.x >= snake.map_size)location.x = 0; + break; + } + } + + void moveSnake(ref CSnake snake, ivec2 location) + { + if(snake.parts.length) + { + .snake.element(MapElement(),snake.parts[0]); + foreach(j; 0 .. snake.parts.length - 1) + { + snake.parts[j] = snake.parts[j + 1]; + } + snake.parts[$-1] = location; + } + else .snake.element(MapElement(),location); + } + + void onUpdate(EntitiesData data) + { + if(data.snakes) + { + foreach(i; 0..data.length) + { + ivec2 new_location = data.location[i]; + moveLocation(data.location[i], data.movement[i].direction); + final switch(snake.element(data.location[i].location).type) + { + case MapElement.Type.snake: + launcher.manager.removeEntity(data.entities[i].id); + break; + case MapElement.Type.wall: + launcher.manager.removeEntity(data.entities[i].id); + break; + case MapElement.Type.empty: + moveSnake(data.snakes[i], new_location); + snake.element(MapElement(MapElement.Type.snake, data.entities[i].id),data.location[i].location); + break; + case MapElement.Type.apple: + data.snakes[i].parts.add(new_location); + snake.element(MapElement(MapElement.Type.snake, data.entities[i].id),new_location); + snake.element(MapElement(MapElement.Type.snake, data.entities[i].id),data.location[i].location); + snake.addApple(); + break; + } + } + } + else + { + foreach(i; 0..data.length) + { + final switch(data.movement[i].direction) + { + case CMovement.Direction.down:data.location[i].location.y -= 1;break; + case CMovement.Direction.up:data.location[i].location.y += 1;break; + case CMovement.Direction.left:data.location[i].location.x -= 1;break; + case CMovement.Direction.right:data.location[i].location.x += 1;break; + } + } + } + + } +} + +struct InputSystem +{ + mixin ECS.System!64; + + struct EntitiesData + { + uint length; + CMovement[] movement; + @readonly CInput[] input; + } + + void onUpdate(EntitiesData data) + { + foreach(i; 0..data.length) + { + if(launcher.getKeyState(SDL_SCANCODE_W)) + { + data.movement[i].direction = CMovement.Direction.up; + } + else if(launcher.getKeyState(SDL_SCANCODE_S)) + { + data.movement[i].direction = CMovement.Direction.down; + } + else if(launcher.getKeyState(SDL_SCANCODE_A)) + { + data.movement[i].direction = CMovement.Direction.left; + } + else if(launcher.getKeyState(SDL_SCANCODE_D)) + { + data.movement[i].direction = CMovement.Direction.right; + } + } + } +} + +struct FixSnakeDirectionSystem +{ + mixin ECS.System!64; + + struct EntitiesData + { + uint length; + CMovement[] movement; + @readonly CILocation[] location; + const (CSnake)[] snake; + } + + void onUpdate(EntitiesData data) + { + foreach(i; 0..data.length) + { + ivec2 last_location; + if(data.snake[i].parts.length)last_location = data.snake[i].parts[$ - 1]; + else continue; + ivec2 next_location = data.location[i]; + + final switch(data.movement[i].direction) + { + case CMovement.Direction.up: + next_location.y += 1; + if(next_location.y >= snake.map_size)next_location.y = 0; + if(next_location.x == last_location.x && next_location.y == last_location.y) + { + data.movement[i].direction = CMovement.Direction.down; + } + break; + case CMovement.Direction.down: + next_location.y -= 1; + if(next_location.y < 0)next_location.y = snake.map_size - 1; + if(next_location.x == last_location.x && next_location.y == last_location.y) + { + data.movement[i].direction = CMovement.Direction.up; + } + break; + case CMovement.Direction.left: + next_location.x -= 1; + if(next_location.x < 0)next_location.x = snake.map_size - 1; + if(next_location.x == last_location.x && next_location.y == last_location.y) + { + data.movement[i].direction = CMovement.Direction.right; + } + break; + case CMovement.Direction.right: + next_location.x += 1; + if(next_location.x >= snake.map_size)next_location.x = 0; + if(next_location.x == last_location.x && next_location.y == last_location.y) + { + data.movement[i].direction = CMovement.Direction.left; + } + break; + } + } + } +} + +struct CleanSystem +{ + mixin ECS.System!64; + + struct EntitiesData + { + uint length; + Entity[] entities; + } + + void onUpdate(EntitiesData data) + { + foreach(i; 0..data.length) + { + launcher.manager.removeEntity(data.entities[i].id); + } + } +} + +Snake* snake; + +void snakeStart() +{ + snake = Mallocator.make!Snake; + + snake.snake_texture.create(); + snake.snake_texture.load("assets/textures/buckler.png"); + + snake.apple_texture.create(); + snake.apple_texture.load("assets/textures/buckler.png"); + + snake.wall_texture.create(); + snake.wall_texture.load("assets/textures/buckler.png"); + + launcher.manager.beginRegister(); + + launcher.manager.registerPass("fixed"); + + launcher.manager.registerComponent!CLocation; + launcher.manager.registerComponent!CILocation; + launcher.manager.registerComponent!CSnake; + launcher.manager.registerComponent!CApple; + launcher.manager.registerComponent!CParticle; + launcher.manager.registerComponent!CMovement; + launcher.manager.registerComponent!CInput; + + launcher.manager.registerSystem!MoveSystem(0,"fixed"); + launcher.manager.registerSystem!InputSystem(-100); + launcher.manager.registerSystem!FixSnakeDirectionSystem(-1,"fixed"); + + launcher.manager.endRegister(); + + launcher.gui_manager.addSystem(MoveSystem.system_id,"Move System"); + launcher.gui_manager.addSystem(InputSystem.system_id,"Input System"); + launcher.gui_manager.addSystem(FixSnakeDirectionSystem.system_id,"Fix Direction System"); + + { + ushort[4] components = [CILocation.component_id, CSnake.component_id, CMovement.component_id, CInput.component_id]; + snake.snake_tmpl = launcher.manager.allocateTemplate(components); + CILocation* loc_comp = snake.snake_tmpl.getComponent!CILocation; + loc_comp.location = ivec2(2,2); + launcher.manager.addEntity(snake.snake_tmpl); + } + + { + ushort[2] components = [CILocation.component_id, CApple.component_id]; + snake.apple_tmpl = launcher.manager.allocateTemplate(components); + snake.addApple(); + } + + /*foreach(i; 0..10) + foreach(j; 0..10) + { + loc_comp.location = vec2(i*32+64,j*32+64); + launcher.manager.addEntity(simple.tmpl); + }*/ +} + +void snakeEnd() +{ + snake.wall_texture.destroy(); + snake.apple_texture.destroy(); + snake.snake_texture.destroy(); + + //launcher.manager.freeTemplate(simple.tmpl); + Mallocator.dispose(snake); +} + +void snakeEvent(SDL_Event* event) +{ + +} + +bool snakeLoop() +{ + /*if(launcher.show_demo_wnd) + { + igSetNextWindowPos(ImVec2(800 - 260, 30), ImGuiCond_Once, ImVec2(0,0)); + igSetNextWindowSize(ImVec2(250, 0), ImGuiCond_Once); + if(igBegin("Snake",&launcher.show_demo_wnd,0)) + { + + } + igEnd(); + }*/ + + launcher.manager.begin(); + + float delta_time = launcher.delta_time; + if(delta_time > 2000)delta_time = 2000; + static float time = 0; + + if(launcher.getKeyState(SDL_SCANCODE_SPACE))time += delta_time * 3; + else time += delta_time; + + while(time > 100) + { + time -= 100; + + launcher.manager.update("fixed"); + } + + launcher.manager.update(); + + launcher.manager.end(); + + snake.drawMap(); + + return true; +} \ No newline at end of file diff --git a/demos/source/demos/space_invaders.d b/demos/source/demos/space_invaders.d new file mode 100644 index 0000000..2d8ebc0 --- /dev/null +++ b/demos/source/demos/space_invaders.d @@ -0,0 +1,764 @@ +module demos.space_invaders; + +import app; + +import bindbc.sdl; + +import cimgui.cimgui; + +import ecs.attributes; +import ecs.core; +import ecs.entity; +import ecs.manager; +import ecs.std; + +import ecs_utils.gfx.texture; +import ecs_utils.math.vector; +import ecs_utils.utils; + +extern(C): + +/*####################################################################################################################### +------------------------------------------------ Types ------------------------------------------------------------------ +#######################################################################################################################*/ + +struct SpaceInvaders +{ + __gshared const (char)* tips = "Use \"WASD\" keys to move and \"Space\" for shooting."; + + EntityTemplate* enemy_tmpl; + EntityTemplate* ship_tmpl; + EntityTemplate* laser_tmpl; + Texture enemy_tex; + Texture ship_tex; + Texture laser_tex; + + bool move_system = true; + bool draw_system = true; + + const vec2 map_size = vec2(600,600); + const float cell_size = 60; +} + +struct SceneGrid +{ + struct Element + { + EntityID entity; + int guild; + vec2 min; + vec2 max; + } + + struct Cell + { + Element[20] elements; + } + + void create() + { + cells_count.x = cast(int)((space_invaders.map_size.x - 0.01f) / space_invaders.cell_size) + 1; + cells_count.y = cast(int)((space_invaders.map_size.y - 0.01f) / space_invaders.cell_size) + 1; + cells = Mallocator.makeArray!Cell(cells_count.x * cells_count.y); + } + + void destory() + { + if(cells) + { + Mallocator.dispose(cells); + cells = null; + } + } + + ivec2 cells_count; + Cell[] cells; +} + +enum Direction : byte +{ + up, + down, + left, + right +} + +/*####################################################################################################################### +------------------------------------------------ Components ------------------------------------------------------------------ +#######################################################################################################################*/ + +struct CLocation +{ + mixin ECS.Component; + + alias value this; + + vec2 value; +} + +struct CScale +{ + mixin ECS.Component; + + ///use component as it value + alias value this; + + vec2 value = vec2(32,32); +} + +struct CTexture +{ + mixin ECS.Component; + + Texture tex; +} + +struct CVelocity +{ + mixin ECS.Component; + + alias value this; + + vec2 value = vec2(0,0); +} + +struct CInput +{ + mixin ECS.Component; +} + +struct CEnemy +{ + mixin ECS.Component; +} + +struct CShip +{ + mixin ECS.Component; +} + +struct CAutoShoot +{ + mixin ECS.Component; +} + +struct CGuild +{ + mixin ECS.Component; + + int guild; +} + +struct CLaser +{ + mixin ECS.Component; + + float damage = 1.0f; +} + +struct CLaserWeapon +{ + mixin ECS.Component; + + ubyte level = 1; + float shoot_time = 0; +} + +struct CShootDirection +{ + mixin ECS.Component; + + Direction direction; +} + +struct CSideMove +{ + mixin ECS.Component; + + byte group = -1; +} + +/*####################################################################################################################### +------------------------------------------------ Events ------------------------------------------------------------------ +#######################################################################################################################*/ + +struct EChangeDirection +{ + mixin ECS.Event; + + this(Direction direction) + { + this.direction = direction; + } + + Direction direction; +} + +/*####################################################################################################################### +------------------------------------------------ Systems ------------------------------------------------------------------ +#######################################################################################################################*/ + +struct DrawSystem +{ + mixin ECS.System!1; + + struct EntitiesData + { + uint length; + @readonly CTexture[] textures; + @readonly CLocation[] locations; + @readonly CScale[] scale; + } + + void onUpdate(EntitiesData data) + { + foreach(i; 0..data.length) + { + launcher.renderer.draw(data.textures[i].tex, data.locations[i].value, data.scale[i], vec4(0,0,1,1), 0, 0 , 0); + //draw(renderer, data.textures[i].tex, data.locations[i], vec2(32,32), vec4(0,0,1,1)); + } + } +} + +struct CollisionSystem +{ + mixin ECS.System; + + struct EntitiesData + { + + } + + void onUpdate(EntitiesData data) + { + + } +} + +struct LaserShootingSystem +{ + mixin ECS.System!32; + + bool shoot = false; + float[10] laser_shoot_times = [2000,1500,1000,700,500,300,100,50,10,1]; + + CLocation* laser_location; + CVelocity* laser_velocity; + + struct EntitiesData + { + ///variable named "length" contain entites count + uint length; + @readonly CShootDirection[] shoot_direction; + @readonly @optional CAutoShoot[] auto_shoot; + @readonly CLocation[] location; + CLaserWeapon[] laser; + } + + ///Called inside "registerSystem" function + /*void onCreate() + { + laser_location = space_invaders.laser_tmpl.getComponent!CLocation; + }*/ + + bool onBegin() + { + laser_location = space_invaders.laser_tmpl.getComponent!CLocation; + laser_velocity = space_invaders.laser_tmpl.getComponent!CVelocity; + if(launcher.getKeyState(SDL_SCANCODE_SPACE)) + { + shoot = true; + } + else shoot = false; + return true; + } + + void onUpdate(EntitiesData data) + { + //conditional branch for whole entities block + if(shoot || data.auto_shoot) + { + foreach(i;0..data.length) + { + CLaserWeapon* laser = &data.laser[i]; + laser.shoot_time += launcher.delta_time; + while(laser.shoot_time > laser_shoot_times[laser.level - 1]) + { + laser.shoot_time -= laser_shoot_times[laser.level - 1]; + laser_location.value = data.location[i]; + laser_velocity.value = vec2(randomf()*0.5-0.25,data.shoot_direction[i].direction == Direction.up ? 1.0 : -1.0); + launcher.manager.addEntity(space_invaders.laser_tmpl); + } + } + } + else + { + foreach(i;0..data.length) + { + CLaserWeapon* laser = &data.laser[i]; + laser.shoot_time += launcher.delta_time; + if(laser.shoot_time > laser_shoot_times[laser.level - 1])laser.shoot_time = laser_shoot_times[laser.level - 1]; + } + } + + } +} + +struct ChangeDirectionSystem +{ + mixin ECS.System; + + Direction[8] groups_directions; + + struct EntitiesData + { + uint length; + const (Entity)[] entities; + CVelocity[] velocity; + + @optional const(CSideMove)[] side_move; + } + + void onCreate() + { + foreach(ref direction; groups_directions) + { + direction = cast(Direction)-1; + } + } + + bool onBegin() + { + foreach(direction; groups_directions) + { + if(direction != cast(Direction)-1)return true; + } + return false; + } + + void onEnd() + { + foreach(ref direction; groups_directions) + { + direction = cast(Direction)-1; + } + } + + void onUpdate(EntitiesData data) + { + if(!data.side_move)return; + foreach(i;0..data.length) + { + byte group = data.side_move[i].group; + if(group == -1)continue; + Direction direction = groups_directions[group]; + if(direction != cast(Direction)-1) + { + CVelocity* velocity = &data.velocity[i]; + final switch(direction) + { + case Direction.up: + if(velocity.value.y > 0)velocity.value.y = -velocity.value.y; + break; + case Direction.down: + if(velocity.value.y < 0)velocity.value.y = -velocity.value.y; + break; + case Direction.left: + if(velocity.value.x > 0)velocity.value.x = -velocity.value.x; + break; + case Direction.right: + if(velocity.value.x < 0)velocity.value.x = -velocity.value.x; + break; + } + } + } + } + + void handleEvent(Entity* entity, EChangeDirection event) + { + CSideMove* side_move = entity.getComponent!CSideMove; + if(side_move && side_move.group != -1) + { + groups_directions[side_move.group] = event.direction; + return; + } + //Entity* entity = launcher.manager.getEntity(event.entity_id); + CVelocity* velocity = entity.getComponent!CVelocity; + final switch(event.direction) + { + case Direction.up: + if(velocity.value.y > 0)velocity.value.y = -velocity.value.y; + break; + case Direction.down: + if(velocity.value.y < 0)velocity.value.y = -velocity.value.y; + break; + case Direction.left: + if(velocity.value.x > 0)velocity.value.x = -velocity.value.x; + break; + case Direction.right: + if(velocity.value.x < 0)velocity.value.x = -velocity.value.x; + break; + } + } +} + +struct ClampPositionSystem +{ + mixin ECS.System!32; + + struct EntitiesData + { + uint length; + const (Entity)[] entities; + //components are treated as required by default + CLocation[] locations; + + @optional const (CLaser)[] laser; + @optional const (CSideMove)[] side_move; + } + + void onUpdate(EntitiesData data) + { + if(data.laser) + { + foreach(i;0..data.length) + { + if(data.locations[i].x < 0 || data.locations[i].x > space_invaders.map_size.x || + data.locations[i].y < 0 || data.locations[i].y > space_invaders.map_size.y)launcher.manager.removeEntity(data.entities[i].id); + } + } + else if(data.side_move) + { + foreach(i;0..data.length) + { + if(data.locations[i].x < 0) + { + //data.locations[i].x = 0; + launcher.manager.sendEvent(data.entities[i].id,EChangeDirection(Direction.right)); + } + else if(data.locations[i].x > space_invaders.map_size.x) + { + //data.locations[i].x = space_invaders.map_size.x; + launcher.manager.sendEvent(data.entities[i].id,EChangeDirection(Direction.left)); + } + if(data.locations[i].y < 0) data.locations[i].y = 0; + else if(data.locations[i].y > space_invaders.map_size.y)data.locations[i].y = space_invaders.map_size.y; + } + } + else + { + foreach(i;0..data.length) + { + if(data.locations[i].x < 0)data.locations[i].x = 0; + else if(data.locations[i].x > space_invaders.map_size.x)data.locations[i].x = space_invaders.map_size.x; + if(data.locations[i].y < 0)data.locations[i].y = 0; + else if(data.locations[i].y > space_invaders.map_size.y)data.locations[i].y = space_invaders.map_size.y; + } + } + } +} + +struct MovementSystem +{ + mixin ECS.System!32; + + struct EntitiesData + { + uint length; + //read only components can be marked with @readonly attribute or with const expression instead + const (CVelocity)[] velocity; + //components are treated as required by default + CLocation[] locations; + //@optional const (CLaser)[] laser; + const (Entity)[] entities; + + @optional CSideMove[] side_move; + } + + void onUpdate(EntitiesData data) + { + foreach(i;0..data.length) + { + data.locations[i].x += data.velocity[i].x * launcher.delta_time; + data.locations[i].y += data.velocity[i].y * launcher.delta_time; + } + } +} + +/** +*System is responsible for movement of objects with CInput component. +*In this example every entity has same speed when using movement system. +*/ +struct InputMovementSystem +{ + mixin ECS.System!32; + + vec2 move_vector; + + struct EntitiesData + { + uint length; + //read only components can be marked with @readonly attribute or with const expression instead + const (CInput)[] input; + //components are treated as required by default + CLocation[] locations; + } + + /** + *onBegin gives opportunity to check keys once and call update on entities only when + *one key is pressed. + */ + bool onBegin() + { + if(launcher.getKeyState(SDL_SCANCODE_W)) + { + move_vector = vec2(0,1); + return true; + } + else if(launcher.getKeyState(SDL_SCANCODE_S)) + { + move_vector = vec2(0,-1); + return true; + } + else if(launcher.getKeyState(SDL_SCANCODE_A)) + { + move_vector = vec2(-1,0); + return true; + } + else if(launcher.getKeyState(SDL_SCANCODE_D)) + { + move_vector = vec2(1,0); + return true; + } + //don't call system update because no key pressed + return false; + } + + /** + *Update is called multiple times in one "manager.update()" call. + *Number of "onUpdate" calls is count of buffers which must be updated during pass. + *When multithreading is used, number of "onUpdate" calls can be greater due to fact that + *JobSystem can split buffers for better data packing. + */ + void onUpdate(EntitiesData data) + { + //move every entity using movement vector + foreach(i; 0..data.length) + { + data.locations[i].x += move_vector.x * launcher.delta_time * 0.5; + data.locations[i].y += move_vector.y * launcher.delta_time * 0.5; + } + } +} + +/*####################################################################################################################### +------------------------------------------------ Functions ------------------------------------------------------------------ +#######################################################################################################################*/ + +__gshared SpaceInvaders* space_invaders; + +void spaceInvadersStart() +{ + space_invaders = Mallocator.make!SpaceInvaders; + + space_invaders.ship_tex.create(); + space_invaders.ship_tex.load("assets/textures/buckler.png"); + + space_invaders.laser_tex.create(); + space_invaders.laser_tex.load("assets/textures/buckler.png"); + + launcher.manager.beginRegister(); + + launcher.manager.registerComponent!CLocation; + launcher.manager.registerComponent!CTexture; + launcher.manager.registerComponent!CInput; + launcher.manager.registerComponent!CShip; + launcher.manager.registerComponent!CEnemy; + launcher.manager.registerComponent!CScale; + launcher.manager.registerComponent!CShootDirection; + launcher.manager.registerComponent!CAutoShoot; + launcher.manager.registerComponent!CLaserWeapon; + launcher.manager.registerComponent!CVelocity; + launcher.manager.registerComponent!CLaser; + launcher.manager.registerComponent!CSideMove; + + launcher.manager.registerEvent!EChangeDirection; + + //launcher.manager.registerSystem!MoveSystem(0); + launcher.manager.registerSystem!DrawSystem(100); + launcher.manager.registerSystem!InputMovementSystem(-100); + launcher.manager.registerSystem!LaserShootingSystem(0); + launcher.manager.registerSystem!MovementSystem(0); + launcher.manager.registerSystem!ClampPositionSystem(1); + launcher.manager.registerSystem!ChangeDirectionSystem(0); + + launcher.manager.endRegister(); + + launcher.gui_manager.addSystem(DrawSystem.system_id,"Draw System"); + launcher.gui_manager.addSystem(InputMovementSystem.system_id,"Input Movement"); + launcher.gui_manager.addSystem(LaserShootingSystem.system_id,"Laser Shooting"); + launcher.gui_manager.addSystem(MovementSystem.system_id,"Movement System"); + launcher.gui_manager.addSystem(ClampPositionSystem.system_id,"Clamp Position System"); + launcher.gui_manager.addSystem(ChangeDirectionSystem.system_id,"Change Direction System"); + + //launcher.manager.getSystem(CleanSystem.system_id).disable(); + { + ushort[7] components = [CLocation.component_id, CTexture.component_id, CInput.component_id, CShip.component_id, CScale.component_id, CLaserWeapon.component_id, CShootDirection.component_id]; + space_invaders.ship_tmpl = launcher.manager.allocateTemplate(components); + + CTexture* tex_comp = space_invaders.ship_tmpl.getComponent!CTexture; + tex_comp.tex = space_invaders.ship_tex; + CLocation* loc_comp = space_invaders.ship_tmpl.getComponent!CLocation; + loc_comp.value = vec2(64,64); + CLaserWeapon* weapon = space_invaders.ship_tmpl.getComponent!CLaserWeapon; + weapon.level = 10; + + launcher.manager.addEntity(space_invaders.ship_tmpl); + } + + { + ushort[5] components = [CLocation.component_id, CTexture.component_id, CVelocity.component_id, CScale.component_id, CLaser.component_id]; + space_invaders.laser_tmpl = launcher.manager.allocateTemplate(components); + + CTexture* tex_comp = space_invaders.laser_tmpl.getComponent!CTexture; + tex_comp.tex = space_invaders.laser_tex; + CScale* scale_comp = space_invaders.laser_tmpl.getComponent!CScale; + scale_comp.value = vec2(4,16); + CVelocity* vel_comp = space_invaders.laser_tmpl.getComponent!CVelocity; + vel_comp.value = vec2(0,1); + } + + { + ushort[8] components = [CVelocity.component_id, CAutoShoot.component_id, CLocation.component_id, CTexture.component_id, CScale.component_id, CLaserWeapon.component_id, CEnemy.component_id, CShootDirection.component_id];//, CVelocity.component_id]; + space_invaders.enemy_tmpl = launcher.manager.allocateTemplate(components); + + CTexture* tex_comp = space_invaders.enemy_tmpl.getComponent!CTexture; + tex_comp.tex = space_invaders.ship_tex; + CLocation* loc_comp = space_invaders.enemy_tmpl.getComponent!CLocation; + loc_comp.value = vec2(64,space_invaders.map_size.y - 64); + CShootDirection* shoot_dir_comp = space_invaders.enemy_tmpl.getComponent!CShootDirection; + shoot_dir_comp.direction = Direction.down; + CVelocity* vel_comp = space_invaders.enemy_tmpl.getComponent!CVelocity; + vel_comp.value = vec2(0.1,0); + + Entity* current_entity; + + current_entity = launcher.manager.addEntity(space_invaders.enemy_tmpl); + launcher.manager.addComponents(current_entity.id,CSideMove(0)); + + loc_comp.value = vec2(128,space_invaders.map_size.y - 64); + current_entity = launcher.manager.addEntity(space_invaders.enemy_tmpl); + launcher.manager.addComponents(current_entity.id,CSideMove(-1)); + + loc_comp.value = vec2(256,space_invaders.map_size.y - 64); + launcher.manager.addEntity(space_invaders.enemy_tmpl); + + loc_comp.value = vec2(0,space_invaders.map_size.y - 64); + current_entity = launcher.manager.addEntity(space_invaders.enemy_tmpl); + launcher.manager.addComponents(current_entity.id,CSideMove(0)); + } + +} + +void spaceInvadersEnd() +{ + + launcher.manager.getSystem(DrawSystem.system_id).disable(); + launcher.manager.getSystem(InputMovementSystem.system_id).disable(); + launcher.manager.getSystem(LaserShootingSystem.system_id).disable(); + launcher.manager.getSystem(MovementSystem.system_id).disable(); + launcher.manager.getSystem(ClampPositionSystem.system_id).disable(); + + space_invaders.ship_tex.destroy(); + + launcher.manager.freeTemplate(space_invaders.ship_tmpl); + Mallocator.dispose(space_invaders); +} + +void spaceInvadersEvent(SDL_Event* event) +{ + +} + +bool spaceInvadersLoop() +{ + + /*if(launcher.show_demo_wnd) + { + igSetNextWindowPos(ImVec2(800 - 260, 30), ImGuiCond_Once, ImVec2(0,0)); + igSetNextWindowSize(ImVec2(250, 0), ImGuiCond_Once); + if(igBegin("Simple",&launcher.show_demo_wnd,0)) + { + if(igCheckbox("Move system",&simple.move_system)) + { + if(simple.move_system)launcher.manager.getSystem(MoveSystem.system_id).enable(); + else launcher.manager.getSystem(MoveSystem.system_id).disable(); + } + if(igCheckbox("Draw system",&simple.draw_system)) + { + if(simple.draw_system)launcher.manager.getSystem(DrawSystem.system_id).enable(); + else launcher.manager.getSystem(DrawSystem.system_id).disable(); + } + igPushButtonRepeat(true); + igColumns(3,null,0); + if(igButton("Spawn",ImVec2(-1,0))) + { + spawnEntity(); + } + igNextColumn(); + if(igButton("+10",ImVec2(-1,0))) + { + foreach(i;0..10)spawnEntity(); + } + igNextColumn(); + if(igButton("+100",ImVec2(-1,0))) + { + foreach(i;0..100)spawnEntity(); + } + igPopButtonRepeat(); + igColumns(1,null,0); + if(igButton("Clear",ImVec2(-1,0))) + { + launcher.manager.getSystem(CleanSystem.system_id).enable(); + launcher.manager.begin(); + launcher.manager.update(); + launcher.manager.end(); + launcher.manager.getSystem(CleanSystem.system_id).disable(); + } + } + igEnd(); + }*/ + + /*if(launcher.show_tips) + { + igSetNextWindowPos(ImVec2(800 - 550, 80), ImGuiCond_Once, ImVec2(0,0)); + igSetNextWindowSize(ImVec2(300, 0), ImGuiCond_Once); + if(igBegin("Tips",&launcher.show_tips,ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoSavedSettings)) + { + igTextWrapped("Use \"space\" to spwan entities.\n\nSystems can be enabled/disabled from \"Simple\" window."); + } + igEnd(); + }*/ + + launcher.manager.begin(); + if(launcher.multithreading) + { + launcher.job_updater.begin(); + launcher.manager.updateMT(); + launcher.job_updater.call(); + launcher.multithreading = false; + printf("Disable mt\n"); + } + else + { + launcher.manager.update(); + } + launcher.manager.end(); + + /*foreach(i;0..1000)//13000) + { + launcher.renderer.draw(simple.texture,vec2(i%100*32,i/100*32),vec2(32,32),vec4(0,0,1,1),0.0); + }*/ + + return true; +} \ No newline at end of file diff --git a/demos/source/game_core/job_updater.d b/demos/source/game_core/job_updater.d new file mode 100644 index 0000000..26cd8e3 --- /dev/null +++ b/demos/source/game_core/job_updater.d @@ -0,0 +1,199 @@ +module game_core.job_updater; + +import ecs.std; +import ecs.vector; + +import ecs_utils.utils; + +//import core.time; +import ecs.manager; +import mmutils.thread_pool; + +//import supre.core.call_graph_generator; + +struct ECSJobUpdater +{ + + this(uint threads) + { + onCreate(threads); + } + + ~this() + { + pool.waitThreads(); + //pool.unregistExternalThread(thread_data); + if(jobs)Mallocator.dispose(jobs); + } + + ThreadPool pool; + ThreadData* thread_data; + + int job_id = 0; + int no_dep_count = 0; + static uint thread_id = 0; + + struct Group + { + ~this() nothrow + { + + } + + JobsGroup group; + JobData[1024] jobs; + JobCaller[1024] callers; + uint count = 0; + + void dependantOn(Group* dependency) + { + group.dependantOn(&dependency.group); + } + + void start() + { + group.thPool.addGroupAsynchronous(&group); + } + + void build(ThreadPool* pool) + { + group.thPool = pool; + group.jobs = jobs[0..count]; + } + + void clear() + { + group = JobsGroup("name",null); + count = 0; + } + + void add(JobCaller caller) + { + callers[count] = caller; + jobs[count] = JobData(&callers[count].callJob,"hmm"); + count++; + } + } + + Group[] jobs; + Vector!(Group*) call_jobs; + Group last_job; + + //TrackData[32] trackers; + + void onCreate(uint threads_count) + { + pool.initialize(); + //thread_data = pool.registerExternalThread(); + pool.setThreadsNum(threads_count); + + jobs = Mallocator.makeArray!Group(256); + } + + uint getThreadID() nothrow + { + return thread_id; + } + + void begin() + { + job_id = 0; + call_jobs.clear(); + + foreach(ref job;jobs) + { + job.clear(); + } + + last_job.clear(); + } + + void clearTracker() + { + //foreach(ref tracker;trackers)tracker.clear(); + } + + void call() + { + if(last_job.group.getDependenciesWaitCount() == 0)return; + if(call_jobs.length == 0)return; + + JobData[1] groupEndJobs; + groupEndJobs[0] = JobData(&releaseMainThread, "Stop Threads"); + + last_job.group.jobs = groupEndJobs; + last_job.group.executeOnThreadNum = 0; + + foreach(job;call_jobs) + { + job.start(); + } + ret = false; + while(!ret) + { + printf("SDL\n"); + } + printf("NonSDL\n"); + //thread_data.threadStartFunc(); + + int i = 10; + } +shared bool ret = false; + void releaseMainThread(ThreadData* th_data, JobData* data) + { + //pool.releaseExternalThreads(); + ret = true; + } + + static struct JobCaller + { + EntityManager.Job* job; + ECSJobUpdater* updater; + uint id; + + void callJob(ThreadData* th_data, JobData* data) + { + updater.thread_id = th_data.threadId; + uint job_id = updater.getThreadID(); + //updater.trackers[job_id].begin(id); + job.execute(); + //updater.trackers[job_id].end(); + } + } + + void dispatch(EntityManager.JobGroup group) + { + if(group.jobs.length == 0) + { + return; + } + + foreach(ref job;group.jobs) + { + uint index = 0; + if(job.callers.length)index = job.callers[0].system_id; + JobCaller caller; + caller.updater = &this; + caller.job = &job; + caller.id = index; + jobs[group.id].add(caller); + } + + jobs[group.id].build(&pool); + + uint deps = cast(uint)group.dependencies.length; + + foreach(dep;group.dependencies) + { + if(jobs[dep.id].count && dep.caller.system.execute && dep.caller.system.enabled)jobs[group.id].dependantOn(&jobs[dep.id]); + else deps--; + } + + if(deps == 0) + { + call_jobs.add(&jobs[group.id]); + } + + last_job.dependantOn(&jobs[group.id]); + } +} \ No newline at end of file diff --git a/demos/source/gui/component.d b/demos/source/gui/component.d new file mode 100644 index 0000000..bbd7ec5 --- /dev/null +++ b/demos/source/gui/component.d @@ -0,0 +1,6 @@ +module gui.components; + +struct ComponentGUI +{ + +} \ No newline at end of file diff --git a/demos/source/gui/manager.d b/demos/source/gui/manager.d new file mode 100644 index 0000000..10727eb --- /dev/null +++ b/demos/source/gui/manager.d @@ -0,0 +1,49 @@ +module gui.manager; + +import app; + +import cimgui.cimgui; + +import ecs.std; +import ecs.system; +import ecs.vector; + +import gui.system; + +extern(C): + +struct GUIManager +{ + Vector!SystemGUI systems; + + void clear() + { + systems.clear(); + } + + void addSystem(ushort id, const (char)* name, bool enabled = true) + { + System* system = launcher.manager.getSystem(id); + //const (char)* name = + systems.add(SystemGUI(name,system,enabled)); + } + + void gui() + { + if(igCollapsingHeader("Systems", ImGuiTreeNodeFlags_Framed)) + { + bool true_ = true; + igIndent(8); + foreach(ref SystemGUI system;systems) + { + if(igCheckbox(system.name,&system.enabled)) + { + if(system.enabled)system.system.enable(); + else system.system.disable(); + } + } + igUnindent(8); + } + + } +} \ No newline at end of file diff --git a/demos/source/gui/system.d b/demos/source/gui/system.d new file mode 100644 index 0000000..bbee409 --- /dev/null +++ b/demos/source/gui/system.d @@ -0,0 +1,11 @@ +module gui.system; + +import ecs.system; + +struct SystemGUI +{ + const (char)* name; + System* system; + + bool enabled = true; +} \ No newline at end of file diff --git a/demos/utils/dub.json b/demos/utils/dub.json index 2f7d1bb..d8ecfb1 100644 --- a/demos/utils/dub.json +++ b/demos/utils/dub.json @@ -12,7 +12,6 @@ ], "importPaths": [ "source", - "../external/imports", "../external/sources" ], "dependencies": { diff --git a/demos/utils/source/ecs_utils/gfx/renderer.d b/demos/utils/source/ecs_utils/gfx/renderer.d index 5b151bc..e064c9e 100644 --- a/demos/utils/source/ecs_utils/gfx/renderer.d +++ b/demos/utils/source/ecs_utils/gfx/renderer.d @@ -799,10 +799,10 @@ struct Renderer sdl_transform = vec4(0,0,1.0/size.x,1.0/size.y); } - static void function(ref Renderer this_, Texture tex, vec2 pos, vec2 size, vec4 coords, float angle, uint material_id, uint mesh_id) __draw; - static void function(ref Renderer this_) __present; - static void function(ref Renderer this_) __clear; - static void function(ref Renderer this_) __initialize; + __gshared void function(ref Renderer this_, Texture tex, vec2 pos, vec2 size, vec4 coords, float angle, uint material_id, uint mesh_id) __draw; + __gshared void function(ref Renderer this_) __present; + __gshared void function(ref Renderer this_) __clear; + __gshared void function(ref Renderer this_) __initialize; static void __loadBackend() { diff --git a/source/ecs/vector.d b/source/ecs/vector.d index fa616ed..84ecc51 100644 --- a/source/ecs/vector.d +++ b/source/ecs/vector.d @@ -29,7 +29,7 @@ public: } - static if (isCopyable!T) { + /*static if (isCopyable!T) { export this(this) { T[] tmp = array[0 .. used]; array = null; @@ -38,9 +38,9 @@ public: } } else { @disable this(this); - } + }*/ - //@disable this(this); + @disable this(this); export ~this() { clear(); From 46de0f6adb602636363cf7c89db8331a8022b468 Mon Sep 17 00:00:00 2001 From: Mergul Date: Wed, 20 Nov 2019 16:42:44 +0000 Subject: [PATCH 082/217] -builded demos on linux -small gitingore fix --- demos/.gitignore | 3 ++- demos/assets/shaders/base.vp | 6 +++--- demos/compile_wasm.py | 8 ++++---- demos/dub.json | 2 ++ demos/libs/linux/x64/libcimgui.so | Bin 0 -> 862272 bytes demos/utils/source/ecs_utils/gfx/shader.d | 7 ++++++- 6 files changed, 17 insertions(+), 9 deletions(-) create mode 100755 demos/libs/linux/x64/libcimgui.so diff --git a/demos/.gitignore b/demos/.gitignore index 7ccfc2f..30c9e9c 100644 --- a/demos/.gitignore +++ b/demos/.gitignore @@ -11,4 +11,5 @@ !external/**/*.d !.gitignore !compile_wasm.py -!cimgui.bc \ No newline at end of file +!cimgui.bc +.dub \ No newline at end of file diff --git a/demos/assets/shaders/base.vp b/demos/assets/shaders/base.vp index 50fc27e..42ed4a7 100644 --- a/demos/assets/shaders/base.vp +++ b/demos/assets/shaders/base.vp @@ -25,9 +25,9 @@ precision lowp samplerCube; #endif #else #if __VERSION__ > 320 - layout(location = 0) uniform vec4 matrix_1; - layout(location = 1) uniform vec4 matrix_2; - layout(location = 2) uniform vec4 uv_transform; + uniform vec4 matrix_1; + uniform vec4 matrix_2; + uniform vec4 uv_transform; layout(location = 0) in vec2 positions; layout(location = 1) in vec2 tex_coords; diff --git a/demos/compile_wasm.py b/demos/compile_wasm.py index 06845cf..9e3f46a 100644 --- a/demos/compile_wasm.py +++ b/demos/compile_wasm.py @@ -24,11 +24,11 @@ def compile(sources, output): for f in files: ldc_cmd += f + ' ' - print ldc_cmd + print(ldc_cmd) if os.system(ldc_cmd): exit(0) - print + print() shared_flags = '' @@ -74,7 +74,7 @@ for arg in sys.argv[1:]: elif(arg == '-pthread'): shared_flags += '-O3 ' ldc_flags += '-release -enable-inlining ' - emc_flags += '-s PTHREAD_POOL_SIZE=16 -Wl,--no-check-features -s USE_PTHREADS=1 ' + emc_flags += '-s PTHREAD_POOL_SIZE=16 -s USE_PTHREADS=1 ' elif(arg == '--demo=simple'): demo = 0 else: @@ -101,6 +101,6 @@ emcc_cmd += 'cimgui.bc ' emcc_cmd += 'mmutils.bc ' emcc_cmd += 'demo.bc ' -print emcc_cmd +print(emcc_cmd) os.system(emcc_cmd) diff --git a/demos/dub.json b/demos/dub.json index 009bf9e..43d248c 100644 --- a/demos/dub.json +++ b/demos/dub.json @@ -16,6 +16,8 @@ "source" ], "libs-windows-x86_64": ["libs/windows/x64/SDL2","libs/windows/x64/SDL2_Image","libs/windows/x64/cimgui"], + "libs-linux-x86_64": ["cimgui","SDL2","SDL2_image"], + "lflags-linux-x86_64": ["-rpath=libs/linux/x64/","-Llibs/linux/x64/"], "configurations" : [ { "name" : "default", diff --git a/demos/libs/linux/x64/libcimgui.so b/demos/libs/linux/x64/libcimgui.so new file mode 100755 index 0000000000000000000000000000000000000000..9c2a0bc7d130ebc54638e6da9775145619970cea GIT binary patch literal 862272 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 HDe!*)FtIkk literal 0 HcmV?d00001 diff --git a/demos/simple/dub.json b/demos/simple/dub.json new file mode 100644 index 0000000..393840f --- /dev/null +++ b/demos/simple/dub.json @@ -0,0 +1,50 @@ +{ + "name": "simple", + "authors": [ + "Michał Masiukiewicz", "Dawid Masiukiewicz" + ], + "targetPath": "..", + "description": "Dynamic Entity Component System simple example", + "copyright": "Copyright © 2018-2019, Michał Masiukiewicz, Dawid Masiukiewicz", + "license": "BSD 3-clause", + "sourcePaths" : ["source\/"], + "dflags-posix-ldc": [ + "-defaultlib=phobos2-ldc,druntime-ldc" + ], + "libs-windows-x86_64": ["../libs/windows/x64/SDL2","../libs/windows/x64/SDL2main","../libs/windows/x64/SDL2_Image"], + "dflagss": [ + "-betterC" + ], + "dependencies": { + "bindbc-sdl":"0.13.0", + "ecs":{"path":"../../"}, + "ecs_utils":{"path":"../utils/"} + }, + "versions": [ + "SDL_2010", + "BindSDL_Image" + ], + "configurations" : [ + { + "name" : "default", + "targetType" : "executable", + "subConfigurations": + { + "ecs":"library" + } + }, + { + "name" : "betterC", + "targetType" : "executable", + "dflags": [ + "-betterC" + ], + "subConfigurations": + { + "bindbc-sdl": "staticBC", + "ecs_utils":"betterC", + "ecs":"library-betterC" + } + } + ] +} \ No newline at end of file diff --git a/demos/simple/source/app.d b/demos/simple/source/app.d new file mode 100644 index 0000000..d8d61f5 --- /dev/null +++ b/demos/simple/source/app.d @@ -0,0 +1,216 @@ +module source.app; + +import ecs.std; +import ecs.core; +import ecs.manager; +import ecs.attributes; +import ecs.entity; + +import bindbc.sdl; + +import utils.utils; +import utils.texture; + +import ecs_utils.math.vector; + +version (WebAssembly) +{ + extern (C) void _start() + { + } +} + +SDL_Renderer *renderer; +SDL_Window* window; +Texture texture; +EntityManager* manager; + +struct CLocation +{ + mixin ECS.Component; + + alias location this; + + vec2 location; +} + +struct CTexture +{ + mixin ECS.Component; + + Texture tex; +} + +struct DrawSystem +{ + mixin ECS.System; + + struct EntitiesData + { + uint length; + @readonly CTexture[] textures; + @readonly CLocation[] locations; + } + + void onUpdate(EntitiesData data) + { + foreach(i; 0..data.length) + { + draw(renderer, data.textures[i].tex, data.locations[i], vec2(32,32), vec4(0,0,1,1)); + } + } +} + +struct MoveSystem +{ + mixin ECS.System; + + struct EntitiesData + { + uint length; + CLocation[] locations; + } + + void onUpdate(EntitiesData data) + { + foreach(i; 0..data.length) + { + data.locations[i].location.y = data.locations[i].location.y + 1; + if(data.locations[i].location.y > 400)data.locations[i].location.y = 0; + } + } +} + +extern (C) int main(int argc, char** argv) +{ + fps = 0; + time = 0; + + if (SDL_Init(SDL_INIT_VIDEO) < 0) + { + printf("SDL could not initialize! SDL_Error: %s", SDL_GetError()); + return -1; + } + + SDL_version sdl_version; + SDL_GetVersion(&sdl_version); + printf("SDL version: %u.%u.%u\n",cast(uint)sdl_version.major,cast(uint)sdl_version.minor,cast(uint)sdl_version.patch); + + SDL_Window* window = SDL_CreateWindow("Simple", SDL_WINDOWPOS_CENTERED, + SDL_WINDOWPOS_CENTERED, 600, 400, SDL_WINDOW_SHOWN); + //SDL_CreateWindowAndRenderer(600, 400, SDL_RENDERER_ACCELERATED, &window, &renderer); + renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC); + SDL_SetRenderDrawColor(renderer, 1, 255, 255, 255); + + texture.create(); + texture.load(renderer, "assets/textures/buckler.png"); + + EntityManager.initialize(8); + manager = EntityManager.instance; + + manager.beginRegister(); + + manager.registerComponent!CLocation; + manager.registerComponent!CTexture; + + manager.registerSystem!MoveSystem(64); + manager.registerSystem!DrawSystem(64); + + manager.endRegister(); + + ushort[2] components = [CLocation.component_id, CTexture.component_id]; + EntityTemplate* tmpl = manager.allocateTemplate(components); + CTexture* tex_comp = tmpl.getComponent!CTexture; + tex_comp.tex = texture; + CLocation* loc_comp = tmpl.getComponent!CLocation; + // loc_comp.location = vec2(64,64); + + foreach(i; 0..10) + foreach(j; 0..10) + { + loc_comp.location = vec2(i*32+64,j*32+64); + manager.addEntity(tmpl); + } + + + manager.freeTemplate(tmpl); + + /*image = IMG_Load("assets/owl.png"); + tex = SDL_CreateTextureFromSurface(renderer, image);*/ + + version(WebAssembly) + { + emscripten_set_main_loop_arg(&loop, null, -1, 1); + } + + bool arg = true; + while(arg == true) + { + loop(&arg); + } + + if (window !is null) { + SDL_DestroyWindow(window); + } + + end(); + + return 0; +} + +long time; +uint fps; + +extern(C) void loop(void *arg = null) +{ + static float fps_time = 0; + float delta_time = cast(float)(Time.getUSecTime() - time); + if(delta_time > 1000_000)delta_time = 1000; + time = Time.getUSecTime(); + + if(fps_time < 0)fps_time = 0; + + fps++; + fps_time += delta_time; + if(fps_time > 1000_000) + { + + printf("FPS: %u\n",fps); + fps = 0; + fps_time -= 1000_000; + } + + SDL_Event event; + while (SDL_PollEvent(&event)) + { + if (event.type == SDL_QUIT) { + version(WebAssembly)emscripten_cancel_main_loop(); + *cast(bool*)arg = false; + //return false; + } + + if (event.type == SDL_KEYDOWN) { + version(WebAssembly)emscripten_cancel_main_loop(); + *cast(bool*)arg = false; + //return false; + } + } + + SDL_RenderClear(renderer); + + manager.begin(); + manager.update(); + manager.end(); + + draw(renderer,texture,vec2(32,32),vec2(32,32),vec4(0,0,1,1)); + //SDL_RenderCopy(ctx->renderer, ctx->owl_tex, NULL, &ctx->dest); + SDL_RenderPresent(renderer); + + //return true; +} + +void end() +{ + EntityManager.destroy(); + SDL_Quit(); +} \ No newline at end of file diff --git a/demos/simple/source/utils/texture.d b/demos/simple/source/utils/texture.d new file mode 100644 index 0000000..5b49390 --- /dev/null +++ b/demos/simple/source/utils/texture.d @@ -0,0 +1,49 @@ +module utils.texture; + +import ecs.std; + +import bindbc.sdl; +import bindbc.sdl.image; + +import ecs_utils.math.vector; + +struct Texture +{ + + void create() + { + data = Mallocator.make!Data; + } + + bool load(SDL_Renderer* renderer, const char[] path) + { + char[] cpath = (cast(char*)alloca(path.length+1))[0..path.length+1]; + //cpath[0..$-1] = path[0..$]; + memcpy(cpath.ptr, path.ptr, path.length); + cpath[$-1] = 0; + + SDL_Surface* surf = IMG_Load(cpath.ptr); + if(!surf)return false; + + data.size = ivec2(surf.w,surf.h); + + data.texture = SDL_CreateTextureFromSurface(renderer,surf); + SDL_FreeSurface(surf); + + if(!data.texture)return false; + + return true; + } + + struct Data + { + ubyte[] data; + + ivec2 size; + uint bpp; + + SDL_Texture* texture; + } + + Data* data; +} \ No newline at end of file diff --git a/demos/simple/source/utils/utils.d b/demos/simple/source/utils/utils.d new file mode 100644 index 0000000..c7d3e9d --- /dev/null +++ b/demos/simple/source/utils/utils.d @@ -0,0 +1,110 @@ +module utils.utils; + +extern(C) int printf(scope const char* format, ...) @nogc nothrow @system; + +version(WebAssembly) +{ + + extern (C) alias em_callback_func = void function(); + extern (C) alias em_arg_callback_func = void function(void*); + extern (C) void emscripten_set_main_loop(em_callback_func func, int fps, int simulate_infinite_loop); + extern (C) void emscripten_set_main_loop_arg(em_arg_callback_func func, void *arg, int fps, int simulate_infinite_loop); + extern (C) int emscripten_set_main_loop_timing(int mode, int value); + extern (C) void emscripten_cancel_main_loop(); + + alias int time_t; + alias int clockid_t; + enum CLOCK_REALTIME = 0; + + struct timespec + { + time_t tv_sec; + int tv_nsec; + } + + extern(C) int clock_gettime(clockid_t, timespec*) @nogc nothrow @system; + + struct Time + { + + + static long getUSecTime() + { + time_t time; + timespec spec; + + clock_gettime(CLOCK_REALTIME, &spec); + + //time = spec.tv_sec; + return spec.tv_sec * 1000_000 + spec.tv_nsec / 1000;//time / 1000_000; + + /*LARGE_INTEGER time, freq; + QueryPerformanceFrequency(&freq); + QueryPerformanceCounter(&time); + return time.QuadPart / (freq.QuadPart / 1000_000);*/ + } + } +} +else version(Windows) +{ + import core.stdc.stdio : printf; + import core.sys.windows.windows; + struct Time + { + static long getUSecTime() + { + LARGE_INTEGER time, freq; + QueryPerformanceFrequency(&freq); + QueryPerformanceCounter(&time); + return time.QuadPart / (freq.QuadPart / 1000_000); + } + } +} +else version(Posix) +{ + import core.stdc.stdio : printf; + import core.sys.posix.time; + struct Time + { + static long getUSecTime() + { + time_t time; + timespec spec; + + clock_gettime(CLOCK_REALTIME, &spec); + + //time = spec.tv_sec; + return spec.tv_sec * 1000_000 + spec.tv_nsec / 1000;//time / 1000_000; + + /*LARGE_INTEGER time, freq; + QueryPerformanceFrequency(&freq); + QueryPerformanceCounter(&time); + return time.QuadPart / (freq.QuadPart / 1000_000);*/ + } + } +} + +import bindbc.sdl; +import utils.texture; +import ecs_utils.math.vector; + +ivec2 resolution = ivec2(600, 400); + +void draw(SDL_Renderer* renderer, Texture tex, vec2 pos, vec2 size, vec4 coords, float angle = 0) +{ + + SDL_Rect rect = SDL_Rect(cast(int)(coords.x*tex.data.size.x),cast(int)(coords.y*tex.data.size.y),cast(int)(coords.z*tex.data.size.x),cast(int)(coords.w*tex.data.size.y)); + SDL_Rect rect2 = SDL_Rect(cast(int)((pos.x-size.x*0.5)), + cast(int)(resolution.y - pos.y - size.y*0.5), + cast(int)(size.x), + cast(int)(size.y)); + + SDL_RenderCopyEx(renderer, + tex.data.texture, + &rect, + &rect2, + angle*360, + null, + SDL_FLIP_NONE); + +} \ No newline at end of file diff --git a/demos/utils/dub.json b/demos/utils/dub.json new file mode 100644 index 0000000..14298cb --- /dev/null +++ b/demos/utils/dub.json @@ -0,0 +1,50 @@ +{ + "name": "ecs_utils", + "authors": [ + "Michał Masiukiewicz", "Dawid Masiukiewicz" + ], + "description": "Dynamic Entity Component System examples utils", + "copyright": "Copyright © 2018-2019, Michał Masiukiewicz, Dawid Masiukiewicz", + "license": "BSD", + "sourcePaths" : [ + "source\/" + ], + "importPaths": [ + "source" + ], + "dflags-posix-ldc": [ + "-defaultlib=phobos2-ldc,druntime-ldc" + ], + "dflagss": [ + "-betterC" + ], + "dependencies": { + "bindbc-sdl":"0.10.1" + }, + "versions": [ + "BindSDL_Image", + "SDL_2010" + ], + + "configurations" : [ + { + "name" : "default", + "targetType" : "library", + "subConfigurations": + { + "bindbc-sdl": "static" + } + }, + { + "name" : "betterC", + "targetType" : "library", + "dflags": [ + "-betterC" + ], + "subConfigurations": + { + "bindbc-sdl": "staticBC" + } + } + ] +} \ No newline at end of file diff --git a/demos/utils/source/ecs_utils/math/matrix.d b/demos/utils/source/ecs_utils/math/matrix.d new file mode 100644 index 0000000..8a8e13b --- /dev/null +++ b/demos/utils/source/ecs_utils/math/matrix.d @@ -0,0 +1,6 @@ +module ecs_utils.math.matrix; + +struct mat3 +{ + float[9] data; +} \ No newline at end of file diff --git a/demos/utils/source/ecs_utils/math/vector.d b/demos/utils/source/ecs_utils/math/vector.d new file mode 100644 index 0000000..10b4de5 --- /dev/null +++ b/demos/utils/source/ecs_utils/math/vector.d @@ -0,0 +1,100 @@ +module ecs_utils.math.vector; + +struct vec2 +{ + union + { + struct + { + float x; + float y; + } + float[2] data; + } + + vec2 opBinary(string op)(vec2 v) + { + static if (op == "+") return vec2(x + v.x, y + v.y); + else static if (op == "-") return vec2(x - v.x, y - v.y); + else static if (op == "*") return vec2(x * v.x, y * v.y); + else static if (op == "/") return vec2(x / v.x, y / v.y); + else static assert(0, "Operator "~op~" not implemented"); + } + + vec2 opBinary(string op)(float v) + { + static if (op == "+") return vec2(x + v, y + v); + else static if (op == "-") return vec2(x - v, y - v); + else static if (op == "*") return vec2(x * v, y * v); + else static if (op == "/") return vec2(x / v, y / v); + else static assert(0, "Operator "~op~" not implemented"); + } + + void opOpAssign(string op)(vec2 v) + { + static if (op == "+") + { + x += v.x; + y += v.y; + } + else static if (op == "-") + { + x -= v.x; + y -= v.y; + } + else static if (op == "*") + { + x *= v.x; + y *= v.y; + } + else static if (op == "/") + { + x /= v.x; + y /= v.y; + } + else static assert(0, "Operator "~op~" not implemented"); + } +} + +struct vec4 +{ + union + { + struct + { + float x; + float y; + float z; + float w; + } + float[4] data; + } +} + +struct ivec2 +{ + union + { + struct + { + int x; + int y; + } + int[2] data; + } +} + +struct ivec4 +{ + union + { + struct + { + int x; + int y; + int z; + int w; + } + int[4] data; + } +} \ No newline at end of file diff --git a/demos/zlib1.dll b/demos/zlib1.dll new file mode 100644 index 0000000000000000000000000000000000000000..e7493de315264b254bdf914737274034e9017598 GIT binary patch literal 108544 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 literal 0 HcmV?d00001 diff --git a/source/ecs/std.d b/source/ecs/std.d index c52d3af..c8b7ecd 100644 --- a/source/ecs/std.d +++ b/source/ecs/std.d @@ -56,7 +56,7 @@ version(D_betterC) private const uint max_alloca = 10000; private char[max_alloca] alloca_array; private uint alloca_pos = 0; - void* alloca(size_t length) @nogc nothrow + export extern(C) void* alloca(size_t length) @nogc nothrow { if(alloca_pos + length > max_alloca)alloca_pos = 0; void* ret = &alloca_array[alloca_pos]; @@ -69,7 +69,7 @@ else version(WebAssembly) private const uint max_alloca = 10000; private char[max_alloca] alloca_array; private uint alloca_pos = 0; - void* alloca(size_t length) @nogc nothrow + export extern(C) void* alloca(size_t length) @nogc nothrow { if(alloca_pos + length > max_alloca)alloca_pos = 0; void* ret = &alloca_array[alloca_pos]; From cb7609dcaa3b4a5446ec0eb8d210e36f5fe52ebc Mon Sep 17 00:00:00 2001 From: Mergul Date: Tue, 12 Nov 2019 20:33:31 +0100 Subject: [PATCH 080/217] -Demos: *added ImGUI styles *added new assets (fonts, shaders) *added cimgui.dll *added imports for bindbc-sdl (for WASM) *added simple demo *added demo launcher *added snake demo *impoved demo utils *added cimgui.bc library for WASM -improved wasm build script -small change in vector --- demos/.gitignore | 3 +- demos/assets/fonts/Ruda-Bold.ttf | Bin 0 -> 24848 bytes demos/assets/shaders/base.fp | 42 + demos/assets/shaders/base.vp | 55 + demos/cimgui.bc | Bin 0 -> 1926057 bytes demos/cimgui.dll | Bin 0 -> 571392 bytes demos/compile_wasm.py | 16 +- demos/{simple => }/dub.json | 26 +- demos/external/sources/cimgui/cimgui.d | 1990 +++++++++++++++++ demos/external/sources/glad/gl/all.d | 28 + demos/external/sources/glad/gl/enums.d | 1302 +++++++++++ demos/external/sources/glad/gl/ext.d | 10 + demos/external/sources/glad/gl/funcs.d | 1508 +++++++++++++ demos/external/sources/glad/gl/gl.d | 404 ++++ demos/external/sources/glad/gl/gles2.d | 183 ++ demos/external/sources/glad/gl/loader.d | 1323 +++++++++++ demos/external/sources/glad/gl/types.d | 46 + demos/external/sources/mmutils/thread_pool.d | 1694 ++++++++++++++ .../bindbc/sdl/bind/package.d | 0 .../bindbc/sdl/bind/sdl.d | 0 .../bindbc/sdl/bind/sdlassert.d | 0 .../bindbc/sdl/bind/sdlaudio.d | 0 .../bindbc/sdl/bind/sdlblendmode.d | 0 .../bindbc/sdl/bind/sdlclipboard.d | 0 .../bindbc/sdl/bind/sdlcpuinfo.d | 0 .../bindbc/sdl/bind/sdlerror.d | 0 .../bindbc/sdl/bind/sdlevents.d | 0 .../bindbc/sdl/bind/sdlfilesystem.d | 0 .../bindbc/sdl/bind/sdlgamecontroller.d | 0 .../bindbc/sdl/bind/sdlgesture.d | 0 .../bindbc/sdl/bind/sdlhaptic.d | 0 .../bindbc/sdl/bind/sdlhints.d | 0 .../bindbc/sdl/bind/sdljoystick.d | 0 .../bindbc/sdl/bind/sdlkeyboard.d | 0 .../bindbc/sdl/bind/sdlkeycode.d | 0 .../bindbc/sdl/bind/sdlloadso.d | 0 .../bindbc/sdl/bind/sdllog.d | 0 .../bindbc/sdl/bind/sdlmessagebox.d | 0 .../bindbc/sdl/bind/sdlmouse.d | 0 .../bindbc/sdl/bind/sdlpixels.d | 0 .../bindbc/sdl/bind/sdlplatform.d | 0 .../bindbc/sdl/bind/sdlpower.d | 0 .../bindbc/sdl/bind/sdlrect.d | 0 .../bindbc/sdl/bind/sdlrender.d | 0 .../bindbc/sdl/bind/sdlrwops.d | 0 .../bindbc/sdl/bind/sdlscancode.d | 0 .../bindbc/sdl/bind/sdlshape.d | 0 .../bindbc/sdl/bind/sdlstdinc.d | 0 .../bindbc/sdl/bind/sdlsurface.d | 0 .../bindbc/sdl/bind/sdlsystem.d | 0 .../bindbc/sdl/bind/sdlsyswm.d | 0 .../bindbc/sdl/bind/sdltimer.d | 0 .../bindbc/sdl/bind/sdltouch.d | 0 .../bindbc/sdl/bind/sdlversion.d | 0 .../bindbc/sdl/bind/sdlvideo.d | 0 .../bindbc/sdl/bind/sdlvulkan.d | 0 .../bindbc/sdl/config.d | 0 .../bindbc/sdl/dynload.d | 0 .../bindbc/sdl/image.d | 0 .../bindbc/sdl/mixer.d | 0 .../bindbc/sdl/package.d | 0 .../bindbc/sdl/ttf.d | 0 demos/simple/source/app.d | 216 -- demos/simple/source/utils/texture.d | 49 - demos/simple/source/utils/utils.d | 110 - demos/utils/dub.json | 24 +- demos/utils/source/ecs_utils/gfx/buffer.d | 134 ++ demos/utils/source/ecs_utils/gfx/config.d | 102 + demos/utils/source/ecs_utils/gfx/material.d | 198 ++ demos/utils/source/ecs_utils/gfx/mesh.d | 121 + .../utils/source/ecs_utils/gfx/mesh_module.d | 12 + .../utils/source/ecs_utils/gfx/render_list.d | 29 + demos/utils/source/ecs_utils/gfx/renderer.d | 817 +++++++ demos/utils/source/ecs_utils/gfx/shader.d | 171 ++ demos/utils/source/ecs_utils/gfx/sprite.d | 11 + demos/utils/source/ecs_utils/gfx/texture.d | 118 + demos/utils/source/ecs_utils/gfx/vertex.d | 64 + demos/utils/source/ecs_utils/imgui_bind.d | 508 +++++ demos/utils/source/ecs_utils/imgui_styles.d | 95 + demos/utils/source/ecs_utils/utils.d | 183 ++ dub.json | 3 + source/ecs/vector.d | 6 +- 82 files changed, 11188 insertions(+), 413 deletions(-) create mode 100644 demos/assets/fonts/Ruda-Bold.ttf create mode 100644 demos/assets/shaders/base.fp create mode 100644 demos/assets/shaders/base.vp create mode 100644 demos/cimgui.bc create mode 100644 demos/cimgui.dll rename demos/{simple => }/dub.json (57%) create mode 100644 demos/external/sources/cimgui/cimgui.d create mode 100644 demos/external/sources/glad/gl/all.d create mode 100644 demos/external/sources/glad/gl/enums.d create mode 100644 demos/external/sources/glad/gl/ext.d create mode 100644 demos/external/sources/glad/gl/funcs.d create mode 100644 demos/external/sources/glad/gl/gl.d create mode 100644 demos/external/sources/glad/gl/gles2.d create mode 100644 demos/external/sources/glad/gl/loader.d create mode 100644 demos/external/sources/glad/gl/types.d create mode 100644 demos/external/sources/mmutils/thread_pool.d rename demos/external/{imports => wasm_imports}/bindbc/sdl/bind/package.d (100%) rename demos/external/{imports => wasm_imports}/bindbc/sdl/bind/sdl.d (100%) rename demos/external/{imports => wasm_imports}/bindbc/sdl/bind/sdlassert.d (100%) rename demos/external/{imports => wasm_imports}/bindbc/sdl/bind/sdlaudio.d (100%) rename demos/external/{imports => wasm_imports}/bindbc/sdl/bind/sdlblendmode.d (100%) rename demos/external/{imports => wasm_imports}/bindbc/sdl/bind/sdlclipboard.d (100%) rename demos/external/{imports => wasm_imports}/bindbc/sdl/bind/sdlcpuinfo.d (100%) rename demos/external/{imports => wasm_imports}/bindbc/sdl/bind/sdlerror.d (100%) rename demos/external/{imports => wasm_imports}/bindbc/sdl/bind/sdlevents.d (100%) rename demos/external/{imports => wasm_imports}/bindbc/sdl/bind/sdlfilesystem.d (100%) rename demos/external/{imports => wasm_imports}/bindbc/sdl/bind/sdlgamecontroller.d (100%) rename demos/external/{imports => wasm_imports}/bindbc/sdl/bind/sdlgesture.d (100%) rename demos/external/{imports => wasm_imports}/bindbc/sdl/bind/sdlhaptic.d (100%) rename demos/external/{imports => wasm_imports}/bindbc/sdl/bind/sdlhints.d (100%) rename demos/external/{imports => wasm_imports}/bindbc/sdl/bind/sdljoystick.d (100%) rename demos/external/{imports => wasm_imports}/bindbc/sdl/bind/sdlkeyboard.d (100%) rename demos/external/{imports => wasm_imports}/bindbc/sdl/bind/sdlkeycode.d (100%) rename demos/external/{imports => wasm_imports}/bindbc/sdl/bind/sdlloadso.d (100%) rename demos/external/{imports => wasm_imports}/bindbc/sdl/bind/sdllog.d (100%) rename demos/external/{imports => wasm_imports}/bindbc/sdl/bind/sdlmessagebox.d (100%) rename demos/external/{imports => wasm_imports}/bindbc/sdl/bind/sdlmouse.d (100%) rename demos/external/{imports => wasm_imports}/bindbc/sdl/bind/sdlpixels.d (100%) rename demos/external/{imports => wasm_imports}/bindbc/sdl/bind/sdlplatform.d (100%) rename demos/external/{imports => wasm_imports}/bindbc/sdl/bind/sdlpower.d (100%) rename demos/external/{imports => wasm_imports}/bindbc/sdl/bind/sdlrect.d (100%) rename demos/external/{imports => wasm_imports}/bindbc/sdl/bind/sdlrender.d (100%) rename demos/external/{imports => wasm_imports}/bindbc/sdl/bind/sdlrwops.d (100%) rename demos/external/{imports => wasm_imports}/bindbc/sdl/bind/sdlscancode.d (100%) rename demos/external/{imports => wasm_imports}/bindbc/sdl/bind/sdlshape.d (100%) rename demos/external/{imports => wasm_imports}/bindbc/sdl/bind/sdlstdinc.d (100%) rename demos/external/{imports => wasm_imports}/bindbc/sdl/bind/sdlsurface.d (100%) rename demos/external/{imports => wasm_imports}/bindbc/sdl/bind/sdlsystem.d (100%) rename demos/external/{imports => wasm_imports}/bindbc/sdl/bind/sdlsyswm.d (100%) rename demos/external/{imports => wasm_imports}/bindbc/sdl/bind/sdltimer.d (100%) rename demos/external/{imports => wasm_imports}/bindbc/sdl/bind/sdltouch.d (100%) rename demos/external/{imports => wasm_imports}/bindbc/sdl/bind/sdlversion.d (100%) rename demos/external/{imports => wasm_imports}/bindbc/sdl/bind/sdlvideo.d (100%) rename demos/external/{imports => wasm_imports}/bindbc/sdl/bind/sdlvulkan.d (100%) rename demos/external/{imports => wasm_imports}/bindbc/sdl/config.d (100%) rename demos/external/{imports => wasm_imports}/bindbc/sdl/dynload.d (100%) rename demos/external/{imports => wasm_imports}/bindbc/sdl/image.d (100%) rename demos/external/{imports => wasm_imports}/bindbc/sdl/mixer.d (100%) rename demos/external/{imports => wasm_imports}/bindbc/sdl/package.d (100%) rename demos/external/{imports => wasm_imports}/bindbc/sdl/ttf.d (100%) delete mode 100644 demos/simple/source/app.d delete mode 100644 demos/simple/source/utils/texture.d delete mode 100644 demos/simple/source/utils/utils.d create mode 100644 demos/utils/source/ecs_utils/gfx/buffer.d create mode 100644 demos/utils/source/ecs_utils/gfx/config.d create mode 100644 demos/utils/source/ecs_utils/gfx/material.d create mode 100644 demos/utils/source/ecs_utils/gfx/mesh.d create mode 100644 demos/utils/source/ecs_utils/gfx/mesh_module.d create mode 100644 demos/utils/source/ecs_utils/gfx/render_list.d create mode 100644 demos/utils/source/ecs_utils/gfx/renderer.d create mode 100644 demos/utils/source/ecs_utils/gfx/shader.d create mode 100644 demos/utils/source/ecs_utils/gfx/sprite.d create mode 100644 demos/utils/source/ecs_utils/gfx/texture.d create mode 100644 demos/utils/source/ecs_utils/gfx/vertex.d create mode 100644 demos/utils/source/ecs_utils/imgui_bind.d create mode 100644 demos/utils/source/ecs_utils/imgui_styles.d create mode 100644 demos/utils/source/ecs_utils/utils.d diff --git a/demos/.gitignore b/demos/.gitignore index c799805..e6f937c 100644 --- a/demos/.gitignore +++ b/demos/.gitignore @@ -9,4 +9,5 @@ !assets/** !external/**/*.d !.gitignore -!compile_wasm.py \ No newline at end of file +!compile_wasm.py +!cimgui.bc \ No newline at end of file diff --git a/demos/assets/fonts/Ruda-Bold.ttf b/demos/assets/fonts/Ruda-Bold.ttf new file mode 100644 index 0000000000000000000000000000000000000000..53ae69c189a4e1742a3ce0dd7d7d3ab34c511126 GIT binary patch literal 24848 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 U290 + in mediump vec2 uv; + #else + varying mediump vec2 uv; + #endif +#else + #if __VERSION__ > 320 + in vec2 uv; + #else + varying vec2 uv; + #endif +#endif + +//layout(binding = 0)uniform sampler2D tex; + +uniform sampler2D tex; + +//layout(location = 0) out vec4 outColor; + +void main() { + + #ifdef GLES + #if __VERSION__ >290 + gl_FragColor = texture(tex,uv); + #else + gl_FragColor = texture2D(tex,uv); + #endif + #else + #if __VERSION__ > 320 + gl_FragColor = texture(tex,uv); + #else + gl_FragColor = texture2D(tex,uv); + #endif + #endif + if(gl_FragColor.a < 0.01)discard; +} diff --git a/demos/assets/shaders/base.vp b/demos/assets/shaders/base.vp new file mode 100644 index 0000000..50fc27e --- /dev/null +++ b/demos/assets/shaders/base.vp @@ -0,0 +1,55 @@ +precision highp float; +precision highp int; +precision lowp sampler2D; +precision lowp samplerCube; + +#ifdef GLES + #if __VERSION__ >290 + layout(location = 0) uniform vec4 matrix_1; + layout(location = 1) uniform vec4 matrix_2; + layout(location = 2) uniform vec4 uv_transform; + + layout(location = 0) in vec2 positions; + layout(location = 1) in vec2 tex_coords; + + out mediump vec2 uv; + #else + uniform vec4 matrix_1; + uniform vec4 matrix_2; + uniform vec4 uv_transform; + + attribute vec2 positions; + attribute vec2 tex_coords; + + varying mediump vec2 uv; + #endif +#else + #if __VERSION__ > 320 + layout(location = 0) uniform vec4 matrix_1; + layout(location = 1) uniform vec4 matrix_2; + layout(location = 2) uniform vec4 uv_transform; + + layout(location = 0) in vec2 positions; + layout(location = 1) in vec2 tex_coords; + + out vec2 uv; + #else + uniform vec4 matrix_1; + uniform vec4 matrix_2; + uniform vec4 uv_transform; + + attribute vec2 positions; + attribute vec2 tex_coords; + + varying vec2 uv; + #endif +#endif + +void main() { + + vec3 position = mat3(matrix_1.x,matrix_1.y,0,matrix_1.z,matrix_1.w,0,matrix_2.xy,1) * vec3(positions,1.0); + uv = tex_coords * uv_transform.zw + uv_transform.xy; + + gl_Position = vec4(position.xy,0,1.0); + +} diff --git a/demos/cimgui.bc b/demos/cimgui.bc new file mode 100644 index 0000000000000000000000000000000000000000..e248fd905cd192e58a6eb0e6c78c475c659caa20 GIT binary patch literal 1926057 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