Merge branch 'Demos' into 'master'

Demos

See merge request Mergul/bubel-ecs!8
This commit is contained in:
Dawid Masiukiewicz 2021-01-09 14:36:27 +00:00
commit 3f01b96b76
60 changed files with 7079 additions and 1187 deletions

1
.gitignore vendored
View file

@ -10,3 +10,4 @@
!meson.build !meson.build
!meson_options.txt !meson_options.txt
!compile_wasm.py !compile_wasm.py
!compile_android.py

78
compile_android.py Normal file
View file

@ -0,0 +1,78 @@
import os
import ntpath
import sys
def compile(sources, output):
files = []
# r=root, d=directories, f = files
for path in sources:
for r, d, f in os.walk(path):
for file in f:
if ntpath.basename(file) != 'win_dll.d':
filename, file_extension = os.path.splitext(file)
if file_extension == '.d' and filename != 'package':
files.append(os.path.join(r, file))
ldc_path = 'ldc'
if 'LDC' in os.environ:
ldc_path = os.environ['LDC']
ldc_cmd = ldc_path + ' ' + ldc_flags + '-lib -mtriple=armv7-none-linux-androideabi -fvisibility=hidden -betterC -oq -od=obj/ --singleobj --of=' + output + ' '
for path in sources:
ldc_cmd += '-I' + path + ' '
for path in import_paths:
ldc_cmd += '-I' + path + ' '
for f in files:
ldc_cmd += f + ' '
print(ldc_cmd)
if os.system(ldc_cmd):
exit(0)
print()
clean = 0
ldc_flags = ''
import_paths = ['source','tests']
build_tests = 0
for arg in sys.argv[1:]:
if(arg == '-release'):
ldc_flags += '-release '
elif(arg == '-enable-inlining'):
ldc_flags += '-enable-inlining '
elif(arg == '-O3'):
ldc_flags += '-O3 '
elif(arg == '-O2'):
ldc_flags += '-O2 '
elif(arg == '-O1'):
ldc_flags += '-O1 '
elif(arg == '-O0'):
ldc_flags += '-O0 '
elif(arg == '-Os'):
ldc_flags += '-Os '
elif(arg == '-Oz'):
ldc_flags += '-Oz '
elif(arg == '-g'):
ldc_flags += '-g '
elif(arg == '-opt'):
ldc_flags += '-release -enable-inlining -O3 '
else:
print('unknown argument: ' + arg)
exit()
compile(['source'], 'ecs.a')
#export LDC_LIBS=/path/to/your/ldc-build-runtime.tmp/lib/
CC = os.environ['NDK'] + '/toolchains/llvm/prebuilt/linux-x86_64/bin/clang'
TOOLCHAIN = os.environ['NDK'] + '/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86_64'
SYSROOT = os.environ['NDK'] + '/platforms/android-21/arch-arm'
LDC_LIBS = ''#os.environ['LDC_LIBS'] + '/libphobos2-ldc.a ' + os.environ['LDC_LIBS'] + '/libdruntime-ldc.a'
os.system(CC + ' -Wl,-soname,libecs.so -shared --sysroot=' + SYSROOT + ' obj/*.o ' + LDC_LIBS + ' -lgcc -gcc-toolchain ' + TOOLCHAIN +
' -no-canonical-prefixes -fuse-ld=bfd -target armv7-none-linux-androideabi -fvisibility=hidden \
-Wl,--gc-sections -Wl,--fix-cortex-a8 -Wl,--no-undefined -Wl,-z,noexecstack -Wl,-z,relro \
-Wl,-z,now -mthumb -o libecs.so')

2
demos/.gitignore vendored
View file

@ -14,4 +14,6 @@
!cimgui.bc !cimgui.bc
!emscripten_shell.html !emscripten_shell.html
!emscripten_multi_shell.html !emscripten_multi_shell.html
!compile_android.py
.dub .dub
Android

View file

@ -0,0 +1,55 @@
precision mediump int;
precision mediump float;
precision lowp sampler2D;
precision lowp samplerCube;
#ifdef GLES
#define TEX(x,y) texture2D(x,y)
#if __VERSION__ >290
#define M_IN in mediump
#define L_IN in lowp
#else
#define M_IN varying mediump
#define L_IN varying lowp
#endif
#else
#define TEX(x,y) texture(x,y)
#if __VERSION__ > 320
#define M_IN in
#define L_IN in
#else
#define M_IN varying
#define L_IN varying
#endif
#endif
M_IN vec2 uv;
M_IN vec4 color;
/*
#ifdef GLES
#if __VERSION__ >290
in mediump vec2 uv;
#else
varying mediump vec2 uv;
#endif
#else
#if __VERSION__ > 320
in vec2 uv;
#else
varying vec2 uv;
#endif
#endif*/
//layout(binding = 0)uniform sampler2D tex;
uniform sampler2D tex;
//layout(location = 0) out vec4 outColor;
void main()
{
gl_FragColor = /*TEX(tex,uv) **/ color;
if(gl_FragColor.a < 0.01)discard;
}

View file

@ -0,0 +1,106 @@
precision highp float;
precision highp int;
precision lowp sampler2D;
precision lowp samplerCube;
#ifdef GLES
#if __VERSION__ >290
#define LOC(x) layout(location = x)
#define ATT in
#define M_OUT out mediump
#define L_OUT out lowp
#else
#define LOC(x)
#define ATT attribute
#define M_OUT varying mediump
#define L_OUT varying lowp
#endif
#else
#if __VERSION__ > 320
#define LOC(x) layout(location = x)
#define ATT in
#define M_OUT out
#define L_OUT out
#else
#define LOC(x)
#define ATT attribute
#define M_OUT varying
#define L_OUT varying
#endif
#endif
/*
#ifdef GLES
#if __VERSION__ >290
uniform vec4 matrix_1;
uniform vec4 matrix_2;
uniform vec4 uv_transform;
layout(location = 0) in vec2 positions;
layout(location = 1) in vec2 tex_coords;
out mediump vec2 uv;
#else
uniform vec4 matrix_1;
uniform vec4 matrix_2;
uniform vec4 uv_transform;
attribute vec2 positions;
attribute vec2 tex_coords;
varying mediump vec2 uv;
#endif
#else
#if __VERSION__ > 320
uniform vec4 matrix_1;
uniform vec4 matrix_2;
uniform vec4 uv_transform;
layout(location = 0) in vec2 positions;
layout(location = 1) in vec2 tex_coords;
out vec2 uv;
#else
uniform vec4 matrix_1;
uniform vec4 matrix_2;
uniform vec4 uv_transform;
attribute vec2 positions;
attribute vec2 tex_coords;
varying vec2 uv;
#endif
#endif*/
#define VBO_BATCH 1
M_OUT vec2 uv;
L_OUT vec4 color;
LOC(0) ATT vec2 positions;
LOC(1) ATT vec2 tex_coords;
#ifdef VBO_BATCH
LOC(2) ATT float depth;
LOC(3) ATT vec4 vcolor;
#else
uniform vec4 matrix_1;
uniform vec4 matrix_2;
uniform vec4 uv_transform;
uniform vec4 vcolor;
float depth = matrix_2.z;
#endif
void main() {
#ifdef VBO_BATCH
vec3 position = vec3(positions*4.0,1.0);
uv = tex_coords;
#else
vec3 position = mat3(matrix_1.x,matrix_1.y,0,matrix_1.z,matrix_1.w,0,matrix_2.xy,1.0) * vec3(positions,1.0);
uv = tex_coords * uv_transform.zw + uv_transform.xy;
#endif
color = vcolor;
gl_Position = vec4(position.xy,depth,1.0);
}

View file

@ -0,0 +1,64 @@
precision mediump int;
precision mediump float;
precision lowp sampler2D;
precision lowp samplerCube;
#ifdef GLES
#define TEX(x,y) texture2D(x,y)
#if __VERSION__ >290
#define M_IN in mediump
#define L_IN in lowp
#else
#define M_IN varying mediump
#define L_IN varying lowp
#endif
#else
#define TEX(x,y) texture(x,y)
#if __VERSION__ > 320
#define M_IN in
#define L_IN in
#else
#define M_IN varying
#define L_IN varying
#endif
#endif
M_IN vec2 pos;
M_IN float edge;
//flat M_IN vec2 fpos;
//M_IN vec2 uv;
//M_IN vec4 color;
/*
#ifdef GLES
#if __VERSION__ >290
in mediump vec2 uv;
#else
varying mediump vec2 uv;
#endif
#else
#if __VERSION__ > 320
in vec2 uv;
#else
varying vec2 uv;
#endif
#endif*/
//layout(binding = 0)uniform sampler2D tex;
//uniform sampler2D tex;
//layout(location = 0) out vec4 outColor;
void main()
{
float len2 = dot(pos,pos);
if(len2 > 1.0)discard;
if(len2 > edge)gl_FragColor = vec4(0.4,0.8,1.0,0.8);//TEX(tex,uv) * color;
else gl_FragColor = vec4(0,0.6,1.0,0.35);//TEX(tex,uv) * color;
//gl_FragColor = vec4(pos,0,1);
//if(gl_FragColor.a < 0.01)discard;
}

View file

