#include #include #include #include #include #include #include #include #include #include #include #include // TODO: Put fullscreen logic in different file, track fullscreen state and // enable dynamic toggling between fullscreen and window. namespace Gosu { namespace { // Mode guessing experimentally adapted from GLFW library. // http://glfw.sourceforge.net/ int findClosestVideoMode(int *w, int *h, int *bpp, int *refresh) { int mode, bestmode, match, bestmatch, rr, bestrr, success; DEVMODE dm; // Find best match bestmatch = 0x7fffffff; bestrr = 0x7fffffff; mode = bestmode = 0; do { dm.dmSize = sizeof(DEVMODE); success = EnumDisplaySettings(NULL, mode, &dm); if( success ) { match = dm.dmBitsPerPel - *bpp; if( match < 0 ) match = -match; match = (match << 25) | ((dm.dmPelsWidth - *w) * (dm.dmPelsWidth - *w) + (dm.dmPelsHeight - *h) * (dm.dmPelsHeight - *h)); if( match < bestmatch ) { bestmatch = match; bestmode = mode; bestrr = (dm.dmDisplayFrequency - *refresh) * (dm.dmDisplayFrequency - *refresh); } else if( match == bestmatch && *refresh > 0 ) { rr = (dm.dmDisplayFrequency - *refresh) * (dm.dmDisplayFrequency - *refresh); if( rr < bestrr ) { bestmatch = match; bestmode = mode; bestrr = rr; } } } ++mode; } while (success); // Get the parameters for the best matching display mode dm.dmSize = sizeof(DEVMODE); EnumDisplaySettings( NULL, bestmode, &dm ); *w = dm.dmPelsWidth; *h = dm.dmPelsHeight; *bpp = dm.dmBitsPerPel; *refresh = dm.dmDisplayFrequency; return bestmode; } void setVideoMode(int mode) { // Get the parameters for the best matching display mode DEVMODE dm; dm.dmSize = sizeof(DEVMODE); EnumDisplaySettings(NULL, mode, &dm); // Set which fields we want to specify dm.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT | DM_BITSPERPEL; // Change display setting dm.dmSize = sizeof(DEVMODE); if (ChangeDisplaySettings(&dm, CDS_FULLSCREEN) != DISP_CHANGE_SUCCESSFUL) throw std::runtime_error("Could not set fullscreen mode"); } void setupVSync() { char* extensions = (char*)glGetString(GL_EXTENSIONS); if (!strstr(extensions, "WGL_EXT_swap_control")) return; typedef void (APIENTRY *PFNWGLEXTSWAPCONTROLPROC) (int); PFNWGLEXTSWAPCONTROLPROC wglSwapIntervalEXT = (PFNWGLEXTSWAPCONTROLPROC) wglGetProcAddress("wglSwapIntervalEXT"); if (!wglSwapIntervalEXT) return; wglSwapIntervalEXT(1); } LRESULT CALLBACK windowProc(HWND wnd, UINT message, WPARAM wparam, LPARAM lparam) { LONG_PTR lptr = GetWindowLongPtr(wnd, GWLP_USERDATA); if (lptr) { Window* obj = reinterpret_cast(lptr); return obj->handleMessage(message, wparam, lparam); } else return DefWindowProc(wnd, message, wparam, lparam); } LPCTSTR windowClass() { static LPCTSTR name = 0; if (name) return name; WNDCLASS wc; wc.lpszClassName = L"Gosu::Window"; wc.style = CS_OWNDC; wc.lpfnWndProc = windowProc; wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hInstance = Win::instance(); wc.hIcon = 0; wc.hCursor = 0; wc.hbrBackground = 0; wc.lpszMenuName = 0; name = reinterpret_cast(::RegisterClass(&wc)); Win::check(name, "registering a window class"); return name; } } } struct Gosu::Window::Impl { HWND handle; HDC hdc; boost::scoped_ptr graphics; boost::scoped_ptr