1 module unecht.glfw.glfwapplication;
2 
3 import std.stdio;
4 
5 import derelict.glfw3.glfw3;
6 import derelict.opengl3.gl3;
7 import derelict.imgui.imgui;
8 import derelict.freeimage.freeimage;
9 
10 import unecht.glfw.glfwwindow;
11 import unecht.glfw.joysticks;
12 import unecht.core.types;
13 
14 public import unecht.glfw.types;
15 
16 import unecht.ue,
17 	unecht.core.application,
18 	unecht.core.window,
19 	unecht.core.entity,
20 	unecht.core.components.camera,
21 	unecht.core.components.misc,
22 	unecht.core.components.internal.gui,
23 	unecht.core.events,
24 	unecht.core.stdex;
25 
26 version(EnableSteam) import unecht.steamaccess;
27 version(UEProfiling) import unecht.core.profiler;
28 
29 ///
30 final class GlfwApplication : UEApplication
31 {
32 	version(EnableSteam)
33 	SteamAccess steam;
34 
35 	private GlfwWindow _mainWindow;
36 	UEEventsSystem events;
37 	UEEntity rootEntity;
38 	private GLFWJoysticks joysticks;
39 
40 	version(UEProfiling)
41 	{
42 		DespikerSender sender;
43 	}
44 
45 	///
46 	public UEWindow mainWindow() nothrow { return _mainWindow; }
47 
48 	/// contains the game loop is run in main function
49 	public int run()
50 	{
51 		version(EnableSteam)
52 		{
53 			steam = new SteamAccess();
54 		}
55 
56 		version(UEProfiling)
57 		{
58 			profiler = new Profiler(storage);
59 			sender = new DespikerSender([profiler]);
60 		}
61 
62 		DerelictFI.load();
63 		DerelictGL3.load();
64 		DerelictGLFW3.load();
65 		DerelictImgui.load();
66 
67 		if(!initGLFW())
68 			return -1;
69 		scope(exit) glfwTerminate();
70 
71 		events = new UEEventsSystem();
72 
73 		_mainWindow = new GlfwWindow();
74 		if(!_mainWindow.create(ue.windowSettings.size,ue.windowSettings.title, events))
75 			return -1;
76 		scope(exit) _mainWindow.destroy();
77 		
78 		DerelictGL3.reload();
79 
80 		startEngine();
81 
82 		glEnable(GL_BLEND);
83 		glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
84 		glDisable(GL_DEPTH_TEST);
85 
86 		version(none)
87 		{
88 			import core.memory:GC;
89 			GC.disable();
90 		}
91 
92 		while (!_mainWindow.shouldClose)
93 		{
94 			import std.datetime:StopWatch,TickDuration,AutoStart;
95 			auto sw = StopWatch(AutoStart.yes);
96 			scope(exit)
97 			{
98 				TickDuration a = sw.peek();
99 				import unecht.core.profiler;
100 				UEProfiling.addFrametime(a,UEGui.framerate);
101 			}
102 
103 			{
104 				version(UEProfiling)
105 				auto frame = Zone(profiler, "frame");
106 
107 				{
108 					version(UEProfiling)
109 					auto profZone = Zone(profiler, "events.cleanup");
110 					events.cleanUp();
111 				}
112 
113 				ue.tickTime = glfwGetTime();
114 
115 				{
116 					UEGui.startFrame();
117 				}
118 
119 				{
120 					version(UEProfiling)
121 						auto profZone = Zone(profiler, "fibers run");
122 					
123 					import unecht.core.fibers:UEFibers;
124 					UEFibers.runFibers();
125 				}
126 
127 				{
128 					version(UEProfiling)
129 					auto profZone = Zone(profiler, "scene update");
130 
131 					ue.scene.update();
132 				}
133 
134 				{
135 					version(UEProfiling)
136 					auto profZone = Zone(profiler, "render update");
137 
138 					render();
139 				}
140 
141 				version(UEIncludeEditor)
142 				{
143 					{
144 						version(UEProfiling)
145 						auto profZone = Zone(profiler, "render editor");
146 
147 						import unecht.core.components._editor:EditorRootComponent;
148 						EditorRootComponent.renderEditor();
149 					}
150 				}
151 
152 				{
153 					version(UEProfiling)
154 					auto profZone = Zone(profiler, "render gui");
155 
156 					UEGui.renderGUI();
157 				}
158 
159 				{
160 					version(EnableSteam)
161 					steam.update();
162 				}
163 
164 				{
165 					version(UEProfiling)
166 					auto profZone = Zone(profiler, "vertical sync");
167 
168 					_mainWindow.swapBuffers();
169 				}
170 
171 				{
172 					version(UEProfiling)
173 					auto profZone = Zone(profiler, "update joysticks");
174 
175 					joysticks.update();
176 				}
177 
178 				{
179 					version(UEProfiling)
180 					auto profZone = Zone(profiler, "poll events");
181 
182 					glfwPollEvents();
183 				}
184 
185 				version(none)
186 				{
187 					version(UEProfiling)
188 					auto profZone = Zone(profiler, "gc");
189 					GC.collect();
190 				}
191 			}
192 
193 			version(UEProfiling)
194 			sender.update();
195 		}
196 
197 		return 0;
198 	}
199 
200 	/// initiate application closing
201 	void terminate()
202 	{
203 		_mainWindow.close();
204 	}
205 
206 	///
207 	void openProfiler()
208 	{
209 		version(UEProfiling)
210 		{
211 			if(sender)
212 			{
213 				if(!sender.sending)
214 				{
215 					try sender.startDespiker();
216 					catch(Exception e)
217 					{
218 						import unecht.core.logger;
219 						log.warning("error starting despiker binary");
220 					}
221 				}
222 			}
223 		}
224 	}
225 
226 	///
227 	void openSteamOverlay()
228 	{
229 		version(EnableSteam)
230 		steam.openOverlay();
231 	}
232 
233 	///
234 	UESize windowSize()
235 	{
236 		return _mainWindow.windowSize;
237 	}
238 	///
239 	UESize framebufferSize()
240 	{
241 		return _mainWindow.framebufferSize;
242 	}
243 
244 private:
245 
246 	bool initGLFW()
247 	{
248 		import unecht.core.logger:log;
249 		import std.conv:to;
250 
251 		glfwSetErrorCallback(&error_callback);
252 
253 		auto res = glfwInit()!=0;
254 
255 		log.infof("glfw ct: %s.%s.%s",GLFW_VERSION_MAJOR,GLFW_VERSION_MINOR,GLFW_VERSION_REVISION);
256 		log.infof("glfw rt: %s",to!string(glfwGetVersionString()));
257 
258 		return res;
259 	}
260 
261 	void startEngine()
262 	{
263 		import unecht.core.scenegraph:UEScenegraph;
264 		import unecht.core.assetDatabase:UEAssetDatabase;
265 		
266 		ue.events = events;
267 
268 		ue.scene = new UEScenegraph();
269 
270 		joysticks.init(events);
271 
272 		UEAssetDatabase.refresh();
273 
274 		insertGuiObj();
275 
276 		insertPhysicsObj();
277 
278 		version(UEIncludeEditor)insertEditorEntity();
279 
280 		if(ue.hookStartup)
281 			ue.hookStartup();
282 
283 		version(UEIncludeEditor)ue.scene.playing = false;
284 	}
285 
286 	void insertGuiObj()
287 	{
288 		auto newE = UEEntity.create("gui");
289 		newE.addComponent!UEGui;
290 	}
291 
292 	void insertPhysicsObj()
293 	{
294 		auto newE = UEEntity.create("physics");
295 		import unecht.core.components.physics;
296 		newE.addComponent!UEPhysicsSystem;
297 	}
298 
299 	version(UEIncludeEditor)void insertEditorEntity()
300 	{
301 		auto newE = UEEntity.create("editor");
302 		import unecht.core.components._editor:EditorRootComponent;
303 		newE.addComponent!EditorRootComponent;
304 	}
305 
306 	void render()
307 	{
308 		auto cams = ue.scene.gatherAllComponents!UECamera;
309 
310 		foreach(cam; cams)
311 		{
312 			if(cam.enabled)
313 				cam.render();
314 		}
315 	}
316 }
317 
318 private nothrow extern(C) void error_callback(int error, const(char)* description)
319 {
320 	try {
321 		import unecht.core.logger:log;
322 		import std.conv:to;
323 		log.errorf("glfw err: %s '%s'", error, to!string(description));
324 	}
325 	catch(Throwable){}
326 }