@ -0,0 +1,114 @@
precision highp float;
precision highp int;
precision lowp sampler2D;
precision lowp samplerCube;
#ifdef GLES
#if __VERSION__ >290
#define LOC(x) layout(location = x)
#define ATT in
#define M_OUT out mediump
#define L_OUT out lowp
#else
#define LOC(x)
#define ATT attribute
#define M_OUT varying mediump
#define L_OUT varying lowp
#endif
#else
#if __VERSION__ > 320
#define LOC(x) layout(location = x)
#define ATT in
#define M_OUT out
#define L_OUT out
#else
#define LOC(x)
#define ATT attribute
#define M_OUT varying
#define L_OUT varying
#endif
#endif
/*
#ifdef GLES
#if __VERSION__ >290
uniform vec4 matrix_1;
uniform vec4 matrix_2;
uniform vec4 uv_transform;
layout(location = 0) in vec2 positions;
layout(location = 1) in vec2 tex_coords;
out mediump vec2 uv;
#else
uniform vec4 matrix_1;
uniform vec4 matrix_2;
uniform vec4 uv_transform;
attribute vec2 positions;
attribute vec2 tex_coords;
varying mediump vec2 uv;
#endif
#else
#if __VERSION__ > 320
uniform vec4 matrix_1;
uniform vec4 matrix_2;
uniform vec4 uv_transform;
layout(location = 0) in vec2 positions;
layout(location = 1) in vec2 tex_coords;
out vec2 uv;
#else
uniform vec4 matrix_1;
uniform vec4 matrix_2;
uniform vec4 uv_transform;
attribute vec2 positions;
attribute vec2 tex_coords;
varying vec2 uv;
#endif
#endif*/
//#define VBO_BATCH 1
//M_OUT vec2 uv;
//L_OUT vec4 color;
M_OUT vec2 pos;
M_OUT float edge;
//flat M_OUT vec2 fpos;
LOC(0) ATT vec2 positions;
//LOC(1) ATT vec2 tex_coords;
#ifdef VBO_BATCH
LOC(2) ATT float depth;
LOC(3) ATT vec4 vcolor;
#else
uniform vec4 matrix_1;
uniform vec4 matrix_2;
//uniform vec4 uv_transform;
//uniform vec4 vcolor;
//float depth = matrix_2.z;
#endif
void main() {
//#ifdef VBO_BATCH
// vec3 position = vec3(positions*4.0,1.0);
// uv = tex_coords;
//#else
//edge = mix(0.1, 0.96, (matrix_2.z / 256));
edge = (matrix_1.w - matrix_2.z) / matrix_1.w;//matrix_2.z;//clamp((matrix_2,0.0,1.0);
edge *= edge;
pos = positions * 2.0;// / matrix_2.zw * 2;
//fpos = positions * matrix_2.xy;
vec3 position = mat3(matrix_1.x,matrix_1.y,0,matrix_1.z,matrix_1.w,0,matrix_2.xy,1.0) * vec3(positions,1.0);
// uv = tex_coords * uv_transform.zw + uv_transform.xy;
//#endif
//color = vcolor * 2.0;
gl_Position = vec4(position.xy,0,1.0);
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 41 KiB

After

Width:  |  Height:  |  Size: 36 KiB

Before After
Before After

91
demos/compile_android.py Normal file
View file

@ -0,0 +1,91 @@
import os
import ntpath
import sys
def compile(sources, output):
files = []
# r=root, d=directories, f = files
for path in sources:
for r, d, f in os.walk(path):
for file in f:
if ntpath.basename(file) != 'win_dll.d':
filename, file_extension = os.path.splitext(file)
if file_extension == '.d':
files.append(os.path.join(r, file))
ldc_path = 'ldc'
if 'LDC' in os.environ:
ldc_path = os.environ['LDC']
ldc_cmd = ldc_path + ' ' + ldc_flags + '-lib -mtriple=armv7-none-linux-androideabi -fvisibility=hidden -betterC -oq -od=obj/ --singleobj --of=' + output + ' '
for path in sources:
ldc_cmd += '-I' + path + ' '
for path in import_paths:
ldc_cmd += '-I' + path + ' '
for f in files:
ldc_cmd += f + ' '
print(ldc_cmd)
if os.system(ldc_cmd):
print('some kind of error')
exit(0)
print()
clean = 0
ldc_flags = '--d-version=SDL_209 --d-version=BindSDL_Image --d-version=MM_USE_POSIX_THREADS '
#import_paths = ['source','tests']
import_paths = ['external/android','external/sources', 'external/imports', 'external/wasm_imports', '../source', 'utils/source', 'simple/source']
build_tests = 0
for arg in sys.argv[1:]:
if(arg == '-release'):
ldc_flags += '-release '
elif(arg == '-enable-inlining'):
ldc_flags += '-enable-inlining '
elif(arg == '-O3'):
ldc_flags += '-O3 '
elif(arg == '-O2'):
ldc_flags += '-O2 '
elif(arg == '-O1'):
ldc_flags += '-O1 '
elif(arg == '-O0'):
ldc_flags += '-O0 '
elif(arg == '-Os'):
ldc_flags += '-Os '
elif(arg == '-Oz'):
ldc_flags += '-Oz '
elif(arg == '-g'):
ldc_flags += '-g '
elif(arg == '-opt'):
ldc_flags += '-release -enable-inlining -O3 '
else:
print('unknown argument: ' + arg)
exit()
#compile(['source'], 'ecs.a')
compile(['external/wasm_imports/bindbc/sdl'], 'build/bindbc-sdl.a')
compile(['utils/source'], 'build/utils.a')
compile(['external/sources/mmutils'], 'build/mmutils.a')
compile(['external/sources/glad'], 'build/glad.a')
compile(['external/android/bindbc'], 'build/bindbc.a')
compile(['source'], 'build/demo.a')
#compile(['external/wasm_imports/bindbc/sdl','utils/source','external/sources/mmutils','external/sources/glad'], 'build/asd.a')
#export LDC_LIBS=/path/to/your/ldc-build-runtime.tmp/lib/
CC = os.environ['NDK'] + '/toolchains/llvm/prebuilt/linux-x86_64/bin/clang'
TOOLCHAIN = os.environ['NDK'] + '/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86_64'
SYSROOT = os.environ['NDK'] + '/platforms/android-21/arch-arm'
#LDC_LIBS = os.environ['LDC_LIBS'] + '/libphobos2-ldc.a ' + os.environ['LDC_LIBS'] + '/libdruntime-ldc.a'
LDC_LIBS = ''
LIBS = '-L/platforms/android-21/arch-arm/usr/lib'
os.system(CC + ' -Wl,-soname,libdemos.so -shared --sysroot=' + SYSROOT + ' ../obj/*.o obj/*.o ' + LDC_LIBS + ' -lgcc -gcc-toolchain ' + TOOLCHAIN +
' -no-canonical-prefixes -fuse-ld=bfd -target armv7-none-linux-androideabi -fvisibility=hidden \
-Wl,--gc-sections -Wl,--fix-cortex-a8 -Wl,--no-undefined -Wl,-z,noexecstack -Wl,-z,relro \
-Wl,-z,now -mthumb -lm -lc -Llibs/armeabi-v7a -lcimgui -o libdemos.so')

View file

@ -19,7 +19,8 @@
"libs-linux-x86_64": ["cimgui","SDL2","SDL2_image"], "libs-linux-x86_64": ["cimgui","SDL2","SDL2_image"],
"lflags-linux-x86_64": ["-rpath=libs/linux/x64/","-Llibs/linux/x64/"], "lflags-linux-x86_64": ["-rpath=libs/linux/x64/","-Llibs/linux/x64/"],
"dflags-ldc" : [ "dflags-ldc" : [
"--ffast-math" "--ffast-math",
"-enable-cross-module-inlining"
], ],
"configurations" : [ "configurations" : [
{ {

View file

@ -0,0 +1,11 @@
// Copyright Michael D. Parker 2018.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
module bindbc.loader;
public
import bindbc.loader.sharedlib,
bindbc.loader.system;

View file

@ -0,0 +1,282 @@
// Copyright Michael D. Parker 2018.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
module bindbc.loader.sharedlib;
import core.stdc.stdlib;
import core.stdc.string;
/// Handle to a shared library
struct SharedLib {
private void* _handle;
}
/// Indicates an uninitialized or unassigned handle.
enum invalidHandle = SharedLib.init;
// Contains information about shared library and symbol load failures.
struct ErrorInfo {
private:
char[32] _error;
char[96] _message;
public @nogc nothrow @property:
/**
Returns the string "Missing Symbol" to indicate a symbol load failure, and
the name of a library to indicate a library load failure.
*/
const(char)* error() const { return _error.ptr; }
/**
Returns a symbol name for symbol load failures, and a system-specific error
message for library load failures.
*/
const(char)* message() const { return _message.ptr; }
}
private {
__gshared ErrorInfo[] _errors;
__gshared size_t _errorCount;
}
@nogc nothrow:
/**
Returns an slice containing all errors that have been accumulated by the
`load` and `bindSymbol` functions since the last call to `resetErrors`.
*/
const(ErrorInfo)[] errors()
{
return _errors[0 .. _errorCount];
}
/**
Returns the total number of errors that have been accumulated by the
`load` and `bindSymbol` functions since the last call to `resetErrors`.
*/
size_t errorCount()
{
return _errorCount;
}
/**
Sets the error count to 0 and erases all accumulated errors. This function
does not release any memory allocated for the error list.
*/
void resetErrors()
{
_errorCount = 0;
memset(_errors.ptr, 0, _errors.length * ErrorInfo.sizeof);
}
/*
void freeErrors()
{
free(_errors.ptr);
_errors.length = _errorCount = 0;
}
*/
/**
Loads a symbol from a shared library and assigns it to a caller-supplied pointer.
Params:
lib = a valid handle to a shared library loaded via the `load` function.
ptr = a pointer to a function or variable pointer whose declaration is
appropriate for the symbol being bound (it is up to the caller to
verify the types match).
symbolName = the name of the symbol to bind.
*/
void bindSymbol(SharedLib lib, void** ptr, const(char)* symbolName)
{
// Without this, DMD can hang in release builds
pragma(inline, false);
assert(lib._handle);
auto sym = loadSymbol(lib._handle, symbolName);
if(sym) {
*ptr = sym;
}
else {
addErr("Missing Symbol", symbolName);
}
}
/**
Formats a symbol using the Windows stdcall mangling if necessary before passing it on to
bindSymbol.
Params:
lib = a valid handle to a shared library loaded via the `load` function.
ptr = a pointer to a function or variable pointer whose declaration is
appropriate for the symbol being bound (it is up to the caller to
verify the types match).
symbolName = the name of the symbol to bind.
*/
void bindSymbol_stdcall(Func)(SharedLib lib, ref Func f, const(char)* symbolName)
{
import bindbc.loader.system : bindWindows, bind32;
static if(bindWindows && bind32) {
import core.stdc.stdio : snprintf;
import std.traits : ParameterTypeTuple;
uint paramSize(A...)(A args)
{
size_t sum = 0;
foreach(arg; args) {
sum += arg.sizeof;
// Align on 32-bit stack
if((sum & 3) != 0) {
sum += 4 - (sum & 3);
}
}
return sum;
}
ParameterTypeTuple!f params;
char[128] mangled;
snprintf(mangled.ptr, mangled.length, "_%s@%d", symbolName, paramSize(params));
symbolName = mangled.ptr;
}
bindSymbol(lib, cast(void**)&f, symbolName);
}
/**
Loads a shared library from disk, using the system-specific API and search rules.
libName = the name of the library to load. May include the full or relative
path for the file.
*/
SharedLib load(const(char)* libName)
{
auto handle = loadLib(libName);
if(handle) return SharedLib(handle);
else {
addErr(libName, null);
return invalidHandle;
}
}
/**
Unloads a shared library from process memory.
Generally, it is not necessary to call this function at program exit, as the system will ensure
any shared libraries loaded by the process will be unloaded then. However, any loaded shared
libraries that are no longer needed by the program during runtime, such as those that are part
of a "hot swap" mechanism, should be unloaded to free up resources.
*/
void unload(ref SharedLib lib) {
if(lib._handle) {
unloadLib(lib._handle);
lib = invalidHandle;
}
}
private:
void allocErrs() {
size_t newSize = _errorCount == 0 ? 16 : _errors.length * 2;
auto errs = cast(ErrorInfo*)malloc(ErrorInfo.sizeof * newSize);
if(!errs) exit(EXIT_FAILURE);
if(_errorCount > 0) {
memcpy(errs, _errors.ptr, ErrorInfo.sizeof * _errors.length);
free(_errors.ptr);
}
_errors = errs[0 .. newSize];
}
void addErr(const(char)* errstr, const(char)* message)
{
if(_errors.length == 0 || _errorCount >= _errors.length) {
allocErrs();
}
auto pinfo = &_errors[_errorCount];
strcpy(pinfo._error.ptr, errstr);
if(message) {
strncpy(pinfo._message.ptr, message, pinfo._message.length);
pinfo._message[pinfo._message.length - 1] = 0;
}
else {
sysError(pinfo._message.ptr, pinfo._message.length);
}
++_errorCount;
}
version(Windows)
{
import core.sys.windows.windows;
void* loadLib(const(char)* name)
{
return LoadLibraryA(name);
}
void unloadLib(void* lib)
{
FreeLibrary(lib);
}
void* loadSymbol(void* lib, const(char)* symbolName)
{
return GetProcAddress(lib, symbolName);
}
void sysError(char* buf, size_t len)
{
char* msgBuf;
enum uint langID = MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT);
FormatMessageA(
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
null,
GetLastError(),
langID,
cast(char*)&msgBuf,
0,
null
);
if(msgBuf) {
strncpy(buf, msgBuf, len);
buf[len - 1] = 0;
LocalFree(msgBuf);
}
else strncpy(buf, "Unknown Error\0", len);
}
}
else version(Posix) {
import core.sys.posix.dlfcn;
void* loadLib(const(char)* name)
{
return dlopen(name, RTLD_NOW);
}
void unloadLib(void* lib)
{
dlclose(lib);
}
void* loadSymbol(void* lib, const(char)* symbolName)
{
return dlsym(lib, symbolName);
}
void sysError(char* buf, size_t len)
{
const (char)* msg = dlerror();
strncpy(buf, msg != null ? msg : "Unknown Error", len);
buf[len - 1] = 0;
}
}
else static assert(0, "bindbc-loader is not implemented on this platform.");

View file

@ -0,0 +1,55 @@
// Copyright Michael D. Parker 2018.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
module bindbc.loader.system;
static if((void*).sizeof == 8) {
enum bind64 = true;
enum bind32 = false;
}
else {
enum bind64 = false;
enum bind32 = true;
}
version(Windows) enum bindWindows = true;
else enum bindWindows = false;
version(OSX) enum bindMac = true;
else enum bindMac = false;
version(linux) enum bindLinux = true;
else enum bindLinux = false;
version(Posix) enum bindPosix = true;
else enum bindPosix = false;
version(Android) enum bindAndroid = true;
else enum bindAndroid = false;
enum bindIOS = false;
enum bindWinRT = false;
version(FreeBSD) {
enum bindBSD = true;
enum bindFreeBSD = true;
enum bindOpenBSD = false;
}
else version(OpenBSD) {
enum bindBSD = true;
enum bindFreeBSD = false;
enum bindOpenBSD = true;
}
else version(BSD) {
enum bindBSD = true;
enum bindFreeBSD = false;
enum bindOpenBSD = false;
}
else {
enum bindBSD = false;
enum bindFreeBSD = false;
enum bindOpenBSD = false;
}

View file

@ -2,9 +2,17 @@
//based on imgui.h file version "1.73" from Dear ImGui https://github.com/ocornut/imgui //based on imgui.h file version "1.73" from Dear ImGui https://github.com/ocornut/imgui
module cimgui.cimgui; module cimgui.cimgui;
import core.stdc.stdarg; // import core.stdc.stdarg;
//import core.stdc.stdio; //import core.stdc.stdio;
version(WebAssembly)
{
alias va_list = char*;
pragma(LDC_va_start)
void va_start(T)(out va_list ap, ref T parmn) @nogc;
}
else import core.stdc.stdarg;
extern (C): extern (C):
//alias ImU64 = ulong; //alias ImU64 = ulong;

View file

@ -35,14 +35,14 @@ bool open_gl() @nogc {
return false; return false;
} else { } else {
version(OSX) { version(OSX) {
enum const(char)*[] NAMES = [ enum const(char)*[4] NAMES = [
"../Frameworks/OpenGL.framework/OpenGL", "../Frameworks/OpenGL.framework/OpenGL",
"/Library/Frameworks/OpenGL.framework/OpenGL", "/Library/Frameworks/OpenGL.framework/OpenGL",
"/System/Library/Frameworks/OpenGL.framework/OpenGL", "/System/Library/Frameworks/OpenGL.framework/OpenGL",
"/System/Library/Frameworks/OpenGL.framework/Versions/Current/OpenGL" "/System/Library/Frameworks/OpenGL.framework/Versions/Current/OpenGL"
]; ];
} else { } else {
enum const(char)*[] NAMES = ["libGL.so.1", "libGL.so"]; enum const(char)*[2] NAMES = ["libGL.so.1", "libGL.so"];
} }
foreach(name; NAMES) { foreach(name; NAMES) {

View file

@ -201,6 +201,21 @@ void instructionPause()
static assert(0); static assert(0);
} }
} }
else version (Android)
{
version(LDC)
{
import ldc.attributes;
@optStrategy("none")
static void nop()
{
int i;
i++;
}
nop();
}
else static assert(0);
}
else version(WebAssembly) else version(WebAssembly)
{ {
version(LDC) version(LDC)
@ -381,8 +396,8 @@ version (MM_USE_POSIX_THREADS)
void start(DG dg) void start(DG dg)
{ {
threadStart = dg; threadStart = dg;
int ok = pthread_create(&handle, null, &threadRunFunc, cast(void*)&this); int err = pthread_create(&handle, null, &threadRunFunc, cast(void*)&this);
if(!ok)handle = pthread_t(); if(err)handle = pthread_t();
//assert(ok == 0); //assert(ok == 0);
} }

View file

@ -6,7 +6,11 @@
module bindbc.sdl.bind.sdllog; module bindbc.sdl.bind.sdllog;
import core.stdc.stdarg : va_list; version(WebAssembly)
{
alias va_list = char*;
}
else import core.stdc.stdarg : va_list;
import bindbc.sdl.config; import bindbc.sdl.config;
enum SDL_MAX_LOG_MESSAGE = 4096; enum SDL_MAX_LOG_MESSAGE = 4096;

View file

@ -14,8 +14,8 @@ import bindbc.sdl.config,
bindbc.sdl.bind; bindbc.sdl.bind;
private { private {
SharedLib lib; __gshared SharedLib lib;
SDLSupport loadedVersion; __gshared SDLSupport loadedVersion;
} }
void unloadSDL() void unloadSDL()
@ -664,14 +664,14 @@ SDLSupport loadSDL(const(char)* libName)
lib.bindSymbol(cast(void**)&SDL_HasColorKey, "SDL_HasColorKey"); lib.bindSymbol(cast(void**)&SDL_HasColorKey, "SDL_HasColorKey");
lib.bindSymbol(cast(void**)&SDL_GetDisplayOrientation, "SDL_GetDisplayOrientation"); lib.bindSymbol(cast(void**)&SDL_GetDisplayOrientation, "SDL_GetDisplayOrientation");
version(linux) { version(Android) {
lib.bindSymbol(cast(void**)&SDL_LinuxSetThreadPriority, "SDL_LinuxSetThreadPriority");
}
else version(Android) {
lib.bindSymbol(cast(void**)&SDL_IsChromebook, "SDL_IsChromebook"); lib.bindSymbol(cast(void**)&SDL_IsChromebook, "SDL_IsChromebook");
lib.bindSymbol(cast(void**)&SDL_IsDeXMode, "SDL_IsDeXMode"); lib.bindSymbol(cast(void**)&SDL_IsDeXMode, "SDL_IsDeXMode");
lib.bindSymbol(cast(void**)&SDL_AndroidBackButton, "SDL_AndroidBackButton"); lib.bindSymbol(cast(void**)&SDL_AndroidBackButton, "SDL_AndroidBackButton");
} }
else version(linux) {
lib.bindSymbol(cast(void**)&SDL_LinuxSetThreadPriority, "SDL_LinuxSetThreadPriority");
}
if(errorCount() != errCount) return SDLSupport.badLibrary; if(errorCount() != errCount) return SDLSupport.badLibrary;
else loadedVersion = SDLSupport.sdl209; else loadedVersion = SDLSupport.sdl209;

View file

@ -229,8 +229,8 @@ else {
} }
private { private {
SharedLib lib; __gshared SharedLib lib;
SDLImageSupport loadedVersion; __gshared SDLImageSupport loadedVersion;
} }
void unloadSDLImage() void unloadSDLImage()

Binary file not shown.

View file

@ -4,10 +4,11 @@ import bindbc.sdl;
import cimgui.cimgui; import cimgui.cimgui;
import game_core.basic;
import game_core.job_updater; import game_core.job_updater;
import bubel.ecs.manager;
import bubel.ecs.core; import bubel.ecs.core;
import bubel.ecs.manager;
import bubel.ecs.std; import bubel.ecs.std;
import ecs_utils.gfx.renderer; import ecs_utils.gfx.renderer;
@ -21,6 +22,7 @@ import glad.gl.gles2;
import glad.gl.loader; import glad.gl.loader;
import gui.manager; import gui.manager;
import gui.tool_circle;
extern (C) : extern (C) :
@ -39,6 +41,16 @@ struct Mouse
bool left, right, middle; bool left, right, middle;
} }
struct DemoCallbacks
{
void function() register;
void function() initialize;
void function() deinitialize;
bool function() loop;
void function(SDL_Event*) event;
const (char)* tips;
}
struct Launcher struct Launcher
{ {
ECSJobUpdater* job_updater; ECSJobUpdater* job_updater;
@ -47,10 +59,10 @@ struct Launcher
SDL_Window* window; SDL_Window* window;
SDL_GLContext gl_context; SDL_GLContext gl_context;
EntityManager* manager; EntityManager* manager;
bool function() loop; /*bool function() loop;
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, bool) tool;
float scalling; float scalling;
ivec2 window_size = ivec2(1024,768); ivec2 window_size = ivec2(1024,768);
Renderer renderer; Renderer renderer;
@ -65,15 +77,20 @@ struct Launcher
vec2 render_position; vec2 render_position;
Tool used_tool; Tool used_tool;
int tool_size = 0; int tool_size = 100;
float tool_repeat = 0; float tool_repeat = 0;
float repeat_time = 0; float repeat_time = 0;
bool tool_show = true;
bool override_ = true;
bool tool_mode = true;
ToolCircle* tool_circle;
bool show_filtered;
bool swap_interval = true; bool swap_interval = true;
float windows_alpha = 0.75; float windows_alpha = 0.75;
const (char)* tips; //const (char)* tips;
bool show_stat_wnd = true; bool show_stat_wnd = true;
bool show_tips = true; bool show_tips = true;
@ -93,17 +110,19 @@ struct Launcher
float draw_time = 0; float draw_time = 0;
} }
void switchDemo(void function() start, bool function() loop, void function() end, void function(SDL_Event*) event, void function(vec2, Tool, int) tool, const (char)* tips) DemoCallbacks demo;
void switchDemo(DemoCallbacks callbacks)//void function() start, bool function() loop, void function() end, void function(SDL_Event*) event, const (char)* tips)
{ {
gui_manager.clear(); gui_manager.clear();
//launcher.ent //launcher.ent
if(this.end)this.end();
manager.begin(); manager.begin();
manager.update("clean"); manager.update("clean");
manager.end(); manager.end();
if(this.demo.deinitialize)this.demo.deinitialize();
foreach(ref system; manager.systems) foreach(ref system; manager.systems)
{ {
if(system.id != CountSystem.system_id && system.id != CleanSystem.system_id)system.disable(); if(system.id != CountSystem.system_id && system.id != CleanSystem.system_id)system.disable();
@ -112,12 +131,154 @@ struct Launcher
/*launcher.manager.getSystem(CountSystem.system_id).enable(); /*launcher.manager.getSystem(CountSystem.system_id).enable();
launcher.manager.getSystem(CleanSystem.system_id).enable();//*/ launcher.manager.getSystem(CleanSystem.system_id).enable();//*/
if(start)start(); if(callbacks.register)callbacks.register();
this.loop = loop; if(callbacks.initialize)callbacks.initialize();
demo = callbacks;
/*this.loop = loop;
this.end = end; this.end = end;
this.event = event; this.event = event;
this.tips = tips; this.tips = tips;*/
this.tool = tool; //this.tool = tool;
}
bool filterEntity(ref const Entity entity)
{
EntityMeta meta = entity.getMeta();
foreach(id;gui_manager.filter_list)
{
if(!meta.hasComponent(id))return false;
}
if(used_tool == Tool.component_manipulator)
{
if(!meta.hasComponent(gui_manager.getSelectedComponent().component_id))return false;
}
return true;
}
void processTool(vec2 position, bool mode)
{
static struct Iterator
{
float size2;
vec2 position;
ComponentRef[] add_comps;
ushort[] rem_comps;
ushort[] filter;
bool filterEntity(ref const Entity entity)
{
EntityMeta meta = entity.getMeta();
foreach(id;filter)
{
if(!meta.hasComponent(id))return false;
}
return true;
}
void removeEntity(IteratorSystem.EntitiesData data)
{
if(!filterEntity(data.entity[0]))return;
foreach(i;0..data.length)
{
vec2 rel_vec = data.location[i] - position;
float length = rel_vec.x * rel_vec.x + rel_vec.y * rel_vec.y;
if(length < size2)gEM.removeEntity(data.entity[i].id);
}
}
void addComponent(IteratorSystem.EntitiesData data)
{
if(!filterEntity(data.entity[0]))return;
foreach(i;0..data.length)
{
vec2 rel_vec = data.location[i] - position;
float length = rel_vec.x * rel_vec.x + rel_vec.y * rel_vec.y;
if(length < size2)gEM.addComponents(data.entity[i].id, add_comps);
}
}
void overrideComponent(IteratorSystem.EntitiesData data)
{
if(!filterEntity(data.entity[0]))return;
foreach(i;0..data.length)
{
vec2 rel_vec = data.location[i] - position;
float length = rel_vec.x * rel_vec.x + rel_vec.y * rel_vec.y;
if(length < size2)
{
gEM.removeComponents(data.entity[i].id, rem_comps);
gEM.addComponents(data.entity[i].id, add_comps);
}
}
}
void removeComponent(IteratorSystem.EntitiesData data)
{
if(!filterEntity(data.entity[0]))return;
foreach(i;0..data.length)
{
vec2 rel_vec = data.location[i] - position;
float length = rel_vec.x * rel_vec.x + rel_vec.y * rel_vec.y;
if(length < size2)gEM.removeComponents(data.entity[i].id, rem_comps);
}
}
}
float half_size = tool_size * 0.5;
float size2 = half_size * half_size;
Iterator iterator;
iterator.size2 = size2;
iterator.position = position;
iterator.filter = gui_manager.filter_list[];
switch(used_tool)
{
case Tool.entity_spawner:
if(mode)
{
if(gui_manager.templates.length == 0)return;
EntityTemplate* tmpl = gui_manager.getSelectedTemplate();
CLocation* location = tmpl.getComponent!CLocation;
if(location)
{
position += randomCircularSample() * half_size;
//if(position.y < 16)position.y = 16;
//else if(position.y > 299)position.y = 299;
*location = position;
}
manager.addEntity(tmpl);
}
else
{
manager.callEntitiesFunction!IteratorSystem(&iterator.removeEntity);
}
break;
case Tool.component_manipulator:
{
if(gui_manager.components.length == 0)return;
if(mode)
{
ComponentRef[1] comps = [gui_manager.getSelectedComponent()];
iterator.add_comps = comps;
if(launcher.override_)
{
ushort[1] rcomps = [gui_manager.getSelectedComponent().component_id];
iterator.rem_comps = rcomps;
manager.callEntitiesFunction!IteratorSystem(&iterator.overrideComponent);
}
else manager.callEntitiesFunction!IteratorSystem(&iterator.addComponent);
}
else
{
ushort[1] comps = [gui_manager.getSelectedComponent().component_id];
iterator.rem_comps = comps;
manager.callEntitiesFunction!IteratorSystem(&iterator.removeComponent);
}
}
break;
default:
break;
}
} }
bool getKeyState(SDL_Scancode key) bool getKeyState(SDL_Scancode key)
@ -184,6 +345,28 @@ struct CleanSystem
} }
} }
struct IteratorSystem
{
mixin ECS.System!1;
struct EntitiesData
{
uint length;
const (Entity)[] entity;
CLocation[] location;
}
bool onBegin()
{
return false;
}
void onUpdate(EntitiesData)
{
}
}
void mainLoop(void* arg) void mainLoop(void* arg)
{ {
__gshared double time = 0; __gshared double time = 0;
@ -203,18 +386,43 @@ void mainLoop(void* arg)
temp_fps = 0; temp_fps = 0;
} }
SDL_Event event; SDL_Event event;
while (SDL_PollEvent(&event)) while (SDL_PollEvent(&event))
{ {
version(WebAssembly)ImGui_ImplSDL2_ProcessEvent(&event); ImGui_ImplSDL2_ProcessEvent(&event);
else ImGui_ImplSDL2_ProcessEvent(&event); if(launcher.demo.event)launcher.demo.event(&event);
if(launcher.event)launcher.event(&event);
if (event.type == SDL_QUIT || (event.type == SDL_KEYDOWN && event.key.keysym.scancode == SDL_SCANCODE_ESCAPE)) { if (event.type == SDL_QUIT || (event.type == SDL_KEYDOWN && event.key.keysym.scancode == SDL_SCANCODE_ESCAPE)) {
quit(); quit();
*cast(bool*)arg = false; *cast(bool*)arg = false;
return; return;
} }
else if(event.type == SDL_KEYDOWN)
{
if(event.key.state)
{
if(SDL_GetModState() & KMOD_CTRL)
{
switch(event.key.keysym.scancode)
{
case SDL_SCANCODE_1:launcher.used_tool=Tool.entity_spawner;break;
case SDL_SCANCODE_2:launcher.used_tool=Tool.component_manipulator;break;
case SDL_SCANCODE_3:launcher.used_tool=Tool.selector;break;
default:break;
}
}
else
{
switch(event.key.keysym.scancode)
{
case SDL_SCANCODE_1:break;
case SDL_SCANCODE_2:break;
case SDL_SCANCODE_3:break;
case SDL_SCANCODE_4:break;
default:break;
}
}
}
}
else if(event.type == SDL_WINDOWEVENT) else if(event.type == SDL_WINDOWEVENT)
{ {
switch(event.window.event) switch(event.window.event)
@ -239,9 +447,12 @@ void mainLoop(void* arg)
case SDL_BUTTON_MIDDLE:launcher.mouse.middle = true;break; case SDL_BUTTON_MIDDLE:launcher.mouse.middle = true;break;
default:break; default:break;
} }
if(launcher.tool && event.button.button == SDL_BUTTON_LEFT && launcher.tool_repeat == 0 && !igIsWindowHovered(ImGuiHoveredFlags_AnyWindow)) if(!igIsAnyItemHovered())igSetWindowFocus();
if(!igIsWindowHovered(ImGuiHoveredFlags_AnyWindow) && !igIsWindowFocused(ImGuiFocusedFlags_AnyWindow))
{ {
launcher.tool(vec2(event.button.x, launcher.window_size.y - event.button.y) * launcher.scalling - launcher.render_position, launcher.used_tool, launcher.tool_size); launcher.repeat_time = 0;
if(event.button.button == SDL_BUTTON_LEFT)launcher.processTool(vec2(event.button.x, launcher.window_size.y - event.button.y) * launcher.scalling - launcher.render_position,launcher.tool_mode);
else if(event.button.button == SDL_BUTTON_RIGHT)launcher.processTool(vec2(event.button.x, launcher.window_size.y - event.button.y) * launcher.scalling - launcher.render_position,!launcher.tool_mode);
} }
} }
else if(event.type == SDL_MOUSEBUTTONUP) else if(event.type == SDL_MOUSEBUTTONUP)
@ -257,17 +468,67 @@ void mainLoop(void* arg)
else if(event.type == SDL_MOUSEMOTION) else if(event.type == SDL_MOUSEMOTION)
{ {
launcher.mouse.position = vec2(event.motion.x, launcher.window_size.y - event.motion.y); launcher.mouse.position = vec2(event.motion.x, launcher.window_size.y - event.motion.y);
}else if(event.type == SDL_MOUSEWHEEL)
{
if(!igIsAnyItemHovered() && !igIsWindowHovered(ImGuiHoveredFlags_AnyWindow))
{
if(SDL_GetModState() & KMOD_CTRL)
{
float sign = 1;
if(event.wheel.y < 0)sign = -1;
float val = /*sign * event.wheel.y */ launcher.tool_repeat * 0.25;
if(val < 0.1)val = 0.1;
launcher.tool_repeat -= sign * val;
if(launcher.tool_repeat < 0)launcher.tool_repeat = 0;
else if(launcher.tool_repeat > 1000)launcher.tool_repeat = 1000;
}
else if(SDL_GetModState() & KMOD_SHIFT)
{
int sign = 1;
if(event.wheel.y < 0)sign = -1;
switch(launcher.used_tool)
{
case Tool.entity_spawner:
launcher.gui_manager.selectTemplate(launcher.gui_manager.selected_template-sign);
break;
case Tool.component_manipulator:
launcher.gui_manager.selectComponent(launcher.gui_manager.selected_component-sign);
break;
default:break;
}
}
else
{
int sign = 1;
if(event.wheel.y < 0)sign = -1;
int val = /*sign * event.wheel.y */ launcher.tool_size / 4;
if(val < 1)val = 1;
launcher.tool_size -= sign * val;
if(launcher.tool_size < 1)launcher.tool_size = 1;
else if(launcher.tool_size > 256)launcher.tool_size = 256;
}
}
} }
} }
if(launcher.tool && launcher.tool_repeat != 0 && launcher.mouse.left && !igIsWindowHovered(ImGuiHoveredFlags_AnyWindow) && !igIsWindowFocused(ImGuiFocusedFlags_AnyWindow)) if(launcher.tool_repeat != 0 && (launcher.mouse.left || launcher.mouse.right) && !igIsWindowHovered(ImGuiHoveredFlags_AnyWindow) && !igIsWindowFocused(ImGuiFocusedFlags_AnyWindow))
{ {
bool mode = launcher.tool_mode;
if(launcher.mouse.right)mode = !mode;
float range = 500.0 / cast(float)launcher.tool_repeat; float range = 500.0 / cast(float)launcher.tool_repeat;
launcher.repeat_time += launcher.delta_time; launcher.repeat_time += launcher.delta_time;
while(launcher.repeat_time > range) if(launcher.used_tool != Tool.entity_spawner || !mode)
{ {
launcher.repeat_time -= range; if(launcher.repeat_time > range)launcher.processTool((launcher.mouse.position*launcher.scalling)-launcher.render_position, mode);
launcher.tool((launcher.mouse.position*launcher.scalling)-launcher.render_position, launcher.used_tool, launcher.tool_size); while(launcher.repeat_time > range)launcher.repeat_time -= range;
}
else
{
while(launcher.repeat_time > range)
{
launcher.repeat_time -= range;
launcher.processTool((launcher.mouse.position*launcher.scalling)-launcher.render_position, mode);
}
} }
} }
@ -278,7 +539,8 @@ void mainLoop(void* arg)
} }
else else
{ {
ImGuiImplOpenGL2NewFrame(); //ImGuiImplOpenGL2NewFrame();
ImGui_ImplOpenGL3_NewFrame();
ImGuiImplSDL2NewFrame(launcher.window); ImGuiImplSDL2NewFrame(launcher.window);
} }
@ -301,17 +563,32 @@ void mainLoop(void* arg)
if(igMenuItemBool("Simpe",null,false,true)) if(igMenuItemBool("Simpe",null,false,true))
{ {
import demos.simple; import demos.simple;
launcher.switchDemo(&simpleStart,&simpleLoop,&simpleEnd,&simpleEvent,&simpleTool,Simple.tips); launcher.switchDemo(getSimpleDemo());//&simpleStart,&simpleLoop,&simpleEnd,&simpleEvent,Simple.tips);
} }
if(igMenuItemBool("Snake",null,false,true)) if(igMenuItemBool("Snake",null,false,true))
{ {
import demos.snake; import demos.snake;
launcher.switchDemo(&snakeStart,&snakeLoop,&snakeEnd,&snakeEvent,&snakeTool,Snake.tips); launcher.switchDemo(getSnakeDemo());//&snakeStart,&snakeLoop,&snakeEnd,&snakeEvent,Snake.tips);
} }
if(igMenuItemBool("Space invaders",null,false,true)) if(igMenuItemBool("Space Invaders",null,false,true))
{ {
import demos.space_invaders; import demos.space_invaders;
launcher.switchDemo(&spaceInvadersStart,&spaceInvadersLoop,&spaceInvadersEnd,&spaceInvadersEvent,&spaceInvadersTool,SpaceInvaders.tips); launcher.switchDemo(getSpaceInvadersDemo());//&spaceInvadersStart,&spaceInvadersLoop,&spaceInvadersEnd,&spaceInvadersEvent,SpaceInvaders.tips);
}
if(igMenuItemBool("Particles",null,false,true))
{
import demos.particles;
launcher.switchDemo(getParticlesDemo());//&particlesStart,&particlesLoop,&particlesEnd,&particlesEvent,ParticlesDemo.tips);
}
if(igMenuItemBool("Brick Breaker",null,false,true))
{
import demos.brick_breaker;
launcher.switchDemo(getBrickBreakerDemo());//&particlesStart,&particlesLoop,&particlesEnd,&particlesEvent,ParticlesDemo.tips);
}
if(igMenuItemBool("Sandbox",null,false,true))
{
import demos.sandbox;
launcher.switchDemo(getSanboxDemo());//&particlesStart,&particlesLoop,&particlesEnd,&particlesEvent,ParticlesDemo.tips);
} }
igEndMenu(); igEndMenu();
} }
@ -344,22 +621,11 @@ void mainLoop(void* arg)
} }
if(igBeginMenu("Show",true)) if(igBeginMenu("Show",true))
{ {
if(igMenuItemBool("Statistics",null,launcher.show_stat_wnd,true)) igMenuItemBoolPtr("Statistics",null,&launcher.show_stat_wnd,true);
{ igMenuItemBoolPtr("Demo",null,&launcher.show_demo_wnd,true);
launcher.show_stat_wnd = !launcher.show_stat_wnd; igMenuItemBoolPtr("Tips",null,&launcher.show_tips,true);
} igMenuItemBoolPtr("Virual keys",null,&launcher.show_virtual_keys_wnd,true);
else if(igMenuItemBool("Demo",null,launcher.show_demo_wnd,true)) igMenuItemBoolPtr("Profile",null,&launcher.show_profile_wnd,true);
{
launcher.show_demo_wnd = !launcher.show_demo_wnd;
}
else if(igMenuItemBool("Tips",null,launcher.show_tips,true))
{
launcher.show_tips = !launcher.show_tips;
}
else if(igMenuItemBool("Virual keys",null,launcher.show_virtual_keys_wnd,true))
{
launcher.show_virtual_keys_wnd = !launcher.show_virtual_keys_wnd;
}
igEndMenu(); igEndMenu();
} }
if(igBeginMenu("Style",true)) if(igBeginMenu("Style",true))
@ -456,7 +722,7 @@ void mainLoop(void* arg)
igSetNextWindowBgAlpha(launcher.windows_alpha); igSetNextWindowBgAlpha(launcher.windows_alpha);
if(igBegin("Tips",&launcher.show_tips,ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoSavedSettings)) if(igBegin("Tips",&launcher.show_tips,ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoSavedSettings))
{ {
igTextWrapped(launcher.tips); igTextWrapped(launcher.demo.tips);
} }
igEnd(); igEnd();
} }
@ -464,20 +730,22 @@ void mainLoop(void* arg)
if(launcher.show_demo_wnd) if(launcher.show_demo_wnd)
{ {
igSetNextWindowPos(ImVec2(launcher.window_size.x - 260, 30), ImGuiCond_Once, ImVec2(0,0)); igSetNextWindowPos(ImVec2(launcher.window_size.x - 260, 30), ImGuiCond_Once, ImVec2(0,0));
igSetNextWindowSize(ImVec2(250, 500), ImGuiCond_Once); igSetNextWindowSize(ImVec2(250, launcher.window_size.y - 60), ImGuiCond_Once);
if(igBegin("Demo",&launcher.show_demo_wnd,0)) if(igBegin("Demo",&launcher.show_demo_wnd,0))
{ {
ImDrawList* draw_list = igGetWindowDrawList(); ImDrawList* draw_list = igGetWindowDrawList();
//igBeginGroup(); igBeginGroup();
launcher.gui_manager.gui(); launcher.gui_manager.gui();
//igEndGroup(); igEndGroup();
ImDrawList_AddRect(draw_list, igGetItemRectMin(), ImVec2(igGetWindowPos().x+igGetWindowWidth()-2,igGetItemRectMax().y), igColorConvertFloat4ToU32(ImVec4(0.4,0.4,0.4,0.4)), 4, ImDrawCornerFlags_All, 1);
//ImDrawList_AddRect(draw_list, igGetItemRectMin(), igGetItemRectMax(), igColorConvertFloat4ToU32(ImVec4(0.4,0.4,0.4,0.4)), -1, 0, 1); //ImDrawList_AddRect(draw_list, igGetItemRectMin(), igGetItemRectMax(), igColorConvertFloat4ToU32(ImVec4(0.4,0.4,0.4,0.4)), -1, 0, 1);
//igBeginChildFrame(1,ImVec2(0,-1),ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_ChildWindow); //igBeginChildFrame(1,ImVec2(0,-1),ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_ChildWindow);
//igBeginChild("Tool frame",ImVec2(-1,-1),true,0); //igBeginChild("Tool frame",ImVec2(-1,-1),true,0);
if(igCollapsingHeader("Tool##ToolHeader", ImGuiTreeNodeFlags_SpanAvailWidth)) igBeginGroup();
if(igCollapsingHeader("Tool##ToolHeader", ImGuiTreeNodeFlags_SpanAvailWidth | ImGuiTreeNodeFlags_DefaultOpen))
{ {
igIndent(8); igIndent(8);
igBeginGroup();
if(igBeginCombo("Tool",tool_strings[launcher.used_tool],0)) if(igBeginCombo("Tool",tool_strings[launcher.used_tool],0))
{ {
if(igSelectable("Entity spawner",false,0,ImVec2(0,0))) if(igSelectable("Entity spawner",false,0,ImVec2(0,0)))
@ -494,14 +762,44 @@ void mainLoop(void* arg)
} }
igEndCombo(); igEndCombo();
} }
if(igIsItemHovered(0))igSetTooltip("Select tool (CTRL + 1,2,3)");
igCheckbox("Show Tool", &launcher.tool_show);
if(igIsItemHovered(0))igSetTooltip("Show/hide graphical tool representation");
igSameLine(0,4);
igCheckbox("Show Filtered", &launcher.show_filtered);
if(igIsItemHovered(0))igSetTooltip("Show/hide filtered entities");
if(launcher.used_tool == Tool.component_manipulator)
{
igCheckbox("Override", &launcher.override_);
}
//igSelectable("Selectabe",false,ImGuiSelectableFlags_None,ImVec2(0,0));
if(launcher.used_tool != Tool.selector)
{
if(igRadioButtonBool("Add", launcher.tool_mode))launcher.tool_mode = true;
if(igIsItemHovered(0))igSetTooltip("Tool should adding (Entities or components)");
igSameLine(0,4);
if(igRadioButtonBool("Remove", !launcher.tool_mode))launcher.tool_mode = false;
if(igIsItemHovered(0))igSetTooltip("Tool should removing (Entities or components)");
}
igSliderInt("Tool size", &launcher.tool_size, 0, 256, null); igSliderInt("Tool size", &launcher.tool_size, 0, 256, null);
igSliderFloat("Tool repeat", &launcher.tool_repeat, 0, 1024, null, 4); igSliderFloat("Tool repeat", &launcher.tool_repeat, 0, 1024, null, 4);
launcher.gui_manager.toolGui(); launcher.gui_manager.toolGui();
igEndGroup();
ImDrawList_AddRect(draw_list, igGetItemRectMin(), igGetItemRectMax(), igColorConvertFloat4ToU32(ImVec4(0.4,0.4,0.4,0.4)), 4, ImDrawCornerFlags_All, 1);
igUnindent(8); igUnindent(8);
} }
igEndGroup();
ImDrawList_AddRect(draw_list, igGetItemRectMin(), ImVec2(igGetWindowPos().x+igGetWindowWidth()-2,igGetItemRectMax().y), igColorConvertFloat4ToU32(ImVec4(0.4,0.4,0.4,0.4)), 2, ImDrawCornerFlags_All, 1);
//igBeginGroup();
if(igCollapsingHeader("Filter", ImGuiTreeNodeFlags_SpanAvailWidth))
{
igIndent(8);
launcher.gui_manager.filterGUI();
igUnindent(8);
}
//igEndGroup();
//ImDrawList_AddRect(draw_list, igGetItemRectMin(), ImVec2(igGetWindowPos().x+igGetWindowWidth()-2,igGetItemRectMax().y), igColorConvertFloat4ToU32(ImVec4(0.4,0.4,0.4,0.4)), 2, ImDrawCornerFlags_All, 1);
//igEndChild(); //igEndChild();
//igEndChildFrame(); //igEndChildFrame();
@ -517,7 +815,8 @@ void mainLoop(void* arg)
if(launcher.show_profile_wnd) if(launcher.show_profile_wnd)
{ {
igSetNextWindowPos(ImVec2(launcher.window_size.x - 260, launcher.window_size.y - 280), ImGuiCond_Once, ImVec2(0,0)); //igSetNextWindowPos(ImVec2(launcher.window_size.x - 260, launcher.window_size.y - 280), ImGuiCond_Once, ImVec2(0,0));
igSetNextWindowPos(ImVec2(8, launcher.window_size.y - 258), ImGuiCond_Once, ImVec2(0,0));
igSetNextWindowSize(ImVec2(250, 250), ImGuiCond_Once); igSetNextWindowSize(ImVec2(250, 250), ImGuiCond_Once);
if(igBegin("Profile",&launcher.show_profile_wnd,0)) if(igBegin("Profile",&launcher.show_profile_wnd,0))
{ {
@ -565,7 +864,7 @@ void mainLoop(void* arg)
double loop_time = launcher.getTime(); double loop_time = launcher.getTime();
launcher.job_updater.pool.tryWaitCount = 10000; launcher.job_updater.pool.tryWaitCount = 10000;
if(launcher.loop && !launcher.loop()) if(launcher.demo.loop && !launcher.demo.loop())
{ {
quit(); quit();
*cast(bool*)arg = false; *cast(bool*)arg = false;
@ -578,6 +877,8 @@ void mainLoop(void* arg)
launcher.renderer.present(); launcher.renderer.present();
draw_time = launcher.getTime() - draw_time; draw_time = launcher.getTime() - draw_time;
if(launcher.tool_show)launcher.tool_circle.draw(&launcher.renderer, (launcher.mouse.position*launcher.scalling)-launcher.render_position, cast(float)launcher.tool_size, launcher.renderer.view_size.y*6*launcher.scalling);
__gshared float plot_time = 0; __gshared float plot_time = 0;
__gshared uint plot_samples = 0; __gshared uint plot_samples = 0;
plot_time += launcher.delta_time; plot_time += launcher.delta_time;
@ -632,7 +933,9 @@ void mainLoop(void* arg)
igRender(); igRender();
version(WebAssembly)ImGui_ImplOpenGL3_RenderDrawData(igGetDrawData()); version(WebAssembly)ImGui_ImplOpenGL3_RenderDrawData(igGetDrawData());
else ImGuiImplOpenGL2RenderDrawData(igGetDrawData()); else version(Android)ImGui_ImplOpenGL3_RenderDrawData(igGetDrawData());
else ImGui_ImplOpenGL3_RenderDrawData(igGetDrawData());
//ImGuiImplOpenGL2RenderDrawData(igGetDrawData());
//launcher.renderer.clear(); //launcher.renderer.clear();
//launcher.renderer.present(); //launcher.renderer.present();
@ -643,24 +946,64 @@ void mainLoop(void* arg)
void quit() void quit()
{ {
import game_core.rendering : TexCoordsManager;
launcher.gui_manager.clear(); launcher.gui_manager.clear();
Mallocator.dispose(launcher.gui_manager); Mallocator.dispose(launcher.gui_manager);
if(launcher.demo.deinitialize)launcher.demo.deinitialize();
launcher.manager.destroy(); launcher.manager.destroy();
launcher.manager = null; launcher.manager = null;
TexCoordsManager.destroy();
SDL_Quit();
version(WebAssembly)emscripten_cancel_main_loop(); version(WebAssembly)emscripten_cancel_main_loop();
} }
int main(int argc, char** argv) version(Android)
{ {
export extern (C) int SDL_main(int argc, char** args)
{
return app_main(argc,args);
}
import ldc.attributes;
extern (C) __gshared
{
@section(".tdata")
int _tlsstart = 0;
@section(".tcommon")
int _tlsend = 0;
}
}
else
{
extern (C) int main(int argc, char** argv)
{
return app_main(argc,argv);
}
}
int app_main(int argc, char** argv)
//int main(int argc, char** argv)
{
version(BindSDL_Static){}
else
{
loadSDL();
loadSDLImage();
}
if (SDL_Init(SDL_INIT_VIDEO) < 0) if (SDL_Init(SDL_INIT_VIDEO) < 0)
{ {
printf("SDL could not initialize! SDL_Error: %s", SDL_GetError()); printf("SDL could not initialize! SDL_Error: %s", SDL_GetError());
return -1; return -1;
} }
SDL_version sdl_version; SDL_version sdl_version;
SDL_GetVersion(&sdl_version); SDL_GetVersion(&sdl_version);
printf("SDL version: %u.%u.%u\n",cast(uint)sdl_version.major,cast(uint)sdl_version.minor,cast(uint)sdl_version.patch); printf("SDL version: %u.%u.%u\n",cast(uint)sdl_version.major,cast(uint)sdl_version.minor,cast(uint)sdl_version.patch);
@ -669,6 +1012,7 @@ int main(int argc, char** argv)
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0); SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0);
launcher.window = SDL_CreateWindow("Simple", SDL_WINDOWPOS_CENTERED, launcher.window = SDL_CreateWindow("Simple", SDL_WINDOWPOS_CENTERED,
SDL_WINDOWPOS_CENTERED, launcher.window_size.x, launcher.window_size.y, SDL_WINDOW_SHOWN | SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE); SDL_WINDOWPOS_CENTERED, launcher.window_size.x, launcher.window_size.y, SDL_WINDOW_SHOWN | SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE);
SDL_MaximizeWindow(launcher.window);
launcher.gl_context = SDL_GL_CreateContext(launcher.window); launcher.gl_context = SDL_GL_CreateContext(launcher.window);
launcher.context = igCreateContext(null); launcher.context = igCreateContext(null);
@ -692,6 +1036,21 @@ int main(int argc, char** argv)
return -3; return -3;
} }
} }
else version(Android)
{
//gladLoadGL();
gladLoadGLES2(x => SDL_GL_GetProcAddress(x));
if(!ImGuiImplSDL2InitForOpenGL(launcher.window,launcher.gl_context))
{
printf("ImGui initialization failed!");
return -2;
}
if(!ImGui_ImplOpenGL3_Init("#version 100"))
{
printf("ImGui OpenGL initialization failed!");
return -3;
}
}
else else
{ {
gladLoadGL(); gladLoadGL();
@ -700,17 +1059,19 @@ int main(int argc, char** argv)
printf("ImGui initialization failed!"); printf("ImGui initialization failed!");
return -2; return -2;
} }
if(!ImGuiImplOpenGL2Init()) //if(!ImGuiImplOpenGL2Init())
if(!ImGui_ImplOpenGL3_Init("#version 120"))
{ {
printf("ImGui OpenGL initialization failed!"); printf("ImGui OpenGL initialization failed!");
return -3; return -3;
} }
} }
ImFontConfig* config = ImFontConfig_ImFontConfig(); //ImFontConfig* config = ImFontConfig_ImFontConfig();
ImGuiIO* io = igGetIO(); ImGuiIO* io = igGetIO();
const ushort* font_ranges = ImFontAtlas_GetGlyphRangesDefault(io.Fonts); const ushort* font_ranges = ImFontAtlas_GetGlyphRangesDefault(io.Fonts);
ImFontAtlas_AddFontFromFileTTF(io.Fonts,"assets/fonts/Ruda-Bold.ttf", 15.0f, config, font_ranges); ImFontAtlas_AddFontFromFileTTF(io.Fonts,"assets/fonts/Ruda-Bold.ttf", 15.0f, null, font_ranges);
//ImFontConfig_destroy(config);
setStyle(3); setStyle(3);
@ -728,14 +1089,19 @@ int main(int argc, char** argv)
launcher.manager.registerPass("clean"); launcher.manager.registerPass("clean");
launcher.manager.registerComponent!CLocation;
launcher.manager.registerSystem!CountSystem(10000); launcher.manager.registerSystem!CountSystem(10000);
launcher.manager.registerSystem!CleanSystem(0,"clean"); launcher.manager.registerSystem!CleanSystem(0,"clean");
launcher.manager.registerSystem!IteratorSystem(0,"clean");
launcher.manager.endRegister(); launcher.manager.endRegister();
loadGFX(); loadGFX();
launcher.renderer.initialize(); launcher.renderer.initialize();
import game_core.rendering : TexCoordsManager;
TexCoordsManager.initialize();
import mmutils.thread_pool : ThreadPool; import mmutils.thread_pool : ThreadPool;
launcher.threads = ThreadPool.getCPUCoresCount(); launcher.threads = ThreadPool.getCPUCoresCount();
@ -746,8 +1112,14 @@ int main(int argc, char** argv)
{ {
import demos.simple; import demos.simple;
import demos.space_invaders; import demos.space_invaders;
// launcher.switchDemo(&spaceInvadersStart,&spaceInvadersLoop,&spaceInvadersEnd,&spaceInvadersEvent,&spaceInvadersTool,SpaceInvaders.tips); import demos.particles;
launcher.switchDemo(&simpleStart,&simpleLoop,&simpleEnd,&simpleEvent,&simpleTool,Simple.tips); import demos.brick_breaker;
// launcher.switchDemo(&spaceInvadersStart,&spaceInvadersLoop,&spaceInvadersEnd,&spaceInvadersEvent,SpaceInvaders.tips);
// launcher.switchDemo(&particlesStart,&particlesLoop,&particlesEnd,&particlesEvent,ParticlesDemo.tips);
// launcher.switchDemo(&simpleStart,&simpleLoop,&simpleEnd,&simpleEvent,Simple.tips);
// launcher.switchDemo(getParticlesDemo());
// launcher.switchDemo(getSimpleDemo());
launcher.switchDemo(getBrickBreakerDemo());
} }
int key_num; int key_num;
@ -775,8 +1147,6 @@ int main(int argc, char** argv)
} }
} }
EntityManager.destroy();
return 0; return 0;
} }
@ -792,7 +1162,7 @@ void loadGFX()
Texture.__loadBackend(); Texture.__loadBackend();
Renderer.__loadBackend(); Renderer.__loadBackend();
GfxConfig.materials = Mallocator.makeArray!Material(1); GfxConfig.materials = Mallocator.makeArray!Material(3);
GfxConfig.meshes = Mallocator.makeArray!Mesh(1); GfxConfig.meshes = Mallocator.makeArray!Mesh(1);
float[16] vertices = [-0.5,-0.5, 0,1, -0.5,0.5, 0,0, 0.5,-0.5, 1,1, 0.5,0.5, 1,0]; float[16] vertices = [-0.5,-0.5, 0,1, -0.5,0.5, 0,0, 0.5,-0.5, 1,1, 0.5,0.5, 1,0];
@ -839,7 +1209,93 @@ void loadGFX()
GfxConfig.materials[0].data.bindings[0] = GfxConfig.materials[0].getLocation("tex"); GfxConfig.materials[0].data.bindings[0] = GfxConfig.materials[0].getLocation("tex");
Shader vsh2;
vsh2.create();
vsh2.load("assets/shaders/circle.vp");
vsh2.compile();
Shader fsh2;
fsh2.create();
fsh2.load("assets/shaders/circle.fp");
fsh2.compile();
GfxConfig.materials[1].create();
GfxConfig.materials[1].data.blend_mode = Material.BlendMode.mixed;
GfxConfig.materials[1].data.mode = Material.TransformMode.position;
Material.ShaderModule[1] modules2 = [Material.ShaderModule(vsh2,fsh2)];
GfxConfig.materials[1].attachModules(modules2);
//GfxConfig.materials[0].
//GfxConfig.materials[0].load(load_data.materials[i].str);
GfxConfig.materials[1].compile();
GfxConfig.materials[1].bindAttribLocation("positions",0);
//GfxConfig.materials[1].bindAttribLocation("tex_coords",1);
//GfxConfig.materials[1].bindAttribLocation("depth",2);
//GfxConfig.materials[1].bindAttribLocation("vcolor",3);
GfxConfig.materials[1].link();
/* import std.stdio;
writeln("positions ",glGetAttribLocation(GfxConfig.materials[0].data.modules[0].gl_handle,"positions"));
writeln("tex_coords ",glGetAttribLocation(GfxConfig.materials[0].data.modules[0].gl_handle,"tex_coords"));
writeln("depth ",glGetAttribLocation(GfxConfig.materials[0].data.modules[0].gl_handle,"depth"));
writeln("vcolor ",glGetAttribLocation(GfxConfig.materials[0].data.modules[0].gl_handle,"vcolor"));*/
GfxConfig.materials[1].data.uniforms = Mallocator.makeArray!(Material.Uniform)(2);
GfxConfig.materials[1].data.uniforms[0] = Material.Uniform(Material.Type.float4, GfxConfig.materials[1].getLocation("matrix_1"), 0);
GfxConfig.materials[1].data.uniforms[1] = Material.Uniform(Material.Type.float4, GfxConfig.materials[1].getLocation("matrix_2"), 16);
//GfxConfig.materials[1].data.uniforms[2] = Material.Uniform(Material.Type.float4, GfxConfig.materials[0].getLocation("uv_transform"), 32);
//GfxConfig.materials[1].data.bindings = Mallocator.makeArray!(int)(1);
//GfxConfig.materials[1].data.bindings[0] = GfxConfig.materials[0].getLocation("tex");
Shader vsh3;
vsh3.create();
vsh3.load("assets/shaders/additive_particles.vp");
vsh3.compile();
Shader fsh3;
fsh3.create();
fsh3.load("assets/shaders/additive_particles.fp");
fsh3.compile();
GfxConfig.materials[2].create();
GfxConfig.materials[2].data.blend_mode = Material.BlendMode.opaque;
GfxConfig.materials[2].data.mode = Material.TransformMode.position;
Material.ShaderModule[1] modules3 = [Material.ShaderModule(vsh3,fsh3)];
GfxConfig.materials[2].attachModules(modules3);
//GfxConfig.materials[0].
//GfxConfig.materials[0].load(load_data.materials[i].str);
GfxConfig.materials[2].compile();
GfxConfig.materials[2].bindAttribLocation("positions",0);
GfxConfig.materials[2].bindAttribLocation("tex_coords",1);
GfxConfig.materials[2].bindAttribLocation("depth",2);
GfxConfig.materials[2].bindAttribLocation("vcolor",3);
GfxConfig.materials[2].link();
/* import std.stdio;
writeln("positions ",glGetAttribLocation(GfxConfig.materials[0].data.modules[0].gl_handle,"positions"));
writeln("tex_coords ",glGetAttribLocation(GfxConfig.materials[0].data.modules[0].gl_handle,"tex_coords"));
writeln("depth ",glGetAttribLocation(GfxConfig.materials[0].data.modules[0].gl_handle,"depth"));
writeln("vcolor ",glGetAttribLocation(GfxConfig.materials[0].data.modules[0].gl_handle,"vcolor"));*/
GfxConfig.materials[2].data.uniforms = Mallocator.makeArray!(Material.Uniform)(3);
GfxConfig.materials[2].data.uniforms[0] = Material.Uniform(Material.Type.float4, GfxConfig.materials[0].getLocation("matrix_1"), 0);
GfxConfig.materials[2].data.uniforms[1] = Material.Uniform(Material.Type.float4, GfxConfig.materials[0].getLocation("matrix_2"), 16);
GfxConfig.materials[2].data.uniforms[2] = Material.Uniform(Material.Type.float4, GfxConfig.materials[0].getLocation("uv_transform"), 32);
GfxConfig.materials[2].data.bindings = Mallocator.makeArray!(int)(1);
GfxConfig.materials[2].data.bindings[0] = GfxConfig.materials[0].getLocation("tex");
GfxConfig.materials[2].data.blend_mode = Material.BlendMode.additive;
/*glUseProgram(0); /*glUseProgram(0);
glBindBuffer(GL_ARRAY_BUFFER, 0); glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);*/ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);*/
launcher.tool_circle = Mallocator.make!ToolCircle;
} }

View file

