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