Merge branch 'master' into wasm_demos

# Conflicts:
#	demos/external/sources/mmutils/thread_pool.d
#	tests/meson.build
This commit is contained in:
mmcomando 2021-03-13 13:30:58 +01:00
commit 84a5cbef13
32 changed files with 1568 additions and 1535 deletions

View file

@ -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" : [
{

View file

@ -1,19 +1,10 @@
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
//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;
@ -31,8 +22,15 @@ else
version (D_BetterC)
{
import bubel.ecs.std;
extern (C) __gshared int _d_eh_personality(int, int, size_t, void*, void*)
version (Posix) version = MM_USE_POSIX_THREADS;
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;
}
@ -45,7 +43,7 @@ version (D_BetterC)
extern (C) void* _d_allocmemory(size_t sz)
{
return malloc(sz);
}
}*/
}
else
{
@ -54,8 +52,132 @@ else
}
//////////////////////////////////////////////
//////////////////// Alloc ///////////////////
/////////////// 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 ///////////////////
//////////////////////////////////////////////////
T* makeVar(T)(T init)
{
T* el = cast(T*) malloc(T.sizeof);
@ -118,21 +240,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)
{
@ -144,6 +252,7 @@ long useconds()
}
else version (Windows)
{
//TODO: implement timer on windows
/*import core.sys.windows.windows : QueryPerformanceFrequency;
__gshared double mul = -1;
@ -241,7 +350,7 @@ version (MM_USE_POSIX_THREADS)
version (WebAssembly)
{
extern(C):
//alias uint time_t;
struct pthread_attr_t
{
union
@ -257,19 +366,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;
@ -280,8 +381,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)
{
@ -345,7 +444,6 @@ version (MM_USE_POSIX_THREADS)
bool tryWait()
{
//return true;
int ret = sem_trywait(&mutex);
return (ret == 0);
}
@ -409,91 +507,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;
@ -549,15 +563,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()
@ -573,7 +585,6 @@ else version(D_BetterC)
th.threadStart();
//(null);
ExitThread(0);
return 0;
}
@ -589,21 +600,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
{
@ -672,7 +684,7 @@ else
///////////////// ThreadPool /////////////////
//////////////////////////////////////////////
private enum gMaxThreadsNum = 32;
private enum gMaxThreadsNum = 64;
alias JobDelegate = void delegate(ThreadData*, JobData*);

View file

@ -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();
@ -192,7 +191,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 +202,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 +215,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 +228,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);
}
}
@ -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 = EntityManager.instance;
//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();

View file

@ -58,7 +58,7 @@ struct CBall
{
mixin ECS.Component;
ubyte radius;
//ubyte radius;
}
struct CHitPoints
@ -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
);
@ -409,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");
@ -446,12 +434,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 +458,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;
}

View file

@ -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;
@ -503,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");
@ -518,32 +425,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 +460,7 @@ void particlesEnd()
{
particles_demo.texture.destroy();
//launcher.manager.freeTemplate(simple.tmpl);
//gEntityManager.freeTemplate(simple.tmpl);
Mallocator.dispose(particles_demo);
}
@ -565,18 +472,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;
}

View file

@ -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;
}

View file

@ -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;
}

View file

@ -19,12 +19,14 @@ import ecs_utils.utils;
import game_core.basic;
import gui.attributes;
//import std.array : staticArray;
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 +40,7 @@ struct MapElement
EntityID id;
}
//snake part is corresponding to graphical representation of snake
enum SnakePart : ubyte
{
head_up = 0,
@ -81,9 +84,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 +119,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,14 +128,16 @@ struct Animation
}
//component has array of frames (texture coordinates) and time used for selection frames
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
struct CILocation
{
mixin ECS.Component;
@ -199,14 +204,16 @@ struct CSnake
}
Parts parts;
CMovement.Direction direction;
@GUIRange(0,3)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 +221,7 @@ struct CParticle
float life = 0;
}
//vector for particle movement
struct CParticleVector
{
mixin ECS.Component;
@ -221,6 +229,7 @@ struct CParticleVector
vec2 velocity = vec2(0,0);
}
//contains current movement direction for snake
struct CMovement
{
mixin ECS.Component;
@ -233,7 +242,7 @@ struct CMovement
right
}
Direction direction;
@GUIRange(0,3)Direction direction;
}
// struct CInput
@ -241,6 +250,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 +263,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 +284,7 @@ struct AppleSystem
}
}
//system is responsible for killing particles when their life drops below 0
struct ParticleSystem
{
mixin ECS.System!1;
@ -288,11 +301,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;
@ -360,10 +374,11 @@ 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);
//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 +388,6 @@ struct MoveSystem
mixin ECS.System!64;
EntityTemplate* destroy_template;
//CLocation* destroy_location;
//CParticleVector* destroy_vector;
struct EntitiesData
{
@ -387,9 +400,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 +458,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 +467,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 +494,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 +549,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 +826,7 @@ struct CleanSystem
{
foreach(i; 0..data.length)
{
launcher.manager.removeEntity(data.entities[i].id);
gEntityManager.removeEntity(data.entities[i].id);
}
}
}
@ -859,38 +871,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()
@ -901,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");
@ -913,17 +926,20 @@ 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);
{
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 +948,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 +986,7 @@ bool snakeLoop()
// igEnd();
// }
launcher.manager.begin();
gEntityManager.begin();
float delta_time = launcher.deltaTime;
if(delta_time > 2000)delta_time = 2000;
@ -983,12 +999,12 @@ bool snakeLoop()
{
time -= 200;
launcher.manager.update("fixed");
gEntityManager.update("fixed");
}
launcher.manager.update();
gEntityManager.update();
launcher.manager.end();
gEntityManager.end();
return true;
}

File diff suppressed because it is too large Load diff

View file

@ -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);
}*/
}
}

View file

@ -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
@ -188,7 +189,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 +965,7 @@ struct BVHBuilder2
void onCreate()
{
tree = gEM.getSystem!BVHBuilder().tree;
tree = gEntityManager.getSystem!BVHBuilder().tree;
}
bool onBegin()

View file

@ -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,7 +18,26 @@ else
}
}
//import supre.core.call_graph_generator;
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
{
@ -33,30 +49,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 +66,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 +108,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 +122,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 +130,9 @@ struct ECSJobUpdater
else return thread_id;
}
//clear jobs data
void begin()
{
job_id = 0;
call_jobs.clear();
foreach(ref job;jobs)
@ -139,68 +143,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 +207,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 +239,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;
}

View file

@ -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;
}
}
}
struct GUIRangeF
{
struct
{
float minf;
float maxf;
}
}
enum GUIDisabled = "GUIDisabled";

View file

@ -54,6 +54,7 @@ struct VariableGUI
Type type;
const (char)* name;
ushort offset;
bool disabled = false;
union
{
Int int_;

View file

@ -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)
@ -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)));
@ -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 = launcher.manager.getSystem(system.id);
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);
@ -472,7 +493,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);
}

View file

@ -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"
}
}
]

View file

@ -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);
}