@ -0,0 +1,501 @@
module demos.brick_breaker;
import app;
import bindbc.sdl;
import bubel.ecs.attributes;
import bubel.ecs.core;
import bubel.ecs.entity;
import bubel.ecs.manager;
import bubel.ecs.std;
import cimgui.cimgui;
import ecs_utils.gfx.texture;
import ecs_utils.math.vector;
import ecs_utils.utils;
import game_core.basic;
import game_core.rendering;
import game_core.collision;
extern(C):
private enum float px = 1.0/512.0;
/*#######################################################################################################################
------------------------------------------------ Components ------------------------------------------------------------------
#######################################################################################################################*/
/*struct CLocation
{
mixin ECS.Component;
alias location this;
vec2 location;
}*/
struct CBrick
{
mixin ECS.Component;
}
struct CPaddle
{
mixin ECS.Component;
}
struct CBall
{
mixin ECS.Component;
ubyte radius;
}
struct CHitPoints
{
mixin ECS.Component;
alias value this;
short value;
}
// struct CVelocityFactor
// {
// mixin ECS.Component;
// alias value this;
// vec2 value = vec2(1);
// }
// struct CVelocity
// {
// mixin ECS.Component;
// alias value this;
// vec2 value = vec2(0);
// }
struct EDamage
{
mixin ECS.Event;
ubyte damage = 1;
}
/*#######################################################################################################################
------------------------------------------------ Systems ------------------------------------------------------------------
#######################################################################################################################*/
// struct MoveSystem
// {
// mixin ECS.System!64;
// struct EntitiesData
// {
// uint length;
// CLocation[] location;
// @readonly CVelocity[] velocity;
// @optional @readonly CVelocityFactor[] vel_factor;
// }
// void onUpdate(EntitiesData data)
// {
// if(data.vel_factor)
// {
// foreach(i; 0..data.length)
// {
// data.location[i] += data.velocity[i] * data.vel_factor[i] * launcher.delta_time;
// }
// }
// else
// {
// foreach(i; 0..data.length)
// {
// data.location[i] += data.velocity[i] * launcher.delta_time;
// }
// }
// }
// }
struct EdgeCollisionSystem
{
mixin ECS.System!64;
struct EntitiesData
{
uint length;
CLocation[] location;
CVelocity[] velocity;
//CBall[] ball_flag;
}
void onUpdate(EntitiesData data)
{
foreach(i; 0..data.length)
{
if(data.location[i].x < 0)
{
if(data.velocity[i].x < 0)data.velocity[i].x = -data.velocity[i].x;
data.location[i].x = 0;
}
else if(data.location[i].x > 400)
{
if(data.velocity[i].x > 0)data.velocity[i].x = -data.velocity[i].x;
data.location[i].x = 400;
}
if(data.location[i].y < 0)
{
if(data.velocity[i].y < 0)data.velocity[i].y = -data.velocity[i].y;
data.location[i].y = 0;
}
else if(data.location[i].y > 300)
{
if(data.velocity[i].y > 0)data.velocity[i].y = -data.velocity[i].y;
data.location[i].y = 300;
}
}
}
}
struct BallCollisionSystem
{
mixin ECS.System!64;
mixin ECS.ReadOnlyDependencies!(ShootGridDependency, BVHDependency);
struct EntitiesData
{
///variable named "length" contain entites count
uint length;
const (Entity)[] entity;
CVelocity[] velocity;
@readonly CLocation[] location;
@readonly CScale[] scale;
@readonly CBall[] ball_flag;
}
struct State
{
bool test(EntityID id)
{
Entity* entity = launcher.manager.getEntity(id);
if(entity)
{
CLocation* location = entity.getComponent!CLocation;
CScale* scale = entity.getComponent!CScale;
if(location && scale)
{
float radius = data.scale[i].x;
vec2 rel_pos = *location - data.location[i];
vec2 abs_rel_pos = rel_pos;
if(abs_rel_pos.x < 0)abs_rel_pos.x = -abs_rel_pos.x;
if(abs_rel_pos.y < 0)abs_rel_pos.y = -abs_rel_pos.y;
vec2 half_scale = *scale * 0.25f;
if(abs_rel_pos.x < half_scale.x + radius &&
abs_rel_pos.y < half_scale.y + radius)
{
if(abs_rel_pos.x < half_scale.x)
{
if(rel_pos.y * data.velocity[i].y > 0)
{
data.velocity[i].y = -data.velocity[i].y;
launcher.manager.sendEvent(id,EDamage(1));
return false;
}
}
else if(abs_rel_pos.y < half_scale.y)
{
if(rel_pos.x * data.velocity[i].x > 0)
{
data.velocity[i].x = -data.velocity[i].x;
launcher.manager.sendEvent(id,EDamage(1));
return false;
}
}
else
{
vec2 vector = abs_rel_pos - half_scale;
if(rel_pos.x > 0)vector.x = -vector.x;
if(rel_pos.y > 0)vector.y = -vector.y;
float pow_dist = vector.length2();
if(pow_dist < radius*radius)
{
vector = vector / sqrtf(pow_dist);
data.velocity[i] = data.velocity[i] - vector * (2 * dot(vector, data.velocity[i]));
launcher.manager.sendEvent(id,EDamage(1));
return false;
}
}
}
}
}
return true;
}
EntitiesData data;
uint i;
}
ShootGrid* grid;
BVHTree* tree;
BVHTree* static_tree;
bool onBegin()
{
//grid = launcher.manager.getSystem!ShootGridManager().grid;
tree = launcher.manager.getSystem!BVHBuilder().tree;
static_tree = launcher.manager.getSystem!StaticBVHBuilder().tree;
//if(grid is null)return false;
if(tree is null || static_tree is null)return false;
else return true;
}
void onUpdate(EntitiesData data)
{
// State state;
// state.data = data;
// EntityID id;
// foreach(i; 0..data.length)
// {
// state.i = i;
// float radius = data.scale[i].x;
// if(grid.test(id, data.location[i] - radius, data.location[i] + radius, ubyte.max))
// {
// state.test(id);
// }
// }
State state;
state.data = data;
foreach(i; 0..data.length)
{
state.i = i;
//float radius = data.scale[i].x;
AABB bounding = AABB(data.location[i]-data.scale[i], data.location[i]+data.scale[i]);
tree.test(bounding, cast(bool delegate(EntityID id))&state.test);
static_tree.test(bounding, cast(bool delegate(EntityID id))&state.test);
}
}
}
struct DamageSystem
{
mixin ECS.System!64;
mixin ECS.ReadOnlyDependencies!(ShootGridDependency);
struct EntitiesData
{
///variable named "length" contain entites count
uint length;
const (Entity)[] entity;
CHitPoints[] hit_points;
}
void handleEvent(Entity* entity, EDamage event)
{
EntityMeta meta = entity.getMeta();
CHitPoints* hp = meta.getComponent!CHitPoints;
hp.value -= event.damage;
if(hp.value < 0)launcher.manager.removeEntity(entity.id);
}
}
/*#######################################################################################################################
------------------------------------------------ Functions ------------------------------------------------------------------
#######################################################################################################################*/
struct BrickBreakerDemo
{
__gshared const (char)* tips = "Brick breaker demo. It's a game about destroying evil bricks.";
//EntityTemplate* tmpl;
Texture texture;
}
__gshared BrickBreakerDemo* demo;
void brickBreakerRegister()
{
demo = Mallocator.make!BrickBreakerDemo;
demo.texture.create();
demo.texture.load("assets/textures/atlas.png");
launcher.manager.beginRegister();
registerRenderingModule(launcher.manager);
registerCollisionModule(launcher.manager);
launcher.manager.registerComponent!CLocation;
launcher.manager.registerComponent!CRotation;
launcher.manager.registerComponent!CScale;
launcher.manager.registerComponent!CTexCoords;
launcher.manager.registerComponent!CTexCoordsIndex;
launcher.manager.registerComponent!CVelocity;
launcher.manager.registerComponent!CInput;
launcher.manager.registerComponent!CPaddle;
launcher.manager.registerComponent!CDamping;
launcher.manager.registerComponent!CVelocityFactor;
launcher.manager.registerComponent!CBall;
launcher.manager.registerComponent!CHitPoints;
launcher.manager.registerEvent!EDamage;
launcher.manager.registerSystem!MoveSystem(-100);
launcher.manager.registerSystem!EdgeCollisionSystem(-99);
launcher.manager.registerSystem!BallCollisionSystem(-79);
launcher.manager.registerSystem!InputMovementSystem(-120);
launcher.manager.registerSystem!DampingSystem(-120);
launcher.manager.registerSystem!DamageSystem(-120);
launcher.manager.endRegister();
}
void brickBreakerStart()
{
DrawSystem* draw_system = launcher.manager.getSystem!DrawSystem;
draw_system.default_data.color = 0x80808080;
draw_system.default_data.texture = demo.texture;
draw_system.default_data.size = vec2(16,16);
draw_system.default_data.coords = vec4(246,64,2,2)*px;
draw_system.default_data.material_id = 0;
EntityTemplate* brick_tmpl = launcher.manager.allocateTemplate(
[CLocation.component_id, CScale.component_id, CColor.component_id,
CTexCoordsIndex.component_id, CBVH.component_id, CHitPoints.component_id,
CAABB.component_id, CStatic.component_id].staticArray
);
brick_tmpl.getComponent!CTexCoordsIndex().value = TexCoordsManager.instance.getCoordIndex(vec4(304,40,16,8)*px);
brick_tmpl.getComponent!CColor().value = 0x80206020;
brick_tmpl.getComponent!CScale().value = vec2(16,8);
brick_tmpl.getComponent!CHitPoints().value = 2;
//brick_tmpl.getComponent!CAABB().bounding = AABB(vec2(),vec2());
EntityTemplate* big_brick_tmpl = launcher.manager.allocateTemplate(brick_tmpl);
big_brick_tmpl.getComponent!CTexCoordsIndex().value = TexCoordsManager.instance.getCoordIndex(vec4(320,32,16,16)*px);
big_brick_tmpl.getComponent!CScale().value = vec2(16,16);
EntityTemplate* paddle_tmpl = launcher.manager.allocateTemplate(
[CLocation.component_id, CScale.component_id, CInput.component_id,
CTexCoordsIndex.component_id, CPaddle.component_id, CVelocity.component_id,
CDamping.component_id, CVelocityFactor.component_id, CBVH.component_id,
CAABB.component_id].staticArray
);
paddle_tmpl.getComponent!CTexCoordsIndex().value = TexCoordsManager.instance.getCoordIndex(vec4(272,48,64,10)*px);
paddle_tmpl.getComponent!CScale().value = vec2(64,10);
paddle_tmpl.getComponent!CDamping().value = 14;
paddle_tmpl.getComponent!CVelocityFactor().value = vec2(1,0);
EntityTemplate* ball_tmpl = launcher.manager.allocateTemplate(
[CLocation.component_id, CScale.component_id, //CDamping.component_id,
CTexCoordsIndex.component_id, CBall.component_id, CVelocity.component_id].staticArray
);
ball_tmpl.getComponent!CTexCoordsIndex().value = TexCoordsManager.instance.getCoordIndex(vec4(304,32,8,8)*px);
ball_tmpl.getComponent!CScale().value = vec2(8,8);
ball_tmpl.getComponent!CVelocity().value = vec2(0.1,0.1);
// paddle_tmpl.getComponent!CDamping().value = 14;
launcher.gui_manager.addComponent(CLocation(), "Location");
launcher.gui_manager.addComponent(CRotation(), "Rotation");
launcher.gui_manager.addComponent(CScale(), "Scale");
launcher.gui_manager.addComponent(CColor(), "Color");
launcher.gui_manager.addComponent(CTexCoords(), "Tex Coords");
launcher.gui_manager.addComponent(CTexCoordsIndex(), "Tex Coords Index");
launcher.gui_manager.addComponent(CVelocity(), "Velocity");
launcher.gui_manager.addComponent(CInput(), "Velocity");
launcher.gui_manager.addComponent(CDamping(), "Damping");
launcher.gui_manager.addComponent(CBall(), "Ball");
launcher.gui_manager.addComponent(CBVH(), "BVH");
launcher.gui_manager.addComponent(CAABB(), "AABB");
launcher.gui_manager.addSystem(MoveSystem.system_id, "Move System");
launcher.gui_manager.addSystem(EdgeCollisionSystem.system_id, "Edge Collision System");
launcher.gui_manager.addSystem(BallCollisionSystem.system_id, "Ball Collision System");
launcher.gui_manager.addSystem(InputMovementSystem.system_id, "Input Movement System");
launcher.gui_manager.addSystem(DampingSystem.system_id, "Damping System");
launcher.gui_manager.addSystem(DamageSystem.system_id, "Damage System");
launcher.gui_manager.addTemplate(brick_tmpl, "Brick");
launcher.gui_manager.addTemplate(big_brick_tmpl, "Big Brick");
launcher.gui_manager.addTemplate(paddle_tmpl, "Paddle");
launcher.gui_manager.addTemplate(ball_tmpl, "Ball");
foreach(i;0..10)
{
CColor color;
final switch(i)
{
case 0:color = 0x80206020;break;
case 1:color = 0x80602020;break;
case 2:color = 0x80202060;break;
case 3:color = 0x80206060;break;
case 4:color = 0x80606020;break;
case 5:color = 0x80602060;break;
case 6:color = 0x80606060;break;
case 7:color = 0x80202020;break;
case 8:color = 0x80008030;break;
case 9:color = 0x80206080;break;
}
foreach (j; 0..20)
{
launcher.manager.addEntity(brick_tmpl,[CLocation(vec2(j*18,300-i*10)).ref_, color.ref_].staticArray);
}
}
launcher.manager.addEntity(paddle_tmpl,[CLocation(vec2(190,20)).ref_].staticArray);
launcher.manager.addEntity(ball_tmpl,[CLocation(vec2(190,40)).ref_].staticArray);
}
void brickBreakerEnd()
{
demo.texture.destroy();
Mallocator.dispose(demo);
}
void brickBreakerEvent(SDL_Event* event)
{
}
bool brickBreakerLoop()
{
launcher.render_position = (vec2(launcher.window_size.x,launcher.window_size.y)*launcher.scalling - vec2(400,300)) * 0.5;
launcher.manager.begin();
if(launcher.multithreading)
{
launcher.job_updater.begin();
launcher.manager.updateMT();
launcher.job_updater.call();
}
else
{
launcher.manager.update();
}
launcher.manager.end();
return true;
}
DemoCallbacks getBrickBreakerDemo()
{
DemoCallbacks demo;
demo.register = &brickBreakerRegister;
demo.initialize = &brickBreakerStart;
demo.deinitialize = &brickBreakerEnd;
demo.loop = &brickBreakerLoop;
demo.tips = .demo.tips;
return demo;
}

View file

@ -0,0 +1,591 @@
module demos.particles;
import app;
import bindbc.sdl;
import cimgui.cimgui;
import bubel.ecs.attributes;
import bubel.ecs.core;
import bubel.ecs.entity;
import bubel.ecs.manager;
import bubel.ecs.std;
import ecs_utils.gfx.texture;
import ecs_utils.math.vector;
import ecs_utils.utils;
import game_core.basic;
import game_core.rendering;
import gui.attributes;
extern(C):
private enum float px = 1.0/512.0;
/*#######################################################################################################################
------------------------------------------------ Components ------------------------------------------------------------------
#######################################################################################################################*/
/*struct CLocation
{
mixin ECS.Component;
alias location this;
vec2 location;
}
struct CColor
{
mixin ECS.Component;
alias value this;
@GUIColor uint value = uint.max;
}
struct CTexCoords
{
mixin ECS.Component;
vec4 value;
}*/
// struct CVelocity
// {
// mixin ECS.Component;
// alias value this;
// vec2 value = vec2(0);
// }
struct CForceRange
{
mixin ECS.Component;
vec2 range = vec2(20,200);
}
struct CAttractor
{
mixin ECS.Component;
//alias value this;
float strength = 0.2;
}
struct CVortex
{
mixin ECS.Component;
float strength = 0.6;
}
// struct CDamping
// {
// mixin ECS.Component;
// alias power this;
// @GUIRange(0,9) ubyte power = 0;
// }
struct CGravity
{
mixin ECS.Component;
}
struct CParticleLife
{
mixin ECS.Component;
this(float life_in_secs)
{
life = cast(int)(life_in_secs * 1000_000);
}
alias life this;
int life = 1000000;
}
/*#######################################################################################################################
------------------------------------------------ Systems ------------------------------------------------------------------
#######################################################################################################################*/
/*
struct DrawSystem
{
mixin ECS.System!32;
struct EntitiesData
{
uint length;
//uint thread_id;
uint job_id;
//@readonly CTexCoords[] coords;
@readonly CLocation[] locations;
@optional @readonly CColor[] color;
}
void onUpdate(EntitiesData data)
{
if(launcher.renderer.prepared_items >= launcher.renderer.MaxObjects)return;//simple leave loop if max visible objects count was reached
import ecs_utils.gfx.renderer;
Renderer.DrawData draw_data;
draw_data.size = vec2(2,2);
draw_data.coords = vec4(246,64,2,2)*px;
draw_data.color = 0x80808080;
draw_data.material_id = 2;
draw_data.thread_id = data.job_id;
draw_data.texture = particles_demo.texture;
if(!data.color)
{
foreach(i; 0..data.length)
{
draw_data.position = data.locations[i];
launcher.renderer.draw(draw_data);//particles_demo.texture, data.locations[i], vec2(2,2), vec4(246,64,2,2)*px, 0, 0x80808080, 0, 2, 0, data.job_id);
}
}
else
{
foreach(i; 0..data.length)
{
draw_data.position = data.locations[i];
draw_data.color = data.color[i].value;
launcher.renderer.draw(draw_data);//particles_demo.texture, data.locations[i], vec2(2,2), vec4(246,64,2,2)*px, 0, data.color[i].value, 0, 2, 0, data.job_id);
}
}
}
}*/
// struct MoveSystem
// {
// mixin ECS.System!64;
// struct EntitiesData
// {
// uint length;
// CLocation[] locations;
// @readonly CVelocity[] velocity;
// }
// void onUpdate(EntitiesData data)
// {
// foreach(i; 0..data.length)
// {
// data.locations[i] += data.velocity[i] * launcher.delta_time;
// }
// }
// }
struct MouseAttractSystem
{
mixin ECS.System!64;
struct EntitiesData
{
uint length;
@readonly CLocation[] locations;
CVelocity[] velocity;
}
vec2 mouse_pos;
bool onBegin()
{
if(!launcher.getKeyState(SDL_SCANCODE_SPACE))return false;
mouse_pos = launcher.mouse.position;
mouse_pos = vec2(mouse_pos.x, mouse_pos.y) * launcher.scalling - launcher.render_position;
return true;
}
void onUpdate(EntitiesData data)
{
float speed = launcher.delta_time * 0.01;
foreach(i;0..data.length)
{
vec2 rel_pos = mouse_pos - data.locations[i];
float len2 = rel_pos.x * rel_pos.x + rel_pos.y * rel_pos.y;
if(len2 < 0.1)len2 = 0.1;
data.velocity[i] = data.velocity[i] + rel_pos / len2 * speed;
}
}
}
struct AttractSystem
{
mixin ECS.System!64;
struct EntitiesData
{
uint length;
@readonly CLocation[] locations;
CVelocity[] velocity;
}
struct Updater
{
AttractSystem.EntitiesData data;
void onUpdate(AttractorIterator.EntitiesData adata)
{
float speed = launcher.delta_time * 0.00004;
if(adata.vortex)
{
foreach(i;0..data.length)
{
foreach(j;0..adata.length)
{
vec2 rel_pos = data.locations[i] - adata.locations[j];
float len2 = rel_pos.length2();
float inv_len = rsqrt(len2);
if(1 < adata.force_range[j].range.y*inv_len)
{
float dist = (adata.force_range[j].range.y - 0.4)*inv_len - 1;
vec2 vec = rel_pos * inv_len;
vec2 cvec = vec2(-vec.y,vec.x);
float sign = -1;
if(1 < adata.force_range[j].range.x*inv_len)sign = 1;
float str = adata.attractor[j].strength * sign;
float vortex_str = adata.vortex[j].strength;
data.velocity[i] = data.velocity[i] + (rel_pos * str + cvec * vortex_str) * speed * dist;
}
}
}
}
else
{
foreach(i;0..data.length)
{
foreach(j;0..adata.length)
{
vec2 rel_pos = data.locations[i] - adata.locations[j];
float len2 = rel_pos.length2();
float inv_len = rsqrt(len2);
if(1 < adata.force_range[j].range.y*inv_len)
{
float dist = (adata.force_range[j].range.y - 0.4)*inv_len - 1;
vec2 vec = rel_pos;
float sign = -1;
if(1 < adata.force_range[j].range.x*inv_len)sign = 1;
float str = adata.attractor[j].strength * speed * dist * sign;
data.velocity[i] = data.velocity[i] + vec * str;
}
}
}
}
}
}
void onUpdate(EntitiesData data)
{
Updater updater;
updater.data = data;
launcher.manager.callEntitiesFunction!AttractorIterator(&updater.onUpdate);
}
}
struct AttractorIterator
{
mixin ECS.System!1;
struct EntitiesData
{
uint length;
@readonly CLocation[] locations;
@readonly CAttractor[] attractor;
@readonly CForceRange[] force_range;
@optional @readonly CVortex[] vortex;
}
bool onBegin()
{
return false;
}
void onUpdate(EntitiesData data)
{
}
}
struct PlayAreaSystem
{
mixin ECS.System!32;
struct EntitiesData
{
uint length;
Entity[] entity;
@readonly CLocation[] locations;
}
void onUpdate(EntitiesData data)
{
foreach(i; 0..data.length)
{
if(data.locations[i].x > 440)launcher.manager.removeEntity(data.entity[i].id);
else if(data.locations[i].x < -40)launcher.manager.removeEntity(data.entity[i].id);
if(data.locations[i].y > 340)launcher.manager.removeEntity(data.entity[i].id);
else if(data.locations[i].y < -40)launcher.manager.removeEntity(data.entity[i].id);
}
}
}
// struct DampingSystem
// {
// mixin ECS.System!32;
// struct EntitiesData
// {
// uint length;
// const (Entity)[] entity;
// @readonly CDamping[] damping;
// CVelocity[] velocity;
// }
// float[10] damp = 0;
// bool onBegin()
// {
// foreach(i;0..10)
// {
// damp[i] = powf((0.99 - cast(float)i * 0.01),launcher.delta_time*0.1);
// }
// return true;
// }
// void onUpdate(EntitiesData data)
// {
// foreach(i; 0..data.length)
// {
// data.velocity[i] = data.velocity[i] * damp[data.damping[i]];
// }
// }
// }
struct ParticleLifeSystem
{
mixin ECS.System!32;
struct EntitiesData
{
uint length;
const (Entity)[] entity;
CParticleLife[] life;
}
int delta_time;
bool onBegin()
{
delta_time = cast(int)(launcher.delta_time * 1000);
return true;
}
void onUpdate(EntitiesData data)
{
foreach(i; 0..data.length)
{
data.life[i] -= delta_time;
if(data.life[i] < 0)launcher.manager.removeEntity(data.entity[i].id);
}
}
}
struct GravitySystem
{
mixin ECS.System!32;
struct EntitiesData
{
uint length;
const (Entity)[] entity;
@readonly CGravity[] gravity;
CVelocity[] velocity;
}
void onUpdate(EntitiesData data)
{
float delta_time = launcher.delta_time * 0.00_092;
foreach(i; 0..data.length)
{
data.velocity[i].y -= delta_time;
}
}
}
/*#######################################################################################################################
------------------------------------------------ Functions ------------------------------------------------------------------
#######################################################################################################################*/
struct ParticlesDemo
{
__gshared const (char)* tips = "Use \"space\" to spwan entities.\n\nSystems can be enabled/disabled from \"Simple\" window.";
Texture texture;
}
__gshared ParticlesDemo* particles_demo;
void particlesRegister()
{
particles_demo = Mallocator.make!ParticlesDemo;
particles_demo.texture.create();
particles_demo.texture.load("assets/textures/atlas.png");
launcher.manager.beginRegister();
registerRenderingModule(launcher.manager);
launcher.manager.registerComponent!CLocation;
//launcher.manager.registerComponent!CTexCoords;
launcher.manager.registerComponent!CColor;
launcher.manager.registerComponent!CVelocity;
launcher.manager.registerComponent!CScale;
launcher.manager.registerComponent!CTexCoords;
launcher.manager.registerComponent!CTexCoordsIndex;
launcher.manager.registerComponent!CRotation;
launcher.manager.registerComponent!CDepth;
launcher.manager.registerComponent!CAttractor;
launcher.manager.registerComponent!CDamping;
launcher.manager.registerComponent!CGravity;
launcher.manager.registerComponent!CVortex;
launcher.manager.registerComponent!CParticleLife;
launcher.manager.registerComponent!CForceRange;
launcher.manager.registerComponent!CMaterialIndex;
launcher.manager.registerSystem!MoveSystem(0);
launcher.manager.registerSystem!DrawSystem(100);
launcher.manager.registerSystem!PlayAreaSystem(102);
launcher.manager.registerSystem!AttractSystem(-1);
launcher.manager.registerSystem!MouseAttractSystem(1);
launcher.manager.registerSystem!DampingSystem(101);
launcher.manager.registerSystem!ParticleLifeSystem(-10);
launcher.manager.registerSystem!GravitySystem(-2);
launcher.manager.registerSystem!AttractorIterator(-1);
launcher.manager.endRegister();
}
void particlesStart()
{
DrawSystem* draw_system = launcher.manager.getSystem!DrawSystem;
draw_system.default_data.size = vec2(2,2);
draw_system.default_data.coords = vec4(246,64,2,2)*px;
draw_system.default_data.material_id = 2;
draw_system.default_data.texture = particles_demo.texture;
launcher.gui_manager.addSystem(MoveSystem.system_id,"Move System");
launcher.gui_manager.addSystem(DrawSystem.system_id,"Draw System");
launcher.gui_manager.addSystem(PlayAreaSystem.system_id,"Play Area System");
launcher.gui_manager.addSystem(AttractSystem.system_id,"Attract System");
launcher.gui_manager.addSystem(MouseAttractSystem.system_id,"Mouse Attract System");
launcher.gui_manager.addSystem(DampingSystem.system_id,"Damping System");
launcher.gui_manager.addSystem(ParticleLifeSystem.system_id,"Particle Life System");
// launcher.gui_manager.addComponent(CColor(),"Color (white)");
// launcher.gui_manager.addComponent(CColor(0xFF101540),"Color (red)");
// launcher.gui_manager.addComponent(CColor(0xFF251010),"Color (blue)");
// launcher.gui_manager.addComponent(CColor(0xFF102010),"Color (green)");
launcher.gui_manager.addComponent(CColor(0xFF101540),"Color");
launcher.gui_manager.addComponent(CAttractor(0.1),"Attractor");
launcher.gui_manager.addComponent(CForceRange(vec2(5,40)),"ForceRange");
launcher.gui_manager.addComponent(CVelocity(),"Velocity");
launcher.gui_manager.addComponent(CDamping(),"Damping");
launcher.gui_manager.addComponent(CVortex(),"Vortex");
launcher.gui_manager.addComponent(CParticleLife(),"Particle Life");
launcher.gui_manager.addComponent(CGravity(),"Gravity");
EntityTemplate* tmpl;
EntityTemplate* base_tmpl = launcher.manager.allocateTemplate([CTexCoords.component_id, CLocation.component_id, CColor.component_id, CVelocity.component_id, CDamping.component_id, CScale.component_id, CMaterialIndex.component_id].staticArray);
base_tmpl.getComponent!CColor().value = 0xFF251010;
base_tmpl.getComponent!CScale().value = vec2(2);
base_tmpl.getComponent!CTexCoords().value = vec4(246,64,2,2)*px;
base_tmpl.getComponent!CMaterialIndex().value = 2;
launcher.gui_manager.addTemplate(base_tmpl,"Particle");
// tmpl = launcher.manager.allocateTemplate(base_tmpl);
// tmpl.getComponent!CColor().value = 0xFF251010;
// launcher.gui_manager.addTemplate(tmpl,"Particle (blue)");
// tmpl = launcher.manager.allocateTemplate(base_tmpl);
// tmpl.getComponent!CColor().value = 0xFF102010;
// launcher.gui_manager.addTemplate(tmpl,"Particle (green)");
// tmpl = launcher.manager.allocateTemplate(base_tmpl);
// tmpl.getComponent!CColor().value = 0xFF101540;
// launcher.gui_manager.addTemplate(tmpl,"Particle (red)");
// tmpl = launcher.manager.allocateTemplate(tmpl, [CDamping.component_id].staticArray);
// launcher.gui_manager.addTemplate(tmpl,"Particle (damping)");
// tmpl = launcher.manager.allocateTemplate(tmpl);
// tmpl.getComponent!CDamping().power = 4;
// launcher.gui_manager.addTemplate(tmpl,"Particle (damping!)");
tmpl = launcher.manager.allocateTemplate([CAttractor.component_id, CLocation.component_id, CForceRange.component_id, CScale.component_id].staticArray);
tmpl.getComponent!CScale().value = vec2(4);
launcher.gui_manager.addTemplate(tmpl,"Attractor");
tmpl = launcher.manager.allocateTemplate(tmpl, [CVortex.component_id].staticArray);
launcher.gui_manager.addTemplate(tmpl,"Vortex");
// tmpl = launcher.manager.allocateTemplate(tmpl);
// tmpl.getComponent!CVortex().strength = -0.6;
// launcher.gui_manager.addTemplate(tmpl,"Vortex (reversed)");
}
void particlesEnd()
{
particles_demo.texture.destroy();
//launcher.manager.freeTemplate(simple.tmpl);
Mallocator.dispose(particles_demo);
}
void particlesEvent(SDL_Event* event)
{
}
bool particlesLoop()
{
launcher.render_position = (vec2(launcher.window_size.x,launcher.window_size.y)*launcher.scalling - vec2(400,300)) * 0.5;
launcher.manager.begin();
if(launcher.multithreading)
{
launcher.job_updater.begin();
launcher.manager.updateMT();
launcher.job_updater.call();
}
else
{
launcher.manager.update();
}
launcher.manager.end();
return true;
}
DemoCallbacks getParticlesDemo()
{
DemoCallbacks demo;
demo.register = &particlesRegister;
demo.initialize = &particlesStart;
demo.deinitialize = &particlesEnd;
demo.loop = &particlesLoop;
demo.tips = ParticlesDemo.tips;
return demo;
}

View file

@ -0,0 +1,101 @@
module demos.sandbox;
import bindbc.sdl;
import demos.simple;
import demos.snake;
import demos.space_invaders;
import demos.particles;
import demos.brick_breaker;
import game_core.rendering;
import app;
import ecs_utils.math.vector;
extern(C):
void sandboxStart()
{
simpleRegister();
snakeRegister();
spaceInvadersRegister();
particlesRegister();
brickBreakerRegister();
simpleStart();
snakeStart();
spaceInvadersStart();
particlesStart();
brickBreakerStart();
DrawSystem* draw_system = launcher.manager.getSystem!DrawSystem;
draw_system.default_data.size = vec2(16,16);
draw_system.default_data.coords = vec4(0,48,16,16)*demos.simple.px;
draw_system.default_data.material_id = 0;
draw_system.default_data.texture = particles_demo.texture;
draw_system.default_data.color = 0x80808080;
launcher.manager.getSystem(MouseAttractSystem.system_id).disable();
launcher.manager.getSystem(demos.simple.MoveSystem.system_id).disable();
}
void sandboxEnd()
{
simpleEnd();
snakeEnd();
spaceInvadersEnd();
particlesEnd();
}
/*
void sandboxEvent(SDL_Event* event)
{
}*/
bool sandboxLoop()
{
launcher.render_position = (vec2(launcher.window_size.x,launcher.window_size.y)*launcher.scalling - vec2(400,300)) * 0.5;
launcher.manager.begin();
float delta_time = launcher.delta_time;
if(delta_time > 2000)delta_time = 2000;
__gshared float time = 0;
/*if(launcher.getKeyState(SDL_SCANCODE_SPACE))time += delta_time * 3;
else */
time += delta_time;
while(time > 200)
{
time -= 200;
launcher.manager.update("fixed");
}
if(launcher.multithreading)
{
launcher.job_updater.begin();
launcher.manager.updateMT();
launcher.job_updater.call();
}
else
{
launcher.manager.update();
}
launcher.manager.end();
return true;
}
DemoCallbacks getSanboxDemo()
{
DemoCallbacks demo;
demo.initialize = &sandboxStart;
demo.deinitialize = &sandboxEnd;
demo.loop = &sandboxLoop;
demo.tips = "tips";
return demo;
}

View file

@ -4,47 +4,42 @@ import app;
import bindbc.sdl; import bindbc.sdl;
import cimgui.cimgui;
import bubel.ecs.attributes; import bubel.ecs.attributes;
import bubel.ecs.core; import bubel.ecs.core;
import bubel.ecs.entity; import bubel.ecs.entity;
import bubel.ecs.manager; import bubel.ecs.manager;
import bubel.ecs.std; import bubel.ecs.std;
import cimgui.cimgui;
import ecs_utils.gfx.texture; import ecs_utils.gfx.texture;
import ecs_utils.math.vector; import ecs_utils.math.vector;
import ecs_utils.utils; import ecs_utils.utils;
import game_core.basic;
import game_core.rendering;
extern(C): extern(C):
struct Simple enum float px = 1.0/512.0;
{
__gshared const (char)* tips = "Use \"space\" to spwan entities.\n\nSystems can be enabled/disabled from \"Simple\" window.";
EntityTemplate* tmpl; /*#######################################################################################################################
Texture texture; ------------------------------------------------ Components ------------------------------------------------------------------
#######################################################################################################################*/
bool move_system = true; /*struct CLocation
bool draw_system = true;
}
struct CLocation
{ {
mixin ECS.Component; mixin ECS.Component;
alias location this; alias location this;
vec2 location; vec2 location;
} }*/
struct CTexture
{
mixin ECS.Component;
Texture tex;
}
/*#######################################################################################################################
------------------------------------------------ Systems ------------------------------------------------------------------
#######################################################################################################################*/
/*
struct DrawSystem struct DrawSystem
{ {
mixin ECS.System!32; mixin ECS.System!32;
@ -54,22 +49,29 @@ struct DrawSystem
uint length; uint length;
//uint thread_id; //uint thread_id;
uint job_id; uint job_id;
@readonly CTexture[] textures;
@readonly CLocation[] locations; @readonly CLocation[] locations;
} }
void onUpdate(EntitiesData data) void onUpdate(EntitiesData data)
{ {
if(launcher.renderer.prepared_items >= launcher.renderer.MaxObjects)return;//simple leave loop if max visible objects count was reached if(launcher.renderer.prepared_items >= launcher.renderer.MaxObjects)return;//simple leave loop if max visible objects count was reached
import ecs_utils.gfx.renderer;
Renderer.DrawData draw_data;
draw_data.size = vec2(16,16);
draw_data.coords = vec4(0,0,1,1);
draw_data.color = 0x80808080;
draw_data.material_id = 0;
draw_data.thread_id = data.job_id;
draw_data.texture = simple.texture;
foreach(i; 0..data.length) foreach(i; 0..data.length)
{ {
launcher.renderer.draw(data.textures[i].tex, data.locations[i].location, vec2(16,16), vec4(0,0,1,1), cast(ushort)(data.locations[i].y), 0x80808080, 0, 0, 0, data.job_id); draw_data.position = data.locations[i];
// launcher.renderer.draw(data.textures[i].tex, data.locations[i].location, vec2(16,16), vec4(0,0,1,1), 0, 0x80808080, 0, 0, 0, data.job_id); draw_data.depth = cast(ushort)(data.locations[i].y);
//draw(renderer, data.textures[i].tex, data.locations[i], vec2(32,32), vec4(0,0,1,1)); launcher.renderer.draw(draw_data);
} }
//if(data.thread_id == 0)launcher.renderer.pushData();
} }
} }*/
struct MoveSystem struct MoveSystem
{ {
@ -85,47 +87,67 @@ 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].y = data.locations[i].y + 1;
if(data.locations[i].location.y > 300)data.locations[i].location.y = 0; if(data.locations[i].y > 300)data.locations[i].y = 0;
} }
} }
} }
/*#######################################################################################################################
------------------------------------------------ Functions ------------------------------------------------------------------
#######################################################################################################################*/
struct Simple
{
__gshared const (char)* tips = "Use \"space\" to spwan entities.\n\nSystems can be enabled/disabled from \"Simple\" window.";
EntityTemplate* tmpl;
Texture texture;
}
__gshared Simple* simple; __gshared Simple* simple;
void simpleStart() void simpleRegister()
{ {
simple = Mallocator.make!Simple; simple = Mallocator.make!Simple;
simple.texture.create(); simple.texture.create();
simple.texture.load("assets/textures/buckler.png"); simple.texture.load("assets/textures/atlas.png");
launcher.manager.beginRegister(); launcher.manager.beginRegister();
registerRenderingModule(launcher.manager);
launcher.manager.registerComponent!CLocation; launcher.manager.registerComponent!CLocation;
launcher.manager.registerComponent!CTexture;
launcher.manager.registerSystem!MoveSystem(0); launcher.manager.registerSystem!MoveSystem(0);
launcher.manager.registerSystem!DrawSystem(1); // launcher.manager.registerSystem!DrawSystem(1);
launcher.manager.endRegister(); launcher.manager.endRegister();
}
launcher.gui_manager.addSystem(MoveSystem.system_id,"Move System"); void simpleStart()
{
DrawSystem* draw_system = launcher.manager.getSystem!DrawSystem;
draw_system.default_data.color = 0x80808080;
draw_system.default_data.texture = simple.texture;
draw_system.default_data.size = vec2(16,16);
draw_system.default_data.coords = vec4(0,48,16,16)*px;//vec4(0,0,1,1);
launcher.gui_manager.addSystem(MoveSystem.system_id,"Move Up System");
launcher.gui_manager.addSystem(DrawSystem.system_id,"Draw System"); launcher.gui_manager.addSystem(DrawSystem.system_id,"Draw System");
ushort[2] components = [CLocation.component_id, CTexture.component_id]; simple.tmpl = launcher.manager.allocateTemplate([CLocation.component_id, CDrawDefault.component_id].staticArray);
simple.tmpl = launcher.manager.allocateTemplate(components); //*simple.tmpl.getComponent!CTexCoordsIndex = TexCoordsManager.instance.getCoordIndex(vec4(0,48,16,16)*px);
CTexture* tex_comp = simple.tmpl.getComponent!CTexture; //CLocation* loc_comp = simple.tmpl.getComponent!CLocation;
tex_comp.tex = simple.texture;
CLocation* loc_comp = simple.tmpl.getComponent!CLocation;
launcher.gui_manager.addTemplate(simple.tmpl, "Basic"); launcher.gui_manager.addTemplate(simple.tmpl, "Basic");
foreach(i; 0..10) foreach(i; 0..10)
foreach(j; 0..10) foreach(j; 0..10)
{ {
loc_comp.location = vec2(i*16+64,j*16+64); //loc_comp.value = vec2(i*16+64,j*16+64);
launcher.manager.addEntity(simple.tmpl); launcher.manager.addEntity(simple.tmpl,[CLocation(vec2(i*16+64,j*16+64)).ref_].staticArray);
} }
} }
@ -140,46 +162,15 @@ void simpleEnd()
Mallocator.dispose(simple); Mallocator.dispose(simple);
} }
void simpleTool(vec2 position, Tool tool, int size)
{
switch(tool)
{
case Tool.entity_spawner:
{
EntityTemplate* tmpl = launcher.gui_manager.getSelectedTemplate();
CLocation* location = tmpl.getComponent!CLocation;
if(location)
{
position.x += (randomf - 0.5) * size;
position.y += (randomf - 0.5) * size;
if(position.x > 400)position.x -= 400;
else if(position.x < 0)position.x += 400;
if(position.y > 300)position.y -= 300;
else if(position.y < 0)position.y += 300;
*location = position;
}
launcher.manager.addEntity(tmpl);
}
break;
default:
break;
}
}
void simpleEvent(SDL_Event* event) void simpleEvent(SDL_Event* event)
{ {
/*if(event.type == event.button)
{
vec2 position = vec2(event.button.x, event.button.y);
}*/
} }
void spawnEntity() void spawnEntity()
{ {
CLocation* loc_comp = simple.tmpl.getComponent!CLocation; //CLocation* loc_comp = simple.tmpl.getComponent!CLocation;
loc_comp.location = vec2(randomf() * 400,0); //loc_comp.value = vec2(randomf() * 400,0);
launcher.manager.addEntity(simple.tmpl); launcher.manager.addEntity(simple.tmpl,[CLocation(vec2(randomf() * 400,0)).ref_].staticArray);
} }
bool simpleLoop() bool simpleLoop()
@ -188,7 +179,7 @@ bool simpleLoop()
if(launcher.getKeyState(SDL_SCANCODE_SPACE)) if(launcher.getKeyState(SDL_SCANCODE_SPACE))
{ {
foreach(i;0..1)spawnEntity(); foreach(i;0..20)spawnEntity();
} }
launcher.manager.begin(); launcher.manager.begin();
@ -206,3 +197,14 @@ bool simpleLoop()
return true; return true;
} }
DemoCallbacks getSimpleDemo()
{
DemoCallbacks demo;
demo.register = &simpleRegister;
demo.initialize = &simpleStart;
demo.deinitialize = &simpleEnd;
demo.loop = &simpleLoop;
demo.tips = simple.tips;
return demo;
}

View file

