1 module app;
2 
3 import bindbc.sdl;
4 
5 import cimgui.cimgui;
6 
7 import game_core.basic;
8 import game_core.job_updater;
9 
10 import bubel.ecs.core;
11 import bubel.ecs.manager;
12 import bubel.ecs.std;
13 
14 import ecs_utils.gfx.renderer;
15 import ecs_utils.imgui_bind;
16 import ecs_utils.imgui_styles;
17 import ecs_utils.math.vector;
18 import ecs_utils.utils;
19 
20 import glad.gl.gl;
21 import glad.gl.gles2;
22 import glad.gl.loader;
23 
24 import gui.manager;
25 import gui.tool_circle;
26 
27 extern (C) :
28 
29 enum Tool
30 {
31     entity_spawner,
32     component_manipulator,
33     selector
34 }
35 
36 __gshared const (char)*[3] tool_strings = ["Entity spawner", "Component manipulator", "Selector"];
37 
38 struct Mouse
39 {
40     vec2 position;
41     bool left, right, middle;
42 }
43 
44 struct DemoCallbacks
45 {
46     void function() register;
47     void function() initialize;
48     void function() deinitialize;
49     bool function() loop;
50     void function(SDL_Event*) event;
51     const (char)* tips;
52 }
53 
54 struct Launcher 
55 {
56     ECSJobUpdater* job_updater;
57     GUIManager* gui_manager;
58     ImGuiContext* context;
59     SDL_Window* window;
60     SDL_GLContext gl_context;
61     /*bool function() loop;
62     void function() end;
63     void function(SDL_Event*) event;*/
64     //void function(vec2, Tool, int, bool) tool;
65     float scalling;
66     ivec2 window_size = ivec2(1024,768);
67     Renderer renderer;
68     ubyte[] keys;
69     uint style = 3;
70     uint entities_count;
71     bool multithreading;
72     int threads = 1;
73     ulong timer_freq;
74     double delta_time;
75     uint fps;
76     vec2 render_position;
77     bool play = true;
78 
79     Tool used_tool;
80     int tool_size = 100;
81     float tool_repeat = 0;
82     float repeat_time = 0;
83     bool tool_show = true;
84     bool override_ = true;
85     bool tool_mode = true;
86     ToolCircle* tool_circle;
87     bool show_filtered;
88     EntityID selected_entity;
89 
90     bool swap_interval = true;
91 
92     float windows_alpha = 0.75;
93 
94     //const (char)* tips;
95 
96     bool show_stat_wnd = true;
97     bool show_tips = true;
98     bool show_demo_wnd = true;
99     bool show_tools_wnd = true;
100     bool show_virtual_keys_wnd = false;
101     bool show_profile_wnd = true;
102 
103     int plot_index;
104     PlotStruct[] plot_values;
105 
106     Mouse mouse;
107 
108     struct PlotStruct
109     {
110         float delta_time = 0;
111         float loop_time = 0;
112         float draw_time = 0;
113     }
114 
115     double deltaTime()
116     {
117         return delta_time * play;
118     }
119 
120     DemoCallbacks demo;
121 
122     void switchDemo(DemoCallbacks callbacks)//void function() start, bool function() loop, void function() end, void function(SDL_Event*) event, const (char)* tips)
123     {
124         show_tips = true;
125         gui_manager.clear();
126         //launcher.ent
127 
128         gEntityManager.begin();
129         gEntityManager.update("clean");
130         gEntityManager.end();
131 
132         if(this.demo.deinitialize)this.demo.deinitialize();
133 
134         foreach(ref system; gEntityManager.systems)
135         {
136             if(system.id != becsID!CountSystem && system.id != becsID!CleanSystem)system.disable();
137         }
138 
139         /*gEntityManager.getSystem(becsID!CountSystem).enable();
140         gEntityManager.getSystem(becsID!CleanSystem).enable();//*/
141 
142         if(callbacks.register)callbacks.register();
143         if(callbacks.initialize)callbacks.initialize();
144         demo = callbacks;
145         /*this.loop = loop;
146         this.end = end;
147         this.event = event;
148         this.tips = tips;*/
149         //this.tool = tool;
150     }
151 
152     bool filterEntity(ref const Entity entity)
153     {
154         EntityMeta meta = entity.getMeta();
155         foreach(id;gui_manager.filter_list)
156         {
157             if(!meta.hasComponent(id))return false;
158         }
159         if(used_tool == Tool.component_manipulator)
160         {
161             if(!meta.hasComponent(gui_manager.getSelectedComponent().component_id))return false;
162         }
163         return true;
164     }
165 
166     void processTool(vec2 position, bool mode)
167     {
168         static struct Iterator 
169         {
170             float size2;
171             vec2 position;
172             ComponentRef[] add_comps;
173             ushort[] rem_comps;
174             ushort[] filter;
175             float distance = float.max;
176 
177             bool filterEntity(ref const Entity entity)
178             {
179                 EntityMeta meta = entity.getMeta();
180                 foreach(id;filter)
181                 {
182                     if(!meta.hasComponent(id))return false;
183                 }
184                 return true;
185             }
186 
187             void removeEntity(IteratorSystem.EntitiesData data)
188             {
189                 if(!filterEntity(data.entity[0]))return;
190                 foreach(i;0..data.length)
191                 {
192                     vec2 rel_vec = data.location[i] - position;
193                     float length = rel_vec.x * rel_vec.x + rel_vec.y * rel_vec.y;
194                     if(length < size2)gEntityManager.removeEntity(data.entity[i].id);
195                 }
196             }
197 
198             void addComponent(IteratorSystem.EntitiesData data)
199             {
200                 if(!filterEntity(data.entity[0]))return;
201                 foreach(i;0..data.length)
202                 {
203                     vec2 rel_vec = data.location[i] - position;
204                     float length = rel_vec.x * rel_vec.x + rel_vec.y * rel_vec.y;
205                     if(length < size2)gEntityManager.addComponents(data.entity[i].id, add_comps);
206                 }
207             }
208 
209             void overrideComponent(IteratorSystem.EntitiesData data)
210             {
211                 if(!filterEntity(data.entity[0]))return;
212                 foreach(i;0..data.length)
213                 {
214                     vec2 rel_vec = data.location[i] - position;
215                     float length = rel_vec.x * rel_vec.x + rel_vec.y * rel_vec.y;
216                     if(length < size2)
217                     {
218                         gEntityManager.removeComponents(data.entity[i].id, rem_comps);
219                         gEntityManager.addComponents(data.entity[i].id, add_comps);
220                     }
221                 }
222             }
223 
224             void removeComponent(IteratorSystem.EntitiesData data)
225             {
226                 if(!filterEntity(data.entity[0]))return;
227                 foreach(i;0..data.length)
228                 {
229                     vec2 rel_vec = data.location[i] - position;
230                     float length = rel_vec.x * rel_vec.x + rel_vec.y * rel_vec.y;
231                     if(length < size2)gEntityManager.removeComponents(data.entity[i].id, rem_comps);
232                 }
233             }
234 
235             void selectEntity(IteratorSystem.EntitiesData data)
236             {
237                 if(!filterEntity(data.entity[0]))return;
238                 foreach(i;0..data.length)
239                 {
240                     vec2 rel_vec = data.location[i] - position;
241                     float length = rel_vec.x * rel_vec.x + rel_vec.y * rel_vec.y;
242                     if(length < distance)
243                     {
244                         distance = length;
245                         launcher.selected_entity = data.entity[i].id;
246                     }
247                 }
248             }
249         }
250 
251         float half_size = tool_size * 0.5;
252         float size2 = half_size * half_size;
253         Iterator iterator;
254         iterator.size2 = size2;
255         iterator.position = position;
256         iterator.filter = gui_manager.filter_list[];
257 
258         switch(used_tool)
259         {
260             case Tool.entity_spawner:
261                 if(mode)
262                 {
263                     if(gui_manager.templates.length == 0)return;
264                     EntityTemplate* tmpl = gui_manager.getSelectedTemplate();
265                     CLocation* location = tmpl.getComponent!CLocation;
266                     if(location)
267                     {
268                         position += randomCircularSample() * half_size;
269                         //if(position.y < 16)position.y = 16;
270                         //else if(position.y > 299)position.y = 299;
271                         *location = position;
272                     }
273                     gEntityManager.addEntity(tmpl);
274                 }
275                 else
276                 {
277                     gEntityManager.callEntitiesFunction!IteratorSystem(&iterator.removeEntity);
278                 }
279                 break;
280             case Tool.component_manipulator:
281                 {
282                     if(gui_manager.components.length == 0)return;
283                     if(mode)
284                     {
285                         ComponentRef[1] comps = [gui_manager.getSelectedComponent()];
286                         iterator.add_comps = comps;
287                         if(launcher.override_)
288                         {
289                             ushort[1] rcomps = [gui_manager.getSelectedComponent().component_id];
290                             iterator.rem_comps = rcomps;
291                             gEntityManager.callEntitiesFunction!IteratorSystem(&iterator.overrideComponent);
292                         }
293                         else gEntityManager.callEntitiesFunction!IteratorSystem(&iterator.addComponent);
294                     }
295                     else 
296                     {
297                         ushort[1] comps = [gui_manager.getSelectedComponent().component_id];
298                         iterator.rem_comps = comps;
299                         gEntityManager.callEntitiesFunction!IteratorSystem(&iterator.removeComponent);
300                     }
301                 }
302                 break;
303             case Tool.selector:
304                 iterator.distance = size2;
305                 gEntityManager.callEntitiesFunction!IteratorSystem(&iterator.selectEntity);
306                 break;
307             default:
308                 break;
309         }
310     }
311 
312     bool getKeyState(SDL_Scancode key)
313     {
314         if(keys[key])return true;
315         else return false;
316     }
317 
318     void setStyle(uint index)
319     {
320         style = index;
321         .setStyle(index);
322     }
323 
324     double getTime()
325     {
326         ulong local_freq = timer_freq / 1000_000;
327         //return cast(double)(SDL_GetPerformanceCounter() & 0x00FFFFFF) / timer_freq;
328         if(local_freq == 0)return cast(double)(SDL_GetPerformanceCounter() / timer_freq * 1000);
329         else return cast(double)(SDL_GetPerformanceCounter() / local_freq) / 1000;
330     }
331 }
332 
333 __gshared Launcher launcher;
334 
335 struct CountSystem
336 {
337     mixin ECS.System!1;
338 
339     struct EntitiesData
340     {
341         uint length;
342         const (Entity)[] entity;
343     }
344 
345     bool onBegin()
346     {
347         launcher.entities_count = 0;
348         return true;
349     }
350 
351     void onUpdate(EntitiesData data)
352     {
353         launcher.entities_count += data.length;
354     }
355 }
356 
357 struct CleanSystem
358 {
359     mixin ECS.System!64;
360 
361     struct EntitiesData
362     {
363         uint length;
364         Entity[] entities;
365     }
366 
367     void onUpdate(EntitiesData data)
368     {
369         foreach(i; 0..data.length)
370         {
371             gEntityManager.removeEntity(data.entities[i].id);
372         }
373     }
374 }
375 
376 struct IteratorSystem
377 {
378     mixin ECS.System!1;
379 
380     struct EntitiesData
381     {
382         uint length;
383         const (Entity)[] entity;
384         CLocation[] location;
385     }
386 
387     bool onBegin()
388     {
389         return false;
390     }
391 
392     void onUpdate(EntitiesData)
393     {
394 
395     }
396 }
397 
398 void mainLoop(void* arg)
399 {
400     __gshared double time = 0;
401     launcher.delta_time = launcher.getTime() - time;
402     time = launcher.getTime();
403 
404     if(launcher.delta_time > 1000)launcher.delta_time = 1000;
405 
406     __gshared uint temp_fps = 0;
407     __gshared double fps_time = 0;
408     temp_fps++;
409     fps_time += launcher.delta_time;
410     while(fps_time > 1000)
411     {
412         fps_time -= 1000;
413         launcher.fps = temp_fps;
414         temp_fps = 0;
415     }
416 
417     SDL_Event event;
418     while (SDL_PollEvent(&event)) 
419     {
420         ImGui_ImplSDL2_ProcessEvent(&event);
421         if(launcher.demo.event)launcher.demo.event(&event);
422         if (event.type == SDL_QUIT || (event.type == SDL_KEYDOWN && event.key.keysym.scancode == SDL_SCANCODE_ESCAPE)) {
423             quit();
424             *cast(bool*)arg = false;
425             return;
426         }
427         else if(event.type == SDL_KEYDOWN)
428         {
429             if(event.key.state)
430             {
431                 if(SDL_GetModState() & KMOD_CTRL)
432                 {
433                     switch(event.key.keysym.scancode)
434                     {
435                         case SDL_SCANCODE_1:launcher.used_tool=Tool.entity_spawner;break;
436                         case SDL_SCANCODE_2:launcher.used_tool=Tool.component_manipulator;break;
437                         case SDL_SCANCODE_3:launcher.used_tool=Tool.selector;break;
438                         default:break;
439                     }
440                 }
441                 else
442                 {
443                     switch(event.key.keysym.scancode)
444                     {
445                         case SDL_SCANCODE_1:break;
446                         case SDL_SCANCODE_2:break;
447                         case SDL_SCANCODE_3:break;
448                         case SDL_SCANCODE_4:break;
449                         default:break;
450                     }
451                 }
452             }
453         }
454         else if(event.type == SDL_WINDOWEVENT)
455         {
456             switch(event.window.event)
457             {
458                 case SDL_WINDOWEVENT_RESIZED:
459                     //launcher.renderer.resize(ivec2(event.window.data1,event.window.data2));
460                     launcher.window_size = ivec2(event.window.data1,event.window.data2);
461                     break;
462                 case SDL_WINDOWEVENT_SIZE_CHANGED:
463                     //launcher.renderer.resize(ivec2(event.window.data1,event.window.data2));
464                     launcher.window_size = ivec2(event.window.data1,event.window.data2);
465                     break;
466                 default:break;
467             }
468         }
469         else if(event.type == SDL_MOUSEBUTTONDOWN)
470         {
471             switch(event.button.button)
472             {
473                 case SDL_BUTTON_LEFT:launcher.mouse.left = true;break;
474                 case SDL_BUTTON_RIGHT:launcher.mouse.right = true;break;
475                 case SDL_BUTTON_MIDDLE:launcher.mouse.middle = true;break;
476                 default:break;
477             }
478             if(!igIsAnyItemHovered())igSetWindowFocus();
479             if(!igIsWindowHovered(ImGuiHoveredFlags_AnyWindow) && !igIsWindowFocused(ImGuiFocusedFlags_AnyWindow))
480             {
481                 launcher.repeat_time = 0;
482                 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);
483                 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);
484             }
485         }
486         else if(event.type == SDL_MOUSEBUTTONUP)
487         {
488             switch(event.button.button)
489             {
490                 case SDL_BUTTON_LEFT:launcher.mouse.left = false;break;
491                 case SDL_BUTTON_RIGHT:launcher.mouse.right = false;break;
492                 case SDL_BUTTON_MIDDLE:launcher.mouse.middle = false;break;
493                 default:break;
494             }
495         }
496         else if(event.type == SDL_MOUSEMOTION)
497         {
498             launcher.mouse.position = vec2(event.motion.x, launcher.window_size.y - event.motion.y);
499         }else if(event.type == SDL_MOUSEWHEEL)
500         {
501             if(!igIsAnyItemHovered() && !igIsWindowHovered(ImGuiHoveredFlags_AnyWindow))
502             {
503                 if(SDL_GetModState() & KMOD_CTRL)
504                 {
505                     float sign = 1;
506                     if(event.wheel.y < 0)sign = -1;
507                     float val = /*sign * event.wheel.y */ launcher.tool_repeat * 0.25;
508                     if(val < 0.1)val = 0.1;
509                     launcher.tool_repeat -= sign * val;
510                     if(launcher.tool_repeat < 0)launcher.tool_repeat = 0;
511                     else if(launcher.tool_repeat > 1000)launcher.tool_repeat = 1000;
512                 }
513                 else if(SDL_GetModState() & KMOD_SHIFT)
514                 {
515                     int sign = 1;
516                     if(event.wheel.y < 0)sign = -1;
517                     switch(launcher.used_tool)
518                     {
519                         case Tool.entity_spawner:
520                             launcher.gui_manager.selectTemplate(launcher.gui_manager.selected_template-sign);
521                             break;
522                         case Tool.component_manipulator:
523                             launcher.gui_manager.selectComponent(launcher.gui_manager.selected_component-sign);
524                             break;
525                         default:break;
526                     }
527                 }
528                 else 
529                 {
530                     int sign = 1;
531                     if(event.wheel.y < 0)sign = -1;
532                     int val = /*sign * event.wheel.y */ launcher.tool_size / 4;
533                     if(val < 1)val = 1;
534                     launcher.tool_size -= sign * val;
535                     if(launcher.tool_size < 1)launcher.tool_size = 1;
536                     else if(launcher.tool_size > 256)launcher.tool_size = 256;
537                 }
538             }
539         }
540     }
541 
542     if(launcher.tool_repeat != 0 && (launcher.mouse.left || launcher.mouse.right) && !igIsWindowHovered(ImGuiHoveredFlags_AnyWindow) && !igIsWindowFocused(ImGuiFocusedFlags_AnyWindow))
543     {
544         bool mode = launcher.tool_mode;
545         if(launcher.mouse.right)mode = !mode;
546         float range = 500.0 / cast(float)launcher.tool_repeat;
547         launcher.repeat_time += launcher.delta_time;
548         if(launcher.used_tool != Tool.entity_spawner || !mode)
549         {
550             if(launcher.repeat_time > range)launcher.processTool((launcher.mouse.position*launcher.scalling)-launcher.render_position, mode);
551             while(launcher.repeat_time > range)launcher.repeat_time -= range;
552         }
553         else
554         {
555             while(launcher.repeat_time > range)
556             {
557                 launcher.repeat_time -= range;
558                 launcher.processTool((launcher.mouse.position*launcher.scalling)-launcher.render_position, mode);
559             }
560         }
561     }
562 
563     version(WebAssembly)
564     {
565         ImGui_ImplOpenGL3_NewFrame();
566         ImGui_ImplSDL2_NewFrame(launcher.window);
567     }
568     else
569     {
570         //ImGuiImplOpenGL2NewFrame();
571         ImGui_ImplOpenGL3_NewFrame();
572         ImGuiImplSDL2NewFrame(launcher.window);
573     }
574 
575     igNewFrame();
576 
577     if(igBeginMainMenuBar())
578     {
579         if(igBeginMenu("File",true))
580         {
581             if(igMenuItemBool("Close","esc",false,true))
582             {
583                 quit();
584                 *cast(bool*)arg = false;
585                 return;
586             }
587             igEndMenu();
588         }
589         if(igBeginMenu("Demos",true))
590         {
591             if(igMenuItemBool("Simpe",null,false,true))
592             {
593                 import demos.simple;
594                 launcher.switchDemo(getSimpleDemo());//&simpleStart,&simpleLoop,&simpleEnd,&simpleEvent,Simple.tips);
595             }
596             if(igMenuItemBool("Snake",null,false,true))
597             {
598                 import demos.snake;
599                 launcher.switchDemo(getSnakeDemo());//&snakeStart,&snakeLoop,&snakeEnd,&snakeEvent,Snake.tips);
600             } 
601             if(igMenuItemBool("Space Invaders",null,false,true))
602             {
603                 import demos.space_invaders;
604                 launcher.switchDemo(getSpaceInvadersDemo());//&spaceInvadersStart,&spaceInvadersLoop,&spaceInvadersEnd,&spaceInvadersEvent,SpaceInvaders.tips);
605             }
606             if(igMenuItemBool("Particles",null,false,true))
607             {
608                 import demos.particles;
609                 launcher.switchDemo(getParticlesDemo());//&particlesStart,&particlesLoop,&particlesEnd,&particlesEvent,ParticlesDemo.tips);
610             }
611             if(igMenuItemBool("Brick Breaker",null,false,true))
612             {
613                 import demos.brick_breaker;
614                 launcher.switchDemo(getBrickBreakerDemo());//&particlesStart,&particlesLoop,&particlesEnd,&particlesEvent,ParticlesDemo.tips);
615             }
616             if(igMenuItemBool("Sandbox",null,false,true))
617             {
618                 import demos.sandbox;
619                 launcher.switchDemo(getSanboxDemo());//&particlesStart,&particlesLoop,&particlesEnd,&particlesEvent,ParticlesDemo.tips);
620             }
621             igEndMenu();
622         }
623         if(igBeginMenu("Options",true))
624         {
625             if(igMenuItemBool("VSync", null, launcher.swap_interval, true))
626             {
627                 launcher.swap_interval = !launcher.swap_interval;
628                 SDL_GL_SetSwapInterval(launcher.swap_interval);
629             }
630             if(igMenuItemBool("Multithreading", null, launcher.multithreading, true))
631             {
632                 launcher.multithreading = !launcher.multithreading;
633                 if(launcher.multithreading)
634                 {
635                     launcher.job_updater.pool.setThreadsNum(launcher.threads);
636                 }
637                 else
638                 {
639                     launcher.job_updater.pool.setThreadsNum(1);
640                 }
641             }
642             igSetNextItemWidth(0);
643             igLabelText("Threads:",null);
644             igSameLine(0,4);
645             if(igSliderInt("##Threads",&launcher.threads, 1, 32, null))//"Multithreading", null, launcher.multithreading, true))
646             {
647                 launcher.job_updater.pool.setThreadsNum(launcher.threads);
648                 //launcher.threads = !launcher.multithreading;
649             }
650             if(igBeginMenu("Show",true))
651             {
652                 igMenuItemBoolPtr("Statistics",null,&launcher.show_stat_wnd,true);
653                 igMenuItemBoolPtr("Demo",null,&launcher.show_demo_wnd,true);
654                 igMenuItemBoolPtr("Tips",null,&launcher.show_tips,true);
655                 igMenuItemBoolPtr("Virual keys",null,&launcher.show_virtual_keys_wnd,true);
656                 igMenuItemBoolPtr("Profile",null,&launcher.show_profile_wnd,true);
657                 igEndMenu();
658             }
659             if(igBeginMenu("Style",true))
660             {
661                 if(igMenuItemBool("Classic",null,launcher.style == 0,true))
662                 {
663                     launcher.setStyle(0);
664                 }
665                 else if(igMenuItemBool("Dark",null,launcher.style == 1,true))
666                 {
667                     launcher.setStyle(1);
668                 }
669                 else if(igMenuItemBool("Light",null,launcher.style == 2,true))
670                 {
671                     launcher.setStyle(2);
672                 }
673                 else if(igMenuItemBool("Default",null,launcher.style == 3,true))
674                 {
675                     launcher.setStyle(3);
676                 }
677                 igEndMenu();
678             }
679             igEndMenu();
680         }
681         igEndMainMenuBar();
682     }
683 
684     if(launcher.show_virtual_keys_wnd)
685     {
686         igSetNextWindowPos(ImVec2(launcher.window_size.x - 400, launcher.window_size.y - 200), ImGuiCond_Once, ImVec2(0,0));
687         igSetNextWindowSize(ImVec2(64*4+128, 168), ImGuiCond_Once);
688         igSetNextWindowBgAlpha(launcher.windows_alpha);
689         ImGuiStyle * style = igGetStyle();
690         style.Colors[ImGuiCol_Button].w = 0.8;
691         if(igBegin("Virtual keys",&launcher.show_virtual_keys_wnd, 0))
692         {
693             igColumns(2,null,0);
694             igSetColumnWidth(0,64*3+16);
695             igIndent(64+4);
696             if(igButton("W",ImVec2(64,64)) || igIsItemDeactivated())
697             {
698                 launcher.keys[SDL_SCANCODE_W] = false;
699             }
700             else if(igIsItemActive())
701             {
702                 launcher.keys[SDL_SCANCODE_W] = true;
703             }
704             igUnindent(64+4);
705             if(igButton("A",ImVec2(64,64)) || igIsItemDeactivated())
706             {
707                 launcher.keys[SDL_SCANCODE_A] = false;
708             }
709             else if(igIsItemActive())
710             {
711                 launcher.keys[SDL_SCANCODE_A] = true;
712             }
713             igSameLine(0,4);
714             if(igButton("S",ImVec2(64,64)) || igIsItemDeactivated())
715             {
716                 launcher.keys[SDL_SCANCODE_S] = false;
717             }
718             else if(igIsItemActive())
719             {
720                 launcher.keys[SDL_SCANCODE_S] = true;
721             }
722             igSameLine(0,4);
723             if(igButton("D",ImVec2(64,64)) || igIsItemDeactivated())
724             {
725                 launcher.keys[SDL_SCANCODE_D] = false;
726             }
727             else if(igIsItemActive())
728             {
729                 launcher.keys[SDL_SCANCODE_D] = true;
730             }
731             igNextColumn();
732             if(igButton("Space",ImVec2(-1,128)) || igIsItemDeactivated())
733             {
734                 launcher.keys[SDL_SCANCODE_SPACE] = false;
735             }
736             else if(igIsItemActive())
737             {
738                 launcher.keys[SDL_SCANCODE_SPACE] = true;
739             }
740             igColumns(1,null,0);
741         }
742         igEnd();
743         style.Colors[ImGuiCol_Button].w = 1.0;
744     }
745 
746     if(launcher.show_tips)
747     {
748         igSetNextWindowPos(ImVec2(launcher.window_size.x /2 -250, 100), ImGuiCond_Once, ImVec2(0,0));
749         igSetNextWindowSize(ImVec2(500, -1), ImGuiCond_Once);
750         igSetNextWindowBgAlpha(0.95);
751         if(igBegin("Tips",&launcher.show_tips,ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoSavedSettings))
752         {
753             // igBeginChild("",ImVec2(0,0),0,0);
754             igTextWrapped(launcher.demo.tips);
755             // igEndChild();
756         }
757         igEnd();
758     }
759 
760     if(launcher.show_demo_wnd)
761     {
762         igSetNextWindowPos(ImVec2(launcher.window_size.x - 260, 30), ImGuiCond_Once, ImVec2(0,0));
763         igSetNextWindowSize(ImVec2(250, 300), ImGuiCond_Once);
764         if(igBegin("Demo",&launcher.show_demo_wnd,0))
765         {
766             igCheckbox("Play",&launcher.play);
767             ImDrawList* draw_list = igGetWindowDrawList();
768             igBeginGroup();
769             launcher.gui_manager.gui();
770             igEndGroup();
771             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);
772 
773             //ImDrawList_AddRect(draw_list, igGetItemRectMin(), igGetItemRectMax(), igColorConvertFloat4ToU32(ImVec4(0.4,0.4,0.4,0.4)), -1, 0, 1);
774             //igBeginChildFrame(1,ImVec2(0,-1),ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_ChildWindow);
775             //igBeginChild("Tool frame",ImVec2(-1,-1),true,0);
776             // igBeginGroup();
777             // if(igCollapsingHeader("Tool##ToolHeader", ImGuiTreeNodeFlags_SpanAvailWidth | ImGuiTreeNodeFlags_DefaultOpen))
778             // {
779                 // igIndent(8);
780                 /*if(igBeginCombo("Tool",tool_strings[launcher.used_tool],0))
781                 {
782                     if(igSelectable("Entity spawner",false,0,ImVec2(0,0)))
783                     {
784                         launcher.used_tool = Tool.entity_spawner;
785                     }
786                     if(igSelectable("Component manipulator",false,0,ImVec2(0,0)))
787                     {
788                         launcher.used_tool = Tool.component_manipulator;
789                     }
790                     if(igSelectable("Selector",false,0,ImVec2(0,0)))
791                     {
792                         launcher.used_tool = Tool.selector;
793                     }
794                     igEndCombo();
795                 }*/
796                 /*if(igSelectable("Entity spawner",false,0,ImVec2(0,0)))
797                 {
798                     launcher.used_tool = Tool.entity_spawner;
799                 }
800                 if(igSelectable("Component manipulator",false,0,ImVec2(0,0)))
801                 {
802                     launcher.used_tool = Tool.component_manipulator;
803                 }
804                 if(igSelectable("Selector",false,0,ImVec2(0,0)))
805                 {
806                     launcher.used_tool = Tool.selector;
807                 }*/
808                 /*if(igBeginTabBar("Tool",ImGuiTabBarFlags_NoCloseWithMiddleMouseButton))
809                 {
810                     if(igIsItemHovered(0))igSetTooltip("Select tool (CTRL + 1,2,3)");
811                     bool a = 1;
812                     //this is used as hack to make CTRL+1/2/3 tab selection possible
813                     static Tool prev_tool = Tool.entity_spawner;
814                     bool different = prev_tool != launcher.used_tool;
815                     Tool tool;
816                     if(igBeginTabItem("Entity spawner", &a, launcher.used_tool == Tool.entity_spawner && different ? ImGuiTabItemFlags_SetSelected : 0))
817                     {
818                         tool = Tool.entity_spawner;
819                         igEndTabItem();
820                     }
821                     if(igBeginTabItem("Component manipulator", &a,  launcher.used_tool == Tool.component_manipulator && different ? ImGuiTabItemFlags_SetSelected : 0))
822                     {
823                         tool = Tool.component_manipulator;
824                         igEndTabItem();
825                     }
826                     if(igBeginTabItem("Selector", &a, launcher.used_tool == Tool.selector && different ? ImGuiTabItemFlags_SetSelected : 0))
827                     {
828                         tool = Tool.selector;
829                         igEndTabItem();
830                     }
831                     launcher.used_tool = tool;
832                     prev_tool = launcher.used_tool;
833                 }
834                 igEndTabBar();
835                 
836                 
837                 igCheckbox("Show Tool", &launcher.tool_show);
838                 if(igIsItemHovered(0))igSetTooltip("Show/hide graphical tool representation");
839                 igSameLine(0,4);
840                 igCheckbox("Show Filtered", &launcher.show_filtered);
841                 if(igIsItemHovered(0))igSetTooltip("Show/hide filtered entities");
842                 if(launcher.used_tool == Tool.component_manipulator)
843                 {
844                     igCheckbox("Override", &launcher.override_);
845                 }
846 
847                 //igSelectable("Selectabe",false,ImGuiSelectableFlags_None,ImVec2(0,0));
848                 if(launcher.used_tool != Tool.selector)
849                 {
850                     if(igRadioButtonBool("Add", launcher.tool_mode))launcher.tool_mode = true;
851                     if(igIsItemHovered(0))igSetTooltip("Tool should adding (Entities or components)");
852                     igSameLine(0,4);
853                     if(igRadioButtonBool("Remove", !launcher.tool_mode))launcher.tool_mode = false;
854                     if(igIsItemHovered(0))igSetTooltip("Tool should removing (Entities or components)");
855                 }
856                 
857                 igSliderInt("Tool size", &launcher.tool_size, 0, 256, null);
858                 igSliderFloat("Tool repeat", &launcher.tool_repeat, 0, 1024, null, 4);
859                 launcher.gui_manager.toolGui();*/
860                 
861                 // igUnindent(8);
862             // }
863             // igEndGroup();
864             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);
865             
866             //igBeginGroup();
867             if(igCollapsingHeader("Filter", ImGuiTreeNodeFlags_SpanAvailWidth))
868             {
869                 igIndent(8);
870                 launcher.gui_manager.filterGUI();
871                 igUnindent(8);
872             }
873             //igEndGroup();
874             //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);
875 
876             //igEndChild();
877             //igEndChildFrame();
878             if(igButton("Clear",ImVec2(-1,0)))
879             {
880                 gEntityManager.begin();
881                 gEntityManager.update("clean");
882                 gEntityManager.end();
883             }
884         }
885         igEnd();
886     }
887 
888     if(launcher.show_tools_wnd)
889     {
890         
891         igSetNextWindowPos(ImVec2(launcher.window_size.x - 300, 340), ImGuiCond_Once, ImVec2(0,0));
892         igSetNextWindowSize(ImVec2(300, launcher.window_size.y - 370), ImGuiCond_Once);
893         if(igBegin("Tools", &launcher.show_tools_wnd, ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoScrollWithMouse))
894         {
895             if(igIsItemHovered(0))igSetTooltip("Select tool (CTRL + 1,2,3)");
896             
897             if(igBeginTabBar("Tool",ImGuiTabBarFlags_NoCloseWithMiddleMouseButton))
898             {
899                 bool a = 1;
900                 //this is used as hack to make CTRL+1/2/3 tab selection possible
901                 static Tool prev_tool = Tool.entity_spawner;
902                 bool different = prev_tool != launcher.used_tool;
903                 Tool tool;
904                 if(igBeginTabItem("Entity spawner", &a, launcher.used_tool == Tool.entity_spawner && different ? ImGuiTabItemFlags_SetSelected : 0))
905                 {
906                     tool = Tool.entity_spawner;
907                     igEndTabItem();
908                 }
909                 if(igBeginTabItem("Component manipulator", &a,  launcher.used_tool == Tool.component_manipulator && different ? ImGuiTabItemFlags_SetSelected : 0))
910                 {
911                     tool = Tool.component_manipulator;
912                     igEndTabItem();
913                 }
914                 if(igBeginTabItem("Selector", &a, launcher.used_tool == Tool.selector && different ? ImGuiTabItemFlags_SetSelected : 0))
915                 {
916                     tool = Tool.selector;
917                     igEndTabItem();
918                 }
919                 launcher.used_tool = tool;
920                 prev_tool = launcher.used_tool;
921             }
922             igEndTabBar();
923             
924             
925             igCheckbox("Show Tool", &launcher.tool_show);
926             if(igIsItemHovered(0))igSetTooltip("Show/hide graphical tool representation");
927             igSameLine(0,4);
928             igCheckbox("Show Filtered", &launcher.show_filtered);
929             if(igIsItemHovered(0))igSetTooltip("Show/hide filtered entities");
930             if(launcher.used_tool == Tool.component_manipulator)
931             {
932                 igCheckbox("Override", &launcher.override_);
933             }
934 
935             //igSelectable("Selectabe",false,ImGuiSelectableFlags_None,ImVec2(0,0));
936             if(launcher.used_tool != Tool.selector)
937             {
938                 if(igRadioButtonBool("Add", launcher.tool_mode))launcher.tool_mode = true;
939                 if(igIsItemHovered(0))igSetTooltip("Tool should adding (Entities or components)");
940                 igSameLine(0,4);
941                 if(igRadioButtonBool("Remove", !launcher.tool_mode))launcher.tool_mode = false;
942                 if(igIsItemHovered(0))igSetTooltip("Tool should removing (Entities or components)");
943             }
944             
945             igSliderInt("Tool size", &launcher.tool_size, 0, 256, null);
946             igSliderFloat("Tool repeat", &launcher.tool_repeat, 0, 1024, null, 4);
947 
948             if(igBeginChild("",ImVec2(0,0),1,0))
949             {
950                 launcher.gui_manager.toolGui();
951             }
952             igEndChild();
953         }
954         igEnd();
955     }
956 
957     if(launcher.show_profile_wnd)
958     {
959         //igSetNextWindowPos(ImVec2(launcher.window_size.x - 260, launcher.window_size.y - 280), ImGuiCond_Once, ImVec2(0,0));
960         igSetNextWindowPos(ImVec2(8, launcher.window_size.y - 258), ImGuiCond_Once, ImVec2(0,0));
961         igSetNextWindowSize(ImVec2(250, 250), ImGuiCond_Once);
962         if(igBegin("Profile",&launcher.show_profile_wnd,0))
963         {
964             if(igBeginTabBar("ProfileTabBar",ImGuiTabBarFlags_FittingPolicyScroll))
965             {
966                 
967                     if(igBeginTabItem("Plots", null, 0))
968                     {
969                         if(igBeginChild("ProfileChild",ImVec2(-1,-1),0,0))
970                         {
971                             igPlotLines("Delta time",&launcher.plot_values[0].delta_time,100,launcher.plot_index,"Delta time",0,float.max,ImVec2(0,64),Launcher.PlotStruct.sizeof);
972                             igPlotLines("Loop time",&launcher.plot_values[0].loop_time,100,launcher.plot_index,"Loop time",0,float.max,ImVec2(0,64),Launcher.PlotStruct.sizeof);
973                             igPlotLines("Draw time",&launcher.plot_values[0].draw_time,100,launcher.plot_index,"Draw time",0,float.max,ImVec2(0,64),Launcher.PlotStruct.sizeof);  
974                         }
975                         igEndChild();
976                         igEndTabItem();
977                     }
978                     if(igBeginTabItem("Multithreading graph", null, 0))
979                     {
980                         if(igBeginChild("ProfileChild",ImVec2(-1,-1),0,0))
981                         {
982                             igText("Work in proggress");
983                         }
984                         igEndChild();
985                         igEndTabItem();
986                     }
987                 
988                 igEndTabBar();
989             }
990         }
991         igEnd();
992     }   
993 
994     launcher.renderer.resize(launcher.window_size);
995     //launcher.renderer.view(vec2(0,0),vec2(launcher.window_size.x,launcher.window_size.y));
996     //if(384, 768, 1152, 1536)
997     //576 960 1344 1728
998     //float scalling;
999     if(launcher.window_size.y < 360)launcher.scalling = 1;
1000     else launcher.scalling = 1.0 / ((launcher.window_size.y+120)/360);
1001     launcher.renderer.view(launcher.render_position,vec2(launcher.window_size.x,launcher.window_size.y)*launcher.scalling);
1002     //launcher.renderer.view(vec2(0,0),vec2(1024*launcher.window_size.x/launcher.window_size.y,768));
1003     //glClear(GL_COLOR_BUFFER_BIT);
1004     launcher.renderer.clear();
1005 
1006     double loop_time = launcher.getTime();
1007     launcher.job_updater.pool.tryWaitCount = 10000;
1008     if(launcher.play)
1009     {
1010         if(launcher.demo.loop && !launcher.demo.loop())
1011         {   
1012             quit();
1013             *cast(bool*)arg = false;
1014         }
1015     }
1016     else 
1017     {
1018         gEntityManager.begin();
1019         import game_core.rendering;
1020         DrawSystem* draw_system = gEntityManager.getSystem!DrawSystem;
1021         gEntityManager.callEntitiesFunction!DrawSystem(&draw_system.onUpdate);
1022         gEntityManager.end();
1023     }
1024     launcher.job_updater.pool.tryWaitCount = 0;
1025 
1026     loop_time = launcher.getTime() - loop_time;
1027 
1028     double draw_time = launcher.getTime();
1029     launcher.renderer.present();
1030     draw_time = launcher.getTime() - draw_time;
1031 
1032     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);
1033 
1034     __gshared float plot_time = 0;
1035     __gshared uint plot_samples = 0;
1036     plot_time += launcher.delta_time;
1037     plot_samples++;
1038     launcher.plot_values[100].delta_time += launcher.delta_time;
1039     launcher.plot_values[100].loop_time += loop_time;
1040     launcher.plot_values[100].draw_time += draw_time;
1041     if(plot_time > 100)
1042     {
1043         launcher.plot_values[launcher.plot_index].delta_time = launcher.plot_values[100].delta_time / cast(float)plot_samples;
1044         launcher.plot_values[launcher.plot_index].loop_time = launcher.plot_values[100].loop_time / cast(float)plot_samples;
1045         launcher.plot_values[launcher.plot_index].draw_time = launcher.plot_values[100].draw_time / cast(float)plot_samples;
1046         launcher.plot_values[100].delta_time = 0;
1047         launcher.plot_values[100].loop_time = 0;
1048         launcher.plot_values[100].draw_time = 0;
1049 
1050         plot_samples = 0;
1051         plot_time -= 100;
1052         launcher.plot_index++;
1053         if(launcher.plot_index >= 100)launcher.plot_index = 0;
1054     }
1055 
1056     if(launcher.show_stat_wnd)
1057     {
1058         igSetNextWindowPos(ImVec2(10, 30), ImGuiCond_Appearing, ImVec2(0,0));
1059         igSetNextWindowContentSize(ImVec2(150, 0.0f));
1060         igSetNextWindowBgAlpha(launcher.windows_alpha);
1061         if(igBegin("Statistics", &launcher.show_stat_wnd, ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_AlwaysAutoResize))
1062         {
1063             igColumns(2,null,0);
1064             igSetColumnWidth(0,100);
1065             igText("FPS: ");
1066             igText("Entities: ");
1067             igText("Loop time: ");
1068             igText("Draw time: ");
1069             igText("Delta time: ");
1070             igNextColumn();
1071             igText("%u",launcher.fps);
1072             igText("%u",launcher.entities_count);
1073             igText("%2.2fms",loop_time);
1074             igText("%2.2fms",draw_time);
1075             igText("%2.2fms",launcher.delta_time);
1076             igColumns(1,null,0);
1077         }
1078         igEnd();
1079     }
1080 
1081     glUseProgram(0);
1082     import ecs_utils.gfx.buffer;
1083     Buffer.unbind(Buffer.BindTarget.array);
1084     Buffer.unbind(Buffer.BindTarget.element_array);
1085 
1086     igRender();
1087     version(WebAssembly)ImGui_ImplOpenGL3_RenderDrawData(igGetDrawData());
1088     else version(Android)ImGui_ImplOpenGL3_RenderDrawData(igGetDrawData());
1089     else ImGui_ImplOpenGL3_RenderDrawData(igGetDrawData());
1090     //ImGuiImplOpenGL2RenderDrawData(igGetDrawData());
1091     
1092     //launcher.renderer.clear();
1093     //launcher.renderer.present();
1094 
1095     SDL_GL_SwapWindow(launcher.window);
1096 
1097 }
1098 
1099 void quit()
1100 {
1101     import game_core.rendering : TexCoordsManager;
1102     launcher.gui_manager.clear();
1103     Mallocator.dispose(launcher.gui_manager);
1104 
1105     if(launcher.demo.deinitialize)launcher.demo.deinitialize();
1106 
1107     gEntityManager.destroy();
1108     gEntityManager = null;
1109 
1110     TexCoordsManager.destroy();
1111 
1112     SDL_Quit();
1113 
1114     version(WebAssembly)emscripten_cancel_main_loop();
1115 }
1116 
1117 version(Android)
1118 {
1119     export extern (C) int SDL_main(int argc, char** args)
1120     {	
1121         return app_main(argc,args);
1122     }
1123 
1124     import ldc.attributes;
1125 
1126     extern (C) __gshared
1127     {
1128         @section(".tdata")
1129         int _tlsstart = 0;
1130         @section(".tcommon")
1131         int _tlsend = 0;
1132     }
1133 
1134 }
1135 else 
1136 {
1137     extern (C) int main(int argc, char** argv)
1138     {	
1139         return app_main(argc,argv);
1140     }
1141 }
1142 
1143 int app_main(int argc, char** argv)
1144 //int main(int argc, char** argv)
1145 {
1146 
1147     version(BindSDL_Static){}
1148     else 
1149     {
1150         loadSDL();
1151         loadSDLImage();
1152     }
1153 
1154     if (SDL_Init(SDL_INIT_VIDEO) < 0)
1155     {
1156         printf("SDL could not initialize! SDL_Error: %s", SDL_GetError());
1157         return -1;
1158     }
1159     SDL_version sdl_version;
1160     SDL_GetVersion(&sdl_version);
1161     printf("SDL version: %u.%u.%u\n",cast(uint)sdl_version.major,cast(uint)sdl_version.minor,cast(uint)sdl_version.patch);
1162 
1163     SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2);
1164 	SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0);
1165     launcher.window = SDL_CreateWindow("Simple", SDL_WINDOWPOS_CENTERED,
1166                 SDL_WINDOWPOS_CENTERED, launcher.window_size.x, launcher.window_size.y, SDL_WINDOW_SHOWN | SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE);
1167     SDL_MaximizeWindow(launcher.window);
1168 
1169     launcher.gl_context = SDL_GL_CreateContext(launcher.window);
1170     launcher.context = igCreateContext(null);
1171     launcher.timer_freq = SDL_GetPerformanceFrequency();
1172 
1173     launcher.plot_values = Mallocator.makeArray!(Launcher.PlotStruct)(101);
1174 
1175     SDL_GetWindowSize(launcher.window, &launcher.window_size.x, &launcher.window_size.y);
1176 
1177     version(WebAssembly)
1178     {
1179         gladLoadGLES2(x => SDL_GL_GetProcAddress(x));
1180         if(!ImGui_ImplSDL2_InitForOpenGL(launcher.window,launcher.gl_context))
1181         {
1182             printf("ImGui initialization failed!");
1183             return -2;
1184         }
1185         if(!ImGui_ImplOpenGL3_Init())
1186         {
1187             printf("ImGui OpenGL initialization failed!");
1188             return -3;
1189         }
1190     }
1191     else version(Android)
1192     {
1193         //gladLoadGL();
1194         gladLoadGLES2(x => SDL_GL_GetProcAddress(x));
1195         if(!ImGuiImplSDL2InitForOpenGL(launcher.window,launcher.gl_context))
1196         {
1197             printf("ImGui initialization failed!");
1198             return -2;
1199         }
1200         if(!ImGui_ImplOpenGL3_Init("#version 100"))
1201         {
1202             printf("ImGui OpenGL initialization failed!");
1203             return -3;
1204         }
1205     }
1206     else 
1207     {
1208         gladLoadGL();
1209         if(!ImGuiImplSDL2InitForOpenGL(launcher.window,launcher.gl_context))
1210         {
1211             printf("ImGui initialization failed!");
1212             return -2;
1213         }
1214         //if(!ImGuiImplOpenGL2Init())
1215         if(!ImGui_ImplOpenGL3_Init("#version 120"))
1216         {
1217             printf("ImGui OpenGL initialization failed!");
1218             return -3;
1219         }
1220     }
1221     
1222     //ImFontConfig* config = ImFontConfig_ImFontConfig();
1223     ImGuiIO* io = igGetIO();
1224     const ushort* font_ranges = ImFontAtlas_GetGlyphRangesDefault(io.Fonts);
1225     ImFontAtlas_AddFontFromFileTTF(io.Fonts,"assets/fonts/Ruda-Bold.ttf", 15.0f, null, font_ranges);
1226     //ImFontConfig_destroy(config);
1227 
1228     setStyle(3);
1229 
1230     launcher.job_updater = Mallocator.make!ECSJobUpdater(1);
1231     //launcher.job_updater.onCreate();
1232 
1233     EntityManager.initialize(32, 1<<16);
1234     //gEntityManager = gEntityManager;
1235 
1236     //gEntityManager.m_thread_id_func = &launcher.job_updater.getThreadID;
1237     //gEntityManager.setJobDispachFunc(&launcher.job_updater.dispatch);
1238     gEntityManager.setMultithreadingCallbacks(&launcher.job_updater.dispatch, &launcher.job_updater.getThreadID);
1239 
1240     gEntityManager.beginRegister();
1241 
1242     gEntityManager.registerPass("clean");
1243 
1244     gEntityManager.registerComponent!CLocation;
1245 
1246     gEntityManager.registerSystem!CountSystem(10000);
1247     gEntityManager.registerSystem!CleanSystem(0,"clean");
1248     gEntityManager.registerSystem!IteratorSystem(0,"clean");
1249     
1250     gEntityManager.endRegister();
1251 
1252     loadGFX();
1253 
1254     launcher.renderer.initialize();
1255     import game_core.rendering : TexCoordsManager;
1256     TexCoordsManager.initialize();
1257 
1258     import mmutils.thread_pool : ThreadPool;
1259     launcher.threads = ThreadPool.getCPUCoresCount();
1260     if(launcher.threads < 2)launcher.threads = 2;
1261 
1262     launcher.gui_manager = Mallocator.make!GUIManager();
1263 
1264     {
1265         import demos.simple;
1266         import demos.space_invaders;
1267         import demos.particles;
1268         import demos.brick_breaker;
1269         // launcher.switchDemo(&spaceInvadersStart,&spaceInvadersLoop,&spaceInvadersEnd,&spaceInvadersEvent,SpaceInvaders.tips);
1270         // launcher.switchDemo(&particlesStart,&particlesLoop,&particlesEnd,&particlesEvent,ParticlesDemo.tips);
1271         // launcher.switchDemo(&simpleStart,&simpleLoop,&simpleEnd,&simpleEvent,Simple.tips);
1272         // launcher.switchDemo(getParticlesDemo());
1273         // launcher.switchDemo(getSimpleDemo());
1274         launcher.switchDemo(getSimpleDemo());
1275     }
1276 
1277     int key_num;
1278     ubyte* keys = SDL_GetKeyboardState(&key_num);
1279     launcher.keys = keys[0..key_num];
1280 
1281     version(WebAssembly)
1282     {
1283         /*EmscriptenFullscreenStrategy strategy;
1284         strategy.scaleMode = EMSCRIPTEN_FULLSCREEN_SCALE_STRETCH;
1285         strategy.canvasResolutionScaleMode = EMSCRIPTEN_FULLSCREEN_CANVAS_SCALE_STDDEF;
1286         strategy.filteringMode = EMSCRIPTEN_FULLSCREEN_FILTERING_NEAREST;*/
1287 
1288         //int result = emscripten_request_fullscreen_strategy(null, true, &strategy);
1289         //emscripten_enter_soft_fullscreen(null, &strategy);
1290         //printf("Fullscreen request: %s.\n", emscripten_result_to_string(result));
1291         emscripten_set_main_loop_arg(&mainLoop, null, 0, 1);
1292     }
1293     else
1294     {
1295         bool arg = true;
1296         while(arg == true)
1297         {
1298             mainLoop(&arg);
1299         }
1300     }
1301 
1302     return 0;
1303 }
1304 
1305 void loadGFX()
1306 {
1307     import ecs_utils.gfx.texture;
1308     import ecs_utils.gfx.vertex;
1309     import ecs_utils.gfx.shader;
1310     import ecs_utils.gfx.material;
1311     import ecs_utils.gfx.config;
1312     import ecs_utils.gfx.mesh;
1313 
1314     Texture.__loadBackend();
1315     Renderer.__loadBackend();
1316 
1317     GfxConfig.materials = Mallocator.makeArray!Material(3);
1318     GfxConfig.meshes = Mallocator.makeArray!Mesh(1);
1319 
1320     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];
1321     GfxConfig.meshes[0].vertices = Mallocator.makeArray(vertices);
1322     ushort[6] indices = [0,1,2,1,2,3];
1323     GfxConfig.meshes[0].indices = Mallocator.makeArray(indices);
1324     GfxConfig.meshes[0].uploadData();
1325 
1326     Shader vsh;
1327     vsh.create();
1328     vsh.load("assets/shaders/base.vp");
1329     vsh.compile();
1330 
1331     Shader fsh;
1332     fsh.create();
1333     fsh.load("assets/shaders/base.fp");
1334     fsh.compile();
1335 
1336     GfxConfig.materials[0].create();
1337     GfxConfig.materials[0].data.blend_mode = Material.BlendMode.opaque;
1338     GfxConfig.materials[0].data.mode = Material.TransformMode.position;
1339     Material.ShaderModule[1] modules = [Material.ShaderModule(vsh,fsh)];
1340     GfxConfig.materials[0].attachModules(modules);
1341     //GfxConfig.materials[0].
1342     //GfxConfig.materials[0].load(load_data.materials[i].str);
1343     GfxConfig.materials[0].compile();
1344     GfxConfig.materials[0].bindAttribLocation("positions",0);
1345     GfxConfig.materials[0].bindAttribLocation("tex_coords",1);
1346     GfxConfig.materials[0].bindAttribLocation("depth",2);
1347     GfxConfig.materials[0].bindAttribLocation("vcolor",3);
1348     GfxConfig.materials[0].link();
1349 
1350    /* import std.stdio;
1351     writeln("positions ",glGetAttribLocation(GfxConfig.materials[0].data.modules[0].gl_handle,"positions"));
1352     writeln("tex_coords ",glGetAttribLocation(GfxConfig.materials[0].data.modules[0].gl_handle,"tex_coords"));
1353     writeln("depth ",glGetAttribLocation(GfxConfig.materials[0].data.modules[0].gl_handle,"depth"));
1354     writeln("vcolor ",glGetAttribLocation(GfxConfig.materials[0].data.modules[0].gl_handle,"vcolor"));*/
1355     
1356     GfxConfig.materials[0].data.uniforms = Mallocator.makeArray!(Material.Uniform)(3);
1357     GfxConfig.materials[0].data.uniforms[0] = Material.Uniform(Material.Type.float4, GfxConfig.materials[0].getLocation("matrix_1"), 0);
1358     GfxConfig.materials[0].data.uniforms[1] = Material.Uniform(Material.Type.float4, GfxConfig.materials[0].getLocation("matrix_2"), 16);
1359     GfxConfig.materials[0].data.uniforms[2] = Material.Uniform(Material.Type.float4, GfxConfig.materials[0].getLocation("uv_transform"), 32);
1360     GfxConfig.materials[0].data.bindings = Mallocator.makeArray!(int)(1);
1361     GfxConfig.materials[0].data.bindings[0] = GfxConfig.materials[0].getLocation("tex");
1362     
1363     
1364     Shader vsh2;
1365     vsh2.create();
1366     vsh2.load("assets/shaders/circle.vp");
1367     vsh2.compile();
1368 
1369     Shader fsh2;
1370     fsh2.create();
1371     fsh2.load("assets/shaders/circle.fp");
1372     fsh2.compile();
1373 
1374     GfxConfig.materials[1].create();
1375     GfxConfig.materials[1].data.blend_mode = Material.BlendMode.mixed;
1376     GfxConfig.materials[1].data.mode = Material.TransformMode.position;
1377     Material.ShaderModule[1] modules2 = [Material.ShaderModule(vsh2,fsh2)];
1378     GfxConfig.materials[1].attachModules(modules2);
1379     //GfxConfig.materials[0].
1380     //GfxConfig.materials[0].load(load_data.materials[i].str);
1381     GfxConfig.materials[1].compile();
1382     GfxConfig.materials[1].bindAttribLocation("positions",0);
1383     //GfxConfig.materials[1].bindAttribLocation("tex_coords",1);
1384     //GfxConfig.materials[1].bindAttribLocation("depth",2);
1385     //GfxConfig.materials[1].bindAttribLocation("vcolor",3);
1386     GfxConfig.materials[1].link();
1387 
1388    /* import std.stdio;
1389     writeln("positions ",glGetAttribLocation(GfxConfig.materials[0].data.modules[0].gl_handle,"positions"));
1390     writeln("tex_coords ",glGetAttribLocation(GfxConfig.materials[0].data.modules[0].gl_handle,"tex_coords"));
1391     writeln("depth ",glGetAttribLocation(GfxConfig.materials[0].data.modules[0].gl_handle,"depth"));
1392     writeln("vcolor ",glGetAttribLocation(GfxConfig.materials[0].data.modules[0].gl_handle,"vcolor"));*/
1393     
1394     GfxConfig.materials[1].data.uniforms = Mallocator.makeArray!(Material.Uniform)(2);
1395     GfxConfig.materials[1].data.uniforms[0] = Material.Uniform(Material.Type.float4, GfxConfig.materials[1].getLocation("matrix_1"), 0);
1396     GfxConfig.materials[1].data.uniforms[1] = Material.Uniform(Material.Type.float4, GfxConfig.materials[1].getLocation("matrix_2"), 16);
1397     //GfxConfig.materials[1].data.uniforms[2] = Material.Uniform(Material.Type.float4, GfxConfig.materials[0].getLocation("uv_transform"), 32);
1398     //GfxConfig.materials[1].data.bindings = Mallocator.makeArray!(int)(1);
1399     //GfxConfig.materials[1].data.bindings[0] = GfxConfig.materials[0].getLocation("tex");
1400 
1401 
1402 
1403 
1404     
1405     Shader vsh3;
1406     vsh3.create();
1407     vsh3.load("assets/shaders/additive_particles.vp");
1408     vsh3.compile();
1409 
1410     Shader fsh3;
1411     fsh3.create();
1412     fsh3.load("assets/shaders/additive_particles.fp");
1413     fsh3.compile();
1414 
1415     GfxConfig.materials[2].create();
1416     GfxConfig.materials[2].data.blend_mode = Material.BlendMode.opaque;
1417     GfxConfig.materials[2].data.mode = Material.TransformMode.position;
1418     Material.ShaderModule[1] modules3 = [Material.ShaderModule(vsh3,fsh3)];
1419     GfxConfig.materials[2].attachModules(modules3);
1420     //GfxConfig.materials[0].
1421     //GfxConfig.materials[0].load(load_data.materials[i].str);
1422     GfxConfig.materials[2].compile();
1423     GfxConfig.materials[2].bindAttribLocation("positions",0);
1424     GfxConfig.materials[2].bindAttribLocation("tex_coords",1);
1425     GfxConfig.materials[2].bindAttribLocation("depth",2);
1426     GfxConfig.materials[2].bindAttribLocation("vcolor",3);
1427     GfxConfig.materials[2].link();
1428 
1429    /* import std.stdio;
1430     writeln("positions ",glGetAttribLocation(GfxConfig.materials[0].data.modules[0].gl_handle,"positions"));
1431     writeln("tex_coords ",glGetAttribLocation(GfxConfig.materials[0].data.modules[0].gl_handle,"tex_coords"));
1432     writeln("depth ",glGetAttribLocation(GfxConfig.materials[0].data.modules[0].gl_handle,"depth"));
1433     writeln("vcolor ",glGetAttribLocation(GfxConfig.materials[0].data.modules[0].gl_handle,"vcolor"));*/
1434     
1435     GfxConfig.materials[2].data.uniforms = Mallocator.makeArray!(Material.Uniform)(3);
1436     GfxConfig.materials[2].data.uniforms[0] = Material.Uniform(Material.Type.float4, GfxConfig.materials[0].getLocation("matrix_1"), 0);
1437     GfxConfig.materials[2].data.uniforms[1] = Material.Uniform(Material.Type.float4, GfxConfig.materials[0].getLocation("matrix_2"), 16);
1438     GfxConfig.materials[2].data.uniforms[2] = Material.Uniform(Material.Type.float4, GfxConfig.materials[0].getLocation("uv_transform"), 32);
1439     GfxConfig.materials[2].data.bindings = Mallocator.makeArray!(int)(1);
1440     GfxConfig.materials[2].data.bindings[0] = GfxConfig.materials[0].getLocation("tex");
1441     GfxConfig.materials[2].data.blend_mode = Material.BlendMode.additive;
1442 
1443 
1444 
1445 
1446 
1447 
1448     /*glUseProgram(0);
1449     glBindBuffer(GL_ARRAY_BUFFER, 0);
1450     glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);*/
1451 
1452     launcher.tool_circle = Mallocator.make!ToolCircle;
1453 }