#include "glad_wgl.h" #include #include #include "Win32Internal.h" #include "Win32GLContext.h" namespace sp { // Can't use GLAD's standard loader function because it // calls wglGetProcAddress without __stdcall // that results in some runtime exception. static GLADapiproc func_loader(const char *name) { return (GLADapiproc) wglGetProcAddress(name); } // Ensure that OpenGL extensions are loaded. static void ensureExtensionsLoaded(HDC dc) { static bool init = false; if (!init) { init = true; if (!gladLoadWGL(dc, func_loader)) { Log::error("Win32: Could not load WGL extensions"); } if (!gladLoaderLoadGL()) { Log::error("Win32: Could not load OpenGL extensions\n"); } } } Win32GLContext::Win32GLContext() : m_wnd (NULL), m_deviceContext (NULL), m_renderContext (NULL) { } Win32GLContext::~Win32GLContext() { destroy(); } bool Win32GLContext::create(const PlatformDisplay* display) { // If created. destroy old handles. destroy(); m_wnd = (HWND) display->getHandle(); // Should have a valid handle here. trigger error. if (!m_wnd) { Log::warn("Win32 - Could not create GL context: Invalid display handle\n"); return false; } m_deviceContext = ::GetDC(m_wnd); createGLContext(); if (!m_deviceContext || !m_renderContext) { // Make sure we release all handles. destroy(); Log::warn("Win32 - Could not create GL context: %s", Win32GetMessage(GetLastError())); return false; } return true; } void Win32GLContext::destroy() { if (m_wnd && m_deviceContext) { ::ReleaseDC(m_wnd, m_deviceContext); m_deviceContext = NULL; m_wnd = NULL; } if (m_renderContext) { ::wglDeleteContext(m_renderContext); m_renderContext = NULL; } } void Win32GLContext::createGLContext() { HGLRC tmpDC; // First set pixel format. if (!setPixelFormat()) { return; } // This is one reason why Win32 context creation is wierd. // I need to create some context first so that GLEW knows if // It supports the "wglCreateContextAttribsARB". That is a 3.2+ Core function. tmpDC = ::wglCreateContext(m_deviceContext); ::wglMakeCurrent(m_deviceContext, tmpDC); ensureExtensionsLoaded(m_deviceContext); // Dont need to old one anymore. wglMakeCurrent(m_deviceContext, NULL); ::wglDeleteContext(tmpDC); // TODO: For now.. We force 3.2 Core but this should not be implementation specific. // The Display class should force that for all GLContext Implementations. int attriblist[] = { WGL_CONTEXT_MAJOR_VERSION_ARB, 3, WGL_CONTEXT_MINOR_VERSION_ARB, 2, WGL_CONTEXT_PROFILE_MASK_ARB, WGL_CONTEXT_CORE_PROFILE_BIT_ARB, 0, 0 }; // Create real context. m_renderContext = ::wglCreateContextAttribsARB(m_deviceContext, 0, attriblist); } bool Win32GLContext::activate() { // Make sure we have dc and rc before calling MakeCurrent. if (m_deviceContext && m_renderContext) { return ::wglMakeCurrent(m_deviceContext, m_renderContext); } return false; } bool Win32GLContext::deactivate() { return ::wglMakeCurrent(NULL, NULL); } bool Win32GLContext::isActive() const { return ::wglGetCurrentContext() == m_renderContext; } bool Win32GLContext::setSwapInterval(int interval) { ensureExtensionsLoaded(m_deviceContext); return wglSwapIntervalEXT(interval); } void Win32GLContext::setSize(unsigned int width, unsigned int height) { if (activate()) { glViewport(0, 0, width, height); } } void Win32GLContext::swapBuffers() { if (m_deviceContext) { ::SwapBuffers(m_deviceContext); } } bool Win32GLContext::setPixelFormat() { PIXELFORMATDESCRIPTOR pfd; int format; // For now, always create a RGBA pixel format with double buffer. ZeroMemory(&pfd, sizeof(pfd)); pfd.nSize = sizeof(pfd); pfd.nVersion = 1; pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER; pfd.iPixelType = PFD_TYPE_RGBA; pfd.cColorBits = 32; pfd.cDepthBits = 16; pfd.iLayerType = PFD_MAIN_PLANE; format = ::ChoosePixelFormat(m_deviceContext, &pfd); if (format) { return ::SetPixelFormat(m_deviceContext, format, &pfd); } return false; } } // namespace sp