]> Pileus Git - grits/blob - src/gtkgl.c
Support OpenGL extensions under Win32
[grits] / src / gtkgl.c
1 /*
2  * Copyright (C) 2009-2011 Andy Spencer <andy753421@gmail.com>
3  *
4  * This program is free software: you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation, either version 3 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
16  */
17
18 #include <gtk/gtk.h>
19
20 /***************************
21  * GtkGlExt implementation *
22  ***************************/
23 #if defined(SYS_GTKGLEXT)
24 #include <gtk/gtkgl.h>
25 void gtk_gl_enable(GtkWidget *widget)
26 {
27         GdkGLConfig *glconfig = gdk_gl_config_new_by_mode(
28                         GDK_GL_MODE_RGBA   | GDK_GL_MODE_DEPTH |
29                         GDK_GL_MODE_ALPHA  | GDK_GL_MODE_DOUBLE);
30         gtk_widget_set_gl_capability(widget,
31                         glconfig, NULL, TRUE, GDK_GL_RGBA_TYPE);
32 }
33
34 void gtk_gl_begin(GtkWidget *widget)
35 {
36         GdkGLContext  *glcontext  = gtk_widget_get_gl_context(widget);
37         GdkGLDrawable *gldrawable = gtk_widget_get_gl_drawable(widget);
38         gdk_gl_drawable_gl_begin(gldrawable, glcontext);
39 }
40
41 void gtk_gl_end(GtkWidget *widget)
42 {
43         GdkGLDrawable *gldrawable = gtk_widget_get_gl_drawable(widget);
44         gdk_gl_drawable_swap_buffers(gldrawable);
45         gdk_gl_drawable_gl_end(gldrawable);
46 }
47
48 void gtk_gl_disable(GtkWidget *widget)
49 {
50 }
51
52
53 /**********************
54  * X11 implementation *
55  **********************/
56 #elif defined(SYS_X11)
57 #include <GL/glx.h>
58 #include <gdk/gdkx.h>
59 void gtk_gl_enable(GtkWidget *widget)
60 {
61         g_debug("GtkGl: enable");
62         GdkScreen *screen   = gdk_screen_get_default();
63         Display   *xdisplay = GDK_SCREEN_XDISPLAY(screen);
64         gint       nscreen  = GDK_SCREEN_XNUMBER(screen);
65
66         /* Create context */
67         int attribs[] = {GLX_RGBA,
68                          GLX_RED_SIZE,    1,
69                          GLX_GREEN_SIZE,  1,
70                          GLX_BLUE_SIZE,   1,
71                          GLX_ALPHA_SIZE,  1,
72                          GLX_DOUBLEBUFFER,
73                          GLX_DEPTH_SIZE,  1,
74                          None};
75         XVisualInfo *xvinfo  = glXChooseVisual(xdisplay, nscreen, attribs);
76         if (!xvinfo)
77                 g_error("GtkGl: enable - unable to get valid OpenGL Visual");
78         GLXContext   context = glXCreateContext(xdisplay, xvinfo, NULL, False);
79         g_object_set_data(G_OBJECT(widget), "glcontext", context);
80
81         /* Fix up colormap */
82         GdkVisual   *visual = gdk_x11_screen_lookup_visual(screen, xvinfo->visualid);
83         GdkColormap *cmap   = gdk_colormap_new(visual, FALSE);
84         gtk_widget_set_colormap(widget, cmap);
85
86         /* Disable GTK double buffering */
87         gtk_widget_set_double_buffered(widget, FALSE);
88 }
89
90 void gtk_gl_begin(GtkWidget *widget)
91 {
92         g_debug("GtkGl: begin");
93         Display   *xdisplay = GDK_SCREEN_XDISPLAY(gtk_widget_get_screen(widget));
94         Window     xwindow  = GDK_WINDOW_XID(gtk_widget_get_window(widget));
95         GLXContext context  = g_object_get_data(G_OBJECT(widget), "glcontext");
96         glXMakeCurrent(xdisplay, xwindow, context);
97 }
98
99 void gtk_gl_end(GtkWidget *widget)
100 {
101         g_debug("GtkGl: end");
102         Display   *xdisplay = GDK_SCREEN_XDISPLAY(gtk_widget_get_screen(widget));
103         Window     xwindow  = GDK_WINDOW_XID(gtk_widget_get_window(widget));
104         glXSwapBuffers(xdisplay, xwindow);
105 }
106
107 void gtk_gl_disable(GtkWidget *widget)
108 {
109         g_debug("GtkGl: disable");
110         Display   *xdisplay = GDK_SCREEN_XDISPLAY(gtk_widget_get_screen(widget));
111         GLXContext context  = g_object_get_data(G_OBJECT(widget), "glcontext");
112         glXDestroyContext(xdisplay, context);
113 }
114
115
116 /************************
117  * Win32 implementation *
118  ************************/
119 #elif defined(SYS_WIN)
120 #include <windows.h>
121 #include <gdk/gdkwin32.h>
122 #include <GL/gl.h>
123
124 /* Windows doens't define OpenGL extensions */
125 static void APIENTRY (*glMultiTexCoord2dvPtr)(int target, const double *v);
126 static void APIENTRY (*glActiveTexturePtr)(int texture);
127
128 void APIENTRY glMultiTexCoord2dv(int target, const double *v)
129 {
130         glMultiTexCoord2dvPtr(target, v);
131 }
132
133 void APIENTRY glActiveTexture(int texture)
134 {
135         glActiveTexturePtr(texture);
136 }
137
138 static void init_extensions(void)
139 {
140         static gboolean init_done = FALSE;
141         if (init_done)
142                 return;
143         init_done = TRUE;
144
145         g_debug("GtkGl: init_extensions");
146         const guchar *exts = NULL;
147         if (!(exts = glGetString(GL_EXTENSIONS)))
148                 g_error("GtkGl: Unable to query extensions");
149         if (!(glMultiTexCoord2dvPtr = (void*)wglGetProcAddress("glMultiTexCoord2dvARB")))
150                 g_error("GtkGl: Unable to load glMultiTexCoord2dv extension:\n%s", exts);
151         if (!(glActiveTexturePtr    = (void*)wglGetProcAddress("glActiveTextureARB")))
152                 g_error("GtkGl: Unable to load glActiveTexture extension\n%s", exts);
153         g_debug("GtkGl: extensions - glMultiTexCoord2dvPtr=%p glActiveTexturePtr=%p",
154                         glMultiTexCoord2dvPtr, glActiveTexturePtr);
155 }
156
157 /* gtkgl implementation */
158 static void on_realize(GtkWidget *widget, gpointer _)
159 {
160         g_debug("GtkGl: on_realize");
161         gdk_window_ensure_native(gtk_widget_get_window(widget));
162         gtk_widget_set_double_buffered(widget, FALSE);
163
164         HWND  hwnd = GDK_WINDOW_HWND(gtk_widget_get_window(widget));
165         HDC   hDC  = GetDC(hwnd);
166
167         PIXELFORMATDESCRIPTOR pfd = {
168                 .nSize       = sizeof(pfd),
169                 .nVersion    = 1,
170                 .dwFlags     = PFD_DRAW_TO_WINDOW
171                              | PFD_SUPPORT_OPENGL
172                              | PFD_DOUBLEBUFFER,
173                 //.dwFlags     = PFD_SUPPORT_OPENGL
174                 //             | PFD_DRAW_TO_WINDOW,
175                 .iPixelType  = PFD_TYPE_RGBA,
176                 .cColorBits  = 24,
177                 .cAlphaBits  = 8,
178                 .cDepthBits  = 32,
179                 .iLayerType  = PFD_MAIN_PLANE,
180         };
181         int pf = ChoosePixelFormat(hDC, &pfd);
182         if (pf == 0)
183                 g_error("GtkGl: ChoosePixelFormat failed");
184         if (!SetPixelFormat(hDC, pf, &pfd))
185                 g_error("GtkGl: SetPixelFormat failed");
186         HGLRC hRC = wglCreateContext(hDC);
187         if (hRC == NULL)
188                 g_error("GtkGl: wglCreateContext failed");
189         g_object_set_data(G_OBJECT(widget), "glcontext", hRC);
190 }
191
192 void gtk_gl_enable(GtkWidget *widget)
193 {
194         g_debug("GtkGl: enable");
195         g_signal_connect(widget, "realize", G_CALLBACK(on_realize), NULL);
196 }
197
198 void gtk_gl_begin(GtkWidget *widget)
199 {
200         g_debug("GtkGl: begin");
201         HWND  hwnd = GDK_WINDOW_HWND(gtk_widget_get_window(widget));
202         HDC   hDC  = GetDC(hwnd);
203         HGLRC hRC  = g_object_get_data(G_OBJECT(widget), "glcontext");
204         if (!wglMakeCurrent(hDC, hRC))
205                 g_error("GtkGl: wglMakeCurrent failed");
206         init_extensions();
207 }
208
209 void gtk_gl_end(GtkWidget *widget)
210 {
211         g_debug("GtkGl: end");
212         HWND  hwnd = GDK_WINDOW_HWND(gtk_widget_get_window(widget));
213         HDC   hDC  = GetDC(hwnd);
214         if (!SwapBuffers(hDC))
215                 g_error("GtkGl: SwapBuffers failed");
216 }
217
218 void gtk_gl_disable(GtkWidget *widget)
219 {
220         g_debug("GtkGl: disable");
221         HGLRC hRC = g_object_get_data(G_OBJECT(widget), "glcontext");
222         wglDeleteContext(hRC);
223 }
224
225
226 /**************************
227  * Mac OSX implementation *
228  **************************/
229 #elif defined(SYS_MAC)
230 #include <gdk/gdkquartz.h>
231 void gtk_gl_enable(GtkWidget *widget)
232 {
233         g_debug("GtkGl: enable");
234
235         /* Create context */
236         NSOpenGLPixelFormatAttribute attribs[] = {
237                 NSOpenGLPFAColorSize, 24,
238                 NSOpenGLPFAAlphaSize, 8,
239                 NSOpenGLPFADepthSize, 1,
240                 NSOpenGLPFADoubleBuffer,
241                 0
242         };
243         NSOpenGLPixelFormat *pix = [[NSOpenGLPixelFormat alloc] initWithAttributes:attribs];
244         NSOpenGLContext     *ctx = [[NSOpenGLContext     alloc] initWithFormat:pix shareContext:nil];
245
246         /* Attach to widget */
247         gtk_widget_set_double_buffered(widget, FALSE);
248
249         /* Save context */
250         g_object_set_data(G_OBJECT(widget), "glcontext", ctx);
251 }
252
253 void gtk_gl_begin(GtkWidget *widget)
254 {
255         g_debug("GtkGl: begin");
256         GtkAllocation alloc;
257         gdk_window_ensure_native(gtk_widget_get_window(widget));
258         gtk_widget_get_allocation(widget, &alloc);
259
260         NSOpenGLContext *ctx  = g_object_get_data(G_OBJECT(widget), "glcontext");
261         GdkWindow       *win  = gtk_widget_get_window(widget);
262         NSView          *view = gdk_quartz_window_get_nsview(win);
263         NSRect           rect = NSMakeRect(alloc.x, alloc.y, alloc.width, alloc.height);
264
265         [ctx  setView:view];
266         [ctx  makeCurrentContext];
267         [ctx  update];
268         [view setFrame:rect];
269 }
270
271 void gtk_gl_end(GtkWidget *widget)
272 {
273         g_debug("GtkGl: end");
274         NSOpenGLContext *ctx = g_object_get_data(G_OBJECT(widget), "glcontext");
275         [ctx flushBuffer];
276 }
277
278 void gtk_gl_disable(GtkWidget *widget)
279 {
280         g_debug("GtkGl: disable");
281 }
282
283
284 /****************************
285  * Undefined implementation *
286  ****************************/
287 #else
288 #warning "Unimplemented GtkGl"
289 void gtk_gl_enable(GtkWidget *widget) { }
290 void gtk_gl_begin(GtkWidget *widget) { }
291 void gtk_gl_end(GtkWidget *widget) { }
292 void gtk_gl_disable(GtkWidget *widget) { }
293 #endif