// Copyright (C) 2015 Jérôme Leclercq // This file is part of the "Nazara Engine - Renderer module" // For conditions of distribution and use, see copyright notice in Config.hpp // Code inspiré de NeHe (Lesson1) et de la SFML par Laurent Gomila #include #include #include #include #include #include #include #include #include NzContextImpl::NzContextImpl() { } bool NzContextImpl::Activate() { return wglMakeCurrent(m_deviceContext, m_context) == TRUE; } bool NzContextImpl::Create(NzContextParameters& parameters) { if (parameters.window) { m_window = static_cast(parameters.window); m_ownsWindow = false; } else { m_window = CreateWindowA("STATIC", nullptr, WS_DISABLED | WS_POPUP, 0, 0, 1, 1, nullptr, nullptr, GetModuleHandle(nullptr), nullptr); if (!m_window) { NazaraError("Failed to create window"); return false; } ShowWindow(m_window, SW_HIDE); m_ownsWindow = true; } // En cas d'exception, la ressource sera quand même libérée NzCallOnExit onExit([this] () { Destroy(); }); m_deviceContext = GetDC(m_window); if (!m_deviceContext) { NazaraError("Failed to get device context"); return false; } int pixelFormat = 0; if (parameters.antialiasingLevel > 0) { if (wglChoosePixelFormat) { bool valid; UINT numFormats; int attributes[] = { WGL_DRAW_TO_WINDOW_ARB, GL_TRUE, WGL_SUPPORT_OPENGL_ARB, GL_TRUE, WGL_ACCELERATION_ARB, WGL_FULL_ACCELERATION_ARB, WGL_COLOR_BITS_ARB, (parameters.bitsPerPixel == 32) ? 24 : parameters.bitsPerPixel, WGL_ALPHA_BITS_ARB, (parameters.bitsPerPixel == 32) ? 8 : 0, WGL_DEPTH_BITS_ARB, parameters.depthBits, WGL_STENCIL_BITS_ARB, parameters.stencilBits, WGL_DOUBLE_BUFFER_ARB, (parameters.doubleBuffered) ? GL_TRUE : GL_FALSE, WGL_SAMPLE_BUFFERS_ARB, GL_TRUE, WGL_SAMPLES_ARB, parameters.antialiasingLevel, 0, 0 }; do { valid = (wglChoosePixelFormat(m_deviceContext, attributes, nullptr, 1, &pixelFormat, &numFormats) == TRUE); } while ((!valid || numFormats == 0) && --attributes[19] > 0); if (!valid) { NazaraWarning("Could not find a format matching requirements, disabling antialiasing..."); pixelFormat = 0; } parameters.antialiasingLevel = attributes[19]; } else { NazaraWarning("Antialiasing is not supported"); parameters.antialiasingLevel = 0; } } PIXELFORMATDESCRIPTOR descriptor; ZeroMemory(&descriptor, sizeof(PIXELFORMATDESCRIPTOR)); descriptor.nSize = sizeof(PIXELFORMATDESCRIPTOR); descriptor.nVersion = 1; if (pixelFormat == 0) { descriptor.cColorBits = parameters.bitsPerPixel; descriptor.cDepthBits = parameters.depthBits; descriptor.cStencilBits = parameters.stencilBits; descriptor.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL; descriptor.iPixelType = PFD_TYPE_RGBA; if (parameters.bitsPerPixel == 32) descriptor.cAlphaBits = 8; if (parameters.doubleBuffered) descriptor.dwFlags |= PFD_DOUBLEBUFFER; pixelFormat = ChoosePixelFormat(m_deviceContext, &descriptor); if (pixelFormat == 0) { NazaraError("Failed to choose pixel format"); return false; } } if (!SetPixelFormat(m_deviceContext, pixelFormat, &descriptor)) { NazaraError("Failed to set pixel format"); return false; } // Arrivé ici, le format de pixel est choisi, nous récupérons donc les paramètres réels du futur contexte if (DescribePixelFormat(m_deviceContext, pixelFormat, sizeof(PIXELFORMATDESCRIPTOR), &descriptor) != 0) { parameters.bitsPerPixel = descriptor.cColorBits + descriptor.cAlphaBits; parameters.depthBits = descriptor.cDepthBits; parameters.stencilBits = descriptor.cDepthBits; } else NazaraWarning("Failed to get context's parameters"); HGLRC shareContext = (parameters.shared) ? static_cast(parameters.shareContext->m_impl)->m_context : nullptr; m_context = nullptr; if (wglCreateContextAttribs) { int attributes[4*2+1]; int* attrib = attributes; *attrib++ = WGL_CONTEXT_MAJOR_VERSION_ARB; *attrib++ = parameters.majorVersion; *attrib++ = WGL_CONTEXT_MINOR_VERSION_ARB; *attrib++ = parameters.minorVersion; if (parameters.majorVersion >= 3) { *attrib++ = WGL_CONTEXT_PROFILE_MASK_ARB; *attrib++ = (parameters.compatibilityProfile) ? WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB : WGL_CONTEXT_CORE_PROFILE_BIT_ARB; // Les contextes forward-compatible ne sont plus utilisés pour cette raison : // http://www.opengl.org/discussion_boards/showthread.php/175052-Forward-compatible-vs-Core-profile } if (parameters.debugMode) { *attrib++ = WGL_CONTEXT_FLAGS_ARB; *attrib++ = WGL_CONTEXT_DEBUG_BIT_ARB; } *attrib++ = 0; m_context = wglCreateContextAttribs(m_deviceContext, shareContext, attributes); } if (!m_context) { m_context = wglCreateContext(m_deviceContext); if (shareContext) { // wglShareLists n'est pas thread-safe (source: SFML) static NzMutex mutex; NzLockGuard lock(mutex); if (!wglShareLists(shareContext, m_context)) NazaraWarning("Failed to share the context: " + NzError::GetLastSystemError()); } } if (!m_context) { NazaraError("Failed to create context"); return false; } onExit.Reset(); return true; } void NzContextImpl::Destroy() { if (m_context) { if (wglGetCurrentContext() == m_context) wglMakeCurrent(nullptr, nullptr); wglDeleteContext(m_context); m_context = nullptr; } if (m_deviceContext) { ReleaseDC(m_window, m_deviceContext); m_deviceContext = nullptr; } if (m_ownsWindow) { DestroyWindow(m_window); m_window = nullptr; } } void NzContextImpl::EnableVerticalSync(bool enabled) { if (wglSwapInterval) wglSwapInterval(enabled ? 1 : 0); else NazaraError("Vertical sync not supported"); } void NzContextImpl::SwapBuffers() { ::SwapBuffers(m_deviceContext); } bool NzContextImpl::Desactivate() { return wglMakeCurrent(nullptr, nullptr) == TRUE; }