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