reprap: Added shadow mapping
[simavr] / examples / board_reprap / src / reprap_gl.c
index 5e041aa..74df728 100644 (file)
  */
 
 #if __APPLE__
+#define GL_GLEXT_PROTOTYPES
 #include <GLUT/glut.h>
+#include <OpenGL/gl.h>
+#include <OpenGL/glext.h>
 #else
+#define GL_GLEXT_PROTOTYPES
+#include <GL/gl.h>
 #include <GL/glut.h>
+#include <GL/glext.h>
 #endif
 
 #include <stdio.h>
 #include "reprap.h"
 #include "reprap_gl.h"
 
-#include "c3/c3.h"
-#include "c3/c3camera.h"
-#include "c3/c3arcball.h"
-#include "c3/c3driver_context.h"
-#include "c3/c3stl.h"
+#include "c3.h"
+#include "c3camera.h"
+#include "c3driver_context.h"
+#include "c3stl.h"
+#include "c3lines.h"
+#include "c3sphere.h"
+#include "c3light.h"
+#include "c3program.h"
+#include "c3gl.h"
+#include "c3gl_fbo.h"
+
+#include <cairo/cairo.h>
+
+struct cairo_surface_t;
 
 int _w = 800, _h = 600;
-c3cam cam;
-c3arcball arcball;
-c3context_p c3;
-c3object_p head;
+
+c3context_p c3 = NULL;
+c3context_p hud = NULL;
+
+c3object_p     head = NULL;    // hotend
+c3texture_p fbo_c3;                    // frame buffer object texture
+c3program_p fxaa = NULL;       // full screen antialias shader
+c3program_p scene = NULL;
+c3gl_fbo_t     fbo;
+c3gl_fbo_t     shadow;
+
+
+enum {
+       uniform_ShadowMap = 0,
+       uniform_pixelOffset,
+       uniform_tex0,
+       uniform_shadowMatrix
+};
+const char *uniforms_scene[] = {
+               "shadowMap",
+               "pixelOffset",
+               "tex0",
+               "shadowMatrix",
+               NULL
+};
+
+int glsl_version = 110;
 
 extern reprap_t reprap;
 
@@ -56,6 +94,32 @@ static int dumpError(const char * what)
        return count;
 }
 
+#define GLCHECK(_w) {_w; dumpError(#_w);}
+
+
+static void
+_gl_reshape_cb(int w, int h)
+{
+    _w  = w;
+    _h = h;
+
+       c3vec2 size = c3vec2f(_w, _h);
+
+       glBindFramebuffer(GL_FRAMEBUFFER, 0);
+    glViewport(0, 0, _w, _h);
+    c3gl_fbo_resize(&fbo, size);
+    c3texture_resize(fbo_c3, size);
+    c3context_view_get_at(c3, 0)->size = size;
+
+    if (fxaa) {
+       glUseProgram((GLuint)fxaa->pid);
+       GLCHECK(glUniform2fv((GLuint)fxaa->params.e[0].pid, 1, size.n));
+       glUseProgram(0);
+    }
+
+    glutPostRedisplay();
+}
+
 static void
 _gl_key_cb(
                unsigned char key,
@@ -76,145 +140,21 @@ _gl_key_cb(
                        printf("Stopping VCD trace\n");
                //      avr_vcd_stop(&vcd_file);
                        break;
+               case '1':
+                       if (fbo_c3->geometry.mat.program)
+                               fbo_c3->geometry.mat.program = NULL;
+                       else
+                               fbo_c3->geometry.mat.program = fxaa;
+                       glutPostRedisplay();
+                       break;
        }
 }
 
