Window.cpp 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342
  1. /**
  2. * Copyright (c) 2006-2013 LOVE Development Team
  3. *
  4. * This software is provided 'as-is', without any express or implied
  5. * warranty. In no event will the authors be held liable for any damages
  6. * arising from the use of this software.
  7. *
  8. * Permission is granted to anyone to use this software for any purpose,
  9. * including commercial applications, and to alter it and redistribute it
  10. * freely, subject to the following restrictions:
  11. *
  12. * 1. The origin of this software must not be misrepresented; you must not
  13. * claim that you wrote the original software. If you use this software
  14. * in a product, an acknowledgment in the product documentation would be
  15. * appreciated but is not required.
  16. * 2. Altered source versions must be plainly marked as such, and must not be
  17. * misrepresented as being the original software.
  18. * 3. This notice may not be removed or altered from any source distribution.
  19. **/
  20. // LOVE
  21. #include "common/config.h"
  22. #include "Window.h"
  23. // SDL
  24. #include <SDL.h>
  25. // STL
  26. #include <iostream>
  27. namespace love
  28. {
  29. namespace window
  30. {
  31. namespace sdl
  32. {
  33. Window::Window()
  34. : windowTitle("")
  35. , created(false)
  36. {
  37. if (SDL_InitSubSystem(SDL_INIT_VIDEO) < 0)
  38. throw love::Exception(SDL_GetError());
  39. }
  40. Window::~Window()
  41. {
  42. SDL_QuitSubSystem(SDL_INIT_VIDEO);
  43. }
  44. Window::_currentMode::_currentMode()
  45. : width(800)
  46. , height(600)
  47. , flags()
  48. {
  49. }
  50. bool Window::setWindow(int width, int height, graphics::Graphics *graphics, WindowFlags *flags)
  51. {
  52. if (graphics)
  53. graphics->unSetMode();
  54. bool fullscreen = false;
  55. bool vsync = true;
  56. int fsaa = 0;
  57. bool resizable = false;
  58. bool borderless = false;
  59. bool centered = true;
  60. if (flags)
  61. {
  62. fullscreen = flags->fullscreen;
  63. vsync = flags->vsync;
  64. fsaa = flags->fsaa;
  65. resizable = flags->resizable;
  66. borderless = flags->borderless;
  67. centered = flags->centered;
  68. }
  69. bool mouseVisible = getMouseVisible();
  70. int keyrepeatDelay, keyrepeatInterval;
  71. SDL_GetKeyRepeat(&keyrepeatDelay, &keyrepeatInterval);
  72. // We need to restart the subsystem for two reasons:
  73. // 1) Special case for fullscreen -> windowed. Windows XP did not
  74. // work well with "normal" display mode change in this case.
  75. // The application window does leave fullscreen, but the desktop
  76. // resolution does not revert to the correct one. Restarting the
  77. // SDL video subsystem does the trick, though.
  78. // 2) Restart the event system (for whatever reason the event system
  79. // started and stopped with SDL_INIT_VIDEO, see:
  80. // http://sdl.beuc.net/sdl.wiki/Introduction_to_Events)
  81. // because the mouse position will not be able to exceed
  82. // the previous' video mode window size (i.e. alway
  83. // love.mouse.getX() < 800 when switching from 800x600 to a
  84. // higher resolution)
  85. SDL_QuitSubSystem(SDL_INIT_VIDEO);
  86. if (centered) // Window should be centered.
  87. SDL_putenv(const_cast<char *>("SDL_VIDEO_CENTERED=center"));
  88. else
  89. SDL_putenv(const_cast<char *>("SDL_VIDEO_CENTERED="));
  90. if (SDL_InitSubSystem(SDL_INIT_VIDEO) < 0)
  91. {
  92. std::cout << "Could not init SDL_VIDEO: " << SDL_GetError() << std::endl;
  93. return false;
  94. }
  95. // Set caption.
  96. setWindowTitle(windowTitle);
  97. setMouseVisible(mouseVisible);
  98. SDL_EnableKeyRepeat(keyrepeatDelay, keyrepeatInterval);
  99. // Set GL attributes
  100. SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8);
  101. SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8);
  102. SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8);
  103. SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 8);
  104. SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
  105. SDL_GL_SetAttribute(SDL_GL_SWAP_CONTROL, (vsync ? 1 : 0));
  106. SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 1);
  107. // FSAA
  108. SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, (fsaa > 0) ? 1 : 0);
  109. SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, (fsaa > 0) ? fsaa : 0);
  110. Uint32 sdlflags = SDL_OPENGL;
  111. // Flags
  112. if (fullscreen)
  113. sdlflags |= SDL_FULLSCREEN;
  114. if (resizable)
  115. sdlflags |= SDL_RESIZABLE;
  116. if (borderless)
  117. sdlflags |= SDL_NOFRAME;
  118. // Have SDL set the video mode.
  119. SDL_Surface *surface;
  120. if ((surface = SDL_SetVideoMode(width, height, 32, sdlflags)) == 0)
  121. {
  122. bool failed = true;
  123. if (fsaa > 0)
  124. {
  125. // FSAA might have caused the failure, disable it and try again
  126. SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, 0);
  127. SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 0);
  128. failed = (surface = SDL_SetVideoMode(width, height, 32, sdlflags)) == 0;
  129. }
  130. if (failed)
  131. {
  132. std::cerr << "Could not set video mode: " << SDL_GetError() << std::endl;
  133. return false;
  134. }
  135. }
  136. created = true;
  137. const SDL_VideoInfo *videoinfo = SDL_GetVideoInfo();
  138. width = videoinfo->current_w;
  139. height = videoinfo->current_h;
  140. int buffers;
  141. int samples;
  142. SDL_GL_GetAttribute(SDL_GL_MULTISAMPLEBUFFERS, &buffers);
  143. SDL_GL_GetAttribute(SDL_GL_MULTISAMPLESAMPLES, &samples);
  144. // Don't fail because of this, but issue a warning.
  145. if ((!buffers && fsaa) || (samples != fsaa))
  146. {
  147. std::cerr << "Warning, FSAA setting failed! (Result: buffers: " << buffers << ", samples: " << samples << ")" << std::endl;
  148. fsaa = (buffers > 0) ? samples : 0;
  149. }
  150. // Get the actual vsync status
  151. int real_vsync;
  152. SDL_GL_GetAttribute(SDL_GL_SWAP_CONTROL, &real_vsync);
  153. // Set the new display mode as the current display mode.
  154. currentMode.width = width;
  155. currentMode.height = height;
  156. currentMode.flags.fsaa = fsaa;
  157. currentMode.flags.fullscreen = fullscreen;
  158. currentMode.flags.vsync = (real_vsync != 0);
  159. currentMode.flags.resizable = ((surface->flags & SDL_RESIZABLE) != 0);
  160. currentMode.flags.borderless = ((surface->flags & SDL_NOFRAME) != 0);
  161. currentMode.flags.centered = centered;
  162. if (graphics)
  163. graphics->setMode(width, height);
  164. return true;
  165. }
  166. void Window::getWindow(int &width, int &height, WindowFlags &flags) const
  167. {
  168. width = currentMode.width;
  169. height = currentMode.height;
  170. flags = currentMode.flags;
  171. }
  172. bool Window::checkWindowSize(int width, int height, bool fullscreen) const
  173. {
  174. Uint32 sdlflags = fullscreen ? (SDL_OPENGL | SDL_FULLSCREEN) : SDL_OPENGL;
  175. // Check if mode is supported
  176. int bpp = SDL_VideoModeOK(width, height, 32, sdlflags);
  177. return (bpp >= 16);
  178. }
  179. typedef Window::WindowSize WindowSize;
  180. WindowSize *Window::getFullscreenSizes(int &n) const
  181. {
  182. SDL_Rect **modes = SDL_ListModes(0, SDL_OPENGL | SDL_FULLSCREEN);
  183. if (modes == (SDL_Rect **)0 || modes == (SDL_Rect **)-1)
  184. {
  185. n = 0;
  186. return NULL;
  187. }
  188. n = 0;
  189. for (int i = 0; modes[i]; i++)
  190. n++;
  191. WindowSize *sizes = new WindowSize[n];
  192. for (int i = 0; i < n; i++)
  193. {
  194. WindowSize w = {modes[i]->w, modes[i]->h};
  195. sizes[i] = w;
  196. }
  197. return sizes;
  198. }
  199. int Window::getWidth() const
  200. {
  201. return currentMode.width;
  202. }
  203. int Window::getHeight() const
  204. {
  205. return currentMode.height;
  206. }
  207. bool Window::isCreated() const
  208. {
  209. return created;
  210. }
  211. void Window::setWindowTitle(const std::string &title)
  212. {
  213. windowTitle = title;
  214. SDL_WM_SetCaption(windowTitle.c_str(), 0);
  215. }
  216. std::string Window::getWindowTitle() const
  217. {
  218. // not a reference
  219. // because we want this untouched
  220. // const std::string& might be an option
  221. return windowTitle;
  222. }
  223. bool Window::setIcon(love::image::ImageData *imgd)
  224. {
  225. Uint32 rmask, gmask, bmask, amask;
  226. #ifdef LOVE_BIG_ENDIAN
  227. rmask = 0xFF000000;
  228. gmask = 0x00FF0000;
  229. bmask = 0x0000FF00;
  230. amask = 0x000000FF;
  231. #else
  232. rmask = 0x000000FF;
  233. gmask = 0x0000FF00;
  234. bmask = 0x00FF0000;
  235. amask = 0xFF000000;
  236. #endif
  237. int w = static_cast<int>(imgd->getWidth());
  238. int h = static_cast<int>(imgd->getHeight());
  239. int pitch = static_cast<int>(imgd->getWidth() * 4);
  240. SDL_Surface *icon = SDL_CreateRGBSurfaceFrom(imgd->getData(), w, h, 32, pitch, rmask, gmask, bmask, amask);
  241. SDL_WM_SetIcon(icon, NULL);
  242. SDL_FreeSurface(icon);
  243. return true;
  244. }
  245. void Window::swapBuffers()
  246. {
  247. SDL_GL_SwapBuffers();
  248. }
  249. bool Window::hasFocus() const
  250. {
  251. return (SDL_GetAppState() & SDL_APPINPUTFOCUS) != 0;
  252. }
  253. bool Window::hasMouseFocus() const
  254. {
  255. return (SDL_GetAppState() & SDL_APPMOUSEFOCUS) != 0;
  256. }
  257. bool Window::isVisible() const
  258. {
  259. return (SDL_GetAppState() & SDL_APPACTIVE) != 0;
  260. }
  261. void Window::setMouseVisible(bool visible)
  262. {
  263. SDL_ShowCursor(visible ? SDL_ENABLE : SDL_DISABLE);
  264. }
  265. bool Window::getMouseVisible() const
  266. {
  267. return (SDL_ShowCursor(SDL_QUERY) == SDL_ENABLE) ? true : false;
  268. }
  269. love::window::Window *Window::getSingleton()
  270. {
  271. if (!singleton)
  272. singleton = new Window();
  273. else
  274. singleton->retain();
  275. return singleton;
  276. }
  277. const char *Window::getName() const
  278. {
  279. return "love.window.sdl";
  280. }
  281. } // sdl
  282. } // window
  283. } // love