@ -4,8 +4,6 @@ import app;
import bindbc.sdl; import bindbc.sdl;
import cimgui.cimgui;
import bubel.ecs.attributes; import bubel.ecs.attributes;
import bubel.ecs.core; import bubel.ecs.core;
import bubel.ecs.entity; import bubel.ecs.entity;
@ -13,10 +11,14 @@ import bubel.ecs.manager;
import bubel.ecs.std; import bubel.ecs.std;
import bubel.ecs.vector; import bubel.ecs.vector;
import cimgui.cimgui;
import ecs_utils.gfx.texture; import ecs_utils.gfx.texture;
import ecs_utils.math.vector; import ecs_utils.math.vector;
import ecs_utils.utils; import ecs_utils.utils;
import game_core.basic;
//import std.array : staticArray; //import std.array : staticArray;
enum float px = 1.0/512.0; enum float px = 1.0/512.0;
@ -31,22 +33,6 @@ struct MapElement
apple = 1, apple = 1,
wall = 2, wall = 2,
snake = 3, snake = 3,
/* snake_head_up = 5,
snake_head_down = 6,
snake_head_left = 7,
snake_head_right = 8,
snake_tail_up = 9,
snake_tail_down = 10,
snake_tail_left = 11,
snake_tail_right = 12,
snake_turn_ld = 13,
snake_turn_lu = 14,
snake_turn_rd = 15,
snake_turn_ru = 16,
snake_vertical = 17,
snake_horizontal = 18*/
} }
Type type; Type type;
EntityID id; EntityID id;
@ -86,7 +72,7 @@ struct Snake
bool move_system = true; bool move_system = true;
bool draw_system = true; bool draw_system = true;
const int map_size = 18; enum int map_size = 18;
MapElement[map_size * map_size] map; MapElement[map_size * map_size] map;
@ -97,7 +83,7 @@ struct Snake
if(apple_tmpl)launcher.manager.freeTemplate(apple_tmpl); if(apple_tmpl)launcher.manager.freeTemplate(apple_tmpl);
if(snake_tmpl)launcher.manager.freeTemplate(snake_tmpl); if(snake_tmpl)launcher.manager.freeTemplate(snake_tmpl);
if(snake_destroy_particle)launcher.manager.freeTemplate(snake_destroy_particle); if(snake_destroy_particle)launcher.manager.freeTemplate(snake_destroy_particle);
texture.destory(); texture.destroy();
} }
MapElement element(ivec2 pos) MapElement element(ivec2 pos)
@ -129,10 +115,7 @@ struct Snake
} }
if(base_pos.x == random_pos.x && base_pos.y == random_pos.y)return; if(base_pos.x == random_pos.x && base_pos.y == random_pos.y)return;
} }
//CILocation* location = apple_tmpl.getComponent!CILocation; launcher.manager.addEntity(apple_tmpl,[CLocation(cast(vec2)(random_pos)*16).ref_].staticArray);
//*location = random_pos;
//Entity* apple =
launcher.manager.addEntity(apple_tmpl,[CILocation(random_pos).ref_].staticArray);
} }
} }
@ -158,14 +141,14 @@ struct CILocation
ivec2 location; ivec2 location;
} }
struct CLocation // struct CLocation
{ // {
mixin ECS.Component; // mixin ECS.Component;
alias location this; // alias location this;
vec2 location = vec2(0,0); // vec2 location = vec2(0,0);
} // }
struct CSnake struct CSnake
{ {
@ -252,10 +235,10 @@ struct CMovement
Direction direction; Direction direction;
} }
struct CInput // struct CInput
{ // {
mixin ECS.Component; // mixin ECS.Component;
} // }
struct AppleSystem struct AppleSystem
{ {
@ -264,8 +247,8 @@ struct AppleSystem
struct EntitiesData struct EntitiesData
{ {
uint length; uint length;
@readonly Entity[] entities; @readonly Entity[] entity;
@readonly CApple[] movement; @readonly CApple[] apple;
@readonly CILocation[] location; @readonly CILocation[] location;
} }
@ -273,7 +256,17 @@ struct AppleSystem
{ {
foreach(i;0..data.length) foreach(i;0..data.length)
{ {
snake.element(MapElement(MapElement.Type.apple,data.entities[i].id),data.location[i]); if(snake.element(data.location[i]).id == EntityID())snake.element(MapElement(MapElement.Type.apple,data.entity[i].id),data.location[i]);
else launcher.manager.removeEntity(data.entity[i].id);
}
}
void onRemoveEntity(EntitiesData data)
{
foreach(i;0..data.length)
{
if(snake.element(data.location[i].location).id == data.entity[i].id)
snake.element(MapElement(MapElement.Type.empty, EntityID()),data.location[i].location);
} }
} }
} }
@ -315,7 +308,7 @@ struct ParticleMovementSystem
{ {
foreach(i;0..data.length) foreach(i;0..data.length)
{ {
data.location[i].location -= data.movement[i].velocity; data.location[i] -= data.movement[i].velocity;
} }
} }
} }
@ -355,9 +348,21 @@ struct AnimationRenderSystem
void onUpdate(EntitiesData data) void onUpdate(EntitiesData data)
{ {
import ecs_utils.gfx.renderer;
Renderer.DrawData draw_data;
draw_data.size = vec2(16,16);
//draw_data.coords = vec4(0,0,1,1)*px;
draw_data.color = 0x80808080;
draw_data.material_id = 0;
draw_data.thread_id = 0;
draw_data.texture = snake.texture;
draw_data.depth = -1;
foreach(i;0..data.length) foreach(i;0..data.length)
{ {
launcher.renderer.draw(snake.texture, cast(vec2)cast(ivec2)data.location[i].location, vec2(16,16), data.animation[i].frames[cast(int)(data.animation[i].time)], -1, 0x80808080); draw_data.position = data.location[i];
draw_data.coords = data.animation[i].frames[cast(int)(data.animation[i].time)];
launcher.renderer.draw(draw_data);
//launcher.renderer.draw(snake.texture, cast(vec2)cast(ivec2)data.location[i], vec2(16,16), data.animation[i].frames[cast(int)(data.animation[i].time)], -1, 0x80808080);
} }
} }
} }
@ -477,7 +482,12 @@ struct MoveSystem
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);
if(data.snakes[i].parts.length < 100)data.snakes[i].parts.add(new_location); if(data.snakes[i].parts.length >= 99)
{
snake.addApple();
goto case(MapElement.Type.empty);
}
data.snakes[i].parts.add(new_location);
if(data.snakes[i].parts.length > 1) if(data.snakes[i].parts.length > 1)
{ {
@ -506,7 +516,40 @@ struct MoveSystem
} }
} }
} }
}
}
struct SnakeSystem
{
mixin ECS.System!1;
struct EntitiesData
{
uint length;
Entity[] entity;
@readonly CSnake[] snake;
@readonly CILocation[] location;
}
void onAddSystem(EntitiesData data)
{
foreach(i;0..data.length)
{
if(snake.element(data.location[i]).id == EntityID())snake.element(MapElement(MapElement.Type.snake,data.entity[i].id),data.location[i]);
else launcher.manager.removeEntity(data.entity[i].id);
}
}
void onRemoveEntity(EntitiesData data)
{
foreach(i;0..data.length)
{
if(snake.element(data.location[i].location).id == data.entity[i].id)
snake.element(MapElement(MapElement.Type.empty, EntityID()),data.location[i].location);
foreach(part; data.snake[i].parts.array)
if(snake.element(part).id == data.entity[i].id)
snake.element(MapElement(MapElement.Type.empty, EntityID()),part);
}
} }
} }
@ -618,9 +661,19 @@ struct DrawAppleSystem
void onUpdate(EntitiesData data) void onUpdate(EntitiesData data)
{ {
import ecs_utils.gfx.renderer;
Renderer.DrawData draw_data;
draw_data.size = vec2(16,16);
draw_data.coords = vec4(0,32*px,16*px,16*px);
draw_data.color = 0x80808080;
draw_data.material_id = 0;
draw_data.thread_id = 0;
draw_data.texture = snake.texture;
foreach(i; 0..data.location.length) foreach(i; 0..data.location.length)
{ {
launcher.renderer.draw(snake.texture, vec2(data.location[i].x*16,data.location[i].y*16), vec2(16,16), vec4(0,32*px,16*px,16*px), 0, 0x80808080, 0); draw_data.position = vec2(data.location[i].x*16,data.location[i].y*16);
launcher.renderer.draw(draw_data);
//launcher.renderer.draw(snake.texture, vec2(data.location[i].x*16,data.location[i].y*16), vec2(16,16), vec4(0,32*px,16*px,16*px), 0, 0x80808080, 0);
} }
} }
} }
@ -688,34 +741,49 @@ struct DrawSnakeSystem
static void drawElement(ivec2 loc, SnakePart part) static void drawElement(ivec2 loc, SnakePart part)
{ {
import ecs_utils.gfx.renderer;
Renderer.DrawData draw_data;
draw_data.size = vec2(16,16);
draw_data.color = 0x80808080;
draw_data.texture = snake.texture;
draw_data.position = cast(vec2)loc;
final switch(cast(ubyte)part) final switch(cast(ubyte)part)
{ {
case SnakePart.tail_up:launcher.renderer.draw(.snake.texture, cast(vec2)loc, vec2(16,16), vec4(16,112,16,16)*px, 0, 0x80808080, 0);break; case SnakePart.tail_up:draw_data.coords = vec4(16,112,16,16)*px;break;
case SnakePart.tail_down:launcher.renderer.draw(.snake.texture, cast(vec2)loc, vec2(16,16), vec4(0,112,16,16)*px, 0, 0x80808080, 0);break; case SnakePart.tail_down:draw_data.coords = vec4(0,112,16,16)*px;break;
case SnakePart.tail_left:launcher.renderer.draw(.snake.texture, cast(vec2)loc, vec2(16,16), vec4(32,112,16,16)*px, 0, 0x80808080, 0);break; case SnakePart.tail_left:draw_data.coords = vec4(32,112,16,16)*px;break;
case SnakePart.tail_right:launcher.renderer.draw(.snake.texture, cast(vec2)loc, vec2(16,16), vec4(0,144,16,16)*px, 0, 0x80808080, 0);break; case SnakePart.tail_right:draw_data.coords = vec4(0,144,16,16)*px;break;
case SnakePart.turn_ld:launcher.renderer.draw(.snake.texture, cast(vec2)loc, vec2(16,16), vec4(64,128,16,16)*px, 0, 0x80808080, 0);break; case SnakePart.turn_ld:draw_data.coords = vec4(64,128,16,16)*px;break;
case SnakePart.turn_lu:launcher.renderer.draw(.snake.texture, cast(vec2)loc, vec2(16,16), vec4(32,144,16,16)*px, 0, 0x80808080, 0);break; case SnakePart.turn_lu:draw_data.coords = vec4(32,144,16,16)*px;break;
case SnakePart.turn_rd:launcher.renderer.draw(.snake.texture, cast(vec2)loc, vec2(16,16), vec4(16,144,16,16)*px, 0, 0x80808080, 0);break; case SnakePart.turn_rd:draw_data.coords = vec4(16,144,16,16)*px;break;
case SnakePart.turn_ru:launcher.renderer.draw(.snake.texture, cast(vec2)loc, vec2(16,16), vec4(64,112,16,16)*px, 0, 0x80808080, 0);break; case SnakePart.turn_ru:draw_data.coords = vec4(64,112,16,16)*px;break;
case SnakePart.vertical:launcher.renderer.draw(.snake.texture, cast(vec2)loc, vec2(16,16), vec4(16,128,16,16)*px, 0, 0x80808080, 0);break; case SnakePart.vertical:draw_data.coords = vec4(16,128,16,16)*px;break;
case SnakePart.horizontal:launcher.renderer.draw(.snake.texture, cast(vec2)loc, vec2(16,16), vec4(48,128,16,16)*px, 0, 0x80808080, 0);break; case SnakePart.horizontal:draw_data.coords = vec4(48,128,16,16)*px;break;
} }
launcher.renderer.draw(draw_data);
} }
void onUpdate(EntitiesData data) void onUpdate(EntitiesData data)
{ {
import ecs_utils.gfx.renderer;
Renderer.DrawData draw_data;
draw_data.size = vec2(16,16);
draw_data.color = 0x80808080;
draw_data.texture = snake.texture;
foreach(i; 0..data.length) foreach(i; 0..data.length)
{ {
const (CSnake)* snake = &data.snake[i]; const (CSnake)* snake = &data.snake[i];
scope vec2 loc = cast(vec2)(data.location[i].location * 16); scope vec2 loc = cast(vec2)(data.location[i].location * 16);
draw_data.position = loc;
final switch(snake.direction) final switch(snake.direction)
{ {
case CMovement.Direction.up:launcher.renderer.draw(.snake.texture, vec2(data.location[i].x*16,data.location[i].y*16), vec2(16,16), vec4(48,112,16,16)*px, 0, 0x80808080, 0);break; case CMovement.Direction.up:draw_data.coords = vec4(48,112,16,16)*px;break;
case CMovement.Direction.down:launcher.renderer.draw(.snake.texture, vec2(data.location[i].x*16,data.location[i].y*16), vec2(16,16), vec4(48,144,16,16)*px, 0, 0x80808080, 0);break; case CMovement.Direction.down:draw_data.coords = vec4(48,144,16,16)*px;break;
case CMovement.Direction.left:launcher.renderer.draw(.snake.texture, vec2(data.location[i].x*16,data.location[i].y*16), vec2(16,16), vec4(0,128,16,16)*px, 0, 0x80808080, 0);break; case CMovement.Direction.left:draw_data.coords = vec4(0,128,16,16)*px;break;
case CMovement.Direction.right:launcher.renderer.draw(.snake.texture, vec2(data.location[i].x*16,data.location[i].y*16), vec2(16,16), vec4(32,128,16,16)*px, 0, 0x80808080, 0);break; case CMovement.Direction.right:draw_data.coords = vec4(32,128,16,16)*px;break;
} }
launcher.renderer.draw(draw_data);
if(snake.parts.length >1) if(snake.parts.length >1)
{ {
foreach(j;1..snake.parts.length - 1)drawElement(snake.parts[j]*16, snakePart(snake.parts[j], snake.parts[j+1], snake.parts[j-1])); foreach(j;1..snake.parts.length - 1)drawElement(snake.parts[j]*16, snakePart(snake.parts[j], snake.parts[j+1], snake.parts[j-1]));
@ -750,10 +818,41 @@ struct CleanSystem
} }
} }
struct CopyLocationSystem
{
mixin ECS.System!32;
struct EntitiesData
{
uint length;
const (Entity)[] entity;
CLocation[] location;
@readonly CILocation[] ilocation;
}
void onAddEntity(EntitiesData data)
{
foreach(i;0..data.length)
{
data.ilocation[i] = cast(ivec2)(data.location[i] / 16);
}
}
void onUpdate(EntitiesData data)
{
foreach(i;0..data.length)
{
data.location[i] = cast(vec2)(data.ilocation[i] * 16);
}
}
}
__gshared Snake* snake; __gshared Snake* snake;
void snakeStart() void snakeRegister()
{ {
import game_core.rendering;
snake = Mallocator.make!Snake; snake = Mallocator.make!Snake;
snake.texture.create(); snake.texture.create();
@ -763,6 +862,8 @@ void snakeStart()
launcher.manager.registerPass("fixed"); launcher.manager.registerPass("fixed");
registerRenderingModule(launcher.manager);
launcher.manager.registerComponent!CLocation; launcher.manager.registerComponent!CLocation;
launcher.manager.registerComponent!CILocation; launcher.manager.registerComponent!CILocation;
launcher.manager.registerComponent!CSnake; launcher.manager.registerComponent!CSnake;
@ -776,7 +877,6 @@ void snakeStart()
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!AnimationRenderSystem(100); launcher.manager.registerSystem!AnimationRenderSystem(100);
launcher.manager.registerSystem!AnimationSystem(-1); launcher.manager.registerSystem!AnimationSystem(-1);
launcher.manager.registerSystem!ParticleSystem(-1); launcher.manager.registerSystem!ParticleSystem(-1);
@ -784,7 +884,24 @@ void snakeStart()
launcher.manager.registerSystem!DrawAppleSystem(99); launcher.manager.registerSystem!DrawAppleSystem(99);
launcher.manager.registerSystem!DrawSnakeSystem(101); launcher.manager.registerSystem!DrawSnakeSystem(101);
launcher.manager.registerSystem!CopyLocationSystem(100);
//launcher.manager.registerSystem!AppleRemoveSystem(100);
launcher.manager.registerSystem!AppleSystem(101);
launcher.manager.registerSystem!SnakeSystem(101);
launcher.manager.endRegister(); launcher.manager.endRegister();
}
void snakeStart()
{
launcher.gui_manager.addComponent(CApple(),"Apple");
launcher.gui_manager.addComponent(CSnake(),"Snake");
launcher.gui_manager.addComponent(CParticle(1000),"Particle");
launcher.gui_manager.addComponent(CParticleVector(vec2(0,1)),"Particle Vector");
launcher.gui_manager.addComponent(CInput(),"Input");
launcher.gui_manager.addComponent(CMovement(CMovement.Direction.up),"Movement");
//launcher.gui_manager.addComponent(CAnimation(),"Movement");
launcher.gui_manager.addComponent(CILocation(),"Int Location");
launcher.gui_manager.addSystem(MoveSystem.system_id,"Move System"); launcher.gui_manager.addSystem(MoveSystem.system_id,"Move System");
launcher.gui_manager.addSystem(InputSystem.system_id,"Input System"); launcher.gui_manager.addSystem(InputSystem.system_id,"Input System");
@ -793,19 +910,19 @@ void snakeStart()
launcher.gui_manager.addSystem(AnimationSystem.system_id,"Animation System"); launcher.gui_manager.addSystem(AnimationSystem.system_id,"Animation System");
launcher.gui_manager.addSystem(ParticleSystem.system_id,"Particle Life System"); launcher.gui_manager.addSystem(ParticleSystem.system_id,"Particle Life System");
launcher.gui_manager.addSystem(ParticleMovementSystem.system_id,"Particle Movement System"); launcher.gui_manager.addSystem(ParticleMovementSystem.system_id,"Particle Movement System");
launcher.gui_manager.addSystem(DrawAppleSystem.system_id,"Draw Apple System");
launcher.gui_manager.addSystem(DrawSnakeSystem.system_id,"Draw Snake System");
snake.snake_destroy_particle_frames = Mallocator.makeArray([vec4(64,144,16,16)*px,vec4(80,144,16,16)*px,vec4(96,144,16,16)*px,vec4(112,144,16,16)*px].staticArray); snake.snake_destroy_particle_frames = Mallocator.makeArray([vec4(64,144,16,16)*px,vec4(80,144,16,16)*px,vec4(96,144,16,16)*px,vec4(112,144,16,16)*px].staticArray);
{ {
ushort[4] components = [CILocation.component_id, CSnake.component_id, CMovement.component_id, CInput.component_id]; ushort[5] components = [CILocation.component_id, CSnake.component_id, CMovement.component_id, CInput.component_id, CLocation.component_id];
snake.snake_tmpl = launcher.manager.allocateTemplate(components); snake.snake_tmpl = launcher.manager.allocateTemplate(components);
//CILocation* loc_comp = snake.snake_tmpl.getComponent!CILocation;
//*loc_comp = ivec2(2,2);
launcher.manager.addEntity(snake.snake_tmpl,[CILocation(ivec2(2,2)).ref_].staticArray); launcher.manager.addEntity(snake.snake_tmpl,[CILocation(ivec2(2,2)).ref_].staticArray);
} }
{ {
snake.snake_destroy_particle = launcher.manager.allocateTemplate([CLocation.component_id, CParticle.component_id, CParticleVector.component_id, CAnimation.component_id].staticArray); snake.snake_destroy_particle = launcher.manager.allocateTemplate([CLocation.component_id, CParticle.component_id, CParticleVector.component_id, CAnimation.component_id, CLocation.component_id].staticArray);
CAnimation* canim = snake.snake_destroy_particle.getComponent!CAnimation; CAnimation* canim = snake.snake_destroy_particle.getComponent!CAnimation;
canim.frames = snake.snake_destroy_particle_frames; canim.frames = snake.snake_destroy_particle_frames;
CParticle* particle = snake.snake_destroy_particle.getComponent!CParticle; CParticle* particle = snake.snake_destroy_particle.getComponent!CParticle;
@ -813,7 +930,7 @@ void snakeStart()
} }
{ {
ushort[2] components = [CILocation.component_id, CApple.component_id]; ushort[3] components = [CILocation.component_id, CApple.component_id, CLocation.component_id];
snake.apple_tmpl = launcher.manager.allocateTemplate(components); snake.apple_tmpl = launcher.manager.allocateTemplate(components);
snake.addApple(); snake.addApple();
} }
@ -824,13 +941,6 @@ void snakeStart()
MoveSystem* move_system = launcher.manager.getSystem!MoveSystem(); MoveSystem* move_system = launcher.manager.getSystem!MoveSystem();
move_system.setTemplates(); move_system.setTemplates();
/*foreach(i; 0..10)
foreach(j; 0..10)
{
loc_compation = vec2(i*32+64,j*32+64);
launcher.manager.addEntity(simple.tmpl);
}*/
} }
void snakeEnd() void snakeEnd()
@ -839,39 +949,6 @@ void snakeEnd()
Mallocator.dispose(snake); Mallocator.dispose(snake);
} }
void snakeTool(vec2 position, Tool tool, int size)
{
switch(tool)
{
case Tool.entity_spawner:
{
EntityTemplate* tmpl = launcher.gui_manager.getSelectedTemplate();
CLocation* location = tmpl.getComponent!CLocation;
if(location)
{
position.x += (randomf() - 0.5) * size;
position.y += (randomf() - 0.5) * size;
*location = position;
}
CILocation* ilocation = tmpl.getComponent!CILocation;
if(ilocation)
{
position.x += (randomf() - 0.5) * size;
position.y += (randomf() - 0.5) * size;
ivec2 ipos;
ipos.x = cast(int)(position.x / 16);
ipos.y = cast(int)(position.y / 16);
*ilocation = ipos;
if(snake.element(ipos).type != MapElement.Type.empty)return;
}
launcher.manager.addEntity(tmpl);
}
break;
default:
break;
}
}
void snakeEvent(SDL_Event* event) void snakeEvent(SDL_Event* event)
{ {
@ -881,16 +958,16 @@ bool snakeLoop()
{ {
launcher.render_position = (vec2(launcher.window_size.x,launcher.window_size.y)*launcher.scalling - vec2(288,288)) * 0.5; 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));
igSetNextWindowSize(ImVec2(250, 0), ImGuiCond_Once); // igSetNextWindowSize(ImVec2(250, 0), ImGuiCond_Once);
if(igBegin("Snake",&launcher.show_demo_wnd,0)) // if(igBegin("Snake",&launcher.show_demo_wnd,0))
{ // {
} // }
igEnd(); // igEnd();
}*/ // }
launcher.manager.begin(); launcher.manager.begin();
@ -901,9 +978,9 @@ bool snakeLoop()
if(launcher.getKeyState(SDL_SCANCODE_SPACE))time += delta_time * 3; if(launcher.getKeyState(SDL_SCANCODE_SPACE))time += delta_time * 3;
else time += delta_time; else time += delta_time;
while(time > 100) while(time > 200)
{ {
time -= 100; time -= 200;
launcher.manager.update("fixed"); launcher.manager.update("fixed");
} }
@ -912,7 +989,16 @@ bool snakeLoop()
launcher.manager.end(); launcher.manager.end();
//snake.drawMap();
return true; return true;
} }
DemoCallbacks getSnakeDemo()
{
DemoCallbacks demo;
demo.register = &snakeRegister;
demo.initialize = &snakeStart;
demo.deinitialize = &snakeEnd;
demo.loop = &snakeLoop;
demo.tips = snake.tips;
return demo;
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,255 @@
module game_core.basic;
import bubel.ecs.core;
import bubel.ecs.attributes;
import ecs_utils.math.vector;
import gui.attributes;
import ecs_utils.utils;
import app : launcher;
import bindbc.sdl;
struct CLocation
{
mixin ECS.Component;
alias value this;
vec2 value = vec2(0);
}
struct CScale
{
mixin ECS.Component;
alias value this;///use component as it value
vec2 value = vec2(16,16);
}
struct CRotation
{
mixin ECS.Component;
alias value this;///use component as it value
float value = 0;
}
struct CDepth
{
mixin ECS.Component;
alias value this;
short value;
}
struct CColor
{
mixin ECS.Component;
alias value this;
@GUIColor uint value;
}
struct CSelected
{
mixin ECS.Component;
bool value = false;
}
struct CInput
{
mixin ECS.Component;
}
struct CDamping
{
mixin ECS.Component;
alias value this;
@GUIRange(0,9) byte value = 1;
}
struct CVelocity
{
mixin ECS.Component;
alias value this;
vec2 value = vec2(0,0);
}
struct CVelocityFactor
{
mixin ECS.Component;
alias value this;
vec2 value = vec2(1);
}
struct DampingSystem
{
mixin ECS.System!32;
struct EntitiesData
{
uint length;
const (Entity)[] entity;
@readonly CDamping[] damping;
CVelocity[] velocity;
}
float[20] damp = 0;
bool onBegin()
{
foreach(i;0..20)
{
damp[i] = powf((0.99 - cast(float)i * 0.01),launcher.delta_time*0.1);
}
return true;
}
void onUpdate(EntitiesData data)
{
foreach(i; 0..data.length)
{
data.velocity[i] = data.velocity[i] * damp[data.damping[i]];
}
}
}
struct MoveSystem
{
mixin ECS.System!64;
struct EntitiesData
{
uint length;
CLocation[] location;
@readonly CVelocity[] velocity;
@optional @readonly CVelocityFactor[] vel_factor;
}
void onUpdate(EntitiesData data)
{
if(data.vel_factor)
{
foreach(i; 0..data.length)
{
data.location[i] += data.velocity[i] * data.vel_factor[i] * launcher.delta_time;
}
}
else
{
foreach(i; 0..data.length)
{
data.location[i] += data.velocity[i] * launcher.delta_time;
}
}
}
}
/**
*System is responsible for movement of objects with CInput component.
*In this example every entity has same speed when using movement system.
*/
struct InputMovementSystem
{
mixin ECS.System!32;
vec2 move_vector;
struct EntitiesData
{
uint length;
//read only components can be marked with @readonly attribute or with const expression instead
const (CInput)[] input;
//components are treated as required by default
//CLocation[] locations;
CVelocity[] velocity;
//CTexture[] textures;
}
/**
*onBegin gives opportunity to check keys once and call update on entities only when
*one key is pressed.
*/
bool onBegin()
{
move_vector = vec2(0,0);
if(launcher.getKeyState(SDL_SCANCODE_W))
{
move_vector += vec2(0,1);
}
else if(launcher.getKeyState(SDL_SCANCODE_S))
{
move_vector += vec2(0,-1);
}
if(launcher.getKeyState(SDL_SCANCODE_A))
{
move_vector += vec2(-1,0);
}
else if(launcher.getKeyState(SDL_SCANCODE_D))
{
move_vector += vec2(1,0);
}
if(move_vector.x != 0 ||move_vector.y != 0)
{
move_vector = move_vector / sqrtf(move_vector.x * move_vector.x + move_vector.y * move_vector.y);
return true;
}
//don't call system update because no key pressed
return false;
}
/**
*Update is called multiple times in one "manager.update()" call.
*Number of "onUpdate" calls is count of buffers which must be updated during pass.
*When multithreading is used, number of "onUpdate" calls can be greater due to fact that
*JobSystem can split buffers for better data packing.
*/
void onUpdate(EntitiesData data)
{
/*if(move_vector.x == 0)
{
foreach(i; 0..data.length)
{
data.textures[i].coords = vec4(0*px,80*px,48*px,32*px);
}
//return;
}*/
//move every entity using movement vector
//if(move_vector.x != 0 || move_vector.y != 0)
foreach(i; 0..data.length)
{
data.velocity[i] += move_vector * launcher.delta_time * 0.005;
if(data.velocity[i].x > 0.5)data.velocity[i].x = 0.5;
else if(data.velocity[i].x < -0.5)data.velocity[i].x = -0.5;
if(data.velocity[i].y > 0.5)data.velocity[i].y = 0.5;
else if(data.velocity[i].y < -0.5)data.velocity[i].y = -0.5;
//data.locations[i].x += move_vector.x * launcher.delta_time * 0.25;
//data.locations[i].y += move_vector.y * launcher.delta_time * 0.25;
//if(move_vector.x > 0)data.textures[i].coords = vec4(48*px,80*px,48*px,32*px);
//else data.textures[i].coords = vec4(0*px,80*px,48*px,32*px);
}
/*else
foreach(i; 0..data.length)
{
data.velocity[i] = vec2(0,0);
}*/
}
}

File diff suppressed because it is too large Load diff

View file

@ -37,12 +37,17 @@ struct ECSJobUpdater
//pool.unregistExternalThread(thread_data); //pool.unregistExternalThread(thread_data);
if(jobs)Mallocator.dispose(jobs); if(jobs)Mallocator.dispose(jobs);
version(WebAssembly)pthread_key_delete(tls_key); version(WebAssembly)pthread_key_delete(tls_key);
else version(Android)pthread_key_delete(tls_key);
} }
version(WebAssembly) version(WebAssembly)
{ {
__gshared pthread_key_t tls_key; __gshared pthread_key_t tls_key;
} }
else version(Android)
{
__gshared pthread_key_t tls_key;
}
else static uint thread_id = 0; else static uint thread_id = 0;
ThreadPool pool; ThreadPool pool;
@ -105,6 +110,7 @@ struct ECSJobUpdater
void onCreate(uint threads_count) void onCreate(uint threads_count)
{ {
version(WebAssembly)pthread_key_create(&tls_key, null); version(WebAssembly)pthread_key_create(&tls_key, null);
else version(Android)pthread_key_create(&tls_key, null);
pool.initialize(); pool.initialize();
thread_data = pool.registerExternalThread(); thread_data = pool.registerExternalThread();
@ -116,6 +122,7 @@ struct ECSJobUpdater
uint getThreadID() @nogc nothrow uint getThreadID() @nogc nothrow
{ {
version(WebAssembly)return cast(int)pthread_getspecific(tls_key); version(WebAssembly)return cast(int)pthread_getspecific(tls_key);
else version(Android)return cast(int)pthread_getspecific(tls_key);
else return thread_id; else return thread_id;
} }
@ -200,6 +207,11 @@ struct ECSJobUpdater
} }
else job.execute(); else job.execute();
} }
else version(Android)
{
pthread_setspecific(tls_key, cast(void*)th_data.threadId);
job.execute();
}
else else
{ {
updater.thread_id = th_data.threadId; updater.thread_id = th_data.threadId;

View file

@ -0,0 +1,616 @@
module game_core.rendering;
import bubel.ecs.attributes;
import bubel.ecs.core;
import bubel.ecs.std;
import ecs_utils.gfx.texture;
import ecs_utils.math.vector;
import game_core.basic;
void registerRenderingModule(EntityManager* manager)
{
manager.registerComponent!CLocation;
manager.registerComponent!CScale;
manager.registerComponent!CRotation;
manager.registerComponent!CDepth;
manager.registerComponent!CColor;
manager.registerComponent!CSelected;
manager.registerComponent!CTexCoords;
manager.registerComponent!CTexCoordsIndex;
manager.registerComponent!CMaterialIndex;
manager.registerComponent!CDrawDefault;
manager.registerSystem!DrawSystem(100);
}
struct CTexCoords
{
mixin ECS.Component;
alias value this;///use component as it value
vec4 value;
}
struct CTexCoordsIndex
{
mixin ECS.Component;
alias value this;
ushort value;
}
struct CMaterialIndex
{
mixin ECS.Component;
alias value this;
ushort value;
}
struct CDrawDefault
{
mixin ECS.Component;
}
struct TexCoordsManager
{
import bubel.ecs.vector;
import bubel.ecs.hash_map;
__gshared TexCoordsManager* instance = null;
static void initialize()
{
if(instance is null)instance = Mallocator.make!TexCoordsManager;
}
static void destroy()
{
if(instance)Mallocator.dispose(instance);
instance = null;
}
vec4 get(ushort index)
{
if(index > coords.length)return vec4(0,0,1,1);
else return coords[index];
}
ushort getCoordIndex(vec4 coords)
{
ushort ret = coords_map.get(coords, ushort.max);
if(ret != ushort.max)
{
return ret;
}
this.coords.add(coords);
coords_map.add(coords, cast(ushort)(this.coords.length - 1));
return cast(ushort)(this.coords.length - 1);
}
Vector!vec4 coords;
HashMap!(vec4,ushort) coords_map;
}
struct DrawSystem
{
mixin ECS.System!32;
import ecs_utils.gfx.renderer : Renderer;
struct EntitiesData
{
uint length;
//uint thread_id;
uint job_id;
const(Entity)[] entity;
@readonly CLocation[] locations;
@readonly @optional CScale[] scale;
// @readonly CTexCoords[] texcoord;
@readonly @optional CTexCoords[] texcoord;
@readonly @optional CTexCoordsIndex[] texcoord_index;
@readonly @optional CRotation[] rotation;
@readonly @optional CDepth[] depth;
@readonly @optional CColor[] color;
@readonly @optional CMaterialIndex[] material;
@readonly @optional CDrawDefault[] draw_default;
}
Renderer.DrawData default_data;
float color_time = 0;
uint select_color = 0;
bool onBegin()
{
import app : launcher;
color_time += launcher.delta_time * 0.001;
color_time = color_time - cast(int)(color_time*0.5)*2;
float ratio = color_time - cast(int)color_time;
if(color_time > 1)ratio = 1 - ratio;
uint multipler = cast(uint)(0x60 * ratio);
select_color = 0xA0A0A0A0 + cast(uint)(0x01010101 * multipler);
return true;
}
void onUpdate(EntitiesData data)
{
import app : launcher;
if(launcher.renderer.prepared_items >= launcher.renderer.MaxObjects)return;//simple leave loop if max visible objects count was reached
Renderer.DrawData draw_data = default_data;
draw_data.thread_id = data.job_id;
if(launcher.show_filtered && launcher.filterEntity(data.entity[0]))
{
draw_data.color = select_color;
data.color = null;
}
//import std.stdio;
//writeln(data.draw_default);
//if(data.draw_default is null && data.texcoord is null && data.texcoord_index is null && !data.entity[0].hasComponent(CDrawDefault.component_id))return;
if(data.texcoord is null && data.texcoord_index is null && data.draw_default is null)return;
foreach(i; 0..data.length)
{
draw_data.position = data.locations[i];
if(data.color)draw_data.color = data.color[i];
if(data.depth)draw_data.depth = data.depth[i];
if(data.rotation)draw_data.angle = data.rotation[i];
if(data.scale)draw_data.size = data.scale[i];
if(data.texcoord)draw_data.coords = data.texcoord[i];
else if(data.texcoord_index)draw_data.coords = TexCoordsManager.instance.get(data.texcoord_index[i]);
if(data.material)draw_data.material_id = data.material[i];
launcher.renderer.draw(draw_data);
}//*/
/*
ubyte mode;
if(data.scale)mode |= 0x01;
if(data.texcoord)mode |= 0x02;
if(data.texcoord_index)mode |= 0x04;
if(data.rotation)mode |= 0x08;
if(data.depth)mode |= 0x10;
if(data.color)mode |= 0x20;
if(launcher.show_filtered && launcher.filterEntity(data.entity[0]))
{
draw_data.color = select_color;
mode &= ~0x20;
//goto draw_nocolor;
}
switch(mode)
{
case 0:
foreach(i; 0..data.length)
{
draw_data.position = data.locations[i];
launcher.renderer.draw(draw_data);
}
break;
case 0b000001:
foreach(i; 0..data.length)
{
draw_data.position = data.locations[i];
draw_data.size = data.scale[i];
launcher.renderer.draw(draw_data);
}
break;
case 0b000010:
foreach(i; 0..data.length)
{
draw_data.position = data.locations[i];
draw_data.coords = data.texcoord[i];
launcher.renderer.draw(draw_data);
}
break;
case 0b000011:
foreach(i; 0..data.length)
{
draw_data.position = data.locations[i];
draw_data.size = data.scale[i];
draw_data.coords = data.texcoord[i];
launcher.renderer.draw(draw_data);
}
break;
case 0b001000:
foreach(i; 0..data.length)
{
draw_data.position = data.locations[i];
draw_data.angle = data.rotation[i];
launcher.renderer.draw(draw_data);
}
break;
case 0b001001:
foreach(i; 0..data.length)
{
draw_data.position = data.locations[i];
draw_data.angle = data.rotation[i];
draw_data.size = data.scale[i];
launcher.renderer.draw(draw_data);
}
break;
case 0b001010:
foreach(i; 0..data.length)
{
draw_data.position = data.locations[i];
draw_data.angle = data.rotation[i];
draw_data.coords = data.texcoord[i];
launcher.renderer.draw(draw_data);
}
break;
case 0b001011:
foreach(i; 0..data.length)
{
draw_data.position = data.locations[i];
draw_data.angle = data.rotation[i];
draw_data.size = data.scale[i];
draw_data.coords = data.texcoord[i];
launcher.renderer.draw(draw_data);
}
break;
case 0b010000:
foreach(i; 0..data.length)
{
draw_data.position = data.locations[i];
draw_data.depth = data.depth[i];
launcher.renderer.draw(draw_data);
}
break;
case 0b010001:
foreach(i; 0..data.length)
{
draw_data.position = data.locations[i];
draw_data.depth = data.depth[i];
draw_data.size = data.scale[i];
launcher.renderer.draw(draw_data);
}
break;
case 0b010010:
foreach(i; 0..data.length)
{
draw_data.position = data.locations[i];
draw_data.depth = data.depth[i];
draw_data.coords = data.texcoord[i];
launcher.renderer.draw(draw_data);
}
break;
case 0b010011:
foreach(i; 0..data.length)
{
draw_data.position = data.locations[i];
draw_data.depth = data.depth[i];
draw_data.size = data.scale[i];
draw_data.coords = data.texcoord[i];
launcher.renderer.draw(draw_data);
}
break;
case 0b011000:
foreach(i; 0..data.length)
{
draw_data.position = data.locations[i];
draw_data.depth = data.depth[i];
draw_data.angle = data.rotation[i];
launcher.renderer.draw(draw_data);
}
break;
case 0b011001:
foreach(i; 0..data.length)
{
draw_data.position = data.locations[i];
draw_data.depth = data.depth[i];
draw_data.angle = data.rotation[i];
draw_data.size = data.scale[i];
launcher.renderer.draw(draw_data);
}
break;
case 0b011010:
foreach(i; 0..data.length)
{
draw_data.position = data.locations[i];
draw_data.depth = data.depth[i];
draw_data.angle = data.rotation[i];
draw_data.coords = data.texcoord[i];
launcher.renderer.draw(draw_data);
}
break;
case 0b011011:
foreach(i; 0..data.length)
{
draw_data.position = data.locations[i];
draw_data.depth = data.depth[i];
draw_data.angle = data.rotation[i];
draw_data.size = data.scale[i];
draw_data.coords = data.texcoord[i];
launcher.renderer.draw(draw_data);
}
break;
case 0b100000:
foreach(i; 0..data.length)
{
draw_data.position = data.locations[i];
draw_data.color = data.color[i];
launcher.renderer.draw(draw_data);
}
break;
case 0b100001:
foreach(i; 0..data.length)
{
draw_data.position = data.locations[i];
draw_data.color = data.color[i];
draw_data.size = data.scale[i];
launcher.renderer.draw(draw_data);
}
break;
case 0b100010:
foreach(i; 0..data.length)
{
draw_data.position = data.locations[i];
draw_data.color = data.color[i];
draw_data.coords = data.texcoord[i];
launcher.renderer.draw(draw_data);
}
break;
case 0b100011:
foreach(i; 0..data.length)
{
draw_data.position = data.locations[i];
draw_data.color = data.color[i];
draw_data.size = data.scale[i];
draw_data.coords = data.texcoord[i];
launcher.renderer.draw(draw_data);
}
break;
case 0b101000:
foreach(i; 0..data.length)
{
draw_data.position = data.locations[i];
draw_data.color = data.color[i];
draw_data.angle = data.rotation[i];
launcher.renderer.draw(draw_data);
}
break;
case 0b101001:
foreach(i; 0..data.length)
{
draw_data.position = data.locations[i];
draw_data.color = data.color[i];
draw_data.angle = data.rotation[i];
draw_data.size = data.scale[i];
launcher.renderer.draw(draw_data);
}
break;
case 0b101010:
foreach(i; 0..data.length)
{
draw_data.position = data.locations[i];
draw_data.color = data.color[i];
draw_data.angle = data.rotation[i];
draw_data.coords = data.texcoord[i];
launcher.renderer.draw(draw_data);
}
break;
case 0b101011:
foreach(i; 0..data.length)
{
draw_data.position = data.locations[i];
draw_data.color = data.color[i];
draw_data.angle = data.rotation[i];
draw_data.size = data.scale[i];
draw_data.coords = data.texcoord[i];
launcher.renderer.draw(draw_data);
}
break;
case 0b110000:
foreach(i; 0..data.length)
{
draw_data.position = data.locations[i];
draw_data.color = data.color[i];
draw_data.depth = data.depth[i];
launcher.renderer.draw(draw_data);
}
break;
case 0b110001:
foreach(i; 0..data.length)
{
draw_data.position = data.locations[i];
draw_data.color = data.color[i];
draw_data.depth = data.depth[i];
draw_data.size = data.scale[i];
launcher.renderer.draw(draw_data);
}
break;
case 0b110010:
foreach(i; 0..data.length)
{
draw_data.position = data.locations[i];
draw_data.color = data.color[i];
draw_data.depth = data.depth[i];
draw_data.coords = data.texcoord[i];
launcher.renderer.draw(draw_data);
}
break;
case 0b110011:
foreach(i; 0..data.length)
{
draw_data.position = data.locations[i];
draw_data.color = data.color[i];
draw_data.depth = data.depth[i];
draw_data.size = data.scale[i];
draw_data.coords = data.texcoord[i];
launcher.renderer.draw(draw_data);
}
break;
case 0b111000:
foreach(i; 0..data.length)
{
draw_data.position = data.locations[i];
draw_data.color = data.color[i];
draw_data.depth = data.depth[i];
draw_data.angle = data.rotation[i];
launcher.renderer.draw(draw_data);
}
break;
case 0b111001:
foreach(i; 0..data.length)
{
draw_data.position = data.locations[i];
draw_data.color = data.color[i];
draw_data.depth = data.depth[i];
draw_data.angle = data.rotation[i];
draw_data.size = data.scale[i];
launcher.renderer.draw(draw_data);
}
break;
case 0b111010:
foreach(i; 0..data.length)
{
draw_data.position = data.locations[i];
draw_data.color = data.color[i];
draw_data.depth = data.depth[i];
draw_data.angle = data.rotation[i];
draw_data.coords = data.texcoord[i];
launcher.renderer.draw(draw_data);
}
break;
case 0b111011:
foreach(i; 0..data.length)
{
draw_data.position = data.locations[i];
draw_data.color = data.color[i];
draw_data.depth = data.depth[i];
draw_data.angle = data.rotation[i];
draw_data.size = data.scale[i];
draw_data.coords = data.texcoord[i];
launcher.renderer.draw(draw_data);
}
break;
default:break;
}//*/
/*
if(!data.color)
{
draw_nocolor:
if(!data.depth)
{
if(!data.rotation)
{
foreach(i; 0..data.length)
{
draw_data.coords = data.texcoord[i];
draw_data.size = data.scale[i];
draw_data.position = data.locations[i];
launcher.renderer.draw(draw_data);
}
}
else
{
foreach(i; 0..data.length)
{
draw_data.angle = data.rotation[i];
draw_data.coords = data.texcoord[i];
draw_data.size = data.scale[i];
draw_data.position = data.locations[i];
launcher.renderer.draw(draw_data);
}
}
}
else
{
if(!data.rotation)
{
foreach(i; 0..data.length)
{
draw_data.depth = data.depth[i];
draw_data.coords = data.texcoord[i];
draw_data.size = data.scale[i];
draw_data.position = data.locations[i];
launcher.renderer.draw(draw_data);
}
}
else
{
foreach(i; 0..data.length)
{
draw_data.depth = data.depth[i];
draw_data.angle = data.rotation[i];
draw_data.coords = data.texcoord[i];
draw_data.size = data.scale[i];
draw_data.position = data.locations[i];
launcher.renderer.draw(draw_data);
}
}
}
}
else
{
if(!data.depth)
{
if(!data.rotation)
{
foreach(i; 0..data.length)
{
draw_data.color = data.color[i];
draw_data.coords = data.texcoord[i];
draw_data.size = data.scale[i];
draw_data.position = data.locations[i];
launcher.renderer.draw(draw_data);
}
}
else
{
foreach(i; 0..data.length)
{
draw_data.color = data.color[i];
draw_data.angle = data.rotation[i];
draw_data.coords = data.texcoord[i];
draw_data.size = data.scale[i];
draw_data.position = data.locations[i];
launcher.renderer.draw(draw_data);
}
}
}
else
{
if(!data.rotation)
{
foreach(i; 0..data.length)
{
draw_data.depth = data.depth[i];
draw_data.color = data.color[i];
draw_data.coords = data.texcoord[i];
draw_data.size = data.scale[i];
draw_data.position = data.locations[i];
launcher.renderer.draw(draw_data);
}
}
else
{
foreach(i; 0..data.length)
{
draw_data.depth = data.depth[i];
draw_data.color = data.color[i];
draw_data.coords = data.texcoord[i];
draw_data.size = data.scale[i];
draw_data.position = data.locations[i];
launcher.renderer.draw(draw_data);
}
}
}
}*/
}
}

View file

@ -0,0 +1,20 @@
module gui.attributes;
enum GUIColor = "GUIColor";
struct GUIRange
{
union
{
struct
{
int min;
int max;
}
struct
{
float minf;
float maxf;
}
}
}

View file

@ -1,6 +1,63 @@
module gui.components; module gui.component;
import ecs_utils.utils;
struct ComponentGUI struct ComponentGUI
{ {
const (char)* name;
void* data;
ushort component_id;
}
struct ComponentEditGUI
{
const (char)* name;
VariableGUI[] variables;
uint used;
}
struct VariableGUI
{
struct Int
{
int min;
int max;
}
struct Float
{
float min;
float max;
}
struct Enum
{
const (char)[][] strings;
}
enum Type
{
byte_,
ubyte_,
short_,
ushort_,
int_,
uint_,
float_,
enum_,
color,
vec2,
ivec2,
vec4,
ivec4
}
Type type;
const (char)* name;
ushort offset;
union
{
Int int_;
Float float_;
Enum enum_;
}
} }

View file

@ -4,22 +4,55 @@ import app;
import cimgui.cimgui; import cimgui.cimgui;
import bubel.ecs.entity;
import bubel.ecs.manager;
import bubel.ecs.std; import bubel.ecs.std;
import bubel.ecs.system; import bubel.ecs.system;
import bubel.ecs.vector; import bubel.ecs.vector;
import bubel.ecs.entity;
import ecs_utils.math.vector;
import gui.attributes;
import gui.component;
import gui.system; import gui.system;
import gui.template_; import gui.template_;
import std.traits;
extern(C): extern(C):
struct GUIManager struct GUIManager
{ {
Vector!SystemGUI systems; Vector!SystemGUI systems;
Vector!ComponentGUI components;
Vector!TemplateGUI templates; Vector!TemplateGUI templates;
Vector!ComponentEditGUI edit_components;
Vector!bool filter;
Vector!ushort filter_list;
uint selected_tempalte = 0; int selected_template = 0;
int selected_component = 0;
~this()
{
clear();
}
void selectTemplate(int id)
{
if(templates.length == 0)return;
selected_template = id;
while(selected_template < 0)selected_template += cast(int)templates.length;
while(selected_template >= templates.length)selected_template -= cast(int)templates.length;
}
void selectComponent(int id)
{
if(components.length == 0)return;
selected_component = id;
while(selected_component < 0)selected_component += cast(int)components.length;
while(selected_component >= components.length)selected_component -= cast(int)components.length;
}
void clear() void clear()
{ {
@ -27,23 +60,51 @@ struct GUIManager
{ {
launcher.manager.freeTemplate(tmpl.tmpl); launcher.manager.freeTemplate(tmpl.tmpl);
} }
foreach(comp; components)
{
free(comp.data);
}
foreach(ref comp; edit_components)
{
if(comp.variables)Mallocator.dispose(comp.variables);
comp.variables = null;
comp.used = 0;
comp.name = null;
}
foreach(ref comp; filter)
{
comp = false;
}
filter_list.clear();
systems.clear(); systems.clear();
templates.clear(); templates.clear();
selected_tempalte = 0; components.clear();
selected_template = 0;
selected_component = 0;
} }
EntityTemplate* getSelectedTemplate() EntityTemplate* getSelectedTemplate()
{ {
if(templates.length > selected_tempalte)return templates[selected_tempalte].tmpl; if(templates.length > selected_template)return templates[selected_template].tmpl;
else return null; else return null;
} }
ComponentRef getSelectedComponent()
{
if(components.length > selected_component)return ComponentRef(components[selected_component].data, components[selected_component].component_id);
else return ComponentRef(null, ushort.max);
}
void addSystem(ushort id, const (char)* name, bool enabled = true) void addSystem(ushort id, const (char)* name, bool enabled = true)
{ {
foreach(ref sys; systems)
{
if(sys.id == id)return;
}
System* system = launcher.manager.getSystem(id); System* system = launcher.manager.getSystem(id);
//const (char)* name = //const (char)* name =
systems.add(SystemGUI(name,system,enabled)); systems.add(SystemGUI(name,id,enabled));
} }
void addTemplate(ushort[] components, const (char)* name) void addTemplate(ushort[] components, const (char)* name)
@ -56,43 +117,394 @@ struct GUIManager
templates.add(TemplateGUI(name, tmpl)); templates.add(TemplateGUI(name, tmpl));
} }
// void addComponent(ComponentRef comp, const (char)* name)
// {
// uint size = EntityManager.instance.components[comp.component_id].size;
// void* data = malloc(size);
// memcpy(data, comp.ptr, size);
// components.add(ComponentGUI(name, data, comp.component_id));
// }
void addComponent(T)(T comp, const (char)* name)
{
static assert(hasStaticMember!(T,"component_id"));
uint size = EntityManager.instance.components[comp.component_id].size;
void* data = malloc(size);
memcpy(data, &comp, size);
components.add(ComponentGUI(name, data, comp.component_id));
if(edit_components.length <= comp.component_id)
{
edit_components.length = comp.component_id+1;//.extend(comp.component_id + 1);
}
//edit_components[comp.component_id] = ComponentEditGUI(name);
if(edit_components[comp.component_id].variables)return;
ComponentEditGUI comp_edit;
comp_edit.name = T.stringof;
//enum fields = __traits(allMembers, T);
alias fields = FieldNameTuple!T;
//pragma(msg,fields);
comp_edit.variables = Mallocator.makeArray!VariableGUI(fields.length);
foreach(member_str; fields)
{
alias member = __traits(getMember, T, member_str);
alias member_type = typeof(member);
//pragma(msg,member);
//pragma(msg,member_type);
//pragma(msg,__traits(getMember, T, member).offsetof);
ushort offset = member.offsetof;//cast(ushort)__traits(getMember, T, member).offsetof;
static if(is(member_type == vec2))
{
comp_edit.variables[comp_edit.used++] = VariableGUI(VariableGUI.Type.vec2,member_str,offset);
}
else static if(is(member_type == ivec2))
{
comp_edit.variables[comp_edit.used++] = VariableGUI(VariableGUI.Type.ivec2,member_str,offset);
}
else static if(is(member_type == vec4))
{
comp_edit.variables[comp_edit.used++] = VariableGUI(VariableGUI.Type.vec4,member_str,offset);
}
else static if(is(member_type == ivec4))
{
comp_edit.variables[comp_edit.used++] = VariableGUI(VariableGUI.Type.ivec4,member_str,offset);
}
else static if(__traits(isIntegral,member_type))
{
static if(__traits(isUnsigned, member_type))
{
static if(hasUDA!(member,GUIColor))
{
comp_edit.variables[comp_edit.used++] = VariableGUI(VariableGUI.Type.color,member_str,offset);
}
else switch(member_type.sizeof)
{
case 1: comp_edit.variables[comp_edit.used++] = VariableGUI(VariableGUI.Type.ubyte_,member_str,offset);break;
case 2: comp_edit.variables[comp_edit.used++] = VariableGUI(VariableGUI.Type.ushort_,member_str,offset);break;
case 4: comp_edit.variables[comp_edit.used++] = VariableGUI(VariableGUI.Type.uint_,member_str,offset);break;
default:break;
}
static if(hasUDA!(member,GUIRange))
{
comp_edit.variables[comp_edit.used-1].int_.min = getUDAs!(member,GUIRange)[0].min;
comp_edit.variables[comp_edit.used-1].int_.max = getUDAs!(member,GUIRange)[0].max;
}
else
{
comp_edit.variables[comp_edit.used-1].int_.min = 0;
comp_edit.variables[comp_edit.used-1].int_.max = int.max;
}
}
else
{
switch(member_type.sizeof)
{
case 1:
comp_edit.variables[comp_edit.used++] = VariableGUI(VariableGUI.Type.byte_,member_str,offset);
comp_edit.variables[comp_edit.used-1].int_.min = byte.min;
comp_edit.variables[comp_edit.used-1].int_.max = byte.max;
break;
case 2:
comp_edit.variables[comp_edit.used++] = VariableGUI(VariableGUI.Type.short_,member_str,offset);
comp_edit.variables[comp_edit.used-1].int_.min = short.min;
comp_edit.variables[comp_edit.used-1].int_.max = short.max;
break;
case 4:
comp_edit.variables[comp_edit.used++] = VariableGUI(VariableGUI.Type.int_,member_str,offset);
comp_edit.variables[comp_edit.used-1].int_.min = int.min;
comp_edit.variables[comp_edit.used-1].int_.max = int.max;
break;
default:break;
}
static if(hasUDA!(member,GUIRange))
{
comp_edit.variables[comp_edit.used-1].int_.min = getUDAs!(member,GUIRange)[0].min;
comp_edit.variables[comp_edit.used-1].int_.max = getUDAs!(member,GUIRange)[0].max;
}
/*{
comp_edit.variables[comp_edit.used-1].int_.min = int.min;
comp_edit.variables[comp_edit.used-1].int_.max = int.max;
}*/
}
}
else static if(__traits(isScalar,member_type))
{
switch(member_type.sizeof)
{
case 4:comp_edit.variables[comp_edit.used++] = VariableGUI(VariableGUI.Type.float_,member_str,offset);break;
case 8:
default:break;
}
static if(hasUDA!(member,GUIRange))
{
comp_edit.variables[comp_edit.used-1].float_.min = getUDAs!(member,GUIRange)[0].minf;
comp_edit.variables[comp_edit.used-1].float_.max = getUDAs!(member,GUIRange)[1].maxf;
}
{
comp_edit.variables[comp_edit.used-1].float_.min = -float.max;
comp_edit.variables[comp_edit.used-1].float_.max = float.max;
}
}
}
edit_components[comp.component_id] = comp_edit;
}
void gui() void gui()
{ {
if(igCollapsingHeader("Systems", ImGuiTreeNodeFlags_Framed | ImGuiTreeNodeFlags_SpanFullWidth | ImGuiTreeNodeFlags_FramePadding)) if(igCollapsingHeader("Systems", ImGuiTreeNodeFlags_SpanFullWidth | ImGuiTreeNodeFlags_DefaultOpen))
{ {
bool true_ = true; //bool true_ = true;
igIndent(8); igIndent(8);
foreach(ref SystemGUI system;systems) foreach(ref SystemGUI system;systems)
{ {
if(igCheckbox(system.name,&system.enabled)) if(igCheckbox(system.name,&system.enabled))
{ {
if(system.enabled)system.system.enable(); System* sys = launcher.manager.getSystem(system.id);
else system.system.disable(); if(system.enabled)sys.enable();
else sys.disable();
} }
} }
igUnindent(8); igUnindent(8);
} }
} }
void toolGui() static vec4 colorUintToVec4(uint color)
{ {
if(templates.length) // color = *cast(uint*)(comp_ptr+var.offset);
return vec4(cast(float)(color & 0xFF) / 255,
cast(float)(color >> 8 & 0xFF) / 255,
cast(float)(color >> 16 & 0xFF) / 255,
cast(float)(color >> 24 & 0xFF) / 255);
}
static uint colorVec4ToUint(vec4 color)
{
return cast(uint)(color.x * 255) |
cast(uint)(color.y * 255) << 8 |
cast(uint)(color.z * 255) << 16 |
cast(uint)(color.w * 255) << 24;
}
static bool igDragScalarClamp(const(char)* label, ImGuiDataType data_type, void* v, float v_speed, const(void)* v_min, const(void)* v_max, const(char)* format, float power)
{
ubyte[8] v_backup;// = *v;
final switch(data_type)
{ {
if(igBeginCombo("Template",templates[selected_tempalte].name,0)) case ImGuiDataType_S8:memcpy(v_backup.ptr, v, 1);break;
{ case ImGuiDataType_S16:memcpy(v_backup.ptr, v, 2);break;
foreach(i, tmpl; templates) case ImGuiDataType_S32:memcpy(v_backup.ptr, v, 4);break;
{ case ImGuiDataType_U8:memcpy(v_backup.ptr, v, 1);break;
if(igSelectable(tmpl.name,false,0,ImVec2(0,0))) case ImGuiDataType_U16:memcpy(v_backup.ptr, v, 2);break;
{ case ImGuiDataType_U32:memcpy(v_backup.ptr, v, 4);break;
selected_tempalte = cast(uint)i; case ImGuiDataType_Float:memcpy(v_backup.ptr, v, 4);break;
}
}
igEndCombo();
}
} }
else if (!igDragScalar(label, data_type, v, v_speed, v_min, v_max, format, power))
return false;
final switch(data_type)
{ {
if(igBeginCombo("Template",null,0))igEndCombo(); case ImGuiDataType_S8:
if(*cast(byte*)v < *cast(byte*)v_min)*cast(byte*)v = *cast(byte*)v_min;
else if(*cast(byte*)v > *cast(byte*)v_max)*cast(byte*)v = *cast(byte*)v_max;
return *cast(byte*)v != *cast(byte*)v_backup.ptr;
case ImGuiDataType_S16:
if(*cast(short*)v < *cast(short*)v_min)*cast(short*)v = *cast(short*)v_min;
else if(*cast(short*)v > *cast(short*)v_max)*cast(short*)v = *cast(short*)v_max;
return *cast(short*)v != *cast(short*)v_backup.ptr;
case ImGuiDataType_S32:
if(*cast(int*)v < *cast(int*)v_min)*cast(int*)v = *cast(int*)v_min;
else if(*cast(int*)v > *cast(int*)v_max)*cast(int*)v = *cast(int*)v_max;
return *cast(int*)v != *cast(int*)v_backup.ptr;
case ImGuiDataType_U8:
if(*cast(ubyte*)v < *cast(ubyte*)v_min)*cast(ubyte*)v = *cast(ubyte*)v_min;
else if(*cast(ubyte*)v > *cast(ubyte*)v_max)*cast(ubyte*)v = *cast(ubyte*)v_max;
return *cast(ubyte*)v != *cast(ubyte*)v_backup.ptr;
case ImGuiDataType_U16:
if(*cast(ushort*)v < *cast(ushort*)v_min)*cast(ushort*)v = *cast(ushort*)v_min;
else if(*cast(ushort*)v > *cast(ushort*)v_max)*cast(ushort*)v = *cast(ushort*)v_max;
return *cast(ushort*)v != *cast(ushort*)v_backup.ptr;
case ImGuiDataType_U32:
if(*cast(uint*)v < *cast(uint*)v_min)*cast(uint*)v = *cast(uint*)v_min;
else if(*cast(uint*)v > *cast(uint*)v_max)*cast(uint*)v = *cast(uint*)v_max;
return *cast(uint*)v != *cast(uint*)v_backup.ptr;
case ImGuiDataType_Float:
if(*cast(float*)v < *cast(float*)v_min)*cast(float*)v = *cast(float*)v_min;
else if(*cast(float*)v > *cast(float*)v_max)*cast(float*)v = *cast(float*)v_max;
return *cast(float*)v != *cast(float*)v_backup.ptr;
} }
} }
void componentGUI(ushort comp_id, void* data_ptr)
{
vec4 color;
if(comp_id >= edit_components.length)return;
if(edit_components[comp_id].used)
{
if(igCollapsingHeader(edit_components[comp_id].name, ImGuiTreeNodeFlags_SpanAvailWidth | ImGuiTreeNodeFlags_DefaultOpen))
{
igIndent(8);
foreach(ref VariableGUI var;edit_components[comp_id].variables[0 .. edit_components[comp_id].used])
{
igPushIDPtr(&var);
switch(var.type)
{
case VariableGUI.Type.byte_:
igDragScalarClamp(var.name, ImGuiDataType_S8, data_ptr+var.offset, 0.1, cast(void*)&var.int_.min, cast(void*)&var.int_.max, null, 1);
break;
case VariableGUI.Type.ubyte_:
igDragScalarClamp(var.name, ImGuiDataType_U8, data_ptr+var.offset, 0.1, cast(void*)&var.int_.min, cast(void*)&var.int_.max, null, 1);
break;
case VariableGUI.Type.short_:
igDragScalarClamp(var.name, ImGuiDataType_S16, data_ptr+var.offset, 0.1, cast(void*)&var.int_.min, cast(void*)&var.int_.max, null, 1);
break;
case VariableGUI.Type.ushort_:
igDragScalarClamp(var.name, ImGuiDataType_U16, data_ptr+var.offset, 0.1, cast(void*)&var.int_.min, cast(void*)&var.int_.max, null, 1);
break;
case VariableGUI.Type.int_:
igDragScalarClamp(var.name, ImGuiDataType_S32, data_ptr+var.offset, 0.1, cast(void*)&var.int_.min, cast(void*)&var.int_.max, null, 1);
break;
case VariableGUI.Type.uint_:
igDragScalarClamp(var.name, ImGuiDataType_U32, data_ptr+var.offset, 0.1, cast(void*)&var.int_.min, cast(void*)&var.int_.max, null, 1);
break;
case VariableGUI.Type.float_:
igDragScalarClamp(var.name, ImGuiDataType_Float, data_ptr+var.offset, 0.1, cast(void*)&var.float_.min, cast(void*)&var.float_.max, "%2.2f", 1);
break;
case VariableGUI.Type.color:
color = colorUintToVec4(*cast(uint*)(data_ptr+var.offset));
if(igColorEdit4(var.name, color.data, ImGuiColorEditFlags_None))
*cast(uint*)(data_ptr+var.offset) = colorVec4ToUint(color);
break;
case VariableGUI.Type.vec2:
igDragFloat2(var.name, (cast(float*)(data_ptr+var.offset))[0..2], 0.1, -float.max, float.max, null, 1);
break;
case VariableGUI.Type.ivec2:
igDragInt2(var.name, (cast(int*)(data_ptr+var.offset))[0..2], 0.1, int.min, int.max, null);
break;
case VariableGUI.Type.vec4:
igDragFloat4(var.name, (cast(float*)(data_ptr+var.offset))[0..4], 0.1, -float.max, float.max, null, 1);
break;
case VariableGUI.Type.ivec4:
igDragInt4(var.name, (cast(int*)(data_ptr+var.offset))[0..4], 0.1, int.min, int.max, null);
break;
default:break;
}
igPopID();
}
//igPopID();
igUnindent(8);
}
}
}
void entityComponentsGUI()
{
if(selected_template >= templates.length)return;
EntityTemplate* tmpl = templates[selected_template].tmpl;
EntityManager.EntityInfo* info = tmpl.info;
foreach(comp_id; info.components)
{
void* data_ptr = tmpl.entity_data.ptr;
void* comp_ptr = data_ptr + info.tmpl_deltas[comp_id];
componentGUI(comp_id, comp_ptr);
}
}
void toolGui()
{
ImGuiStyle * style = igGetStyle();
ImVec4 col = style.Colors[ImGuiCol_Header];
style.Colors[ImGuiCol_Header] = style.Colors[ImGuiCol_TextSelectedBg];
//style.
//ImDrawList* draw_list = igGetWindowDrawList();
final switch(launcher.used_tool)
{
case Tool.entity_spawner:
if(templates.length)
{
{
if(igListBoxHeaderInt("Template",cast(int)templates.length,cast(int)templates.length))
{
foreach(i, tmpl; templates)
{
if(igSelectable(tmpl.name,selected_template == i,ImGuiSelectableFlags_AllowDoubleClick,ImVec2(0,0)))
{
selected_template = cast(uint)i;
}
}
igListBoxFooter();
}
}
if(igIsItemHovered(0))igSetTooltip("Select entity to spawn (SHIFT + Scroll)");
}
style.Colors[ImGuiCol_Header] = col;
entityComponentsGUI();
break;
case Tool.component_manipulator:
if(components.length)
{
if(igListBoxHeaderInt("Components",cast(int)components.length,cast(int)components.length))
{
foreach(i, comp; components)
{
if(igSelectable(comp.name,selected_component == i,0,ImVec2(0,0)))
{
selected_component = cast(uint)i;
}
}
igListBoxFooter();
}
if(igIsItemHovered(0))igSetTooltip("Select component to add/remove (SHIFT + Scroll)");
}
style.Colors[ImGuiCol_Header] = col;
if(selected_component < components.length)componentGUI(components[selected_component].component_id, components[selected_component].data);
break;
case Tool.selector:
break;
}
style.Colors[ImGuiCol_Header] = col;
}
private void genFilterList()
{
filter_list.clear();
foreach(i, comp; filter)
{
if(comp)
{
filter_list.add(cast(ushort)i);
}
}
}
void filterGUI()
{
ImGuiStyle * style = igGetStyle();
ImVec4 col = style.Colors[ImGuiCol_Header];
style.Colors[ImGuiCol_Header] = style.Colors[ImGuiCol_TextSelectedBg];
if(filter.length < edit_components.length)filter.length(edit_components.length);
int length = 0;
foreach(comp; edit_components)
{
if(comp.name !is null)length++;
}
if(length && igListBoxHeaderInt("Components##FilterComponents",cast(int)length,cast(int)length))
{
foreach(i, ref comp; edit_components)
{
if(comp.name is null)continue;
if(igSelectableBoolPtr(comp.name,&filter[i],0,ImVec2(0,0)))
{
genFilterList();
}
}
igListBoxFooter();
}
if(igIsItemHovered(0))igSetTooltip("Select components to filter while tool work.\nComponents are only changed for filtered entities.");
style.Colors[ImGuiCol_Header] = col;
}
} }