-static void
-_c3_geometry_prepare(
-               c3context_p c,
-               const struct c3driver_context_t *d,
-               c3geometry_p g)
-{
-       switch(g->type.type) {
-               case C3_TRIANGLE_TYPE: {
-                       g->type.subtype = GL_TRIANGLES;
-                       //g->mat.color = c3vec4f(0.0, 0.0, 1.0, 1.0);
-               }       break;
-               case C3_TEXTURE_TYPE: {
-                       c3texture_p t = (c3texture_p)g;
-                       g->type.subtype = GL_TRIANGLE_FAN;
-                       g->mat.color = c3vec4f(0.0, 1.0, 0.0, 0.5);
-                       printf("_c3_geometry_prepare xrure %d!\n", g->textures.count);
-                       if (!g->texture) {
-                               GLuint texID = 0;
-                               dumpError("cp_gl_texture_load_argb flush");
-
-                               glEnable(GL_TEXTURE_RECTANGLE_ARB);
-                               dumpError("cp_gl_texture_load_argb GL_TEXTURE_RECTANGLE_ARB");
-
-                               glGenTextures(1, &texID);
-                               dumpError("cp_gl_texture_load_argb glBindTexture GL_TEXTURE_RECTANGLE_ARB");
-
-                               glPixelStorei(GL_UNPACK_ROW_LENGTH, t->pixels.row / 4);
-                               glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
-                               glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
-                               glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
-                               glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
-
-                               g->mat.texture = texID;
-                               g->texture = 1;
-                       }
-                       glBindTexture(GL_TEXTURE_RECTANGLE_ARB, g->mat.texture);
-                       glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA8,
-                                       t->pixels.w, t->pixels.h, 0,
-                                       GL_RGBA, GL_UNSIGNED_BYTE,
-                                       t->pixels.base);
-               }       break;
-               default:
-                   break;
-       }
-}
-
-static void
-_c3_geometry_draw(
-               c3context_p c,
-               const struct c3driver_context_t *d,
-               c3geometry_p g )
-{
-       glColor4fv(g->mat.color.n);
-//     glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, g->mat.color.n);
-       glVertexPointer(3, GL_FLOAT, 0,
-                       g->projected.count ? g->projected.e : g->vertice.e);
-       glEnableClientState(GL_VERTEX_ARRAY);
-       if (g->textures.count && g->texture) {
-               glDisable(GL_TEXTURE_2D);
-               glEnable(GL_TEXTURE_RECTANGLE_ARB);
-               glBindTexture(GL_TEXTURE_RECTANGLE_ARB, g->mat.texture);
-               glTexCoordPointer(2, GL_FLOAT, 0,
-                               g->textures.e);
-               glEnableClientState(GL_TEXTURE_COORD_ARRAY);
-       } else
-               glDisable(GL_TEXTURE_RECTANGLE_ARB);
-       if (g->normals.count) {
-               glNormalPointer(GL_FLOAT, 0,
-                               g->normals.e);
-               glEnableClientState(GL_NORMAL_ARRAY);
-       }
-       glDrawArrays(g->type.subtype, 0, g->vertice.count);
-       glDisableClientState(GL_VERTEX_ARRAY);
-       glDisableClientState(GL_TEXTURE_COORD_ARRAY);
-       glDisableClientState(GL_NORMAL_ARRAY);
-}
-
-const c3driver_context_t c3context_driver = {
-               .geometry_prepare = _c3_geometry_prepare,
-               .geometry_draw = _c3_geometry_draw,
-};
-
-/*
- * Computes the distance from the eye, sort by this value
- */
-static int
-_c3_z_sorter(
-               const void *_p1,
-               const void *_p2)
-{
-       c3geometry_p g1 = *(c3geometry_p*)_p1;
-       c3geometry_p g2 = *(c3geometry_p*)_p2;
-       // get center of bboxes
-       c3vec3 c1 = c3vec3_add(g1->bbox.min, c3vec3_divf(c3vec3_sub(g1->bbox.max, g1->bbox.min), 2));
-       c3vec3 c2 = c3vec3_add(g2->bbox.min, c3vec3_divf(c3vec3_sub(g2->bbox.max, g2->bbox.min), 2));
-
-       c3f d1 = c3vec3_length2(c3vec3_sub(c1, cam.eye));
-       c3f d2 = c3vec3_length2(c3vec3_sub(c2, cam.eye));
-
-       /*
-        * make sure transparent items are drawn after everyone else
-        */
-       if (g1->mat.color.n[3] < 1)
-               d1 -= 100000.0;
-       if (g2->mat.color.n[3] < 1)
-               d2 -= 100000.0;
-
-       return d1 < d2 ? 1 : d1 > d2 ? -1 : 0;
-}
-
 static void
 _gl_display_cb(void)           /* function called whenever redisplay needed */
 {
-       glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
-       glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
-
-       // Set up projection matrix
-       glMatrixMode(GL_PROJECTION); // Select projection matrix
-       glLoadIdentity(); // Start with an identity matrix
-
-       gluPerspective(60, _w / _h, 60, 400);
-
-//     glDepthMask(GL_TRUE);
-//     glCullFace(GL_BACK);
-//     glEnable(GL_CULL_FACE);
-       glEnable(GL_DEPTH_TEST);
-
-       glEnable(GL_BLEND);                         // Enable Blending
-       glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);          // Type Of Blending To Use
-
-    glMatrixMode( GL_MODELVIEW );
-    glLoadIdentity();
-   // glMultMatrixf(arcball.rot.n);
-    glMultMatrixf(cam.mtx.n);
-    glTranslatef( -cam.eye.n[VX], -cam.eye.n[VY], -cam.eye.n[VZ] );
-  //  glMultMatrixf(arcball.rot.n);
+       int drawIndexes[] = { 1, 0 };
+       int drawViewStart = c3->root->dirty ? 0 : 1;
 
        c3vec3 headp = c3vec3f(
                        stepper_get_position_mm(&reprap.step_x),
@@ -223,29 +163,118 @@ _gl_display_cb(void)             /* function called whenever redisplay needed */
        c3mat4 headmove = translation3D(headp);
        c3transform_set(head->transform.e[0], &headmove);
 
-       if (c3->root->dirty) {
-       //      printf("reproject\n");
-               c3context_prepare(c3);
-
-               qsort(c3->projected.e, c3->projected.count,
-                               sizeof(c3->projected.e[0]), _c3_z_sorter);
+       for (int vi = drawViewStart; vi < 2; vi++) {
+               c3context_view_set(c3, drawIndexes[vi]);
+
+               /*
+                * Draw in FBO object
+                */
+               c3context_view_p view = c3context_view_get(c3);
+               glBindFramebuffer(GL_FRAMEBUFFER, (GLuint)view->bid);
+               // draw (without glutSwapBuffers)
+               dumpError("glBindFramebuffer fbo");
+               glViewport(0, 0, view->size.x, view->size.y);
+
+               c3context_project(c3);
+
+               glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
+               glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+               // Set up projection matrix
+               glMatrixMode(GL_PROJECTION); // Select projection matrix
+               glLoadMatrixf(view->projection.n);
+
+               glEnable(GL_CULL_FACE);
+               glDepthMask(GL_TRUE);
+               glDepthFunc(GL_LEQUAL);
+               glEnable(GL_DEPTH_TEST);
+       //      glPolygonMode( GL_FRONT_AND_BACK, GL_LINE );
+
+               //glEnable(GL_ALPHA_TEST);
+               //glAlphaFunc(GL_GREATER, 1.0f / 255.0f);
+               glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); // Type Of Blending To Use
+
+               glMatrixMode(GL_MODELVIEW);
+
+
+               if (view->type == C3_CONTEXT_VIEW_EYE) {
+               //      glShadeModel(GL_SMOOTH);
+               //      glEnable(GL_LIGHTING);
+                       glCullFace(GL_BACK);
+                       glEnable(GL_BLEND); // Enable Blending
+
+                       c3context_view_p light = c3context_view_get_at(c3, 1);
+
+                       // This is matrix transform every coordinate x,y,z
+                       // x = x* 0.5 + 0.5
+                       // y = y* 0.5 + 0.5
+                       // z = z* 0.5 + 0.5
+                       // Moving from unit cube [-1,1] to [0,1]
+                       const c3f bias[16] = {
+                               0.5, 0.0, 0.0, 0.0,
+                               0.0, 0.5, 0.0, 0.0,
+                               0.0, 0.0, 0.5, 0.0,
+                               0.5, 0.5, 0.5, 1.0};
+
+                       c3mat4 b = c3mat4_mul(&light->projection, (c3mat4p)bias);
+                       c3mat4 tex = c3mat4_mul(&light->cam.mtx, &b);
+
+                       GLCHECK(glUseProgram((GLuint)scene->pid));
+                       glUniformMatrix4fv(
+                                       (GLuint)scene->params.e[uniform_shadowMatrix].pid,
+                                       1, GL_FALSE, tex.n);
+               } else {
+                       glCullFace(GL_FRONT);
+                       glShadeModel(GL_FLAT);
+                       glDisable(GL_LIGHTING);
+                       glDisable(GL_BLEND); // Disable Blending
+               }
+
+               c3context_draw(c3);
        }
-       c3context_draw(c3);
+
+       /*
+        * Draw back FBO over the screen
+        */
+       glBindFramebuffer(GL_FRAMEBUFFER, 0);
+       dumpError("glBindFramebuffer 0");
+       glViewport(0, 0, _w, _h);
+
+       glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
+       glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+       glDisable(GL_DEPTH_TEST);
+       glDisable(GL_LIGHTING);
+       glDisable(GL_ALPHA_TEST);
+       glDisable(GL_CULL_FACE);
+
+       glUseProgram(0);
 
        glMatrixMode(GL_PROJECTION); // Select projection matrix
        glLoadIdentity(); // Start with an identity matrix
-       glOrtho(0, _w, 0, _h, 0, 10);
-       glScalef(1,-1,1);
-       glTranslatef(0, -1 * _h, 0);
+
+       c3mat4 pro = screen_ortho3D(0, _w, 0, _h, 0, 10);
+       glLoadMatrixf(pro.n);
 
        glMatrixMode(GL_MODELVIEW); // Select modelview matrix
 
+       if (hud->root->dirty) {
+       //      printf("reproject head %.2f,%.2f,%.2f\n", headp.x, headp.y,headp.z);
+               c3context_project(hud);
+       }
+       c3context_draw(hud);
+
     glutSwapBuffers();
 }
 
