c3geometry: Removed projected vertices
[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 "c3sphere.h"
46 #include "c3program.h"
47 #include "c3gl.h"
48
49 #include <cairo/cairo.h>
50
51 #define FBO 1
52
53 struct cairo_surface_t;
54
55 int _w = 800, _h = 600;
56
57 c3context_p c3 = NULL;
58 c3context_p hud = NULL;
59
60 c3object_p head = NULL;         // hotend
61 c3texture_p fbo_c3;                     // frame buffer object texture
62 c3program_p fxaa = NULL;        // full screen antialias shader
63
64 int glsl_version = 110;
65
66 extern reprap_t reprap;
67
68 static int dumpError(const char * what)
69 {
70         GLenum e;
71         int count = 0;
72         while ((e = glGetError()) != GL_NO_ERROR) {
73                 printf("%s: %s\n", what, gluErrorString(e));
74                 count++;
75         }
76         return count;
77 }
78
79 #define GLCHECK(_w) {_w; dumpError(#_w);}
80
81 /* Global */
82 GLuint fbo, fbo_texture, rbo_depth;
83 //GLuint vbo_fbo_vertices;
84
85 static void
86 gl_offscreenInit(
87                 int screen_width,
88                 int screen_height)
89 {
90         /* init_resources */
91         /* Create back-buffer, used for post-processing */
92
93         /* Texture */
94         GLCHECK(glActiveTexture(GL_TEXTURE0));
95         glGenTextures(1, &fbo_texture);
96         glBindTexture(GL_TEXTURE_2D, fbo_texture);
97         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
98         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
99         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
100         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
101         glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, screen_width, screen_height, 0,
102                 GL_RGBA, GL_UNSIGNED_BYTE, NULL);
103         glBindTexture(GL_TEXTURE_2D, 0);
104
105         /* Depth buffer */
106         GLCHECK(glGenRenderbuffers(1, &rbo_depth));
107         glBindRenderbuffer(GL_RENDERBUFFER, rbo_depth);
108         glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, screen_width,
109                 screen_height);
110         glBindRenderbuffer(GL_RENDERBUFFER, 0);
111
112         /* Framebuffer to link everything together */
113         GLCHECK(glGenFramebuffers(1, &fbo));
114         glBindFramebuffer(GL_FRAMEBUFFER, fbo);
115         glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
116                 fbo_texture, 0);
117         glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
118                 GL_RENDERBUFFER, rbo_depth);
119
120         GLenum status;
121         if ((status = glCheckFramebufferStatus(GL_FRAMEBUFFER))
122                 != GL_FRAMEBUFFER_COMPLETE) {
123                 fprintf(stderr, "glCheckFramebufferStatus: error %d", (int)status);
124                 return ;
125         }
126 #if 0
127         // Set the list of draw buffers.
128         GLenum DrawBuffers[2] = {GL_COLOR_ATTACHMENT0};
129         glDrawBuffers(1, DrawBuffers); // "1" is the size of DrawBuffers
130         glBindFramebuffer(GL_FRAMEBUFFER, 0);
131 #endif
132 }
133
134 void
135 gl_offscreenReshape(
136                 int screen_width,
137                 int screen_height)
138 {
139 // Rescale FBO and RBO as well
140         glBindTexture(GL_TEXTURE_2D, fbo_texture);
141         glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, screen_width, screen_height, 0,
142                 GL_RGBA, GL_UNSIGNED_BYTE, NULL);
143         glBindTexture(GL_TEXTURE_2D, 0);
144
145         glBindRenderbuffer(GL_RENDERBUFFER, rbo_depth);
146         glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, screen_width,
147                 screen_height);
148         glBindRenderbuffer(GL_RENDERBUFFER, 0);
149 }
150
151 void gl_offscreenFree()
152 {
153         /* free_resources */
154         glDeleteRenderbuffers(1, &rbo_depth);
155         glDeleteTextures(1, &fbo_texture);
156         glDeleteFramebuffers(1, &fbo);
157 }
158
159 static void
160 _gl_reshape_cb(int w, int h)
161 {
162     _w  = w;
163     _h = h;
164
165         glBindFramebuffer(GL_FRAMEBUFFER, 0);
166     glViewport(0, 0, _w, _h);
167     gl_offscreenReshape(_w, _h);
168     glutPostRedisplay();
169 }
170
171 static void
172 _gl_key_cb(
173                 unsigned char key,
174                 int x,
175                 int y)  /* called on key press */
176 {
177         switch (key) {
178                 case 'q':
179                 //      avr_vcd_stop(&vcd_file);
180                         c3context_dispose(c3);
181                         exit(0);
182                         break;
183                 case 'r':
184                         printf("Starting VCD trace; press 's' to stop\n");
185                 //      avr_vcd_start(&vcd_file);
186                         break;
187                 case 's':
188                         printf("Stopping VCD trace\n");
189                 //      avr_vcd_stop(&vcd_file);
190                         break;
191                 case '1':
192                         if (fbo_c3->geometry.mat.program)
193                                 fbo_c3->geometry.mat.program = NULL;
194                         else
195                                 fbo_c3->geometry.mat.program = fxaa;
196                         glutPostRedisplay();
197                         break;
198         }
199 }
200
201 static void
202 _gl_display_cb(void)            /* function called whenever redisplay needed */
203 {
204 #if FBO
205         /*
206          * Draw in FBO object
207          */
208         glBindFramebuffer(GL_FRAMEBUFFER, fbo);
209         // draw (without glutSwapBuffers)
210         dumpError("glBindFramebuffer fbo");
211         glViewport(0, 0, _w, _h);
212
213 #else
214         glBindFramebuffer(GL_FRAMEBUFFER, 0);
215 #endif
216
217         c3context_view_set(c3, 0);
218         c3vec3 headp = c3vec3f(
219                         stepper_get_position_mm(&reprap.step_x),
220                         stepper_get_position_mm(&reprap.step_y),
221                         stepper_get_position_mm(&reprap.step_z));
222         c3mat4 headmove = translation3D(headp);
223         c3transform_set(head->transform.e[0], &headmove);
224
225         if (c3->root->dirty) {
226         //      printf("reproject head %.2f,%.2f,%.2f\n", headp.x, headp.y,headp.z);
227                 c3context_project(c3);
228         }
229         float z_min = c3context_view_get(c3)->z.min,
230                         z_max = c3context_view_get(c3)->z.max;
231         if (z_min < 0)
232                 z_min = 10;
233         z_min = 10;
234         if (z_max < z_min || z_max > 1000)
235                 z_max = 1000;
236
237         glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
238         glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
239
240         // Set up projection matrix
241         glMatrixMode(GL_PROJECTION); // Select projection matrix
242         c3mat4 p = perspective3D(50, (float)_w / (float)_h, z_min, z_max);
243         glLoadMatrixf(p.n);
244
245 #if 0
246         glCullFace(GL_BACK);
247         glEnable(GL_CULL_FACE);
248 #endif
249         glDepthMask(GL_TRUE);
250         glDepthFunc(GL_LEQUAL);
251         glEnable(GL_DEPTH_TEST);
252         glEnable(GL_LIGHTING);
253 //      glPolygonMode( GL_FRONT_AND_BACK, GL_LINE );
254
255         glEnable(GL_ALPHA_TEST);
256         glAlphaFunc(GL_GREATER, 1.0f / 255.0f);
257         glEnable(GL_BLEND); // Enable Blending
258         glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); // Type Of Blending To Use
259
260         glMatrixMode(GL_MODELVIEW);
261
262         c3context_draw(c3);
263
264 #if FBO
265         /*
266          * Draw back FBO over the screen
267          */
268         glBindFramebuffer(GL_FRAMEBUFFER, 0);
269         dumpError("glBindFramebuffer 0");
270
271         glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
272         glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
273 #endif
274         glDisable(GL_DEPTH_TEST);
275         glDisable(GL_LIGHTING);
276         glDisable(GL_ALPHA_TEST);
277
278         glUseProgram(0);
279
280         glMatrixMode(GL_PROJECTION); // Select projection matrix
281         glLoadIdentity(); // Start with an identity matrix
282         glOrtho(0, _w, 0, _h, 0, 10);
283         glScalef(1, -1, 1);
284         glTranslatef(0, -1 * _h, 0);
285         glMatrixMode(GL_MODELVIEW); // Select modelview matrix
286
287         if (hud)
288                 c3context_draw(hud);
289
290     glutSwapBuffers();
291 }
292
293 #if !defined(GLUT_WHEEL_UP)
294 #  define GLUT_WHEEL_UP   3
295 #  define GLUT_WHEEL_DOWN 4
296 #endif
297
298
299 int button;
300 c3vec2 move;
301
302 static
303 void _gl_button_cb(
304                 int b,
305                 int s,
306                 int x,
307                 int y)
308 {
309         button = s == GLUT_DOWN ? b : 0;
310         move = c3vec2f(x, y);
311         c3context_view_p view = c3context_view_get_at(c3, 0);
312 //      printf("button %d: %.1f,%.1f\n", b, move.x, move.y);
313         switch (b) {
314                 case GLUT_LEFT_BUTTON:
315                 case GLUT_RIGHT_BUTTON: // call motion
316                         break;
317                 case GLUT_WHEEL_UP:
318                 case GLUT_WHEEL_DOWN:
319                         if (view->cam.distance > 10) {
320                                 const float d = 0.004;
321                                 c3cam_set_distance(&view->cam,
322                                                 view->cam.distance * ((b == GLUT_WHEEL_DOWN) ? (1.0+d) : (1.0-d)));
323                                 c3cam_update_matrix(&view->cam);
324                                 view->dirty = 1;        // resort the array
325                         }
326                         break;
327         }
328 }
329
330 void
331 _gl_motion_cb(
332                 int x,
333                 int y)
334 {
335         c3vec2 m = c3vec2f(x, y);
336         c3vec2 delta = c3vec2_sub(move, m);
337         c3context_view_p view = c3context_view_get_at(c3, 0);
338
339 //      printf("%s b%d click %.1f,%.1f now %d,%d delta %.1f,%.1f\n",
340 //                      __func__, button, move.n[0], move.n[1], x, y, delta.x, delta.y);
341
342         switch (button) {
343                 case GLUT_LEFT_BUTTON: {
344                         c3mat4 rotx = rotation3D(view->cam.side, delta.n[1] / 4);
345                         c3mat4 roty = rotation3D(c3vec3f(0.0, 0.0, 1.0), delta.n[0] / 4);
346                         rotx = c3mat4_mul(&rotx, &roty);
347                         c3cam_rot_about_lookat(&view->cam, &rotx);
348                         c3cam_update_matrix(&view->cam);
349
350                         view->dirty = 1;        // resort the array
351                 }       break;
352                 case GLUT_RIGHT_BUTTON: {
353                         // offset both points, but following the plane
354                         c3vec3 f = c3vec3_mulf(
355                                         c3vec3f(-view->cam.side.y, view->cam.side.x, 0),
356                                         -delta.n[1] / 4);
357                         view->cam.eye = c3vec3_add(view->cam.eye, f);
358                         view->cam.lookat = c3vec3_add(view->cam.lookat, f);
359                         c3cam_movef(&view->cam, delta.n[0] / 8, 0, 0);
360                         c3cam_update_matrix(&view->cam);
361
362                     view->dirty = 1;    // resort the array
363                 }       break;
364         }
365         move = m;
366 }
367
368 // gl timer. if the lcd is dirty, refresh display
369 static void
370 _gl_timer_cb(
371                 int i)
372 {
373         glutTimerFunc(1000 / 24, _gl_timer_cb, 0);
374         glutPostRedisplay();
375 }
376
377 const c3driver_context_t * c3_driver_list[3] = { NULL, NULL };
378
379 int
380 gl_init(
381                 int argc,
382                 char *argv[] )
383 {
384         glutInit(&argc, argv);          /* initialize GLUT system */
385
386         glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH | GLUT_ALPHA);
387         glutInitWindowSize(_w, _h);             /* width=400pixels height=500pixels */
388         /*window =*/ glutCreateWindow("Press 'q' to quit");     /* create window */
389
390         glutDisplayFunc(_gl_display_cb);                /* set window's display callback */
391         glutKeyboardFunc(_gl_key_cb);           /* set window's key callback */
392         glutTimerFunc(1000 / 24, _gl_timer_cb, 0);
393
394         glutMouseFunc(_gl_button_cb);
395         glutMotionFunc(_gl_motion_cb);
396     glutReshapeFunc(_gl_reshape_cb);
397
398         glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
399         glHint(GL_GENERATE_MIPMAP_HINT, GL_NICEST);
400         /*
401         glHint(GL_POINT_SMOOTH_HINT, GL_NICEST);
402         glHint(GL_LINE_SMOOTH_HINT, GL_NICEST);
403         glHint(GL_POLYGON_SMOOTH_HINT, GL_NICEST);
404         glEnable(GL_LINE_SMOOTH);
405          */
406         // enable color tracking
407         glEnable(GL_COLOR_MATERIAL);
408         // set material properties which will be assigned by glColor
409         glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE);
410
411         /* setup some lights */
412         glShadeModel(GL_SMOOTH);
413         glEnable(GL_LIGHTING);
414         GLfloat global_ambient[] = { 0.5f, 0.5f, 0.5f, 1.0f };
415         glLightModelfv(GL_LIGHT_MODEL_AMBIENT, global_ambient);
416
417         {
418                 GLfloat specular[] = {1.0f, 1.0f, 1.0f , 0.8f};
419                 GLfloat position[] = { -30.0f, -30.0f, 200.0f, 1.0f };
420                 glLightfv(GL_LIGHT0, GL_SPECULAR, specular);
421                 glLightfv(GL_LIGHT0, GL_POSITION, position);
422                 glEnable(GL_LIGHT0);
423         }
424         {
425                 GLfloat specular[] = {1.0f, 1.0f, 1.0f , 0.8f};
426                 GLfloat position[] = { 250.0f, -50.0f, 100.0f, 1.0f };
427                 glLightfv(GL_LIGHT0, GL_SPECULAR, specular);
428                 glLightfv(GL_LIGHT0, GL_POSITION, position);
429                 glEnable(GL_LIGHT0);
430         }
431
432         /*
433          * Extract the GLSL version as a nuneric value for later
434          */
435         const char * glsl = (const char *)glGetString(GL_SHADING_LANGUAGE_VERSION);
436         {
437                 int M = 0, m = 0;
438                 if (sscanf(glsl, "%d.%d", &M, &m) == 2)
439                         glsl_version = (M * 100) + m;
440
441         }
442         printf("GL_SHADING_LANGUAGE_VERSION %s = %d\n", glsl, glsl_version);
443
444         gl_offscreenInit(_w, _h);
445
446         c3_driver_list[0] = c3gl_getdriver();
447
448     c3 = c3context_new(_w, _h);
449     c3->driver = c3_driver_list;
450
451     c3cam_p cam = &c3context_view_get_at(c3, 0)->cam;
452         cam->lookat = c3vec3f(100.0, 100.0, 0.0);
453         cam->eye = c3vec3f(100.0, -100.0, 100.0);
454
455     {
456         const char *path = "gfx/hb.png";
457         cairo_surface_t * image = cairo_image_surface_create_from_png (path);
458         printf("image = %p %p\n", image, cairo_image_surface_get_data (image));
459         c3texture_p b = c3texture_new(c3->root);
460
461         c3pixels_p dst = c3pixels_new(
462                         cairo_image_surface_get_width (image),
463                         cairo_image_surface_get_height (image),
464                         4, cairo_image_surface_get_stride(image),
465                         cairo_image_surface_get_data (image));
466                 dst->name = str_new(path);
467         b->geometry.mat.texture = dst;
468         b->size = c3vec2f(200, 200);
469                 b->geometry.mat.color = c3vec4f(1.0, 1.0, 1.0, 1.0);
470 //          c3transform_new(head);
471     }
472     c3pixels_p line_aa_tex = NULL;
473     {
474         const char *path = "gfx/BlurryCircle.png";
475         cairo_surface_t * image = cairo_image_surface_create_from_png (path);
476         printf("image = %p %p\n", image, cairo_image_surface_get_data (image));
477
478 #if 0
479         c3pixels_p dst = &b->pixels;
480         c3pixels_init(dst,
481                         cairo_image_surface_get_width (image),
482                         cairo_image_surface_get_height (image),
483                         1, cairo_image_surface_get_width (image),
484                         NULL);
485         c3pixels_alloc(dst);
486         b->size = c3vec2f(32, 32);
487         b->normalized = 1;
488
489         c3pixels_p src = c3pixels_new(
490                         cairo_image_surface_get_width (image),
491                         cairo_image_surface_get_height (image),
492                         4, cairo_image_surface_get_stride(image),
493                         cairo_image_surface_get_data (image));
494
495         uint32_t * _s = (uint32_t *)src->base;
496         uint8_t * _d = (uint8_t *)dst->base;
497         int max = 0;
498         for (int i = 0; i < dst->h * dst->w; i++)
499                 if ((_s[i] & 0xff) > max)
500                         max = _s[i] & 0xff;
501         for (int i = 0; i < dst->h * dst->w; i++)
502                 *_d++ = ((_s[i] & 0xff) * 255) / max;// + (0xff - max);
503         b->pixels.format = C3PIXEL_A;
504 #else
505         c3pixels_p dst = c3pixels_new(
506                         cairo_image_surface_get_width (image),
507                         cairo_image_surface_get_height (image),
508                         4, cairo_image_surface_get_stride(image),
509                         cairo_image_surface_get_data (image));
510         dst->format = C3PIXEL_ARGB;
511         dst->normalize = 1;
512         dst->name = str_new(path);
513         uint8_t * line = dst->base;
514         for (int y = 0; y < dst->h; y++, line += dst->row) {
515                 uint32_t *p = (uint32_t *)line;
516                 for (int x = 0; x < dst->w; x++, p++) {
517                         uint8_t b = *p;
518                         *p = ((0xff - b) << 24);//|(b << 16)|(b << 8)|(b);
519                 }
520         }
521 #endif
522         line_aa_tex = dst;
523 #if 0
524         c3pixels_p p = dst;
525         printf("struct { int w, h, stride, size, format; uint8_t pix[] } img = {\n"
526                         "%d, %d, %d, %d, %d\n",
527                         p->w, p->h, (int)p->row, p->psize, cairo_image_surface_get_format(image));
528         for (int i = 0; i < 32; i++)
529                 printf("0x%08x ", ((uint32_t*)p->base)[i]);
530         printf("\n");
531 #endif
532     }
533     c3object_p grid = c3object_new(c3->root);
534     {
535         for (int x = 0; x <= 20; x++) {
536                 for (int y = 0; y <= 20; y++) {
537                         c3vec3 p[4] = {
538                                 c3vec3f(-1+x*10,y*10,0.01), c3vec3f(1+x*10,y*10,0.01),
539                                 c3vec3f(x*10,-1+y*10,0.02), c3vec3f(x*10,1+y*10,0.02),
540                         };
541                 c3geometry_p g = c3geometry_new(
542                                 c3geometry_type(C3_LINES_TYPE, 0), grid);
543                 g->mat.color = c3vec4f(0.0, 0.0, 0.0, 0.8);
544                 g->mat.texture = line_aa_tex;
545                         c3lines_init(g, p, 4, 0.2);
546                 }
547         }
548     }
549     {   // light bulb
550         c3geometry_p g = c3sphere_uv(c3->root, c3vec3f(-30.0f, -20.0f, 200.0f), 3, 10, 10);
551         g->mat.color = c3vec4f(1.0, 1.0, 0.0, 1.0);
552     }
553
554    if (0) {
555                 c3vec3 p[4] = {
556                         c3vec3f(-5,-5,1), c3vec3f(205,-5,1),
557                 };
558         c3geometry_p g = c3geometry_new(
559                         c3geometry_type(C3_LINES_TYPE, 0), grid);
560         g->mat.color = c3vec4f(0.0, 0.0, 0.0, 1.0);
561         g->mat.texture = line_aa_tex;
562         g->line.width = 2;
563
564                 c3vertex_array_insert(&g->vertice,
565                                 g->vertice.count, p, 2);
566
567     }
568     head = c3stl_load("gfx/buserror-nozzle-model.stl", c3->root);
569     //head = c3object_new(c3->root);
570     c3transform_new(head);
571     if (head->geometry.count > 0) {
572         c3geometry_factor(head->geometry.e[0], 0.1, (20 * M_PI) / 180.0);
573         head->geometry.e[0]->mat.color = c3vec4f(0.6, 0.5, 0.0, 1.0);
574     }
575
576 #if 0
577     c3texture_p b = c3texture_new(head);
578     c3pixels_init(&b->pixels, 64, 64, 4, 4 * 64, NULL);
579     b->geometry.dirty = 1;
580     memset(b->pixels.base, 0xff, 10 * b->pixels.row);
581 #endif
582
583
584     hud = c3context_new(_w, _h);
585     hud->driver = c3_driver_list;
586
587     /*
588      * This is the offscreen framebuffer where the 3D scene is drawn
589      */
590     if (FBO) {
591         /*
592          * need to insert a header since there is nothing to detect the version number
593          * reliably without it, and __VERSION__ returns idiocy
594          */
595         char head[128];
596         sprintf(head, "#version %d\n#define GLSL_VERSION %d\n", glsl_version, glsl_version);
597
598         fxaa = c3program_new("fxaa");
599         c3program_array_add(&hud->programs, fxaa);
600         c3program_load_shader(fxaa, GL_VERTEX_SHADER, head,
601                         "gfx/postproc.vs", C3_PROGRAM_LOAD_UNIFORM);
602         c3program_load_shader(fxaa, GL_FRAGMENT_SHADER, head,
603                         "gfx/postproc.fs", C3_PROGRAM_LOAD_UNIFORM);
604
605         c3texture_p b = c3texture_new(hud->root);
606
607         c3pixels_p dst = c3pixels_new(_w, _h, 4, _w * 4, NULL);
608                 dst->name = str_new("fbo");
609                 dst->texture = (c3apiobject_t)fbo_texture;
610                 dst->normalize = 1;
611                 dst->dirty = 0;
612         //      dst->trace = 1;
613         b->geometry.mat.texture = dst;
614         b->geometry.mat.program = fxaa;
615         b->size = c3vec2f(_w, _h);
616                 b->geometry.mat.color = c3vec4f(1.0, 1.0, 1.0, 1.0);
617                 fbo_c3 = b;
618     }
619
620     {
621                 c3vec3 p[4] = {
622                         c3vec3f(10,10,0), c3vec3f(800-10,10,0),
623                 };
624         c3geometry_p g = c3geometry_new(
625                         c3geometry_type(C3_LINES_TYPE, 0), hud->root);
626         g->mat.color = c3vec4f(0.5, 0.5, 1.0, .3f);
627         g->mat.texture = line_aa_tex;
628                 c3lines_init(g, p, 2, 10);
629     }
630         return 1;
631 }
632
633 void
634 gl_dispose()
635 {
636         c3context_dispose(c3);
637 }
638
639 int
640 gl_runloop()
641 {
642         glutMainLoop();
643         gl_dispose();
644         return 0;
645 }