Merge branch 'ci-update' into 'master'

Ci update

See merge request Mergul/bubel-ecs!6
This commit is contained in:
Dawid Masiukiewicz 2020-05-01 19:26:21 +00:00
commit 2ddb97e9ce
29 changed files with 1167 additions and 322 deletions

2
.gitignore vendored
View file

@ -5,6 +5,8 @@
!README.md !README.md
!./dub.json !./dub.json
!.gitignore !.gitignore
!codecov.yml
!skeleton.html
!meson.build !meson.build
!meson_options.txt !meson_options.txt
!compile_wasm.py !compile_wasm.py

View file

@ -1,60 +1,91 @@
image: "registry.gitlab.com/mergul/bubel-ecs:latest"
variables:
DOCKER_DRIVER: overlay2
stages: stages:
- build - build
- test - test
- testcov - testcov
- build_emscripten
- deploy
test_compile: build_code:
stage: build stage: build
image: "registry.gitlab.com/mergul/bubel-ecs:latest"
script: script:
- source $(/script/dlang/install.sh dmd -a) && dmd --version - mkdir build
- dub build -c unittest-runner -b debug --verror - /bin/bash /compile_ecs.sh
- dub build -c unittest-runner -b release --verror - cp artifacts/* build/
- dub build -c unittest-runner-betterC -b debug --verror - cp -r public build/
- dub build -c unittest-runner-betterC -b release --verror artifacts:
- deactivate expire_in: 1h
- source $(/script/dlang/install.sh ldc -a) && ldc2 --version paths:
- dub build -c unittest-runner --compiler=ldc2 -b debug --verror - build
- dub build -c unittest-runner --compiler=ldc2 -b release --verror rules:
- dub build -c unittest-runner-betterC --compiler=ldc2 -b debug --verror - if: '$CI_MERGE_REQUEST_TARGET_BRANCH_NAME == "master"'
- dub build -c unittest-runner-betterC --compiler=ldc2 -b release --verror when: always
- deactivate - when: always
allow_failure: true allow_failure: true
test_dmd_debug: test_dmd_debug:
stage: test stage: test
image: frolvlad/alpine-glibc
script: script:
- source $(/script/dlang/install.sh dmd -a) && dmd --version - build/dmd_debug_unittest
- dub -c unittest-runner -b debug --verror
artifacts: artifacts:
reports: reports:
junit: test_report.xml junit: test_report.xml
test_dmd: test_dmd:
stage: test stage: test
image: frolvlad/alpine-glibc
script: script:
- source $(/script/dlang/install.sh dmd -a) && dmd --version - build/dmd_release_unittest
- dub -c unittest-runner -b release --verror
artifacts: artifacts:
reports: reports:
junit: test_report.xml junit: test_report.xml
test_dmd_betterC: test_dmd_betterC:
stage: test stage: test
image: frolvlad/alpine-glibc
script: script:
- source $(/script/dlang/install.sh dmd -a) && dmd --version - build/dmd_release_unittest_bc
- dub -c unittest-runner-betterC -b release --verror
artifacts: artifacts:
reports: reports:
junit: test_report.xml junit: test_report.xml
coverage_test_dmd: coverage_test_dmd:
stage: testcov 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: script:
- mkdir reports - mkdir reports
- source $(/script/dlang/install.sh dmd -a) && dmd --version - build/dmd_unittest_cov
- dub -c unittest-runner-cov -b debug --verror
after_script: after_script:
- bash <(curl -s https://codecov.io/bash) -s reports -t 1a0c0169-a721-4085-8252-fed4755dcd8c - bash <(curl -s https://codecov.io/bash) -s reports -t 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

2
demos/.gitignore vendored
View file

@ -12,4 +12,6 @@
!.gitignore !.gitignore
!compile_wasm.py !compile_wasm.py
!cimgui.bc !cimgui.bc
!emscripten_shell.html
!emscripten_multi_shell.html
.dub .dub

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 24 KiB

Before After
Before After

View file

@ -1,6 +1,7 @@
import os import os
import ntpath import ntpath
import sys import sys
import imp
def compile(sources, output): def compile(sources, output):
files = [] files = []
@ -36,8 +37,10 @@ compiler = 'ldc2 '
shared_flags = '' shared_flags = ''
clean = 0 clean = 0
demo = 0 demo = 0
only_bc = 0
multi = 0
sources = ['tests', 'source'] 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 ' 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'] 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 ' shared_flags += '-Oz '
elif(arg == '-g'): elif(arg == '-g'):
shared_flags += '-g ' shared_flags += '-g '
elif(arg == '--multi'):
multi = 1
elif(arg == '-g4'): elif(arg == '-g4'):
ldc_flags += '-g ' ldc_flags += '-g '
emc_flags += '-g4 --source-map-base ./ ' emc_flags += '-g4 --source-map-base ./ '
@ -79,6 +84,8 @@ for arg in sys.argv[1:]:
emc_flags += '-s USE_PTHREADS=1 ' emc_flags += '-s USE_PTHREADS=1 '
elif(arg == '--demo=simple'): elif(arg == '--demo=simple'):
demo = 0 demo = 0
elif(arg == '--only-bc'):
only_bc = 1
else: else:
print('unknown argument: ' + arg) print('unknown argument: ' + arg)
exit() 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: if clean or os.path.exists('../ecs.bc') == 0 or os.path.isfile('../ecs.bc') == 0:
compile(['../source'], '../ecs.bc') 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 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 += '../ecs.bc '
emcc_cmd += 'utils.bc ' emcc_cmd += 'utils.bc '
@ -103,6 +119,24 @@ emcc_cmd += 'cimgui.bc '
emcc_cmd += 'mmutils.bc ' emcc_cmd += 'mmutils.bc '
emcc_cmd += 'demo.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(emcc_cmd)
os.system('rm build/assets.js')

View file

@ -0,0 +1,170 @@
<!doctype html>
<html lang="en-us">
<head>
<meta charset="utf-8">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>ECS Demo</title>
<style>
.emscripten { padding-right: 0; margin-left: auto; margin-right: auto; display: block; }
textarea.emscripten { font-family: monospace; width: 80%; }
div.emscripten { text-align: center; }
div.emscripten_border { border: 1px solid black; }
/* the canvas *must not* have any border or padding, or mouse coords will be wrong */
canvas.emscripten { position: absolute;top: 0px;left: 0px;margin: 0px; border: 0px none; background-color: black; width: 100%; height: 100%; overflow: hidden;}
.spinner {
height: 50px;
width: 50px;
margin: 0px auto;
-webkit-animation: rotation .8s linear infinite;
-moz-animation: rotation .8s linear infinite;
-o-animation: rotation .8s linear infinite;
animation: rotation 0.8s linear infinite;
border-left: 10px solid rgb(0,150,240);
border-right: 10px solid rgb(0,150,240);
border-bottom: 10px solid rgb(0,150,240);
border-top: 10px solid rgb(100,0,200);
border-radius: 100%;
background-color: rgb(200,100,250);
}
@-webkit-keyframes rotation {
from {-webkit-transform: rotate(0deg);}
to {-webkit-transform: rotate(360deg);}
}
@-moz-keyframes rotation {
from {-moz-transform: rotate(0deg);}
to {-moz-transform: rotate(360deg);}
}
@-o-keyframes rotation {
from {-o-transform: rotate(0deg);}
to {-o-transform: rotate(360deg);}
}
@keyframes rotation {
from {transform: rotate(0deg);}
to {transform: rotate(360deg);}
}
</style>
</head>
<body>
<!--<hr/>-->
<figure style="overflow:visible;" id="spinner"><div class="spinner"></div><center style="margin-top:0.5em"><strong>emscripten</strong></center></figure>
<div class="emscripten" id="status">Downloading...</div>
<div class="emscripten">
<progress value="0" max="100" id="progress" hidden=1></progress>
</div>
<div class="emscripten_border">
<canvas class="emscripten" id="canvas" oncontextmenu="event.preventDefault()" tabindex=-1></canvas>
</div>
<!--<hr/>
<div class="emscripten">
<input type="checkbox" id="resize">Resize canvas
<input type="checkbox" id="pointerLock" checked>Lock/hide mouse pointer
&nbsp;&nbsp;&nbsp;
<input type="button" value="Fullscreen" onclick="Module.requestFullscreen(document.getElementById('pointerLock').checked,
document.getElementById('resize').checked)">
</div>-->
<hr/>
<textarea class="emscripten" id="output" rows="8"></textarea>
<hr>
<script type='text/javascript'>
var statusElement = document.getElementById('status');
var progressElement = document.getElementById('progress');
var spinnerElement = document.getElementById('spinner');
var canvasElement = document.getElementById('canvas');
canvasElement.style.display = "none";
var Module = {
preRun: [],
postRun: [],
print: (function() {
var element = document.getElementById('output');
if (element) element.value = ''; // clear browser cache
return function(text) {
if (arguments.length > 1) text = Array.prototype.slice.call(arguments).join(' ');
// These replacements are necessary if you render to raw HTML
//text = text.replace(/&/g, "&amp;");
//text = text.replace(/</g, "&lt;");
//text = text.replace(/>/g, "&gt;");
//text = text.replace('\n', '<br>', 'g');
console.log(text);
if (element) {
element.value += text + "\n";
element.scrollTop = element.scrollHeight; // focus on bottom
}
};
})(),
printErr: function(text) {
if (arguments.length > 1) text = Array.prototype.slice.call(arguments).join(' ');
console.error(text);
},
canvas: (function() {
var canvas = document.getElementById('canvas');
// As a default initial behavior, pop up an alert when webgl context is lost. To make your
// application robust, you may want to override this behavior before shipping!
// See http://www.khronos.org/registry/webgl/specs/latest/1.0/#5.15.2
canvas.addEventListener("webglcontextlost", function(e) { alert('WebGL context lost. You will need to reload the page.'); e.preventDefault(); }, false);
return canvas;
})(),
setStatus: function(text) {
if (!Module.setStatus.last) Module.setStatus.last = { time: Date.now(), text: '' };
if (text === Module.setStatus.last.text) return;
var m = text.match(/([^(]+)\((\d+(\.\d+)?)\/(\d+)\)/);
var now = Date.now();
if (m && now - Module.setStatus.last.time < 30) return; // if this is a progress update, skip it if too soon
Module.setStatus.last.time = now;
Module.setStatus.last.text = text;
if (m) {
text = m[1];
progressElement.value = parseInt(m[2])*100;
progressElement.max = parseInt(m[4])*100;
progressElement.hidden = false;
spinnerElement.hidden = false;
} else {
progressElement.value = null;
progressElement.max = null;
progressElement.hidden = true;
if (!text) spinnerElement.hidden = true;
}
statusElement.innerHTML = text;
},
totalDependencies: 0,
monitorRunDependencies: function(left) {
this.totalDependencies = Math.max(this.totalDependencies, left);
Module.setStatus(left ? 'Preparing... (' + (this.totalDependencies-left) + '/' + this.totalDependencies + ')' : 'All downloads complete.');
if (!left) canvasElement.style.display = "block";
}
};
Module.setStatus('Downloading...');
window.onerror = function() {
canvasElement.style.display = "none";
Module.setStatus('Exception thrown, see JavaScript console');
spinnerElement.style.display = 'none';
Module.setStatus = function(text) {
if (text) Module.printErr('[post-exception status] ' + text);
};
};
(function() {
if(typeof SharedArrayBuffer !== "undefined")
{
memory_test = new WebAssembly.Memory({
"initial": 1,
"maximum": 1,
"shared": true
});
if (!(memory_test.buffer instanceof SharedArrayBuffer))src = "ecs_demo.js";
else src = "ecs_demo_mt.js";
delete memory_test;
}
else src = "ecs_demo.js";
document.write('<script async type="text/javascript" src="' + src + '"><\/script>');
})();
</script>
<!--{{{ SCRIPT }}}-->
</body>
</html>

154
demos/emscripten_shell.html Normal file
View file

@ -0,0 +1,154 @@
<!doctype html>
<html lang="en-us">
<head>
<meta charset="utf-8">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>ECS Demo</title>
<style>
.emscripten { padding-right: 0; margin-left: auto; margin-right: auto; display: block; }
textarea.emscripten { font-family: monospace; width: 80%; }
div.emscripten { text-align: center; }
div.emscripten_border { border: 1px solid black; }
/* the canvas *must not* have any border or padding, or mouse coords will be wrong */
canvas.emscripten { position: absolute;top: 0px;left: 0px;margin: 0px; border: 0px none; background-color: black; width: 100%; height: 100%; overflow: hidden;}
.spinner {
height: 50px;
width: 50px;
margin: 0px auto;
-webkit-animation: rotation .8s linear infinite;
-moz-animation: rotation .8s linear infinite;
-o-animation: rotation .8s linear infinite;
animation: rotation 0.8s linear infinite;
border-left: 10px solid rgb(0,150,240);
border-right: 10px solid rgb(0,150,240);
border-bottom: 10px solid rgb(0,150,240);
border-top: 10px solid rgb(100,0,200);
border-radius: 100%;
background-color: rgb(200,100,250);
}
@-webkit-keyframes rotation {
from {-webkit-transform: rotate(0deg);}
to {-webkit-transform: rotate(360deg);}
}
@-moz-keyframes rotation {
from {-moz-transform: rotate(0deg);}
to {-moz-transform: rotate(360deg);}
}
@-o-keyframes rotation {
from {-o-transform: rotate(0deg);}
to {-o-transform: rotate(360deg);}
}
@keyframes rotation {
from {transform: rotate(0deg);}
to {transform: rotate(360deg);}
}
</style>
</head>
<body>
<!--<hr/>-->
<figure style="overflow:visible;" id="spinner"><div class="spinner"></div><center style="margin-top:0.5em"><strong>emscripten</strong></center></figure>
<div class="emscripten" id="status">Downloading...</div>
<div class="emscripten">
<progress value="0" max="100" id="progress" hidden=1></progress>
</div>
<div class="emscripten_border">
<canvas class="emscripten" id="canvas" oncontextmenu="event.preventDefault()" tabindex=-1></canvas>
</div>
<!--<hr/>
<div class="emscripten">
<input type="checkbox" id="resize">Resize canvas
<input type="checkbox" id="pointerLock" checked>Lock/hide mouse pointer
&nbsp;&nbsp;&nbsp;
<input type="button" value="Fullscreen" onclick="Module.requestFullscreen(document.getElementById('pointerLock').checked,
document.getElementById('resize').checked)">
</div>-->
<hr/>
<textarea class="emscripten" id="output" rows="8"></textarea>
<hr>
<script type='text/javascript'>
var statusElement = document.getElementById('status');
var progressElement = document.getElementById('progress');
var spinnerElement = document.getElementById('spinner');
var canvasElement = document.getElementById('canvas');
canvasElement.style.display = "none";
var Module = {
preRun: [],
postRun: [],
print: (function() {
var element = document.getElementById('output');
if (element) element.value = ''; // clear browser cache
return function(text) {
if (arguments.length > 1) text = Array.prototype.slice.call(arguments).join(' ');
// These replacements are necessary if you render to raw HTML
//text = text.replace(/&/g, "&amp;");
//text = text.replace(/</g, "&lt;");
//text = text.replace(/>/g, "&gt;");
//text = text.replace('\n', '<br>', 'g');
console.log(text);
if (element) {
element.value += text + "\n";
element.scrollTop = element.scrollHeight; // focus on bottom
}
};
})(),
printErr: function(text) {
if (arguments.length > 1) text = Array.prototype.slice.call(arguments).join(' ');
console.error(text);
},
canvas: (function() {
var canvas = document.getElementById('canvas');
// As a default initial behavior, pop up an alert when webgl context is lost. To make your
// application robust, you may want to override this behavior before shipping!
// See http://www.khronos.org/registry/webgl/specs/latest/1.0/#5.15.2
canvas.addEventListener("webglcontextlost", function(e) { alert('WebGL context lost. You will need to reload the page.'); e.preventDefault(); }, false);
return canvas;
})(),
setStatus: function(text) {
if (!Module.setStatus.last) Module.setStatus.last = { time: Date.now(), text: '' };
if (text === Module.setStatus.last.text) return;
var m = text.match(/([^(]+)\((\d+(\.\d+)?)\/(\d+)\)/);
var now = Date.now();
if (m && now - Module.setStatus.last.time < 30) return; // if this is a progress update, skip it if too soon
Module.setStatus.last.time = now;
Module.setStatus.last.text = text;
if (m) {
text = m[1];
progressElement.value = parseInt(m[2])*100;
progressElement.max = parseInt(m[4])*100;
progressElement.hidden = false;
spinnerElement.hidden = false;
} else {
progressElement.value = null;
progressElement.max = null;
progressElement.hidden = true;
if (!text) spinnerElement.hidden = true;
}
statusElement.innerHTML = text;
},
totalDependencies: 0,
monitorRunDependencies: function(left) {
this.totalDependencies = Math.max(this.totalDependencies, left);
Module.setStatus(left ? 'Preparing... (' + (this.totalDependencies-left) + '/' + this.totalDependencies + ')' : 'All downloads complete.');
if (!left) canvasElement.style.display = "block";
}
};
Module.setStatus('Downloading...');
window.onerror = function() {
canvasElement.style.display = "none";
Module.setStatus('Exception thrown, see JavaScript console');
spinnerElement.style.display = 'none';
Module.setStatus = function(text) {
if (text) Module.printErr('[post-exception status] ' + text);
};
};
</script>
{{{ SCRIPT }}}
</body>
</html>

View file

@ -12,6 +12,8 @@ import std.algorithm : map;
version = MM_NO_LOGS; // Disable log creation version = MM_NO_LOGS; // Disable log creation
//version = MM_USE_POSIX_THREADS; // Use posix threads insted of standard library, required for betterC //version = MM_USE_POSIX_THREADS; // Use posix threads insted of standard library, required for betterC
version (Posix)version = MM_USE_POSIX_THREADS;
version (WebAssembly) version (WebAssembly)
{ {
extern(C) struct FILE extern(C) struct FILE
@ -374,7 +376,8 @@ version (MM_USE_POSIX_THREADS)
{ {
threadStart = dg; threadStart = dg;
int ok = pthread_create(&handle, null, &threadRunFunc, cast(void*)&this); int ok = pthread_create(&handle, null, &threadRunFunc, cast(void*)&this);
assert(ok == 0); if(!ok)handle = pthread_t();
//assert(ok == 0);
} }
void join() void join()
@ -459,7 +462,8 @@ else version(D_BetterC)
{ {
threadStart = dg; threadStart = dg;
int ok = pthread_create(&handle, null, &threadRunFunc, cast(void*)&this); int ok = pthread_create(&handle, null, &threadRunFunc, cast(void*)&this);
assert(ok == 0); if(!ok)handle = pthread_t();
//assert(ok == 0);
} }
void join() void join()
@ -567,7 +571,7 @@ else version(D_BetterC)
threadStart = dg; threadStart = dg;
handle = cast(HANDLE) _beginthreadex( null, 0, &threadRunFunc, cast(void*)&this, 0, null ); handle = cast(HANDLE) _beginthreadex( null, 0, &threadRunFunc, cast(void*)&this, 0, null );
//int ok = pthread_create(&handle, null, &threadRunFunc, cast(void*)&this); //int ok = pthread_create(&handle, null, &threadRunFunc, cast(void*)&this);
assert(handle != null); //assert(handle != null);
} }
void join() void join()

View file

@ -51,6 +51,7 @@ struct Launcher
void function() end; void function() end;
void function(SDL_Event*) event; void function(SDL_Event*) event;
void function(vec2, Tool, int) tool; void function(vec2, Tool, int) tool;
float scalling;
ivec2 window_size = ivec2(1024,768); ivec2 window_size = ivec2(1024,768);
Renderer renderer; Renderer renderer;
ubyte[] keys; ubyte[] keys;
@ -60,6 +61,7 @@ struct Launcher
ulong timer_freq; ulong timer_freq;
double delta_time; double delta_time;
uint fps; uint fps;
vec2 render_position;
Tool used_tool; Tool used_tool;
int tool_size = 0; 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)) 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) else if(event.type == SDL_MOUSEBUTTONUP)
@ -255,7 +257,7 @@ void mainLoop(void* arg)
while(launcher.repeat_time > range) while(launcher.repeat_time > range)
{ {
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.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); //glClear(GL_COLOR_BUFFER_BIT);
launcher.renderer.clear(); launcher.renderer.clear();

View file

@ -60,7 +60,7 @@ struct DrawSystem
{ {
foreach(i; 0..data.length) 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)); //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) foreach(i; 0..data.length)
{ {
data.locations[i].location.y = data.locations[i].location.y + 1; 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(i; 0..10)
foreach(j; 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); launcher.manager.addEntity(simple.tmpl);
} }
} }
@ -147,6 +147,10 @@ void simpleTool(vec2 position, Tool tool, int size)
{ {
position.x += (randomf - 0.5) * size; position.x += (randomf - 0.5) * size;
position.y += (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; *location = position;
} }
launcher.manager.addEntity(tmpl); launcher.manager.addEntity(tmpl);
@ -169,18 +173,19 @@ void simpleEvent(SDL_Event* event)
void spawnEntity() void spawnEntity()
{ {
CLocation* loc_comp = simple.tmpl.getComponent!CLocation; 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); launcher.manager.addEntity(simple.tmpl);
} }
bool simpleLoop() 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)) if(launcher.getKeyState(SDL_SCANCODE_SPACE))
{ {
foreach(i;0..1)spawnEntity(); foreach(i;0..1)spawnEntity();
} }
launcher.manager.begin(); launcher.manager.begin();
if(launcher.multithreading) if(launcher.multithreading)
{ {

View file

@ -17,6 +17,10 @@ import ecs_utils.gfx.texture;
import ecs_utils.math.vector; import ecs_utils.math.vector;
import ecs_utils.utils; import ecs_utils.utils;
import std.array : staticArray;
enum float px = 1.0/512.0;
extern(C): extern(C):
struct MapElement struct MapElement
@ -24,9 +28,24 @@ struct MapElement
enum Type enum Type
{ {
empty = 0, empty = 0,
snake = 1, apple = 1,
apple = 2, wall = 2,
wall = 3
snake_head_up = 5,
snake_head_down = 6,
snake_head_left = 7,
snake_head_right = 8,
snake_tail_up = 9,
snake_tail_down = 10,
snake_tail_left = 11,
snake_tail_right = 12,
snake_turn_ld = 13,
snake_turn_lu = 14,
snake_turn_rd = 15,
snake_turn_ru = 16,
snake_vertical = 17,
snake_horizontal = 18
} }
Type type; Type type;
EntityID id; EntityID id;
@ -38,8 +57,13 @@ struct Snake
EntityTemplate* apple_tmpl; EntityTemplate* apple_tmpl;
EntityTemplate* snake_tmpl; EntityTemplate* snake_tmpl;
EntityTemplate* snake_destroy_particle;
Texture texture; Texture texture;
vec4[] snake_destroy_particle_frames;
vec4[] smoke_frames;
bool move_system = true; bool move_system = true;
bool draw_system = true; bool draw_system = true;
@ -83,16 +107,30 @@ struct Snake
void drawMap() void drawMap()
{ {
const float px = 1.0/512.0;
foreach(x; 0 .. map_size) foreach(x; 0 .. map_size)
{ {
foreach(y; 0 .. map_size) foreach(y; 0 .. map_size)
{ {
switch(element(ivec2(x,y)).type) 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.apple:launcher.renderer.draw(texture, vec2(x*16,y*16), vec2(16,16), vec4(0,32*px,16*px,16*px), 0, 0 , 0);break;
case MapElement.Type.snake:launcher.renderer.draw(texture, vec2(x*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.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; default:break;
} }
} }
@ -101,6 +139,19 @@ struct Snake
} }
struct Animation
{
}
struct CAnimation
{
mixin ECS.Component;
vec4[] frames;
float time = 0;
}
struct CILocation struct CILocation
{ {
mixin ECS.Component; mixin ECS.Component;
@ -116,7 +167,7 @@ struct CLocation
alias location this; alias location this;
vec2 location; vec2 location = vec2(0,0);
} }
struct CSnake struct CSnake
@ -176,13 +227,15 @@ struct CApple
struct CParticle struct CParticle
{ {
mixin ECS.Component; mixin ECS.Component;
float life = 0;
} }
struct CParticleVector struct CParticleVector
{ {
mixin ECS.Component; mixin ECS.Component;
vec2 velocity; vec2 velocity = vec2(0,0);
} }
struct CMovement 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 struct MoveSystem
{ {
mixin ECS.System!64; mixin ECS.System!64;
EntityTemplate* destroy_template;
CLocation* destroy_location;
CParticleVector* destroy_vector;
struct EntitiesData struct EntitiesData
{ {
uint length; uint length;
@ -239,6 +380,13 @@ struct MoveSystem
CILocation[] location; 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) void moveLocation(ref CILocation location, CMovement.Direction direction)
{ {
final switch(direction) final switch(direction)
@ -276,6 +424,56 @@ struct MoveSystem
else .snake.element(MapElement(),location); 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) void onUpdate(EntitiesData data)
{ {
if(data.snakes) if(data.snakes)
@ -286,21 +484,104 @@ struct MoveSystem
moveLocation(data.location[i], data.movement[i].direction); moveLocation(data.location[i], data.movement[i].direction);
final switch(snake.element(data.location[i].location).type) final switch(snake.element(data.location[i].location).type)
{ {
case MapElement.Type.snake: case MapElement.Type.snake_head_up:goto case(MapElement.Type.snake_horizontal);
launcher.manager.removeEntity(data.entities[i].id); case MapElement.Type.snake_head_down:goto case(MapElement.Type.snake_horizontal);
break; case MapElement.Type.snake_head_left:goto case(MapElement.Type.snake_horizontal);
case MapElement.Type.wall: 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); launcher.manager.removeEntity(data.entities[i].id);
break; break;
case MapElement.Type.wall:break;
//launcher.manager.removeEntity(data.entities[i].id);
//break;
case MapElement.Type.empty: case MapElement.Type.empty:
moveSnake(data.snakes[i], new_location); 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; break;
case MapElement.Type.apple: case MapElement.Type.apple:
launcher.manager.removeEntity(snake.element(data.location[i].location).id); launcher.manager.removeEntity(snake.element(data.location[i].location).id);
data.snakes[i].parts.add(new_location); if(data.snakes[i].parts.length < 100)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 > 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(); snake.addApple();
break; break;
} }
@ -455,19 +736,31 @@ void snakeStart()
launcher.manager.registerComponent!CSnake; launcher.manager.registerComponent!CSnake;
launcher.manager.registerComponent!CApple; launcher.manager.registerComponent!CApple;
launcher.manager.registerComponent!CParticle; launcher.manager.registerComponent!CParticle;
launcher.manager.registerComponent!CParticleVector;
launcher.manager.registerComponent!CMovement; launcher.manager.registerComponent!CMovement;
launcher.manager.registerComponent!CInput; launcher.manager.registerComponent!CInput;
launcher.manager.registerComponent!CAnimation;
launcher.manager.registerSystem!MoveSystem(0,"fixed"); launcher.manager.registerSystem!MoveSystem(0,"fixed");
launcher.manager.registerSystem!InputSystem(-100); launcher.manager.registerSystem!InputSystem(-100);
launcher.manager.registerSystem!FixSnakeDirectionSystem(-1,"fixed"); launcher.manager.registerSystem!FixSnakeDirectionSystem(-1,"fixed");
launcher.manager.registerSystem!AppleSystem(-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.manager.endRegister();
launcher.gui_manager.addSystem(MoveSystem.system_id,"Move System"); launcher.gui_manager.addSystem(MoveSystem.system_id,"Move System");
launcher.gui_manager.addSystem(InputSystem.system_id,"Input System"); launcher.gui_manager.addSystem(InputSystem.system_id,"Input System");
launcher.gui_manager.addSystem(FixSnakeDirectionSystem.system_id,"Fix Direction 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]; ushort[4] components = [CILocation.component_id, CSnake.component_id, CMovement.component_id, CInput.component_id];
@ -477,6 +770,14 @@ void snakeStart()
launcher.manager.addEntity(snake.snake_tmpl); 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]; ushort[2] components = [CILocation.component_id, CApple.component_id];
snake.apple_tmpl = launcher.manager.allocateTemplate(components); snake.apple_tmpl = launcher.manager.allocateTemplate(components);
@ -485,6 +786,10 @@ void snakeStart()
launcher.gui_manager.addTemplate(snake.snake_tmpl, "Snake"); launcher.gui_manager.addTemplate(snake.snake_tmpl, "Snake");
launcher.gui_manager.addTemplate(snake.apple_tmpl, "Apple"); 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(i; 0..10)
foreach(j; 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.x += (randomf - 0.5) * size;
position.y += (randomf - 0.5) * size; position.y += (randomf - 0.5) * size;
ivec2 ipos; ivec2 ipos;
ipos.x = cast(int)(position.x / 32); ipos.x = cast(int)(position.x / 16);
ipos.y = cast(int)(position.y / 32); ipos.y = cast(int)(position.y / 16);
*ilocation = ipos; *ilocation = ipos;
if(snake.element(ipos).type != MapElement.Type.empty)return; if(snake.element(ipos).type != MapElement.Type.empty)return;
} }
@ -540,6 +845,8 @@ void snakeEvent(SDL_Event* event)
bool snakeLoop() 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) /*if(launcher.show_demo_wnd)
{ {
igSetNextWindowPos(ImVec2(800 - 260, 30), ImGuiCond_Once, ImVec2(0,0)); igSetNextWindowPos(ImVec2(800 - 260, 30), ImGuiCond_Once, ImVec2(0,0));

View file

@ -16,6 +16,8 @@ import ecs_utils.gfx.texture;
import ecs_utils.math.vector; import ecs_utils.math.vector;
import ecs_utils.utils; import ecs_utils.utils;
enum float px = 1.0/512.0;
extern(C): extern(C):
/*####################################################################################################################### /*#######################################################################################################################
@ -34,7 +36,7 @@ struct SpaceInvaders
bool move_system = true; bool move_system = true;
bool draw_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; const float cell_size = 60;
} }
@ -101,7 +103,7 @@ struct CScale
///use component as it value ///use component as it value
alias value this; alias value this;
vec2 value = vec2(32,32); vec2 value = vec2(16,16);
} }
struct CTexture struct CTexture
@ -564,8 +566,8 @@ struct MovementSystem
{ {
foreach(i;0..data.length) foreach(i;0..data.length)
{ {
data.locations[i].x += data.velocity[i].x * 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; data.locations[i].y += data.velocity[i].y * launcher.delta_time * 0.5;
} }
} }
} }
@ -587,6 +589,7 @@ struct InputMovementSystem
const (CInput)[] input; const (CInput)[] input;
//components are treated as required by default //components are treated as required by default
CLocation[] locations; CLocation[] locations;
CTexture[] textures;
} }
/** /**
@ -595,6 +598,7 @@ struct InputMovementSystem
*/ */
bool onBegin() bool onBegin()
{ {
move_vector = vec2(0,0);
if(launcher.getKeyState(SDL_SCANCODE_W)) if(launcher.getKeyState(SDL_SCANCODE_W))
{ {
move_vector = vec2(0,1); move_vector = vec2(0,1);
@ -616,7 +620,7 @@ struct InputMovementSystem
return true; return true;
} }
//don't call system update because no key pressed //don't call system update because no key pressed
return false; return true;
} }
/** /**
@ -627,11 +631,21 @@ struct InputMovementSystem
*/ */
void onUpdate(EntitiesData data) 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 //move every entity using movement vector
foreach(i; 0..data.length) foreach(i; 0..data.length)
{ {
data.locations[i].x += move_vector.x * 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.5; 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() void spaceInvadersStart()
{ {
const float px = 1.0/512.0;
space_invaders = Mallocator.make!SpaceInvaders; space_invaders = Mallocator.make!SpaceInvaders;
space_invaders.texture.create(); 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]; ushort[7] components = [CLocation.component_id, CTexture.component_id, CInput.component_id, CShip.component_id, CScale.component_id, CLaserWeapon.component_id, CShootDirection.component_id];
space_invaders.ship_tmpl = launcher.manager.allocateTemplate(components); space_invaders.ship_tmpl = launcher.manager.allocateTemplate(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; CTexture* tex_comp = space_invaders.ship_tmpl.getComponent!CTexture;
tex_comp.tex = space_invaders.texture;//ship_tex; tex_comp.tex = space_invaders.texture;//ship_tex;
tex_comp.coords = vec4(0*px,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; CLocation* loc_comp = space_invaders.ship_tmpl.getComponent!CLocation;
loc_comp.value = vec2(64,64); loc_comp.value = vec2(64,64);
CLaserWeapon* weapon = space_invaders.ship_tmpl.getComponent!CLaserWeapon; CLaserWeapon* weapon = space_invaders.ship_tmpl.getComponent!CLaserWeapon;
@ -707,9 +721,9 @@ void spaceInvadersStart()
CTexture* tex_comp = space_invaders.laser_tmpl.getComponent!CTexture; CTexture* tex_comp = space_invaders.laser_tmpl.getComponent!CTexture;
tex_comp.tex = space_invaders.texture;//laser_tex; 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; 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; CVelocity* vel_comp = space_invaders.laser_tmpl.getComponent!CVelocity;
vel_comp.value = vec2(0,1); vel_comp.value = vec2(0,1);
} }
@ -727,7 +741,7 @@ void spaceInvadersStart()
tex_comp.tex = space_invaders.texture;//ship_tex; tex_comp.tex = space_invaders.texture;//ship_tex;
tex_comp.coords = vec4(32*px,32*px,16*px,16*px); tex_comp.coords = vec4(32*px,32*px,16*px,16*px);
CLocation* loc_comp = space_invaders.enemy_tmpl.getComponent!CLocation; 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; CShootDirection* shoot_dir_comp = space_invaders.enemy_tmpl.getComponent!CShootDirection;
shoot_dir_comp.direction = Direction.down; shoot_dir_comp.direction = Direction.down;
CVelocity* vel_comp = space_invaders.enemy_tmpl.getComponent!CVelocity; CVelocity* vel_comp = space_invaders.enemy_tmpl.getComponent!CVelocity;
@ -738,17 +752,17 @@ void spaceInvadersStart()
current_entity = launcher.manager.addEntity(space_invaders.enemy_tmpl); current_entity = launcher.manager.addEntity(space_invaders.enemy_tmpl);
launcher.manager.addComponents(current_entity.id,CSideMove(0)); 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); current_entity = launcher.manager.addEntity(space_invaders.enemy_tmpl);
launcher.manager.addComponents(current_entity.id,CSideMove(-1)); launcher.manager.addComponents(current_entity.id,CSideMove(-1));
enemy_id = current_entity.id; enemy_id = current_entity.id;
//enemy_tmpl = launcher.manager.allocateTemplate(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); 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); current_entity = launcher.manager.addEntity(space_invaders.enemy_tmpl);
launcher.manager.addComponents(current_entity.id,CSideMove(0)); launcher.manager.addComponents(current_entity.id,CSideMove(0));
@ -809,6 +823,7 @@ void spaceInvadersEvent(SDL_Event* event)
bool spaceInvadersLoop() 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) /*if(launcher.show_demo_wnd)
{ {

View file

@ -55,10 +55,10 @@ struct Buffer
glBufferStorage(GL_ARRAY_BUFFER,size*count,data, flags); 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); bind(target);
glBufferSubData(GL_ARRAY_BUFFER,offset,size,data); glBufferSubData(target,offset,size,data);
} }
void map(BindTarget target) nothrow void map(BindTarget target) nothrow

View file

@ -98,7 +98,7 @@ struct Renderer
alias Technique = RenderTechnique; alias Technique = RenderTechnique;
__gshared Technique technique = Technique.simple; __gshared Technique technique = Technique.vbo_batch;
void* data_ptr; void* data_ptr;
//import ecs_utils.core : RenderTechnique; //import ecs_utils.core : RenderTechnique;
@ -339,6 +339,7 @@ struct Renderer
//import core.stdc.string; //import core.stdc.string;
with(this_) with(this_)
{ {
if(item_id >= MaxObjects)return;
//pos += view_pos; //pos += view_pos;
size.x *= view_size.x; size.x *= view_size.x;
size.y *= view_size.y; size.y *= view_size.y;
@ -470,8 +471,8 @@ struct Renderer
break; break;
case Technique.vbo_batch: case Technique.vbo_batch:
//if(data_index){ //if(data_index){
batch_vbo[0].bufferSubData(item_id*4*16,0,batch_vertices.ptr); batch_vbo[0].bufferSubData(Buffer.BindTarget.array,item_id*4*16,0,batch_vertices.ptr);
batch_ibo[0].bufferSubData(item_id*6*2,0,batch_indices.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_vbo[0].bind(Buffer.BindTarget.array);
batch_ibo[0].bind(Buffer.BindTarget.element_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);//} glVertexAttribPointer(1,2,GL_FLOAT,false,16,cast(void*)8);//}
break; break;
case Technique.instanced_attrib_divisor: case Technique.instanced_attrib_divisor:
ubos[0].bufferSubData(data_index,0,uniform_block.ptr); ubos[0].bufferSubData(Buffer.BindTarget.uniform,data_index,0,uniform_block.ptr);
ubos[0].bind(Buffer.BindTarget.array); ubos[0].bind(Buffer.BindTarget.uniform);
glEnableVertexAttribArray(2); glEnableVertexAttribArray(2);
glEnableVertexAttribArray(3); glEnableVertexAttribArray(3);
glEnableVertexAttribArray(4); glEnableVertexAttribArray(4);
@ -496,7 +497,7 @@ struct Renderer
break; break;
case Technique.uniform_buffer: case Technique.uniform_buffer:
//ubos[0].bufferData(1,64*MaxObjects,BufferUsage,null); //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; break;
case Technique.uniform_buffer_indexed: case Technique.uniform_buffer_indexed:
ubos[0].bindRange(Buffer.BindTarget.uniform,0,0,block_max_size); ubos[0].bindRange(Buffer.BindTarget.uniform,0,0,block_max_size);
@ -581,6 +582,8 @@ struct Renderer
{ {
material_id = render_list[i].material_id; material_id = render_list[i].material_id;
GfxConfig.materials[material_id].bind(); 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) if(texture.data != render_list[i].texture.data)
{ {
@ -589,17 +592,17 @@ struct Renderer
} }
uint instance_count = 16_384; 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)); 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) else if(technique == Technique.ssbo_instanced || technique == Technique.instanced_attrib_divisor)
@ -794,9 +797,10 @@ struct Renderer
void view(vec2 pos, vec2 size) 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); view_size = vec2(2/size.x,2/size.y);
sdl_transform = vec4(0,0,1.0/size.x,1.0/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; __gshared void function(ref Renderer this_, Texture tex, vec2 pos, vec2 size, vec4 coords, float angle, uint material_id, uint mesh_id) __draw;

View file

@ -55,6 +55,7 @@ struct Texture
data.data[0..$] = (cast(ubyte*)surf.pixels)[0..data.data.length]; data.data[0..$] = (cast(ubyte*)surf.pixels)[0..data.data.length];
glGenTextures(1, &data.gl_handle); glGenTextures(1, &data.gl_handle);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D,data.gl_handle); glBindTexture(GL_TEXTURE_2D,data.gl_handle);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);

View file

@ -30,6 +30,11 @@ struct vec2
else static assert(0, "Operator "~op~" not implemented"); else static assert(0, "Operator "~op~" not implemented");
} }
ivec2 opCast()
{
return ivec2(cast(int)x,cast(int)y);
}
void opOpAssign(string op)(vec2 v) void opOpAssign(string op)(vec2 v)
{ {
static if (op == "+") static if (op == "+")
@ -69,6 +74,15 @@ struct vec4
} }
float[4] data; 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 struct ivec2
@ -82,6 +96,11 @@ struct ivec2
} }
int[2] data; int[2] data;
} }
vec2 opCast()
{
return vec2(x,y);
}
} }
struct ivec4 struct ivec4

View file

@ -5,7 +5,7 @@
], ],
"description": "Dynamic Entity Component System", "description": "Dynamic Entity Component System",
"copyright": "Copyright © 2018-2019, Michał Masiukiewicz, Dawid Masiukiewicz", "copyright": "Copyright © 2018-2019, Michał Masiukiewicz, Dawid Masiukiewicz",
"license": "BSD", "license": "BSD 3-clause",
"sourcePaths" : ["source\/"], "sourcePaths" : ["source\/"],
"excludedSourceFiles":[ "excludedSourceFiles":[
"source\/ecs\/traits.d" "source\/ecs\/traits.d"

36
skeleton.html Normal file
View file

@ -0,0 +1,36 @@
<!DOCTYPE html>
<html>
<head>
<title>BubelECS</title>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="stylesheet" href="style.css" />
<script type="text/javascript" src="script.js"></script>
<!-- You should delete this line if you don't want to use
the JS-based search as it exists just to optimize that. -->
<link rel="prefetch" href="search-results.html" />
</head>
<body>
<div id="page-header">
<div id="logotype">
<span>BubelECS</span>
<nav>
<a href="https://gitlab.com/Mergul/bubel-ecs/">Repository</a>
</nav>
</div>
<form id="search" action="search-docs.html">
<input placeholder="Find a symbol name..." type="search" name="searchTerm" />
<input type="submit" value="Go" />
</form>
</div>
<div id="page-body">
<div id="page-content">
</div>
<div id="page-nav">
</div>
</div>
<div id="page-footer">Page generated by <a href="https://github.com/adamdruppe/adrdox">adrdox</a></div>
</body>
</html>

View file

@ -1,8 +1,11 @@
/************************************************************************************************************************ /************************************************************************************************************************
*It's internal code. Can be used for atomics if emscripten backend will be used. 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. This module contain atomic operations which include support for emscripten atomics functions.
*Emscripten functions are contained in API similar to druntime. Emscripten functions are contained in API similar to druntime.
Copyright: Copyright © 2018-2019, Dawid Masiukiewicz, Michał Masiukiewicz
License: BSD 3-clause, see LICENSE file in project root folder.
*/ */
module ecs.atomic; module ecs.atomic;

View file

@ -1,17 +1,24 @@
/************************************************************************************************************************ /************************************************************************************************************************
*This module contain attributes used to mark components. This module contain attributes used to mark components.
*Currently only two attributes are supported: Currently only two attributes are supported:
* - optional: mark component as optional for system update $(LIST
* - readonly: mark component access as read only (used for multithreading) * 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 By default components are required and mutable. "const" attribute can be used insteac od readonly mark.
*{
* Comp1[] cmp; //mutable required component ---
* @readonly @optional Comp2[] cmp2; //optional read only component Struct EntitiesData
* @optional const (Comp3)[] cmp3; //same as cmp2 {
*} 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; module ecs.attributes;

View file

@ -1,7 +1,10 @@
/************************************************************************************************************************ /************************************************************************************************************************
*It's internal code. It's internal code.
*
*Module contain memory allocator. Module contain memory allocator.
Copyright: Copyright © 2018-2019, Dawid Masiukiewicz, Michał Masiukiewicz
License: BSD 3-clause, see LICENSE file in project root folder.
*/ */
module ecs.block_allocator; module ecs.block_allocator;
@ -9,14 +12,14 @@ import ecs.manager;
import ecs.std; import ecs.std;
/************************************************************************************************************************ /************************************************************************************************************************
*Allocator allocate large blocks and return smaller blocks. When there is no more blocks then next large block is allocated. 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. 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. freeMemory function return to system memory even if chunk blocks wasn't freed.
*/ */
struct BlockAllocator 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 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 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 void freeMemory() nothrow @nogc
{ {

View file

@ -1,34 +1,53 @@
/************************************************************************************************************************ /************************************************************************************************************************
*This module contain main templates for user. This module contain main templates for user.
*There are three structure templates (mixins) which should be added on top of structure: There are three structure templates (mixins) which should be added on top of structure:
* - System: make system structure $(LIST
* - Component: make component structure * System: make system structure
* - Event: make event structure * Component: make component structure
* * Event: make event structure
*ex. )
*Struct System1
*{ ---
* mixin!ECS.System; Struct System1
*} {
* mixin!ECS.System;
*Struct System2 }
*{
* mixin!ECS.System(16);//set number of jobs generated for system by multithreaded update Struct System2
*} {
* mixin!ECS.System(16);//set number of jobs generated for system by multithreaded update
*Struct Component1 }
*{
* mixin!ECS.Component; Struct Component1
*} {
* mixin!ECS.Component;
*Struct Event1 }
*{
* mixin!ECS.Event; 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. ---
*
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; module ecs.core;
@ -36,12 +55,12 @@ public import ecs.manager;
public import ecs.entity; public import ecs.entity;
/************************************************************************************************************************ /************************************************************************************************************************
*Main struct used as namespace for templates. Main struct used as namespace for templates.
*/ */
static struct ECS 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) 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() 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() 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...) mixin template ExcludedComponents(T...)
{ {

View file

@ -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; module ecs.entity;
@ -7,7 +10,7 @@ import ecs.system;
import ecs.manager; 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 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 struct Entity
{ {
@ -26,8 +29,8 @@ struct Entity
EntityID id; EntityID id;
/************************************************************************************************************************ /************************************************************************************************************************
*Get specified component. If component doesn't exist function retun null. Pointer is valid only before next "commit()", "begin()" or "end()" 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. function is called. Returned pointer shouldn't be used to store reference to entity data.
*/ */
T* getComponent(T)() const T* getComponent(T)() const
{ {
@ -45,13 +48,15 @@ struct Entity
} }
/************************************************************************************************************************ /************************************************************************************************************************
*Entity template structure. 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. Entity contain whole information needed to create new entity. Allocating EntityTemplate is considered as more expensive operation
*If you want to place several entity with small difference in data then you should take pointer to component and change it before every than adding entity. Whole components memory is stored in EntityTemplate and is copyied to newly added entity.
*entity addition. If you want to place several entity with small difference in data then you should take pointer to component and change it before every
*There is no restriction about number of allocated templates. Single template can be used from multiple threads, but if you entity addition.
*want to changes some components data before add entity (entity position for example) it's better to use multiple templates.
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 export struct EntityTemplate
{ {
@ -61,7 +66,7 @@ export struct EntityTemplate
EntityManager.EntityInfo* info; 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 T* getComponent(T)() nothrow @nogc
{ {

View file

@ -34,7 +34,7 @@ package struct EventManager
EventData* data = &events[Ev.event_id]; EventData* data = &events[Ev.event_id];
EventBlock* block = data.blocks[block_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; event.entity_id = id;
if(block is null) if(block is null)
@ -119,15 +119,15 @@ package struct EventManager
void allocateData(uint threads_count) nothrow @nogc void allocateData(uint threads_count) nothrow @nogc
{ {
disposeData(); disposeData();
events = Mallocator.makeArray!EventData(gEM.events.length); events = Mallocator.makeArray!EventData(manager.events.length);
foreach(i,ref event;events) foreach(i,ref event;events)
{ {
event.blocks = Mallocator.makeArray!(EventBlock*)(threads_count*2); event.blocks = Mallocator.makeArray!(EventBlock*)(threads_count*2);
event.first_blocks = Mallocator.makeArray!(EventBlock*)(threads_count*2); event.first_blocks = Mallocator.makeArray!(EventBlock*)(threads_count*2);
event.data_offset = EventBlock.sizeof;//gEM.events[i]. event.data_offset = EventBlock.sizeof;//manager.events[i].
gEM.alignNum(event.data_offset, gEM.events[i].alignment); 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);
} }
} }

View file

@ -8,12 +8,12 @@ import ecs.atomic;
import core.stdc.string : memcpy; 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 struct IDManager
{ {
/************************************************************************************************************************ /************************************************************************************************************************
*Get new ID. Get new ID.
*/ */
pragma(inline, false) EntityID getNewID() nothrow @nogc pragma(inline, false) EntityID getNewID() nothrow @nogc
{ {
@ -74,7 +74,7 @@ struct IDManager
} }
/************************************************************************************************************************ /************************************************************************************************************************
*Release ID. Release ID.
*/ */
void releaseID(EntityID id) nothrow @nogc 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 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 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 export bool isExist(EntityID id) nothrow @nogc
{ {
@ -143,7 +143,7 @@ struct IDManager
} }
/************************************************************************************************************************ /************************************************************************************************************************
*Initialize manager. Initialize manager.
*/ */
void initialize() nothrow @nogc void initialize() nothrow @nogc
{ {
@ -162,7 +162,7 @@ struct IDManager
} }
/************************************************************************************************************************ /************************************************************************************************************************
*Free manager memory. Free manager memory.
*/ */
void deinitialize() @trusted @nogc nothrow 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 void optimize() nothrow @nogc
{ {

View file

@ -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; module ecs.manager;
@ -28,37 +31,38 @@ export alias gEntityManager = EntityManager.instance;
alias SerializeVector = ecs.vector.Vector!ubyte; alias SerializeVector = ecs.vector.Vector!ubyte;
/************************************************************************************************************************ /************************************************************************************************************************
*Entity manager is responsible for everything. Entity manager is responsible for everything.
*
*Entity manager can be in three states: Entity manager can be in three states:
* - registration: time between beginRegister() and endRegister() calls. - registration: time between beginRegister() and endRegister() calls.
* - update: time between being() and end() calls. - update: time between being() and end() calls.
* - default: when it's not in registration or update time - default: when it's not in registration or update time
*
*Manager can be only in one state simultaneously. Manager can be only in one state simultaneously.
*
*Manager must be initialized before use. There is global instance of EntityManager: EntityManager.instance or gEM as alias. Manager must be initialized before use. There is global instance of EntityManager: EntityManager.instance or gEM as alias.
*
*Registration process consist of registration of passes, systems, entities and events. 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.<br/> 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 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 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.<br/> 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.<br/> 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.
*Events are structures with data used to handle events. Event can contain for exmaple one floating point number used as damage dealt to entity.<br/> In practice sometimes it's better to join data into one component even if it's can be accessed separetly.
*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 Events are structures with data used to handle events. Event can contain for exmaple one floating point number used as damage dealt to entity.
*grouped by component type so entity can be fracted in big memory chunk.<br/> 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:
*<br/> - update(): function used to call update pass. There is two types of update:
*<br/> - updateMT(): function used to call update pass multithreaded. This call only generates jobs which must be called by user. - 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 export struct EntityManager
{ {
/************************************************************************************************************************ /************************************************************************************************************************
*Initialize ECS. Initialize ECS.
*/ */
export static void initialize(uint threads_count, uint page_size = 32768, export static void initialize(uint threads_count, uint page_size = 32768,
uint block_pages_count = 128) 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() 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 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() 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) 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. 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. 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. System mustn't be registered before components which system want to use, in this case functions call assertion.
*
*Params: Params:
*priority = system priority. Priority determines order of execution of systems updates priority = system priority. Priority determines order of execution of systems updates
*pass = index of UpdatePass which sholud call system update pass = index of UpdatePass which sholud call system update
*/ */
void registerSystem(Sys)(int priority, ushort pass = 0) 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 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 Sys* getSystem(Sys)() nothrow @nogc
{ {
@ -1115,7 +1119,7 @@ export struct EntityManager
} }
/************************************************************************************************************************ /************************************************************************************************************************
*Register component into EntityManager. Register component into EntityManager.
*/ */
void registerComponent(Comp)() 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 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 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 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() 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 Return number of pages in single block allocation. Library allocate defined number of pages at once and assign it's
*for entities. for entities.
*/ */
uint pagesInBlock() 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. Allocate EntityTemplate with all components from entity witch it's data and returns pointer to it.
*
*Params: Params:
*entity_id = ID of entity from which should be created template entity_id = ID of entity from which should be created template
*fill_default = if true, components will be filled with default data, instead entity data will be taken 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) 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. Allocate EntityTemplate with specifed components and returns pointer to it.
*
*Params: Params:
*components_ids = array of components allocated with template components_ids = array of components allocated with template
*/ */
export EntityTemplate* allocateTemplate(ushort[] components_ids) export EntityTemplate* allocateTemplate(ushort[] components_ids)
{ {
@ -1551,10 +1555,13 @@ export struct EntityManager
} }
/************************************************************************************************************************ /************************************************************************************************************************
*Allocate EntityTemplate with specifed components and returns pointer to it. Allocate EntityTemplate from basic Template with modifications by adding and removing some components and returns pointer to it.
* Arrays of components needen't to be checked for repeated components, as function itself check if components exist in base template.
*Params:
*components_ids = array of components allocated with template 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, export EntityTemplate* allocateTemplate(EntityTemplate* base_tmpl,
ushort[] components_ids, ushort[] remove_components_ids = null) ushort[] components_ids, ushort[] remove_components_ids = null)
@ -1624,10 +1631,10 @@ export struct EntityManager
} }
/************************************************************************************************************************ /************************************************************************************************************************
*Returns entity type info. Returns entity type info.
*
*Params: Params:
*ids = array of components ids = array of components
*/ */
export EntityInfo* getEntityInfo(ushort[] ids) export EntityInfo* getEntityInfo(ushort[] ids)
{ {
@ -1930,10 +1937,10 @@ export struct EntityManager
} }
/************************************************************************************************************************ /************************************************************************************************************************
*Returns pointer to entity. Returns pointer to entity.
*
*Params: Params:
*id = ID of entity id = ID of entity
*/ */
export Entity* getEntity(EntityID id) nothrow @nogc 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. Remove components from entity by IDs. Components will be removed on end of frame.
*
*Params: Params:
*entity_id = ID of entity entity_id = ID of entity
*del_ids = array of components IDs del_ids = array of components IDs
*/ */
export void removeComponents(EntityID entity_id, ushort[] del_ids) nothrow @nogc export void removeComponents(EntityID entity_id, ushort[] del_ids) nothrow @nogc
{ {
@ -2051,11 +2058,11 @@ export struct EntityManager
} }
/************************************************************************************************************************ /************************************************************************************************************************
*Remove coponents from entity. Remove coponents from entity.
*
*Params: Params:
*Components = components types to remove Components = components types to remove
*entity_id = ID of entity entity_id = ID of entity
*/ */
void removeComponents(Components...)(EntityID entity_id) 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. Add components to entity. Components will be added on end of frame.
*
*Params: Params:
*entity_id = ID of entity to remove entity_id = ID of entity to remove
*comps = components to add comps = components to add
*/ */
void addComponents(Components...)(const EntityID entity_id, Components comps) nothrow @nogc void addComponents(Components...)(const EntityID entity_id, Components comps) nothrow @nogc
{ {
@ -2239,10 +2246,10 @@ export struct EntityManager
} }
/************************************************************************************************************************ /************************************************************************************************************************
*Free template memory. Free template memory.
*
*Params: Params:
*template_ = pointer entity template allocated by EntityManager. template_ = pointer entity template allocated by EntityManager.
*/ */
export void freeTemplate(EntityTemplate* template_) 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 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 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. instead of pointer.
* *
*Params: *Params:
*id = ID of entity to be copyied. *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 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. use you should save ID instead of pointer.
*
*Params: Params:
*tmpl = pointer entity template allocated by EntityManager. tmpl = pointer entity template allocated by EntityManager.
*/ */
export Entity* addEntity(EntityTemplate* tmpl) 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 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) private EntitiesBlock* findBlockWithFreeSpaceMT(EntityInfo* info)
{ {
@ -2427,10 +2434,10 @@ export struct EntityManager
} }
/************************************************************************************************************************ /************************************************************************************************************************
*Remove entity by ID. Entity will be removed on frame end. Remove entity by ID. Entity will be removed on frame end.
*
*Params: Params:
*id = id of entity to remove id = id of entity to remove
*/ */
export void removeEntity(EntityID id) export void removeEntity(EntityID id)
{ {
@ -2513,10 +2520,10 @@ export struct EntityManager
} }
/************************************************************************************************************************ /************************************************************************************************************************
*functions return MetaData of page. functions return MetaData of page.
*
*Params: Params:
*pointer = pointer to any data of entity (i.e. component data pointer) pointer = pointer to any data of entity (i.e. component data pointer)
*/ */
export EntitiesBlock* getMetaData(const void* pointer) nothrow @nogc 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() 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() export void end()
{ {
@ -2917,7 +2924,7 @@ export struct EntityManager
} }
/************************************************************************************************************************ /************************************************************************************************************************
*Component info; Component info;
*/ */
struct ComponentInfo struct ComponentInfo
{ {
@ -2961,7 +2968,7 @@ export struct EntityManager
} }
/************************************************************************************************************************ /************************************************************************************************************************
*Entity type info. Entity type info.
*/ */
struct EntityInfo 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 struct EntitiesBlock
{ {
@ -3180,10 +3187,10 @@ export struct EntityManager
} }
/************************************************************************************************************************ /************************************************************************************************************************
*Structure with data used to calling System calls. Structure with data used to calling System calls.
*
*<i>first_block</i>, <i>begin</i>, <i>end</i>, <i>blocks</i> parameters are used <i>first_block</i>, <i>begin</i>, <i>end</i>, <i>blocks</i> parameters are used
*to call partial info update to call partial info update
*/ */
struct CallData struct CallData
{ {

View file

@ -1,6 +1,9 @@
/************************************************************************************************************************ /************************************************************************************************************************
*It's internal code! It's internal code!
*This module contain implementation of standard functionality. This module contain implementation of standard functionality.
Copyright: Copyright © 2018-2019, Dawid Masiukiewicz, Michał Masiukiewicz
License: BSD 3-clause, see LICENSE file in project root folder.
*/ */
module ecs.std; module ecs.std;

View file

@ -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; module ecs.system;
@ -7,25 +10,27 @@ import ecs.entity;
import ecs.manager; import ecs.manager;
/************************************************************************************************************************ /************************************************************************************************************************
*System contain data required to proper glue EntityManager with Systems. System contain data required to proper glue EntityManager with Systems.
*System callbacks: System callbacks:
*<br/>-void onUpdate(EntitesData); $(LIST
*<br/>-void onEnable() * void onUpdate(EntitesData);
*<br/>-void onDisable(); * void onEnable()
*<br/>-bool onBegin(); * void onDisable();
*<br/>-void onEnd(); * bool onBegin();
*<br/>-void onCreate() * void onEnd();
*<br/>-void onDestroy(); * void onCreate()
*<br/>-void onAddEntity(EntitesData); * void onDestroy();
*<br/>-void onRemoveEntity(EntitiesData); * void onAddEntity(EntitesData);
*<br/>-void onChangeEntity(EntitiesData); * void onRemoveEntity(EntitiesData);
*<br/>-void handleEvent(Entity*, Event); * void onChangeEntity(EntitiesData);
* void handleEvent(Entity*, Event);
)
*/ */
struct System struct System
{ {
/************************************************************************************************************************ /************************************************************************************************************************
*Check if system is enabled. Check if system is enabled.
*/ */
export bool enabled() nothrow @nogc 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 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 export void disable() nothrow @nogc
{ {
@ -53,7 +58,7 @@ struct System
} }
/************************************************************************************************************************ /************************************************************************************************************************
*Get system priority. Get system priority.
*/ */
export int priority() nothrow @nogc export int priority() nothrow @nogc
{ {
@ -61,7 +66,7 @@ struct System
} }
/************************************************************************************************************************ /************************************************************************************************************************
*Get system priority. Get system priority.
*/ */
export bool execute() nothrow @nogc export bool execute() nothrow @nogc
{ {
@ -69,7 +74,7 @@ struct System
} }
/************************************************************************************************************************ /************************************************************************************************************************
*Get system priority. Get system priority.
*/ */
export ushort id() nothrow @nogc export ushort id() nothrow @nogc
{ {
@ -77,7 +82,7 @@ struct System
} }
/************************************************************************************************************************ /************************************************************************************************************************
*Get system name. Get system name.
*/ */
export const(char)[] name() nothrow @nogc export const(char)[] name() nothrow @nogc
{ {

View file

@ -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)() static long getIndexOfTypeInEntitiesData(EntitiesData, Type)()
{ {