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 498f34d..c628969 100644 Binary files a/demos/assets/textures/atlas.png and b/demos/assets/textures/atlas.png differ diff --git a/demos/compile_wasm.py b/demos/compile_wasm.py index 30d0a0f..06d31ac 100644 --- a/demos/compile_wasm.py +++ b/demos/compile_wasm.py @@ -1,6 +1,7 @@ import os import ntpath import sys +import imp def compile(sources, output): files = [] @@ -36,8 +37,10 @@ compiler = 'ldc2 ' shared_flags = '' clean = 0 demo = 0 +only_bc = 0 +multi = 0 sources = ['tests', 'source'] -emc_flags = '-s USE_SDL=2 -s USE_SDL_IMAGE=2 -s SDL2_IMAGE_FORMATS="[\'png\']" --preload-file assets ' +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 ' import_paths = ['external/sources', 'external/imports', 'external/wasm_imports', '../source', 'utils/source', 'simple/source'] @@ -60,6 +63,8 @@ for arg in sys.argv[1:]: shared_flags += '-Oz ' elif(arg == '-g'): shared_flags += '-g ' + elif(arg == '--multi'): + multi = 1 elif(arg == '-g4'): ldc_flags += '-g ' emc_flags += '-g4 --source-map-base ./ ' @@ -79,6 +84,8 @@ for arg in sys.argv[1:]: emc_flags += '-s USE_PTHREADS=1 ' elif(arg == '--demo=simple'): demo = 0 + elif(arg == '--only-bc'): + only_bc = 1 else: print('unknown argument: ' + arg) exit() @@ -92,8 +99,17 @@ 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 ' +if only_bc: + exit() + +if multi: + emcc_cmd = 'emcc ' + shared_flags + emc_flags + '--pre-js build/assets.js -s FORCE_FILESYSTEM=1 -s MAX_WEBGL_VERSION=2 --emrun -s ERROR_ON_UNDEFINED_SYMBOLS=0 -s DISABLE_DEPRECATED_FIND_EVENT_TARGET_BEHAVIOR=1 -s ALLOW_MEMORY_GROWTH=1 -s WASM_MEM_MAX=2048MB -s MALLOC=dlmalloc -s WASM=1 {0} -o {1} --shell-file emscripten_multi_shell.html ' +else: + emcc_cmd = 'emcc ' + shared_flags + emc_flags + '--pre-js build/assets.js -s FORCE_FILESYSTEM=1 -s MAX_WEBGL_VERSION=2 --emrun -s ERROR_ON_UNDEFINED_SYMBOLS=0 -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 build/ecs_demo.html --shell-file emscripten_shell.html ' + +#emcc_cmd = 'emcc -v ' + shared_flags + emc_flags + '-s MAX_WEBGL_VERSION=2 --emrun -s ERROR_ON_UNDEFINED_SYMBOLS=0 -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 build/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 +#-s MAX_WEBGL_VERSION=2 emcc_cmd += '../ecs.bc ' emcc_cmd += 'utils.bc ' @@ -103,6 +119,24 @@ emcc_cmd += 'cimgui.bc ' emcc_cmd += 'mmutils.bc ' emcc_cmd += 'demo.bc ' -print(emcc_cmd) +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' +print('Packafing files: ' + pack_cmd) + +os.system(pack_cmd) + +if multi: + final_cmd = emcc_cmd.format('','build/ecs_demo.html') + print(final_cmd) + os.system(final_cmd) + final_cmd = emcc_cmd.format('-s USE_PTHREADS=1','build/ecs_demo_mt.js') + print(final_cmd) + os.system(final_cmd) +else: + print(emcc_cmd) + os.system(emcc_cmd) + +os.system('rm build/assets.js') -os.system(emcc_cmd) diff --git a/demos/emscripten_multi_shell.html b/demos/emscripten_multi_shell.html new file mode 100644 index 0000000..c0b5598 --- /dev/null +++ b/demos/emscripten_multi_shell.html @@ -0,0 +1,170 @@ + + + + + + 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)() {