]> git.tdb.fi Git - libs/gui.git/blob - source/graphics/wgl/glcontext.cpp
Add support for using the latest available OpenGL version
[libs/gui.git] / source / graphics / wgl / glcontext.cpp
1 #include <vector>
2 #include <windows.h>
3 #include <GL/gl.h>
4 #include <GL/wglext.h>
5 #include <msp/strings/lexicalcast.h>
6 #include <msp/strings/utils.h>
7 #include "glcontext.h"
8 #include "window_private.h"
9
10 using namespace std;
11
12 namespace {
13
14 template<typename T>
15 T get_proc(const char *name)
16 {
17         return reinterpret_cast<T>(reinterpret_cast<void *>(wglGetProcAddress(name)));
18 }
19
20 }
21
22 namespace Msp {
23 namespace Graphics {
24
25 typedef HGLRC ContextHandle;
26
27 struct GLContext::Private
28 {
29         ContextHandle context;
30 };
31
32
33 void GLContext::platform_init(const GLOptions &opts)
34 {
35         HDC dc = GetDC(window.get_private().window);
36
37         PIXELFORMATDESCRIPTOR pfd;
38         memset(&pfd, 0, sizeof(pfd));
39
40         pfd.nSize = sizeof(pfd);
41         pfd.nVersion = 1;
42         pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL;
43         if(opts.doublebuffer)
44                 pfd.dwFlags |= PFD_DOUBLEBUFFER;
45         pfd.iPixelType = PFD_TYPE_RGBA;
46         if(opts.alpha)
47                 pfd.cAlphaBits = 1;
48         pfd.cDepthBits = 1;
49         if(opts.stencil)
50                 pfd.cStencilBits = 1;
51
52         int pf_index = ChoosePixelFormat(dc, &pfd);
53         if(!pf_index)
54                 throw unsupported_gl_mode(opts);
55         SetPixelFormat(dc, pf_index, &pfd);
56
57         priv = new Private;
58         if(opts.forward_compatible || opts.gl_version_major!=DEFAULT_VERSION)
59         {
60                 ContextHandle fake_context = wglCreateContext(dc);
61                 wglMakeCurrent(dc, fake_context);
62
63                 PFNWGLCREATECONTEXTATTRIBSARBPROC wglCreateContextAttribs = get_proc<PFNWGLCREATECONTEXTATTRIBSARBPROC>("wglCreateContextAttribsARB");
64                 if(!wglCreateContextAttribs)
65                         throw unsupported_gl_mode(opts);
66
67                 unsigned gl_version_major = opts.gl_version_major;
68                 unsigned gl_version_minor = opts.gl_version_minor;
69                 if(opts.gl_version_major==GLOptions::LATEST_VERSION)
70                 {
71                         const char *gl_ver_ptr = reinterpret_cast<const char *>(glGetString(GL_VERSION));
72                         if(!gl_ver_ptr)
73                                 throw unsupported_gl_mode(opts);
74
75                         string gl_ver = gl_ver_ptr;
76                         vector<string> parts = split(gl_ver.substr(0, gl_ver.find(' ')), '.');
77
78                         gl_version_major = lexical_cast<unsigned>(parts[0]);
79                         gl_version_minor = lexical_cast<unsigned>(parts[1]);
80                 }
81
82                 vector<int> ctx_attribs;
83
84                 if(opts.forward_compatible)
85                 {
86                         ctx_attribs.push_back(WGL_CONTEXT_FLAGS_ARB);
87                         ctx_attribs.push_back(WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB);
88                 }
89
90                 if(opts.core_profile)
91                 {
92                         ctx_attribs.push_back(WGL_CONTEXT_PROFILE_MASK_ARB);
93                         ctx_attribs.push_back(WGL_CONTEXT_CORE_PROFILE_BIT_ARB);
94                 }
95
96                 if(opts.gl_version_major)
97                 {
98                         ctx_attribs.push_back(WGL_CONTEXT_MAJOR_VERSION_ARB);
99                         ctx_attribs.push_back(gl_version_major);
100                         ctx_attribs.push_back(WGL_CONTEXT_MINOR_VERSION_ARB);
101                         ctx_attribs.push_back(gl_version_minor);
102                 }
103
104                 ctx_attribs.push_back(0);
105
106                 priv->context = wglCreateContextAttribs(dc, 0, &ctx_attribs[0]);
107                 if(!priv->context)
108                         throw unsupported_gl_mode(opts);
109
110                 wglMakeCurrent(0, 0);
111                 wglDeleteContext(fake_context);
112         }
113         else
114                 priv->context = wglCreateContext(dc);
115         wglMakeCurrent(dc, priv->context);
116
117         ReleaseDC(window.get_private().window, dc);
118 }
119
120 GLContext::~GLContext()
121 {
122         wglMakeCurrent(0, 0);
123         wglDeleteContext(priv->context);
124
125         delete priv;
126 }
127
128 void GLContext::set_swap_interval(unsigned i)
129 {
130         PFNWGLSWAPINTERVALEXTPROC wglSwapInterval = get_proc<PFNWGLSWAPINTERVALEXTPROC>("wglSwapIntervalEXT");
131         if(!wglSwapInterval)
132                 throw runtime_error("wglSwapIntervalEXT not found");
133         wglSwapInterval(i);
134 }
135
136 void GLContext::swap_buffers()
137 {
138         HDC dc = GetDC(window.get_private().window);
139         SwapBuffers(dc);
140         ReleaseDC(window.get_private().window, dc);
141 }
142
143 void GLContext::window_resized(unsigned, unsigned)
144 { }
145
146 } // namespace Graphics
147 } // namespace Msp