Add support for GTK 3
[grits] / examples / gl / gl.c
1 #include <math.h>
2 #include <gtk/gtk.h>
3 #include <gdk/gdkkeysyms.h>
4
5 //#define SYS_CAIRO
6 //#define SYS_GTKGLEXT
7 //#define SYS_X11
8 //#define SYS_WIN
9 //#define SYS_MAC
10
11 /************************
12  * Cairo implementation *
13  ************************/
14 #if defined(SYS_CAIRO)
15 gpointer setup(GtkWidget *widget) { return NULL; }
16 gboolean expose(GtkWidget *widget, gpointer data, gpointer user_data)
17 {
18         GtkAllocation alloc;
19         gtk_widget_get_allocation(widget, &alloc);
20         cairo_t *cairo = gdk_cairo_create(gtk_widget_get_window(widget));
21         cairo_set_source_rgb(cairo, 1, 1, 1);
22         cairo_arc(cairo,
23                 alloc.width/2, alloc.height/2,
24                 MIN(alloc.width/2,alloc.height/2),
25                 0, 2*G_PI);
26         cairo_fill(cairo);
27         return FALSE;
28 }
29
30
31 /***************************
32  * GtkGlExt implementation *
33  ***************************/
34 #elif defined(SYS_GTKGLEXT)
35 #include <gtk/gtkgl.h>
36 #include <GL/gl.h>
37 void realize(GtkWidget *widget, gpointer user_data)
38 {
39         gdk_window_ensure_native(gtk_widget_get_window(widget));
40 }
41 gpointer setup(GtkWidget *widget)
42 {
43         //GdkGLConfig *glconfig = gdk_gl_config_new_by_mode(
44         //              GDK_GL_MODE_RGBA   | GDK_GL_MODE_DEPTH |
45         //              GDK_GL_MODE_ALPHA);
46         GdkGLConfig *glconfig = gdk_gl_config_new_by_mode(
47                         GDK_GL_MODE_RGBA   | GDK_GL_MODE_DEPTH |
48                         GDK_GL_MODE_ALPHA  | GDK_GL_MODE_DOUBLE);
49         gtk_widget_set_gl_capability(widget,
50                         glconfig, NULL, TRUE, GDK_GL_RGBA_TYPE);
51         return NULL;
52 }
53 gboolean expose(GtkWidget *widget, gpointer data, gpointer user_data)
54 {
55         GtkAllocation alloc;
56         gtk_widget_get_allocation(widget, &alloc);
57         GdkGLContext  *glcontext  = gtk_widget_get_gl_context(widget);
58         GdkGLDrawable *gldrawable = gtk_widget_get_gl_drawable(widget);
59         gdk_gl_drawable_gl_begin(gldrawable, glcontext);
60         glViewport(0, 0, alloc.width, alloc.height);
61         glClear(GL_COLOR_BUFFER_BIT);
62         glColor3f(1.0, 1.0, 1.0);
63         glBegin(GL_TRIANGLE_FAN);
64         glVertex2f(0.0, 0.0);
65         for (double i = 0; i < 2*G_PI; i+=(2*G_PI)/100)
66                 glVertex2d(sin(i), cos(i));
67         glEnd();
68         gdk_gl_drawable_swap_buffers(gldrawable);
69         gdk_gl_drawable_gl_end(gldrawable);
70         return FALSE;
71 }
72
73
74 /**********************
75  * X11 implementation *
76  **********************/
77 #elif defined(SYS_X11)
78 #include <GL/gl.h>
79 #include <GL/glx.h>
80 #include <gdk/gdkx.h>
81 void realize(GtkWidget *widget, gpointer user_data)
82 {
83         gdk_window_ensure_native(gtk_widget_get_window(widget));
84 }
85 gpointer setup(GtkWidget *widget)
86 {
87         GdkScreen *screen    = gdk_screen_get_default();
88         Display   *xdisplay  = GDK_SCREEN_XDISPLAY(screen);
89         gint       nscreen   = GDK_SCREEN_XNUMBER(screen);
90
91         /* Create context */
92         int attribs[]        = {GLX_RGBA,
93                                 GLX_RED_SIZE,    1,
94                                 GLX_GREEN_SIZE,  1,
95                                 GLX_BLUE_SIZE,   1,
96                                 GLX_ALPHA_SIZE,  1,
97                                 GLX_DOUBLEBUFFER,
98                                 GLX_DEPTH_SIZE,  1,
99                                 None};
100         XVisualInfo *xvinfo  = glXChooseVisual(xdisplay, nscreen, attribs);
101         GLXContext   context = glXCreateContext(xdisplay, xvinfo, 0, True);
102
103         /* Fix up visual/colormap */
104 #if GTK_CHECK_VERSION(3,0,0)
105         GdkVisual *visual = gdk_x11_screen_lookup_visual(screen, xvinfo->visualid);
106         gtk_widget_set_visual(widget, visual);
107 #else
108         GdkVisual   *visual  = gdk_x11_screen_lookup_visual(screen, xvinfo->visualid);
109         GdkColormap *cmap    = gdk_colormap_new(visual, FALSE);
110         gtk_widget_set_colormap(widget, cmap);
111 #endif
112
113         /* Disable GTK double buffering */
114         gtk_widget_set_double_buffered(widget, FALSE);
115
116         return context;
117 }
118 gboolean expose(GtkWidget *widget, gpointer data, GLXContext context)
119 {
120         /* Make current */
121         Display     *xdisplay = GDK_SCREEN_XDISPLAY(gdk_screen_get_default());
122         Window       xwindow  = GDK_WINDOW_XID(gtk_widget_get_window(widget));
123         glXMakeCurrent(xdisplay, xwindow, context);
124
125         GtkWidget *toplevel = gtk_widget_get_toplevel(widget);
126         g_message("window: w=%x tl=%x",
127                 (guint)GDK_WINDOW_XID(gtk_widget_get_window(widget)),
128                 (guint)GDK_WINDOW_XID(gtk_widget_get_window(toplevel)));
129
130         /* Drawing */
131         GtkAllocation alloc;
132         gtk_widget_get_allocation(widget, &alloc);
133         glViewport(0, 0, alloc.width, alloc.height);
134         glClear(GL_COLOR_BUFFER_BIT);
135         glColor3f(1.0, 1.0, 1.0);
136         glBegin(GL_TRIANGLE_FAN);
137         glVertex2f(0.0, 0.0);
138         for (double i = 0; i < 2*G_PI; i+=(2*G_PI)/100)
139                 glVertex2d(sin(i), cos(i));
140         glEnd();
141
142         /* Swap buffers */
143         glXSwapBuffers(xdisplay, xwindow);
144         return FALSE;
145 }
146
147
148 /************************
149  * Win32 implementation *
150  ************************/
151 #elif defined(SYS_WIN)
152 #include <GL/gl.h>
153 #include <windows.h>
154 #include <gdk/gdkwin32.h>
155 void realize(GtkWidget *widget, gpointer user_data)
156 {
157         gdk_window_ensure_native(gtk_widget_get_window(widget));
158 }
159 gpointer setup(GtkWidget *widget)
160 {
161         /* Create context */
162         //HWND  hwnd = GDK_WINDOW_HWND(gtk_widget_get_window(widget));
163         //HGLRC hDC  = GetDC(hwnd);           // get the device context for window
164         //HDC   hRC  = wglCreateContext(hDC); // create rendering context
165         //wglMakeCurrent(hDC,hRC);            // make rendering context current
166
167         /* Delete context */
168         //wglMakeCurrent(hDC,NULL);    // deselect rendering context
169         //wglDeleteContext(hRC);       // delete rendering context
170         //PostQuitMessage(0);          // send wm_quit
171
172         /* Disable GTK double buffering */
173         gtk_widget_set_double_buffered(widget, FALSE);
174         return FALSE;
175 }
176 gboolean expose(GtkWidget *widget, gpointer data, gpointer user_data)
177 {
178         GtkWidget *toplevel = gtk_widget_get_toplevel(widget);
179         GdkWindow *window   = gtk_widget_get_window(widget);
180         GdkWindow *topwin   = gtk_widget_get_window(toplevel);
181         gdk_window_ensure_native(window);
182
183         PIXELFORMATDESCRIPTOR pfo = {}, pfd = {
184                 .nSize       = sizeof(pfd),
185                 .nVersion    = 1,
186                 .dwFlags     = PFD_DRAW_TO_WINDOW // "Correct" way
187                              | PFD_SUPPORT_OPENGL
188                              | PFD_DOUBLEBUFFER,
189                 //.dwFlags     = PFD_SUPPORT_OPENGL  // Works in wine
190                 //             | PFD_DRAW_TO_WINDOW,
191                 .iPixelType  = PFD_TYPE_RGBA,
192                 .cColorBits  = 24,
193                 .cAlphaBits  = 8,
194                 .cDepthBits  = 32,
195                 .iLayerType  = PFD_MAIN_PLANE,
196         };
197         HWND  hwnd = GDK_WINDOW_HWND(window);
198         HDC   hDC  = GetDC(hwnd);           // get the device context for window
199         int   pf   = ChoosePixelFormat(hDC, &pfd);
200         int   st0  = DescribePixelFormat(hDC, pf, sizeof(pfd), &pfo);
201         int   st1  = SetPixelFormat(hDC, pf, &pfd);
202         HGLRC hRC  = wglCreateContext(hDC);
203         int   st2  = wglMakeCurrent(hDC, hRC);
204
205         g_message("dc: %p, %p, %p", hDC, GetDC(hwnd), wglGetCurrentDC());
206
207         g_message("window: pf=%d st=%d,%d,%d dc=%p rc=%p wins=%x=%x!=%x",
208                 pf, st0,st1,st2, hDC, hRC, (guint)hwnd,
209                 (guint)GDK_WINDOW_HWND(window),
210                 (guint)GDK_WINDOW_HWND(topwin));
211
212         g_message("pdfOut: dwFlags=%lx=%lx, ipt=%x=%x, layer=%x=%x, {c,a,d}bits=%d,%d,%d",
213                 pfo.dwFlags,    pfd.dwFlags,
214                 pfo.iPixelType, pfd.iPixelType,
215                 pfo.iLayerType, pfd.iLayerType,
216                 pfo.cColorBits, pfo.cAlphaBits, pfo.cDepthBits);
217
218         /* Drawing */
219         GtkAllocation alloc = widget->allocation;
220         glViewport(0, 0, alloc.width, alloc.height);
221         g_message("alloc: %dx%d", alloc.width, alloc.height);
222         glClear(GL_COLOR_BUFFER_BIT);
223         glColor3f(1.0, 1.0, 1.0);
224         glBegin(GL_TRIANGLE_FAN);
225         glVertex2f(0.0, 0.0);
226         for (double i = 0; i < 2*G_PI; i+=(2*G_PI)/100)
227                 glVertex2d(sin(i), cos(i));
228         glEnd();
229
230         /* Swap buffers */
231         SwapBuffers(hDC);
232
233         /* Cleanup */
234         wglMakeCurrent(NULL, NULL);
235         wglDeleteContext(hRC);
236         return TRUE;
237 }
238
239
240 /**************************
241  * Mac OSX implementation *
242  **************************/
243 #elif defined(SYS_MAC)
244 #include <OpenGL/gl.h>
245 #include <OpenGL/glu.h>
246 #include <gdk/gdkquartz.h>
247 gpointer setup(GtkWidget *widget)
248 {
249         /* Create context */
250         NSOpenGLPixelFormatAttribute attribs[] = {
251                 NSOpenGLPFAColorSize, 24,
252                 NSOpenGLPFAAlphaSize, 8,
253                 NSOpenGLPFADepthSize, 1,
254                 NSOpenGLPFADoubleBuffer,
255                 0
256         };
257         NSOpenGLPixelFormat *pix  = [[NSOpenGLPixelFormat alloc] initWithAttributes:attribs];
258         NSOpenGLContext     *ctx  = [[NSOpenGLContext     alloc] initWithFormat:pix shareContext:nil];
259
260         /* Disable GTK double buffering */
261         gtk_widget_set_double_buffered(widget, FALSE);
262
263         return ctx;
264 }
265 gboolean configure(GtkWidget *widget, GdkEventConfigure *event, NSOpenGLContext *ctx)
266 {
267         GtkAllocation alloc;
268         gtk_widget_get_allocation(widget, &alloc);
269
270         GdkWindow *win  = gtk_widget_get_window(widget);
271         NSView    *view = gdk_quartz_window_get_nsview(win);
272         NSRect     rect = NSMakeRect(alloc.x, alloc.y, alloc.width, alloc.height);
273
274         [view setFrame:rect];
275         [ctx  update];
276         return FALSE;
277 }
278 gboolean expose(GtkWidget *widget, gpointer data, NSOpenGLContext *ctx)
279 {
280         gdk_window_ensure_native(gtk_widget_get_window(widget));
281
282         GdkWindow *win  = gtk_widget_get_window(widget);
283         NSView    *view = gdk_quartz_window_get_nsview(win);
284
285         configure(widget, NULL, ctx);
286
287         [ctx setView:view];
288         [ctx makeCurrentContext];
289
290         /* Drawing */
291         GtkAllocation alloc;
292         gtk_widget_get_allocation(widget, &alloc);
293         glViewport(0, 0, alloc.width, alloc.height);
294         glClear(GL_COLOR_BUFFER_BIT);
295         glColor3f(1.0, 1.0, 1.0);
296         glBegin(GL_TRIANGLE_FAN);
297         glVertex2f(0.0, 0.0);
298         for (double i = 0; i < 2*G_PI; i+=(2*G_PI)/100)
299                 glVertex2d(sin(i), cos(i));
300         glEnd();
301
302         [ctx flushBuffer];
303         return FALSE;
304 }
305
306
307 /****************************
308  * Undefined implementation *
309  ****************************/
310 #else
311 gpointer setup(GtkWidget *widget) { return NULL; }
312 gboolean expose(GtkWidget *widget, gpointer data, gpointer user_data)
313 {
314         g_message("unimplemented");
315         return FALSE;
316 }
317 #endif
318
319
320
321 /***************
322  * Common code *
323  ***************/
324 gboolean key_press(GtkWidget *widget, GdkEventKey *event, gpointer user_data)
325 {
326         if (event->keyval == GDK_KEY_q)
327                 gtk_main_quit();
328         return FALSE;
329 }
330 int main(int argc, char **argv)
331 {
332         gtk_init_check(&argc, &argv);
333         GtkWidget *window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
334         GtkWidget *box    = gtk_box_new(GTK_ORIENTATION_VERTICAL, 5);
335         GtkWidget *draw   = gtk_drawing_area_new();
336         GtkWidget *label  = gtk_label_new("Hello, World");
337         GtkWidget *button = gtk_button_new_with_label("Hello, World");
338         gpointer   data   = setup(draw);
339         g_signal_connect(window, "destroy",         G_CALLBACK(gtk_main_quit), NULL);
340         g_signal_connect(window, "key-press-event", G_CALLBACK(key_press),     NULL);
341         //g_signal_connect(draw,   "configure-event", G_CALLBACK(configure),     data);
342 #if GTK_CHECK_VERSION(3,0,0)
343         g_signal_connect(draw,   "draw",            G_CALLBACK(expose),        data);
344 #else
345         g_signal_connect(draw,   "expose-event",    G_CALLBACK(expose),        data);
346 #endif
347         gtk_widget_set_size_request(draw,   300, 300);
348         gtk_widget_set_size_request(button, -1,  50);
349         gtk_box_pack_start(GTK_BOX(box), label,  FALSE, TRUE, 0);
350         gtk_box_pack_start(GTK_BOX(box), draw,   TRUE,  TRUE, 0);
351         gtk_box_pack_start(GTK_BOX(box), button, FALSE, TRUE, 0);
352         gtk_container_add(GTK_CONTAINER(window), box);
353         gtk_widget_show_all(window);
354         gtk_main();
355         return 0;
356 }