View file

@ -5,7 +5,8 @@ import bubel.ecs.system;
struct SystemGUI struct SystemGUI
{ {
const (char)* name; const (char)* name;
System* system; //System* system;
ushort id;
bool enabled = true; bool enabled = true;
} }

View file

@ -0,0 +1,53 @@
module gui.tool_circle;
import ecs_utils.gfx.buffer;
import ecs_utils.gfx.shader;
import ecs_utils.gfx.config;
import ecs_utils.gfx.renderer;
import ecs_utils.math.vector;
version(WebAssembly)import glad.gl.gles2;
else version(Android)import glad.gl.gles2;
else import glad.gl.gl;
struct ToolCircle
{
//Buffer vbo;
//Buffer ibo;
uint material_id = 1;
uint mesh_id = 0;
/*/void generate()
{
ushort[]
}*/
void draw(Renderer* renderer, vec2 position, float size, float edge = 1)
{
glDisable(GL_DEPTH_TEST);
position = position * renderer.view_size + renderer.view_pos;
vec2 sizes = renderer.view_size * size;
vec2 sizes2 = vec2(edge,0);
import core.stdc.string;
ubyte[32] uniform_block;
void* ptr = uniform_block.ptr;
*cast(float*)(ptr) = sizes.x;
*cast(float*)(ptr+4) = 0;
*cast(float*)(ptr+8) = 0;
*cast(float*)(ptr+12) = sizes.y;
memcpy(ptr+16,position.data.ptr,8);
memcpy(ptr+24,sizes2.data.ptr,8);
glEnableVertexAttribArray(0);
GfxConfig.meshes[mesh_id].bind();
GfxConfig.materials[material_id].bind();
GfxConfig.materials[material_id].pushBindings();
GfxConfig.materials[material_id].pushUniforms(uniform_block.ptr);
//glDisable(GL_DEPTH_TEST);
glDrawElements(GL_TRIANGLES,6,GL_UNSIGNED_SHORT,null);
}
}

View file

