1 /++ 2 Runtime is a fundamental module for building two-dimensional games. It is he 3 who connects to the window manager of the operating system, initializes the 4 sound device and loads the necessary libraries for the game. Also, it is able 5 to store program arguments in itself, in order to pass them later to 6 other functions. 7 8 How do I create a runtime?: 9 Creating a runtime is quick and easy. There is a class, it has a static 10 method $(HREF ../tida/runtime/ITidaRuntime.initialize.html, initialize), which allocates memory, and then calls the internal 11 functions of the object to execute its functions. This is done 12 in the following way: 13 --- 14 import tida; 15 16 int main(string[] args) 17 { 18 TidaRuntime.initialize(args); 19 20 return 0; 21 } 22 --- 23 24 As you can see, the program arguments are passed to the function. 25 This is necessary in order to later use them outside the main function. 26 27 Also, the second parameter can be a list of libraries to load. 28 All kinds of libraries that runtime can load are described in $(HREF #OpenAL, here). 29 --- 30 import tida; 31 32 int main(string[] args) 33 { 34 TidaRuntime.initialize(args, [FreeType, OpenAL]); 35 36 return 0; 37 } 38 --- 39 40 Or you can use $(LREF AllLibrary) to say that you need to load everything, 41 or $(LREF WithoutLibrary) that you need to load nothing. 42 43 Next, to take advantage of the runtime, you can refer to the $(LREF runtime) function, 44 which will give the runtime object as long as you can do something. 45 All actions are described in $(HREF ../tida/runtime/ITidaRuntime.html, ITidaRuntime). 46 47 Macros: 48 LREF = <a href="#$1">$1</a> 49 HREF = <a href="$1">$2</a> 50 OBJECTREF = <a href="https://dlang.org/library/object.html#$1">$1</a> 51 52 Authors: $(HREF https://github.com/TodNaz, TodNaz) 53 Copyright: Copyright (c) 2020 - 2021, TodNaz. 54 License: $(HREF https://github.com/TodNaz/Tida/blob/master/LICENSE, MIT) 55 +/ 56 module tida.runtime; 57 58 __gshared TidaRuntime _runtimeObject; 59 60 /++ 61 Global access to runtime. An object can be called from anywhere, 62 but cannot be replaced. 63 +/ 64 @property TidaRuntime runtime() @trusted 65 { 66 return _runtimeObject; 67 } 68 69 enum : int 70 { 71 OpenAL = 0, /// Open Audio Library 72 FreeType, /// Free Type Library 73 GLX, /// Graphics library X11 74 EGL /// EGL library wayland 75 } 76 77 alias LibraryUnite = int; /// 78 79 /++ 80 An array of library indexes. Indicates that all libraries should be loaded, 81 when specified in the 82 $(HREF ../tida/runtime/ITidaRuntime.initialize.html, initialization) of the runtime. 83 +/ 84 enum AllLibrary = [OpenAL, FreeType, GLX]; 85 86 /++ 87 An array of only important libraries. Loads only the necessary libraries 88 (for connecting to the window manager) when specified in the 89 $(HREF ../tida/runtime/ITidaRuntime.initialize.html, initialization) of the runtime. 90 +/ 91 enum WithoutLibrary = [GLX]; 92 93 /++ 94 The interface of interaction between the program and the window manager. 95 +/ 96 interface ITidaRuntime 97 { 98 import tida.sound : Device; 99 100 @safe: 101 /++ 102 A function for loading external libraries that are needed when implementing 103 internal functions. 104 105 Params: 106 libs = What external libraries need to be loaded. 107 (`AllLibrary` to load all external libraries, 108 `WithoutLibrary` in order not to load unnecessary 109 external libraries.) 110 111 Throws: 112 $(OBJECTREF Exception) If the libraries were not installed on the machine 113 being started or they were damaged. 114 +/ 115 void loadExternalLibraries(LibraryUnite[] libs); 116 117 /++ 118 Connects to the window manager. 119 120 Throws: 121 $(OBJECTREF Exception) If the libraries were not installed on the machine 122 being started or they were damaged. And also if the connection to the 123 window manager was not successful (for example, there is no such component 124 in the OS or the connection to an unknown window manager is not supported). 125 +/ 126 void connectToWndMng(); 127 128 /++ 129 Closes the session with the window manager. 130 +/ 131 void closeWndMngSession(); 132 133 /++ 134 Arguments given to the program. 135 +/ 136 @property string[] mainArguments(); 137 138 /++ 139 Accepts program arguments for subsequent operations with them. 140 +/ 141 void acceptArguments(string[] arguments); 142 143 @property Device device() @safe; 144 145 uint[2] monitorSize(); 146 147 @trusted: 148 /++ 149 Static function to initialize the runtime. Allocates memory for runtime and 150 executes its functions of accepting arguments, loading the necessary 151 libraries and connecting to the window manager through its 152 interface functions. 153 154 An example of how to load individual libraries: 155 --- 156 import tida.runtime; 157 158 int main(string[] args) 159 { 160 TidaRuntime.initialize(args, [FreeType, OpenAL]); 161 162 return 0; 163 } 164 --- 165 166 Params: 167 arguments = Arguments that were nested in the main function. They will 168 be stored in the runtime memory from where they can be read. 169 Rantheim doesn't read such arguments. 170 libs = List of libraries to download. Please note that this does 171 not affect libraries that the framework does not use. 172 Notable libraries are listed 173 $(HREF ../runtime.html#EGL, here). 174 175 Throws: $(OBJECTREF Exception) if during initialization the libraries 176 were not loaded or the runner could not connect to the window manager. 177 +/ 178 static final void initialize( string[] arguments = [], 179 LibraryUnite[] libs = AllLibrary) 180 { 181 _runtimeObject = new TidaRuntime(); 182 _runtimeObject.acceptArguments(arguments); 183 _runtimeObject.loadExternalLibraries(libs); 184 _runtimeObject.connectToWndMng(); 185 } 186 } 187 188 /++ 189 The interface of interaction between the program and the window manager. 190 +/ 191 version (Posix) 192 class TidaRuntime : ITidaRuntime 193 { 194 import x11.X, x11.Xlib, x11.Xutil; 195 import std.exception : enforce; 196 import tida.sound : initSoundlibrary, Device; 197 import tida.text : initFontLibrary; 198 199 enum SessionType 200 { 201 unknown, 202 x11, 203 wayland 204 } 205 206 enum SessionWarning = 207 "WARNING! The session is not defined. Perhaps she simply does not exist?"; 208 209 private: 210 Display* _display; 211 int _displayID; 212 string[] arguments; 213 SessionType _session; 214 Device _device; 215 216 public @trusted: 217 this() 218 { 219 import std.process; 220 import std.stdio : stderr, writeln; 221 222 auto env = environment.get("XDG_SESSION_TYPE"); 223 if (env == "x11") 224 { 225 _session = SessionType.x11; 226 } else 227 if (env == "wayland") 228 { 229 _session = SessionType.wayland; 230 } else 231 { 232 _session = SessionType.unknown; 233 stderr.writeln(SessionWarning); 234 } 235 236 } 237 238 override @property Device device() 239 { 240 return _device; 241 } 242 243 override void loadExternalLibraries(LibraryUnite[] libs) 244 { 245 import dglx.glx : loadGLXLibrary; 246 247 foreach (e; libs) 248 { 249 if (e == OpenAL) 250 { 251 initSoundlibrary(); 252 _device = new Device(); 253 _device.open(); 254 } 255 else 256 if (e == FreeType) 257 initFontLibrary(); 258 else 259 if (e == GLX) 260 { 261 if (_session == SessionType.x11) 262 loadGLXLibrary(); 263 else 264 throw new Exception("[Wayland] The creation of runtime via wayland is not implemented."); 265 } 266 } 267 } 268 269 override void connectToWndMng() 270 { 271 this._display = XOpenDisplay(null); 272 enforce!Exception(this._display, 273 "Failed to connect to window manager."); 274 275 this._displayID = DefaultScreen(this._display); 276 } 277 278 override void closeWndMngSession() 279 { 280 XCloseDisplay(this._display); 281 this._display = null; 282 this._displayID = 0; 283 } 284 285 override void acceptArguments(string[] arguments) 286 { 287 this.arguments = arguments; 288 } 289 290 @property override string[] mainArguments() 291 { 292 return this.arguments; 293 } 294 295 @property Window rootWindow() 296 { 297 return RootWindow(_display, _displayID); 298 } 299 300 uint[2] monitorSize() 301 { 302 auto screen = ScreenOfDisplay(_display, 0); 303 return [screen.width, screen.height]; 304 } 305 306 @safe: 307 /// An instance for contacting the manager's server. 308 @property Display* display() 309 { 310 return this._display; 311 } 312 313 /// Default screen number 314 @property int displayID() 315 { 316 return this._displayID; 317 } 318 319 ~this() 320 { 321 closeWndMngSession(); 322 } 323 } 324 325 /++ 326 Required to enable high performance on devices with nvidia optimus. 327 328 If necessary, include the "WitoutHighNvidiaOptimus" version in the flags. 329 330 See_Also: 331 https://developer.download.nvidia.com/devzone/devcenter/gamegraphics/files/OptimusRenderingPolicies.pdf 332 +/ 333 version (Windows) 334 { 335 version (WitoutHighNvidiaOptimus) 336 { 337 // Nothing 338 } else 339 { 340 extern(C) 341 { 342 export ulong NvOptimusEnablement = 0x00000001; 343 } 344 } 345 } 346 347 version (Windows) 348 class TidaRuntime : ITidaRuntime 349 { 350 import core.sys.windows.windows; 351 import std.exception : enforce; 352 import tida.sound : initSoundlibrary, Device; 353 import tida.text : initFontLibrary; 354 355 pragma(lib, "opengl32.lib"); 356 pragma(lib, "winmm.lib"); 357 358 private: 359 HINSTANCE hInstance; 360 string[] arguments; 361 Device _device; 362 363 public @trusted: 364 override void loadExternalLibraries(LibraryUnite[] libs) 365 { 366 foreach (e; libs) 367 { 368 if (e == OpenAL) 369 { 370 initSoundlibrary(); 371 _device = new Device(); 372 _device.open(); 373 } 374 else 375 if (e == FreeType) 376 initFontLibrary(); 377 } 378 } 379 380 override Device device() @safe 381 { 382 return _device; 383 } 384 385 override void connectToWndMng() 386 { 387 this.hInstance = GetModuleHandle(null); 388 debug {} else 389 ShowWindow(GetConsoleWindow(), SW_HIDE); 390 391 enforce!Exception(this.hInstance, 392 "Failed to connect to window manager."); 393 } 394 395 override void closeWndMngSession() 396 { 397 this.hInstance = null; 398 } 399 400 override void acceptArguments(string[] arguments) 401 { 402 this.arguments = arguments; 403 } 404 405 override uint[2] monitorSize() 406 { 407 HDC hScreenDC = GetDC(GetDesktopWindow()); 408 int width = GetDeviceCaps(hScreenDC, HORZRES); 409 int height = GetDeviceCaps(hScreenDC, VERTRES); 410 ReleaseDC(GetDesktopWindow(), hScreenDC); 411 412 return [width, height]; 413 } 414 415 @property override string[] mainArguments() 416 { 417 return this.arguments; 418 } 419 420 @safe: 421 @property HINSTANCE instance() 422 { 423 return this.hInstance; 424 } 425 }