forked from Mirrors/openclonk
WGL: Wrap the temporary context for OpenGL extension detection in a class
Unlike GLX, the OpenGL function pointers are context-dependant. Because we need an extension function to create the context we're going to use, we first need to create a temporary context. Since this is independent of the library used to fetch the function pointers, decouple it from glewInit().epoxy
parent
5e5d8dd49a
commit
506d116c42
|
@ -124,10 +124,8 @@ protected:
|
|||
// this handles are declared as pointers to structs
|
||||
C4Window * pWindow; // window to draw in
|
||||
#ifdef USE_WIN32_WINDOWS
|
||||
static HGLRC hrc; // rendering context
|
||||
HWND hWindow; // used if pWindow==NULL
|
||||
HDC hDC; // device context handle
|
||||
static bool InitGlew(HINSTANCE hInst);
|
||||
#elif defined(USE_GTK)
|
||||
/*GLXContext*/void * ctx;
|
||||
#endif
|
||||
|
|
|
@ -59,8 +59,8 @@ void CStdGLCtx::SelectCommon()
|
|||
|
||||
#include <GL/wglew.h>
|
||||
|
||||
decltype(CStdGLCtx::hrc) CStdGLCtx::hrc = 0;
|
||||
static PIXELFORMATDESCRIPTOR pfd; // desired pixel format
|
||||
static HGLRC hrc = 0;
|
||||
|
||||
// Enumerate available pixel formats. Choose the best pixel format in
|
||||
// terms of color and depth buffer bits and then return all formats with
|
||||
|
@ -159,97 +159,72 @@ static int GetPixelFormatForMS(HDC hDC, int samples)
|
|||
return 0;
|
||||
}
|
||||
|
||||
// Initialize GLEW. We need to choose a pixel format for this, however we need
|
||||
// GLEW initialized to enumerate pixel formats. So this creates a temporary
|
||||
// window with a default pixel format, initializes glew and removes that temp
|
||||
// window again. Then we can enumerate pixel formats and choose a proper one
|
||||
// for the main window in CStdGLCtx::Init.
|
||||
bool CStdGLCtx::InitGlew(HINSTANCE hInst)
|
||||
class WinAPIError : public std::runtime_error
|
||||
{
|
||||
static bool glewInitialized = false;
|
||||
if(glewInitialized) return true;
|
||||
public:
|
||||
typedef DWORD error_code;
|
||||
|
||||
// Create window
|
||||
HWND hWnd = CreateWindowExW (
|
||||
0,
|
||||
L"STATIC",
|
||||
NULL,
|
||||
WS_OVERLAPPEDWINDOW,
|
||||
CW_USEDEFAULT,CW_USEDEFAULT,0,0,
|
||||
NULL,NULL,hInst,NULL);
|
||||
WinAPIError() : WinAPIError(GetLastError()) {}
|
||||
WinAPIError(error_code err) : std::runtime_error(format_error(err)) {}
|
||||
|
||||
if(!hWnd)
|
||||
private:
|
||||
static std::string format_error(error_code err)
|
||||
{
|
||||
pGL->Error(" gl: Failed to create temporary window to choose pixel format");
|
||||
LPWSTR buffer = 0;
|
||||
FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_FROM_SYSTEM,
|
||||
0, err, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), reinterpret_cast<LPWSTR>(&buffer), 0, 0);
|
||||
StdStrBuf str(buffer);
|
||||
LocalFree(buffer);
|
||||
return std::string(str.getData(), str.getLength());
|
||||
}
|
||||
else
|
||||
};
|
||||
|
||||
class GLTempContext
|
||||
{
|
||||
HWND wnd;
|
||||
HDC dc;
|
||||
HGLRC glrc;
|
||||
public:
|
||||
GLTempContext()
|
||||
{
|
||||
HDC dc = GetDC(hWnd);
|
||||
|
||||
PIXELFORMATDESCRIPTOR pfd;
|
||||
|
||||
// pixel format
|
||||
memset(&pfd, 0, sizeof(PIXELFORMATDESCRIPTOR)) ;
|
||||
pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR);
|
||||
pfd.nVersion = 1 ;
|
||||
pfd.dwFlags = PFD_DOUBLEBUFFER |
|
||||
PFD_SUPPORT_OPENGL |
|
||||
PFD_DRAW_TO_WINDOW ;
|
||||
wnd = CreateWindowExW(0, L"STATIC", 0, WS_OVERLAPPEDWINDOW, 0, 0, 0, 0, 0, 0, GetModuleHandle(0), 0);
|
||||
if (!wnd)
|
||||
throw WinAPIError();
|
||||
dc = GetDC(wnd);
|
||||
auto pfd = PIXELFORMATDESCRIPTOR();
|
||||
pfd.nSize = sizeof(pfd);
|
||||
pfd.nVersion = 1;
|
||||
pfd.dwFlags = PFD_DOUBLEBUFFER | PFD_SUPPORT_OPENGL | PFD_DRAW_TO_WINDOW;
|
||||
pfd.iPixelType = PFD_TYPE_RGBA;
|
||||
pfd.cColorBits = pGL->iClrDpt;
|
||||
pfd.cDepthBits = 0;
|
||||
pfd.iLayerType = PFD_MAIN_PLANE;
|
||||
int temp_fmt = ChoosePixelFormat(dc, &pfd);
|
||||
|
||||
if(!temp_fmt)
|
||||
int format = ChoosePixelFormat(dc, &pfd);
|
||||
if (!format ||
|
||||
!SetPixelFormat(dc, format, &pfd) ||
|
||||
(glrc = wglCreateContext(dc)) == 0)
|
||||
{
|
||||
pGL->Error(" gl: Error choosing temp pixel format");
|
||||
DWORD err = GetLastError();
|
||||
ReleaseDC(wnd, dc);
|
||||
DestroyWindow(wnd);
|
||||
throw WinAPIError(err);
|
||||
}
|
||||
else if(!SetPixelFormat(dc, temp_fmt, &pfd))
|
||||
if (!wglMakeCurrent(dc, glrc))
|
||||
{
|
||||
pGL->Error(" gl: Error setting temp pixel format");
|
||||
DWORD err = GetLastError();
|
||||
wglDeleteContext(glrc);
|
||||
ReleaseDC(wnd, dc);
|
||||
DestroyWindow(wnd);
|
||||
throw WinAPIError(err);
|
||||
}
|
||||
else
|
||||
{
|
||||
HGLRC hrc = wglCreateContext(dc);
|
||||
if(!hrc)
|
||||
{
|
||||
pGL->Error(" gl: Error creating temp context");
|
||||
}
|
||||
else
|
||||
{
|
||||
if(!wglMakeCurrent(dc, hrc))
|
||||
{
|
||||
pGL->Error(" gl: Error making temp context current");
|
||||
}
|
||||
else
|
||||
{
|
||||
// init extensions
|
||||
glewExperimental = GL_TRUE;
|
||||
GLenum err = glewInit();
|
||||
if(err != GLEW_OK)
|
||||
{
|
||||
// Problem: glewInit failed, something is seriously wrong.
|
||||
pGL->Error(reinterpret_cast<const char*>(glewGetErrorString(err)));
|
||||
}
|
||||
else
|
||||
{
|
||||
glewInitialized = true;
|
||||
}
|
||||
|
||||
wglMakeCurrent(NULL, NULL);
|
||||
}
|
||||
|
||||
wglDeleteContext(hrc);
|
||||
}
|
||||
}
|
||||
|
||||
ReleaseDC(hWnd, dc);
|
||||
DestroyWindow(hWnd);
|
||||
}
|
||||
|
||||
return glewInitialized;
|
||||
}
|
||||
~GLTempContext()
|
||||
{
|
||||
if (glrc == wglGetCurrentContext())
|
||||
wglMakeCurrent(dc, 0);
|
||||
wglDeleteContext(glrc);
|
||||
ReleaseDC(wnd, dc);
|
||||
DestroyWindow(wnd);
|
||||
}
|
||||
};
|
||||
|
||||
CStdGLCtx::CStdGLCtx(): pWindow(0), hDC(0), this_context(contexts.end()) { }
|
||||
|
||||
|
@ -282,8 +257,28 @@ bool CStdGLCtx::Init(C4Window * pWindow, C4AbstractApp *pApp)
|
|||
// safety
|
||||
if (!pGL) return false;
|
||||
|
||||
// Initialize GLEW so that we can choose a pixel format later
|
||||
if(!InitGlew(pApp->hInstance)) return false;
|
||||
std::unique_ptr<GLTempContext> tempContext;
|
||||
if (hrc == 0)
|
||||
{
|
||||
// Create a temporary context to be able to fetch GL extension pointers
|
||||
try
|
||||
{
|
||||
tempContext.reset(new GLTempContext);
|
||||
glewExperimental = GL_TRUE;
|
||||
GLenum err = glewInit();
|
||||
if(err != GLEW_OK)
|
||||
{
|
||||
// Problem: glewInit failed, something is seriously wrong.
|
||||
pGL->Error(reinterpret_cast<const char*>(glewGetErrorString(err)));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
catch (const WinAPIError &e)
|
||||
{
|
||||
pGL->Error((std::string(" gl: Unable to create temporary context: ") + e.what()).c_str());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// store window
|
||||
this->pWindow = pWindow;
|
||||
|
|
Loading…
Reference in New Issue