189 lines
3.8 KiB
C++
189 lines
3.8 KiB
C++
|
|
#include "glad_wgl.h"
|
|
|
|
#include <Platform/PlatformDisplay.h>
|
|
#include <Spectre/System/Log.h>
|
|
|
|
#include "Win32Internal.h"
|
|
#include "Win32GLContext.h"
|
|
|
|
namespace sp {
|
|
|
|
// Ensure that OpenGL extensions are loaded.
|
|
static bool ensureExtensionsLoaded(HDC dc)
|
|
{
|
|
static bool init = false;
|
|
|
|
if (!init) {
|
|
|
|
if (!gladLoaderLoadWGL(dc)) {
|
|
Log::error("WGL: Could not load WGL extensions");
|
|
return false;
|
|
}
|
|
|
|
if (!gladLoaderLoadGL()) {
|
|
Log::error("WGL: Could not load OpenGL extensions");
|
|
return false;
|
|
}
|
|
|
|
init = true;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
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("WGL: Could not create GL context: Invalid display handle");
|
|
return false;
|
|
}
|
|
|
|
m_deviceContext = ::GetDC(m_wnd);
|
|
|
|
createGLContext();
|
|
|
|
if (!m_deviceContext || !m_renderContext) {
|
|
|
|
// Make sure we release all handles.
|
|
destroy();
|
|
|
|
Log::warn("WGL: 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);
|
|
|
|
if (!ensureExtensionsLoaded(m_deviceContext)) {
|
|
goto err;
|
|
}
|
|
|
|
// 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);
|
|
|
|
err:
|
|
// Dont need the old one anymore.
|
|
wglMakeCurrent(m_deviceContext, NULL);
|
|
::wglDeleteContext(tmpDC);
|
|
}
|
|
|
|
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
|