1 module polyplex.core.window; 2 import polyplex.utils.sdlbool; 3 public import polyplex.core.render; 4 static import polyplex; 5 6 import derelict.sdl2.sdl; 7 import derelict.sdl2.image; 8 import polyplex.math; 9 import polyplex.utils.logging; 10 import std.stdio; 11 import std..string; 12 import std.conv; 13 14 15 public enum WindowPosition { 16 Center = -1, 17 Undefined = 0 18 } 19 20 public class GameWindow { 21 private int width; 22 private int height; 23 private SDL_Window* window; 24 private Renderer renderer; 25 private string start_title; 26 private Rectangle start_bounds; 27 28 public @property int Width() { return this.width; } 29 public @property int Height() { return this.height; } 30 31 public @property Renderer Backend() { return this.renderer; } 32 33 /* 34 Gets whenever the window is visible 35 */ 36 public @property bool Visible() { return (this.window != null); } 37 38 //Resizing 39 public @property bool AllowResizing() { 40 SDL_WindowFlags flags = SDL_GetWindowFlags(window); 41 return ((flags & SDL_WINDOW_RESIZABLE) > 0); 42 } 43 public @property void AllowResizing(bool allow) { SDL_SetWindowResizable(this.window, ToSDL(allow)); } 44 45 //Vertical Syncronization 46 public @property VSyncState VSync() { 47 return renderer.VSync; 48 } 49 public @property void VSync(VSyncState allow) { renderer.VSync = allow; } 50 51 52 //Borderless 53 public @property bool Borderless() { 54 SDL_WindowFlags flags = SDL_GetWindowFlags(window); 55 return ((flags & SDL_WINDOW_BORDERLESS) > 0); 56 } 57 58 public @property void Borderless(bool i) { SDL_SetWindowBordered(this.window, ToSDL(!i)); } 59 60 //Title 61 public @property string Title() { return to!string(SDL_GetWindowTitle(this.window)); } 62 public @property void Title(string t) { return SDL_SetWindowTitle(this.window, t.toStringz); } 63 64 //Brightness 65 public @property float Brightness() { return SDL_GetWindowBrightness(this.window); } 66 public @property void Brightness(float b) { SDL_SetWindowBrightness(this.window, b); } 67 68 //Backend 69 public @property polyplex.GraphicsBackend GLBackend() { return polyplex.ChosenBackend; } 70 71 //Fullscreen 72 public @property bool Fullscreen() { 73 SDL_WindowFlags flags = SDL_GetWindowFlags(window); 74 return ((flags & (SDL_WINDOW_FULLSCREEN | SDL_WINDOW_FULLSCREEN_DESKTOP)) > 0); 75 } 76 77 public @property void Fullscreen(bool i) { 78 if (!i) { 79 //Windowed. 80 SDL_SetWindowFullscreen(this.window, 0); 81 return; 82 } 83 if (Borderless) { 84 //Fullscreen Borderless 85 SDL_SetWindowFullscreen(this.window, SDL_WINDOW_FULLSCREEN_DESKTOP); 86 return; 87 } 88 //Fullscreen 89 SDL_SetWindowFullscreen(this.window, SDL_WINDOW_FULLSCREEN); 90 } 91 92 //Renderer 93 public @property Renderer Drawing() { return this.renderer; } 94 95 /* 96 Returns the raw placement of the window. 97 Use RealPlacement if you want your application to be dpi aware. 98 */ 99 public @property Rectangle Placement() { 100 int x, y; 101 SDL_GetWindowPosition(this.window, &x, &y); 102 return new Rectangle(x, y, width, height); 103 } 104 105 /** 106 Returns the position of the window. 107 */ 108 public @property Vector2 Position() { 109 Rectangle r = Placement(); 110 return Vector2(r.X, r.Y); 111 } 112 113 /** 114 Allows you to set the position of the window. 115 */ 116 public @property void Position(Vector2 pos) { 117 SDL_SetWindowPosition(this.window, cast(int)pos.X, cast(int)pos.Y); 118 } 119 120 this(string name, Rectangle bounds) { 121 if (!SDL_Init(SDL_INIT_EVERYTHING) < 0) { 122 Logger.Fatal("Initialization of SDL2 failed!...\n{0}", SDL_GetError()); 123 } 124 125 //Set info. 126 this.start_bounds = bounds; 127 this.start_title = name; 128 129 //Cap info. 130 if (this.start_bounds is null) this.start_bounds = new Rectangle(WindowPosition.Undefined, WindowPosition.Undefined, 640, 480); 131 if (this.start_bounds.X == WindowPosition.Center) this.start_bounds.X = SDL_WINDOWPOS_CENTERED; 132 if (this.start_bounds.Y == WindowPosition.Center) this.start_bounds.Y = SDL_WINDOWPOS_CENTERED; 133 if (this.start_bounds.X == WindowPosition.Undefined) this.start_bounds.X = SDL_WINDOWPOS_UNDEFINED; 134 if (this.start_bounds.Y == WindowPosition.Undefined) this.start_bounds.Y = SDL_WINDOWPOS_UNDEFINED; 135 if (this.start_bounds.Width == WindowPosition.Undefined) this.start_bounds.Width = 640; 136 if (this.start_bounds.Height == WindowPosition.Undefined) this.start_bounds.Height = 480; 137 } 138 139 this (Rectangle bounds) { 140 this("My Game", bounds); 141 } 142 143 this() { 144 this(new Rectangle(WindowPosition.Undefined, WindowPosition.Undefined, 640, 480)); 145 } 146 147 ~this() { 148 if (this.window != null) Close(); 149 SDL_Quit(); 150 } 151 152 /** 153 Triggers an window info update. 154 */ 155 void UpdateInfo() { 156 SDL_GetWindowSize(this.window, &this.width, &this.height); 157 } 158 159 /** 160 Closes the window. 161 */ 162 void Close() { 163 SDL_DestroyWindow(this.window); 164 IMG_Quit(); 165 //Explicitly destroy window. 166 destroy(this.window); 167 } 168 169 /** 170 Puts the window in focus (ONLY WORKS ON SOME PLATFORMS!) 171 */ 172 void Focus() { 173 SDL_RaiseWindow(this.window); 174 } 175 176 /** 177 TODO 178 Sets the icon for the window. 179 */ 180 void SetIcon() { 181 //TODO: When rendering is there, set icon. 182 } 183 184 /** 185 Swaps the rendering buffer. 186 */ 187 void SwapBuffers() { 188 this.renderer.SwapBuffers(); 189 } 190 191 /** 192 Shows the window. 193 */ 194 void Show() { 195 Logger.Debug("Spawning window..."); 196 if (polyplex.ChosenBackend == polyplex.GraphicsBackend.Vulkan) this.window = SDL_CreateWindow(this.start_title.dup.ptr, this.start_bounds.X, this.start_bounds.Y, this.start_bounds.Width, this.start_bounds.Height, SDL_WINDOW_VULKAN); 197 else this.window = SDL_CreateWindow(this.start_title.toStringz, this.start_bounds.X, this.start_bounds.Y, this.start_bounds.Width, this.start_bounds.Height, SDL_WINDOW_OPENGL); 198 this.renderer = CreateBackendRenderer(this); 199 this.renderer.Init(this.window); 200 if (this.window == null) { 201 destroy(this.window); 202 Logger.Fatal("Window creation error: {0}", SDL_GetError()); 203 } 204 // Enable VSync by default. 205 VSync = VSyncState.VSync; 206 // Focus window 207 this.Focus(); 208 } 209 }