@ -15,14 +15,13 @@
"../external/sources" "../external/sources"
], ],
"dependencies": { "dependencies": {
"bindbc-sdl":"0.13.0", "bindbc-sdl":"0.19.0",
"ecs":{"path":"../../"} "ecs":{"path":"../../"}
}, },
"versions": [ "versions": [
"BindSDL_Image", "BindSDL_Image",
"SDL_2010" "SDL_2010"
], ],
"configurations" : [ "configurations" : [
{ {
"name" : "default", "name" : "default",

View file

@ -2,8 +2,12 @@ module ecs_utils.gfx.buffer;
import bubel.ecs.std; import bubel.ecs.std;
import glad.gl.gl; //import glad.gl.gl;
import glad.gl.gles2; //import glad.gl.gles2;
version(WebAssembly)import glad.gl.gles2;
else version(Android)import glad.gl.gles2;
else import glad.gl.gl;
extern(C): extern(C):
@ -64,13 +68,13 @@ struct Buffer
void map(BindTarget target) nothrow void map(BindTarget target) nothrow
{ {
bind(target); bind(target);
data.map_ptr = glMapBuffer(target,GL_WRITE_ONLY); version(Android){}else version(WebAssembly){}else data.map_ptr = glMapBuffer(target,GL_WRITE_ONLY);
} }
void map(uint offset, uint size, BindTarget target, uint flags = MapFlagBits.write | MapFlagBits.flush_explict | MapFlagBits.invalidate_buffer) nothrow void map(uint offset, uint size, BindTarget target, uint flags = MapFlagBits.write | MapFlagBits.flush_explict | MapFlagBits.invalidate_buffer) nothrow
{ {
bind(target); bind(target);
data.map_ptr = glMapBufferRange(target,offset,size,flags); version(Android){}else data.map_ptr = glMapBufferRange(target,offset,size,flags);
} }
void flush(uint offset, uint size, BindTarget target) nothrow void flush(uint offset, uint size, BindTarget target) nothrow

View file

@ -6,7 +6,9 @@ import bubel.ecs.std;
import ecs_utils.gfx.shader; import ecs_utils.gfx.shader;
import glad.gl.gl; version(WebAssembly)import glad.gl.gles2;
else version(Android)import glad.gl.gles2;
else import glad.gl.gl;
//import mutils.serializer.json; //import mutils.serializer.json;
@ -76,6 +78,25 @@ struct Material
void bind() nothrow void bind() nothrow
{ {
final switch(data.blend_mode)
{
case BlendMode.mixed:
glDepthMask(0);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
break;
case BlendMode.opaque:
glDepthMask(1);
glDisable(GL_BLEND);
break;
case BlendMode.additive:
glDepthMask(0);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE);
//glBlendFunc(GL_ONE, GL_ONE);
break;
}
glUseProgram(data.modules[0].gl_handle); glUseProgram(data.modules[0].gl_handle);
} }

View file

@ -6,7 +6,9 @@ import bubel.ecs.std;
import ecs_utils.gfx.buffer; import ecs_utils.gfx.buffer;
import glad.gl.gl; version(WebAssembly)import glad.gl.gles2;
else version(Android)import glad.gl.gles2;
else import glad.gl.gl;
//import mutils.serializer.json; //import mutils.serializer.json;
extern(C): extern(C):

View file

@ -12,6 +12,7 @@ import ecs_utils.math.vector;
import bubel.ecs.block_allocator; import bubel.ecs.block_allocator;
import bubel.ecs.vector; import bubel.ecs.vector;
version(WebAssembly)import glad.gl.gles2; version(WebAssembly)import glad.gl.gles2;
else version(Android)import glad.gl.gles2;
else import glad.gl.gl; else import glad.gl.gl;
version = ver1; version = ver1;
@ -66,8 +67,10 @@ struct Renderer
enum max_items = batch_size;//963; enum max_items = batch_size;//963;
byte[] batch_vertices; byte[] batch_vertices;
ushort[] batch_indices; ushort[] batch_indices;
void* memory; void* memory = null;
uint items = 0; uint items = 0;
uint material_id;
uint texture_id;
} }
Mutex* get_block_mutex; Mutex* get_block_mutex;
@ -127,11 +130,11 @@ struct Renderer
block_stack_mutex.unlock();*/ block_stack_mutex.unlock();*/
foreach(ref Thread thread; threads) foreach(ref Thread thread; threads)
{ {
foreach(VertexBlock block; thread.blocks) foreach(VertexBlock block; thread.filled_blocks)
{ {
allocator.freeBlock(block.memory); allocator.freeBlock(block.memory);
} }
thread.blocks.clear(); thread.filled_blocks.clear();
} }
render_blocks = 0; render_blocks = 0;
current_block = 0; current_block = 0;
@ -143,13 +146,13 @@ struct Renderer
{ {
foreach(ref Thread thread; threads) foreach(ref Thread thread; threads)
{ {
foreach(VertexBlock block; thread.blocks) foreach(VertexBlock block; thread.filled_blocks)
{ {
uint items = block.items; uint items = block.items;
if(items + item_id >= MaxObjects)items = MaxObjects - item_id; if(items + item_id >= MaxObjects)items = MaxObjects - item_id;
batch_vbo[0].bufferSubData(Buffer.BindTarget.array,items*4*14,item_id*4*14,block.batch_vertices.ptr); batch_vbo[0].bufferSubData(Buffer.BindTarget.array,items*4*14,item_id*4*14,block.batch_vertices.ptr);
batch_ibo[0].bufferSubData(Buffer.BindTarget.element_array,items*2*6,item_id*2*6,block.batch_indices.ptr); batch_ibo[0].bufferSubData(Buffer.BindTarget.element_array,items*2*6,item_id*2*6,block.batch_indices.ptr);
draw_list.add(DrawCall(item_id,items)); draw_list.add(DrawCall(block.texture_id,block.material_id,item_id,items));
item_id += items; item_id += items;
} }
//thread.blocks.clear(); //thread.blocks.clear();
@ -172,17 +175,38 @@ struct Renderer
foreach(i, ref Thread thread; threads) foreach(i, ref Thread thread; threads)
{ {
//pushBlock(thread.block); //pushBlock(thread.block);
thread.blocks.add(thread.block); foreach(ref block; thread.blocks)
thread.block = getBlock(); {
if(block.items > 0)
{
thread.filled_blocks.add(block);
block.items = 0;
}
}
//thread.blocks = getBlock();
} }
} }
struct DrawData
{
Texture texture;
vec2 position;
vec2 size;
vec4 coords;
short depth = 0;
uint color = uint.max;
float angle = 0;
uint material_id = 0;
uint mesh_id = 0;
uint thread_id = 0;
}
struct Thread struct Thread
{ {
//Vector!VertexBlock block; //Vector!VertexBlock block;
RenderData[] render_list; RenderData[] render_list;
VertexBlock block; VertexBlock[] blocks;
Vector!VertexBlock blocks; Vector!VertexBlock filled_blocks;
} }
Thread[] threads; Thread[] threads;
@ -224,6 +248,8 @@ struct Renderer
struct DrawCall struct DrawCall
{ {
uint texture_id;
uint material_id;
uint start; uint start;
uint count; uint count;
} }
@ -248,6 +274,7 @@ struct Renderer
void initialize() void initialize()
{ {
import ecs_utils.gfx.config;
//this.technique = __ecs_used_technique; //this.technique = __ecs_used_technique;
__initialize(this); __initialize(this);
@ -260,7 +287,8 @@ struct Renderer
threads = Mallocator.makeArray!Thread(32); threads = Mallocator.makeArray!Thread(32);
foreach(ref Thread thread;threads) foreach(ref Thread thread;threads)
{ {
thread.block = getBlock(); //thread.blocks = getBlock();
thread.blocks = Mallocator.makeArray!VertexBlock(GfxConfig.materials.length);
} }
} }
@ -416,13 +444,15 @@ struct Renderer
} }
void draw(Texture tex, vec2 pos, vec2 size, vec4 coords, short depth = 0, uint color = uint.max, float angle = 0, uint material_id = 0, uint mesh_id = 0, uint thread_id = 0) //void draw(Texture tex, vec2 pos, vec2 size, vec4 coords, short depth = 0, uint color = uint.max, float angle = 0, uint material_id = 0, uint mesh_id = 0, uint thread_id = 0)
void draw(scope ref const(DrawData) data)
{ {
if(prepared_items >= MaxObjects)return; if(prepared_items >= MaxObjects)return;
__draw(this,tex,pos,size,coords,depth,color,angle,material_id,mesh_id,thread_id); __draw(this,data);//tex,pos,size,coords,depth,color,angle,material_id,mesh_id,thread_id);
} }
private static void __draw_sdl(ref Renderer this_, Texture tex, vec2 pos, vec2 size, vec4 coords, short depth, uint color, float angle, uint material_id, uint mesh_id, uint thread_id) //private static void __draw_sdl(ref Renderer this_, Texture tex, vec2 pos, vec2 size, vec4 coords, short depth, uint color, float angle, uint material_id, uint mesh_id, uint thread_id)
private static void __draw_sdl(ref Renderer this_, scope ref const(DrawData) data)
{ {
/*with(this_) /*with(this_)
{ {
@ -442,22 +472,25 @@ struct Renderer
}*/ }*/
} }
private static void __draw_gl(ref Renderer this_, Texture tex, vec2 pos, vec2 size, vec4 coords, short depth, uint color, float angle, uint material_id, uint mesh_id, uint thread_id) // private static void __draw_gl(ref Renderer this_, Texture tex, vec2 pos, vec2 size, vec4 coords, short depth, uint color, float angle, uint material_id, uint mesh_id, uint thread_id)
private static void __draw_gl(ref Renderer this_, scope ref const(DrawData) data)
{ {
//import core.stdc.string; //import core.stdc.string;
with(this_) with(this_)
{ {
//pos += view_pos; //pos += view_pos;
size.x *= view_size.x; vec2 pos = void;
size.y *= view_size.y; vec2 size = void;
pos.x = pos.x * view_size.x + view_pos.x; size.x = data.size.x * view_size.x;
pos.y = pos.y * view_size.y + view_pos.y;//*/ size.y = data.size.y * view_size.y;
pos.x = data.position.x * view_size.x + view_pos.x;
pos.y = data.position.y * view_size.y + view_pos.y;//*/
/*version(ver6)void* ptr = ubos[0].mappedPointer() + data_index; /*version(ver6)void* ptr = ubos[0].mappedPointer() + data_index;
else void* ptr = uniform_block.ptr + data_index;*/ else void* ptr = uniform_block.ptr + data_index;*/
if(data_ptr is null)return; if(data_ptr is null)return;
void* ptr = data_ptr + data_index; void* ptr = data_ptr + data_index;
if(angle == 0) if(data.angle == 0)
{ {
*cast(float*)ptr = size.x; *cast(float*)ptr = size.x;
*cast(float*)(ptr+4) = 0; *cast(float*)(ptr+4) = 0;
@ -467,8 +500,8 @@ struct Renderer
else else
{ {
//import core.stdc.math; //import core.stdc.math;
float sinn = sinf(angle); float sinn = sinf(data.angle);
float coss = cosf(angle); float coss = cosf(data.angle);
*cast(float*)ptr = coss * size.x; *cast(float*)ptr = coss * size.x;
*cast(float*)(ptr+4) = -sinn * size.y; *cast(float*)(ptr+4) = -sinn * size.y;
*cast(float*)(ptr+8) = sinn * size.x; *cast(float*)(ptr+8) = sinn * size.x;
@ -477,12 +510,12 @@ struct Renderer
//memcpy(ptr,); //memcpy(ptr,);
memcpy(ptr+16,pos.data.ptr,8); memcpy(ptr+16,pos.data.ptr,8);
memcpy(ptr+32,coords.data.ptr,16); memcpy(ptr+32,data.coords.data.ptr,16);
//render_list[item_id] = RenderData(tex,material_id,mesh_id); //render_list[item_id] = RenderData(tex,material_id,mesh_id);
render_list[item_id].texture = tex; render_list[item_id].texture = *cast(Texture*)&data.texture;
render_list[item_id].material_id = material_id; render_list[item_id].material_id = data.material_id;
render_list[item_id].mesh_id = mesh_id; render_list[item_id].mesh_id = data.mesh_id;
data_index += data_offset; data_index += data_offset;
item_id++; item_id++;
@ -490,18 +523,43 @@ struct Renderer
} }
} }
private static void __draw_gl_vbo_batch(ref Renderer this_, Texture tex, vec2 pos, vec2 size, vec4 coords, short depth, uint color, float angle, uint material_id, uint mesh_id, uint thread_id = 0) // private static void __draw_gl_vbo_batch(ref Renderer this_, Texture tex, vec2 pos, vec2 size, vec4 coords, short depth, uint color, float angle, uint material_id, uint mesh_id, uint thread_id = 0)
private static void __draw_gl_vbo_batch(ref Renderer this_, scope ref const(DrawData) data)
{ {
import ecs_utils.gfx.config; import ecs_utils.gfx.config;
short[3] mem = [depth, *cast(short*)&color, *(cast(short*)&color + 1)];
//import core.stdc.string; //import core.stdc.string;
with(this_) with(this_)
{ {
uint thread_id = data.thread_id;
//if(item_id >= MaxObjects)return; //if(item_id >= MaxObjects)return;
//pos += view_pos; //pos += view_pos;
Thread* thread = &threads[thread_id];
VertexBlock* block;
assert(thread.blocks.length > data.material_id);
block = &thread.blocks[data.material_id];
if(block.items == 0)
{
thread.blocks[data.material_id] = getBlock();
block = &thread.blocks[data.material_id];
block.material_id = data.material_id;
}
else if(block.items >= VertexBlock.max_items)
{
//pushBlock(thread.block);
prepared_items += block.items;
thread.filled_blocks.add(*block);
thread.blocks[data.material_id] = getBlock();
block = &thread.blocks[data.material_id];
block.material_id = data.material_id;
}
pos.x = pos.x * view_size.x + view_pos.x; short[3] mem = [data.depth, *cast(short*)&data.color, *(cast(short*)&data.color + 1)];
pos.y = pos.y * view_size.y + view_pos.y;//*/
vec2 pos = void;
vec2 size = void;
pos.x = data.position.x * view_size.x + view_pos.x;
pos.y = data.position.y * view_size.y + view_pos.y;//*/
/*void* ptr = data_ptr + data_index; /*void* ptr = data_ptr + data_index;
*cast(float*)ptr = size.x; *cast(float*)ptr = size.x;
@ -512,13 +570,16 @@ struct Renderer
memcpy(ptr+16,pos.data.ptr,8); memcpy(ptr+16,pos.data.ptr,8);
memcpy(ptr+32,coords.data.ptr,16);*/ memcpy(ptr+32,coords.data.ptr,16);*/
short[] verts = cast(short[])threads[thread_id].block.batch_vertices; short[] verts = (cast(short*)block.batch_vertices.ptr)[0..block.batch_vertices.length>>1];
uint item_id = threads[thread_id].block.items; uint item_id = block.items;
if(angle == 0) uint mesh_id = data.mesh_id;
vec4 coords = data.coords;
if(data.angle == 0)
{ {
size.x *= view_size.x; size.x = data.size.x * view_size.x;
size.y *= view_size.y; size.y = data.size.y * view_size.y;
verts[item_id*28] = cast(short)((GfxConfig.meshes[mesh_id].vertices[0] * size.x + pos.x) * 8191); verts[item_id*28] = cast(short)((GfxConfig.meshes[mesh_id].vertices[0] * size.x + pos.x) * 8191);
verts[item_id*28+1] = cast(short)((GfxConfig.meshes[mesh_id].vertices[1] * size.y + pos.y) * 8191); verts[item_id*28+1] = cast(short)((GfxConfig.meshes[mesh_id].vertices[1] * size.y + pos.y) * 8191);
@ -550,10 +611,11 @@ struct Renderer
else else
{ {
//import core.stdc.math; //import core.stdc.math;
float sinx = sinf(angle) * size.x * view_size.y; float angle = data.angle;
float cosx = cosf(angle) * size.x * view_size.x; float sinx = sinf(angle) * data.size.x * view_size.y;
float siny = sinf(angle) * size.y * view_size.x; float cosx = cosf(angle) * data.size.x * view_size.x;
float cosy = cosf(angle) * size.y * view_size.y; float siny = sinf(angle) * data.size.y * view_size.x;
float cosy = cosf(angle) * data.size.y * view_size.y;
/*batch_vertices[item_id*28] = GfxConfig.meshes[mesh_id].vertices[0] * size.x; /*batch_vertices[item_id*28] = GfxConfig.meshes[mesh_id].vertices[0] * size.x;
batch_vertices[item_id*28+1] = GfxConfig.meshes[mesh_id].vertices[1] * size.y; batch_vertices[item_id*28+1] = GfxConfig.meshes[mesh_id].vertices[1] * size.y;
@ -618,7 +680,7 @@ struct Renderer
uint ind_id = (item_id % batch_size)*4; uint ind_id = (item_id % batch_size)*4;
ushort[] indices = threads[thread_id].block.batch_indices; ushort[] indices = block.batch_indices;
indices[item_id*6] = cast(ushort)(GfxConfig.meshes[mesh_id].indices[0] + ind_id); indices[item_id*6] = cast(ushort)(GfxConfig.meshes[mesh_id].indices[0] + ind_id);
indices[item_id*6+1] = cast(ushort)(GfxConfig.meshes[mesh_id].indices[1] + ind_id); indices[item_id*6+1] = cast(ushort)(GfxConfig.meshes[mesh_id].indices[1] + ind_id);
@ -633,13 +695,7 @@ struct Renderer
//render_list[item_id].mesh_id = mesh_id; //render_list[item_id].mesh_id = mesh_id;
//data_index += 1;//data_offset; //data_index += 1;//data_offset;
threads[thread_id].block.items++; block.items++;
if(threads[thread_id].block.items >= VertexBlock.max_items)
{
//pushBlock(threads[thread_id].block);
threads[thread_id].blocks.add(threads[thread_id].block);
threads[thread_id].block = getBlock();
}
} }
} }
@ -657,6 +713,7 @@ struct Renderer
{ {
glClearColor(0,0,0,0); glClearColor(0,0,0,0);
glViewport(0,0,this_.resolution.x,this_.resolution.y); glViewport(0,0,this_.resolution.x,this_.resolution.y);
glDepthMask(1);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
//glDisable(GL_DEPTH_TEST); //glDisable(GL_DEPTH_TEST);
glEnable(GL_DEPTH_TEST); glEnable(GL_DEPTH_TEST);
@ -667,6 +724,10 @@ struct Renderer
{ {
glDepthRangef(0,1); glDepthRangef(0,1);
} }
else version(Android)
{
glDepthRangef(0,1);
}
else else
{ {
glDepthRange(0,1); glDepthRange(0,1);
@ -822,9 +883,9 @@ struct Renderer
//uint items = item_id/batch_size+1; //uint items = item_id/batch_size+1;
foreach(i; 0..draw_list.length) foreach(i; 0..draw_list.length)
{ {
if(material_id != render_list[i].material_id) if(material_id != draw_list[i].material_id)
{ {
material_id = render_list[i].material_id; material_id = draw_list[i].material_id;
GfxConfig.materials[material_id].bind(); GfxConfig.materials[material_id].bind();
float[3*4] data = [1,0,0,1,0,0,0,0,0,0,1,1]; float[3*4] data = [1,0,0,1,0,0,0,0,0,0,1,1];
GfxConfig.materials[material_id].pushUniforms(data.ptr); GfxConfig.materials[material_id].pushUniforms(data.ptr);
@ -1054,7 +1115,8 @@ struct Renderer
view_pos = (pos - size * 0.5) * view_size; view_pos = (pos - size * 0.5) * view_size;
} }
__gshared void function(ref Renderer this_, Texture tex, vec2 pos, vec2 size, vec4 coords, short depth, uint color, float angle, uint material_id, uint mesh_id, uint thread_id) __draw; // __gshared void function(ref Renderer this_, Texture tex, vec2 pos, vec2 size, vec4 coords, short depth, uint color, float angle, uint material_id, uint mesh_id, uint thread_id) __draw;
__gshared void function(ref Renderer this_, scope ref const(DrawData) data) __draw;
__gshared void function(ref Renderer this_) __present; __gshared void function(ref Renderer this_) __present;
__gshared void function(ref Renderer this_) __clear; __gshared void function(ref Renderer this_) __clear;
__gshared void function(ref Renderer this_) __initialize; __gshared void function(ref Renderer this_) __initialize;

View file

@ -4,7 +4,9 @@ import bindbc.sdl;
import bubel.ecs.std; import bubel.ecs.std;
import glad.gl.gl; version(WebAssembly)import glad.gl.gles2;
else version(Android)import glad.gl.gles2;
else import glad.gl.gl;
//version = ver1; //version = ver1;
@ -67,10 +69,12 @@ struct Shader
} }
version(WebAssembly)const char* glsl = "#version 100\n"; version(WebAssembly)const char* glsl = "#version 100\n";
else version(Android)const char* glsl = "#version 100\n";
else const char* glsl = "#version 330\n"; else const char* glsl = "#version 330\n";
const char* buffer = data.code.ptr; const char* buffer = data.code.ptr;
char* ver; char* ver;
version(WebAssembly)ver = cast(char*)"#define ver1 1\n#define GLES\n".ptr; version(WebAssembly)ver = cast(char*)"#define ver1 1\n#define GLES\n".ptr;
else version(Android)ver = cast(char*)"#define ver1 1\n#define GLES\n".ptr;
else ver = cast(char*)"#define ver1 1\n".ptr; else ver = cast(char*)"#define ver1 1\n".ptr;
/*switch(__ecs_used_technique) /*switch(__ecs_used_technique)
{ {

View file

@ -6,7 +6,9 @@ import bubel.ecs.std;
import ecs_utils.math.vector; import ecs_utils.math.vector;
import glad.gl.gl; version(WebAssembly)import glad.gl.gles2;
else version(Android)import glad.gl.gles2;
else import glad.gl.gl;
extern(C): extern(C):
@ -53,6 +55,7 @@ struct Texture
data.bpp = surf.format.BytesPerPixel; data.bpp = surf.format.BytesPerPixel;
data.data = Mallocator.makeArray!ubyte(surf.w*surf.h*surf.format.BytesPerPixel); data.data = Mallocator.makeArray!ubyte(surf.w*surf.h*surf.format.BytesPerPixel);
data.data[0..$] = (cast(ubyte*)surf.pixels)[0..data.data.length]; data.data[0..$] = (cast(ubyte*)surf.pixels)[0..data.data.length];
data.size = ivec2(surf.w, surf.h);
SDL_FreeSurface(surf); SDL_FreeSurface(surf);
@ -65,8 +68,8 @@ struct Texture
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
if(data.bpp == 3)glTexImage2D(GL_TEXTURE_2D,0,GL_RGB,surf.w,surf.h,0,GL_RGB,GL_UNSIGNED_BYTE,data.data.ptr); if(data.bpp == 3)glTexImage2D(GL_TEXTURE_2D,0,GL_RGB,data.size.x,data.size.y,0,GL_RGB,GL_UNSIGNED_BYTE,data.data.ptr);
else if(data.bpp == 4)glTexImage2D(GL_TEXTURE_2D,0,GL_RGBA,surf.w,surf.h,0,GL_RGBA,GL_UNSIGNED_BYTE,data.data.ptr); else if(data.bpp == 4)glTexImage2D(GL_TEXTURE_2D,0,GL_RGBA,data.size.x,data.size.y,0,GL_RGBA,GL_UNSIGNED_BYTE,data.data.ptr);
else return false; else return false;
} }
@ -80,7 +83,7 @@ struct Texture
glBindTexture(GL_TEXTURE_2D, data.gl_handle); glBindTexture(GL_TEXTURE_2D, data.gl_handle);
} }
void destory() @nogc nothrow void destroy() @nogc nothrow
{ {
if(data) if(data)
{ {

View file

@ -22,7 +22,9 @@ else :
import bindbc.sdl; import bindbc.sdl;
import glad.gl.gl; version(WebAssembly)import glad.gl.gles2;
else version(Android)import glad.gl.gles2;
else import glad.gl.gl;
import cimgui.cimgui; import cimgui.cimgui;
@ -210,7 +212,7 @@ static void ImGui_ImplSDL2_UpdateMousePosAndButtons()
// SDL_CaptureMouse() let the OS know e.g. that our imgui drag outside the SDL window boundaries shouldn't e.g. trigger the OS window resize cursor. // SDL_CaptureMouse() let the OS know e.g. that our imgui drag outside the SDL window boundaries shouldn't e.g. trigger the OS window resize cursor.
// The function is only supported from SDL 2.0.4 (released Jan 2016) // The function is only supported from SDL 2.0.4 (released Jan 2016)
bool any_mouse_button_down = ImGui::IsAnyMouseDown(); bool any_mouse_button_down = ImGui.IsAnyMouseDown();
SDL_CaptureMouse(any_mouse_button_down ? SDL_TRUE : SDL_FALSE); SDL_CaptureMouse(any_mouse_button_down ? SDL_TRUE : SDL_FALSE);
//#else*/ //#else*/
if (SDL_GetWindowFlags(g_Window) & SDL_WINDOW_INPUT_FOCUS) if (SDL_GetWindowFlags(g_Window) & SDL_WINDOW_INPUT_FOCUS)
@ -291,10 +293,11 @@ void ImGuiImplSDL2NewFrame(SDL_Window* window)
int w, h; int w, h;
int display_w, display_h; int display_w, display_h;
SDL_GetWindowSize(window, &w, &h); SDL_GetWindowSize(window, &w, &h);
SDL_GL_GetDrawableSize(window, &display_w, &display_h); // SDL_GL_GetDrawableSize(window, &display_w, &display_h); FIXME: you see
io.DisplaySize = ImVec2(cast(float)w, cast(float)h); io.DisplaySize = ImVec2(cast(float)w, cast(float)h);
if (w > 0 && h > 0) // if (w > 0 && h > 0)
io.DisplayFramebufferScale = ImVec2(cast(float)display_w / w, cast(float)display_h / h); // io.DisplayFramebufferScale = ImVec2(cast(float)display_w / w, cast(float)display_h / h);
io.DisplayFramebufferScale = ImVec2(1,1);
// Setup time step (we don't use SDL_GetTicks() because it is using millisecond resolution) // Setup time step (we don't use SDL_GetTicks() because it is using millisecond resolution)
frequency = SDL_GetPerformanceFrequency(); frequency = SDL_GetPerformanceFrequency();
@ -310,89 +313,460 @@ void ImGuiImplSDL2NewFrame(SDL_Window* window)
} }
__gshared GLuint g_GlVersion = 0; // Extracted at runtime using GL_MAJOR_VERSION, GL_MINOR_VERSION queries (e.g. 320 for GL 3.2)
__gshared char[32] g_GlslVersionString = ""; // Specified by user or detected based on compile time GL settings.
//__gshared GLuint g_FontTexture = 0;
__gshared GLuint g_ShaderHandle = 0, g_VertHandle = 0, g_FragHandle = 0;
__gshared int g_AttribLocationTex = 0, g_AttribLocationProjMtx = 0; // Uniforms location
__gshared int g_AttribLocationVtxPos = 0, g_AttribLocationVtxUV = 0, g_AttribLocationVtxColor = 0; // Vertex attributes location
__gshared uint g_VboHandle = 0, g_ElementsHandle = 0;
bool ImGui_ImplOpenGL3_Init(const char* glsl_version)
bool ImGuiImplOpenGL2Init()
{ {
// Setup back-end capabilities flags // Setup back-end capabilities flags
ImGuiIO* io = igGetIO(); ImGuiIO* io = igGetIO();
io.BackendRendererName = "imgui_impl_opengl2"; io.BackendRendererName = "imgui_impl_opengl3";
// Store GLSL version string so we can refer to it later in case we recreate shaders.
// Note: GLSL version is NOT the same as GL version. Leave this to null if unsure.
/*#if defined(IMGUI_IMPL_OPENGL_ES2)
if (glsl_version == null)
glsl_version = "#version 100";
#elif defined(IMGUI_IMPL_OPENGL_ES3)
if (glsl_version == null)
glsl_version = "#version 300 es";
#elif defined(__APPLE__)
if (glsl_version == null)
glsl_version = "#version 150";
#else
if (glsl_version == null)
glsl_version = "#version 130";
#endif
IM_ASSERT((int)strlen(glsl_version) + 2 < IM_ARRAYSIZE(g_GlslVersionString));*/
//const (char)*glsl_version = "#version 100";
import core.stdc.string;
strcpy(g_GlslVersionString.ptr, glsl_version);
strcat(g_GlslVersionString.ptr, "\n");
// Dummy construct to make it easily visible in the IDE and debugger which GL loader has been selected.
// The code actually never uses the 'gl_loader' variable! It is only here so you can read it!
// If auto-detection fails or doesn't select the same GL loader file as used by your application,
// you are likely to get a crash below.
// You can explicitly select a loader by using '#define IMGUI_IMPL_OPENGL_LOADER_XXX' in imconfig.h or compiler command-line.
/*const char* gl_loader = "Unknown";
IM_UNUSED(gl_loader);
#if defined(IMGUI_IMPL_OPENGL_LOADER_GL3W)
gl_loader = "GL3W";
#elif defined(IMGUI_IMPL_OPENGL_LOADER_GLEW)
gl_loader = "GLEW";
#elif defined(IMGUI_IMPL_OPENGL_LOADER_GLAD)
gl_loader = "GLAD";
#elif defined(IMGUI_IMPL_OPENGL_LOADER_GLBINDING2)
gl_loader = "glbinding2";
#elif defined(IMGUI_IMPL_OPENGL_LOADER_GLBINDING3)
gl_loader = "glbinding3";
#elif defined(IMGUI_IMPL_OPENGL_LOADER_CUSTOM)
gl_loader = "custom";
#else
gl_loader = "none";
#endif*/
// Make a dummy GL call (we don't actually need the result)
// IF YOU GET A CRASH HERE: it probably means that you haven't initialized the OpenGL function loader used by this code.
// Desktop OpenGL 3/4 need a function loader. See the IMGUI_IMPL_OPENGL_LOADER_xxx explanation above.
/*GLint current_texture;
glGetIntegerv(GL_TEXTURE_BINDING_2D, &current_texture);*/
return true; return true;
} }
void ImGuiImplOpenGL2Shutdown() static void ImGui_ImplOpenGL3_SetupRenderState(ImDrawData* draw_data, int fb_width, int fb_height, GLuint vertex_array_object)
{ {
ImGuiImplOpenGL2DestroyDeviceObjects(); // Setup render state: alpha-blending enabled, no face culling, no depth testing, scissor enabled, polygon fill
}
void ImGuiImplOpenGL2NewFrame()
{
if (!g_FontTexture)
ImGuiImplOpenGL2CreateDeviceObjects();
}
static void ImGuiImplOpenGL2SetupRenderState(ImDrawData* draw_data, int fb_width, int fb_height)
{
// Setup render state: alpha-blending enabled, no face culling, no depth testing, scissor enabled, vertex/texcoord/color pointers, polygon fill.
glEnable(GL_BLEND); glEnable(GL_BLEND);
glBlendEquation(GL_FUNC_ADD);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glDisable(GL_CULL_FACE); glDisable(GL_CULL_FACE);
glDisable(GL_DEPTH_TEST); glDisable(GL_DEPTH_TEST);
//glDisable(GL_LIGHTING);
//glDisable(GL_COLOR_MATERIAL);
glEnable(GL_SCISSOR_TEST); glEnable(GL_SCISSOR_TEST);
glEnableClientState(GL_VERTEX_ARRAY); // #ifdef GL_POLYGON_MODE
glEnableClientState(GL_TEXTURE_COORD_ARRAY); // glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
glEnableClientState(GL_COLOR_ARRAY); // #endif
glEnable(GL_TEXTURE_2D);
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
// If you are using this code with non-legacy OpenGL header/contexts (which you should not, prefer using imgui_impl_opengl3.cpp!!), // Support for GL 4.5 rarely used glClipControl(GL_UPPER_LEFT)
// you may need to backup/reset/restore current shader using the lines below. DO NOT MODIFY THIS FILE! Add the code in your calling function: bool clip_origin_lower_left = true;
// GLint last_program; // #if defined(GL_CLIP_ORIGIN) && !defined(__APPLE__)
// glGetIntegerv(GL_CURRENT_PROGRAM, &last_program); // GLenum current_clip_origin = 0; glGetIntegerv(GL_CLIP_ORIGIN, (GLint*)&current_clip_origin);
// glUseProgram(0); // if (current_clip_origin == GL_UPPER_LEFT)
// ImGui_ImplOpenGL2_RenderDrawData(...); // clip_origin_lower_left = false;
// glUseProgram(last_program) // #endif
// Setup viewport, orthographic projection matrix // Setup viewport, orthographic projection matrix
// Our visible imgui space lies from draw_data.DisplayPos (top left) to draw_data.DisplayPos+data_data.DisplaySize (bottom right). DisplayPos is (0,0) for single viewport apps. // Our visible imgui space lies from draw_data.DisplayPos (top left) to draw_data.DisplayPos+data_data.DisplaySize (bottom right). DisplayPos is (0,0) for single viewport apps.
glViewport(0, 0, cast(GLsizei)fb_width, cast(GLsizei)fb_height); glViewport(0, 0, cast(GLsizei)fb_width, cast(GLsizei)fb_height);
glMatrixMode(GL_PROJECTION); float L = draw_data.DisplayPos.x;
glPushMatrix(); float R = draw_data.DisplayPos.x + draw_data.DisplaySize.x;
glLoadIdentity(); float T = draw_data.DisplayPos.y;
glOrtho(draw_data.DisplayPos.x, draw_data.DisplayPos.x + draw_data.DisplaySize.x, draw_data.DisplayPos.y + draw_data.DisplaySize.y, draw_data.DisplayPos.y, -1.0f, +1.0f); float B = draw_data.DisplayPos.y + draw_data.DisplaySize.y;
glMatrixMode(GL_MODELVIEW); if (!clip_origin_lower_left) { float tmp = T; T = B; B = tmp; } // Swap top and bottom if origin is upper left
glPushMatrix(); const float[4][4] ortho_projection =
glLoadIdentity(); [
[ 2.0f/(R-L), 0.0f, 0.0f, 0.0f ],
[ 0.0f, 2.0f/(T-B), 0.0f, 0.0f ],
[ 0.0f, 0.0f, -1.0f, 0.0f ],
[ (R+L)/(L-R), (T+B)/(B-T), 0.0f, 1.0f ],
];
glUseProgram(g_ShaderHandle);
glUniform1i(g_AttribLocationTex, 0);
glUniformMatrix4fv(g_AttribLocationProjMtx, 1, GL_FALSE, &ortho_projection[0][0]);
// #ifdef GL_SAMPLER_BINDING
// glBindSampler(0, 0); // We use combined texture/sampler state. Applications using GL 3.3 may set that otherwise.
// #endif
// (void)vertex_array_object;
// #ifndef IMGUI_IMPL_OPENGL_ES2
// glBindVertexArray(vertex_array_object);
// #endif
// Bind vertex/index buffers and setup attributes for ImDrawVert
glBindBuffer(GL_ARRAY_BUFFER, g_VboHandle);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, g_ElementsHandle);
glEnableVertexAttribArray(g_AttribLocationVtxPos);
glEnableVertexAttribArray(g_AttribLocationVtxUV);
glEnableVertexAttribArray(g_AttribLocationVtxColor);
glVertexAttribPointer(g_AttribLocationVtxPos, 2, GL_FLOAT, GL_FALSE, ImDrawVert.sizeof, cast(GLvoid*)ImDrawVert.pos.offsetof);
glVertexAttribPointer(g_AttribLocationVtxUV, 2, GL_FLOAT, GL_FALSE, ImDrawVert.sizeof, cast(GLvoid*)ImDrawVert.uv.offsetof);
glVertexAttribPointer(g_AttribLocationVtxColor, 4, GL_UNSIGNED_BYTE, GL_TRUE, ImDrawVert.sizeof, cast(GLvoid*)ImDrawVert.col.offsetof);
} }
// OpenGL2 Render function.
// (this used to be set in io.RenderDrawListsFn and called by ImGui::Render(), but you can now call this directly from your main loop) void ImGui_ImplOpenGL3_Shutdown()
// Note that this implementation is little overcomplicated because we are saving/setting up/restoring every OpenGL state explicitly, in order to be able to run within any OpenGL engine that doesn't do so. {
void ImGuiImplOpenGL2RenderDrawData(ImDrawData* draw_data) ImGui_ImplOpenGL3_DestroyDeviceObjects();
}
void ImGui_ImplOpenGL3_NewFrame()
{
if (!g_ShaderHandle)
ImGui_ImplOpenGL3_CreateDeviceObjects();
}
bool ImGui_ImplOpenGL3_CreateDeviceObjects()
{
// Backup GL state
GLint last_texture, last_array_buffer;
glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture);
glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &last_array_buffer);
// #ifndef IMGUI_IMPL_OPENGL_ES2
// GLint last_vertex_array;
// glGetIntegerv(GL_VERTEX_ARRAY_BINDING, &last_vertex_array);
// #endif
// Parse GLSL version string
import core.stdc.stdio;
int glsl_version = 130;
sscanf(g_GlslVersionString.ptr, "#version %d", &glsl_version);
const GLchar* vertex_shader_glsl_120 =
"uniform mat4 ProjMtx;\n
attribute vec2 Position;\n
attribute vec2 UV;\n
attribute vec4 Color;\n
varying vec2 Frag_UV;\n
varying vec4 Frag_Color;\n
void main()\n
{\n
Frag_UV = UV;\n
Frag_Color = Color;\n
gl_Position = ProjMtx * vec4(Position.xy,0,1);\n
}\n";
const GLchar* vertex_shader_glsl_130 =
"uniform mat4 ProjMtx;\n
in vec2 Position;\n
in vec2 UV;\n
in vec4 Color;\n
out vec2 Frag_UV;\n
out vec4 Frag_Color;\n
void main()\n
{\n
Frag_UV = UV;\n
Frag_Color = Color;\n
gl_Position = ProjMtx * vec4(Position.xy,0,1);\n
}\n";
const GLchar* vertex_shader_glsl_300_es =
"precision mediump float;\n
layout (location = 0) in vec2 Position;\n
layout (location = 1) in vec2 UV;\n
layout (location = 2) in vec4 Color;\n
uniform mat4 ProjMtx;\n
out vec2 Frag_UV;\n
out vec4 Frag_Color;\n
void main()\n
{\n
Frag_UV = UV;\n
Frag_Color = Color;\n
gl_Position = ProjMtx * vec4(Position.xy,0,1);\n
}\n";
const GLchar* vertex_shader_glsl_410_core =
"layout (location = 0) in vec2 Position;\n
layout (location = 1) in vec2 UV;\n
layout (location = 2) in vec4 Color;\n
uniform mat4 ProjMtx;\n
out vec2 Frag_UV;\n
out vec4 Frag_Color;\n
void main()\n
{\n
Frag_UV = UV;\n
Frag_Color = Color;\n
gl_Position = ProjMtx * vec4(Position.xy,0,1);\n
}\n";
const GLchar* fragment_shader_glsl_120 =
"#ifdef GL_ES\n
precision mediump float;\n
#endif\n
uniform sampler2D Texture;\n
varying vec2 Frag_UV;\n
varying vec4 Frag_Color;\n
void main()\n
{\n
gl_FragColor = Frag_Color * texture2D(Texture, Frag_UV.st);\n
}\n";
const GLchar* fragment_shader_glsl_130 =
"uniform sampler2D Texture;\n
in vec2 Frag_UV;\n
in vec4 Frag_Color;\n
out vec4 Out_Color;\n
void main()\n
{\n
Out_Color = Frag_Color * texture(Texture, Frag_UV.st);\n
}\n";
const GLchar* fragment_shader_glsl_300_es =
"precision mediump float;\n
uniform sampler2D Texture;\n
in vec2 Frag_UV;\n
in vec4 Frag_Color;\n
layout (location = 0) out vec4 Out_Color;\n
void main()\n
{\n
Out_Color = Frag_Color * texture(Texture, Frag_UV.st);\n
}\n";
const GLchar* fragment_shader_glsl_410_core =
"in vec2 Frag_UV;\n
in vec4 Frag_Color;\n
uniform sampler2D Texture;\n
layout (location = 0) out vec4 Out_Color;\n
void main()\n
{\n
Out_Color = Frag_Color * texture(Texture, Frag_UV.st);\n
}\n";
// Select shaders matching our GLSL versions
const (char)* vertex_shader = null;
const (char)* fragment_shader = null;
if (glsl_version < 130)
{
vertex_shader = vertex_shader_glsl_120;
fragment_shader = fragment_shader_glsl_120;
}
else if (glsl_version >= 410)
{
vertex_shader = vertex_shader_glsl_410_core;
fragment_shader = fragment_shader_glsl_410_core;
}
else if (glsl_version == 300)
{
vertex_shader = vertex_shader_glsl_300_es;
fragment_shader = fragment_shader_glsl_300_es;
}
else
{
vertex_shader = vertex_shader_glsl_130;
fragment_shader = fragment_shader_glsl_130;
}
// Create shaders
const (char)*[2] vertex_shader_with_version = [ g_GlslVersionString.ptr, vertex_shader ];
g_VertHandle = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(g_VertHandle, 2, vertex_shader_with_version.ptr, null);
glCompileShader(g_VertHandle);
CheckShader(g_VertHandle, "vertex shader");
const (char)*[2] fragment_shader_with_version = [ g_GlslVersionString.ptr, fragment_shader ];
g_FragHandle = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(g_FragHandle, 2, fragment_shader_with_version.ptr, null);
glCompileShader(g_FragHandle);
CheckShader(g_FragHandle, "fragment shader");
g_ShaderHandle = glCreateProgram();
glAttachShader(g_ShaderHandle, g_VertHandle);
glAttachShader(g_ShaderHandle, g_FragHandle);
glLinkProgram(g_ShaderHandle);
CheckProgram(g_ShaderHandle, "shader program");
g_AttribLocationTex = glGetUniformLocation(g_ShaderHandle, "Texture");
g_AttribLocationProjMtx = glGetUniformLocation(g_ShaderHandle, "ProjMtx");
g_AttribLocationVtxPos = glGetAttribLocation(g_ShaderHandle, "Position");
g_AttribLocationVtxUV = glGetAttribLocation(g_ShaderHandle, "UV");
g_AttribLocationVtxColor = glGetAttribLocation(g_ShaderHandle, "Color");
// Create buffers
glGenBuffers(1, &g_VboHandle);
glGenBuffers(1, &g_ElementsHandle);
ImGui_ImplOpenGL3_CreateFontsTexture();
// Restore modified GL state
glBindTexture(GL_TEXTURE_2D, last_texture);
glBindBuffer(GL_ARRAY_BUFFER, last_array_buffer);
// #ifndef IMGUI_IMPL_OPENGL_ES2
// glBindVertexArray(last_vertex_array);
// #endif
return true;
}
void ImGui_ImplOpenGL3_DestroyDeviceObjects()
{
if (g_VboHandle) { glDeleteBuffers(1, &g_VboHandle); g_VboHandle = 0; }
if (g_ElementsHandle) { glDeleteBuffers(1, &g_ElementsHandle); g_ElementsHandle = 0; }
if (g_ShaderHandle && g_VertHandle) { glDetachShader(g_ShaderHandle, g_VertHandle); }
if (g_ShaderHandle && g_FragHandle) { glDetachShader(g_ShaderHandle, g_FragHandle); }
if (g_VertHandle) { glDeleteShader(g_VertHandle); g_VertHandle = 0; }
if (g_FragHandle) { glDeleteShader(g_FragHandle); g_FragHandle = 0; }
if (g_ShaderHandle) { glDeleteProgram(g_ShaderHandle); g_ShaderHandle = 0; }
ImGui_ImplOpenGL3_DestroyFontsTexture();
}
static bool CheckShader(GLuint handle, const char* desc)
{
GLint status = 0, log_length = 0;
glGetShaderiv(handle, GL_COMPILE_STATUS, &status);
glGetShaderiv(handle, GL_INFO_LOG_LENGTH, &log_length);
/*if (cast(GLboolean)status == GL_FALSE)
fprintf(stderr, "ERROR: ImGui_ImplOpenGL3_CreateDeviceObjects: failed to compile %s!\n", desc);
if (log_length > 1)
{
ImVector<char> buf;
buf.resize(cast(int)(log_length + 1));
glGetShaderInfoLog(handle, log_length, null, cast(GLchar*)buf.begin());
fprintf(stderr, "%s\n", buf.begin());
}*/
return cast(GLboolean)status == GL_TRUE;
}
// If you get an error please report on GitHub. You may try different GL context version or GLSL version.
static bool CheckProgram(GLuint handle, const char* desc)
{
GLint status = 0, log_length = 0;
glGetProgramiv(handle, GL_LINK_STATUS, &status);
glGetProgramiv(handle, GL_INFO_LOG_LENGTH, &log_length);
/*if (cast(GLboolean)status == GL_FALSE)
fprintf(stderr, "ERROR: ImGui_ImplOpenGL3_CreateDeviceObjects: failed to link %s! (with GLSL '%s')\n", desc, g_GlslVersionString);
if (log_length > 1)
{
ImVector<char> buf;
buf.resize(cast(int)(log_length + 1));
glGetProgramInfoLog(handle, log_length, null, cast(GLchar*)buf.begin());
fprintf(stderr, "%s\n", buf.begin());
}*/
return cast(GLboolean)status == GL_TRUE;
}
bool ImGui_ImplOpenGL3_CreateFontsTexture()
{
// Build texture atlas
ImGuiIO* io = igGetIO();
ubyte* pixels;
int width, height, bpp;
ImFontAtlas_GetTexDataAsRGBA32(io.Fonts,&pixels, &width, &height, &bpp);
//io.Fonts.GetTexDataAsRGBA32(&pixels, &width, &height); // Load as RGBA 32-bit (75% of the memory is wasted, but default font is so small) because it is more likely to be compatible with user's existing shaders. If your ImTextureId represent a higher-level concept than just a GL texture id, consider calling GetTexDataAsAlpha8() instead to save on GPU memory.
// Upload texture to graphics system
GLint last_texture;
glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture);
glGenTextures(1, &g_FontTexture);
glBindTexture(GL_TEXTURE_2D, g_FontTexture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
// #ifdef GL_UNPACK_ROW_LENGTH
// glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
// #endif
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
// Store our identifier
io.Fonts.TexID = cast(ImTextureID)cast(sizediff_t)g_FontTexture;
// Restore state
glBindTexture(GL_TEXTURE_2D, last_texture);
return true;
}
void ImGui_ImplOpenGL3_DestroyFontsTexture()
{
if (g_FontTexture)
{
ImGuiIO* io = igGetIO();
glDeleteTextures(1, &g_FontTexture);
io.Fonts.TexID = null;
g_FontTexture = 0;
}
}
void ImGui_ImplOpenGL3_RenderDrawData(ImDrawData* draw_data)
{ {
// Avoid rendering when minimized, scale coordinates for retina displays (screen coordinates != framebuffer coordinates) // Avoid rendering when minimized, scale coordinates for retina displays (screen coordinates != framebuffer coordinates)
int fb_width = cast(int)(draw_data.DisplaySize.x * draw_data.FramebufferScale.x); int fb_width = cast(int)(draw_data.DisplaySize.x * draw_data.FramebufferScale.x);
int fb_height = cast(int)(draw_data.DisplaySize.y * draw_data.FramebufferScale.y); int fb_height = cast(int)(draw_data.DisplaySize.y * draw_data.FramebufferScale.y);
if (fb_width == 0 || fb_height == 0) if (fb_width <= 0 || fb_height <= 0)
return; return;
// Backup GL state // Backup GL state
GLenum last_active_texture; glGetIntegerv(GL_ACTIVE_TEXTURE, cast(GLint*)&last_active_texture);
glActiveTexture(GL_TEXTURE0);
GLint last_program; glGetIntegerv(GL_CURRENT_PROGRAM, &last_program);
GLint last_texture; glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture); GLint last_texture; glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture);
GLint[2] last_polygon_mode; glGetIntegerv(GL_POLYGON_MODE, last_polygon_mode.ptr); // #ifdef GL_SAMPLER_BINDING
// GLint last_sampler; glGetIntegerv(GL_SAMPLER_BINDING, &last_sampler);
// #endif
GLint last_array_buffer; glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &last_array_buffer);
// #ifndef IMGUI_IMPL_OPENGL_ES2
// GLint last_vertex_array_object; glGetIntegerv(GL_VERTEX_ARRAY_BINDING, &last_vertex_array_object);
// #endif
// #ifdef GL_POLYGON_MODE
// GLint last_polygon_mode[2]; glGetIntegerv(GL_POLYGON_MODE, last_polygon_mode);
// #endif
GLint[4] last_viewport; glGetIntegerv(GL_VIEWPORT, last_viewport.ptr); GLint[4] last_viewport; glGetIntegerv(GL_VIEWPORT, last_viewport.ptr);
GLint[4] last_scissor_box; glGetIntegerv(GL_SCISSOR_BOX, last_scissor_box.ptr); GLint[4] last_scissor_box; glGetIntegerv(GL_SCISSOR_BOX, last_scissor_box.ptr);
glPushAttrib(GL_ENABLE_BIT | GL_COLOR_BUFFER_BIT | GL_TRANSFORM_BIT); GLenum last_blend_src_rgb; glGetIntegerv(GL_BLEND_SRC_RGB, cast(GLint*)&last_blend_src_rgb);
GLenum last_blend_dst_rgb; glGetIntegerv(GL_BLEND_DST_RGB, cast(GLint*)&last_blend_dst_rgb);
GLenum last_blend_src_alpha; glGetIntegerv(GL_BLEND_SRC_ALPHA, cast(GLint*)&last_blend_src_alpha);
GLenum last_blend_dst_alpha; glGetIntegerv(GL_BLEND_DST_ALPHA, cast(GLint*)&last_blend_dst_alpha);
GLenum last_blend_equation_rgb; glGetIntegerv(GL_BLEND_EQUATION_RGB, cast(GLint*)&last_blend_equation_rgb);
GLenum last_blend_equation_alpha; glGetIntegerv(GL_BLEND_EQUATION_ALPHA, cast(GLint*)&last_blend_equation_alpha);
GLboolean last_enable_blend = glIsEnabled(GL_BLEND);
GLboolean last_enable_cull_face = glIsEnabled(GL_CULL_FACE);
GLboolean last_enable_depth_test = glIsEnabled(GL_DEPTH_TEST);
GLboolean last_enable_scissor_test = glIsEnabled(GL_SCISSOR_TEST);
// Setup desired GL state // Setup desired GL state
ImGuiImplOpenGL2SetupRenderState(draw_data, fb_width, fb_height); // Recreate the VAO every time (this is to easily allow multiple GL contexts to be rendered to. VAO are not shared among GL contexts)
// The renderer would actually work without any VAO bound, but then our VertexAttrib calls would overwrite the default one currently bound.
GLuint vertex_array_object = 0;
// #ifndef IMGUI_IMPL_OPENGL_ES2
// glGenVertexArrays(1, &vertex_array_object);
// #endif
ImGui_ImplOpenGL3_SetupRenderState(draw_data, fb_width, fb_height, vertex_array_object);
// Will project scissor/clipping rectangles into framebuffer space // Will project scissor/clipping rectangles into framebuffer space
ImVec2 clip_off = draw_data.DisplayPos; // (0,0) unless using multi-viewports ImVec2 clip_off = draw_data.DisplayPos; // (0,0) unless using multi-viewports
@ -401,23 +775,22 @@ void ImGuiImplOpenGL2RenderDrawData(ImDrawData* draw_data)
// Render command lists // Render command lists
for (int n = 0; n < draw_data.CmdListsCount; n++) for (int n = 0; n < draw_data.CmdListsCount; n++)
{ {
ImDrawList* cmd_list = draw_data.CmdLists[n]; const ImDrawList* cmd_list = draw_data.CmdLists[n];
ImDrawVert* vtx_buffer = cmd_list.VtxBuffer.Data;
ImDrawIdx* idx_buffer = cmd_list.IdxBuffer.Data; // Upload vertex/index buffers
glVertexPointer(2, GL_FLOAT, ImDrawVert.sizeof, cast(const GLvoid*)(cast(const char*)vtx_buffer + ImDrawVert.pos.offsetof)); glBufferData(GL_ARRAY_BUFFER, cast(GLsizeiptr)cmd_list.VtxBuffer.Size * ImDrawVert.sizeof, cast(const GLvoid*)cmd_list.VtxBuffer.Data, GL_STREAM_DRAW);
glTexCoordPointer(2, GL_FLOAT, ImDrawVert.sizeof, cast(const GLvoid*)(cast(const char*)vtx_buffer + ImDrawVert.uv.offsetof)); glBufferData(GL_ELEMENT_ARRAY_BUFFER, cast(GLsizeiptr)cmd_list.IdxBuffer.Size * ImDrawIdx.sizeof, cast(const GLvoid*)cmd_list.IdxBuffer.Data, GL_STREAM_DRAW);
glColorPointer(4, GL_UNSIGNED_BYTE, ImDrawVert.sizeof, cast(const GLvoid*)(cast(const char*)vtx_buffer + ImDrawVert.col.offsetof));
for (int cmd_i = 0; cmd_i < cmd_list.CmdBuffer.Size; cmd_i++) for (int cmd_i = 0; cmd_i < cmd_list.CmdBuffer.Size; cmd_i++)
{ {
const ImDrawCmd* pcmd = &cmd_list.CmdBuffer.Data[cmd_i]; const ImDrawCmd* pcmd = &cmd_list.CmdBuffer.Data[cmd_i];
if (pcmd.UserCallback) if (pcmd.UserCallback != null)
{ {
// User callback, registered via ImDrawList::AddCallback() // User callback, registered via ImDrawList::AddCallback()
// (ImDrawCallback_ResetRenderState is a special callback value used by the user to request the renderer to reset render state.) // (ImDrawCallback_ResetRenderState is a special callback value used by the user to request the renderer to reset render state.)
/*if (pcmd.UserCallback == &ImDrawCallback_ResetRenderState) // if (pcmd.UserCallback == ImDrawCallback_ResetRenderState)
ImGui_ImplOpenGL2_SetupRenderState(draw_data, fb_width, fb_height); // ImGui_ImplOpenGL3_SetupRenderState(draw_data, fb_width, fb_height, vertex_array_object);
else*/ // else
pcmd.UserCallback(cmd_list, pcmd); pcmd.UserCallback(cmd_list, pcmd);
} }
else else
@ -435,74 +808,43 @@ void ImGuiImplOpenGL2RenderDrawData(ImDrawData* draw_data)
glScissor(cast(int)clip_rect.x, cast(int)(fb_height - clip_rect.w), cast(int)(clip_rect.z - clip_rect.x), cast(int)(clip_rect.w - clip_rect.y)); glScissor(cast(int)clip_rect.x, cast(int)(fb_height - clip_rect.w), cast(int)(clip_rect.z - clip_rect.x), cast(int)(clip_rect.w - clip_rect.y));
// Bind texture, Draw // Bind texture, Draw
glBindTexture(GL_TEXTURE_2D, cast(GLuint)pcmd.TextureId); glBindTexture(GL_TEXTURE_2D, cast(GLuint)cast(sizediff_t)pcmd.TextureId);
glDrawElements(GL_TRIANGLES, cast(GLsizei)pcmd.ElemCount, ImDrawIdx.sizeof == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT, idx_buffer); // #if IMGUI_IMPL_OPENGL_MAY_HAVE_VTX_OFFSET
// if (g_GlVersion >= 320)
// glDrawElementsBaseVertex(GL_TRIANGLES, (GLsizei)pcmd.ElemCount, sizeof(ImDrawIdx) == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT, (void*)(intptr_t)(pcmd.IdxOffset * sizeof(ImDrawIdx)), (GLint)pcmd.VtxOffset);
// else
// #endif
glDrawElements(GL_TRIANGLES, cast(GLsizei)pcmd.ElemCount, ImDrawIdx.sizeof == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT, cast(void*)cast(sizediff_t)(pcmd.IdxOffset * ImDrawIdx.sizeof));
} }
} }
idx_buffer += pcmd.ElemCount;
} }
} }
// Destroy the temporary VAO
// #ifndef IMGUI_IMPL_OPENGL_ES2
// glDeleteVertexArrays(1, &vertex_array_object);
// #endif
// Restore modified GL state // Restore modified GL state
glDisableClientState(GL_COLOR_ARRAY); glUseProgram(last_program);
glDisableClientState(GL_TEXTURE_COORD_ARRAY); glBindTexture(GL_TEXTURE_2D, last_texture);
glDisableClientState(GL_VERTEX_ARRAY); // #ifdef GL_SAMPLER_BINDING
glBindTexture(GL_TEXTURE_2D, cast(GLuint)last_texture); // glBindSampler(0, last_sampler);
glMatrixMode(GL_MODELVIEW); // #endif
glPopMatrix(); glActiveTexture(last_active_texture);
glMatrixMode(GL_PROJECTION); // #ifndef IMGUI_IMPL_OPENGL_ES2
glPopMatrix(); // glBindVertexArray(last_vertex_array_object);
glPopAttrib(); // #endif
glPolygonMode(GL_FRONT, cast(GLenum)last_polygon_mode[0]); glPolygonMode(GL_BACK, cast(GLenum)last_polygon_mode[1]); glBindBuffer(GL_ARRAY_BUFFER, last_array_buffer);
glBlendEquationSeparate(last_blend_equation_rgb, last_blend_equation_alpha);
glBlendFuncSeparate(last_blend_src_rgb, last_blend_dst_rgb, last_blend_src_alpha, last_blend_dst_alpha);
if (last_enable_blend) glEnable(GL_BLEND); else glDisable(GL_BLEND);
if (last_enable_cull_face) glEnable(GL_CULL_FACE); else glDisable(GL_CULL_FACE);
if (last_enable_depth_test) glEnable(GL_DEPTH_TEST); else glDisable(GL_DEPTH_TEST);
if (last_enable_scissor_test) glEnable(GL_SCISSOR_TEST); else glDisable(GL_SCISSOR_TEST);
// #ifdef GL_POLYGON_MODE
// glPolygonMode(GL_FRONT_AND_BACK, (GLenum)last_polygon_mode[0]);
// #endif
glViewport(last_viewport[0], last_viewport[1], cast(GLsizei)last_viewport[2], cast(GLsizei)last_viewport[3]); glViewport(last_viewport[0], last_viewport[1], cast(GLsizei)last_viewport[2], cast(GLsizei)last_viewport[3]);
glScissor(last_scissor_box[0], last_scissor_box[1], cast(GLsizei)last_scissor_box[2], cast(GLsizei)last_scissor_box[3]); glScissor(last_scissor_box[0], last_scissor_box[1], cast(GLsizei)last_scissor_box[2], cast(GLsizei)last_scissor_box[3]);
} }
bool ImGuiImplOpenGL2CreateFontsTexture()
{
// Build texture atlas
ImGuiIO* io = igGetIO();
ubyte* pixels;
int width, height;
int bpp;
ImFontAtlas_GetTexDataAsRGBA32(io.Fonts, &pixels, &width, &height, &bpp); // Load as RGBA 32-bits (75% of the memory is wasted, but default font is so small) because it is more likely to be compatible with user's existing shaders. If your ImTextureId represent a higher-level concept than just a GL texture id, consider calling GetTexDataAsAlpha8() instead to save on GPU memory.
// Upload texture to graphics system
GLint last_texture;
glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture);
glGenTextures(1, &g_FontTexture);
glBindTexture(GL_TEXTURE_2D, g_FontTexture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
// Store our identifier
io.Fonts.TexID = cast(ImTextureID)g_FontTexture;
// Restore state
glBindTexture(GL_TEXTURE_2D, last_texture);
return true;
}
void ImGuiImplOpenGL2DestroyFontsTexture()
{
if (g_FontTexture)
{
ImGuiIO* io = igGetIO();
glDeleteTextures(1, &g_FontTexture);
io.Fonts.TexID = null;
g_FontTexture = 0;
}
}
bool ImGuiImplOpenGL2CreateDeviceObjects()
{
return ImGuiImplOpenGL2CreateFontsTexture();
}
void ImGuiImplOpenGL2DestroyDeviceObjects()
{
ImGuiImplOpenGL2DestroyFontsTexture();
}

