1 module gfm.sdl2.window; 2 3 import std.string; 4 5 import derelict.sdl2.sdl; 6 7 import std.logger; 8 9 import gfm.sdl2.sdl, 10 gfm.sdl2.surface; 11 12 /// SDL Window wrapper. 13 /// There is two ways to receive events, either by polling a SDL2 object, 14 /// or by overriding the event callbacks. 15 class SDL2Window 16 { 17 public 18 { 19 /// Creates a SDL window which targets a window. 20 /// See_also: $(LINK http://wiki.libsdl.org/SDL_CreateWindow) 21 /// Throws: $(D SDL2Exception) on error. 22 this(SDL2 sdl2, int x, int y, int width, int height, int flags) 23 { 24 _sdl2 = sdl2; 25 _logger = sdl2._logger; 26 _surface = null; 27 _glContext = null; 28 _surfaceMustBeRenewed = false; 29 30 bool OpenGL = (flags & SDL_WINDOW_OPENGL) != 0; 31 32 if (OpenGL) 33 { 34 // put here your desired context profile and version 35 36 //SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3); 37 //SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3); 38 //SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE); 39 //SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, SDL_GL_CONTEXT_DEBUG_FLAG | SDL_GL_CONTEXT_FORWARD_COMPATIBLE_FLAG); 40 41 // force debug OpenGL context creation in debug mode 42 debug 43 { 44 SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, SDL_GL_CONTEXT_DEBUG_FLAG); 45 } 46 } 47 48 _window = SDL_CreateWindow(toStringz(""), x, y, width, height, flags); 49 if (_window == null) 50 throw new SDL2Exception("SDL_CreateWindow failed: " ~ _sdl2.getErrorString()); 51 52 _id = SDL_GetWindowID(_window); 53 54 // register window for event dispatch 55 _sdl2.registerWindow(this); 56 57 if (OpenGL) 58 _glContext = new SDL2GLContext(this); 59 } 60 61 /// Releases the SDL resource. 62 /// See_also: $(LINK http://wiki.libsdl.org/SDL_DestroyWindow) 63 final void close() 64 { 65 if (_glContext !is null) 66 { 67 _glContext.close(); 68 _glContext = null; 69 } 70 71 if (_window !is null) 72 { 73 _sdl2.unregisterWindow(this); 74 SDL_DestroyWindow(_window); 75 _window = null; 76 } 77 } 78 79 /// 80 ~this() 81 { 82 close(); 83 } 84 85 /// See_also: $(LINK http://wiki.libsdl.org/SDL_SetWindowFullscreen) 86 /// Throws: $(D SDL2Exception) on error. 87 deprecated("Use setFullscreenSetting instead") final void setFullscreen(bool fullscreen) 88 { 89 SDL_SetWindowFullscreen(_window, fullscreen ? SDL_WINDOW_FULLSCREEN : 0); 90 } 91 92 /// See_also: $(LINK http://wiki.libsdl.org/SDL_SetWindowFullscreen) 93 /// Throws: $(D SDL2Exception) on error. 94 final void setFullscreenSetting(uint flags) 95 { 96 if (SDL_SetWindowFullscreen(_window, flags) != 0) 97 _sdl2.throwSDL2Exception("SDL_SetWindowFullscreen"); 98 } 99 100 /// Returns: X window coordinate. 101 /// See_also: $(LINK http://wiki.libsdl.org/SDL_GetWindowPosition) 102 final int getX() 103 { 104 return getPosition().x; 105 } 106 107 /// Returns: Y window coordinate. 108 /// See_also: $(LINK http://wiki.libsdl.org/SDL_GetWindowPosition) 109 final int getY() 110 { 111 return getPosition().y; 112 } 113 114 /// Returns: Window coordinates. 115 /// See_also: $(LINK http://wiki.libsdl.org/SDL_GetWindowPosition) 116 final SDL_Point getPosition() 117 { 118 int x, y; 119 SDL_GetWindowPosition(_window, &x, &y); 120 return SDL_Point(x, y); 121 } 122 123 /// See_also: $(LINK http://wiki.libsdl.org/SDL_SetWindowPosition) 124 final void setPosition(int positionX, int positionY) 125 { 126 SDL_SetWindowPosition(_window, positionX, positionY); 127 } 128 129 /// See_also: $(LINK http://wiki.libsdl.org/SDL_SetWindowSize) 130 final void setSize(int width, int height) 131 { 132 SDL_SetWindowSize(_window, width, height); 133 } 134 135 /// See_also: $(LINK http://wiki.libsdl.org/SDL_GetWindowSize) 136 /// Returns: Window size in pixels. 137 final SDL_Point getSize() 138 { 139 int w, h; 140 SDL_GetWindowSize(_window, &w, &h); 141 return SDL_Point(w, h); 142 } 143 144 /// See_also: $(LINK http://wiki.libsdl.org/SDL_GetWindowSize) 145 /// Returns: Window width in pixels. 146 final int getWidth() 147 { 148 int w, h; 149 SDL_GetWindowSize(_window, &w, &h); 150 return w; 151 } 152 153 /// See_also: $(LINK http://wiki.libsdl.org/SDL_GetWindowSize) 154 /// Returns: Window height in pixels. 155 final int getHeight() 156 { 157 int w, h; 158 SDL_GetWindowSize(_window, &w, &h); 159 return h; 160 } 161 162 /// See_also: $(LINK http://wiki.libsdl.org/SDL_SetWindowTitle) 163 final void setTitle(string title) 164 { 165 SDL_SetWindowTitle(_window, toStringz(title)); 166 } 167 168 /// See_also: $(LINK http://wiki.libsdl.org/SDL_ShowWindow) 169 final void show() 170 { 171 SDL_ShowWindow(_window); 172 } 173 174 /// See_also: $(LINK http://wiki.libsdl.org/SDL_HideWindow) 175 final void hide() 176 { 177 SDL_HideWindow(_window); 178 } 179 180 /// See_also: $(LINK http://wiki.libsdl.org/SDL_MinimizeWindow) 181 final void minimize() 182 { 183 SDL_MinimizeWindow(_window); 184 } 185 186 /// See_also: $(LINK http://wiki.libsdl.org/SDL_MaximizeWindow) 187 final void maximize() 188 { 189 SDL_MaximizeWindow(_window); 190 } 191 192 /// Returns: Window surface. 193 /// See_also: $(LINK http://wiki.libsdl.org/SDL_GetWindowSurface) 194 /// Throws: $(D SDL2Exception) on error. 195 final SDL2Surface surface() 196 { 197 if (!hasValidSurface()) 198 { 199 SDL_Surface* internalSurface = SDL_GetWindowSurface(_window); 200 if (internalSurface is null) 201 _sdl2.throwSDL2Exception("SDL_GetWindowSurface"); 202 203 // renews surface as needed 204 _surfaceMustBeRenewed = false; 205 _surface = new SDL2Surface(_sdl2, internalSurface, SDL2Surface.Owned.NO); 206 } 207 return _surface; 208 } 209 210 /// Submit changes to the window surface. 211 /// See_also: $(LINK http://wiki.libsdl.org/SDL_UpdateWindowSurface) 212 /// Throws: $(D SDL2Exception) on error. 213 final void updateSurface() 214 { 215 if (!hasValidSurface()) 216 surface(); 217 218 int res = SDL_UpdateWindowSurface(_window); 219 if (res != 0) 220 _sdl2.throwSDL2Exception("SDL_UpdateWindowSurface"); 221 222 } 223 224 /// Returns: Window ID. 225 /// See_also: $(LINK http://wiki.libsdl.org/SDL_GetWindowID) 226 final int id() 227 { 228 return _id; 229 } 230 231 /// Returns: System-specific window information, useful to use a third-party rendering library. 232 /// See_also: $(LINK http://wiki.libsdl.org/SDL_GetWindowWMInfo) 233 /// Throws: $(D SDL2Exception) on error. 234 SDL_SysWMinfo getWindowInfo() 235 { 236 SDL_SysWMinfo info; 237 SDL_VERSION(&info.version_); 238 int res = SDL_GetWindowWMInfo(_window, &info); 239 if (res != SDL_TRUE) 240 _sdl2.throwSDL2Exception("SDL_GetWindowWMInfo"); 241 return info; 242 } 243 244 // override these function, they are event callbacks 245 246 /// 247 void onShow() 248 { 249 } 250 251 /// 252 void onHide() 253 { 254 } 255 256 /// 257 void onExposed() 258 { 259 _surfaceMustBeRenewed = true; 260 } 261 262 /// 263 void onMove(int x, int y) 264 { 265 } 266 267 /// 268 void onResized(int width, int height) 269 { 270 _surfaceMustBeRenewed = true; 271 } 272 273 /// 274 void onSizeChanged() 275 { 276 _surfaceMustBeRenewed = true; 277 } 278 279 /// 280 void onMinimized() 281 { 282 _surfaceMustBeRenewed = true; 283 } 284 285 /// 286 void onMaximized() 287 { 288 _surfaceMustBeRenewed = true; 289 } 290 291 /// 292 void onRestored() 293 { 294 } 295 296 /// 297 void onEnter() 298 { 299 } 300 301 /// 302 void onLeave() 303 { 304 } 305 306 /// 307 void onFocusGained() 308 { 309 } 310 311 /// 312 void onFocusLost() 313 { 314 } 315 316 /// 317 void onClose() 318 { 319 } 320 321 /// Swap OpenGL buffers. 322 /// See_also: $(LINK http://wiki.libsdl.org/SDL_GL_SwapWindow) 323 /// Throws: $(D SDL2Exception) on error. 324 void swapBuffers() 325 { 326 if (_glContext is null) 327 throw new SDL2Exception("swapBuffers failed: not an OpenGL window"); 328 SDL_GL_SwapWindow(_window); 329 } 330 } 331 332 package 333 { 334 SDL2 _sdl2; 335 SDL_Window* _window; 336 } 337 338 private 339 { 340 Logger _logger; 341 SDL2Surface _surface; 342 SDL2GLContext _glContext; 343 uint _id; 344 345 bool _surfaceMustBeRenewed; 346 347 bool hasValidSurface() 348 { 349 return (!_surfaceMustBeRenewed) && (_surface !is null); 350 } 351 } 352 } 353 354 /// SDL OpenGL context wrapper. You probably don't need to use it directly. 355 final class SDL2GLContext 356 { 357 public 358 { 359 /// Creates for a given SDL window. 360 this(SDL2Window window) 361 { 362 _window = window; 363 _context = SDL_GL_CreateContext(window._window); 364 _initialized = true; 365 } 366 367 ~this() 368 { 369 close(); 370 } 371 372 /// Release the associated SDL ressource. 373 void close() 374 { 375 if (_initialized) 376 { 377 // work-around Issue #19 378 // SDL complains with log message "wglMakeCurrent(): The handle is invalid." 379 // in the SDL_DestroyWindow() call if we destroy the OpenGL context before-hand 380 // 381 // SDL_GL_DeleteContext(_context); 382 _initialized = false; 383 } 384 } 385 386 /// Makes this OpenGL context current. 387 /// Throws: $(D SDL2Exception) on error. 388 void makeCurrent() 389 { 390 if (0 != SDL_GL_MakeCurrent(_window._window, _context)) 391 _window._sdl2.throwSDL2Exception("SDL_GL_MakeCurrent"); 392 } 393 } 394 395 package 396 { 397 SDL_GLContext _context; 398 SDL2Window _window; 399 } 400 401 private 402 { 403 bool _initialized; 404 } 405 } 406