diff --git a/compile_wasm.py b/compile_wasm.py index da42783..e808354 100644 --- a/compile_wasm.py +++ b/compile_wasm.py @@ -13,7 +13,7 @@ def compile(sources, output): if file_extension == '.d' and filename != 'package': files.append(os.path.join(r, file)) - ldc_cmd = 'ldc2 ' + shared_flags + ldc_flags + '-oq -mtriple=wasm32-unknown-unknown-wasm -betterC -L-allow-undefined --output-bc --od=.bc --singleobj --checkaction=C --of=' + output + ' ' + ldc_cmd = 'ldc2 ' + shared_flags + ldc_flags + '-oq -mtriple=wasm32-unknown-unknown-wasm -betterC --output-bc --od=.bc --singleobj --checkaction=C --of=' + output + ' ' for path in sources: ldc_cmd += '-I' + path + ' ' @@ -56,6 +56,9 @@ for arg in sys.argv[1:]: shared_flags += '-Oz ' elif(arg == '-g'): shared_flags += '-g ' + elif(arg == '-g4'): + ldc_flags += '-g ' + emc_flags += '-g4 ' elif(arg == '--build-tests'): build_tests = 1 elif(arg == '--llvm-lto'): @@ -77,8 +80,9 @@ if build_tests == 0: compile(['tests'], 'tests.bc') -emcc_cmd = 'emcc -v ' + shared_flags + emc_flags + '-s ALLOW_MEMORY_GROWTH=1 -s MALLOC=dlmalloc -s WASM=1 -o index.html ' - +emcc_cmd = 'emcc -v ' + shared_flags + emc_flags + '-s ALLOW_MEMORY_GROWTH=1 -s WASM_MEM_MAX=1024MB -s MALLOC=dlmalloc -s WASM=1 -o index.html ' +#-s ALLOW_MEMORY_GROWTH=1 + emcc_cmd += 'ecs.bc tests.bc' print emcc_cmd diff --git a/demos/.gitignore b/demos/.gitignore index e6f937c..7ccfc2f 100644 --- a/demos/.gitignore +++ b/demos/.gitignore @@ -3,8 +3,9 @@ !**/dub.json !libs/ !*.dll +!libs/** !utils/**/*.d -!simple/**/*.d +!source/**/*.d !launcher/**/*.d !assets/** !external/**/*.d diff --git a/demos/compile_wasm.py b/demos/compile_wasm.py index b34b5c6..06845cf 100644 --- a/demos/compile_wasm.py +++ b/demos/compile_wasm.py @@ -13,7 +13,7 @@ def compile(sources, output): if file_extension == '.d' and filename != 'package': files.append(os.path.join(r, file)) - ldc_cmd = 'ldc2 ' + shared_flags + ldc_flags + '-oq -mtriple=wasm32-unknown-unknown-wasm -betterC -L-allow-undefined --output-bc --od=.bc --singleobj --checkaction=C --of=' + output + ' ' + ldc_cmd = 'ldc2 ' + shared_flags + ldc_flags + '-oq -mtriple=wasm32-unknown-unknown-wasm -betterC --output-bc --od=.bc --singleobj --checkaction=C --of=' + output + ' ' for path in sources: ldc_cmd += '-I' + path + ' ' @@ -58,6 +58,9 @@ for arg in sys.argv[1:]: shared_flags += '-Oz ' elif(arg == '-g'): shared_flags += '-g ' + elif(arg == '-g4'): + ldc_flags += '-g ' + emc_flags += '-g4 ' elif(arg == '--llvm-lto'): emc_flags += '--llvm-lto 3 ' elif(arg == '--simd'): @@ -68,6 +71,10 @@ for arg in sys.argv[1:]: emc_flags += '--llvm-lto 3 -s SIMD=1 ' elif(arg == '--clean'): clean = 1 + elif(arg == '-pthread'): + shared_flags += '-O3 ' + ldc_flags += '-release -enable-inlining ' + emc_flags += '-s PTHREAD_POOL_SIZE=16 -Wl,--no-check-features -s USE_PTHREADS=1 ' elif(arg == '--demo=simple'): demo = 0 else: @@ -83,14 +90,14 @@ compile(['source'], 'demo.bc') if clean or os.path.exists('../ecs.bc') == 0 or os.path.isfile('../ecs.bc') == 0: compile(['../source'], '../ecs.bc') -emcc_cmd = 'emcc -v ' + shared_flags + emc_flags + '-s ALLOW_MEMORY_GROWTH=1 -s MALLOC=dlmalloc -s FULL_ES2=1 -s WASM=1 -o index.html ' +emcc_cmd = 'emcc -v ' + shared_flags + emc_flags + '-s ERROR_ON_UNDEFINED_SYMBOLS=0 -s DISABLE_DEPRECATED_FIND_EVENT_TARGET_BEHAVIOR=1 -s TOTAL_MEMORY=256MB -s WASM_MEM_MAX=1024MB -s MALLOC=dlmalloc -s WASM=1 -o index.html ' +#-s ALLOW_MEMORY_GROWTH=1 -s PROXY_TO_PTHREAD=1 emcc_cmd += '../ecs.bc ' emcc_cmd += 'utils.bc ' emcc_cmd += 'bindbc-sdl.bc ' emcc_cmd += 'glad.bc ' emcc_cmd += 'cimgui.bc ' -emcc_cmd += 'nuklear.bc ' emcc_cmd += 'mmutils.bc ' emcc_cmd += 'demo.bc ' diff --git a/demos/dub.json b/demos/dub.json index 0bda382..009bf9e 100644 --- a/demos/dub.json +++ b/demos/dub.json @@ -22,7 +22,7 @@ "targetType" : "executable", "subConfigurations": { - "ecs":"library" + "ecs_utils":"default" } }, { @@ -33,9 +33,7 @@ ], "subConfigurations": { - "bindbc-sdl":"staticBC", - "ecs_utils":"betterC", - "ecs":"library-betterC" + "ecs_utils":"betterC" } } ] diff --git a/demos/external/sources/mmutils/thread_pool.d b/demos/external/sources/mmutils/thread_pool.d index a986048..eb4d53f 100644 --- a/demos/external/sources/mmutils/thread_pool.d +++ b/demos/external/sources/mmutils/thread_pool.d @@ -537,7 +537,7 @@ else version(D_BetterC) threadStart = dg; handle = cast(HANDLE) _beginthreadex( null, 0, &threadRunFunc, cast(void*)&this, 0, null ); //int ok = pthread_create(&handle, null, &threadRunFunc, cast(void*)&this); - assert(handle == null); + assert(handle != null); } void join() diff --git a/demos/libs/windows/x64/SDL2.lib b/demos/libs/windows/x64/SDL2.lib new file mode 100644 index 0000000..89f7d37 Binary files /dev/null and b/demos/libs/windows/x64/SDL2.lib differ diff --git a/demos/libs/windows/x64/SDL2_image.lib b/demos/libs/windows/x64/SDL2_image.lib new file mode 100644 index 0000000..6d00aed Binary files /dev/null and b/demos/libs/windows/x64/SDL2_image.lib differ diff --git a/demos/libs/windows/x64/SDL2main.lib b/demos/libs/windows/x64/SDL2main.lib new file mode 100644 index 0000000..4d07170 Binary files /dev/null and b/demos/libs/windows/x64/SDL2main.lib differ diff --git a/demos/libs/windows/x64/SDL2test.lib b/demos/libs/windows/x64/SDL2test.lib new file mode 100644 index 0000000..f3ad021 Binary files /dev/null and b/demos/libs/windows/x64/SDL2test.lib differ diff --git a/demos/libs/windows/x64/cimgui.lib b/demos/libs/windows/x64/cimgui.lib new file mode 100644 index 0000000..3a6b57c Binary files /dev/null and b/demos/libs/windows/x64/cimgui.lib differ diff --git a/demos/source/app.d b/demos/source/app.d new file mode 100644 index 0000000..10592ac --- /dev/null +++ b/demos/source/app.d @@ -0,0 +1,716 @@ +module app; + +import bindbc.sdl; + +import cimgui.cimgui; + +import game_core.job_updater; + +import ecs.manager; +import ecs.core; +import ecs.std; + +import ecs_utils.gfx.renderer; +import ecs_utils.imgui_bind; +import ecs_utils.imgui_styles; +import ecs_utils.math.vector; +import ecs_utils.utils; + +import glad.gl.gl; +import glad.gl.gles2; +import glad.gl.loader; + +import gui.manager; + +extern (C) : + +enum Tool +{ + entity_spawner, + component_manipulator, + selector +} + +__gshared const (char)*[3] tool_strings = ["Entity spawner", "Component manipulator", "Selector"]; + +struct Launcher +{ + ECSJobUpdater* job_updater; + GUIManager* gui_manager; + ImGuiContext* context; + SDL_Window* window; + SDL_GLContext gl_context; + EntityManager* manager; + bool function() loop; + void function() end; + void function(SDL_Event*) event; + ivec2 window_size = ivec2(1024,768); + Renderer renderer; + ubyte[] keys; + uint style = 3; + uint entities_count; + bool multithreading; + ulong timer_freq; + double delta_time; + uint fps; + + Tool used_tool; + + bool swap_interval = true; + + float windows_alpha = 0.75; + + const (char)* tips; + + bool show_stat_wnd = true; + bool show_tips = true; + bool show_demo_wnd = true; + bool show_virtual_keys_wnd = false; + bool show_profile_wnd = true; + + int plot_index; + PlotStruct[] plot_values; + + struct PlotStruct + { + float delta_time = 0; + float loop_time = 0; + float draw_time = 0; + } + + void switchDemo(void function() start, bool function() loop, void function() end, void function(SDL_Event*) event, const (char)* tips) + { + gui_manager.clear(); + + if(this.end)this.end(); + + manager.begin(); + manager.update("clean"); + manager.end(); + + if(start)start(); + this.loop = loop; + this.end = end; + this.event = event; + this.tips = tips; + } + + bool getKeyState(SDL_Scancode key) + { + if(keys[key])return true; + else return false; + } + + void setStyle(uint index) + { + style = index; + .setStyle(index); + } + + double getTime() + { + ulong local_freq = timer_freq / 1000_000; + //return cast(double)(SDL_GetPerformanceCounter() & 0x00FFFFFF) / timer_freq; + if(local_freq == 0)return cast(double)(SDL_GetPerformanceCounter() / timer_freq * 1000); + else return cast(double)(SDL_GetPerformanceCounter() / local_freq) / 1000; + } +} + +__gshared Launcher launcher; + +struct CountSystem +{ + mixin ECS.System!1; + + struct EntitiesData + { + uint length; + } + + bool onBegin() + { + launcher.entities_count = 0; + return true; + } + + void onUpdate(EntitiesData data) + { + launcher.entities_count += data.length; + } +} + +struct CleanSystem +{ + mixin ECS.System!64; + + struct EntitiesData + { + uint length; + Entity[] entities; + } + + void onUpdate(EntitiesData data) + { + foreach(i; 0..data.length) + { + launcher.manager.removeEntity(data.entities[i].id); + } + } +} + +void mainLoop(void* arg) +{ + static double time = 0; + launcher.delta_time = launcher.getTime() - time; + time = launcher.getTime(); + + if(launcher.delta_time > 1000)launcher.delta_time = 1000; + + static uint temp_fps = 0; + static double fps_time = 0; + temp_fps++; + fps_time += launcher.delta_time; + while(fps_time > 1000) + { + fps_time -= 1000; + launcher.fps = temp_fps; + temp_fps = 0; + } + + + SDL_Event event; + while (SDL_PollEvent(&event)) + { + version(WebAssembly)ImGui_ImplSDL2_ProcessEvent(&event); + else ImGui_ImplSDL2_ProcessEvent(&event); + if(launcher.event)launcher.event(&event); + if (event.type == SDL_QUIT || (event.type == SDL_KEYDOWN && event.key.keysym.scancode == SDL_SCANCODE_ESCAPE)) { + quit(); + *cast(bool*)arg = false; + return; + } + else if(event.type == SDL_WINDOWEVENT) + { + switch(event.window.event) + { + case SDL_WINDOWEVENT_RESIZED: + //launcher.renderer.resize(ivec2(event.window.data1,event.window.data2)); + launcher.window_size = ivec2(event.window.data1,event.window.data2); + break; + case SDL_WINDOWEVENT_SIZE_CHANGED: + //launcher.renderer.resize(ivec2(event.window.data1,event.window.data2)); + launcher.window_size = ivec2(event.window.data1,event.window.data2); + break; + default:break; + } + } + } + + version(WebAssembly) + { + ImGui_ImplOpenGL3_NewFrame(); + ImGui_ImplSDL2_NewFrame(launcher.window); + } + else + { + ImGuiImplOpenGL2NewFrame(); + ImGuiImplSDL2NewFrame(launcher.window); + } + + igNewFrame(); + + if(igBeginMainMenuBar()) + { + if(igBeginMenu("File",true)) + { + if(igMenuItemBool("Close","esc",false,true)) + { + quit(); + *cast(bool*)arg = false; + return; + } + igEndMenu(); + } + if(igBeginMenu("Demos",true)) + { + if(igMenuItemBool("Simpe",null,false,true)) + { + import demos.simple; + launcher.switchDemo(&simpleStart,&simpleLoop,&simpleEnd,&simpleEvent,Simple.tips); + } + if(igMenuItemBool("Snake",null,false,true)) + { + import demos.snake; + launcher.switchDemo(&snakeStart,&snakeLoop,&snakeEnd,&snakeEvent,Snake.tips); + } + if(igMenuItemBool("Space invaders",null,false,true)) + { + import demos.space_invaders; + launcher.switchDemo(&spaceInvadersStart,&spaceInvadersLoop,&spaceInvadersEnd,&spaceInvadersEvent,SpaceInvaders.tips); + } + igEndMenu(); + } + if(igBeginMenu("Options",true)) + { + if(igMenuItemBool("VSync", null, launcher.swap_interval, true)) + { + launcher.swap_interval = !launcher.swap_interval; + SDL_GL_SetSwapInterval(launcher.swap_interval); + } + if(igMenuItemBool("Multithreading", null, launcher.multithreading, true)) + { + launcher.multithreading = !launcher.multithreading; + } + if(igBeginMenu("Show",true)) + { + if(igMenuItemBool("Statistics",null,launcher.show_stat_wnd,true)) + { + launcher.show_stat_wnd = !launcher.show_stat_wnd; + } + else if(igMenuItemBool("Demo",null,launcher.show_demo_wnd,true)) + { + launcher.show_demo_wnd = !launcher.show_demo_wnd; + } + else if(igMenuItemBool("Tips",null,launcher.show_tips,true)) + { + launcher.show_tips = !launcher.show_tips; + } + else if(igMenuItemBool("Virual keys",null,launcher.show_virtual_keys_wnd,true)) + { + launcher.show_virtual_keys_wnd = !launcher.show_virtual_keys_wnd; + } + igEndMenu(); + } + if(igBeginMenu("Style",true)) + { + if(igMenuItemBool("Classic",null,launcher.style == 0,true)) + { + launcher.setStyle(0); + } + else if(igMenuItemBool("Dark",null,launcher.style == 1,true)) + { + launcher.setStyle(1); + } + else if(igMenuItemBool("Light",null,launcher.style == 2,true)) + { + launcher.setStyle(2); + } + else if(igMenuItemBool("Super",null,launcher.style == 3,true)) + { + launcher.setStyle(3); + } + igEndMenu(); + } + igEndMenu(); + } + igEndMainMenuBar(); + } + + if(launcher.show_virtual_keys_wnd) + { + igSetNextWindowPos(ImVec2(launcher.window_size.x - 400, launcher.window_size.y - 200), ImGuiCond_Once, ImVec2(0,0)); + igSetNextWindowSize(ImVec2(64*4+128, 168), ImGuiCond_Once); + igSetNextWindowBgAlpha(launcher.windows_alpha); + ImGuiStyle * style = igGetStyle(); + style.Colors[ImGuiCol_Button].w = 0.8; + if(igBegin("Virtual keys",&launcher.show_virtual_keys_wnd, 0)) + { + igColumns(2,null,0); + igSetColumnWidth(0,64*3+16); + igIndent(64+4); + if(igButton("W",ImVec2(64,64)) || igIsItemDeactivated()) + { + launcher.keys[SDL_SCANCODE_W] = false; + } + else if(igIsItemActive()) + { + launcher.keys[SDL_SCANCODE_W] = true; + } + igUnindent(64+4); + if(igButton("A",ImVec2(64,64)) || igIsItemDeactivated()) + { + launcher.keys[SDL_SCANCODE_A] = false; + } + else if(igIsItemActive()) + { + launcher.keys[SDL_SCANCODE_A] = true; + } + igSameLine(0,4); + if(igButton("S",ImVec2(64,64)) || igIsItemDeactivated()) + { + launcher.keys[SDL_SCANCODE_S] = false; + } + else if(igIsItemActive()) + { + launcher.keys[SDL_SCANCODE_S] = true; + } + igSameLine(0,4); + if(igButton("D",ImVec2(64,64)) || igIsItemDeactivated()) + { + launcher.keys[SDL_SCANCODE_D] = false; + } + else if(igIsItemActive()) + { + launcher.keys[SDL_SCANCODE_D] = true; + } + igNextColumn(); + if(igButton("Space",ImVec2(-1,128)) || igIsItemDeactivated()) + { + launcher.keys[SDL_SCANCODE_SPACE] = false; + } + else if(igIsItemActive()) + { + launcher.keys[SDL_SCANCODE_SPACE] = true; + } + igColumns(1,null,0); + } + igEnd(); + style.Colors[ImGuiCol_Button].w = 1.0; + } + + if(launcher.show_tips) + { + igSetNextWindowPos(ImVec2(launcher.window_size.x - 550, 80), ImGuiCond_Once, ImVec2(0,0)); + igSetNextWindowSize(ImVec2(300, 0), ImGuiCond_Once); + igSetNextWindowBgAlpha(launcher.windows_alpha); + if(igBegin("Tips",&launcher.show_tips,ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoSavedSettings)) + { + igTextWrapped(launcher.tips); + } + igEnd(); + } + + if(launcher.show_demo_wnd) + { + igSetNextWindowPos(ImVec2(launcher.window_size.x - 260, 30), ImGuiCond_Once, ImVec2(0,0)); + igSetNextWindowSize(ImVec2(250, 250), ImGuiCond_Once); + if(igBegin("Demo",&launcher.show_demo_wnd,0)) + { + launcher.gui_manager.gui(); + if(igBeginCombo("Tool",tool_strings[launcher.used_tool],0)) + { + if(igSelectable("Entity spawner",false,0,ImVec2(0,0))) + { + launcher.used_tool = Tool.entity_spawner; + } + if(igSelectable("Component manipulator",false,0,ImVec2(0,0))) + { + launcher.used_tool = Tool.component_manipulator; + } + if(igSelectable("Selector",false,0,ImVec2(0,0))) + { + launcher.used_tool = Tool.selector; + } + igEndCombo(); + } + if(igButton("Clear",ImVec2(-1,0))) + { + launcher.manager.begin(); + launcher.manager.update("clean"); + launcher.manager.end(); + } + } + igEnd(); + } + + if(launcher.show_profile_wnd) + { + igSetNextWindowPos(ImVec2(launcher.window_size.x - 260, launcher.window_size.y - 280), ImGuiCond_Once, ImVec2(0,0)); + igSetNextWindowSize(ImVec2(250, 250), ImGuiCond_Once); + if(igBegin("Profile",&launcher.show_profile_wnd,0)) + { + if(igBeginTabBar("ProfileTabBar",ImGuiTabBarFlags_FittingPolicyScroll)) + { + + if(igBeginTabItem("Plots", null, 0)) + { + if(igBeginChild("ProfileChild",ImVec2(-1,-1),0,0)) + { + igPlotLines("Delta time",&launcher.plot_values[0].delta_time,100,launcher.plot_index,"Delta time",0,float.max,ImVec2(0,64),Launcher.PlotStruct.sizeof); + igPlotLines("Loop time",&launcher.plot_values[0].loop_time,100,launcher.plot_index,"Loop time",0,float.max,ImVec2(0,64),Launcher.PlotStruct.sizeof); + igPlotLines("Draw time",&launcher.plot_values[0].draw_time,100,launcher.plot_index,"Draw time",0,float.max,ImVec2(0,64),Launcher.PlotStruct.sizeof); + } + igEndChild(); + igEndTabItem(); + } + if(igBeginTabItem("Multithreading graph", null, 0)) + { + if(igBeginChild("ProfileChild",ImVec2(-1,-1),0,0)) + { + igText("Work in proggress"); + } + igEndChild(); + igEndTabItem(); + } + + igEndTabBar(); + } + } + igEnd(); + } + + launcher.renderer.resize(launcher.window_size); + launcher.renderer.view(vec2(0,0),vec2(launcher.window_size.x,launcher.window_size.y)); + //glClear(GL_COLOR_BUFFER_BIT); + launcher.renderer.clear(); + + double loop_time = launcher.getTime(); + if(launcher.loop && !launcher.loop()) + { + quit(); + *cast(bool*)arg = false; + } + loop_time = launcher.getTime() - loop_time; + + double draw_time = launcher.getTime(); + launcher.renderer.present(); + draw_time = launcher.getTime() - draw_time; + + static float plot_time = 0; + static uint plot_samples = 0; + plot_time += launcher.delta_time; + plot_samples++; + launcher.plot_values[100].delta_time += launcher.delta_time; + launcher.plot_values[100].loop_time += loop_time; + launcher.plot_values[100].draw_time += draw_time; + if(plot_time > 100) + { + launcher.plot_values[launcher.plot_index].delta_time = launcher.plot_values[100].delta_time / cast(float)plot_samples; + launcher.plot_values[launcher.plot_index].loop_time = launcher.plot_values[100].loop_time / cast(float)plot_samples; + launcher.plot_values[launcher.plot_index].draw_time = launcher.plot_values[100].draw_time / cast(float)plot_samples; + launcher.plot_values[100].delta_time = 0; + launcher.plot_values[100].loop_time = 0; + launcher.plot_values[100].draw_time = 0; + + plot_samples = 0; + plot_time -= 100; + launcher.plot_index++; + if(launcher.plot_index >= 100)launcher.plot_index = 0; + } + + if(launcher.show_stat_wnd) + { + igSetNextWindowPos(ImVec2(10, 30), ImGuiCond_Appearing, ImVec2(0,0)); + igSetNextWindowContentSize(ImVec2(150, 0.0f)); + igSetNextWindowBgAlpha(launcher.windows_alpha); + if(igBegin("Statistics", &launcher.show_stat_wnd, ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_AlwaysAutoResize)) + { + igColumns(2,null,0); + igSetColumnWidth(0,100); + igText("FPS: "); + igText("Entities: "); + igText("Loop time: "); + igText("Draw time: "); + igText("Delta time: "); + igNextColumn(); + igText("%u",launcher.fps); + igText("%u",launcher.entities_count); + igText("%2.2fms",loop_time); + igText("%2.2fms",draw_time); + igText("%2.2fms",launcher.delta_time); + igColumns(1,null,0); + } + igEnd(); + } + + glUseProgram(0); + import ecs_utils.gfx.buffer; + Buffer.unbind(Buffer.BindTarget.array); + Buffer.unbind(Buffer.BindTarget.element_array); + + igRender(); + version(WebAssembly)ImGui_ImplOpenGL3_RenderDrawData(igGetDrawData()); + else ImGuiImplOpenGL2RenderDrawData(igGetDrawData()); + + //launcher.renderer.clear(); + //launcher.renderer.present(); + + SDL_GL_SwapWindow(launcher.window); + +} + +void quit() +{ + launcher.gui_manager.clear(); + Mallocator.dispose(launcher.gui_manager); + + launcher.manager.destroy(); + launcher.manager = null; + + version(WebAssembly)emscripten_cancel_main_loop(); +} + +int main(int argc, char** argv) +{ + + if (SDL_Init(SDL_INIT_VIDEO) < 0) + { + printf("SDL could not initialize! SDL_Error: %s", SDL_GetError()); + return -1; + } + + SDL_version sdl_version; + SDL_GetVersion(&sdl_version); + printf("SDL version: %u.%u.%u\n",cast(uint)sdl_version.major,cast(uint)sdl_version.minor,cast(uint)sdl_version.patch); + + SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2); + SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0); + launcher.window = SDL_CreateWindow("Simple", SDL_WINDOWPOS_CENTERED, + SDL_WINDOWPOS_CENTERED, launcher.window_size.x, launcher.window_size.y, SDL_WINDOW_SHOWN | SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE); + + launcher.gl_context = SDL_GL_CreateContext(launcher.window); + launcher.context = igCreateContext(null); + launcher.timer_freq = SDL_GetPerformanceFrequency(); + + launcher.plot_values = Mallocator.makeArray!(Launcher.PlotStruct)(101); + + SDL_GetWindowSize(launcher.window, &launcher.window_size.x, &launcher.window_size.y); + + version(WebAssembly) + { + gladLoadGLES2(x => SDL_GL_GetProcAddress(x)); + if(!ImGui_ImplSDL2_InitForOpenGL(launcher.window,launcher.gl_context)) + { + printf("ImGui initialization failed!"); + return -2; + } + if(!ImGui_ImplOpenGL3_Init()) + { + printf("ImGui OpenGL initialization failed!"); + return -3; + } + } + else + { + gladLoadGL(); + if(!ImGuiImplSDL2InitForOpenGL(launcher.window,launcher.gl_context)) + { + printf("ImGui initialization failed!"); + return -2; + } + if(!ImGuiImplOpenGL2Init()) + { + printf("ImGui OpenGL initialization failed!"); + return -3; + } + } + + ImFontConfig* config = ImFontConfig_ImFontConfig(); + ImGuiIO* io = igGetIO(); + const ushort* font_ranges = ImFontAtlas_GetGlyphRangesDefault(io.Fonts); + ImFontAtlas_AddFontFromFileTTF(io.Fonts,"assets/fonts/Ruda-Bold.ttf", 15.0f, config, font_ranges); + + setStyle(3); + + launcher.job_updater = Mallocator.make!ECSJobUpdater(8); + //launcher.job_updater.onCreate(); + + EntityManager.initialize(8); + launcher.manager = EntityManager.instance; + + launcher.manager.m_thread_id_func = &launcher.job_updater.getThreadID; + launcher.manager.setJobDispachFunc(&launcher.job_updater.dispatch); + + launcher.manager.beginRegister(); + + launcher.manager.registerPass("clean"); + + launcher.manager.registerSystem!CountSystem(10000); + launcher.manager.registerSystem!CleanSystem(0,"clean"); + + launcher.manager.endRegister(); + + loadGFX(); + + launcher.renderer.initialize(); + + launcher.gui_manager = Mallocator.make!GUIManager(); + + { + import demos.simple; + launcher.switchDemo(&simpleStart,&simpleLoop,&simpleEnd,&simpleEvent,Simple.tips); + } + + int key_num; + ubyte* keys = SDL_GetKeyboardState(&key_num); + launcher.keys = keys[0..key_num]; + + version(WebAssembly) + { + /*EmscriptenFullscreenStrategy strategy; + strategy.scaleMode = EMSCRIPTEN_FULLSCREEN_SCALE_STRETCH; + strategy.canvasResolutionScaleMode = EMSCRIPTEN_FULLSCREEN_CANVAS_SCALE_STDDEF; + strategy.filteringMode = EMSCRIPTEN_FULLSCREEN_FILTERING_NEAREST;*/ + + //int result = emscripten_request_fullscreen_strategy(null, true, &strategy); + //emscripten_enter_soft_fullscreen(null, &strategy); + //printf("Fullscreen request: %s.\n", emscripten_result_to_string(result)); + emscripten_set_main_loop_arg(&mainLoop, null, -1, 1); + } + else + { + bool arg = true; + while(arg == true) + { + mainLoop(&arg); + } + } + + return 0; +} + +void loadGFX() +{ + import ecs_utils.gfx.texture; + import ecs_utils.gfx.vertex; + import ecs_utils.gfx.shader; + import ecs_utils.gfx.material; + import ecs_utils.gfx.config; + import ecs_utils.gfx.mesh; + + Texture.__loadBackend(); + Renderer.__loadBackend(); + + GfxConfig.materials = Mallocator.makeArray!Material(1); + GfxConfig.meshes = Mallocator.makeArray!Mesh(1); + + float[16] vertices = [-0.5,-0.5, 0,0, -0.5,0.5, 0,1, 0.5,-0.5, 1,0, 0.5,0.5, 1,1]; + GfxConfig.meshes[0].vertices = Mallocator.makeArray(vertices); + ushort[6] indices = [0,1,2,1,2,3]; + GfxConfig.meshes[0].indices = Mallocator.makeArray(indices); + GfxConfig.meshes[0].uploadData(); + + Shader vsh; + vsh.create(); + vsh.load("assets/shaders/base.vp"); + vsh.compile(); + + Shader fsh; + fsh.create(); + fsh.load("assets/shaders/base.fp"); + fsh.compile(); + + GfxConfig.materials[0].create(); + GfxConfig.materials[0].data.blend_mode = Material.BlendMode.opaque; + GfxConfig.materials[0].data.mode = Material.TransformMode.position; + Material.ShaderModule[1] modules = [Material.ShaderModule(vsh,fsh)]; + GfxConfig.materials[0].attachModules(modules); + //GfxConfig.materials[0]. + //GfxConfig.materials[0].load(load_data.materials[i].str); + GfxConfig.materials[0].compile(); + GfxConfig.materials[0].bindAttribLocation("positions",0); + GfxConfig.materials[0].bindAttribLocation("tex_coords",1); + GfxConfig.materials[0].link(); + + GfxConfig.materials[0].data.uniforms = Mallocator.makeArray!(Material.Uniform)(3); + GfxConfig.materials[0].data.uniforms[0] = Material.Uniform(Material.Type.float4, GfxConfig.materials[0].getLocation("matrix_1"), 0); + GfxConfig.materials[0].data.uniforms[1] = Material.Uniform(Material.Type.float4, GfxConfig.materials[0].getLocation("matrix_2"), 16); + GfxConfig.materials[0].data.uniforms[2] = Material.Uniform(Material.Type.float4, GfxConfig.materials[0].getLocation("uv_transform"), 32); + GfxConfig.materials[0].data.bindings = Mallocator.makeArray!(int)(1); + GfxConfig.materials[0].data.bindings[0] = GfxConfig.materials[0].getLocation("tex"); + + + /*glUseProgram(0); + glBindBuffer(GL_ARRAY_BUFFER, 0); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);*/ +} \ No newline at end of file diff --git a/demos/source/demos/bullet_madnes.d b/demos/source/demos/bullet_madnes.d new file mode 100644 index 0000000..0996e2e --- /dev/null +++ b/demos/source/demos/bullet_madnes.d @@ -0,0 +1,19 @@ +module demos.bullet_madnes; + +import app; + +import bindbc.sdl; + +import cimgui.cimgui; + +import ecs.attributes; +import ecs.core; +import ecs.entity; +import ecs.manager; +import ecs.std; + +import ecs_utils.gfx.texture; +import ecs_utils.math.vector; +import ecs_utils.utils; + +extern(C): \ No newline at end of file diff --git a/demos/source/demos/chipmunk2d.d b/demos/source/demos/chipmunk2d.d new file mode 100644 index 0000000..25b9c66 --- /dev/null +++ b/demos/source/demos/chipmunk2d.d @@ -0,0 +1,19 @@ +module demos.chipmunk2d; + +import app; + +import bindbc.sdl; + +import cimgui.cimgui; + +import ecs.attributes; +import ecs.core; +import ecs.entity; +import ecs.manager; +import ecs.std; + +import ecs_utils.gfx.texture; +import ecs_utils.math.vector; +import ecs_utils.utils; + +extern(C): \ No newline at end of file diff --git a/demos/source/demos/events.d b/demos/source/demos/events.d new file mode 100644 index 0000000..620ff4d --- /dev/null +++ b/demos/source/demos/events.d @@ -0,0 +1,19 @@ +module demos.events; + +import app; + +import bindbc.sdl; + +import cimgui.cimgui; + +import ecs.attributes; +import ecs.core; +import ecs.entity; +import ecs.manager; +import ecs.std; + +import ecs_utils.gfx.texture; +import ecs_utils.math.vector; +import ecs_utils.utils; + +extern(C): \ No newline at end of file diff --git a/demos/source/demos/flag_component.d b/demos/source/demos/flag_component.d new file mode 100644 index 0000000..a1863b9 --- /dev/null +++ b/demos/source/demos/flag_component.d @@ -0,0 +1,19 @@ +module demos.flag_component; + +import app; + +import bindbc.sdl; + +import cimgui.cimgui; + +import ecs.attributes; +import ecs.core; +import ecs.entity; +import ecs.manager; +import ecs.std; + +import ecs_utils.gfx.texture; +import ecs_utils.math.vector; +import ecs_utils.utils; + +extern(C): \ No newline at end of file diff --git a/demos/source/demos/physics.d b/demos/source/demos/physics.d new file mode 100644 index 0000000..6e9ba4a --- /dev/null +++ b/demos/source/demos/physics.d @@ -0,0 +1,19 @@ +module demos.physics; + +import app; + +import bindbc.sdl; + +import cimgui.cimgui; + +import ecs.attributes; +import ecs.core; +import ecs.entity; +import ecs.manager; +import ecs.std; + +import ecs_utils.gfx.texture; +import ecs_utils.math.vector; +import ecs_utils.utils; + +extern(C): \ No newline at end of file diff --git a/demos/source/demos/simple.d b/demos/source/demos/simple.d new file mode 100644 index 0000000..9340458 --- /dev/null +++ b/demos/source/demos/simple.d @@ -0,0 +1,171 @@ +module demos.simple; + +import app; + +import bindbc.sdl; + +import cimgui.cimgui; + +import ecs.attributes; +import ecs.core; +import ecs.entity; +import ecs.manager; +import ecs.std; + +import ecs_utils.gfx.texture; +import ecs_utils.math.vector; +import ecs_utils.utils; + +extern(C): + +struct Simple +{ + __gshared const (char)* tips = "Use \"space\" to spwan entities.\n\nSystems can be enabled/disabled from \"Simple\" window."; + + EntityTemplate* tmpl; + Texture texture; + + bool move_system = true; + bool draw_system = true; +} + +struct CLocation +{ + mixin ECS.Component; + + alias location this; + + vec2 location; +} + +struct CTexture +{ + mixin ECS.Component; + + Texture tex; +} + +struct DrawSystem +{ + mixin ECS.System!1; + + struct EntitiesData + { + uint length; + @readonly CTexture[] textures; + @readonly CLocation[] locations; + } + + void onUpdate(EntitiesData data) + { + foreach(i; 0..data.length) + { + launcher.renderer.draw(data.textures[i].tex, data.locations[i].location, vec2(32,32), vec4(0,0,1,1), 0, 0 , 0); + //draw(renderer, data.textures[i].tex, data.locations[i], vec2(32,32), vec4(0,0,1,1)); + } + } +} + +struct MoveSystem +{ + mixin ECS.System!64; + + struct EntitiesData + { + uint length; + CLocation[] locations; + } + + void onUpdate(EntitiesData data) + { + foreach(i; 0..data.length) + { + data.locations[i].location.y = data.locations[i].location.y + 1; + if(data.locations[i].location.y > 400)data.locations[i].location.y = 0; + } + } +} + +Simple* simple; + +void simpleStart() +{ + simple = Mallocator.make!Simple; + + simple.texture.create(); + simple.texture.load("assets/textures/buckler.png"); + + launcher.manager.beginRegister(); + + launcher.manager.registerComponent!CLocation; + launcher.manager.registerComponent!CTexture; + + launcher.manager.registerSystem!MoveSystem(0); + launcher.manager.registerSystem!DrawSystem(1); + + launcher.manager.endRegister(); + + launcher.gui_manager.addSystem(MoveSystem.system_id,"Move System"); + launcher.gui_manager.addSystem(DrawSystem.system_id,"Draw System"); + + ushort[2] components = [CLocation.component_id, CTexture.component_id]; + simple.tmpl = launcher.manager.allocateTemplate(components); + CTexture* tex_comp = simple.tmpl.getComponent!CTexture; + tex_comp.tex = simple.texture; + CLocation* loc_comp = simple.tmpl.getComponent!CLocation; + + foreach(i; 0..10) + foreach(j; 0..10) + { + loc_comp.location = vec2(i*32+64,j*32+64); + launcher.manager.addEntity(simple.tmpl); + } +} + +void simpleEnd() +{ + launcher.manager.getSystem(MoveSystem.system_id).disable(); + launcher.manager.getSystem(DrawSystem.system_id).disable(); + + simple.texture.destroy(); + + launcher.manager.freeTemplate(simple.tmpl); + Mallocator.dispose(simple); +} + +void simpleEvent(SDL_Event* event) +{ + +} + +void spawnEntity() +{ + CLocation* loc_comp = simple.tmpl.getComponent!CLocation; + loc_comp.location = vec2(randomf() * 600,0); + launcher.manager.addEntity(simple.tmpl); +} + +bool simpleLoop() +{ + if(launcher.getKeyState(SDL_SCANCODE_SPACE)) + { + spawnEntity(); + } + + + launcher.manager.begin(); + if(launcher.multithreading) + { + launcher.job_updater.begin(); + launcher.manager.updateMT(); + launcher.job_updater.call(); + launcher.multithreading = false; + } + else + { + launcher.manager.update(); + } + launcher.manager.end(); + + return true; +} \ No newline at end of file diff --git a/demos/source/demos/snake.d b/demos/source/demos/snake.d new file mode 100644 index 0000000..19f08ad --- /dev/null +++ b/demos/source/demos/snake.d @@ -0,0 +1,522 @@ +module demos.snake; + +import app; + +import bindbc.sdl; + +import cimgui.cimgui; + +import ecs.attributes; +import ecs.core; +import ecs.entity; +import ecs.manager; +import ecs.std; +import ecs.vector; + +import ecs_utils.gfx.texture; +import ecs_utils.math.vector; +import ecs_utils.utils; + +extern(C): + +struct MapElement +{ + enum Type + { + empty = 0, + snake = 1, + apple = 2, + wall = 3 + } + Type type; + EntityID id; +} + +struct Snake +{ + __gshared const (char)* tips = "Use \"WASD\" keys to move."; + + EntityTemplate* apple_tmpl; + EntityTemplate* snake_tmpl; + Texture snake_texture; + Texture wall_texture; + Texture apple_texture; + + bool move_system = true; + bool draw_system = true; + + const int map_size = 18; + + MapElement[map_size * map_size] map; + + MapElement element(ivec2 pos) + { + return map[pos.x + pos.y * map_size]; + } + + void element(MapElement el, ivec2 pos) + { + map[pos.x + pos.y * map_size] = el; + } + + void addApple() + { + ivec2 random_pos = ivec2(rand()%map_size,rand()%map_size); + while(element(random_pos).type != MapElement.Type.empty) + { + random_pos.x += 1; + if(random_pos.x > map_size) + { + random_pos.y = 0; + random_pos.y += 1; + if(random_pos.y > map_size)random_pos.y = 0; + } + } + Entity* apple = launcher.manager.addEntity(apple_tmpl); + element(MapElement(MapElement.Type.apple,apple.id),random_pos); + } + + void drawMap() + { + foreach(x; 0 .. map_size) + { + foreach(y; 0 .. map_size) + { + switch(element(ivec2(x,y)).type) + { + case MapElement.Type.apple:launcher.renderer.draw(apple_texture, vec2(x*32,y*32), vec2(32,32), vec4(0,0,1,1), 0, 0 , 0);break; + case MapElement.Type.snake:launcher.renderer.draw(snake_texture, vec2(x*32,y*32), vec2(32,32), vec4(0,0,1,1), 0, 0 , 0);break; + case MapElement.Type.wall:launcher.renderer.draw(wall_texture, vec2(x*32,y*32), vec2(32,32), vec4(0,0,1,1), 0, 0 , 0);break; + default:break; + } + } + } + } + +} + +struct CILocation +{ + mixin ECS.Component; + + alias location this; + + ivec2 location; +} + +struct CLocation +{ + mixin ECS.Component; + + alias location this; + + vec2 location; +} + +struct CSnake +{ + void onCreate() + { + parts.array = Mallocator.makeArray!ivec2(100); + } + + void onDestroy() + { + Mallocator.dispose(parts.array); + } + + mixin ECS.Component; + + struct Parts + { + uint length = 0; + ivec2[] array; + + ivec2 opIndex(size_t ind) const + { + return array[ind]; + } + + ivec2[] opSlice() + { + return array[0 .. length]; + } + + void opIndexAssign(ivec2 vec, size_t ind) + { + array[ind] = vec; + } + + size_t opDollar() const + { + return length; + } + + void add(ivec2 v) + { + length++; + array[length-1] = v; + } + } + + Parts parts; +} + +struct CApple +{ + mixin ECS.Component; +} + +struct CParticle +{ + mixin ECS.Component; +} + +struct CParticleVector +{ + mixin ECS.Component; + + vec2 velocity; +} + +struct CMovement +{ + mixin ECS.Component; + + enum Direction : byte + { + up, + down, + left, + right + } + + Direction direction; +} + +struct CInput +{ + mixin ECS.Component; +} + +struct MoveSystem +{ + mixin ECS.System!64; + + struct EntitiesData + { + uint length; + @readonly Entity[] entities; + @readonly CMovement[] movement; + @optional CSnake[] snakes; + CILocation[] location; + } + + void moveLocation(ref CILocation location, CMovement.Direction direction) + { + final switch(direction) + { + case CMovement.Direction.down: + location.y -= 1; + if(location.y < 0)location.y = snake.map_size - 1; + break; + case CMovement.Direction.up: + location.y += 1; + if(location.y >= snake.map_size)location.y = 0; + break; + case CMovement.Direction.left: + location.x -= 1; + if(location.x < 0)location.x = snake.map_size - 1; + break; + case CMovement.Direction.right: + location.x += 1; + if(location.x >= snake.map_size)location.x = 0; + break; + } + } + + void moveSnake(ref CSnake snake, ivec2 location) + { + if(snake.parts.length) + { + .snake.element(MapElement(),snake.parts[0]); + foreach(j; 0 .. snake.parts.length - 1) + { + snake.parts[j] = snake.parts[j + 1]; + } + snake.parts[$-1] = location; + } + else .snake.element(MapElement(),location); + } + + void onUpdate(EntitiesData data) + { + if(data.snakes) + { + foreach(i; 0..data.length) + { + ivec2 new_location = data.location[i]; + moveLocation(data.location[i], data.movement[i].direction); + final switch(snake.element(data.location[i].location).type) + { + case MapElement.Type.snake: + launcher.manager.removeEntity(data.entities[i].id); + break; + case MapElement.Type.wall: + launcher.manager.removeEntity(data.entities[i].id); + break; + case MapElement.Type.empty: + moveSnake(data.snakes[i], new_location); + snake.element(MapElement(MapElement.Type.snake, data.entities[i].id),data.location[i].location); + break; + case MapElement.Type.apple: + data.snakes[i].parts.add(new_location); + snake.element(MapElement(MapElement.Type.snake, data.entities[i].id),new_location); + snake.element(MapElement(MapElement.Type.snake, data.entities[i].id),data.location[i].location); + snake.addApple(); + break; + } + } + } + else + { + foreach(i; 0..data.length) + { + final switch(data.movement[i].direction) + { + case CMovement.Direction.down:data.location[i].location.y -= 1;break; + case CMovement.Direction.up:data.location[i].location.y += 1;break; + case CMovement.Direction.left:data.location[i].location.x -= 1;break; + case CMovement.Direction.right:data.location[i].location.x += 1;break; + } + } + } + + } +} + +struct InputSystem +{ + mixin ECS.System!64; + + struct EntitiesData + { + uint length; + CMovement[] movement; + @readonly CInput[] input; + } + + void onUpdate(EntitiesData data) + { + foreach(i; 0..data.length) + { + if(launcher.getKeyState(SDL_SCANCODE_W)) + { + data.movement[i].direction = CMovement.Direction.up; + } + else if(launcher.getKeyState(SDL_SCANCODE_S)) + { + data.movement[i].direction = CMovement.Direction.down; + } + else if(launcher.getKeyState(SDL_SCANCODE_A)) + { + data.movement[i].direction = CMovement.Direction.left; + } + else if(launcher.getKeyState(SDL_SCANCODE_D)) + { + data.movement[i].direction = CMovement.Direction.right; + } + } + } +} + +struct FixSnakeDirectionSystem +{ + mixin ECS.System!64; + + struct EntitiesData + { + uint length; + CMovement[] movement; + @readonly CILocation[] location; + const (CSnake)[] snake; + } + + void onUpdate(EntitiesData data) + { + foreach(i; 0..data.length) + { + ivec2 last_location; + if(data.snake[i].parts.length)last_location = data.snake[i].parts[$ - 1]; + else continue; + ivec2 next_location = data.location[i]; + + final switch(data.movement[i].direction) + { + case CMovement.Direction.up: + next_location.y += 1; + if(next_location.y >= snake.map_size)next_location.y = 0; + if(next_location.x == last_location.x && next_location.y == last_location.y) + { + data.movement[i].direction = CMovement.Direction.down; + } + break; + case CMovement.Direction.down: + next_location.y -= 1; + if(next_location.y < 0)next_location.y = snake.map_size - 1; + if(next_location.x == last_location.x && next_location.y == last_location.y) + { + data.movement[i].direction = CMovement.Direction.up; + } + break; + case CMovement.Direction.left: + next_location.x -= 1; + if(next_location.x < 0)next_location.x = snake.map_size - 1; + if(next_location.x == last_location.x && next_location.y == last_location.y) + { + data.movement[i].direction = CMovement.Direction.right; + } + break; + case CMovement.Direction.right: + next_location.x += 1; + if(next_location.x >= snake.map_size)next_location.x = 0; + if(next_location.x == last_location.x && next_location.y == last_location.y) + { + data.movement[i].direction = CMovement.Direction.left; + } + break; + } + } + } +} + +struct CleanSystem +{ + mixin ECS.System!64; + + struct EntitiesData + { + uint length; + Entity[] entities; + } + + void onUpdate(EntitiesData data) + { + foreach(i; 0..data.length) + { + launcher.manager.removeEntity(data.entities[i].id); + } + } +} + +Snake* snake; + +void snakeStart() +{ + snake = Mallocator.make!Snake; + + snake.snake_texture.create(); + snake.snake_texture.load("assets/textures/buckler.png"); + + snake.apple_texture.create(); + snake.apple_texture.load("assets/textures/buckler.png"); + + snake.wall_texture.create(); + snake.wall_texture.load("assets/textures/buckler.png"); + + launcher.manager.beginRegister(); + + launcher.manager.registerPass("fixed"); + + launcher.manager.registerComponent!CLocation; + launcher.manager.registerComponent!CILocation; + launcher.manager.registerComponent!CSnake; + launcher.manager.registerComponent!CApple; + launcher.manager.registerComponent!CParticle; + launcher.manager.registerComponent!CMovement; + launcher.manager.registerComponent!CInput; + + launcher.manager.registerSystem!MoveSystem(0,"fixed"); + launcher.manager.registerSystem!InputSystem(-100); + launcher.manager.registerSystem!FixSnakeDirectionSystem(-1,"fixed"); + + launcher.manager.endRegister(); + + launcher.gui_manager.addSystem(MoveSystem.system_id,"Move System"); + launcher.gui_manager.addSystem(InputSystem.system_id,"Input System"); + launcher.gui_manager.addSystem(FixSnakeDirectionSystem.system_id,"Fix Direction System"); + + { + ushort[4] components = [CILocation.component_id, CSnake.component_id, CMovement.component_id, CInput.component_id]; + snake.snake_tmpl = launcher.manager.allocateTemplate(components); + CILocation* loc_comp = snake.snake_tmpl.getComponent!CILocation; + loc_comp.location = ivec2(2,2); + launcher.manager.addEntity(snake.snake_tmpl); + } + + { + ushort[2] components = [CILocation.component_id, CApple.component_id]; + snake.apple_tmpl = launcher.manager.allocateTemplate(components); + snake.addApple(); + } + + /*foreach(i; 0..10) + foreach(j; 0..10) + { + loc_comp.location = vec2(i*32+64,j*32+64); + launcher.manager.addEntity(simple.tmpl); + }*/ +} + +void snakeEnd() +{ + snake.wall_texture.destroy(); + snake.apple_texture.destroy(); + snake.snake_texture.destroy(); + + //launcher.manager.freeTemplate(simple.tmpl); + Mallocator.dispose(snake); +} + +void snakeEvent(SDL_Event* event) +{ + +} + +bool snakeLoop() +{ + /*if(launcher.show_demo_wnd) + { + igSetNextWindowPos(ImVec2(800 - 260, 30), ImGuiCond_Once, ImVec2(0,0)); + igSetNextWindowSize(ImVec2(250, 0), ImGuiCond_Once); + if(igBegin("Snake",&launcher.show_demo_wnd,0)) + { + + } + igEnd(); + }*/ + + launcher.manager.begin(); + + float delta_time = launcher.delta_time; + if(delta_time > 2000)delta_time = 2000; + static float time = 0; + + if(launcher.getKeyState(SDL_SCANCODE_SPACE))time += delta_time * 3; + else time += delta_time; + + while(time > 100) + { + time -= 100; + + launcher.manager.update("fixed"); + } + + launcher.manager.update(); + + launcher.manager.end(); + + snake.drawMap(); + + return true; +} \ No newline at end of file diff --git a/demos/source/demos/space_invaders.d b/demos/source/demos/space_invaders.d new file mode 100644 index 0000000..2d8ebc0 --- /dev/null +++ b/demos/source/demos/space_invaders.d @@ -0,0 +1,764 @@ +module demos.space_invaders; + +import app; + +import bindbc.sdl; + +import cimgui.cimgui; + +import ecs.attributes; +import ecs.core; +import ecs.entity; +import ecs.manager; +import ecs.std; + +import ecs_utils.gfx.texture; +import ecs_utils.math.vector; +import ecs_utils.utils; + +extern(C): + +/*####################################################################################################################### +------------------------------------------------ Types ------------------------------------------------------------------ +#######################################################################################################################*/ + +struct SpaceInvaders +{ + __gshared const (char)* tips = "Use \"WASD\" keys to move and \"Space\" for shooting."; + + EntityTemplate* enemy_tmpl; + EntityTemplate* ship_tmpl; + EntityTemplate* laser_tmpl; + Texture enemy_tex; + Texture ship_tex; + Texture laser_tex; + + bool move_system = true; + bool draw_system = true; + + const vec2 map_size = vec2(600,600); + const float cell_size = 60; +} + +struct SceneGrid +{ + struct Element + { + EntityID entity; + int guild; + vec2 min; + vec2 max; + } + + struct Cell + { + Element[20] elements; + } + + void create() + { + cells_count.x = cast(int)((space_invaders.map_size.x - 0.01f) / space_invaders.cell_size) + 1; + cells_count.y = cast(int)((space_invaders.map_size.y - 0.01f) / space_invaders.cell_size) + 1; + cells = Mallocator.makeArray!Cell(cells_count.x * cells_count.y); + } + + void destory() + { + if(cells) + { + Mallocator.dispose(cells); + cells = null; + } + } + + ivec2 cells_count; + Cell[] cells; +} + +enum Direction : byte +{ + up, + down, + left, + right +} + +/*####################################################################################################################### +------------------------------------------------ Components ------------------------------------------------------------------ +#######################################################################################################################*/ + +struct CLocation +{ + mixin ECS.Component; + + alias value this; + + vec2 value; +} + +struct CScale +{ + mixin ECS.Component; + + ///use component as it value + alias value this; + + vec2 value = vec2(32,32); +} + +struct CTexture +{ + mixin ECS.Component; + + Texture tex; +} + +struct CVelocity +{ + mixin ECS.Component; + + alias value this; + + vec2 value = vec2(0,0); +} + +struct CInput +{ + mixin ECS.Component; +} + +struct CEnemy +{ + mixin ECS.Component; +} + +struct CShip +{ + mixin ECS.Component; +} + +struct CAutoShoot +{ + mixin ECS.Component; +} + +struct CGuild +{ + mixin ECS.Component; + + int guild; +} + +struct CLaser +{ + mixin ECS.Component; + + float damage = 1.0f; +} + +struct CLaserWeapon +{ + mixin ECS.Component; + + ubyte level = 1; + float shoot_time = 0; +} + +struct CShootDirection +{ + mixin ECS.Component; + + Direction direction; +} + +struct CSideMove +{ + mixin ECS.Component; + + byte group = -1; +} + +/*####################################################################################################################### +------------------------------------------------ Events ------------------------------------------------------------------ +#######################################################################################################################*/ + +struct EChangeDirection +{ + mixin ECS.Event; + + this(Direction direction) + { + this.direction = direction; + } + + Direction direction; +} + +/*####################################################################################################################### +------------------------------------------------ Systems ------------------------------------------------------------------ +#######################################################################################################################*/ + +struct DrawSystem +{ + mixin ECS.System!1; + + struct EntitiesData + { + uint length; + @readonly CTexture[] textures; + @readonly CLocation[] locations; + @readonly CScale[] scale; + } + + void onUpdate(EntitiesData data) + { + foreach(i; 0..data.length) + { + launcher.renderer.draw(data.textures[i].tex, data.locations[i].value, data.scale[i], vec4(0,0,1,1), 0, 0 , 0); + //draw(renderer, data.textures[i].tex, data.locations[i], vec2(32,32), vec4(0,0,1,1)); + } + } +} + +struct CollisionSystem +{ + mixin ECS.System; + + struct EntitiesData + { + + } + + void onUpdate(EntitiesData data) + { + + } +} + +struct LaserShootingSystem +{ + mixin ECS.System!32; + + bool shoot = false; + float[10] laser_shoot_times = [2000,1500,1000,700,500,300,100,50,10,1]; + + CLocation* laser_location; + CVelocity* laser_velocity; + + struct EntitiesData + { + ///variable named "length" contain entites count + uint length; + @readonly CShootDirection[] shoot_direction; + @readonly @optional CAutoShoot[] auto_shoot; + @readonly CLocation[] location; + CLaserWeapon[] laser; + } + + ///Called inside "registerSystem" function + /*void onCreate() + { + laser_location = space_invaders.laser_tmpl.getComponent!CLocation; + }*/ + + bool onBegin() + { + laser_location = space_invaders.laser_tmpl.getComponent!CLocation; + laser_velocity = space_invaders.laser_tmpl.getComponent!CVelocity; + if(launcher.getKeyState(SDL_SCANCODE_SPACE)) + { + shoot = true; + } + else shoot = false; + return true; + } + + void onUpdate(EntitiesData data) + { + //conditional branch for whole entities block + if(shoot || data.auto_shoot) + { + foreach(i;0..data.length) + { + CLaserWeapon* laser = &data.laser[i]; + laser.shoot_time += launcher.delta_time; + while(laser.shoot_time > laser_shoot_times[laser.level - 1]) + { + laser.shoot_time -= laser_shoot_times[laser.level - 1]; + laser_location.value = data.location[i]; + laser_velocity.value = vec2(randomf()*0.5-0.25,data.shoot_direction[i].direction == Direction.up ? 1.0 : -1.0); + launcher.manager.addEntity(space_invaders.laser_tmpl); + } + } + } + else + { + foreach(i;0..data.length) + { + CLaserWeapon* laser = &data.laser[i]; + laser.shoot_time += launcher.delta_time; + if(laser.shoot_time > laser_shoot_times[laser.level - 1])laser.shoot_time = laser_shoot_times[laser.level - 1]; + } + } + + } +} + +struct ChangeDirectionSystem +{ + mixin ECS.System; + + Direction[8] groups_directions; + + struct EntitiesData + { + uint length; + const (Entity)[] entities; + CVelocity[] velocity; + + @optional const(CSideMove)[] side_move; + } + + void onCreate() + { + foreach(ref direction; groups_directions) + { + direction = cast(Direction)-1; + } + } + + bool onBegin() + { + foreach(direction; groups_directions) + { + if(direction != cast(Direction)-1)return true; + } + return false; + } + + void onEnd() + { + foreach(ref direction; groups_directions) + { + direction = cast(Direction)-1; + } + } + + void onUpdate(EntitiesData data) + { + if(!data.side_move)return; + foreach(i;0..data.length) + { + byte group = data.side_move[i].group; + if(group == -1)continue; + Direction direction = groups_directions[group]; + if(direction != cast(Direction)-1) + { + CVelocity* velocity = &data.velocity[i]; + final switch(direction) + { + case Direction.up: + if(velocity.value.y > 0)velocity.value.y = -velocity.value.y; + break; + case Direction.down: + if(velocity.value.y < 0)velocity.value.y = -velocity.value.y; + break; + case Direction.left: + if(velocity.value.x > 0)velocity.value.x = -velocity.value.x; + break; + case Direction.right: + if(velocity.value.x < 0)velocity.value.x = -velocity.value.x; + break; + } + } + } + } + + void handleEvent(Entity* entity, EChangeDirection event) + { + CSideMove* side_move = entity.getComponent!CSideMove; + if(side_move && side_move.group != -1) + { + groups_directions[side_move.group] = event.direction; + return; + } + //Entity* entity = launcher.manager.getEntity(event.entity_id); + CVelocity* velocity = entity.getComponent!CVelocity; + final switch(event.direction) + { + case Direction.up: + if(velocity.value.y > 0)velocity.value.y = -velocity.value.y; + break; + case Direction.down: + if(velocity.value.y < 0)velocity.value.y = -velocity.value.y; + break; + case Direction.left: + if(velocity.value.x > 0)velocity.value.x = -velocity.value.x; + break; + case Direction.right: + if(velocity.value.x < 0)velocity.value.x = -velocity.value.x; + break; + } + } +} + +struct ClampPositionSystem +{ + mixin ECS.System!32; + + struct EntitiesData + { + uint length; + const (Entity)[] entities; + //components are treated as required by default + CLocation[] locations; + + @optional const (CLaser)[] laser; + @optional const (CSideMove)[] side_move; + } + + void onUpdate(EntitiesData data) + { + if(data.laser) + { + foreach(i;0..data.length) + { + if(data.locations[i].x < 0 || data.locations[i].x > space_invaders.map_size.x || + data.locations[i].y < 0 || data.locations[i].y > space_invaders.map_size.y)launcher.manager.removeEntity(data.entities[i].id); + } + } + else if(data.side_move) + { + foreach(i;0..data.length) + { + if(data.locations[i].x < 0) + { + //data.locations[i].x = 0; + launcher.manager.sendEvent(data.entities[i].id,EChangeDirection(Direction.right)); + } + else if(data.locations[i].x > space_invaders.map_size.x) + { + //data.locations[i].x = space_invaders.map_size.x; + launcher.manager.sendEvent(data.entities[i].id,EChangeDirection(Direction.left)); + } + if(data.locations[i].y < 0) data.locations[i].y = 0; + else if(data.locations[i].y > space_invaders.map_size.y)data.locations[i].y = space_invaders.map_size.y; + } + } + else + { + foreach(i;0..data.length) + { + if(data.locations[i].x < 0)data.locations[i].x = 0; + else if(data.locations[i].x > space_invaders.map_size.x)data.locations[i].x = space_invaders.map_size.x; + if(data.locations[i].y < 0)data.locations[i].y = 0; + else if(data.locations[i].y > space_invaders.map_size.y)data.locations[i].y = space_invaders.map_size.y; + } + } + } +} + +struct MovementSystem +{ + mixin ECS.System!32; + + struct EntitiesData + { + uint length; + //read only components can be marked with @readonly attribute or with const expression instead + const (CVelocity)[] velocity; + //components are treated as required by default + CLocation[] locations; + //@optional const (CLaser)[] laser; + const (Entity)[] entities; + + @optional CSideMove[] side_move; + } + + void onUpdate(EntitiesData data) + { + foreach(i;0..data.length) + { + data.locations[i].x += data.velocity[i].x * launcher.delta_time; + data.locations[i].y += data.velocity[i].y * launcher.delta_time; + } + } +} + +/** +*System is responsible for movement of objects with CInput component. +*In this example every entity has same speed when using movement system. +*/ +struct InputMovementSystem +{ + mixin ECS.System!32; + + vec2 move_vector; + + struct EntitiesData + { + uint length; + //read only components can be marked with @readonly attribute or with const expression instead + const (CInput)[] input; + //components are treated as required by default + CLocation[] locations; + } + + /** + *onBegin gives opportunity to check keys once and call update on entities only when + *one key is pressed. + */ + bool onBegin() + { + if(launcher.getKeyState(SDL_SCANCODE_W)) + { + move_vector = vec2(0,1); + return true; + } + else if(launcher.getKeyState(SDL_SCANCODE_S)) + { + move_vector = vec2(0,-1); + return true; + } + else if(launcher.getKeyState(SDL_SCANCODE_A)) + { + move_vector = vec2(-1,0); + return true; + } + else if(launcher.getKeyState(SDL_SCANCODE_D)) + { + move_vector = vec2(1,0); + return true; + } + //don't call system update because no key pressed + return false; + } + + /** + *Update is called multiple times in one "manager.update()" call. + *Number of "onUpdate" calls is count of buffers which must be updated during pass. + *When multithreading is used, number of "onUpdate" calls can be greater due to fact that + *JobSystem can split buffers for better data packing. + */ + void onUpdate(EntitiesData data) + { + //move every entity using movement vector + foreach(i; 0..data.length) + { + data.locations[i].x += move_vector.x * launcher.delta_time * 0.5; + data.locations[i].y += move_vector.y * launcher.delta_time * 0.5; + } + } +} + +/*####################################################################################################################### +------------------------------------------------ Functions ------------------------------------------------------------------ +#######################################################################################################################*/ + +__gshared SpaceInvaders* space_invaders; + +void spaceInvadersStart() +{ + space_invaders = Mallocator.make!SpaceInvaders; + + space_invaders.ship_tex.create(); + space_invaders.ship_tex.load("assets/textures/buckler.png"); + + space_invaders.laser_tex.create(); + space_invaders.laser_tex.load("assets/textures/buckler.png"); + + launcher.manager.beginRegister(); + + launcher.manager.registerComponent!CLocation; + launcher.manager.registerComponent!CTexture; + launcher.manager.registerComponent!CInput; + launcher.manager.registerComponent!CShip; + launcher.manager.registerComponent!CEnemy; + launcher.manager.registerComponent!CScale; + launcher.manager.registerComponent!CShootDirection; + launcher.manager.registerComponent!CAutoShoot; + launcher.manager.registerComponent!CLaserWeapon; + launcher.manager.registerComponent!CVelocity; + launcher.manager.registerComponent!CLaser; + launcher.manager.registerComponent!CSideMove; + + launcher.manager.registerEvent!EChangeDirection; + + //launcher.manager.registerSystem!MoveSystem(0); + launcher.manager.registerSystem!DrawSystem(100); + launcher.manager.registerSystem!InputMovementSystem(-100); + launcher.manager.registerSystem!LaserShootingSystem(0); + launcher.manager.registerSystem!MovementSystem(0); + launcher.manager.registerSystem!ClampPositionSystem(1); + launcher.manager.registerSystem!ChangeDirectionSystem(0); + + launcher.manager.endRegister(); + + launcher.gui_manager.addSystem(DrawSystem.system_id,"Draw System"); + launcher.gui_manager.addSystem(InputMovementSystem.system_id,"Input Movement"); + launcher.gui_manager.addSystem(LaserShootingSystem.system_id,"Laser Shooting"); + launcher.gui_manager.addSystem(MovementSystem.system_id,"Movement System"); + launcher.gui_manager.addSystem(ClampPositionSystem.system_id,"Clamp Position System"); + launcher.gui_manager.addSystem(ChangeDirectionSystem.system_id,"Change Direction System"); + + //launcher.manager.getSystem(CleanSystem.system_id).disable(); + { + ushort[7] components = [CLocation.component_id, CTexture.component_id, CInput.component_id, CShip.component_id, CScale.component_id, CLaserWeapon.component_id, CShootDirection.component_id]; + space_invaders.ship_tmpl = launcher.manager.allocateTemplate(components); + + CTexture* tex_comp = space_invaders.ship_tmpl.getComponent!CTexture; + tex_comp.tex = space_invaders.ship_tex; + CLocation* loc_comp = space_invaders.ship_tmpl.getComponent!CLocation; + loc_comp.value = vec2(64,64); + CLaserWeapon* weapon = space_invaders.ship_tmpl.getComponent!CLaserWeapon; + weapon.level = 10; + + launcher.manager.addEntity(space_invaders.ship_tmpl); + } + + { + ushort[5] components = [CLocation.component_id, CTexture.component_id, CVelocity.component_id, CScale.component_id, CLaser.component_id]; + space_invaders.laser_tmpl = launcher.manager.allocateTemplate(components); + + CTexture* tex_comp = space_invaders.laser_tmpl.getComponent!CTexture; + tex_comp.tex = space_invaders.laser_tex; + CScale* scale_comp = space_invaders.laser_tmpl.getComponent!CScale; + scale_comp.value = vec2(4,16); + CVelocity* vel_comp = space_invaders.laser_tmpl.getComponent!CVelocity; + vel_comp.value = vec2(0,1); + } + + { + ushort[8] components = [CVelocity.component_id, CAutoShoot.component_id, CLocation.component_id, CTexture.component_id, CScale.component_id, CLaserWeapon.component_id, CEnemy.component_id, CShootDirection.component_id];//, CVelocity.component_id]; + space_invaders.enemy_tmpl = launcher.manager.allocateTemplate(components); + + CTexture* tex_comp = space_invaders.enemy_tmpl.getComponent!CTexture; + tex_comp.tex = space_invaders.ship_tex; + CLocation* loc_comp = space_invaders.enemy_tmpl.getComponent!CLocation; + loc_comp.value = vec2(64,space_invaders.map_size.y - 64); + CShootDirection* shoot_dir_comp = space_invaders.enemy_tmpl.getComponent!CShootDirection; + shoot_dir_comp.direction = Direction.down; + CVelocity* vel_comp = space_invaders.enemy_tmpl.getComponent!CVelocity; + vel_comp.value = vec2(0.1,0); + + Entity* current_entity; + + current_entity = launcher.manager.addEntity(space_invaders.enemy_tmpl); + launcher.manager.addComponents(current_entity.id,CSideMove(0)); + + loc_comp.value = vec2(128,space_invaders.map_size.y - 64); + current_entity = launcher.manager.addEntity(space_invaders.enemy_tmpl); + launcher.manager.addComponents(current_entity.id,CSideMove(-1)); + + loc_comp.value = vec2(256,space_invaders.map_size.y - 64); + launcher.manager.addEntity(space_invaders.enemy_tmpl); + + loc_comp.value = vec2(0,space_invaders.map_size.y - 64); + current_entity = launcher.manager.addEntity(space_invaders.enemy_tmpl); + launcher.manager.addComponents(current_entity.id,CSideMove(0)); + } + +} + +void spaceInvadersEnd() +{ + + launcher.manager.getSystem(DrawSystem.system_id).disable(); + launcher.manager.getSystem(InputMovementSystem.system_id).disable(); + launcher.manager.getSystem(LaserShootingSystem.system_id).disable(); + launcher.manager.getSystem(MovementSystem.system_id).disable(); + launcher.manager.getSystem(ClampPositionSystem.system_id).disable(); + + space_invaders.ship_tex.destroy(); + + launcher.manager.freeTemplate(space_invaders.ship_tmpl); + Mallocator.dispose(space_invaders); +} + +void spaceInvadersEvent(SDL_Event* event) +{ + +} + +bool spaceInvadersLoop() +{ + + /*if(launcher.show_demo_wnd) + { + igSetNextWindowPos(ImVec2(800 - 260, 30), ImGuiCond_Once, ImVec2(0,0)); + igSetNextWindowSize(ImVec2(250, 0), ImGuiCond_Once); + if(igBegin("Simple",&launcher.show_demo_wnd,0)) + { + if(igCheckbox("Move system",&simple.move_system)) + { + if(simple.move_system)launcher.manager.getSystem(MoveSystem.system_id).enable(); + else launcher.manager.getSystem(MoveSystem.system_id).disable(); + } + if(igCheckbox("Draw system",&simple.draw_system)) + { + if(simple.draw_system)launcher.manager.getSystem(DrawSystem.system_id).enable(); + else launcher.manager.getSystem(DrawSystem.system_id).disable(); + } + igPushButtonRepeat(true); + igColumns(3,null,0); + if(igButton("Spawn",ImVec2(-1,0))) + { + spawnEntity(); + } + igNextColumn(); + if(igButton("+10",ImVec2(-1,0))) + { + foreach(i;0..10)spawnEntity(); + } + igNextColumn(); + if(igButton("+100",ImVec2(-1,0))) + { + foreach(i;0..100)spawnEntity(); + } + igPopButtonRepeat(); + igColumns(1,null,0); + if(igButton("Clear",ImVec2(-1,0))) + { + launcher.manager.getSystem(CleanSystem.system_id).enable(); + launcher.manager.begin(); + launcher.manager.update(); + launcher.manager.end(); + launcher.manager.getSystem(CleanSystem.system_id).disable(); + } + } + igEnd(); + }*/ + + /*if(launcher.show_tips) + { + igSetNextWindowPos(ImVec2(800 - 550, 80), ImGuiCond_Once, ImVec2(0,0)); + igSetNextWindowSize(ImVec2(300, 0), ImGuiCond_Once); + if(igBegin("Tips",&launcher.show_tips,ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoSavedSettings)) + { + igTextWrapped("Use \"space\" to spwan entities.\n\nSystems can be enabled/disabled from \"Simple\" window."); + } + igEnd(); + }*/ + + launcher.manager.begin(); + if(launcher.multithreading) + { + launcher.job_updater.begin(); + launcher.manager.updateMT(); + launcher.job_updater.call(); + launcher.multithreading = false; + printf("Disable mt\n"); + } + else + { + launcher.manager.update(); + } + launcher.manager.end(); + + /*foreach(i;0..1000)//13000) + { + launcher.renderer.draw(simple.texture,vec2(i%100*32,i/100*32),vec2(32,32),vec4(0,0,1,1),0.0); + }*/ + + return true; +} \ No newline at end of file diff --git a/demos/source/game_core/job_updater.d b/demos/source/game_core/job_updater.d new file mode 100644 index 0000000..26cd8e3 --- /dev/null +++ b/demos/source/game_core/job_updater.d @@ -0,0 +1,199 @@ +module game_core.job_updater; + +import ecs.std; +import ecs.vector; + +import ecs_utils.utils; + +//import core.time; +import ecs.manager; +import mmutils.thread_pool; + +//import supre.core.call_graph_generator; + +struct ECSJobUpdater +{ + + this(uint threads) + { + onCreate(threads); + } + + ~this() + { + pool.waitThreads(); + //pool.unregistExternalThread(thread_data); + if(jobs)Mallocator.dispose(jobs); + } + + ThreadPool pool; + ThreadData* thread_data; + + int job_id = 0; + int no_dep_count = 0; + static uint thread_id = 0; + + struct Group + { + ~this() nothrow + { + + } + + JobsGroup group; + JobData[1024] jobs; + JobCaller[1024] callers; + uint count = 0; + + void dependantOn(Group* dependency) + { + group.dependantOn(&dependency.group); + } + + void start() + { + group.thPool.addGroupAsynchronous(&group); + } + + void build(ThreadPool* pool) + { + group.thPool = pool; + group.jobs = jobs[0..count]; + } + + void clear() + { + group = JobsGroup("name",null); + count = 0; + } + + void add(JobCaller caller) + { + callers[count] = caller; + jobs[count] = JobData(&callers[count].callJob,"hmm"); + count++; + } + } + + Group[] jobs; + Vector!(Group*) call_jobs; + Group last_job; + + //TrackData[32] trackers; + + void onCreate(uint threads_count) + { + pool.initialize(); + //thread_data = pool.registerExternalThread(); + pool.setThreadsNum(threads_count); + + jobs = Mallocator.makeArray!Group(256); + } + + uint getThreadID() nothrow + { + return thread_id; + } + + void begin() + { + job_id = 0; + call_jobs.clear(); + + foreach(ref job;jobs) + { + job.clear(); + } + + last_job.clear(); + } + + void clearTracker() + { + //foreach(ref tracker;trackers)tracker.clear(); + } + + void call() + { + if(last_job.group.getDependenciesWaitCount() == 0)return; + if(call_jobs.length == 0)return; + + JobData[1] groupEndJobs; + groupEndJobs[0] = JobData(&releaseMainThread, "Stop Threads"); + + last_job.group.jobs = groupEndJobs; + last_job.group.executeOnThreadNum = 0; + + foreach(job;call_jobs) + { + job.start(); + } + ret = false; + while(!ret) + { + printf("SDL\n"); + } + printf("NonSDL\n"); + //thread_data.threadStartFunc(); + + int i = 10; + } +shared bool ret = false; + void releaseMainThread(ThreadData* th_data, JobData* data) + { + //pool.releaseExternalThreads(); + ret = true; + } + + static struct JobCaller + { + EntityManager.Job* job; + ECSJobUpdater* updater; + uint id; + + void callJob(ThreadData* th_data, JobData* data) + { + updater.thread_id = th_data.threadId; + uint job_id = updater.getThreadID(); + //updater.trackers[job_id].begin(id); + job.execute(); + //updater.trackers[job_id].end(); + } + } + + void dispatch(EntityManager.JobGroup group) + { + if(group.jobs.length == 0) + { + return; + } + + foreach(ref job;group.jobs) + { + uint index = 0; + if(job.callers.length)index = job.callers[0].system_id; + JobCaller caller; + caller.updater = &this; + caller.job = &job; + caller.id = index; + jobs[group.id].add(caller); + } + + jobs[group.id].build(&pool); + + uint deps = cast(uint)group.dependencies.length; + + foreach(dep;group.dependencies) + { + if(jobs[dep.id].count && dep.caller.system.execute && dep.caller.system.enabled)jobs[group.id].dependantOn(&jobs[dep.id]); + else deps--; + } + + if(deps == 0) + { + call_jobs.add(&jobs[group.id]); + } + + last_job.dependantOn(&jobs[group.id]); + } +} \ No newline at end of file diff --git a/demos/source/gui/component.d b/demos/source/gui/component.d new file mode 100644 index 0000000..bbd7ec5 --- /dev/null +++ b/demos/source/gui/component.d @@ -0,0 +1,6 @@ +module gui.components; + +struct ComponentGUI +{ + +} \ No newline at end of file diff --git a/demos/source/gui/manager.d b/demos/source/gui/manager.d new file mode 100644 index 0000000..10727eb --- /dev/null +++ b/demos/source/gui/manager.d @@ -0,0 +1,49 @@ +module gui.manager; + +import app; + +import cimgui.cimgui; + +import ecs.std; +import ecs.system; +import ecs.vector; + +import gui.system; + +extern(C): + +struct GUIManager +{ + Vector!SystemGUI systems; + + void clear() + { + systems.clear(); + } + + void addSystem(ushort id, const (char)* name, bool enabled = true) + { + System* system = launcher.manager.getSystem(id); + //const (char)* name = + systems.add(SystemGUI(name,system,enabled)); + } + + void gui() + { + if(igCollapsingHeader("Systems", ImGuiTreeNodeFlags_Framed)) + { + bool true_ = true; + igIndent(8); + foreach(ref SystemGUI system;systems) + { + if(igCheckbox(system.name,&system.enabled)) + { + if(system.enabled)system.system.enable(); + else system.system.disable(); + } + } + igUnindent(8); + } + + } +} \ No newline at end of file diff --git a/demos/source/gui/system.d b/demos/source/gui/system.d new file mode 100644 index 0000000..bbee409 --- /dev/null +++ b/demos/source/gui/system.d @@ -0,0 +1,11 @@ +module gui.system; + +import ecs.system; + +struct SystemGUI +{ + const (char)* name; + System* system; + + bool enabled = true; +} \ No newline at end of file diff --git a/demos/utils/dub.json b/demos/utils/dub.json index 2f7d1bb..d8ecfb1 100644 --- a/demos/utils/dub.json +++ b/demos/utils/dub.json @@ -12,7 +12,6 @@ ], "importPaths": [ "source", - "../external/imports", "../external/sources" ], "dependencies": { diff --git a/demos/utils/source/ecs_utils/gfx/renderer.d b/demos/utils/source/ecs_utils/gfx/renderer.d index 5b151bc..e064c9e 100644 --- a/demos/utils/source/ecs_utils/gfx/renderer.d +++ b/demos/utils/source/ecs_utils/gfx/renderer.d @@ -799,10 +799,10 @@ struct Renderer sdl_transform = vec4(0,0,1.0/size.x,1.0/size.y); } - static void function(ref Renderer this_, Texture tex, vec2 pos, vec2 size, vec4 coords, float angle, uint material_id, uint mesh_id) __draw; - static void function(ref Renderer this_) __present; - static void function(ref Renderer this_) __clear; - static void function(ref Renderer this_) __initialize; + __gshared void function(ref Renderer this_, Texture tex, vec2 pos, vec2 size, vec4 coords, float angle, uint material_id, uint mesh_id) __draw; + __gshared void function(ref Renderer this_) __present; + __gshared void function(ref Renderer this_) __clear; + __gshared void function(ref Renderer this_) __initialize; static void __loadBackend() { diff --git a/source/ecs/vector.d b/source/ecs/vector.d index fa616ed..84ecc51 100644 --- a/source/ecs/vector.d +++ b/source/ecs/vector.d @@ -29,7 +29,7 @@ public: } - static if (isCopyable!T) { + /*static if (isCopyable!T) { export this(this) { T[] tmp = array[0 .. used]; array = null; @@ -38,9 +38,9 @@ public: } } else { @disable this(this); - } + }*/ - //@disable this(this); + @disable this(this); export ~this() { clear();