+#if !defined(GLUT_WHEEL_UP)
+#  define GLUT_WHEEL_UP   3
+#  define GLUT_WHEEL_DOWN 4
+#endif
+
+
 int button;
 c3vec2 move;
-c3cam startcam;
 
 static
 void _gl_button_cb(
@@ -255,12 +284,24 @@ void _gl_button_cb(
                int y)
 {
        button = s == GLUT_DOWN ? b : 0;
-       startcam = cam;
        move = c3vec2f(x, y);
-       if (s == GLUT_DOWN)
-               c3arcball_mouse_down(&arcball, x, y);
-       else
-               c3arcball_mouse_up(&arcball);
+       c3context_view_p view = c3context_view_get_at(c3, 0);
+//     printf("button %d: %.1f,%.1f\n", b, move.x, move.y);
+       switch (b) {
+               case GLUT_LEFT_BUTTON:
+               case GLUT_RIGHT_BUTTON: // call motion
+                       break;
+               case GLUT_WHEEL_UP:
+               case GLUT_WHEEL_DOWN:
+                       if (view->cam.distance > 10) {
+                               const float d = 0.004;
+                               c3cam_set_distance(&view->cam,
+                                               view->cam.distance * ((b == GLUT_WHEEL_DOWN) ? (1.0+d) : (1.0-d)));
+                               c3cam_update_matrix(&view->cam);
+                               view->dirty = 1;        // resort the array
+                       }
+                       break;
+       }
 }
 
 void
@@ -270,27 +311,32 @@ _gl_motion_cb(
 {
        c3vec2 m = c3vec2f(x, y);
        c3vec2 delta = c3vec2_sub(move, m);
+       c3context_view_p view = c3context_view_get_at(c3, 0);
 
-//     printf("%s b%d click %.1f,%.1f now %d,%d\n",
-//                     __func__, button, move.n[0], move.n[1], x, y);
+//     printf("%s b%d click %.1f,%.1f now %d,%d delta %.1f,%.1f\n",
+//                     __func__, button, move.n[0], move.n[1], x, y, delta.x, delta.y);
 
        switch (button) {
                case GLUT_LEFT_BUTTON: {
-
-               //      c3cam_eye_yaw(&cam, delta.n[0] / 4);
-               //      c3cam_eye_pitch(&cam, delta.n[1] / 4);
-
-                       c3mat4 rotx = rotation3D(c3vec3f(1.0, 0, 0), delta.n[1] / 4);
+                       c3mat4 rotx = rotation3D(view->cam.side, delta.n[1] / 4);
                        c3mat4 roty = rotation3D(c3vec3f(0.0, 0.0, 1.0), delta.n[0] / 4);
                        rotx = c3mat4_mul(&rotx, &roty);
-                       c3cam_rot_about_lookat(&cam, &rotx);
+                       c3cam_rot_about_lookat(&view->cam, &rotx);
+                       c3cam_update_matrix(&view->cam);
 
-                   c3cam_update_matrix(&cam);
-                   c3->root->dirty = 1;        // resort the array
-//                 c3arcball_mouse_motion(&arcball, x, y, 0,0,0);
+                       view->dirty = 1;        // resort the array
                }       break;
                case GLUT_RIGHT_BUTTON: {
-
+                       // offset both points, but following the plane
+                       c3vec3 f = c3vec3_mulf(
+                                       c3vec3f(-view->cam.side.y, view->cam.side.x, 0),
+                                       -delta.n[1] / 4);
+                       view->cam.eye = c3vec3_add(view->cam.eye, f);
+                       view->cam.lookat = c3vec3_add(view->cam.lookat, f);
+                       c3cam_movef(&view->cam, delta.n[0] / 8, 0, 0);
+                       c3cam_update_matrix(&view->cam);
+
+                   view->dirty = 1;    // resort the array
                }       break;
        }
        move = m;
@@ -301,13 +347,12 @@ static void
 _gl_timer_cb(
                int i)
 {
-       //static int oldstate = -1;
-       // restart timer
-       c3arcball_idle(&arcball);
        glutTimerFunc(1000 / 24, _gl_timer_cb, 0);
        glutPostRedisplay();
 }
 
+const c3driver_context_t * c3_driver_list[3] = { NULL, NULL };
+
 int
 gl_init(
                int argc,
@@ -315,7 +360,7 @@ gl_init(
 {
        glutInit(&argc, argv);          /* initialize GLUT system */
 
-       glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH);
+       glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH | GLUT_ALPHA);
        glutInitWindowSize(_w, _h);             /* width=400pixels height=500pixels */
        /*window =*/ glutCreateWindow("Press 'q' to quit");     /* create window */
 
@@ -325,79 +370,225 @@ gl_init(
 
        glutMouseFunc(_gl_button_cb);
        glutMotionFunc(_gl_motion_cb);
+    glutReshapeFunc(_gl_reshape_cb);
 
        glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
-       glHint(GL_POINT_SMOOTH_HINT, GL_NICEST);
-       glHint(GL_LINE_SMOOTH_HINT, GL_NICEST);
-       glHint(GL_POLYGON_SMOOTH_HINT, GL_NICEST);
-
-       glEnable(GL_LINE_SMOOTH);
+       glHint(GL_GENERATE_MIPMAP_HINT, GL_NICEST);
 
        // enable color tracking
        glEnable(GL_COLOR_MATERIAL);
        // set material properties which will be assigned by glColor
        glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE);
 
-
-       glShadeModel(GL_SMOOTH);
-#if 1
-//     glEnable(GL_DEPTH_TEST);
-       glEnable(GL_LIGHTING);
+       /* setup some lights */
        GLfloat global_ambient[] = { 0.5f, 0.5f, 0.5f, 1.0f };
        glLightModelfv(GL_LIGHT_MODEL_AMBIENT, global_ambient);
 
-       {
+       if (0) {
                GLfloat specular[] = {1.0f, 1.0f, 1.0f , 0.8f};
-               GLfloat position[] = { -50.0f, -50.0f, 100.0f, 1.0f };
-               glLightfv(GL_LIGHT0, GL_SPECULAR, specular);
-               glLightfv(GL_LIGHT0, GL_POSITION, position);
-               glEnable(GL_LIGHT0);
+               GLfloat position[] = { 250.0f, -50.0f, 100.0f, 1.0f };
+               glLightfv(GL_LIGHT1, GL_SPECULAR, specular);
+               glLightfv(GL_LIGHT1, GL_POSITION, position);
+               glEnable(GL_LIGHT1);
        }
+
+       /*
+        * Extract the GLSL version as a numeric value for later
+        */
+       const char * glsl = (const char *)glGetString(GL_SHADING_LANGUAGE_VERSION);
        {
-               GLfloat specular[] = {1.0f, 1.0f, 1.0f , 0.8f};
-               GLfloat position[] = { 250.0f, -50.0f, 100.0f, 1.0f };
-               glLightfv(GL_LIGHT0, GL_SPECULAR, specular);
-               glLightfv(GL_LIGHT0, GL_POSITION, position);
-               glEnable(GL_LIGHT0);
+               int M = 0, m = 0;
+               if (sscanf(glsl, "%d.%d", &M, &m) == 2)
+                       glsl_version = (M * 100) + m;
+
        }
-#endif
-//     glEnable(GL_BLEND);
-       // Works for the UI !!
-//     glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+       printf("GL_SHADING_LANGUAGE_VERSION %s = %d\n", glsl, glsl_version);
 
-       cam = c3cam_new();
-       cam.lookat = c3vec3f(100.0, 100.0, 0.0);
-    cam.eye = c3vec3f(100.0, -100.0, 100.0);
-    c3cam_update_matrix(&cam);
+       c3gl_fbo_create(&fbo, c3vec2f(_w, _h), (1 << C3GL_FBO_COLOR)|(1 << C3GL_FBO_DEPTH));
+       // shadow buffer
 
-    c3arcball_init_center(&arcball, c3vec2f(_w/2, _h/2), 100);
-//     hd44780_gl_init();
+       c3_driver_list[0] = c3gl_getdriver();
 
     c3 = c3context_new(_w, _h);
-    static const c3driver_context_t * list[] = { &c3context_driver, NULL };
-    c3->driver = list;
+    c3->driver = c3_driver_list;
+
+    c3cam_p cam = &c3context_view_get_at(c3, 0)->cam;
+       cam->lookat = c3vec3f(100.0, 100.0, 0.0);
+       cam->eye = c3vec3f(100.0, -100.0, 100.0);
+       // associate the framebuffer object with this view
+       c3context_view_get_at(c3, 0)->bid = fbo.fbo;
+       /*
+        * Create a light, attach it to a movable object, and attach a sphere
+        * to it too so it's visible.
+        */
+       {
+               c3object_p ligthhook = c3object_new(c3->root);
+           c3transform_p pos = c3transform_new(ligthhook);
 
+           pos->matrix = translation3D(c3vec3f(-30.0f, -30.0f, 200.0f));
+
+               c3light_p light = c3light_new(ligthhook);
+               light->geometry.name = str_new("light0");
+               light->color.specular = c3vec4f(1.0f, 1.0f, 1.0f , 0.8f);
+               light->position = c3vec4f(0, 0, 0, 1.0f );
+
+           {   // light bulb
+               c3geometry_p g = c3sphere_uv(ligthhook, c3vec3f(0, 0, 0), 3, 10, 10);
+               g->mat.color = c3vec4f(1.0, 1.0, 0.0, 1.0);
+               g->hidden = 0;  // hidden from light scenes
+           }
+       }
+       {
+               c3vec2 size = c3vec2f(1024, 1024);
+               c3gl_fbo_create(&shadow, size, (1 << C3GL_FBO_DEPTH_TEX));
+
+               c3context_view_t v = {
+                               .type = C3_CONTEXT_VIEW_LIGHT,
+                               .size = size,
+                               .dirty = 1,
+                               .index = c3->views.count,
+                               .bid = shadow.fbo,
+               };
+               c3cam_init(&v.cam);
+               c3vec3 listpos = c3vec3f(-30.0f, -30.0f, 200.0f);
+               v.cam.eye = listpos;
+               v.cam.lookat = c3vec3f(100.0, 100.0, 0.0);
+               c3context_view_array_add(&c3->views, v);
+       }
+
+    {
+       const char *path = "gfx/hb.png";
+        cairo_surface_t * image = cairo_image_surface_create_from_png (path);
+        printf("image = %p %p\n", image, cairo_image_surface_get_data (image));
+       c3texture_p b = c3texture_new(c3->root);
+
+       c3pixels_p dst = c3pixels_new(
+                       cairo_image_surface_get_width (image),
+                       cairo_image_surface_get_height (image),
+                       4, cairo_image_surface_get_stride(image),
+                       cairo_image_surface_get_data (image));
+               dst->name = str_new(path);
+       dst->normalize = 1;
+       b->geometry.mat.texture = dst;
+       b->size = c3vec2f(200, 200);
+               b->geometry.mat.color = c3vec4f(1.0, 1.0, 1.0, 1.0);
+//         c3transform_new(head);
+    }
+    c3pixels_p brass_tex = NULL;
+    {
+       const char *path = "gfx/brass.png";
+        cairo_surface_t * image = cairo_image_surface_create_from_png (path);
+        printf("image = %p %p\n", image, cairo_image_surface_get_data (image));
+
+       c3pixels_p dst = c3pixels_new(
+                       cairo_image_surface_get_width (image),
+                       cairo_image_surface_get_height (image),
+                       4, cairo_image_surface_get_stride(image),
+                       cairo_image_surface_get_data (image));
+               dst->name = str_new(path);
+       dst->normalize = 1;
+               c3pixels_array_add(&c3->pixels, dst);
+//         c3transform_new(head);
+               brass_tex = dst;
+    }
+    c3pixels_p line_aa_tex = NULL;
+    {
+       const char *path = "gfx/BlurryCircle.png";
+        cairo_surface_t * image = cairo_image_surface_create_from_png (path);
+        printf("image = %p %p\n", image, cairo_image_surface_get_data (image));
+
+#if 0
+       c3pixels_p dst = &b->pixels;
+       c3pixels_init(dst,
+                       cairo_image_surface_get_width (image),
+                       cairo_image_surface_get_height (image),
+                       1, cairo_image_surface_get_width (image),
+                       NULL);
+       c3pixels_alloc(dst);
+       b->size = c3vec2f(32, 32);
+       b->normalized = 1;
+
+       c3pixels_p src = c3pixels_new(
+                       cairo_image_surface_get_width (image),
+                       cairo_image_surface_get_height (image),
+                       4, cairo_image_surface_get_stride(image),
+                       cairo_image_surface_get_data (image));
+
+       uint32_t * _s = (uint32_t *)src->base;
+       uint8_t * _d = (uint8_t *)dst->base;
+       int max = 0;
+       for (int i = 0; i < dst->h * dst->w; i++)
+               if ((_s[i] & 0xff) > max)
+                       max = _s[i] & 0xff;
+       for (int i = 0; i < dst->h * dst->w; i++)
+               *_d++ = ((_s[i] & 0xff) * 255) / max;// + (0xff - max);
+       b->pixels.format = C3PIXEL_A;
+#else
+       c3pixels_p dst = c3pixels_new(
+                       cairo_image_surface_get_width (image),
+                       cairo_image_surface_get_height (image),
+                       4, cairo_image_surface_get_stride(image),
+                       cairo_image_surface_get_data (image));
+       dst->format = C3PIXEL_ARGB;
+       dst->normalize = 1;
+       dst->name = str_new(path);
+       uint8_t * line = dst->base;
+       for (int y = 0; y < dst->h; y++, line += dst->row) {
+               uint32_t *p = (uint32_t *)line;
+               for (int x = 0; x < dst->w; x++, p++) {
+                       uint8_t b = *p;
+                       *p = ((0xff - b) << 24);//|(b << 16)|(b << 8)|(b);
+               }
+       }
+#endif
+       line_aa_tex = dst;
+#if 0
+       c3pixels_p p = dst;
+       printf("struct { int w, h, stride, size, format; uint8_t pix[] } img = {\n"
+                       "%d, %d, %d, %d, %d\n",
+                       p->w, p->h, (int)p->row, p->psize, cairo_image_surface_get_format(image));
+       for (int i = 0; i < 32; i++)
+               printf("0x%08x ", ((uint32_t*)p->base)[i]);
+       printf("\n");
+#endif
+    }
     c3object_p grid = c3object_new(c3->root);
     {
-        for (int x = 0; x < 20; x++) {
-               for (int y = 0; y < 20; y++) {
+        for (int x = 0; x <= 20; x++) {
+               for (int y = 0; y <= 20; y++) {
                        c3vec3 p[4] = {
-                               c3vec3f(-1+x*10,y*10,0), c3vec3f(1+x*10,y*10,0),
-                               c3vec3f(x*10,-1+y*10,0), c3vec3f(x*10,1+y*10,0),
+                               c3vec3f(-1+x*10,y*10,0.01), c3vec3f(1+x*10,y*10,0.01),
+                               c3vec3f(x*10,-1+y*10,0.02), c3vec3f(x*10,1+y*10,0.02),
                        };
                c3geometry_p g = c3geometry_new(
-                               c3geometry_type(C3_RAW_TYPE, GL_LINES), grid);
-               g->mat.color = c3vec4f(0.0, 0.0, 0.0, 1.0);
-                       c3vertex_array_insert(&g->vertice,
-                                       g->vertice.count, p, 4);
+                               c3geometry_type(C3_LINES_TYPE, 0), grid);
+               g->mat.color = c3vec4f(0.0, 0.0, 0.0, 0.8);
+               g->mat.texture = line_aa_tex;
+                       c3lines_init(g, p, 4, 0.2);
                }
         }
     }
+
+   if (0) {
+               c3vec3 p[4] = {
+                       c3vec3f(-5,-5,1), c3vec3f(205,-5,1),
+               };
+       c3geometry_p g = c3geometry_new(
+                       c3geometry_type(C3_LINES_TYPE, 0), grid);
+       g->mat.color = c3vec4f(0.0, 0.0, 0.0, 1.0);
+       g->mat.texture = line_aa_tex;
+       g->line.width = 2;
+
+               c3vertex_array_insert(&g->vertice,
+                               g->vertice.count, p, 2);
+
+    }
     head = c3stl_load("gfx/buserror-nozzle-model.stl", c3->root);
-    //head = c3object_new(c3->root);
     c3transform_new(head);
     if (head->geometry.count > 0) {
+       c3geometry_factor(head->geometry.e[0], 0.1, (20 * M_PI) / 180.0);
        head->geometry.e[0]->mat.color = c3vec4f(0.6, 0.5, 0.0, 1.0);
+       head->geometry.e[0]->mat.texture = brass_tex;
     }
 
 #if 0
@@ -407,6 +598,86 @@ gl_init(
     memset(b->pixels.base, 0xff, 10 * b->pixels.row);
 #endif
 
+
+    hud = c3context_new(_w, _h);
+    hud->driver = c3_driver_list;
+
+    /*
+     * This is the offscreen framebuffer where the 3D scene is drawn
+     */
+    {
+       /*
+        * need to insert a header since there is nothing to detect the version number
+        * reliably without it, and __VERSION__ returns idiocy
+        */
+       char head[128];
+       sprintf(head, "#version %d\n#define GLSL_VERSION %d\n", glsl_version, glsl_version);
+
+       const char *uniforms[] = { "g_Resolution", NULL };
+        fxaa = c3program_new("fxaa", uniforms);
+        c3program_array_add(&hud->programs, fxaa);
+        c3program_load_shader(fxaa, GL_VERTEX_SHADER, head,
+                       "gfx/postproc.vs", C3_PROGRAM_LOAD_UNIFORM);
+        c3program_load_shader(fxaa, GL_FRAGMENT_SHADER, head,
+                       "gfx/postproc.fs", C3_PROGRAM_LOAD_UNIFORM);
+
+        c3texture_p b = c3texture_new(hud->root);
+
+       c3pixels_p dst = c3pixels_new(_w, _h, 4, _w * 4, NULL);
+               dst->name = str_new("fbo");
+               dst->texture = fbo.buffers[C3GL_FBO_COLOR].bid;
+               dst->normalize = 1;
+               dst->dirty = 0;
+       //      dst->trace = 1;
+       b->geometry.mat.texture = dst;
+       b->geometry.mat.program = fxaa;
+       b->size = c3vec2f(_w, _h);
+               b->geometry.mat.color = c3vec4f(1.0, 1.0, 1.0, 1.0);
+               fbo_c3 = b;
+    }
+
+    {
+       /*
+        * need to insert a header since there is nothing to detect the version number
+        * reliably without it, and __VERSION__ returns idiocy
+        */
+       char head[128];
+       sprintf(head, "#version %d\n#define GLSL_VERSION %d\n", glsl_version, glsl_version);
+
+        scene = c3program_new("scene", uniforms_scene);
+        scene->verbose = 1;
+        c3program_array_add(&c3->programs, scene);
+        c3program_load_shader(scene, GL_VERTEX_SHADER, head,
+                       "gfx/scene.vs", C3_PROGRAM_LOAD_UNIFORM);
+        c3program_load_shader(scene, GL_FRAGMENT_SHADER, head,
+                       "gfx/scene.fs", C3_PROGRAM_LOAD_UNIFORM);
+        c3gl_program_load(scene);
+
+               GLCHECK(glUseProgram((GLuint)scene->pid));
+        GLCHECK(glUniform1i(
+                                       (GLuint)scene->params.e[uniform_ShadowMap].pid, 7));
+               GLCHECK(glUniform1i(
+                                       (GLuint)scene->params.e[uniform_tex0].pid, 0));
+               c3vec2 isize = c3vec2f(1.0f / c3->views.e[1].size.x,
+                                       1.0f / c3->views.e[1].size.y);
+               GLCHECK(glUniform2fv(
+                                       (GLuint)scene->params.e[uniform_pixelOffset].pid, 1,
+                                       isize.n));
+               glActiveTexture(GL_TEXTURE7);
+               GLCHECK(glBindTexture(GL_TEXTURE_2D,
+                                       (GLuint)shadow.buffers[C3GL_FBO_DEPTH_TEX].bid));
+               glActiveTexture(GL_TEXTURE0);
+    }
+    {
+               c3vec3 p[4] = {
+                       c3vec3f(10,10,0), c3vec3f(800-10,10,0),
+               };
+       c3geometry_p g = c3geometry_new(
+                       c3geometry_type(C3_LINES_TYPE, 0), hud->root);
+       g->mat.color = c3vec4f(0.5, 0.5, 1.0, .3f);
+       g->mat.texture = line_aa_tex;
+               c3lines_init(g, p, 2, 10);
+    }
        return 1;
 }
 
@@ -414,6 +685,8 @@ void
 gl_dispose()
 {
        c3context_dispose(c3);
+       c3context_dispose(hud);
+       c3gl_fbo_dispose(&fbo);
 }
 
 int