]> git.tdb.fi Git - libs/gui.git/blob - source/graphics/glcontext.cpp
Consistently label the graphics part as graphics
[libs/gui.git] / source / graphics / glcontext.cpp
1 #include <vector>
2 #ifdef WIN32
3 #include <windows.h>
4 #endif
5 #ifdef WITH_OPENGL
6 #include <GL/gl.h>
7 #ifndef WIN32
8 #include <GL/glx.h>
9 #endif
10 #endif
11 #include <msp/core/application.h>
12 #include <msp/strings/format.h>
13 #include "display.h"
14 #include "glcontext.h"
15 #include "window.h"
16 #include "display_priv.h"
17
18 namespace Msp {
19 namespace Graphics {
20
21 GLOptions::GLOptions():
22         alpha(false),
23         stencil(false),
24         doublebuffer(true),
25         multisample(0)
26 { }
27
28
29 unsupported_gl_mode::unsupported_gl_mode(const GLOptions &opts):
30         runtime_error(format("{ .alpha=%s, .stencil=%s, .doublebuffer=%s, .multisample=%d }",
31                 opts.alpha, opts.stencil, opts.doublebuffer, opts.multisample))
32 { }
33
34
35 #ifdef WITH_OPENGL
36 #ifdef WIN32
37 typedef HGLRC Context;
38 #else
39 typedef GLXContext Context;
40 #endif
41
42 struct GLContext::Private
43 {
44         Context context;
45 #ifndef WIN32
46         // In X11, we need to create a window with the chosen visual
47         WindowHandle subwnd;
48 #endif
49 };
50 #endif
51
52
53 GLContext::GLContext(Window &wnd, const GLOptions &opts):
54         display(wnd.get_display()),
55         window(wnd)
56 {
57 #ifdef WITH_OPENGL
58         priv = new Private;
59
60 #ifdef WIN32
61         HDC dc = GetDC(window.get_private().window);
62
63         PIXELFORMATDESCRIPTOR pfd;
64         memset(&pfd, 0, sizeof(pfd));
65
66         pfd.nSize = sizeof(pfd);
67         pfd.nVersion = 1;
68         pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL;
69         if(opts.doublebuffer)
70                 pfd.dwFlags |= PFD_DOUBLEBUFFER;
71         pfd.iPixelType = PFD_TYPE_RGBA;
72         if(opts.alpha)
73                 pfd.cAlphaBits = 1;
74         pfd.cDepthBits = 1;
75         if(opts.stencil)
76                 pfd.cStencilBits = 1;
77
78         int pf_index = ChoosePixelFormat(dc, &pfd);
79         if(!pf_index)
80                 throw unsupported_gl_mode(opts);
81         SetPixelFormat(dc, pf_index, &pfd);
82
83         priv->context = wglCreateContext(dc);
84         wglMakeCurrent(dc, priv->context);
85
86         ReleaseDC(window.get_private().window, dc);
87 #else
88         std::vector<int> attribs;
89         
90         attribs.push_back(GLX_RGBA);
91         attribs.push_back(GLX_DEPTH_SIZE);
92         attribs.push_back(1);
93         
94         if(opts.alpha)
95         {
96                 attribs.push_back(GLX_ALPHA_SIZE);
97                 attribs.push_back(1);
98         }
99         
100         if(opts.stencil)
101         {
102                 attribs.push_back(GLX_STENCIL_SIZE);
103                 attribs.push_back(1);
104         }
105         
106         if(opts.doublebuffer)
107                 attribs.push_back(GLX_DOUBLEBUFFER);
108         
109         if(opts.multisample>0)
110         {
111                 attribs.push_back(GLX_SAMPLE_BUFFERS_ARB);
112                 attribs.push_back(opts.multisample);
113         }
114         
115         attribs.push_back(0);
116
117         ::Display *dpy = display.get_private().display;
118
119         XVisualInfo *vi = glXChooseVisual(dpy, DefaultScreen(dpy), &attribs.front());
120         if(!vi)
121                 throw unsupported_gl_mode(opts);
122         priv->context = glXCreateContext(dpy, vi, 0, true);
123
124         XSetWindowAttributes attr;
125         attr.colormap = XCreateColormap(dpy, DefaultRootWindow(dpy), vi->visual, AllocNone);
126
127         priv->subwnd = XCreateWindow(dpy, window.get_private().window, 0, 0, window.get_width(), window.get_height(), 0, vi->depth, InputOutput, vi->visual, CWColormap, &attr);
128         XMapWindow(dpy, priv->subwnd);
129
130         XFree(vi);
131
132         glXMakeCurrent(dpy, priv->subwnd, priv->context);
133 #endif
134 #else
135         (void)wnd;
136         (void)opts;
137         throw runtime_error("no OpenGL support");
138 #endif
139
140         window.signal_resize.connect(sigc::mem_fun(this, &GLContext::window_resized));
141 }
142
143 GLContext::~GLContext()
144 {
145 #ifdef WITH_OPENGL
146 #ifdef WIN32
147         wglMakeCurrent(0, 0);
148         wglDeleteContext(priv->context);
149 #else
150         ::Display *dpy = display.get_private().display;
151
152         glXMakeCurrent(dpy, 0, 0);
153         glXDestroyContext(dpy, priv->context);
154         XDestroyWindow(dpy, priv->subwnd);
155 #endif
156         delete priv;
157 #endif
158 }
159
160 void GLContext::swap_buffers()
161 {
162 #ifdef WITH_OPENGL
163 #ifdef WIN32
164         HDC dc = GetDC(window.get_private().window);
165         SwapBuffers(dc);
166         ReleaseDC(window.get_private().window, dc);
167 #else
168         glXSwapBuffers(display.get_private().display, priv->subwnd);
169 #endif
170 #endif
171 }
172
173 void GLContext::window_resized(unsigned w, unsigned h)
174 {
175 #ifdef WITH_OPENGL
176 #ifndef WIN32
177         XMoveResizeWindow(display.get_private().display, priv->subwnd, 0, 0, w, h);
178 #endif
179         glViewport(0, 0, w, h);
180 #else
181         (void)w;
182         (void)h;
183 #endif
184 }
185
186 } // namespace Graphics
187 } // namespace Msp