int _glfwPlatformCreateWindow(_GLFWwindow* window, const _GLFWwndconfig* wndconfig, const _GLFWctxconfig* ctxconfig, const _GLFWfbconfig* fbconfig) { int status; if (!createWindow(window, wndconfig, ctxconfig, fbconfig)) return GL_FALSE; status = _glfwAnalyzeContext(window, ctxconfig, fbconfig); if (status == _GLFW_RECREATION_IMPOSSIBLE) return GL_FALSE; if (status == _GLFW_RECREATION_REQUIRED) { // Some window hints require us to re-create the context using WGL // extensions retrieved through the current context, as we cannot check // for WGL extensions or retrieve WGL entry points before we have a // current context (actually until we have implicitly loaded the ICD) // Yes, this is strange, and yes, this is the proper way on Win32 // As Windows only allows you to set the pixel format once for a // window, we need to destroy the current window and create a new one // to be able to use the new pixel format // Technically, it may be possible to keep the old window around if // we're just creating an OpenGL 3.0+ context with the same pixel // format, but it's not worth the added code complexity // First we clear the current context (the one we just created) // This is usually done by glfwDestroyWindow, but as we're not doing // full GLFW window destruction, it's duplicated here _glfwPlatformMakeContextCurrent(NULL); // Next destroy the Win32 window and WGL context (without resetting or // destroying the GLFW window object) destroyWindow(window); // ...and then create them again, this time with better APIs if (!createWindow(window, wndconfig, ctxconfig, fbconfig)) return GL_FALSE; } if (window->monitor) { _glfwPlatformShowWindow(window); if (!enterFullscreenMode(window)) return GL_FALSE; } return GL_TRUE; }
GLFWAPI void glfwMakeContextCurrent(GLFWwindow* handle) { _GLFWwindow* window = (_GLFWwindow*) handle; _GLFW_REQUIRE_INIT(); if (_glfwPlatformGetCurrentContext() == window) return; _glfwPlatformMakeContextCurrent(window); }
GLFWAPI void glfwDestroyWindow(GLFWwindow handle) { _GLFWwindow* window = (_GLFWwindow*) handle; if (!_glfwInitialized) { _glfwSetError(GLFW_NOT_INITIALIZED, NULL); return; } // Allow closing of NULL (to match the behavior of free) if (window == NULL) return; // Clear all callbacks to avoid exposing a half torn-down window object window->windowPosCallback = NULL; window->windowSizeCallback = NULL; window->windowCloseCallback = NULL; window->windowRefreshCallback = NULL; window->windowFocusCallback = NULL; window->windowIconifyCallback = NULL; window->mouseButtonCallback = NULL; window->cursorPosCallback = NULL; window->cursorEnterCallback = NULL; window->scrollCallback = NULL; window->keyCallback = NULL; window->charCallback = NULL; // The window's context must not be current on another thread when the // window is destroyed if (window == _glfwPlatformGetCurrentContext()) _glfwPlatformMakeContextCurrent(NULL); // Clear the focused window pointer if this is the focused window if (window == _glfwLibrary.focusedWindow) _glfwLibrary.focusedWindow = NULL; _glfwPlatformDestroyWindow(window); // Unlink window from global linked list { _GLFWwindow** prev = &_glfwLibrary.windowListHead; while (*prev != window) prev = &((*prev)->next); *prev = window->next; } free(window); }
GLFWAPI void glfwMakeContextCurrent(GLFWwindow* handle) { _GLFWwindow* window = (_GLFWwindow*) handle; _GLFW_REQUIRE_INIT(); if (window->context.api == GLFW_NO_API) { _glfwInputError(GLFW_NO_WINDOW_CONTEXT, NULL); return; } _glfwPlatformMakeContextCurrent(window); }
GLFWAPI void glfwMakeContextCurrent(GLFWwindow* handle) { _GLFWwindow* window = (_GLFWwindow*) handle; if (!_glfwInitialized) { _glfwInputError(GLFW_NOT_INITIALIZED, NULL); return; } if (_glfwPlatformGetCurrentContext() == window) return; _glfwPlatformMakeContextCurrent(window); }
GLFWAPI void glfwMakeContextCurrent(GLFWwindow handle) { _GLFWwindow* window = (_GLFWwindow*) handle; if (!_glfwInitialized) { _glfwSetError(GLFW_NOT_INITIALIZED, NULL); return; } if (_glfwLibrary.currentWindow == window) return; _glfwPlatformMakeContextCurrent(window); _glfwLibrary.currentWindow = window; }
GLFWAPI void glfwDestroyWindow(GLFWwindow* handle) { _GLFWwindow* window = (_GLFWwindow*) handle; if (!_glfwInitialized) { _glfwInputError(GLFW_NOT_INITIALIZED, NULL); return; } // Allow closing of NULL (to match the behavior of free) if (window == NULL) return; // Clear all callbacks to avoid exposing a half torn-down window object memset(&window->callbacks, 0, sizeof(window->callbacks)); // The window's context must not be current on another thread when the // window is destroyed if (window == _glfwPlatformGetCurrentContext()) _glfwPlatformMakeContextCurrent(NULL); // Clear the focused window pointer if this is the focused window if (window == _glfw.focusedWindow) _glfw.focusedWindow = NULL; _glfwPlatformDestroyWindow(window); // Unlink window from global linked list { _GLFWwindow** prev = &_glfw.windowListHead; while (*prev != window) prev = &((*prev)->next); *prev = window->next; } free(window); }
GLFWAPI GLFWwindow* glfwCreateWindow(int width, int height, const char* title, GLFWmonitor* monitor, GLFWwindow* share) { _GLFWfbconfig fbconfig; _GLFWctxconfig ctxconfig; _GLFWwndconfig wndconfig; _GLFWwindow* window; _GLFWwindow* previous; assert(title != NULL); _GLFW_REQUIRE_INIT_OR_RETURN(NULL); if (width <= 0 || height <= 0) { _glfwInputError(GLFW_INVALID_VALUE, "Invalid window size %ix%i", width, height); return NULL; } fbconfig = _glfw.hints.framebuffer; ctxconfig = _glfw.hints.context; wndconfig = _glfw.hints.window; wndconfig.width = width; wndconfig.height = height; wndconfig.title = title; ctxconfig.share = (_GLFWwindow*) share; if (ctxconfig.share) { if (ctxconfig.share->context.api == GLFW_NO_API) { _glfwInputError(GLFW_NO_WINDOW_CONTEXT, NULL); return NULL; } } if (!_glfwIsValidContextConfig(&ctxconfig)) return NULL; window = calloc(1, sizeof(_GLFWwindow)); window->next = _glfw.windowListHead; _glfw.windowListHead = window; window->videoMode.width = width; window->videoMode.height = height; window->videoMode.redBits = fbconfig.redBits; window->videoMode.greenBits = fbconfig.greenBits; window->videoMode.blueBits = fbconfig.blueBits; window->videoMode.refreshRate = _glfw.hints.refreshRate; window->monitor = (_GLFWmonitor*) monitor; window->resizable = wndconfig.resizable; window->decorated = wndconfig.decorated; window->autoIconify = wndconfig.autoIconify; window->floating = wndconfig.floating; window->cursorMode = GLFW_CURSOR_NORMAL; window->minwidth = GLFW_DONT_CARE; window->minheight = GLFW_DONT_CARE; window->maxwidth = GLFW_DONT_CARE; window->maxheight = GLFW_DONT_CARE; window->numer = GLFW_DONT_CARE; window->denom = GLFW_DONT_CARE; // Save the currently current context so it can be restored later previous = _glfwPlatformGetCurrentContext(); // Open the actual window and create its context if (!_glfwPlatformCreateWindow(window, &wndconfig, &ctxconfig, &fbconfig)) { glfwDestroyWindow((GLFWwindow*) window); _glfwPlatformMakeContextCurrent(previous); return NULL; } if (ctxconfig.api != GLFW_NO_API) { _glfwPlatformMakeContextCurrent(window); // Retrieve the actual (as opposed to requested) context attributes if (!_glfwRefreshContextAttribs(&ctxconfig)) { glfwDestroyWindow((GLFWwindow*) window); _glfwPlatformMakeContextCurrent(previous); return NULL; } // Restore the previously current context (or NULL) _glfwPlatformMakeContextCurrent(previous); } if (window->monitor) { int width, height; _glfwPlatformGetWindowSize(window, &width, &height); window->cursorPosX = width / 2; window->cursorPosY = height / 2; _glfwPlatformSetCursorPos(window, window->cursorPosX, window->cursorPosY); } else { if (wndconfig.visible) { _glfwPlatformShowWindow(window); if (wndconfig.focused) _glfwPlatformFocusWindow(window); } } return (GLFWwindow*) window; }
// Window callback function (handles window events) // static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { _GLFWwindow* window = (_GLFWwindow*) GetWindowLongPtrW(hWnd, 0); switch (uMsg) { case WM_NCCREATE: { CREATESTRUCTW* cs = (CREATESTRUCTW*) lParam; SetWindowLongPtrW(hWnd, 0, (LONG_PTR) cs->lpCreateParams); break; } case WM_SETFOCUS: { if (window->cursorMode != GLFW_CURSOR_NORMAL) _glfwPlatformApplyCursorMode(window); if (window->monitor && window->autoIconify) enterFullscreenMode(window); _glfwInputWindowFocus(window, GL_TRUE); return 0; } case WM_KILLFOCUS: { if (window->cursorMode != GLFW_CURSOR_NORMAL) restoreCursor(window); if (window->monitor && window->autoIconify) { _glfwPlatformIconifyWindow(window); leaveFullscreenMode(window); } _glfwInputWindowFocus(window, GL_FALSE); return 0; } case WM_SYSCOMMAND: { switch (wParam & 0xfff0) { case SC_SCREENSAVE: case SC_MONITORPOWER: { if (window->monitor) { // We are running in full screen mode, so disallow // screen saver and screen blanking return 0; } else break; } // User trying to access application menu using ALT? case SC_KEYMENU: return 0; } break; } case WM_CLOSE: { _glfwInputWindowCloseRequest(window); return 0; } case WM_KEYDOWN: case WM_SYSKEYDOWN: { const int scancode = (lParam >> 16) & 0x1ff; const int key = translateKey(wParam, lParam); if (key == _GLFW_KEY_INVALID) break; _glfwInputKey(window, key, scancode, GLFW_PRESS, getKeyMods()); break; } case WM_CHAR: { _glfwInputChar(window, (unsigned int) wParam, getKeyMods(), GL_TRUE); return 0; } case WM_SYSCHAR: { _glfwInputChar(window, (unsigned int) wParam, getKeyMods(), GL_FALSE); return 0; } case WM_UNICHAR: { // This message is not sent by Windows, but is sent by some // third-party input method engines if (wParam == UNICODE_NOCHAR) { // Returning TRUE here announces support for this message return TRUE; } _glfwInputChar(window, (unsigned int) wParam, getKeyMods(), GL_TRUE); return FALSE; } case WM_KEYUP: case WM_SYSKEYUP: { const int mods = getKeyMods(); const int scancode = (lParam >> 16) & 0x1ff; const int key = translateKey(wParam, lParam); if (key == _GLFW_KEY_INVALID) break; if (wParam == VK_SHIFT) { // Release both Shift keys on Shift up event, as only one event // is sent even if both keys are released _glfwInputKey(window, GLFW_KEY_LEFT_SHIFT, scancode, GLFW_RELEASE, mods); _glfwInputKey(window, GLFW_KEY_RIGHT_SHIFT, scancode, GLFW_RELEASE, mods); } else if (wParam == VK_SNAPSHOT) { // Key down is not reported for the print screen key _glfwInputKey(window, key, scancode, GLFW_PRESS, mods); _glfwInputKey(window, key, scancode, GLFW_RELEASE, mods); } else _glfwInputKey(window, key, scancode, GLFW_RELEASE, mods); break; } case WM_LBUTTONDOWN: case WM_RBUTTONDOWN: case WM_MBUTTONDOWN: case WM_XBUTTONDOWN: { const int mods = getKeyMods(); SetCapture(hWnd); if (uMsg == WM_LBUTTONDOWN) _glfwInputMouseClick(window, GLFW_MOUSE_BUTTON_LEFT, GLFW_PRESS, mods); else if (uMsg == WM_RBUTTONDOWN) _glfwInputMouseClick(window, GLFW_MOUSE_BUTTON_RIGHT, GLFW_PRESS, mods); else if (uMsg == WM_MBUTTONDOWN) _glfwInputMouseClick(window, GLFW_MOUSE_BUTTON_MIDDLE, GLFW_PRESS, mods); else { if (HIWORD(wParam) == XBUTTON1) _glfwInputMouseClick(window, GLFW_MOUSE_BUTTON_4, GLFW_PRESS, mods); else if (HIWORD(wParam) == XBUTTON2) _glfwInputMouseClick(window, GLFW_MOUSE_BUTTON_5, GLFW_PRESS, mods); return TRUE; } return 0; } case WM_LBUTTONUP: case WM_RBUTTONUP: case WM_MBUTTONUP: case WM_XBUTTONUP: { const int mods = getKeyMods(); ReleaseCapture(); if (uMsg == WM_LBUTTONUP) _glfwInputMouseClick(window, GLFW_MOUSE_BUTTON_LEFT, GLFW_RELEASE, mods); else if (uMsg == WM_RBUTTONUP) _glfwInputMouseClick(window, GLFW_MOUSE_BUTTON_RIGHT, GLFW_RELEASE, mods); else if (uMsg == WM_MBUTTONUP) _glfwInputMouseClick(window, GLFW_MOUSE_BUTTON_MIDDLE, GLFW_RELEASE, mods); else { if (HIWORD(wParam) == XBUTTON1) _glfwInputMouseClick(window, GLFW_MOUSE_BUTTON_4, GLFW_RELEASE, mods); else if (HIWORD(wParam) == XBUTTON2) _glfwInputMouseClick(window, GLFW_MOUSE_BUTTON_5, GLFW_RELEASE, mods); return TRUE; } return 0; } case WM_MOUSEMOVE: { const int x = GET_X_LPARAM(lParam); const int y = GET_Y_LPARAM(lParam); if (window->cursorMode == GLFW_CURSOR_DISABLED) { if (_glfw.focusedWindow != window) break; _glfwInputCursorMotion(window, x - window->win32.cursorPosX, y - window->win32.cursorPosY); } else _glfwInputCursorMotion(window, x, y); window->win32.cursorPosX = x; window->win32.cursorPosY = y; if (!window->win32.cursorInside) { TRACKMOUSEEVENT tme; ZeroMemory(&tme, sizeof(tme)); tme.cbSize = sizeof(tme); tme.dwFlags = TME_LEAVE; tme.hwndTrack = window->win32.handle; TrackMouseEvent(&tme); window->win32.cursorInside = GL_TRUE; _glfwInputCursorEnter(window, GL_TRUE); } return 0; } case WM_MOUSELEAVE: { window->win32.cursorInside = GL_FALSE; _glfwInputCursorEnter(window, GL_FALSE); return 0; } case WM_MOUSEWHEEL: { _glfwInputScroll(window, 0.0, (SHORT) HIWORD(wParam) / (double) WHEEL_DELTA); return 0; } case WM_MOUSEHWHEEL: { // This message is only sent on Windows Vista and later // NOTE: The X-axis is inverted for consistency with OS X and X11. _glfwInputScroll(window, -((SHORT) HIWORD(wParam) / (double) WHEEL_DELTA), 0.0); return 0; } case WM_SIZE: { if (_glfw.focusedWindow == window) { if (window->cursorMode == GLFW_CURSOR_DISABLED) updateClipRect(window); } if (!window->win32.iconified && wParam == SIZE_MINIMIZED) { window->win32.iconified = GL_TRUE; _glfwInputWindowIconify(window, GL_TRUE); } else if (window->win32.iconified && (wParam == SIZE_RESTORED || wParam == SIZE_MAXIMIZED)) { window->win32.iconified = GL_FALSE; _glfwInputWindowIconify(window, GL_FALSE); } _glfwInputFramebufferSize(window, LOWORD(lParam), HIWORD(lParam)); _glfwInputWindowSize(window, LOWORD(lParam), HIWORD(lParam)); return 0; } case WM_MOVE: { if (_glfw.focusedWindow == window) { if (window->cursorMode == GLFW_CURSOR_DISABLED) updateClipRect(window); } // NOTE: This cannot use LOWORD/HIWORD recommended by MSDN, as // those macros do not handle negative window positions correctly _glfwInputWindowPos(window, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)); return 0; } case WM_PAINT: { _glfwInputWindowDamage(window); break; } case WM_ERASEBKGND: { return TRUE; } case WM_SETCURSOR: { if (_glfw.focusedWindow == window && LOWORD(lParam) == HTCLIENT) { if (window->cursorMode == GLFW_CURSOR_HIDDEN || window->cursorMode == GLFW_CURSOR_DISABLED) { SetCursor(NULL); return TRUE; } else if (window->cursor) { SetCursor(window->cursor->win32.handle); return TRUE; } } break; } case WM_DEVICECHANGE: { if (DBT_DEVNODES_CHANGED == wParam) { _glfwInputMonitorChange(); return TRUE; } break; } case WM_DWMCOMPOSITIONCHANGED: { if (_glfwIsCompositionEnabled()) { _GLFWwindow* previous = _glfwPlatformGetCurrentContext(); _glfwPlatformMakeContextCurrent(window); _glfwPlatformSwapInterval(0); _glfwPlatformMakeContextCurrent(previous); } // TODO: Restore vsync if compositing was disabled break; } case WM_DROPFILES: { HDROP hDrop = (HDROP) wParam; POINT pt; int i; const int count = DragQueryFileW(hDrop, 0xffffffff, NULL, 0); char** paths = calloc(count, sizeof(char*)); // Move the mouse to the position of the drop DragQueryPoint(hDrop, &pt); _glfwInputCursorMotion(window, pt.x, pt.y); for (i = 0; i < count; i++) { const UINT length = DragQueryFileW(hDrop, i, NULL, 0); WCHAR* buffer = calloc(length + 1, sizeof(WCHAR)); DragQueryFileW(hDrop, i, buffer, length + 1); paths[i] = _glfwCreateUTF8FromWideString(buffer); free(buffer); } _glfwInputDrop(window, count, (const char**) paths); for (i = 0; i < count; i++) free(paths[i]); free(paths); DragFinish(hDrop); return 0; } } return DefWindowProc(hWnd, uMsg, wParam, lParam); }
GLFWAPI GLFWwindow* glfwCreateWindow(int width, int height, const char* title, GLFWmonitor* monitor, GLFWwindow* share) { _GLFWfbconfig fbconfig; _GLFWctxconfig ctxconfig; _GLFWwndconfig wndconfig; _GLFWwindow* window; _GLFWwindow* previous; _GLFW_REQUIRE_INIT_OR_RETURN(NULL); if (width <= 0 || height <= 0) { _glfwInputError(GLFW_INVALID_VALUE, "Invalid window size"); return NULL; } // Set up desired framebuffer config fbconfig.redBits = _glfw.hints.redBits; fbconfig.greenBits = _glfw.hints.greenBits; fbconfig.blueBits = _glfw.hints.blueBits; fbconfig.alphaBits = _glfw.hints.alphaBits; fbconfig.depthBits = _glfw.hints.depthBits; fbconfig.stencilBits = _glfw.hints.stencilBits; fbconfig.accumRedBits = _glfw.hints.accumRedBits; fbconfig.accumGreenBits = _glfw.hints.accumGreenBits; fbconfig.accumBlueBits = _glfw.hints.accumBlueBits; fbconfig.accumAlphaBits = _glfw.hints.accumAlphaBits; fbconfig.auxBuffers = _glfw.hints.auxBuffers; fbconfig.stereo = _glfw.hints.stereo ? GL_TRUE : GL_FALSE; fbconfig.samples = _glfw.hints.samples; fbconfig.sRGB = _glfw.hints.sRGB; fbconfig.doublebuffer = _glfw.hints.doublebuffer ? GL_TRUE : GL_FALSE; fbconfig.alphaMask = _glfw.hints.alphaMask ? GL_TRUE : GL_FALSE; // Set up desired window config wndconfig.width = width; wndconfig.height = height; wndconfig.title = title; wndconfig.resizable = _glfw.hints.resizable ? GL_TRUE : GL_FALSE; wndconfig.visible = _glfw.hints.visible ? GL_TRUE : GL_FALSE; wndconfig.decorated = _glfw.hints.decorated ? GL_TRUE : GL_FALSE; wndconfig.focused = _glfw.hints.focused ? GL_TRUE : GL_FALSE; wndconfig.autoIconify = _glfw.hints.autoIconify ? GL_TRUE : GL_FALSE; wndconfig.floating = _glfw.hints.floating ? GL_TRUE : GL_FALSE; wndconfig.monitor = (_GLFWmonitor*) monitor; wndconfig.alphaMask = _glfw.hints.alphaMask ? GL_TRUE : GL_FALSE; // Set up desired context config ctxconfig.api = _glfw.hints.api; ctxconfig.major = _glfw.hints.major; ctxconfig.minor = _glfw.hints.minor; ctxconfig.forward = _glfw.hints.forward ? GL_TRUE : GL_FALSE; ctxconfig.debug = _glfw.hints.debug ? GL_TRUE : GL_FALSE; ctxconfig.profile = _glfw.hints.profile; ctxconfig.robustness = _glfw.hints.robustness; ctxconfig.release = _glfw.hints.release; ctxconfig.share = (_GLFWwindow*) share; // Check the OpenGL bits of the window config if (!_glfwIsValidContextConfig(&ctxconfig)) return NULL; window = calloc(1, sizeof(_GLFWwindow)); window->next = _glfw.windowListHead; _glfw.windowListHead = window; if (wndconfig.monitor) { wndconfig.resizable = GL_TRUE; wndconfig.visible = GL_TRUE; wndconfig.focused = GL_TRUE; // Set up desired video mode window->videoMode.width = width; window->videoMode.height = height; window->videoMode.redBits = _glfw.hints.redBits; window->videoMode.greenBits = _glfw.hints.greenBits; window->videoMode.blueBits = _glfw.hints.blueBits; window->videoMode.refreshRate = _glfw.hints.refreshRate; } // Transfer window hints that are persistent settings and not // just initial states window->monitor = wndconfig.monitor; window->resizable = wndconfig.resizable; window->decorated = wndconfig.decorated; window->autoIconify = wndconfig.autoIconify; window->floating = wndconfig.floating; window->transparent = wndconfig.alphaMask; window->cursorMode = GLFW_CURSOR_NORMAL; // Save the currently current context so it can be restored later previous = _glfwPlatformGetCurrentContext(); // Open the actual window and create its context if (!_glfwPlatformCreateWindow(window, &wndconfig, &ctxconfig, &fbconfig)) { glfwDestroyWindow((GLFWwindow*) window); _glfwPlatformMakeContextCurrent(previous); return NULL; } _glfwPlatformMakeContextCurrent(window); // Retrieve the actual (as opposed to requested) context attributes if (!_glfwRefreshContextAttribs(&ctxconfig)) { glfwDestroyWindow((GLFWwindow*) window); _glfwPlatformMakeContextCurrent(previous); return NULL; } // Verify the context against the requested parameters if (!_glfwIsValidContext(&ctxconfig)) { glfwDestroyWindow((GLFWwindow*) window); _glfwPlatformMakeContextCurrent(previous); return NULL; } // Clearing the front buffer to black to avoid garbage pixels left over // from previous uses of our bit of VRAM glClear(GL_COLOR_BUFFER_BIT); _glfwPlatformSwapBuffers(window); // Restore the previously current context (or NULL) _glfwPlatformMakeContextCurrent(previous); if (wndconfig.monitor) { int width, height; _glfwPlatformGetWindowSize(window, &width, &height); window->cursorPosX = width / 2; window->cursorPosY = height / 2; _glfwPlatformSetCursorPos(window, window->cursorPosX, window->cursorPosY); } else { if (wndconfig.visible) { if (wndconfig.focused) _glfwPlatformShowWindow(window); else _glfwPlatformUnhideWindow(window); } } return (GLFWwindow*) window; }
// Prepare for creation of the OpenGL context // int _glfwCreateContext(_GLFWwindow* window, const _GLFWwndconfig* wndconfig, const _GLFWfbconfig* fbconfig) { int attribs[40]; int pixelFormat = 0; PIXELFORMATDESCRIPTOR pfd; HGLRC share = NULL; if (wndconfig->share) share = wndconfig->share->wgl.context; window->wgl.dc = GetDC(window->win32.handle); if (!window->wgl.dc) { _glfwInputError(GLFW_PLATFORM_ERROR, "Win32: Failed to retrieve DC for window"); return GL_FALSE; } if (!choosePixelFormat(window, fbconfig, &pixelFormat)) { _glfwInputError(GLFW_PLATFORM_ERROR, "WGL: Failed to find a suitable pixel format"); return GL_FALSE; } if (!DescribePixelFormat(window->wgl.dc, pixelFormat, sizeof(pfd), &pfd)) { _glfwInputError(GLFW_PLATFORM_ERROR, "Win32: Failed to retrieve PFD for selected pixel " "format"); return GL_FALSE; } if (!SetPixelFormat(window->wgl.dc, pixelFormat, &pfd)) { _glfwInputError(GLFW_PLATFORM_ERROR, "Win32: Failed to set selected pixel format"); return GL_FALSE; } if (window->wgl.ARB_create_context) { int index = 0, mask = 0, flags = 0, strategy = 0; if (wndconfig->clientAPI == GLFW_OPENGL_API) { if (wndconfig->glForward) flags |= WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB; if (wndconfig->glDebug) flags |= WGL_CONTEXT_DEBUG_BIT_ARB; if (wndconfig->glProfile) { if (wndconfig->glProfile == GLFW_OPENGL_CORE_PROFILE) mask |= WGL_CONTEXT_CORE_PROFILE_BIT_ARB; else if (wndconfig->glProfile == GLFW_OPENGL_COMPAT_PROFILE) mask |= WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB; } } else mask |= WGL_CONTEXT_ES2_PROFILE_BIT_EXT; if (wndconfig->glRobustness) { if (window->wgl.ARB_create_context_robustness) { if (wndconfig->glRobustness == GLFW_NO_RESET_NOTIFICATION) strategy = WGL_NO_RESET_NOTIFICATION_ARB; else if (wndconfig->glRobustness == GLFW_LOSE_CONTEXT_ON_RESET) strategy = WGL_LOSE_CONTEXT_ON_RESET_ARB; flags |= WGL_CONTEXT_ROBUST_ACCESS_BIT_ARB; } } if (wndconfig->glMajor != 1 || wndconfig->glMinor != 0) { setWGLattrib(WGL_CONTEXT_MAJOR_VERSION_ARB, wndconfig->glMajor); setWGLattrib(WGL_CONTEXT_MINOR_VERSION_ARB, wndconfig->glMinor); } if (flags) setWGLattrib(WGL_CONTEXT_FLAGS_ARB, flags); if (mask) setWGLattrib(WGL_CONTEXT_PROFILE_MASK_ARB, mask); if (strategy) setWGLattrib(WGL_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB, strategy); setWGLattrib(0, 0); window->wgl.context = window->wgl.CreateContextAttribsARB(window->wgl.dc, share, attribs); if (!window->wgl.context) { _glfwInputError(GLFW_VERSION_UNAVAILABLE, "WGL: Failed to create OpenGL context"); return GL_FALSE; } } else { window->wgl.context = wglCreateContext(window->wgl.dc); if (!window->wgl.context) { _glfwInputError(GLFW_PLATFORM_ERROR, "WGL: Failed to create OpenGL context"); return GL_FALSE; } if (share) { if (!wglShareLists(share, window->wgl.context)) { _glfwInputError(GLFW_PLATFORM_ERROR, "WGL: Failed to enable sharing with specified " "OpenGL context"); return GL_FALSE; } } } _glfwPlatformMakeContextCurrent(window); initWGLExtensions(window); return GL_TRUE; }
// Create the OpenGL or OpenGL ES context // int _glfwCreateContext(_GLFWwindow* window, const _GLFWctxconfig* ctxconfig, const _GLFWfbconfig* fbconfig) { int attribs[40]; int pixelFormat = 0; PIXELFORMATDESCRIPTOR pfd; HGLRC share = NULL; if (ctxconfig->share) share = ctxconfig->share->wgl.context; window->wgl.dc = GetDC(window->win32.handle); if (!window->wgl.dc) { _glfwInputError(GLFW_PLATFORM_ERROR, "WGL: Failed to retrieve DC for window"); return GLFW_FALSE; } if (!choosePixelFormat(window, fbconfig, &pixelFormat)) return GLFW_FALSE; if (!DescribePixelFormat(window->wgl.dc, pixelFormat, sizeof(pfd), &pfd)) { _glfwInputError(GLFW_PLATFORM_ERROR, "WGL: Failed to retrieve PFD for selected pixel format"); return GLFW_FALSE; } if (!SetPixelFormat(window->wgl.dc, pixelFormat, &pfd)) { _glfwInputError(GLFW_PLATFORM_ERROR, "WGL: Failed to set selected pixel format"); return GLFW_FALSE; } if (window->wgl.ARB_create_context) { int index = 0, mask = 0, flags = 0; if (ctxconfig->api == GLFW_OPENGL_API) { if (ctxconfig->forward) flags |= WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB; if (ctxconfig->profile == GLFW_OPENGL_CORE_PROFILE) mask |= WGL_CONTEXT_CORE_PROFILE_BIT_ARB; else if (ctxconfig->profile == GLFW_OPENGL_COMPAT_PROFILE) mask |= WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB; } else mask |= WGL_CONTEXT_ES2_PROFILE_BIT_EXT; if (ctxconfig->debug) flags |= WGL_CONTEXT_DEBUG_BIT_ARB; if (ctxconfig->robustness) { if (window->wgl.ARB_create_context_robustness) { if (ctxconfig->robustness == GLFW_NO_RESET_NOTIFICATION) { setWGLattrib(WGL_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB, WGL_NO_RESET_NOTIFICATION_ARB); } else if (ctxconfig->robustness == GLFW_LOSE_CONTEXT_ON_RESET) { setWGLattrib(WGL_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB, WGL_LOSE_CONTEXT_ON_RESET_ARB); } flags |= WGL_CONTEXT_ROBUST_ACCESS_BIT_ARB; } } if (ctxconfig->release) { if (window->wgl.ARB_context_flush_control) { if (ctxconfig->release == GLFW_RELEASE_BEHAVIOR_NONE) { setWGLattrib(WGL_CONTEXT_RELEASE_BEHAVIOR_ARB, WGL_CONTEXT_RELEASE_BEHAVIOR_NONE_ARB); } else if (ctxconfig->release == GLFW_RELEASE_BEHAVIOR_FLUSH) { setWGLattrib(WGL_CONTEXT_RELEASE_BEHAVIOR_ARB, WGL_CONTEXT_RELEASE_BEHAVIOR_FLUSH_ARB); } } } // NOTE: Only request an explicitly versioned context when necessary, as // explicitly requesting version 1.0 does not always return the // highest version supported by the driver if (ctxconfig->major != 1 || ctxconfig->minor != 0) { setWGLattrib(WGL_CONTEXT_MAJOR_VERSION_ARB, ctxconfig->major); setWGLattrib(WGL_CONTEXT_MINOR_VERSION_ARB, ctxconfig->minor); } if (flags) setWGLattrib(WGL_CONTEXT_FLAGS_ARB, flags); if (mask) setWGLattrib(WGL_CONTEXT_PROFILE_MASK_ARB, mask); setWGLattrib(0, 0); window->wgl.context = window->wgl.CreateContextAttribsARB(window->wgl.dc, share, attribs); if (!window->wgl.context) { _glfwInputError(GLFW_VERSION_UNAVAILABLE, "WGL: Failed to create OpenGL context"); return GLFW_FALSE; } } else { window->wgl.context = _glfw_wglCreateContext(window->wgl.dc); if (!window->wgl.context) { _glfwInputError(GLFW_VERSION_UNAVAILABLE, "WGL: Failed to create OpenGL context"); return GLFW_FALSE; } if (share) { if (!_glfw_wglShareLists(share, window->wgl.context)) { _glfwInputError(GLFW_PLATFORM_ERROR, "WGL: Failed to enable sharing with specified OpenGL context"); return GLFW_FALSE; } } } _glfwPlatformMakeContextCurrent(window); initWGLExtensions(window); return GLFW_TRUE; }
GLFWAPI void glfwMakeContextCurrent(GLFWwindow* handle) { _GLFWwindow* window = (_GLFWwindow*) handle; _GLFW_REQUIRE_INIT(); _glfwPlatformMakeContextCurrent(window); }
GLFWAPI GLFWwindow* glfwCreateWindow(int width, int height, const char* title, GLFWmonitor* monitor, GLFWwindow* share) { _GLFWfbconfig fbconfig; _GLFWctxconfig ctxconfig; _GLFWwndconfig wndconfig; _GLFWwindow* window; _GLFWwindow* previous; _GLFW_REQUIRE_INIT_OR_RETURN(NULL); if (width <= 0 || height <= 0) { _glfwInputError(GLFW_INVALID_VALUE, "Invalid window size"); return NULL; } fbconfig = _glfw.hints.framebuffer; ctxconfig = _glfw.hints.context; wndconfig = _glfw.hints.window; wndconfig.width = width; wndconfig.height = height; wndconfig.title = title; wndconfig.monitor = (_GLFWmonitor*) monitor; ctxconfig.share = (_GLFWwindow*) share; if (wndconfig.monitor) { wndconfig.resizable = GLFW_TRUE; wndconfig.visible = GLFW_TRUE; wndconfig.focused = GLFW_TRUE; } // Check the OpenGL bits of the window config if (!_glfwIsValidContextConfig(&ctxconfig)) return NULL; window = calloc(1, sizeof(_GLFWwindow)); window->next = _glfw.windowListHead; _glfw.windowListHead = window; window->videoMode.width = width; window->videoMode.height = height; window->videoMode.redBits = fbconfig.redBits; window->videoMode.greenBits = fbconfig.greenBits; window->videoMode.blueBits = fbconfig.blueBits; window->videoMode.refreshRate = _glfw.hints.refreshRate; window->monitor = wndconfig.monitor; window->resizable = wndconfig.resizable; window->decorated = wndconfig.decorated; window->autoIconify = wndconfig.autoIconify; window->floating = wndconfig.floating; window->cursorMode = GLFW_CURSOR_NORMAL; // Save the currently current context so it can be restored later previous = _glfwPlatformGetCurrentContext(); // Open the actual window and create its context if (!_glfwPlatformCreateWindow(window, &wndconfig, &ctxconfig, &fbconfig)) { glfwDestroyWindow((GLFWwindow*) window); _glfwPlatformMakeContextCurrent(previous); return NULL; } _glfwPlatformMakeContextCurrent(window); // Retrieve the actual (as opposed to requested) context attributes if (!_glfwRefreshContextAttribs(&ctxconfig)) { glfwDestroyWindow((GLFWwindow*) window); _glfwPlatformMakeContextCurrent(previous); return NULL; } // Verify the context against the requested parameters if (!_glfwIsValidContext(&ctxconfig)) { glfwDestroyWindow((GLFWwindow*) window); _glfwPlatformMakeContextCurrent(previous); return NULL; } // Clearing the front buffer to black to avoid garbage pixels left over // from previous uses of our bit of VRAM window->Clear(GL_COLOR_BUFFER_BIT); _glfwPlatformSwapBuffers(window); // Restore the previously current context (or NULL) _glfwPlatformMakeContextCurrent(previous); if (wndconfig.monitor) { int width, height; _glfwPlatformGetWindowSize(window, &width, &height); window->cursorPosX = width / 2; window->cursorPosY = height / 2; _glfwPlatformSetCursorPos(window, window->cursorPosX, window->cursorPosY); } else { if (wndconfig.visible) { if (wndconfig.focused) _glfwPlatformShowWindow(window); else _glfwPlatformUnhideWindow(window); } } return (GLFWwindow*) window; }
// Prepare for creation of the OpenGL context // int _glfwCreateContext(_GLFWwindow* window, const _GLFWwndconfig* wndconfig, const _GLFWfbconfig* fbconfig) { int attribs[40]; int pixelFormat; PIXELFORMATDESCRIPTOR pfd; HGLRC share = NULL; if (wndconfig->share) share = wndconfig->share->wgl.context; window->wgl.dc = GetDC(window->win32.handle); if (!window->wgl.dc) { _glfwInputError(GLFW_PLATFORM_ERROR, "Win32: Failed to retrieve DC for window"); return GL_FALSE; } if (window->wgl.ARB_pixel_format) { int index = 0; UINT count; setWGLattrib(WGL_SUPPORT_OPENGL_ARB, TRUE); setWGLattrib(WGL_DRAW_TO_WINDOW_ARB, TRUE); setWGLattrib(WGL_PIXEL_TYPE_ARB, WGL_TYPE_RGBA_ARB); setWGLattrib(WGL_DOUBLE_BUFFER_ARB, TRUE); if (fbconfig->redBits) setWGLattrib(WGL_RED_BITS_ARB, fbconfig->redBits); if (fbconfig->greenBits) setWGLattrib(WGL_GREEN_BITS_ARB, fbconfig->greenBits); if (fbconfig->blueBits) setWGLattrib(WGL_BLUE_BITS_ARB, fbconfig->blueBits); if (fbconfig->alphaBits) setWGLattrib(WGL_ALPHA_BITS_ARB, fbconfig->alphaBits); if (fbconfig->depthBits) setWGLattrib(WGL_DEPTH_BITS_ARB, fbconfig->depthBits); if (fbconfig->stencilBits) setWGLattrib(WGL_STENCIL_BITS_ARB, fbconfig->stencilBits); if (fbconfig->auxBuffers) setWGLattrib(WGL_AUX_BUFFERS_ARB, fbconfig->auxBuffers); if (fbconfig->accumRedBits) setWGLattrib(WGL_ACCUM_RED_BITS_ARB, fbconfig->accumRedBits); if (fbconfig->accumGreenBits) setWGLattrib(WGL_ACCUM_GREEN_BITS_ARB, fbconfig->accumGreenBits); if (fbconfig->accumBlueBits) setWGLattrib(WGL_ACCUM_BLUE_BITS_ARB, fbconfig->accumBlueBits); if (fbconfig->accumAlphaBits) setWGLattrib(WGL_ACCUM_BLUE_BITS_ARB, fbconfig->accumAlphaBits); if (fbconfig->stereo) setWGLattrib(WGL_STEREO_ARB, TRUE); if (window->wgl.ARB_multisample) { if (fbconfig->samples) { setWGLattrib(WGL_SAMPLE_BUFFERS_ARB, 1); setWGLattrib(WGL_SAMPLES_ARB, fbconfig->samples); } } if (window->wgl.ARB_framebuffer_sRGB) { if (fbconfig->sRGB) setWGLattrib(WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB, TRUE); } setWGLattrib(0, 0); if (!window->wgl.ChoosePixelFormatARB(window->wgl.dc, attribs, NULL, 1, &pixelFormat, &count)) { _glfwInputError(GLFW_PLATFORM_ERROR, "WGL: Failed to find a suitable pixel format"); return GL_FALSE; } } else { ZeroMemory(&pfd, sizeof(pfd)); pfd.nSize = sizeof(pfd); pfd.nVersion = 1; pfd.dwFlags |= PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER; if (fbconfig->stereo) pfd.dwFlags |= PFD_STEREO; pfd.iPixelType = PFD_TYPE_RGBA; pfd.cColorBits = fbconfig->redBits + fbconfig->greenBits + fbconfig->blueBits; pfd.cAlphaBits = fbconfig->alphaBits; pfd.cAccumBits = fbconfig->accumRedBits + fbconfig->accumGreenBits + fbconfig->accumBlueBits; pfd.cDepthBits = fbconfig->depthBits; pfd.cStencilBits = fbconfig->stencilBits; pfd.cAuxBuffers = fbconfig->auxBuffers; pixelFormat = ChoosePixelFormat(window->wgl.dc, &pfd); if (!pixelFormat) { _glfwInputError(GLFW_PLATFORM_ERROR, "WGL: Failed to find a suitable pixel format"); return GL_FALSE; } } if (!DescribePixelFormat(window->wgl.dc, pixelFormat, sizeof(pfd), &pfd)) { _glfwInputError(GLFW_PLATFORM_ERROR, "Win32: Failed to retrieve PFD for selected pixel " "format"); return GL_FALSE; } if (!(pfd.dwFlags & PFD_GENERIC_ACCELERATED) && (pfd.dwFlags & PFD_GENERIC_FORMAT)) { _glfwInputError(GLFW_PLATFORM_ERROR, "Win32: Failed to find an accelerated pixel format"); return GL_FALSE; } if (!SetPixelFormat(window->wgl.dc, pixelFormat, &pfd)) { _glfwInputError(GLFW_PLATFORM_ERROR, "Win32: Failed to set selected pixel format"); return GL_FALSE; } if (window->wgl.ARB_create_context) { int index = 0, mask = 0, flags = 0, strategy = 0; if (wndconfig->clientAPI == GLFW_OPENGL_API) { if (wndconfig->glForward) flags |= WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB; if (wndconfig->glDebug) flags |= WGL_CONTEXT_DEBUG_BIT_ARB; if (wndconfig->glProfile) { if (wndconfig->glProfile == GLFW_OPENGL_CORE_PROFILE) mask |= WGL_CONTEXT_CORE_PROFILE_BIT_ARB; else if (wndconfig->glProfile == GLFW_OPENGL_COMPAT_PROFILE) mask |= WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB; } } else mask |= WGL_CONTEXT_ES2_PROFILE_BIT_EXT; if (wndconfig->glRobustness) { if (window->wgl.ARB_create_context_robustness) { if (wndconfig->glRobustness == GLFW_NO_RESET_NOTIFICATION) strategy = WGL_NO_RESET_NOTIFICATION_ARB; else if (wndconfig->glRobustness == GLFW_LOSE_CONTEXT_ON_RESET) strategy = WGL_LOSE_CONTEXT_ON_RESET_ARB; flags |= WGL_CONTEXT_ROBUST_ACCESS_BIT_ARB; } } if (wndconfig->glMajor != 1 || wndconfig->glMinor != 0) { setWGLattrib(WGL_CONTEXT_MAJOR_VERSION_ARB, wndconfig->glMajor); setWGLattrib(WGL_CONTEXT_MINOR_VERSION_ARB, wndconfig->glMinor); } if (flags) setWGLattrib(WGL_CONTEXT_FLAGS_ARB, flags); if (mask) setWGLattrib(WGL_CONTEXT_PROFILE_MASK_ARB, mask); if (strategy) setWGLattrib(WGL_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB, strategy); setWGLattrib(0, 0); window->wgl.context = window->wgl.CreateContextAttribsARB(window->wgl.dc, share, attribs); if (!window->wgl.context) { _glfwInputError(GLFW_VERSION_UNAVAILABLE, "WGL: Failed to create OpenGL context"); return GL_FALSE; } } else { window->wgl.context = wglCreateContext(window->wgl.dc); if (!window->wgl.context) { _glfwInputError(GLFW_PLATFORM_ERROR, "WGL: Failed to create OpenGL context"); return GL_FALSE; } if (share) { if (!wglShareLists(share, window->wgl.context)) { _glfwInputError(GLFW_PLATFORM_ERROR, "WGL: Failed to enable sharing with specified " "OpenGL context"); return GL_FALSE; } } } _glfwPlatformMakeContextCurrent(window); initWGLExtensions(window); return GL_TRUE; }
// Analyzes the specified context for possible recreation // int _glfwAnalyzeContext(_GLFWwindow* window, const _GLFWctxconfig* ctxconfig, const _GLFWfbconfig* fbconfig) { GLFWbool required = GLFW_FALSE; if (_glfw.wgl.extensionsLoaded) return _GLFW_RECREATION_NOT_NEEDED; _glfwPlatformMakeContextCurrent(window); loadExtensions(); if (ctxconfig->api == GLFW_OPENGL_API) { if (ctxconfig->forward) { if (!_glfw.wgl.ARB_create_context) { _glfwInputError(GLFW_VERSION_UNAVAILABLE, "WGL: A forward compatible OpenGL context requested but WGL_ARB_create_context is unavailable"); return _GLFW_RECREATION_IMPOSSIBLE; } required = GLFW_TRUE; } if (ctxconfig->profile) { if (!_glfw.wgl.ARB_create_context_profile) { _glfwInputError(GLFW_VERSION_UNAVAILABLE, "WGL: OpenGL profile requested but WGL_ARB_create_context_profile is unavailable"); return _GLFW_RECREATION_IMPOSSIBLE; } required = GLFW_TRUE; } if (ctxconfig->release) { if (_glfw.wgl.ARB_context_flush_control) required = GLFW_TRUE; } } else { if (!_glfw.wgl.ARB_create_context || !_glfw.wgl.ARB_create_context_profile || !_glfw.wgl.EXT_create_context_es2_profile) { _glfwInputError(GLFW_API_UNAVAILABLE, "WGL: OpenGL ES requested but WGL_ARB_create_context_es2_profile is unavailable"); return _GLFW_RECREATION_IMPOSSIBLE; } required = GLFW_TRUE; } if (ctxconfig->major != 1 || ctxconfig->minor != 0) { if (_glfw.wgl.ARB_create_context) required = GLFW_TRUE; } if (ctxconfig->debug) { if (_glfw.wgl.ARB_create_context) required = GLFW_TRUE; } if (fbconfig->samples > 0) { // MSAA is not a hard constraint, so do nothing if it's not supported if (_glfw.wgl.ARB_multisample && _glfw.wgl.ARB_pixel_format) required = GLFW_TRUE; } if (fbconfig->sRGB) { // sRGB is not a hard constraint, so do nothing if it's not supported if ((_glfw.wgl.ARB_framebuffer_sRGB || _glfw.wgl.EXT_framebuffer_sRGB) && _glfw.wgl.ARB_pixel_format) { required = GLFW_TRUE; } } if (required) return _GLFW_RECREATION_REQUIRED; return _GLFW_RECREATION_NOT_NEEDED; }