]> Pileus Git - grits/blob - examples/sorting/sort.c
Update copyright and email address
[grits] / examples / sorting / sort.c
1 /*
2  * Copyright (C) 2009-2010 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 #define GL_GLEXT_PROTOTYPES
19 #include <gtk/gtk.h>
20 #include <gtk/gtkgl.h>
21 #include <gdk/gdkkeysyms.h>
22 #include <GL/gl.h>
23 #include <GL/glu.h>
24 #include <stdlib.h>
25
26 gdouble pos[3];
27 gdouble rot[3];
28 guint tex;
29
30 typedef struct {
31         gfloat xyz[4];
32         gfloat color[4];
33         gfloat texture[4];
34 } __attribute__ ((packed)) vert_t;
35
36 static int sort_cmp(const void *a, const void *b)
37 {
38         vert_t *a_verts = (vert_t*)(((gfloat*)a)+2);
39         vert_t *b_verts = (vert_t*)(((gfloat*)b)+2);
40         gfloat a_sum = a_verts[0].xyz[2] + a_verts[1].xyz[2] + a_verts[2].xyz[2];
41         gfloat b_sum = b_verts[0].xyz[2] + b_verts[1].xyz[2] + b_verts[2].xyz[2];
42         return a_sum == b_sum ? 0 :
43                a_sum <  b_sum ? 1 : -1;
44 }
45
46 static gfloat *sort_start()
47 {
48         int size = 1000000;
49         gfloat *data = g_new0(gfloat, size);
50         glFeedbackBuffer(size, GL_4D_COLOR_TEXTURE, data);
51         glRenderMode(GL_FEEDBACK);
52         g_print("1st = %f\n", data[0]);
53         return data;
54 }
55
56 static void sort_end(gfloat *data)
57 {
58         int vertsize = sizeof(vert_t)/sizeof(gfloat);
59         int nvals = glRenderMode(GL_RENDER);
60
61         /* Set up screen coords */
62         gint view[4];
63         glGetIntegerv(GL_VIEWPORT, view);
64
65         glMatrixMode(GL_PROJECTION);
66         glPushMatrix();
67         glLoadIdentity();
68         glOrtho(view[0],view[2], view[1],view[3], -100,100);
69
70         glMatrixMode(GL_MODELVIEW);
71         glPushMatrix();
72         glLoadIdentity();
73         glDisable(GL_LIGHTING);
74
75         glMatrixMode(GL_TEXTURE);
76         glPushMatrix();
77         glLoadIdentity();
78
79         //glTranslatef(pos[0], pos[1], pos[2]);
80         //glTranslatef(0.05, 0.1, -2);
81         //glRotatef(0.03, 1, 1, 0);
82
83         //gluPerspective(90, 0.8, 0.1, 10);
84
85
86         /* Sort the vertexes (this only works with all-triangles */
87         int trisize = 2*sizeof(gfloat) + 3*sizeof(vert_t);
88         int ntris   = nvals*sizeof(gfloat) / trisize;
89         g_print("%d, %d, %d\n", sizeof(gfloat), trisize, ntris);
90         qsort(data, ntris, trisize, sort_cmp);
91
92         /* Draw the data */
93         for (int i = 0; i < nvals;) {
94                 gfloat token = data[i++];
95                 if (token == GL_POLYGON_TOKEN) {
96                         gfloat n = data[i++];
97                         vert_t *verts = (vert_t*)&data[i];
98                         i += n*vertsize;
99                         //g_print("GL_POLYGON_TOKEN: %f\n", n);
100
101                         /* Draw triangle */
102                         glBegin(GL_TRIANGLES);
103                         for (int j = 0; j < n; j++) {
104                                 g_print("\t%7.2f, %6.2f, %6.2f %6.2f - "
105                                         "%5.2f, %5.2f, %5.2f, %5.2f\n",
106                                         verts[j].xyz[0],
107                                         verts[j].xyz[1],
108                                         verts[j].xyz[2],
109                                         verts[j].xyz[3],
110                                         verts[j].texture[0],
111                                         verts[j].texture[1],
112                                         verts[j].texture[2],
113                                         verts[j].texture[3]);
114                                 glTexCoord4f(
115                                         verts[j].texture[0],
116                                         verts[j].texture[1],
117                                         verts[j].texture[2],
118                                         verts[j].texture[3]);
119                                 glColor4f(
120                                         verts[j].color[0],
121                                         verts[j].color[1],
122                                         verts[j].color[2],
123                                         verts[j].color[3]);
124                                 if (j == 2)
125                                         verts[j].xyz[2] = -100;
126                                 glVertex3f(
127                                         verts[j].xyz[0],
128                                         verts[j].xyz[1],
129                                         verts[j].xyz[2]);
130                         }
131                         glEnd();
132
133                         /* Draw line */
134                         //glDisable(GL_TEXTURE_2D);
135                         //glBegin(GL_LINE_LOOP);
136                         //glColor4f(1,1,1,1);
137                         //for (int j = 0; j < n; j++)
138                         //      glVertex3fv(verts[j].xyz);
139                         //glEnd();
140                 } else {
141                         g_error("Unknown token: %f\n", token);
142                 }
143         }
144         glMatrixMode(GL_PROJECTION);
145         glPopMatrix();
146         glMatrixMode(GL_MODELVIEW);
147         glPopMatrix();
148         glMatrixMode(GL_TEXTURE);
149         glPopMatrix();
150         g_free(data);
151 }
152
153 static gboolean on_expose(GtkWidget *drawing, GdkEventExpose *event, gpointer _)
154 {
155         //glClearColor(0.5, 0.5, 1.0, 1.0);
156         glClearColor(0.0, 0.0, 0.0, 0.0);
157         glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
158
159         glEnable(GL_BLEND);
160
161         /* Blend, but broken sorting */
162         //glEnable(GL_DEPTH_TEST);
163         glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
164
165         /* No sorting, just add */
166         //glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
167         //glBlendFunc(GL_ONE, GL_ONE);
168
169         /* Lighting */
170         float light_ambient[]  = {0.1f, 0.1f, 0.0f, 1.0f};
171         float light_diffuse[]  = {0.9f, 0.9f, 0.9f, 1.0f};
172         float light_position[] = {-30.0f, 50.0f, 40.0f, 1.0f};
173         glLightfv(GL_LIGHT0, GL_AMBIENT,  light_ambient);
174         glLightfv(GL_LIGHT0, GL_DIFFUSE,  light_diffuse);
175         glLightfv(GL_LIGHT0, GL_POSITION, light_position);
176         glEnable(GL_COLOR_MATERIAL);
177         glEnable(GL_LIGHTING);
178         glEnable(GL_LIGHT0);
179
180         glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
181
182         /* Draw teapots */
183         g_print("%f,%f,%f\n", pos[0], pos[1], pos[2]);
184         g_print("%f,%f,%f\n", rot[0], rot[1], rot[2]);
185
186         glMatrixMode(GL_MODELVIEW);
187
188         gfloat *data = sort_start();
189         glLoadIdentity();
190         glTranslatef(pos[0], pos[1], pos[2]);
191         glTranslatef(0.05, 0.1, -2);
192         glRotatef(60, 1, -1, -0.2);
193         glColor4f(1,1,1,1);
194         glDisable(GL_COLOR_MATERIAL);
195         glEnable(GL_TEXTURE_2D);
196         glBindTexture(GL_TEXTURE_2D, tex);
197         glBegin(GL_QUADS);
198         glTexCoord2f(0, 0); glVertex3f(-0.8,  0.5, 0.0);
199         glTexCoord2f(0, 1); glVertex3f(-0.8, -0.5, 0.0);
200         glTexCoord2f(1, 1); glVertex3f( 0.8, -0.5, 0.0);
201         glTexCoord2f(1, 0); glVertex3f( 0.8,  0.5, 0.0);
202         glEnd();
203
204         //glLoadIdentity();
205         //glTranslatef(pos[0], pos[1], pos[2]);
206         //glTranslatef(0.05, 0.1, -2);
207         //glRotatef(30, 1, -1, -0.2);
208         //glColor4f(1.0, 0.2, 0.2, 0.5);
209         ////gdk_gl_draw_teapot(TRUE, 0.5);
210         //gdk_gl_draw_cube(TRUE, 0.5);
211
212         //glLoadIdentity();
213         //glTranslatef(pos[0], pos[1], pos[2]);
214         //glTranslatef(-0.2, 0, -2);
215         //glRotatef(30, 1, -1, -0.2);
216         //glColor4f(0.2, 0.2, 1.0, 0.5);
217         ////gdk_gl_draw_teapot(TRUE, 0.5);
218         //gdk_gl_draw_cube(TRUE, 0.5);
219         sort_end(data);
220
221         /* Flush */
222         GdkGLDrawable *gldrawable = gdk_gl_drawable_get_current();
223         if (gdk_gl_drawable_is_double_buffered(gldrawable))
224                 gdk_gl_drawable_swap_buffers(gldrawable);
225         else
226                 glFlush();
227         return FALSE;
228 }
229
230 static gboolean on_configure(GtkWidget *drawing, GdkEventConfigure *event, gpointer _)
231 {
232         gdouble width  = drawing->allocation.width;
233         gdouble height = drawing->allocation.height;
234         glViewport(0, 0, width, height);
235
236         /* Set up projection */
237         glMatrixMode(GL_PROJECTION);
238         glLoadIdentity();
239         //gluPerspective(90, width/height, 0.1, 10);
240         gluPerspective(90, 0.8, 0.1, 10);
241         //glOrtho(1,-1, -0.7,0.7, -10,10);
242         return FALSE;
243 }
244
245 static gboolean on_key_press(GtkWidget *widget, GdkEventKey *event, gpointer _)
246 {
247         guint kv = event->keyval;
248         if      (kv == GDK_q) gtk_main_quit();
249         else if (kv == GDK_h) pos[0] -= 0.02;
250         else if (kv == GDK_j) pos[1] += 0.02;
251         else if (kv == GDK_k) pos[1] -= 0.02;
252         else if (kv == GDK_l) pos[0] += 0.02;
253         else if (kv == GDK_o) pos[2] -= 0.02;
254         else if (kv == GDK_i) pos[2] += 0.02;
255         else if (kv == GDK_H) rot[2] -= 2.0;
256         else if (kv == GDK_J) rot[0] += 2.0;
257         else if (kv == GDK_K) rot[0] -= 2.0;
258         else if (kv == GDK_L) rot[2] += 2.0;
259         gtk_widget_queue_draw(widget);
260         return FALSE;
261 }
262
263 static guint load_tex(gchar *filename)
264 {
265         GdkPixbuf *pixbuf = gdk_pixbuf_new_from_file(filename, NULL);
266         guchar    *pixels = gdk_pixbuf_get_pixels(pixbuf);
267         int        width  = gdk_pixbuf_get_width(pixbuf);
268         int        height = gdk_pixbuf_get_height(pixbuf);
269         int        alpha  = gdk_pixbuf_get_has_alpha(pixbuf);
270         guint      tex;
271         glGenTextures(1, &tex);
272         glBindTexture(GL_TEXTURE_2D, tex);
273         glTexImage2D(GL_TEXTURE_2D, 0, 4, width, height, 0,
274                         (alpha ? GL_RGBA : GL_RGB), GL_UNSIGNED_BYTE, pixels);
275         glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
276         glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
277
278         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
279         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
280         g_object_unref(pixbuf);
281         return tex;
282 }
283
284 gchar *gl_program_log(guint program, int *_len)
285 {
286         gchar *buf = NULL;
287         int len = 0;
288         glGetProgramiv(program, GL_INFO_LOG_LENGTH, &len);
289         if (len > 0) {
290                 buf = g_malloc(len);
291                 glGetProgramInfoLog(program, len, &len, buf);
292         }
293         if (_len)
294                 *_len = len;
295         return buf;
296 }
297
298 static void load_shader(gchar *filename)
299 {
300         gchar *source;
301         gboolean status = g_file_get_contents(filename, &source, NULL, NULL);
302         if (!status)
303                 g_error("Failed to load shader");
304
305         guint program = glCreateProgram();
306         if (!program)
307                 g_error("Error creating program");
308
309         guint shader = glCreateShader(GL_VERTEX_SHADER_ARB);
310         if (!shader)
311                 g_error("Error creating shader");
312
313         glShaderSource(shader, 1, (const gchar**)&source, NULL);
314         if (glGetError())
315                 g_error("Error setting shader source");
316
317         glCompileShader(shader);
318         if (glGetError())
319                 g_error("Error compiling shader");
320
321         glAttachShader(program, shader);
322         if (glGetError())
323                 g_error("Error attaching shader");
324
325         glLinkProgram(program);
326         if (glGetError())
327                 g_error("Error linking program");
328
329         glUseProgram(program);
330         if (glGetError())
331                 g_error("Error using program:\n%s", gl_program_log(program, NULL));
332 }
333
334 int main(int argc, char **argv)
335 {
336         gtk_init(&argc, &argv);
337
338         GtkWidget   *window   = gtk_window_new(GTK_WINDOW_TOPLEVEL);
339         GtkWidget   *drawing  = gtk_drawing_area_new();
340         GdkGLConfig *glconfig = gdk_gl_config_new_by_mode((GdkGLConfigMode)(
341                         GDK_GL_MODE_RGBA   | GDK_GL_MODE_DEPTH |
342                         GDK_GL_MODE_DOUBLE | GDK_GL_MODE_ALPHA));
343         g_signal_connect(window,  "destroy",         G_CALLBACK(gtk_main_quit), NULL);
344         g_signal_connect(window,  "key-press-event", G_CALLBACK(on_key_press),  NULL);
345         g_signal_connect(drawing, "expose-event",    G_CALLBACK(on_expose),     NULL);
346         g_signal_connect(drawing, "configure-event", G_CALLBACK(on_configure),  NULL);
347         gtk_widget_set_gl_capability(drawing, glconfig, NULL, TRUE, GDK_GL_RGBA_TYPE);
348         gtk_container_add(GTK_CONTAINER(window), drawing);
349         gtk_widget_show_all(window);
350
351         /* OpenGL setup */
352         GdkGLContext  *glcontext  = gtk_widget_get_gl_context(GTK_WIDGET(drawing));
353         GdkGLDrawable *gldrawable = gtk_widget_get_gl_drawable(GTK_WIDGET(drawing));
354         gdk_gl_drawable_gl_begin(gldrawable, glcontext);
355
356         /* Load texture */
357         tex = load_tex("flag.png");
358
359         /* Load shader */
360         load_shader("sort.glsl");
361
362         gtk_main();
363
364         gdk_gl_drawable_gl_end(gldrawable);
365 }