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 }