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