libc3: Few more updates
[simavr] / examples / board_reprap / src / reprap_gl.c
1 /*
2         reprap_gl.c
3
4         Copyright 2008-2012 Michel Pollet <buserror@gmail.com>
5
6         This file is part of simavr.
7
8         simavr is free software: you can redistribute it and/or modify
9         it under the terms of the GNU General Public License as published by
10         the Free Software Foundation, either version 3 of the License, or
11         (at your option) any later version.
12
13         simavr is distributed in the hope that it will be useful,
14         but WITHOUT ANY WARRANTY; without even the implied warranty of
15         MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16         GNU General Public License for more details.
17
18         You should have received a copy of the GNU General Public License
19         along with simavr.  If not, see <http://www.gnu.org/licenses/>.
20  */
21
22 #if __APPLE__
23 #define GL_GLEXT_PROTOTYPES
24 #include <GLUT/glut.h>
25 #include <OpenGL/gl.h>
26 #include <OpenGL/glext.h>
27 #else
28 #define GL_GLEXT_PROTOTYPES
29 #include <GL/gl.h>
30 #include <GL/glut.h>
31 #include <GL/glext.h>
32 #endif
33
34 #include <stdio.h>
35 #include <math.h>
36
37 #include "reprap.h"
38 #include "reprap_gl.h"
39
40 #include "c3.h"
41 #include "c3camera.h"
42 #include "c3driver_context.h"
43 #include "c3stl.h"
44 #include "c3lines.h"
45 #include "c3program.h"
46
47 #include <cairo/cairo.h>
48
49 struct cairo_surface_t;
50
51 int _w = 800, _h = 600;
52 //c3cam cam;
53 c3context_p c3;
54 c3context_p hud;
55 c3object_p head;
56 c3texture_p fbo_c3;
57 c3program_p fxaa = NULL;
58
59 int glsl_version = 110;
60
61 extern reprap_t reprap;
62
63 static int dumpError(const char * what)
64 {
65         GLenum e;
66         int count = 0;
67         while ((e = glGetError()) != GL_NO_ERROR) {
68                 printf("%s: %s\n", what, gluErrorString(e));
69                 count++;
70         }
71         return count;
72 }
73
74 #define GLCHECK(_w) {_w; dumpError(#_w);}
75
76 /* Global */
77 GLuint fbo, fbo_texture, rbo_depth;
78 //GLuint vbo_fbo_vertices;
79
80 static void
81 gl_offscreenInit(
82                 int screen_width,
83                 int screen_height)
84 {
85         /* init_resources */
86         /* Create back-buffer, used for post-processing */
87
88         /* Texture */
89         GLCHECK(glActiveTexture(GL_TEXTURE0));
90         glGenTextures(1, &fbo_texture);
91         glBindTexture(GL_TEXTURE_2D, fbo_texture);
92         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
93         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
94         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
95         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
96         glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, screen_width, screen_height, 0,
97                 GL_RGBA, GL_UNSIGNED_BYTE, NULL);
98         glBindTexture(GL_TEXTURE_2D, 0);
99
100         /* Depth buffer */
101         GLCHECK(glGenRenderbuffers(1, &rbo_depth));
102         glBindRenderbuffer(GL_RENDERBUFFER, rbo_depth);
103         glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, screen_width,
104                 screen_height);
105         glBindRenderbuffer(GL_RENDERBUFFER, 0);
106
107         /* Framebuffer to link everything together */
108         GLCHECK(glGenFramebuffers(1, &fbo));
109         glBindFramebuffer(GL_FRAMEBUFFER, fbo);
110         glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
111                 fbo_texture, 0);
112         glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
113                 GL_RENDERBUFFER, rbo_depth);
114
115         GLenum status;
116         if ((status = glCheckFramebufferStatus(GL_FRAMEBUFFER))
117                 != GL_FRAMEBUFFER_COMPLETE) {
118                 fprintf(stderr, "glCheckFramebufferStatus: error %d", (int)status);
119                 return ;
120         }
121 #if 0
122         // Set the list of draw buffers.
123         GLenum DrawBuffers[2] = {GL_COLOR_ATTACHMENT0};
124         glDrawBuffers(1, DrawBuffers); // "1" is the size of DrawBuffers
125         glBindFramebuffer(GL_FRAMEBUFFER, 0);
126 #endif
127 }
128
129 void
130 gl_offscreenReshape(
131                 int screen_width,
132                 int screen_height)
133 {
134 // Rescale FBO and RBO as well
135         glBindTexture(GL_TEXTURE_2D, fbo_texture);
136         glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, screen_width, screen_height, 0,
137                 GL_RGBA, GL_UNSIGNED_BYTE, NULL);
138         glBindTexture(GL_TEXTURE_2D, 0);
139
140         glBindRenderbuffer(GL_RENDERBUFFER, rbo_depth);
141         glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, screen_width,
142                 screen_height);
143         glBindRenderbuffer(GL_RENDERBUFFER, 0);
144 }
145
146 void gl_offscreenFree()
147 {
148         /* free_resources */
149         glDeleteRenderbuffers(1, &rbo_depth);
150         glDeleteTextures(1, &fbo_texture);
151         glDeleteFramebuffers(1, &fbo);
152 }
153
154 static void
155 _gl_reshape_cb(int w, int h)
156 {
157     _w  = w;
158     _h = h;
159
160     glViewport(0, 0, _w, _h);
161     gl_offscreenReshape(_w, _h);
162     glutPostRedisplay();
163 }
164
165 static void
166 _gl_key_cb(
167                 unsigned char key,
168                 int x,
169                 int y)  /* called on key press */
170 {
171         switch (key) {
172                 case 'q':
173                 //      avr_vcd_stop(&vcd_file);
174                         c3context_dispose(c3);
175                         exit(0);
176                         break;
177                 case 'r':
178                         printf("Starting VCD trace; press 's' to stop\n");
179                 //      avr_vcd_start(&vcd_file);
180                         break;
181                 case 's':
182                         printf("Stopping VCD trace\n");
183                 //      avr_vcd_stop(&vcd_file);
184                         break;
185                 case '1':
186                         if (fbo_c3->geometry.mat.program)
187                                 fbo_c3->geometry.mat.program = NULL;
188                         else
189                                 fbo_c3->geometry.mat.program = fxaa;
190                         glutPostRedisplay();
191                         break;
192         }
193 }
194
195 static void
196 _c3_load_program(
197                 c3program_p p)
198 {
199         if (!p || p->pid || p->log)
200                 return;
201
202         printf("%s loading %s\n", __func__, p->name->str);
203         for (int si = 0; si < p->shaders.count && !p->log; si++) {
204                 c3shader_p s = &p->shaders.e[si];
205
206                 printf("%s compiling shader %s\n", __func__, s->name->str);
207
208                 s->sid = glCreateShader(s->type);
209                 const GLchar * pgm = s->shader->str;
210                 glShaderSource(s->sid, 1, &pgm, NULL);
211
212                 glCompileShader(s->sid);
213
214                 GLint status;
215                 glGetShaderiv(s->sid, GL_COMPILE_STATUS, &status);
216
217                 if (status != GL_FALSE)
218                         continue;
219
220                 GLint infoLogLength;
221                 glGetShaderiv(s->sid, GL_INFO_LOG_LENGTH, &infoLogLength);
222
223                 p->log = str_alloc(infoLogLength);
224                 glGetShaderInfoLog(s->sid, infoLogLength, NULL, p->log->str);
225
226                 fprintf(stderr, "%s compile %s: %s\n", __func__, s->name->str, p->log->str);
227                 break;
228         }
229         if (p->log)
230                 return;
231     p->pid = glCreateProgram();
232
233         for (int si = 0; si < p->shaders.count && !p->log; si++) {
234                 c3shader_p s = &p->shaders.e[si];
235
236         glAttachShader(p->pid, s->sid);
237         }
238     glLinkProgram(p->pid);
239
240     GLint status;
241     glGetProgramiv (p->pid, GL_LINK_STATUS, &status);
242
243         for (int si = 0; si < p->shaders.count && !p->log; si++) {
244                 c3shader_p s = &p->shaders.e[si];
245
246                 glDetachShader(p->pid, s->sid);
247                 glDeleteShader(s->sid);
248         s->sid = 0;
249         }
250
251     if (status == GL_FALSE) {
252         GLint infoLogLength;
253         glGetProgramiv(p->pid, GL_INFO_LOG_LENGTH, &infoLogLength);
254
255                 p->log = str_alloc(infoLogLength);
256
257         glGetProgramInfoLog(p->pid, infoLogLength, NULL, p->log->str);
258                 fprintf(stderr, "%s link %s: %s\n", __func__, p->name->str, p->log->str);
259
260                 goto error;
261     }
262     for (int pi = 0; pi < p->params.count; pi++) {
263         c3program_param_p pa = &p->params.e[pi];
264         pa->pid = glGetUniformLocation(p->pid, pa->name->str);
265         if (pa->pid == -1) {
266                 fprintf(stderr, "%s %s: parameter '%s' not found\n",
267                                 __func__, p->name->str, pa->name->str);
268         }
269     }
270
271     c3program_purge(p);
272     return;
273 error:
274 c3program_purge(p);
275         if (p->pid)
276                 glDeleteProgram(p->pid);
277         p->pid = 0;
278 }
279
280 static void
281 _c3_load_pixels(
282                 c3pixels_p pix)
283 {
284         GLuint mode = pix->normalize ? GL_TEXTURE_2D : GL_TEXTURE_RECTANGLE_ARB;
285         if (!pix->texture) {
286                 printf("Creating texture %s %dx%d\n", pix->name ? pix->name->str : "", pix->w, pix->h);
287                 pix->dirty = 1;
288                 GLuint texID = 0;
289                 dumpError("cp_gl_texture_load_argb flush");
290                 GLCHECK(glEnable(mode));
291
292                 glGenTextures(1, &texID);
293 //              glTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE,
294 //                              GL_MODULATE); //set texture environment parameters
295 //              dumpError("glTexEnvf");
296
297                 glPixelStorei(GL_UNPACK_ROW_LENGTH, pix->row / pix->psize);
298                 glTexParameteri(mode, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
299                 dumpError("GL_TEXTURE_MAG_FILTER");//
300                 glTexParameteri(mode, GL_TEXTURE_MIN_FILTER,
301                                 pix->normalize ? GL_LINEAR_MIPMAP_LINEAR : GL_LINEAR);
302                 dumpError("GL_TEXTURE_MIN_FILTER");
303                 glTexParameteri(mode, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
304                 dumpError("GL_TEXTURE_WRAP_S");
305                 glTexParameteri(mode, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
306                 dumpError("GL_TEXTURE_WRAP_T");
307                 if (pix->normalize)
308                         GLCHECK(glTexParameteri(mode, GL_GENERATE_MIPMAP, GL_TRUE));
309         #if 1
310                 GLfloat fLargest;
311                 glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &fLargest);
312                 //printf("fLargest = %f\n", fLargest);
313                 GLCHECK(glTexParameterf(mode, GL_TEXTURE_MAX_ANISOTROPY_EXT, fLargest));
314         #endif
315                 if (pix->normalize)
316                         GLCHECK(glGenerateMipmap(mode));
317
318                 pix->texture = texID;
319                 pix->dirty = 1;
320         }
321         if (pix->dirty) {
322                 pix->dirty = 0;
323                 GLCHECK(glBindTexture(mode, pix->texture));
324                 glTexImage2D(mode, 0,
325                                 pix->format == C3PIXEL_A ? GL_ALPHA16 : GL_RGBA8,
326                                 pix->w, pix->h, 0,
327                                 pix->format == C3PIXEL_A ? GL_ALPHA : GL_BGRA,
328                                 GL_UNSIGNED_BYTE,
329                                 pix->base);
330                 dumpError("glTexImage2D");
331                 if (pix->normalize)
332                         GLCHECK(glGenerateMipmap(mode));
333         }
334 }
335
336 static void
337 _c3_geometry_project(
338                 c3context_p c,
339                 const struct c3driver_context_t * d,
340                 c3geometry_p g,
341                 c3mat4p m)
342 {
343         if (g->mat.texture) {
344 //              printf("_c3_geometry_project xrure %d!\n", g->textures.count);
345                 _c3_load_pixels(g->mat.texture);
346         }
347         if (g->mat.program) {
348                 _c3_load_program(g->mat.program);
349         }
350
351         switch(g->type.type) {
352                 case C3_TRIANGLE_TYPE:
353                         g->type.subtype = GL_TRIANGLES;
354                         break;
355                 case C3_TEXTURE_TYPE: {
356                 //      c3texture_p t = (c3texture_p)g;
357                         if (g->mat.texture) {
358                                 g->type.subtype = GL_TRIANGLE_FAN;
359                         }
360                 }       break;
361                 case C3_LINES_TYPE:
362                         g->type.subtype = GL_TRIANGLES;
363                         break;
364                 default:
365                     break;
366         }
367 }
368
369 static void
370 _c3_geometry_draw(
371                 c3context_p c,
372                 const struct c3driver_context_t *d,
373                 c3geometry_p g )
374 {
375         glColor4fv(g->mat.color.n);
376         dumpError("glColor");
377 //      glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, g->mat.color.n);
378         glVertexPointer(3, GL_FLOAT, 0,
379                         g->projected.count ? g->projected.e : g->vertice.e);
380         glEnableClientState(GL_VERTEX_ARRAY);
381         dumpError("GL_VERTEX_ARRAY");
382         glDisable(GL_TEXTURE_2D);
383         if (g->mat.texture) {
384                 GLuint mode = g->mat.texture->normalize ? GL_TEXTURE_2D : GL_TEXTURE_RECTANGLE_ARB;
385                 glEnable(mode);
386                 if (g->mat.texture->trace)
387                         printf("%s uses texture %s (%d tex)\n",
388                                         __func__, g->mat.texture->name->str, g->textures.count);
389         //      printf("tex mode %d texture %d\n", g->mat.mode, g->mat.texture);
390                 dumpError("glEnable texture");
391                 glBindTexture(mode, g->mat.texture->texture);
392                 dumpError("glBindTexture");
393                 glTexCoordPointer(2, GL_FLOAT, 0, g->textures.e);
394                 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
395                 dumpError("GL_TEXTURE_COORD_ARRAY");
396         }
397         if (g->mat.program) {
398                 glUseProgram(g->mat.program->pid);
399                 dumpError("glUseProgram program_postproc");
400         }
401         if (g->normals.count) {
402                 glNormalPointer(GL_FLOAT, 0, g->normals.e);
403                 glEnableClientState(GL_NORMAL_ARRAY);
404         }
405         glDrawArrays(g->type.subtype, 0,
406                         g->projected.count ? g->projected.count : g->vertice.count);
407         glDisableClientState(GL_VERTEX_ARRAY);
408         glDisableClientState(GL_TEXTURE_COORD_ARRAY);
409         glDisableClientState(GL_NORMAL_ARRAY);
410         if (g->mat.texture)
411                 glDisable(g->mat.texture->normalize ? GL_TEXTURE_2D : GL_TEXTURE_RECTANGLE_ARB);
412         if (g->mat.program)
413                 glUseProgram(0);
414 }
415
416 const c3driver_context_t c3context_driver = {
417                 .geometry_project = _c3_geometry_project,
418                 .geometry_draw = _c3_geometry_draw,
419 };
420
421 #define FBO 1
422
423 static void
424 _gl_display_cb(void)            /* function called whenever redisplay needed */
425 {
426 #if FBO
427         /*
428          * Draw in FBO object
429          */
430         glBindFramebuffer(GL_FRAMEBUFFER, fbo);
431         // draw (without glutSwapBuffers)
432         dumpError("glBindFramebuffer fbo");
433         glViewport(0, 0, _w, _h);
434
435 #else
436         glBindFramebuffer(GL_FRAMEBUFFER, 0);
437 #endif
438
439         c3context_view_set(c3, 0);
440         c3vec3 headp = c3vec3f(
441                         stepper_get_position_mm(&reprap.step_x),
442                         stepper_get_position_mm(&reprap.step_y),
443                         stepper_get_position_mm(&reprap.step_z));
444         c3mat4 headmove = translation3D(headp);
445         c3transform_set(head->transform.e[0], &headmove);
446
447         if (c3->root->dirty) {
448         //      printf("reproject head %.2f,%.2f,%.2f\n", headp.x, headp.y,headp.z);
449                 c3context_project(c3);
450         }
451         float z_min = c3context_view_get(c3)->z.min,
452                         z_max = c3context_view_get(c3)->z.max;
453         if (z_min < 0)
454                 z_min = 10;
455         z_min = 10;
456         if (z_max < z_min || z_max > 1000)
457                 z_max = 1000;
458
459         glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
460         glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
461
462         // Set up projection matrix
463         glMatrixMode(GL_PROJECTION); // Select projection matrix
464         glLoadIdentity(); // Start with an identity matrix
465
466         gluPerspective(50, (float)_w / (float)_h, z_min, z_max);
467 #if 0
468         glCullFace(GL_BACK);
469         glEnable(GL_CULL_FACE);
470 #endif
471         glDepthMask(GL_TRUE);
472         glDepthFunc(GL_LEQUAL);
473         glEnable(GL_DEPTH_TEST);
474         glEnable(GL_LIGHTING);
475 //      glPolygonMode( GL_FRONT_AND_BACK, GL_LINE );
476
477         glEnable(GL_ALPHA_TEST);
478         glAlphaFunc(GL_GREATER, 1.0f / 255.0f);
479         glEnable(GL_BLEND); // Enable Blending
480         glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); // Type Of Blending To Use
481
482         glMatrixMode(GL_MODELVIEW);
483         glLoadIdentity();
484
485         glMultMatrixf(c3context_view_get(c3)->cam.mtx.n);
486         glTranslatef(-c3context_view_get(c3)->cam.eye.n[VX],
487                         -c3context_view_get(c3)->cam.eye.n[VY],
488                         -c3context_view_get(c3)->cam.eye.n[VZ]);
489
490         dumpError("flush");
491
492         c3context_draw(c3);
493
494 #if FBO
495         /*
496          * Draw back FBO over the screen
497          */
498         glBindFramebuffer(GL_FRAMEBUFFER, 0);
499         dumpError("glBindFramebuffer 0");
500
501         glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
502         glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
503 #endif
504         glDisable(GL_DEPTH_TEST);
505         glDisable(GL_LIGHTING);
506         glDisable(GL_ALPHA_TEST);
507
508         glUseProgram(0);
509
510         glMatrixMode(GL_PROJECTION); // Select projection matrix
511         glLoadIdentity(); // Start with an identity matrix
512         glOrtho(0, _w, 0, _h, 0, 10);
513         glScalef(1, -1, 1);
514         glTranslatef(0, -1 * _h, 0);
515         glMatrixMode(GL_MODELVIEW); // Select modelview matrix
516         glLoadIdentity(); // Start with an identity matrix
517
518         if (hud)
519                 c3context_draw(hud);
520
521     glutSwapBuffers();
522 }
523
524 #if !defined(GLUT_WHEEL_UP)
525 #  define GLUT_WHEEL_UP   3
526 #  define GLUT_WHEEL_DOWN 4
527 #endif
528
529
530 int button;
531 c3vec2 move;
532
533 static
534 void _gl_button_cb(
535                 int b,
536                 int s,
537                 int x,
538                 int y)
539 {
540         button = s == GLUT_DOWN ? b : 0;
541         move = c3vec2f(x, y);
542         c3context_view_p view = c3context_view_get_at(c3, 0);
543 //      printf("button %d: %.1f,%.1f\n", b, move.x, move.y);
544         switch (b) {
545                 case GLUT_LEFT_BUTTON:
546                 case GLUT_RIGHT_BUTTON: // call motion
547                         break;
548                 case GLUT_WHEEL_UP:
549                 case GLUT_WHEEL_DOWN:
550                         if (view->cam.distance > 10) {
551                                 const float d = 0.004;
552                                 c3cam_set_distance(&view->cam,
553                                                 view->cam.distance * ((b == GLUT_WHEEL_DOWN) ? (1.0+d) : (1.0-d)));
554                                 c3cam_update_matrix(&view->cam);
555                                 view->dirty = 1;        // resort the array
556                         }
557                         break;
558         }
559 }
560
561 void
562 _gl_motion_cb(
563                 int x,
564                 int y)
565 {
566         c3vec2 m = c3vec2f(x, y);
567         c3vec2 delta = c3vec2_sub(move, m);
568         c3context_view_p view = c3context_view_get_at(c3, 0);
569
570 //      printf("%s b%d click %.1f,%.1f now %d,%d delta %.1f,%.1f\n",
571 //                      __func__, button, move.n[0], move.n[1], x, y, delta.x, delta.y);
572
573         switch (button) {
574                 case GLUT_LEFT_BUTTON: {
575                         c3mat4 rotx = rotation3D(view->cam.side, delta.n[1] / 4);
576                         c3mat4 roty = rotation3D(c3vec3f(0.0, 0.0, 1.0), delta.n[0] / 4);
577                         rotx = c3mat4_mul(&rotx, &roty);
578                         c3cam_rot_about_lookat(&view->cam, &rotx);
579                         c3cam_update_matrix(&view->cam);
580
581                         view->dirty = 1;        // resort the array
582                 }       break;
583                 case GLUT_RIGHT_BUTTON: {
584                         // offset both points, but following the plane
585                         c3vec3 f = c3vec3_mulf(
586                                         c3vec3f(-view->cam.side.y, view->cam.side.x, 0),
587                                         -delta.n[1] / 4);
588                         view->cam.eye = c3vec3_add(view->cam.eye, f);
589                         view->cam.lookat = c3vec3_add(view->cam.lookat, f);
590                         c3cam_movef(&view->cam, delta.n[0] / 8, 0, 0);
591                         c3cam_update_matrix(&view->cam);
592
593                     view->dirty = 1;    // resort the array
594                 }       break;
595         }
596         move = m;
597 }
598
599 // gl timer. if the lcd is dirty, refresh display
600 static void
601 _gl_timer_cb(
602                 int i)
603 {
604         glutTimerFunc(1000 / 24, _gl_timer_cb, 0);
605         glutPostRedisplay();
606 }
607
608 int
609 gl_init(
610                 int argc,
611                 char *argv[] )
612 {
613         glutInit(&argc, argv);          /* initialize GLUT system */
614
615         glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH | GLUT_ALPHA);
616         glutInitWindowSize(_w, _h);             /* width=400pixels height=500pixels */
617         /*window =*/ glutCreateWindow("Press 'q' to quit");     /* create window */
618
619         glutDisplayFunc(_gl_display_cb);                /* set window's display callback */
620         glutKeyboardFunc(_gl_key_cb);           /* set window's key callback */
621         glutTimerFunc(1000 / 24, _gl_timer_cb, 0);
622
623         glutMouseFunc(_gl_button_cb);
624         glutMotionFunc(_gl_motion_cb);
625     glutReshapeFunc(_gl_reshape_cb);
626
627         glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
628         glHint(GL_GENERATE_MIPMAP_HINT, GL_NICEST);
629         /*
630         glHint(GL_POINT_SMOOTH_HINT, GL_NICEST);
631         glHint(GL_LINE_SMOOTH_HINT, GL_NICEST);
632         glHint(GL_POLYGON_SMOOTH_HINT, GL_NICEST);
633         glEnable(GL_LINE_SMOOTH);
634          */
635         // enable color tracking
636         glEnable(GL_COLOR_MATERIAL);
637         // set material properties which will be assigned by glColor
638         glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE);
639
640         /* setup some lights */
641         glShadeModel(GL_SMOOTH);
642         glEnable(GL_LIGHTING);
643         GLfloat global_ambient[] = { 0.5f, 0.5f, 0.5f, 1.0f };
644         glLightModelfv(GL_LIGHT_MODEL_AMBIENT, global_ambient);
645
646         {
647                 GLfloat specular[] = {1.0f, 1.0f, 1.0f , 0.8f};
648                 GLfloat position[] = { -50.0f, -50.0f, 100.0f, 1.0f };
649                 glLightfv(GL_LIGHT0, GL_SPECULAR, specular);
650                 glLightfv(GL_LIGHT0, GL_POSITION, position);
651                 glEnable(GL_LIGHT0);
652         }
653         {
654                 GLfloat specular[] = {1.0f, 1.0f, 1.0f , 0.8f};
655                 GLfloat position[] = { 250.0f, -50.0f, 100.0f, 1.0f };
656                 glLightfv(GL_LIGHT0, GL_SPECULAR, specular);
657                 glLightfv(GL_LIGHT0, GL_POSITION, position);
658                 glEnable(GL_LIGHT0);
659         }
660
661         /*
662          * Extract the GLSL version as a nuneric value for later
663          */
664         const char * glsl = (const char *)glGetString(GL_SHADING_LANGUAGE_VERSION);
665         {
666                 int M = 0, m = 0;
667                 if (sscanf(glsl, "%d.%d", &M, &m) == 2)
668                         glsl_version = (M * 100) + m;
669
670         }
671         printf("GL_SHADING_LANGUAGE_VERSION %s = %d\n", glsl, glsl_version);
672
673         gl_offscreenInit(_w, _h);
674         //gl_ppProgram();
675
676     c3 = c3context_new(_w, _h);
677     static const c3driver_context_t * list[] = { &c3context_driver, NULL };
678     c3->driver = list;
679
680     c3cam_p cam = &c3context_view_get_at(c3, 0)->cam;
681         cam->lookat = c3vec3f(100.0, 100.0, 0.0);
682         cam->eye = c3vec3f(100.0, -100.0, 100.0);
683
684     {
685         const char *path = "gfx/hb.png";
686         cairo_surface_t * image = cairo_image_surface_create_from_png (path);
687         printf("image = %p %p\n", image, cairo_image_surface_get_data (image));
688         c3texture_p b = c3texture_new(c3->root);
689
690         c3pixels_p dst = c3pixels_new(
691                         cairo_image_surface_get_width (image),
692                         cairo_image_surface_get_height (image),
693                         4, cairo_image_surface_get_stride(image),
694                         cairo_image_surface_get_data (image));
695                 dst->name = str_new(path);
696         b->geometry.mat.texture = dst;
697         b->size = c3vec2f(200, 200);
698                 b->geometry.mat.color = c3vec4f(1.0, 1.0, 1.0, 1.0);
699 //          c3transform_new(head);
700     }
701     c3pixels_p line_aa_tex = NULL;
702     {
703         const char *path = "gfx/BlurryCircle.png";
704         cairo_surface_t * image = cairo_image_surface_create_from_png (path);
705         printf("image = %p %p\n", image, cairo_image_surface_get_data (image));
706
707 #if 0
708         c3pixels_p dst = &b->pixels;
709         c3pixels_init(dst,
710                         cairo_image_surface_get_width (image),
711                         cairo_image_surface_get_height (image),
712                         1, cairo_image_surface_get_width (image),
713                         NULL);
714         c3pixels_alloc(dst);
715         b->size = c3vec2f(32, 32);
716         b->normalized = 1;
717
718         c3pixels_p src = c3pixels_new(
719                         cairo_image_surface_get_width (image),
720                         cairo_image_surface_get_height (image),
721                         4, cairo_image_surface_get_stride(image),
722                         cairo_image_surface_get_data (image));
723
724         uint32_t * _s = (uint32_t *)src->base;
725         uint8_t * _d = (uint8_t *)dst->base;
726         int max = 0;
727         for (int i = 0; i < dst->h * dst->w; i++)
728                 if ((_s[i] & 0xff) > max)
729                         max = _s[i] & 0xff;
730         for (int i = 0; i < dst->h * dst->w; i++)
731                 *_d++ = ((_s[i] & 0xff) * 255) / max;// + (0xff - max);
732         b->pixels.format = C3PIXEL_A;
733 #else
734         c3pixels_p dst = c3pixels_new(
735                         cairo_image_surface_get_width (image),
736                         cairo_image_surface_get_height (image),
737                         4, cairo_image_surface_get_stride(image),
738                         cairo_image_surface_get_data (image));
739         dst->format = C3PIXEL_ARGB;
740         dst->normalize = 1;
741         dst->name = str_new(path);
742         uint8_t * line = dst->base;
743         for (int y = 0; y < dst->h; y++, line += dst->row) {
744                 uint32_t *p = (uint32_t *)line;
745                 for (int x = 0; x < dst->w; x++, p++) {
746                         uint8_t b = *p;
747                         *p = ((0xff - b) << 24);//|(b << 16)|(b << 8)|(b);
748                 }
749         }
750 #endif
751         line_aa_tex = dst;
752
753         c3pixels_p p = dst;
754         printf("struct { int w, h, stride, size, format; uint8_t pix[] } img = {\n"
755                         "%d, %d, %d, %d, %d\n",
756                         p->w, p->h, (int)p->row, p->psize, cairo_image_surface_get_format(image));
757         for (int i = 0; i < 32; i++)
758                 printf("0x%08x ", ((uint32_t*)p->base)[i]);
759         printf("\n");
760     }
761     c3object_p grid = c3object_new(c3->root);
762     {
763         for (int x = 0; x <= 20; x++) {
764                 for (int y = 0; y <= 20; y++) {
765                         c3vec3 p[4] = {
766                                 c3vec3f(-1+x*10,y*10,0.01), c3vec3f(1+x*10,y*10,0.01),
767                                 c3vec3f(x*10,-1+y*10,0.02), c3vec3f(x*10,1+y*10,0.02),
768                         };
769                 c3geometry_p g = c3geometry_new(
770                                 c3geometry_type(C3_LINES_TYPE, 0), grid);
771                 g->mat.color = c3vec4f(0.0, 0.0, 0.0, 0.8);
772                 g->mat.texture = line_aa_tex;
773                         c3lines_init(g, p, 4, 0.2);
774                 }
775         }
776     }
777
778    if (0) {
779                 c3vec3 p[4] = {
780                         c3vec3f(-5,-5,1), c3vec3f(205,-5,1),
781                 };
782         c3geometry_p g = c3geometry_new(
783                         c3geometry_type(C3_LINES_TYPE, 0), grid);
784         g->mat.color = c3vec4f(0.0, 0.0, 0.0, 1.0);
785         g->mat.texture = line_aa_tex;
786         g->line.width = 2;
787
788                 c3vertex_array_insert(&g->vertice,
789                                 g->vertice.count, p, 2);
790
791     }
792     head = c3stl_load("gfx/buserror-nozzle-model.stl", c3->root);
793     //head = c3object_new(c3->root);
794     c3transform_new(head);
795     if (head->geometry.count > 0) {
796         head->geometry.e[0]->mat.color = c3vec4f(0.6, 0.5, 0.0, 1.0);
797     }
798
799 #if 0
800     c3texture_p b = c3texture_new(head);
801     c3pixels_init(&b->pixels, 64, 64, 4, 4 * 64, NULL);
802     b->geometry.dirty = 1;
803     memset(b->pixels.base, 0xff, 10 * b->pixels.row);
804 #endif
805
806
807     hud = c3context_new(_w, _h);
808     hud->driver = list;
809
810     /*
811      * This is the offscreen framebuffer where the 3D scene is drawn
812      */
813     if (FBO) {
814         /*
815          * need to insert a header since there is nothing to detect the version number
816          * reliably without it, and __VERSION__ returns idiocy
817          */
818         char head[128];
819         sprintf(head, "#version %d\n#define GLSL_VERSION %d\n", glsl_version, glsl_version);
820
821         fxaa = c3program_new("fxaa");
822         c3program_array_add(&hud->programs, fxaa);
823         c3program_load_shader(fxaa, GL_VERTEX_SHADER, head,
824                         "gfx/postproc.vs", C3_PROGRAM_LOAD_UNIFORM);
825         c3program_load_shader(fxaa, GL_FRAGMENT_SHADER, head,
826                         "gfx/postproc.fs", C3_PROGRAM_LOAD_UNIFORM);
827
828         c3texture_p b = c3texture_new(hud->root);
829
830         c3pixels_p dst = c3pixels_new(_w, _h, 4, _w * 4, NULL);
831                 dst->name = str_new("fbo");
832                 dst->texture = fbo_texture;
833                 dst->normalize = 1;
834                 dst->dirty = 0;
835         //      dst->trace = 1;
836         b->geometry.mat.texture = dst;
837         b->geometry.mat.program = fxaa;
838         b->size = c3vec2f(_w, _h);
839                 b->geometry.mat.color = c3vec4f(1.0, 1.0, 1.0, 1.0);
840                 fbo_c3 = b;
841     }
842
843     {
844                 c3vec3 p[4] = {
845                         c3vec3f(10,10,0), c3vec3f(800-10,10,0),
846                 };
847         c3geometry_p g = c3geometry_new(
848                         c3geometry_type(C3_LINES_TYPE, 0), hud->root);
849         g->mat.color = c3vec4f(0.5, 0.5, 1.0, .3f);
850         g->mat.texture = line_aa_tex;
851                 c3lines_init(g, p, 2, 10);
852     }
853         return 1;
854 }
855
856 void
857 gl_dispose()
858 {
859         c3context_dispose(c3);
860 }
861
862 int
863 gl_runloop()
864 {
865         glutMainLoop();
866         gl_dispose();
867         return 0;
868 }