View file

@ -1,5 +1,7 @@
module ecs_utils.math.vector; module ecs_utils.math.vector;
import ecs_utils.utils;
struct vec2 struct vec2
{ {
this(float v) @nogc nothrow this(float v) @nogc nothrow
@ -42,6 +44,11 @@ struct vec2
else static assert(0, "Operator "~op~" not implemented"); else static assert(0, "Operator "~op~" not implemented");
} }
vec2 opUnary(string op)()if (op == "-")
{
return vec2(-x,-y);
}
ivec2 opCast() ivec2 opCast()
{ {
return ivec2(cast(int)x,cast(int)y); return ivec2(cast(int)x,cast(int)y);
@ -71,6 +78,31 @@ struct vec2
} }
else static assert(0, "Operator "~op~" not implemented"); else static assert(0, "Operator "~op~" not implemented");
} }
float length2()
{
return x*x + y*y;
}
float length()
{
return sqrtf(length2);
}
float fastSqrLength()
{
return rsqrt(length2);
}
vec2 normalize()
{
return this * fastSqrLength();
}
}
float dot(vec2 a, vec2 b)
{
return a.x*b.x + a.y*b.y;
} }
struct vec4 struct vec4

View file

@ -2,13 +2,26 @@ module ecs_utils.utils;
extern(C): extern(C):
int randomRange(int min, int max) import ecs_utils.math.vector;
enum PI = 3.141592653589793238462643383279502884197169399375105820;
extern(C) float sqrtf(float x) @nogc nothrow @system;
extern(C) float acosf(float x) @nogc nothrow @system;
extern(C) float sinf(float x) @nogc nothrow @system;
extern(C) float cosf(float x) @nogc nothrow @system;
extern(C) float powf(float x, float y) @nogc nothrow @system;
extern(C) float fabs(float x) @nogc nothrow @system;
extern(C) float log2f(float arg) @nogc nothrow @system;
int randomRange(int min, int max) nothrow @nogc @trusted
{ {
int range = max - min; int range = max - min;
return rand() % range - min; return rand() % range - min;
} }
float randomf() float randomf() nothrow @nogc @trusted
{ {
const float scale = 1.0 / 32_767.0; const float scale = 1.0 / 32_767.0;
return cast(float)(rand() & 0x007FFF) * scale; return cast(float)(rand() & 0x007FFF) * scale;
@ -21,6 +34,38 @@ float randomRangef(float min, float max)
return rand()%4096; return rand()%4096;
}*/ }*/
float mix(float x, float y, float a)
{
//return x*a + y*(a-1);
//return x*a + y*a - y;
return x*(a+y) - y;
}
float rsqrt(float number)
{
long i;
float x2, y;
const float threehalfs = 1.5F;
x2 = number * 0.5F;
y = number;
i = * cast( long * ) &y; // evil floating point bit level hacking
i = 0x5f3759df - ( i >> 1 ); // what the fuck?
y = * cast( float * ) &i;
y = y * ( threehalfs - ( x2 * y * y ) ); // 1st iteration
return y;
}
vec2 randomCircularSample() nothrow @nogc @trusted
{
float angle = 2 * PI * randomf;
float radius = sqrtf(randomf);
float s = sinf(angle);
float c = cosf(angle);
return vec2(c,s)*radius;
}
version(GNU) version(GNU)
{ {
public import core.stdc.stdio : printf; public import core.stdc.stdio : printf;
@ -32,9 +77,13 @@ version(GNU)
else else
{ {
extern(C) int printf(scope const char* format, ...) @nogc nothrow @system; extern(C) int printf(scope const char* format, ...) @nogc nothrow @system;
public import std.array : staticArray; // public import std.array : staticArray;
pragma(inline, true) T[n] staticArray(T, size_t n)(auto ref T[n] a)
{
return a;
}
} }
extern(C) int rand(); extern(C) int rand() nothrow @nogc @trusted;
version(D_BetterC) version(D_BetterC)
{ {
@ -58,7 +107,15 @@ version(D_BetterC)
} }
} }
version(Android)
{
alias pthread_key_t = uint;
extern (C) int pthread_key_create(pthread_key_t *, void* function(void *)) @nogc nothrow;
extern (C) int pthread_key_delete(pthread_key_t) @nogc nothrow;
extern (C) void* pthread_getspecific(pthread_key_t) @nogc nothrow;
extern (C) int pthread_setspecific(pthread_key_t, const void *) @nogc nothrow;
}
version(WebAssembly) version(WebAssembly)
{ {

View file

@ -1,5 +1,6 @@
{ {
"name": "ecs", "name": "bubel_ecs",
"targetName" : "ecs",
"authors": [ "authors": [
"Michał Masiukiewicz", "Dawid Masiukiewicz" "Michał Masiukiewicz", "Dawid Masiukiewicz"
], ],
@ -118,7 +119,8 @@
"-unittest" "-unittest"
], ],
"dflags-gdc": [ "dflags-gdc": [
"-fno-druntime" "-fno-druntime",
"-lpthread"
], ],
"sourcePaths": ["source/","tests/"], "sourcePaths": ["source/","tests/"],
"mainSourceFile":"tests/runner.d", "mainSourceFile":"tests/runner.d",

View file

@ -23,6 +23,8 @@ tests_src = [
] ]
betterC_opt = get_option('betterC') betterC_opt = get_option('betterC')
BuildDemos_opt = get_option('BuildDemos')
LTO_otp = get_option('LTO')
comp = meson.get_compiler('d') comp = meson.get_compiler('d')
@ -31,16 +33,43 @@ comp_id = comp.get_id()
args = [] args = []
link_args = [] link_args = []
if comp_id == 'gcc'
args += '-pthread'
link_args += '-pthread'
endif
if LTO_otp
if comp_id == 'gcc'
args += '-flto'
link_args += '-flto'
elif comp_id == 'llvm'
args += '-flto=thin'
link_args += '-flto=thin'
else
message('LTO don\'t work with DMD')
endif
endif
if betterC_opt if betterC_opt
args += '-betterC' if comp_id == 'gcc'
link_args += '-betterC' args += ['-fno-druntime']
link_args += ['-fno-druntime']
else
args += '-betterC'
link_args += '-betterC'
endif
endif endif
inc = include_directories('source/') inc = include_directories('source/')
tests_inc = include_directories('source/') tests_inc = include_directories('source/')
ecs_lib = shared_library('ecs', src, include_directories : [tests_inc, inc], d_args: args, link_args: link_args) ecs_lib = library('ecs', src, include_directories : [tests_inc, inc], d_args: args, link_args: link_args)
executable('tests', tests_src, include_directories : [tests_inc, inc], d_args: args, link_args: link_args, link_with: ecs_lib) executable('tests', tests_src, include_directories : [tests_inc, inc], d_args: args, link_args: link_args, link_with: ecs_lib)
bubel_ecs_dep = declare_dependency(include_directories : [inc], link_with : ecs_lib)
if BuildDemos_opt
subdir('demos/utils')
subdir('demos')
endif

View file

@ -1 +1,3 @@
option('betterC', type: 'boolean', value: false) option('betterC', type: 'boolean', value: false)
option('BuildDemos', type: 'boolean', value: false)
option('LTO', type: 'boolean', value: false)

View file

@ -54,6 +54,7 @@ struct BlockAllocator
Mallocator.dispose(pointers); Mallocator.dispose(pointers);
pointers = next_pointers; pointers = next_pointers;
} }
next_block = null;
} }
private: private:

View file

