45075f6d724616ffe07b23a1c9cd4066e3e28522
[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 colormap */
104         GdkVisual   *visual  = gdk_x11_screen_lookup_visual(screen, xvinfo->visualid);
105         GdkColormap *cmap    = gdk_colormap_new(visual, FALSE);
106         gtk_widget_set_colormap(widget, cmap);
107
108         /* Disable GTK double buffering */
109         gtk_widget_set_double_buffered(widget, FALSE);
110
111         return context;
112 }
113 gboolean expose(GtkWidget *widget, gpointer data, GLXContext context)
114 {
115         /* Make current */
116         Display     *xdisplay = GDK_SCREEN_XDISPLAY(gdk_screen_get_default());
117         Window       xwindow  = GDK_WINDOW_XID(gtk_widget_get_window(widget));
118         glXMakeCurrent(xdisplay, xwindow, context);
119
120         GtkWidget *toplevel = gtk_widget_get_toplevel(widget);
121         g_message("window: w=%x tl=%x",
122                 (guint)GDK_WINDOW_XID(gtk_widget_get_window(widget)),
123                 (guint)GDK_WINDOW_XID(gtk_widget_get_window(toplevel)));
124
125         /* Drawing */
126         GtkAllocation alloc;
127         gtk_widget_get_allocation(widget, &alloc);
128         glViewport(0, 0, alloc.width, alloc.height);
129         glClear(GL_COLOR_BUFFER_BIT);
130         glColor3f(1.0, 1.0, 1.0);
131         glBegin(GL_TRIANGLE_FAN);
132         glVertex2f(0.0, 0.0);
133         for (double i = 0; i < 2*G_PI; i+=(2*G_PI)/100)
134                 glVertex2d(sin(i), cos(i));
135         glEnd();
136
137         /* Swap buffers */
138         glXSwapBuffers(xdisplay, xwindow);
139         return FALSE;
140 }
141
142
143 /************************
144  * Win32 implementation *
145  ************************/
146 #elif defined(SYS_WIN)
147 #include <GL/gl.h>
148 #include <windows.h>
149 #include <gdk/gdkwin32.h>
150 void realize(GtkWidget *widget, gpointer user_data)
151 {
152         gdk_window_ensure_native(gtk_widget_get_window(widget));
153 }
154 gpointer setup(GtkWidget *widget)
155 {
156         /* Create context */
157         //HWND  hwnd = GDK_WINDOW_HWND(gtk_widget_get_window(widget));
158         //HGLRC hDC  = GetDC(hwnd);           // get the device context for window
159         //HDC   hRC  = wglCreateContext(hDC); // create rendering context
160         //wglMakeCurrent(hDC,hRC);            // make rendering context current
161
162         /* Delete context */
163         //wglMakeCurrent(hDC,NULL);    // deselect rendering context
164         //wglDeleteContext(hRC);       // delete rendering context
165         //PostQuitMessage(0);          // send wm_quit
166
167         /* Disable GTK double buffering */
168         gtk_widget_set_double_buffered(widget, FALSE);
169         return FALSE;
170 }
171 gboolean expose(GtkWidget *widget, gpointer data, gpointer user_data)
172 {
173         GtkWidget *toplevel = gtk_widget_get_toplevel(widget);
174         GdkWindow *window   = gtk_widget_get_window(widget);
175         GdkWindow *topwin   = gtk_widget_get_window(toplevel);
176         gdk_window_ensure_native(window);
177
178         PIXELFORMATDESCRIPTOR pfo = {}, pfd = {
179                 .nSize       = sizeof(pfd),
180                 .nVersion    = 1,
181                 .dwFlags     = PFD_DRAW_TO_WINDOW // "Correct" way
182                              | PFD_SUPPORT_OPENGL
183                              | PFD_DOUBLEBUFFER,
184                 //.dwFlags     = PFD_SUPPORT_OPENGL  // Works in wine
185                 //             | PFD_DRAW_TO_WINDOW,
186                 .iPixelType  = PFD_TYPE_RGBA,
187                 .cColorBits  = 24,
188                 .cAlphaBits  = 8,
189                 .cDepthBits  = 32,
190                 .iLayerType  = PFD_MAIN_PLANE,
191         };
192         HWND  hwnd = GDK_WINDOW_HWND(window);
193         HDC   hDC  = GetDC(hwnd);           // get the device context for window
194         int   pf   = ChoosePixelFormat(hDC, &pfd);
195         int   st0  = DescribePixelFormat(hDC, pf, sizeof(pfd), &pfo);
196         int   st1  = SetPixelFormat(hDC, pf, &pfd);
197         HGLRC hRC  = wglCreateContext(hDC);
198         int   st2  = wglMakeCurrent(hDC, hRC);
199
200         g_message("dc: %p, %p, %p", hDC, GetDC(hwnd), wglGetCurrentDC());
201
202         g_message("window: pf=%d st=%d,%d,%d dc=%p rc=%p wins=%x=%x!=%x",
203                 pf, st0,st1,st2, hDC, hRC, (guint)hwnd,
204                 (guint)GDK_WINDOW_HWND(window),
205                 (guint)GDK_WINDOW_HWND(topwin));
206
207         g_message("pdfOut: dwFlags=%lx=%lx, ipt=%x=%x, layer=%x=%x, {c,a,d}bits=%d,%d,%d",
208                 pfo.dwFlags,    pfd.dwFlags,
209                 pfo.iPixelType, pfd.iPixelType,
210                 pfo.iLayerType, pfd.iLayerType,
211                 pfo.cColorBits, pfo.cAlphaBits, pfo.cDepthBits);
212
213         /* Drawing */
214         GtkAllocation alloc = widget->allocation;
215         glViewport(0, 0, alloc.width, alloc.height);
216         g_message("alloc: %dx%d", alloc.width, alloc.height);
217         glClear(GL_COLOR_BUFFER_BIT);
218         glColor3f(1.0, 1.0, 1.0);
219         glBegin(GL_TRIANGLE_FAN);
220         glVertex2f(0.0, 0.0);
221         for (double i = 0; i < 2*G_PI; i+=(2*G_PI)/100)
222                 glVertex2d(sin(i), cos(i));
223         glEnd();
224
225         /* Swap buffers */
226         SwapBuffers(hDC);
227
228         /* Cleanup */
229         wglMakeCurrent(NULL, NULL);
230         wglDeleteContext(hRC);
231         return TRUE;
232 }
233
234
235 /**************************
236  * Mac OSX implementation *
237  **************************/
238 #elif defined(SYS_MAC)
239 #include <OpenGL/gl.h>
240 #include <OpenGL/glu.h>
241 #include <gdk/gdkquartz.h>
242 gpointer setup(GtkWidget *widget)
243 {
244         /* Create context */
245         NSOpenGLPixelFormatAttribute attribs[] = {
246                 NSOpenGLPFAColorSize, 24,
247                 NSOpenGLPFAAlphaSize, 8,
248                 NSOpenGLPFADepthSize, 1,
249                 NSOpenGLPFADoubleBuffer,
250                 0
251         };
252         NSOpenGLPixelFormat *pix  = [[NSOpenGLPixelFormat alloc] initWithAttributes:attribs];
253         NSOpenGLContext     *ctx  = [[NSOpenGLContext     alloc] initWithFormat:pix shareContext:nil];
254
255         /* Disable GTK double buffering */
256         gtk_widget_set_double_buffered(widget, FALSE);
257
258         return ctx;
259 }
260 gboolean configure(GtkWidget *widget, GdkEventConfigure *event, NSOpenGLContext *ctx)
261 {
262         GtkAllocation alloc;
263         gtk_widget_get_allocation(widget, &alloc);
264
265         GdkWindow *win  = gtk_widget_get_window(widget);
266         NSView    *view = gdk_quartz_window_get_nsview(win);
267         NSRect     rect = NSMakeRect(alloc.x, alloc.y, alloc.width, alloc.height);
268
269         [view setFrame:rect];
270         [ctx  update];
271         return FALSE;
272 }
273 gboolean expose(GtkWidget *widget, gpointer data, NSOpenGLContext *ctx)
274 {
275         gdk_window_ensure_native(gtk_widget_get_window(widget));
276
277         GdkWindow *win  = gtk_widget_get_window(widget);
278         NSView    *view = gdk_quartz_window_get_nsview(win);
279
280         configure(widget, NULL, ctx);
281
282         [ctx setView:view];
283         [ctx makeCurrentContext];
284
285         /* Drawing */
286         GtkAllocation alloc;
287         gtk_widget_get_allocation(widget, &alloc);
288         glViewport(0, 0, alloc.width, alloc.height);
289         glClear(GL_COLOR_BUFFER_BIT);
290         glColor3f(1.0, 1.0, 1.0);
291         glBegin(GL_TRIANGLE_FAN);
292         glVertex2f(0.0, 0.0);
293         for (double i = 0; i < 2*G_PI; i+=(2*G_PI)/100)
294                 glVertex2d(sin(i), cos(i));
295         glEnd();
296
297         [ctx flushBuffer];
298         return FALSE;
299 }
300
301
302 /****************************
303  * Undefined implementation *
304  ****************************/
305 #else
306 gpointer setup(GtkWidget *widget) { return NULL; }
307 gboolean expose(GtkWidget *widget, gpointer data, gpointer user_data)
308 {
309         g_message("unimplemented");
310         return FALSE;
311 }
312 #endif
313
314
315
316 /***************
317  * Common code *
318  ***************/
319 gboolean key_press(GtkWidget *widget, GdkEventKey *event, gpointer user_data)
320 {
321         if (event->keyval == GDK_KEY_q)
322                 gtk_main_quit();
323         return FALSE;
324 }
325 int main(int argc, char **argv)
326 {
327         gtk_init_check(&argc, &argv);
328         GtkWidget *window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
329         GtkWidget *box    = gtk_vbox_new(FALSE, 5);
330         GtkWidget *draw   = gtk_drawing_area_new();
331         GtkWidget *label  = gtk_label_new("Hello, World");
332         GtkWidget *button = gtk_button_new_with_label("Hello, World");
333         gpointer   data   = setup(draw);
334         g_signal_connect(window, "destroy",         G_CALLBACK(gtk_main_quit), NULL);
335         g_signal_connect(window, "key-press-event", G_CALLBACK(key_press),     NULL);
336         //g_signal_connect(draw,   "configure-event", G_CALLBACK(configure),     data);
337         g_signal_connect(draw,   "expose-event",    G_CALLBACK(expose),        data);
338         gtk_widget_set_size_request(draw,   300, 300);
339         gtk_widget_set_size_request(button, -1,  50);
340         gtk_box_pack_start(GTK_BOX(box), label,  FALSE, TRUE, 0);
341         gtk_box_pack_start(GTK_BOX(box), draw,   TRUE,  TRUE, 0);
342         gtk_box_pack_start(GTK_BOX(box), button, FALSE, TRUE, 0);
343         gtk_container_add(GTK_CONTAINER(window), box);
344         gtk_widget_show_all(window);
345         gtk_main();
346         return 0;
347 }