1 module D2DGame.Window.Window; 2 3 import D2D; 4 5 /// Single-Window class wrapping SDL_Window. 6 class Window : IVerifiable, IDisposable, IRenderTarget 7 { 8 private: 9 SDL_Window * _handle; 10 int _id; 11 uint _fbo, _drb; 12 Texture _texture; 13 RectangleShape _displayPlane; 14 bool _direct = false; 15 mat4 _postMatrix; 16 17 public: 18 /// Static variable to a SDL GL Context. 19 static SDL_GLContext glContext = null; 20 21 /// Creates a new centered window with specified title and flags on a 800x480 resolution. 22 this(string title = "D2DGame", uint flags = WindowFlags.Default) { this(800, 480, title, flags); } 23 24 /// Creates a new centered window with specified dimensions, title and flags. 25 this(int width, int height, string title = "D2DGame", uint flags = WindowFlags.Default) 26 { 27 this(SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, width, height, title, flags); 28 } 29 30 /// Creates a new window with specified parameters. 31 this(int x, int y, int width, int height, string title, uint flags = WindowFlags.Default) 32 { 33 DerelictSDL2.load(); 34 DerelictSDL2Image.load(); 35 DerelictGL3.load(); 36 _handle = SDL_CreateWindow(title.toStringz(), x, y, width, height, flags | SDL_WINDOW_OPENGL); 37 if (!valid) 38 throw new Exception("Couldn't create window!"); 39 _id = SDL_GetWindowID(_handle); 40 41 SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 16); 42 SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 0); 43 44 SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE); 45 SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3); 46 SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 2); 47 48 glContext = SDL_GL_CreateContext(_handle); 49 50 SDL_GL_SetSwapInterval(0); 51 52 DerelictGL3.reload(); 53 54 if (SDL_GL_MakeCurrent(_handle, glContext) < 0) 55 throw new Exception(cast(string) fromStringz(SDL_GetError())); 56 57 glEnable(GL_BLEND); 58 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); 59 60 ShaderProgram.load(); 61 Texture.load(); 62 63 create(width, height); 64 65 _displayPlane = new RectangleShape(); 66 _displayPlane.setSize(vec2(1, 1)); 67 _displayPlane.texture = _texture; 68 69 _postMatrix = mat4.orthographic(0, 1, 0, 1, -1, 1); 70 } 71 72 ~this() 73 { 74 if (valid) 75 dispose(); 76 } 77 78 /// Polls a event from the stack and returns `true` if one was found. 79 bool pollEvent(ref WindowEvent event) 80 { 81 SDL_Event evt; 82 if (SDL_PollEvent(&evt)) 83 { 84 event = WindowEvent(); 85 event.fromSDL(evt); 86 return true; 87 } 88 return false; 89 } 90 91 /// Pushes `WindowEvent.Quit` to the event stack. 92 void quit() 93 { 94 SDL_Event sdlevent; 95 sdlevent.type = SDL_QUIT; 96 SDL_PushEvent(&sdlevent); 97 } 98 99 void bind() 100 { 101 if (!_direct) 102 { 103 glBindFramebuffer(GL_FRAMEBUFFER, _fbo); 104 glViewport(0, 0, _texture.width, _texture.height); 105 } 106 } 107 108 void resize(int width, int height) 109 { 110 _texture.resize(width, height); 111 projectionStack.set(mat4.orthographic(0, width, height, 0, -1, 1)); 112 } 113 114 void create(int width, int height) 115 { 116 glGenFramebuffers(1, &_fbo); 117 glBindFramebuffer(GL_FRAMEBUFFER, _fbo); 118 119 _texture = new Texture(); 120 _texture.minFilter = TextureFilterMode.Nearest; 121 _texture.magFilter = TextureFilterMode.Nearest; 122 _texture.create(width, height, GL_RGB, null); 123 124 glGenRenderbuffers(1, &_drb); 125 glBindRenderbuffer(GL_RENDERBUFFER, _drb); 126 glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, width, height); 127 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, _drb); 128 129 glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, _texture.id, 0); 130 131 glDrawBuffers(1, [GL_COLOR_ATTACHMENT0].ptr); 132 projectionStack.set(mat4.orthographic(0, width, height, 0, -1, 1)); 133 if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) 134 throw new Exception("Invalid Framebuffer"); 135 } 136 137 /// Texture containing rendered content. 138 @property Texture texture() 139 { 140 return _texture; 141 } 142 143 /// Displays rendered content to the window. 144 void display(ShaderProgram post = null) 145 { 146 glBindFramebuffer(GL_FRAMEBUFFER, 0); 147 glViewport(0, 0, width, height); 148 glClearColor(Color3.BlueViolet, 1); 149 glClear(GL_COLOR_BUFFER_BIT); 150 _direct = true; 151 projectionStack.push(); 152 projectionStack.set(_postMatrix); 153 matrixStack.push(); 154 matrixStack.set(mat4.identity); 155 draw(_displayPlane, post); 156 matrixStack.pop(); 157 projectionStack.pop(); 158 _direct = false; 159 SDL_GL_SwapWindow(_handle); 160 } 161 162 /// Dynamically sets the title of the window. 163 @property void title(string title) 164 { 165 SDL_SetWindowTitle(_handle, title.toStringz()); 166 } 167 168 /// Dynamically gets the title of the window. 169 @property string title() 170 { 171 string title = SDL_GetWindowTitle(_handle).fromStringz().dup; 172 return title; 173 } 174 175 /// Dynamically sets the width of the window. 176 @property void width(int width) 177 { 178 SDL_SetWindowSize(_handle, width, height); 179 resize(width, height); 180 } 181 182 /// Dynamically gets the width of the window. 183 @property int width() 184 { 185 int x, y; 186 SDL_GetWindowSize(_handle, &x, &y); 187 return x; 188 } 189 190 /// Dynamically sets the height of the window. 191 @property void height(int height) 192 { 193 SDL_SetWindowSize(_handle, width, height); 194 resize(width, height); 195 } 196 197 /// Dynamically gets the height of the window. 198 @property int height() 199 { 200 int x, y; 201 SDL_GetWindowSize(_handle, &x, &y); 202 return y; 203 } 204 205 /// Dynamically sets the maximum width of the window. 206 @property void maxWidth(int maxWidth) 207 { 208 SDL_SetWindowMaximumSize(_handle, maxWidth, maxHeight); 209 } 210 211 /// Dynamically gets the maximum width of the window. 212 @property int maxWidth() 213 { 214 int x, y; 215 SDL_GetWindowMaximumSize(_handle, &x, &y); 216 return x; 217 } 218 219 /// Dynamically sets the maximum height of the window. 220 @property void maxHeight(int maxHeight) 221 { 222 SDL_SetWindowMaximumSize(_handle, maxWidth, maxHeight); 223 } 224 225 /// Dynamically gets the maximum height of the window. 226 @property int maxHeight() 227 { 228 int x, y; 229 SDL_GetWindowMaximumSize(_handle, &x, &y); 230 return y; 231 } 232 233 /// Dynamically sets the minimum width of the window. 234 @property void minWidth(int minWidth) 235 { 236 SDL_SetWindowMinimumSize(_handle, minWidth, minHeight); 237 } 238 239 /// Dynamically gets the minimum width of the window. 240 @property int minWidth() 241 { 242 int x, y; 243 SDL_GetWindowMinimumSize(_handle, &x, &y); 244 return x; 245 } 246 247 /// Dynamically sets the minimum height of the window. 248 @property void minHeight(int minHeight) 249 { 250 SDL_SetWindowMinimumSize(_handle, minWidth, minHeight); 251 } 252 253 /// Dynamically gets the minimum height of the window. 254 @property int minHeight() 255 { 256 int x, y; 257 SDL_GetWindowMinimumSize(_handle, &x, &y); 258 return y; 259 } 260 261 /// Dynamically sets the x position of the window. 262 @property void x(int x) 263 { 264 SDL_SetWindowPosition(_handle, x, y); 265 } 266 267 /// Dynamically gets the x position of the window. 268 @property int x() 269 { 270 int x, y; 271 SDL_GetWindowPosition(_handle, &x, &y); 272 return x; 273 } 274 275 /// Dynamically sets the y position of the window. 276 @property void y(int y) 277 { 278 SDL_SetWindowPosition(_handle, x, y); 279 } 280 281 /// Dynamically gets the y position of the window. 282 @property int y() 283 { 284 int x, y; 285 SDL_GetWindowPosition(_handle, &x, &y); 286 return y; 287 } 288 289 /// Shows the window if hidden. 290 void show() 291 { 292 SDL_ShowWindow(_handle); 293 } 294 295 /// Hides the window. 296 void hide() 297 { 298 SDL_HideWindow(_handle); 299 } 300 301 /// Minimizes the window. 302 void minimize() 303 { 304 SDL_MinimizeWindow(_handle); 305 } 306 307 /// Maximizes the window. 308 void maximize() 309 { 310 SDL_MaximizeWindow(_handle); 311 } 312 313 /// Restores the window state from minimized or maximized. 314 void restore() 315 { 316 SDL_RestoreWindow(_handle); 317 } 318 319 /// Raises the window to top and focuses it for input. 320 void focus() 321 { 322 SDL_RaiseWindow(_handle); 323 } 324 325 /// Sets the icon to a Btimap. 326 void setIcon(Bitmap icon) 327 { 328 SDL_SetWindowIcon(_handle, icon.surface); 329 } 330 331 /// Closes the window and invalidates it. 332 /// See_Also: Window.close 333 void dispose() 334 { 335 SDL_DestroyWindow(_handle); 336 _handle = null; 337 } 338 339 /// Closes the window and invalidates it. 340 /// See_Also: Window.dispose 341 void close() 342 { 343 dispose(); 344 } 345 346 /// Returns if the is still open. 347 /// See_Also: Window.valid 348 @property bool open() 349 { 350 return valid; 351 } 352 353 /// Returns if the window is still open. 354 /// See_Also: Window.open 355 @property bool valid() 356 { 357 return _handle !is null; 358 } 359 } 360 361 /// 362 unittest 363 { 364 Window window = new Window(800, 600, "Unittest"); 365 366 assert(window.valid); 367 368 assert(window.title == "Unittest"); 369 window.title = "Window Title"; 370 assert(window.title == "Window Title"); 371 // Automatic conversion from c-strings to D-strings 372 373 assert(window.width == 800); 374 375 window.close(); 376 assert(!window.valid); 377 }