@ -34,15 +34,26 @@ struct Entity
*/ */
T* getComponent(T)() const T* getComponent(T)() const
{ {
EntityManager.EntitiesBlock* block = gEM.getMetaData(&this); /*EntityManager.EntitiesBlock* block = gEM.getMetaData(&this);
EntityManager.EntityInfo* info = block.type_info; EntityManager.EntityInfo* info = block.type_info;
if (T.component_id >= info.deltas.length || info.deltas[T.component_id] == 0) if (T.component_id >= info.deltas.length || info.deltas[T.component_id] == 0)
return null; return null;
return cast(T*)(cast(void*)block + info.deltas[T.component_id] + block.entityIndex(&this) * T.sizeof); return cast(T*)(cast(void*)block + info.deltas[T.component_id] + block.entityIndex(&this) * T.sizeof);*/
return cast(T*)getComponent(T.component_id);
} }
bool hasComponent(ushort component_id) void* getComponent(ushort component_id) const
{
EntityManager.EntitiesBlock* block = gEM.getMetaData(&this);
EntityManager.EntityInfo* info = block.type_info;
if (component_id >= info.deltas.length || info.deltas[component_id] == 0)
return null;
return (cast(void*)block + info.deltas[component_id] + block.entityIndex(&this) * gEM.components[component_id].size);
}
bool hasComponent(ushort component_id) const
{ {
EntityManager.EntitiesBlock* block = gEM.getMetaData(&this); EntityManager.EntitiesBlock* block = gEM.getMetaData(&this);
EntityManager.EntityInfo* info = block.type_info; EntityManager.EntityInfo* info = block.type_info;
@ -50,7 +61,7 @@ struct Entity
return true; return true;
} }
EntityMeta getMeta() EntityMeta getMeta() const
{ {
EntityMeta meta; EntityMeta meta;
meta.block = gEM.getMetaData(&this); meta.block = gEM.getMetaData(&this);
@ -66,15 +77,26 @@ struct EntityMeta
T* getComponent(T)() const T* getComponent(T)() const
{ {
const (EntityManager.EntityInfo)* info = block.type_info; /*const (EntityManager.EntityInfo)* info = block.type_info;
if (T.component_id >= info.deltas.length || info.deltas[T.component_id] == 0) if (T.component_id >= info.deltas.length || info.deltas[T.component_id] == 0)
return null; return null;
return cast(T*)(cast(void*)block + block.type_info.deltas[T.component_id] + index * T.sizeof); return cast(T*)(cast(void*)block + info.deltas[T.component_id] + index * T.sizeof);*/
return cast(T*)getComponent(T.component_id);
} }
bool hasComponent(ushort component_id) void* getComponent(ushort component_id) const
{ {
EntityManager.EntityInfo* info = block.type_info; const (EntityManager.EntityInfo)* info = block.type_info;
if (component_id >= info.deltas.length || info.deltas[component_id] == 0)
return null;
return (cast(void*)block + info.deltas[component_id] + index * gEM.components[component_id].size);
}
bool hasComponent(ushort component_id) const
{
const EntityManager.EntityInfo* info = block.type_info;
if (component_id >= info.deltas.length || info.deltas[component_id] == 0)return false; if (component_id >= info.deltas.length || info.deltas[component_id] == 0)return false;
return true; return true;
} }
@ -106,6 +128,15 @@ export struct EntityTemplate
if(T.component_id >= info.tmpl_deltas.length || info.tmpl_deltas[T.component_id] == ushort.max)return null; if(T.component_id >= info.tmpl_deltas.length || info.tmpl_deltas[T.component_id] == ushort.max)return null;
return cast(T*)(entity_data.ptr + info.tmpl_deltas[T.component_id]); return cast(T*)(entity_data.ptr + info.tmpl_deltas[T.component_id]);
} }
/************************************************************************************************************************
Get specified component. If component doesn't exist function return null. Returned pointer is valid during EntityTemplate lifetime.
*/
void* getComponent(ushort component_id) const nothrow @nogc
{
if(component_id >= info.tmpl_deltas.length || info.tmpl_deltas[component_id] == ushort.max)return null;
return cast(void*)(entity_data.ptr + info.tmpl_deltas[component_id]);
}
} }
/************************************************************************************************************************ /************************************************************************************************************************

View file

@ -15,7 +15,7 @@ struct IDManager
/************************************************************************************************************************ /************************************************************************************************************************
Get new ID. Get new ID.
*/ */
pragma(inline, false) EntityID getNewID() nothrow @nogc EntityID getNewID() nothrow @nogc
{ {
int current = m_stack_top.atomicOp!"-="(1) + 1; int current = m_stack_top.atomicOp!"-="(1) + 1;
if (current < 0) if (current < 0)
@ -177,15 +177,9 @@ struct IDManager
if (m_last_id > m_ids_array.length) if (m_last_id > m_ids_array.length)
{ {
uint begin = cast(uint) m_ids_array.length; uint begin = cast(uint) m_ids_array.length;
Data[] new_array = Mallocator.makeArray!Data(begin + (m_blocks_count << 16));
memcpy(new_array.ptr, m_ids_array.ptr, m_ids_array.length * Data.sizeof);
Mallocator.dispose(m_ids_array);
m_ids_array = new_array;
uint[] new_stack = Mallocator.makeArray!uint(m_ids_array.length); m_ids_array = Mallocator.resizeArray(m_ids_array, begin + (m_blocks_count << 16));
memcpy(new_stack.ptr, m_free_stack.ptr, m_free_stack.length * uint.sizeof); m_free_stack = Mallocator.resizeArray(m_free_stack, m_ids_array.length);
Mallocator.dispose(m_free_stack);
m_free_stack = new_stack;
foreach (block; m_blocks[0 .. m_blocks_count - 1]) foreach (block; m_blocks[0 .. m_blocks_count - 1])
{ {

View file

@ -96,29 +96,7 @@ export struct EntityManager
{ {
foreach (ref system; systems) foreach (ref system; systems)
{ {
system.disable(); system.destroy();
if (system.m_destroy)
(cast(void function(void*)) system.m_destroy)(system.m_system_pointer);
if (system.jobs)
Mallocator.dispose(system.jobs);
if (system.m_read_only_components)
Mallocator.dispose(system.m_read_only_components);
if (system.m_writable_components)
Mallocator.dispose(system.m_writable_components);
if (system.m_components)
Mallocator.dispose(system.m_components);
if (system.m_excluded_components)
Mallocator.dispose(system.m_excluded_components);
if (system.m_optional_components)
Mallocator.dispose(system.m_optional_components);
if (system.m_name)
Mallocator.dispose(system.m_name);
if (system.m_event_callers)
Mallocator.dispose(system.m_event_callers);
if (system.m_system_pointer)
Mallocator.dispose(system.m_system_pointer);
} }
foreach (EntityInfo* info; &entities_infos.byValue) foreach (EntityInfo* info; &entities_infos.byValue)
@ -382,6 +360,10 @@ export struct EntityManager
else else
assert(pass < passes.length, "Update pass (ID " ~ pass.to!string ~ ") doesn't exist."); assert(pass < passes.length, "Update pass (ID " ~ pass.to!string ~ ") doesn't exist.");
// enum SystemName = fullyQualifiedName!Sys;
enum SystemName = fullName!Sys;
//enum SystemName = Sys.stringof;
System system; System system;
system.m_pass = pass; system.m_pass = pass;
@ -418,9 +400,11 @@ export struct EntityManager
static if (Params.length == 2 && is(Params[0] == Entity*)) static if (Params.length == 2 && is(Params[0] == Entity*))
{ {
alias EventParamType = Params[1]; alias EventParamType = Params[1];
enum EventName = Unqual!(EventParamType).stringof; enum EventName = fullName!(Unqual!(EventParamType));
// enum EventName = fullyQualifiedName!(Unqual!(EventParamType));//.stringof;
ushort evt = events_map.get(cast(char[]) EventName, ushort.max); ushort evt = events_map.get(cast(char[]) EventName, ushort.max);
assert(evt != ushort.max, "Can't register system \"" ~ Sys.stringof assert(evt != ushort.max,
"Can't register system \"" ~ SystemName
~ "\" due to non existing event \"" ~ EventName ~ "\"."); ~ "\" due to non existing event \"" ~ EventName ~ "\".");
callers[i].callback = cast(void*)&callEventHandler!(EventParamType); callers[i].callback = cast(void*)&callEventHandler!(EventParamType);
@ -456,7 +440,7 @@ export struct EntityManager
uint writable_dep = 1; uint writable_dep = 1;
} }
static ComponentsCounts getComponentsCounts()() static ComponentsCounts getComponentsCounts()
{ {
ComponentsCounts components_counts; ComponentsCounts components_counts;
@ -479,7 +463,8 @@ export struct EntityManager
string name; string name;
static if (isArray!MemberType) static if (isArray!MemberType)
{ // Workaround. This code is never called with: not an array type, but compiler prints an error { // Workaround. This code is never called with: not an array type, but compiler prints an error
name = Unqual!(ForeachType!MemberType).stringof; // name = fullyQualifiedName!(Unqual!(ForeachType!MemberType));//.stringof;
name = fullName!(Unqual!(ForeachType!MemberType));
} }
bool is_optional; bool is_optional;
@ -679,7 +664,7 @@ export struct EntityManager
} }
static ComponentsIndices!component_counts getComponentsInfo()() static ComponentsIndices!component_counts getComponentsInfo()
{ {
ComponentsIndices!component_counts components_info; ComponentsIndices!component_counts components_info;
@ -704,7 +689,9 @@ export struct EntityManager
string name; string name;
static if (isArray!MemberType) static if (isArray!MemberType)
{ // Workaround. This code is never called with: not an array type, but compiler prints an error { // Workaround. This code is never called with: not an array type, but compiler prints an error
name = Unqual!(ForeachType!MemberType).stringof; // name = fullyQualifiedName!(Unqual!(ForeachType!MemberType));
name = fullName!(Unqual!(ForeachType!MemberType));
//name = Unqual!(ForeachType!MemberType).stringof;
} }
bool is_optional; bool is_optional;
@ -759,7 +746,8 @@ export struct EntityManager
{ {
foreach (str; Sys.ExcludedComponents) foreach (str; Sys.ExcludedComponents)
{ {
components_info.addExcluded(CompInfo(str.stringof, str.stringof)); components_info.addExcluded(CompInfo(str.stringof, fullName!str));
// components_info.addExcluded(CompInfo(str.stringof, str.stringof));
} }
} }
@ -786,7 +774,7 @@ export struct EntityManager
enum ComponentsIndices!component_counts components_info = getComponentsInfo(); enum ComponentsIndices!component_counts components_info = getComponentsInfo();
static void genCompList()(ref System system, ref HashMap!(char[], ushort) components_map) static void genCompList(ref System system, ref HashMap!(char[], ushort) components_map)
{ {
foreach (member; __traits(allMembers, Sys.EntitiesData)) foreach (member; __traits(allMembers, Sys.EntitiesData))
@ -828,10 +816,10 @@ export struct EntityManager
ushort comp = components_map.get(cast(char[]) comp_info.type, ushort.max); ushort comp = components_map.get(cast(char[]) comp_info.type, ushort.max);
version (D_BetterC) version (D_BetterC)
assert(comp != ushort.max, assert(comp != ushort.max,
"Can't register system \"" ~ Sys.stringof "Can't register system \"" ~ SystemName
~ "\" due to non existing component."); ~ "\" due to non existing component.");
else else
assert(comp != ushort.max, "Can't register system \"" ~ Sys.stringof assert(comp != ushort.max, "Can't register system \"" ~ SystemName
~ "\" due to non existing component \"" ~ comp_info.type ~ "\"."); ~ "\" due to non existing component \"" ~ comp_info.type ~ "\".");
system.m_components[iii] = comp; system.m_components[iii] = comp;
} }
@ -840,10 +828,10 @@ export struct EntityManager
ushort comp = components_map.get(cast(char[]) comp_info.type, ushort.max); ushort comp = components_map.get(cast(char[]) comp_info.type, ushort.max);
version (D_BetterC) version (D_BetterC)
assert(comp != ushort.max, assert(comp != ushort.max,
"Can't register system \"" ~ Sys.stringof "Can't register system \"" ~ SystemName
~ "\" due to non existing component."); ~ "\" due to non existing component.");
else else
assert(comp != ushort.max, "Can't register system \"" ~ Sys.stringof assert(comp != ushort.max, "Can't register system \"" ~ SystemName
~ "\" due to non existing component \"" ~ comp_info.type ~ "\"."); ~ "\" due to non existing component \"" ~ comp_info.type ~ "\".");
system.m_excluded_components[iii] = comp; system.m_excluded_components[iii] = comp;
} }
@ -852,10 +840,10 @@ export struct EntityManager
ushort comp = components_map.get(cast(char[]) comp_info.type, ushort.max); ushort comp = components_map.get(cast(char[]) comp_info.type, ushort.max);
version (D_BetterC) version (D_BetterC)
assert(comp != ushort.max, assert(comp != ushort.max,
"Can't register system \"" ~ Sys.stringof "Can't register system \"" ~ SystemName
~ "\" due to non existing component."); ~ "\" due to non existing component.");
else else
assert(comp != ushort.max, "Can't register system \"" ~ Sys.stringof assert(comp != ushort.max, "Can't register system \"" ~ SystemName
~ "\" due to non existing component \"" ~ comp_info.type ~ "\"."); ~ "\" due to non existing component \"" ~ comp_info.type ~ "\".");
system.m_optional_components[iii] = comp; system.m_optional_components[iii] = comp;
} }
@ -864,10 +852,10 @@ export struct EntityManager
ushort comp = components_map.get(cast(char[]) comp_info.type, ushort.max); ushort comp = components_map.get(cast(char[]) comp_info.type, ushort.max);
version (D_BetterC) version (D_BetterC)
assert(comp != ushort.max, assert(comp != ushort.max,
"Can't register system \"" ~ Sys.stringof "Can't register system \"" ~ SystemName
~ "\" due to non existing component."); ~ "\" due to non existing component.");
else else
assert(comp != ushort.max, "Can't register system \"" ~ Sys.stringof assert(comp != ushort.max, "Can't register system \"" ~ SystemName
~ "\" due to non existing component \"" ~ comp_info.type ~ "\"."); ~ "\" due to non existing component \"" ~ comp_info.type ~ "\".");
system.m_read_only_components[iii] = comp; system.m_read_only_components[iii] = comp;
} }
@ -876,16 +864,16 @@ export struct EntityManager
ushort comp = components_map.get(cast(char[]) comp_info.type, ushort.max); ushort comp = components_map.get(cast(char[]) comp_info.type, ushort.max);
version (D_BetterC) version (D_BetterC)
assert(comp != ushort.max, assert(comp != ushort.max,
"Can't register system \"" ~ Sys.stringof "Can't register system \"" ~ SystemName
~ "\" due to non existing component."); ~ "\" due to non existing component.");
else else
assert(comp != ushort.max, "Can't register system \"" ~ Sys.stringof assert(comp != ushort.max, "Can't register system \"" ~ SystemName
~ "\" due to non existing component \"" ~ comp_info.type ~ "\"."); ~ "\" due to non existing component \"" ~ comp_info.type ~ "\".");
system.m_writable_components[iii] = comp; system.m_writable_components[iii] = comp;
} }
} }
static void fillInputData()(ref Sys.EntitiesData input_data, EntityInfo* info, static void fillInputData(ref Sys.EntitiesData input_data, EntityInfo* info,
EntitiesBlock* block, uint offset, uint entities_count, System* system) EntitiesBlock* block, uint offset, uint entities_count, System* system)
{ {
//enum ComponentsIndices components_info = getComponentsInfo(); //enum ComponentsIndices components_info = getComponentsInfo();
@ -906,7 +894,9 @@ export struct EntityManager
input_data.thread_id = cast(typeof(input_data.thread_id))threadID(); input_data.thread_id = cast(typeof(input_data.thread_id))threadID();
}//*/ }//*/
static foreach (iii, comp_info; components_info.req) ///FIXME: should be "components_info.req()" but it's not compile with GCC
static foreach (iii, comp_info; components_info.m_req[0
.. components_info.m_req_counter])
{ {
__traits(getMember, input_data, comp_info.name) = (cast(ForeachType!(typeof(__traits(getMember, __traits(getMember, input_data, comp_info.name) = (cast(ForeachType!(typeof(__traits(getMember,
Sys.EntitiesData, comp_info.name)))*)( Sys.EntitiesData, comp_info.name)))*)(
@ -914,7 +904,8 @@ export struct EntityManager
.. entities_count]; .. entities_count];
} }
static foreach (iii, comp_info; components_info.optional) static foreach (iii, comp_info; components_info.m_optional[0
.. components_info.m_optional_counter])
{ {
if (system.m_optional_components[iii] < info.deltas.length if (system.m_optional_components[iii] < info.deltas.length
&& info.deltas[system.m_optional_components[iii]] != 0) && info.deltas[system.m_optional_components[iii]] != 0)
@ -928,7 +919,7 @@ export struct EntityManager
} }
} }
/*bool checkOnUpdateParams()() /*bool checkOnUpdateParams()
{ {
bool ret = false; bool ret = false;
foreach (func; __traits(getOverloads, Sys, "onUpdate")) foreach (func; __traits(getOverloads, Sys, "onUpdate"))
@ -1005,26 +996,30 @@ export struct EntityManager
else else
entities_count = block.entities_count; entities_count = block.entities_count;
assert(entities_count <= block.entities_count if (entities_count > 0)
&& offset <= block.entities_count);
fillInputData(input_data, info, block, offset, entities_count, system);
static if (hasMember!(Sys.EntitiesData, "thread_id"))
{ {
input_data.thread_id = cast(typeof(input_data.thread_id)) data assert(entities_count <= block.entities_count
.thread_id; && offset < block.entities_count);
assert(entities_count > offset);
fillInputData(input_data, info, block, offset, entities_count, system);
static if (hasMember!(Sys.EntitiesData, "thread_id"))
{
input_data.thread_id = cast(
typeof(input_data.thread_id)) data.thread_id;
}
static if (hasMember!(Sys.EntitiesData, "job_id"))
{
input_data.job_id = cast(typeof(input_data.job_id)) data.job_id;
}
//s.onUpdate(input_data);
(cast(typeof(&__traits(getOverloads, s,
"onUpdate")[OnUpdateOverloadNum])) data.update_delegate)(
input_data);
} }
static if (hasMember!(Sys.EntitiesData, "job_id"))
{
input_data.job_id = cast(typeof(input_data.job_id)) data.job_id;
}
//s.onUpdate(input_data);
(cast(typeof(&__traits(getOverloads, s,
"onUpdate")[OnUpdateOverloadNum])) data.update_delegate)(input_data);
block = block.next_block; block = block.next_block;
offset = 0; offset = 0;
blocks--; blocks--;
@ -1115,6 +1110,32 @@ export struct EntityManager
} }
} }
static void catchEntityFilterFunction(string func_name, RetType = void)(void** member)
{
static if (hasMember!(Sys, func_name))
{
foreach (func; __traits(getOverloads, Sys, func_name))
{
static if ((Parameters!(func)).length == 1
&& is(Parameters!(func)[0] == EntityInfo*)
&& is(ReturnType!(func) == RetType))
{
static RetType callFunc(void* system_pointer, EntityInfo* info)
{
Sys* s = cast(Sys*) system_pointer;
static if (is(RetTyp == void))
mixin("s." ~ func_name ~ "(info)");
else
return mixin("s." ~ func_name ~ "(info)");
}
*member = cast(void*)&callFunc;
break;
}
}
}
}
catchFunction!("onEnable")(&system.m_enable); catchFunction!("onEnable")(&system.m_enable);
catchFunction!("onDisable")(&system.m_disable); catchFunction!("onDisable")(&system.m_disable);
catchFunction!("onCreate")(&system.m_create); catchFunction!("onCreate")(&system.m_create);
@ -1126,6 +1147,8 @@ export struct EntityManager
catchEntityFunction!("onRemoveEntity")(&system.m_remove_entity); catchEntityFunction!("onRemoveEntity")(&system.m_remove_entity);
catchEntityFunction!("onChangeEntity")(&system.m_change_entity); catchEntityFunction!("onChangeEntity")(&system.m_change_entity);
catchEntityFilterFunction!("filterEntity", bool)(&system.m_filter_entity);
system.m_system_pointer = cast(void*) Mallocator.make!Sys; system.m_system_pointer = cast(void*) Mallocator.make!Sys;
system.m_priority = priority; system.m_priority = priority;
//(cast(Sys*) system.m_system_pointer).__ecsInitialize(); //(cast(Sys*) system.m_system_pointer).__ecsInitialize();
@ -1148,10 +1171,10 @@ export struct EntityManager
ushort.max); ushort.max);
version (D_BetterC) version (D_BetterC)
assert(comp != ushort.max, assert(comp != ushort.max,
"Can't register system \"" ~ Sys.stringof "Can't register system \"" ~ SystemName
~ "\" due to non existing dependency."); ~ "\" due to non existing dependency.");
else else
assert(comp != ushort.max, "Can't register system \"" ~ Sys.stringof assert(comp != ushort.max, "Can't register system \"" ~ SystemName
~ "\" due to non existing dependency \"" ~ comp_info.type ~ "\"."); ~ "\" due to non existing dependency \"" ~ comp_info.type ~ "\".");
system.m_readonly_dependencies[iii] = comp; system.m_readonly_dependencies[iii] = comp;
} }
@ -1161,21 +1184,20 @@ export struct EntityManager
ushort comp = external_dependencies_map.get(cast(char[]) comp_info.type, ushort.max); ushort comp = external_dependencies_map.get(cast(char[]) comp_info.type, ushort.max);
version (D_BetterC) version (D_BetterC)
assert(comp != ushort.max, assert(comp != ushort.max,
"Can't register system \"" ~ Sys.stringof "Can't register system \"" ~ SystemName
~ "\" due to non existing dependency."); ~ "\" due to non existing dependency.");
else else
assert(comp != ushort.max, "Can't register system \"" ~ Sys.stringof assert(comp != ushort.max, "Can't register system \"" ~ SystemName
~ "\" due to non existing dependency \"" ~ comp_info.type ~ "\"."); ~ "\" due to non existing dependency \"" ~ comp_info.type ~ "\".");
system.m_writable_dependencies[iii] = comp; system.m_writable_dependencies[iii] = comp;
} }
ushort sys_id = systems_map.get(cast(char[]) Sys.stringof, ushort.max); ushort sys_id = systems_map.get(cast(char[]) SystemName, ushort.max);
if (sys_id < systems.length) if (sys_id < systems.length)
{ {
systems[sys_id].disable(); system.m_name = systems[sys_id].m_name;
if (systems[sys_id].m_destroy) systems[sys_id].m_name = null;
(cast(void function(void*)) systems[sys_id].m_destroy)( systems[sys_id].destroy();
systems[sys_id].m_system_pointer);
if (system.m_create) if (system.m_create)
(cast(void function(void*)) system.m_create)(system.m_system_pointer); (cast(void function(void*)) system.m_create)(system.m_system_pointer);
@ -1183,12 +1205,11 @@ export struct EntityManager
system.enable(); system.enable();
system.m_id = sys_id; system.m_id = sys_id;
system.m_name = systems[sys_id].m_name;
systems[sys_id] = system; systems[sys_id] = system;
} }
else else
{ {
system.m_name = Mallocator.makeArray(cast(char[]) Sys.stringof); system.m_name = Mallocator.makeArray(cast(char[]) SystemName);
systems_map.add(system.m_name, cast(ushort) systems.length); systems_map.add(system.m_name, cast(ushort) systems.length);
@ -1247,6 +1268,10 @@ export struct EntityManager
{ {
ComponentInfo info; ComponentInfo info;
// enum ComponentName = fullyQualifiedName!Comp;
enum ComponentName = fullName!Comp;
// enum ComponentName = Comp.stringof;
static if (!(hasMember!(Comp, "component_id")) || !is(typeof(Comp.component_id) == ushort)) static if (!(hasMember!(Comp, "component_id")) || !is(typeof(Comp.component_id) == ushort))
{ {
static assert(0, "Add \"mixin ECS.Component;\" in top of component structure;"); static assert(0, "Add \"mixin ECS.Component;\" in top of component structure;");
@ -1283,19 +1308,19 @@ export struct EntityManager
info.init_data = Mallocator.makeArray!ubyte(Comp.sizeof); info.init_data = Mallocator.makeArray!ubyte(Comp.sizeof);
*cast(Comp*) info.init_data.ptr = Comp.init; // = Comp(); *cast(Comp*) info.init_data.ptr = Comp.init; // = Comp();
ushort comp_id = components_map.get(cast(char[]) Comp.stringof, ushort.max); ushort comp_id = components_map.get(cast(char[]) ComponentName, ushort.max);
if (comp_id < components.length) if (comp_id < components.length)
{ {
Comp.component_id = comp_id; Comp.component_id = comp_id;
if (components[comp_id].init_data)
Mallocator.dispose(components[comp_id].init_data);
components[comp_id] = info; components[comp_id] = info;
} }
else else
{ {
components.add(info); components.add(info);
Comp.component_id = cast(ushort)(components.length - 1); Comp.component_id = cast(ushort)(components.length - 1);
char[] name = Mallocator.makeArray(cast(char[]) Comp.stringof); char[] name = Mallocator.makeArray(cast(char[]) ComponentName);
/*char[] name = Mallocator.makeArray!char(Comp.stringof.length);
name[0..$] = Comp.stringof;*/
components_map.add(name, cast(ushort)(components.length - 1)); components_map.add(name, cast(ushort)(components.length - 1));
} }
} }
@ -1323,7 +1348,8 @@ export struct EntityManager
info.size = Ev.sizeof; info.size = Ev.sizeof;
info.alignment = Ev.alignof; info.alignment = Ev.alignof;
ushort event_id = events_map.get(Ev.stringof, ushort.max); //ushort event_id = events_map.get(Ev.stringof, ushort.max);
ushort event_id = events_map.get(fullName!Ev, ushort.max);
if (event_id < events.length) if (event_id < events.length)
{ {
Ev.event_id = event_id; Ev.event_id = event_id;
@ -1332,26 +1358,31 @@ export struct EntityManager
{ {
events.add(info); events.add(info);
Ev.event_id = cast(ushort)(events.length - 1); Ev.event_id = cast(ushort)(events.length - 1);
events_map.add(Ev.stringof, cast(ushort)(events.length - 1)); // events_map.add(Ev.stringof, cast(ushort)(events.length - 1));
events_map.add(fullName!Ev, cast(ushort)(events.length - 1));
} }
} }
export void callEntitiesFunction(Sys, T)(T func) export void callEntitiesFunction(Sys, T)(T func)
{ {
//TODO: check if onUpdate function is good
Sys* s; Sys* s;
static assert(isDelegate!func, "Function must be delegate."); static assert(isDelegate!func, "Function must be delegate.");
static assert(__traits(hasMember, Sys, "EntitiesData"), static assert(__traits(hasMember, Sys, "EntitiesData"),
"Can't call function with system which hasn't EntitesData structure."); "Can't call function with system which hasn't EntitesData structure.");
///TODO: make possibly to call function to group without system with onUpdate function
static assert(__traits(hasMember, Sys, "onUpdate"), static assert(__traits(hasMember, Sys, "onUpdate"),
"Can't call function with system which hasn't onUpdate function callback."); "Can't call function with system which hasn't onUpdate function callback.");
static assert(is(SetFunctionAttributes!(T, functionLinkage!(s.onUpdate), // static assert(is(SetFunctionAttributes!(T, functionLinkage!(s.onUpdate),
functionAttributes!(s.onUpdate)) == typeof(&s.onUpdate)), // functionAttributes!(s.onUpdate)) == typeof(&s.onUpdate)),
"Function must match system update function."); // "Function must match system update function."); FIXME: It's lead to crash on android build
static assert(__traits(hasMember, Sys, "system_id"), "Sys must be system type."); static assert(__traits(hasMember, Sys, "system_id"), "Sys must be system type.");
System* system = getSystem(Sys.system_id); System* system = getSystem(Sys.system_id);
assert(system != null, assert(system != null,
"System must be registered in EntityManager before any funcion can be called."); "System must be registered in EntityManager before any funcion can be called.");
if (!system.m_any_system_caller)
return;
foreach (info; system.m_any_system_caller.infos) foreach (info; system.m_any_system_caller.infos)
{ {
@ -1479,21 +1510,28 @@ export struct EntityManager
if (first_block is null || blocks_count == 0) if (first_block is null || blocks_count == 0)
continue; continue;
//if this info will fill job
if ((blocks_count - 1) * info.max_entities + entities_count if ((blocks_count - 1) * info.max_entities + entities_count
+ info.last_block.entities_count - first_elem >= entities_per_job) + info.last_block.entities_count - first_elem >= entities_per_job)
{ {
int reamaining_entities = (entities_per_job - entities_count - ( int reamaining_entities = (entities_per_job - entities_count - (
first_block.entities_count - first_elem)); first_block.entities_count - first_elem));
if (reamaining_entities >= 0)
//if first block don't fill job
if (reamaining_entities > 0)
{ {
//take as many full blocks as possible
int full_blocks_count = reamaining_entities / info.max_entities; int full_blocks_count = reamaining_entities / info.max_entities;
EntitiesBlock* block = first_block; EntitiesBlock* block = first_block;
foreach (i; 0 .. full_blocks_count + 1) foreach (i; 0 .. full_blocks_count + 1)
block = block.next_block; block = block.next_block;
//if full block + actual contained entities + remaining entities form first block > entities count per job
if (full_blocks_count * info.max_entities + entities_count + ( if (full_blocks_count * info.max_entities + entities_count + (
first_block.entities_count - first_elem) >= entities_per_job) first_block.entities_count - first_elem) >= entities_per_job)
{ {
assert(entities_per_job == full_blocks_count * info.max_entities + entities_count + (
first_block.entities_count - first_elem));
CallData data = CallData(caller.system_id, sys, CallData data = CallData(caller.system_id, sys,
info, sys.m_update_delegate, first_block, info, sys.m_update_delegate, first_block,
cast(ushort)(full_blocks_count + 1), cast(ushort)(full_blocks_count + 1),
@ -1508,6 +1546,8 @@ export struct EntityManager
entities_count += full_blocks_count * info.max_entities + ( entities_count += full_blocks_count * info.max_entities + (
first_block.entities_count - first_elem); // - first_elem; first_block.entities_count - first_elem); // - first_elem;
uint last_elem = entities_per_job - entities_count; // + first_elem - 1; uint last_elem = entities_per_job - entities_count; // + first_elem - 1;
assert(last_elem > 0);
assert(last_elem <= block.entities_count);
CallData data = CallData(caller.system_id, sys, CallData data = CallData(caller.system_id, sys,
info, sys.m_update_delegate, first_block, info, sys.m_update_delegate, first_block,
cast(ushort)(full_blocks_count + 2), cast(ushort)(full_blocks_count + 2),
@ -1515,19 +1555,31 @@ export struct EntityManager
tmp_datas.add(data); tmp_datas.add(data);
first_elem = last_elem; first_elem = last_elem;
blocks_count -= full_blocks_count + 1; blocks_count -= full_blocks_count + 1;
assert(first_elem <= block.entities_count);
first_block = block; first_block = block;
if (last_elem == block.entities_count)
{
assert(block.next_block == null);
first_block = null;
}
} }
} }
else else
{ {
uint last_elem = entities_per_job - entities_count; uint last_elem = entities_per_job - entities_count;
assert(last_elem > 0);
CallData data = CallData(caller.system_id, sys, CallData data = CallData(caller.system_id, sys,
info, sys.m_update_delegate, first_block, 1, info, sys.m_update_delegate, first_block, 1,
cast(ushort) first_elem, cast(ushort)(first_elem + last_elem)); cast(ushort) first_elem, cast(ushort)(first_elem + last_elem));
tmp_datas.add(data); tmp_datas.add(data);
first_elem += last_elem; first_elem += last_elem;
assert(first_elem <= first_block.entities_count); assert(first_elem <= first_block.entities_count);
//if job takes every entity, take next block
if (first_elem == first_block.entities_count)
{
first_elem = 0;
first_block = first_block.next_block;
blocks_count--;
}
} }
nextJob(); nextJob();
entities_count = 0; entities_count = 0;
@ -1535,6 +1587,7 @@ export struct EntityManager
} }
else else
{ {
//take whole info blocks
CallData data = CallData(caller.system_id, sys, info, sys.m_update_delegate, CallData data = CallData(caller.system_id, sys, info, sys.m_update_delegate,
first_block, cast(ushort) blocks_count, cast(ushort) first_elem); first_block, cast(ushort) blocks_count, cast(ushort) first_elem);
tmp_datas.add(data); tmp_datas.add(data);
@ -1828,6 +1881,8 @@ export struct EntityManager
foreach (i, id; ids) foreach (i, id; ids)
{ {
if (current_delta == 0)
current_delta = ushort.max;
alignNum(current_delta, components[id].alignment); alignNum(current_delta, components[id].alignment);
info.deltas[id] = cast(ushort) current_delta; info.deltas[id] = cast(ushort) current_delta;
current_delta += entites_in_block * components[id].size; current_delta += entites_in_block * components[id].size;
@ -2008,6 +2063,9 @@ export struct EntityManager
is_: is_:
} }
///call Custom Entity Filter test if function exists
if(system.m_filter_entity && !(cast(bool function(void* system_pointer, EntityInfo* info) @nogc nothrow)system.m_filter_entity)(system, &entity))return;
entity.systems[system_id] = true; entity.systems[system_id] = true;
} }
@ -2050,30 +2108,8 @@ export struct EntityManager
{ {
System* system = &systems[system_id]; System* system = &systems[system_id];
if (system.m_excluded_components) connectListenerToEntityInfo(info, system_id);
{ if(!info.systems[system_id])return;
foreach (id; system.m_excluded_components)
{
foreach (id2; info.components)
{
if (id == id2)
return;
}
}
}
foreach (id; system.m_components)
{
foreach (i2, id2; info.components)
{
if (id2 == id)
goto is_;
}
return;
is_:
}
info.systems[system_id] = true;
uint index = 0; uint index = 0;
for (; index < passes[system.m_pass].system_callers.length; index++) for (; index < passes[system.m_pass].system_callers.length; index++)
@ -2486,17 +2522,17 @@ export struct EntityManager
{ {
ushort size = components[comp].size; ushort size = components[comp].size;
if (size != 0) if (size != 0)
memcpy(cast(void*) new_block + info.deltas[comp] + size * new_id, memcpy(cast(void*) new_block + info.deltas[comp] + new_id * size,
cast(void*) block + info.deltas[comp] + size * index, size); cast(void*) block + info.deltas[comp] + size * index, size);
if (components[comp].create_callback) if (components[comp].create_callback)
{ {
components[comp].create_callback( components[comp].create_callback(
cast(void*) block + info.deltas[comp] + new_id * size); cast(void*) new_block + info.deltas[comp] + new_id * size);
} }
} }
if (new_index == 1 && info.update_block == block) if (new_index == 1 && info.update_block == new_block)
threads[threadID].infosToUpdate.add(info); threads[threadID].infosToUpdate.add(info);
Entity* new_entity = cast(Entity*) start; Entity* new_entity = cast(Entity*) start;
@ -2515,43 +2551,6 @@ export struct EntityManager
*/ */
export Entity* addEntity(EntityTemplate* tmpl) export Entity* addEntity(EntityTemplate* tmpl)
{ {
/*EntityInfo* info = tmpl.info;
ushort index = 0;
EntitiesBlock* block;
do
{
block = findBlockWithFreeSpaceMT(info);
index = block.added_count.atomicOp!"+="(1);
}
while (block.entities_count + index > info.max_entities);
uint id = (block.entities_count + index - 1); //block.added_count);
void* data_begin = block.dataBegin();
void* start = data_begin + EntityID.sizeof * id;
foreach (comp; info.components)
{
memcpy(cast(void*) block + info.deltas[comp] + components[comp].size * id,
tmpl.entity_data.ptr + info.tmpl_deltas[comp], components[comp].size);
if (components[comp].create_callback)
{
components[comp].create_callback(
cast(void*) block + info.deltas[comp] + id * components[comp].size);
}
}
if (index == 1)
threads[threadID].infosToUpdate.add(block);
Entity* entity = cast(Entity*) start;
entity.id = id_manager.getNewID();
id_manager.update(*entity); //entity.updateID();
return entity;*/
return addEntity(tmpl, null); return addEntity(tmpl, null);
} }
@ -3100,12 +3099,12 @@ export struct EntityManager
swapData(); swapData();
has_work = false; has_work = false;
// has_work |= updateBlocks(); has_work |= updateBlocks();
// has_work |= changeEntities(); // has_work |= changeEntities();
// has_work |= removeEntities(); // has_work |= removeEntities();
has_work |= updateEvents(); has_work |= updateEvents();
//id_manager.optimize(); id_manager.optimize();
has_work |= updateBlocks(); has_work |= updateBlocks();
has_work |= changeEntities(); has_work |= changeEntities();
has_work |= removeEntities(); has_work |= removeEntities();
@ -3493,6 +3492,12 @@ export struct EntityManager
return new_info; return new_info;
} }
export bool hasComponent(ushort component_id)
{
if(component_id >= deltas.length || !deltas[component_id])return false;
return true;
}
export ~this() @nogc nothrow export ~this() @nogc nothrow
{ {
if (components) if (components)
@ -3501,6 +3506,10 @@ export struct EntityManager
Mallocator.dispose(deltas); Mallocator.dispose(deltas);
if (tmpl_deltas) if (tmpl_deltas)
Mallocator.dispose(tmpl_deltas); Mallocator.dispose(tmpl_deltas);
if (comp_add_info)
Mallocator.dispose(comp_add_info);
if (comp_rem_info)
Mallocator.dispose(comp_rem_info);
if (systems) if (systems)
Mallocator.dispose(systems); Mallocator.dispose(systems);
if (add_listeners) if (add_listeners)

View file

@ -13,6 +13,12 @@ struct SimpleVector
@disable this(this); @disable this(this);
~this() nothrow @nogc
{
if(data)
Mallocator.dispose(data);
}
///Add element to vector ///Add element to vector
void add(ubyte el) nothrow @nogc void add(ubyte el) nothrow @nogc
{ {

View file

@ -112,7 +112,7 @@ else version (D_BetterC)
{ {
private const uint max_alloca = 10000; private const uint max_alloca = 10000;
private __gshared byte[max_alloca] alloca_array; private __gshared byte[max_alloca] alloca_array;
private uint alloca_pos = 0; private __gshared uint alloca_pos = 0;
export extern (C) void* __alloca(size_t length) @nogc nothrow export extern (C) void* __alloca(size_t length) @nogc nothrow
{ {
if (alloca_pos + length > max_alloca) if (alloca_pos + length > max_alloca)
@ -152,13 +152,86 @@ else
static struct Mallocator static struct Mallocator
{ {
static T[] resizeArray(T)(T[] array, size_t length) nothrow @nogc
{
T[] ret;
if (length > array.length)
{
ret = (cast(T*) realloc(array.ptr, T.sizeof * length))[0 .. length];
static if (__traits(isPOD, T))
{
__gshared immutable T init = T.init;
foreach (i; array.length .. ret.length)
{
memcpy(&ret[i], &init, T.sizeof);
}
}
else
{
static import std.conv;
foreach (i; array.length .. ret.length)
{
std.conv.emplace(&ret[i]);
}
}
}
else
{
static if (__traits(hasMember, T, "__xdtor"))
{
foreach (i; length .. array.length)
{
array[i].__xdtor();
}
}
else static if (__traits(hasMember, T, "__dtor"))
{
foreach (i; length .. array.length)
{
array[i].__dtor();
}
}
ret = (cast(T*) realloc(array.ptr, T.sizeof * length))[0 .. length];
}
return ret;
}
static T[] makeArray(T)(size_t length) nothrow @nogc static T[] makeArray(T)(size_t length) nothrow @nogc
{ {
T[] ret = (cast(T*) malloc(T.sizeof * length))[0 .. length]; T[] ret = (cast(T*) malloc(T.sizeof * length))[0 .. length];
static if (__traits(isPOD, T)) static if (__traits(isPOD, T))
{ {
static immutable T init = T.init; __gshared immutable T init = T.init;
foreach (i; 0 .. ret.length)
{
memcpy(&ret[i], &init, T.sizeof);
}
}
else
{
static import std.conv;
foreach (i; 0 .. ret.length)
{
std.conv.emplace(&ret[i]);
}
}
return ret;
}
static T[] alignMakeArray(T)(size_t length, size_t alignment) nothrow @nogc
{
T[] ret = (cast(T*) alignAlloc(T.sizeof * length, alignment))[0 .. length];
static if (__traits(isPOD, T))
{
__gshared immutable T init = T.init;
foreach (i; 0 .. ret.length) foreach (i; 0 .. ret.length)
{ {
@ -206,7 +279,7 @@ static struct Mallocator
static if (__traits(isPOD, T)) static if (__traits(isPOD, T))
{ {
static immutable T init = T.init; __gshared immutable T init = T.init;
memcpy(ret, &init, T.sizeof); memcpy(ret, &init, T.sizeof);
} }
else static if (is(T == struct)) else static if (is(T == struct))
@ -228,13 +301,34 @@ static struct Mallocator
return ret; return ret;
} }
static void dispose(T)(T object) nothrow @nogc static void dispose(T)(T object)
{ {
static if (__traits(hasMember, T, "__xdtor")) static if (isArray!T)
object.__xdtor(); {
else static if (__traits(hasMember, T, "__dtor")) alias TT = PointerTarget!(typeof(object.ptr));
object.__dtor(); static if (!isPointer!TT)
free(cast(void*) object); {
static if (__traits(hasMember, TT, "__xdtor"))
{
foreach (ref TT t; object)
t.__xdtor();
}
else static if (__traits(hasMember, TT, "__dtor"))
{
foreach (TT t; object)
t.__dtor();
}
}
free(cast(void*) object.ptr);
}
else
{
static if (__traits(hasMember, T, "__xdtor"))
object.__xdtor();
else static if (__traits(hasMember, T, "__dtor"))
object.__dtor();
free(cast(void*) object);
}
} }
static void alignDispose(T)(T object) static void alignDispose(T)(T object)

View file

@ -91,6 +91,38 @@ struct System
package: package:
void destroy()
{
import bubel.ecs.std : Mallocator;
disable();
if (m_destroy)
(cast(void function(void*)) m_destroy)(m_system_pointer);
if (m_name)
Mallocator.dispose(m_name);
if (m_components)
Mallocator.dispose(m_components);
if (m_excluded_components)
Mallocator.dispose(m_excluded_components);
if (m_optional_components)
Mallocator.dispose(m_optional_components);
if (jobs)
Mallocator.dispose(jobs);
if (m_read_only_components)
Mallocator.dispose(m_read_only_components);
if (m_writable_components)
Mallocator.dispose(m_writable_components);
if (m_readonly_dependencies)
Mallocator.dispose(m_readonly_dependencies);
if (m_writable_dependencies)
Mallocator.dispose(m_writable_dependencies);
if (m_event_callers)
Mallocator.dispose(m_event_callers);
if (m_system_pointer)
Mallocator.dispose(m_system_pointer);
}
struct EventCaller struct EventCaller
{ {
ushort id; ushort id;
@ -162,6 +194,8 @@ package:
void* m_remove_entity; void* m_remove_entity;
void* m_change_entity; void* m_change_entity;
void* m_filter_entity;
//void function(ref EntityManager.CallData data) m_initialize; //void function(ref EntityManager.CallData data) m_initialize;
//void function(ref EntityManager.CallData data) m_deinitilize; //void function(ref EntityManager.CallData data) m_deinitilize;
void* m_initialize; void* m_initialize;

View file

@ -37,3 +37,35 @@ static long getIndexOfTypeInEntitiesData(EntitiesData, Type)()
} }
return index; return index;
} }
static string attachParentName(alias T, string str)()
{
alias parent = __traits(parent, T);
enum parent_str = parent.stringof;
static if(parent_str[0..7] == "module ")
{
static if(__traits(compiles, __traits(parent, parent)))
{
return attachParentName!(parent, parent_str[7 .. $] ~ '.' ~ str);
}
else return parent_str[8 .. $] ~ '.' ~ str;
}
else static if(parent_str[0..8] == "package ")
{
static if(__traits(compiles, __traits(parent, parent)))
{
return attachParentName!(parent, parent_str[8 .. $] ~ '.' ~ str);
}
else return parent_str[8 .. $] ~ '.' ~ str;
}
else static if(__traits(compiles, __traits(parent, parent)))
{
return attachParentName!(parent, parent_str ~ '.' ~ str);
}
else return parent_str ~ '.' ~ str;
}
static string fullName(T)()
{
return attachParentName!(T, T.stringof);
}

View file

@ -139,6 +139,7 @@ void afterEveryTest()
unittest unittest
{ {
EntityTemplate* tmpl_ = gEM.allocateTemplate([CInt.component_id, CFloat.component_id, CFlag.component_id].staticArray); EntityTemplate* tmpl_ = gEM.allocateTemplate([CInt.component_id, CFloat.component_id, CFlag.component_id].staticArray);
scope(exit)gEM.freeTemplate(tmpl_);
Entity* entity = gEM.addEntity(tmpl_); Entity* entity = gEM.addEntity(tmpl_);
EntityMeta meta = entity.getMeta(); EntityMeta meta = entity.getMeta();
assert(meta.hasComponent(CInt.component_id)); assert(meta.hasComponent(CInt.component_id));
@ -157,6 +158,7 @@ unittest
unittest unittest
{ {
EntityTemplate* tmpl_ = gEM.allocateTemplate([CInt.component_id, CFloat.component_id, CFlag.component_id].staticArray); EntityTemplate* tmpl_ = gEM.allocateTemplate([CInt.component_id, CFloat.component_id, CFlag.component_id].staticArray);
scope(exit)gEM.freeTemplate(tmpl_);
assert(tmpl_.info.components.length == 3); assert(tmpl_.info.components.length == 3);
assert(tmpl_.info.size == (CInt.sizeof + CFloat.sizeof + EntityID.sizeof)); assert(tmpl_.info.size == (CInt.sizeof + CFloat.sizeof + EntityID.sizeof));
assert(tmpl_.getComponent!CInt); assert(tmpl_.getComponent!CInt);
@ -345,6 +347,7 @@ unittest
assert(*tmpl_7.getComponent!CLong == 10); assert(*tmpl_7.getComponent!CLong == 10);
gEM.freeTemplate(tmpl_d); gEM.freeTemplate(tmpl_d);
gEM.freeTemplate(tmpl_cp);
gEM.freeTemplate(tmpl_); gEM.freeTemplate(tmpl_);
gEM.freeTemplate(tmpl_2); gEM.freeTemplate(tmpl_2);
gEM.freeTemplate(tmpl_3); gEM.freeTemplate(tmpl_3);
@ -368,6 +371,8 @@ unittest
assert(*tmpl_.getComponent!CInt == 1); assert(*tmpl_.getComponent!CInt == 1);
assert(*tmpl_.getComponent!CFloat == 2.0); assert(*tmpl_.getComponent!CFloat == 2.0);
assert(tmpl_.info == tmpl_2.info); assert(tmpl_.info == tmpl_2.info);
gEM.freeTemplate(tmpl_);
gEM.freeTemplate(tmpl_2);
} }
@("MultiRegister") @("MultiRegister")
@ -401,7 +406,7 @@ unittest
System* ecs_system = gEM.getSystem(EmptySystem.system_id); System* ecs_system = gEM.getSystem(EmptySystem.system_id);
assert(ecs_system !is null); assert(ecs_system !is null);
assert(ecs_system.id == EmptySystem.system_id); assert(ecs_system.id == EmptySystem.system_id);
assert(ecs_system.name == "EmptySystem"); assert(ecs_system.name == "tests.basic.EmptySystem");
gEM.begin(); gEM.begin();
@ -605,7 +610,7 @@ unittest
assert(ecs_system !is null); assert(ecs_system !is null);
assert(ecs_system.id == LongAddSystem.system_id); assert(ecs_system.id == LongAddSystem.system_id);
assert(ecs_system.priority == -1); assert(ecs_system.priority == -1);
assert(ecs_system.name == "LongAddSystem"); assert(ecs_system.name == "tests.basic.LongAddSystem");
ushort[1] ids = [CLong.component_id]; ushort[1] ids = [CLong.component_id];
EntityTemplate* tmpl = gEM.allocateTemplate(ids); EntityTemplate* tmpl = gEM.allocateTemplate(ids);
@ -897,7 +902,7 @@ unittest
{ {
struct TestSystem struct TestSystem
{ {
mixin ECS.System; mixin ECS.System!64;
struct EntitiesData struct EntitiesData
{ {
@ -1003,15 +1008,51 @@ unittest
assert(empty_system.update == 3); assert(empty_system.update == 3);
system.entities = 0; system.entities = 0;
foreach(i;0..10000)gEM.addEntity(tmpl); // foreach(i;0..10000)gEM.addEntity(tmpl);
gEM.begin(); // gEM.begin();
gEM.updateMT("custom"); // gEM.updateMT("custom");
gEM.end(); // gEM.end();
assert(system.entities == 12001); // assert(system.entities == 12001);
void clearEntities(TestSystem.EntitiesData data)
{
foreach(i;0..data.length)
{
gEM.removeEntity(data.entity[i].id);
}
}
gEM.callEntitiesFunction!TestSystem(&clearEntities);
gEM.commit();
foreach(i;0..2000)
{
gEM.addEntity(tmpl);
gEM.begin();
gEM.updateMT("custom");
gEM.end();
assert(system.entities == i+1);
system.entities = 0;
}
foreach(i;0..90000)gEM.addEntity(tmpl);
foreach(i;0..2000)
{
gEM.addEntity(tmpl);
gEM.begin();
gEM.updateMT("custom");
gEM.end();
assert(system.entities == i+92001);
system.entities = 0;
}
} }
unittest unittest
@ -1580,3 +1621,106 @@ unittest
assert(pass.system_callers[4].dependencies[0].system_id == TestSystem2.system_id); assert(pass.system_callers[4].dependencies[0].system_id == TestSystem2.system_id);
assert(pass.system_callers[4].dependencies[1].system_id == TestSystem4.system_id); assert(pass.system_callers[4].dependencies[1].system_id == TestSystem4.system_id);
} }
@("CustomFilter")
unittest
{
struct TestSystem
{
mixin ECS.System;
struct EntitiesData
{
uint length;
@optional CInt[] int_;
@optional CLong[] long_;
@optional CFloat[] float_;
@optional CDouble[] double_;
}
bool filterEntity(EntityManager.EntityInfo* info)
{
if(!info.hasComponent(CInt.component_id))return false;
int one_from = 0;
if(info.hasComponent(CLong.component_id))one_from++;
if(info.hasComponent(CFloat.component_id))one_from++;
if(info.hasComponent(CDouble.component_id))one_from++;
if(one_from == 1)return true;
return false;
}
void onUpdate(EntitiesData entities)
{
updates++;
}
uint updates = 0;
}
struct TestSystem2
{
mixin ECS.System;
struct EntitiesData
{
uint length;
@optional CInt[] int_;
@optional CLong[] long_;
@optional CFloat[] float_;
@optional CDouble[] double_;
}
bool filterEntity(EntityManager.EntityInfo* info)
{
if(info.hasComponent(CInt.component_id) && info.hasComponent(CFloat.component_id) && !info.hasComponent(CLong.component_id) && !info.hasComponent(CDouble.component_id))return true;
if(info.hasComponent(CLong.component_id) && info.hasComponent(CDouble.component_id) && !info.hasComponent(CInt.component_id) && !info.hasComponent(CFloat.component_id))return true;
return false;
}
void onUpdate(EntitiesData entities)
{
updates++;
}
uint updates = 0;
}
gEM.beginRegister();
gEM.registerSystem!TestSystem(0);
gEM.registerSystem!TestSystem2(1);
gEM.endRegister();
EntityTemplate* tmpl_ = gEM.allocateTemplate([CInt.component_id, CLong.component_id, CFloat.component_id, CDouble.component_id].staticArray);
scope(exit)gEM.freeTemplate(tmpl_);
EntityTemplate* tmpl_2 = gEM.allocateTemplate([CInt.component_id, CFloat.component_id].staticArray);
scope(exit)gEM.freeTemplate(tmpl_2);
EntityTemplate* tmpl_3 = gEM.allocateTemplate([CLong.component_id, CDouble.component_id].staticArray);
scope(exit)gEM.freeTemplate(tmpl_3);
EntityTemplate* tmpl_4 = gEM.allocateTemplate([CInt.component_id, CLong.component_id, CDouble.component_id].staticArray);
scope(exit)gEM.freeTemplate(tmpl_4);
EntityTemplate* tmpl_5 = gEM.allocateTemplate([CInt.component_id, CDouble.component_id].staticArray);
scope(exit)gEM.freeTemplate(tmpl_5);
EntityTemplate* tmpl_6 = gEM.allocateTemplate([CDouble.component_id].staticArray);
scope(exit)gEM.freeTemplate(tmpl_6);
gEM.addEntity(tmpl_);
gEM.addEntity(tmpl_2);
gEM.addEntity(tmpl_3);
gEM.addEntity(tmpl_4);
gEM.addEntity(tmpl_5);
gEM.addEntity(tmpl_6);
TestSystem* test_system = gEM.getSystem!TestSystem;
TestSystem2* test_system2 = gEM.getSystem!TestSystem2;
gEM.begin();
gEM.update();
gEM.end();
assert(test_system.updates == 2);
assert(test_system2.updates == 2);
}

View file

@ -236,7 +236,7 @@ struct TestRunner(Args...)
} }
else else
{ {
import core.exception : AssertError; import core.exception : AssertError, RangeError;
try try
{ {
unittest_(); unittest_();
@ -249,6 +249,13 @@ struct TestRunner(Args...)
test.file_line = cast(int)error.line; test.file_line = cast(int)error.line;
test.msg = copyString(error.msg); test.msg = copyString(error.msg);
} }
catch(RangeError error)
{
test.passed = false;
test.file = copyString(error.file);
test.file_line = cast(int)error.line;
test.msg = copyString(error.msg);
}
} }
if (test.passed) if (test.passed)

View file

@ -93,6 +93,13 @@ struct TestEvent2
float a; float a;
} }
static struct CPosition
{
mixin ECS.Component;
float x;
float y;
}
static struct TestComp static struct TestComp
{ {
mixin ECS.Component; //__gshared ushort component_id; mixin ECS.Component; //__gshared ushort component_id;
@ -186,6 +193,52 @@ static struct TestComp5
} }
} }
struct EverySystem
{
mixin ECS.System;
struct EntitiesData
{
uint length;
Entity[] entity;
CPosition[] pos;
}
void onUpdate(EntitiesData data)
{
foreach(i;0..data.length)
{
data.pos[i].x++;
data.pos[i].y++;
}
}
void iterate(EntitiesData data)
{
foreach(i;0..data.length)
{
data.pos[i].x++;
data.pos[i].y++;
}
}
void free(EntitiesData data)
{
foreach(i;0..data.length)
{
gEM.removeEntity(data.entity[i].id);
}
}
void addOne(EntitiesData data)
{
foreach(i;0..data.length)
{
gEM.addComponents(data.entity[i].id, TestComp2());
}
}
}
struct ChangeTestSystem struct ChangeTestSystem
{ {
mixin ECS.System!16; //__gshared ushort system_id; mixin ECS.System!16; //__gshared ushort system_id;
@ -648,6 +701,7 @@ else:
gEM.registerComponent!TestComp; gEM.registerComponent!TestComp;
gEM.registerComponent!TestComp3; gEM.registerComponent!TestComp3;
gEM.registerComponent!TestComp5; gEM.registerComponent!TestComp5;
gEM.registerComponent!CPosition;
gEM.registerEvent!TestEvent; gEM.registerEvent!TestEvent;
gEM.registerEvent!TestEvent2; gEM.registerEvent!TestEvent2;
@ -669,6 +723,7 @@ else:
gEM.registerSystem!EmptySystem(2); gEM.registerSystem!EmptySystem(2);
gEM.registerSystem!EmptyEventSystem(2); gEM.registerSystem!EmptyEventSystem(2);
gEM.registerSystem!EventSystem(2); gEM.registerSystem!EventSystem(2);
gEM.registerSystem!EverySystem(0);
//gEM.registerSystem!TestSystemWithHighPriority(100); //gEM.registerSystem!TestSystemWithHighPriority(100);
//gEM.registerSystem!TestSystem2(0); //gEM.registerSystem!TestSystem2(0);
gEM.endRegister(); gEM.endRegister();
@ -693,6 +748,62 @@ else:
//dur = (MonoTime.currTime - time).total!"usecs"; //dur = (MonoTime.currTime - time).total!"usecs";
//writeln("Template allocating: ", dur, " usecs"); //writeln("Template allocating: ", dur, " usecs");
printf("Template allocating: %f usecs\n", cast(float)(Time.getUSecTime() - time)); printf("Template allocating: %f usecs\n", cast(float)(Time.getUSecTime() - time));
time = Time.getUSecTime();
ushort[1] empty_ids = [CPosition.component_id];
EntityTemplate* tmpl_empty = gEM.allocateTemplate(empty_ids);
gEM.commit();
time = Time.getUSecTime();
foreach(i;0..4_000_000)gEM.addEntity(tmpl_empty);
gEM.commit();
foreach(i;0..4_000_000)gEM.addEntity(tmpl_empty);
gEM.commit();
foreach(i;0..2_000_000)gEM.addEntity(tmpl_empty);
gEM.commit();
printf("Adding 1M entities: %f usecs\n", cast(float)(Time.getUSecTime() - time));
gEM.commit();
time = Time.getUSecTime();
gEM.callEntitiesFunction!EverySystem(&gEM.getSystem!EverySystem().iterate);
printf("Iterate 1M entities: %f usecs\n", cast(float)(Time.getUSecTime() - time));
gEM.begin();
time = Time.getUSecTime();
gEM.update();
printf("Iterate 1M entities (update): %f usecs\n", cast(float)(Time.getUSecTime() - time));
gEM.end();
time = Time.getUSecTime();
gEM.callEntitiesFunction!EverySystem(&gEM.getSystem!EverySystem().free);
gEM.commit();
printf("Deleting 1M entities: %f usecs\n", cast(float)(Time.getUSecTime() - time));
time = Time.getUSecTime();
foreach(i;0..4_000_000)gEM.addEntity(tmpl_empty);
gEM.commit();
foreach(i;0..4_000_000)gEM.addEntity(tmpl_empty);
gEM.commit();
foreach(i;0..2_000_000)gEM.addEntity(tmpl_empty);
gEM.commit();
printf("Adding 1M entities (prealloc): %f usecs\n", cast(float)(Time.getUSecTime() - time));
gEM.commit();
time = Time.getUSecTime();
gEM.callEntitiesFunction!EverySystem(&gEM.getSystem!EverySystem().addOne);
gEM.commit();
printf("Adding 1M component: %f usecs\n", cast(float)(Time.getUSecTime() - time));
gEM.commit();
gEM.callEntitiesFunction!EverySystem(&gEM.getSystem!EverySystem().free);
gEM.commit();
time = Time.getUSecTime(); time = Time.getUSecTime();
EntityID entity; EntityID entity;
@ -903,6 +1014,7 @@ else:
writeEntityComponents(gEM.getEntity(entity)); writeEntityComponents(gEM.getEntity(entity));
//import std.stdio; //import std.stdio;
////writeln((cast(uint*)tmpl.info.first_block)[0..48]); ////writeln((cast(uint*)tmpl.info.first_block)[0..48]);
gEM.freeTemplate(tmpl_empty);
gEM.freeTemplate(tmpl); gEM.freeTemplate(tmpl);
gEM.freeTemplate(tmpl2); gEM.freeTemplate(tmpl2);
gEM.freeTemplate(copy_tempalte); gEM.freeTemplate(copy_tempalte);