reprap: Added shadow mapping
[simavr] / examples / board_reprap / src / reprap_gl.c
index 12a6cdc..74df728 100644 (file)
 #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;
-c3context_p c3;
-c3context_p hud;
-c3object_p head;
-c3texture_p fbo_c3;
-c3program_p fxaa = NULL;
+
+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;
 
@@ -73,83 +96,6 @@ static int dumpError(const char * what)
 
 #define GLCHECK(_w) {_w; dumpError(#_w);}
 
-/* Global */
-GLuint fbo, fbo_texture, rbo_depth;
-//GLuint vbo_fbo_vertices;
-
-static void
-gl_offscreenInit(
-               int screen_width,
-               int screen_height)
-{
-       /* init_resources */
-       /* Create back-buffer, used for post-processing */
-
-       /* Texture */
-       GLCHECK(glActiveTexture(GL_TEXTURE0));
-       glGenTextures(1, &fbo_texture);
-       glBindTexture(GL_TEXTURE_2D, fbo_texture);
-       glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
-       glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
-       glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
-       glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
-       glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, screen_width, screen_height, 0,
-               GL_RGBA, GL_UNSIGNED_BYTE, NULL);
-       glBindTexture(GL_TEXTURE_2D, 0);
-
-       /* Depth buffer */
-       GLCHECK(glGenRenderbuffers(1, &rbo_depth));
-       glBindRenderbuffer(GL_RENDERBUFFER, rbo_depth);
-       glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, screen_width,
-               screen_height);
-       glBindRenderbuffer(GL_RENDERBUFFER, 0);
-
-       /* Framebuffer to link everything together */
-       GLCHECK(glGenFramebuffers(1, &fbo));
-       glBindFramebuffer(GL_FRAMEBUFFER, fbo);
-       glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
-               fbo_texture, 0);
-       glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
-               GL_RENDERBUFFER, rbo_depth);
-
-       GLenum status;
-       if ((status = glCheckFramebufferStatus(GL_FRAMEBUFFER))
-               != GL_FRAMEBUFFER_COMPLETE) {
-               fprintf(stderr, "glCheckFramebufferStatus: error %d", (int)status);
-               return ;
-       }
-#if 0
-       // Set the list of draw buffers.
-       GLenum DrawBuffers[2] = {GL_COLOR_ATTACHMENT0};
-       glDrawBuffers(1, DrawBuffers); // "1" is the size of DrawBuffers
-       glBindFramebuffer(GL_FRAMEBUFFER, 0);
-#endif
-}
-
-void
-gl_offscreenReshape(
-               int screen_width,
-               int screen_height)
-{
-// Rescale FBO and RBO as well
-       glBindTexture(GL_TEXTURE_2D, fbo_texture);
-       glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, screen_width, screen_height, 0,
-               GL_RGBA, GL_UNSIGNED_BYTE, NULL);
-       glBindTexture(GL_TEXTURE_2D, 0);
-
-       glBindRenderbuffer(GL_RENDERBUFFER, rbo_depth);
-       glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, screen_width,
-               screen_height);
-       glBindRenderbuffer(GL_RENDERBUFFER, 0);
-}
-
-void gl_offscreenFree()
-{
-       /* free_resources */
-       glDeleteRenderbuffers(1, &rbo_depth);
-       glDeleteTextures(1, &fbo_texture);
-       glDeleteFramebuffers(1, &fbo);
-}
 
 static void
 _gl_reshape_cb(int w, int h)
@@ -157,8 +103,20 @@ _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);
-    gl_offscreenReshape(_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();
 }
 
@@ -192,251 +150,12 @@ _gl_key_cb(
        }
 }
 
-static void
-_c3_load_program(
-               c3program_p p)
-{
-       if (!p || p->pid || p->log)
-               return;
-
-       printf("%s loading %s\n", __func__, p->name->str);
-       for (int si = 0; si < p->shaders.count && !p->log; si++) {
-               c3shader_p s = &p->shaders.e[si];
-
-               printf("%s compiling shader %s\n", __func__, s->name->str);
-
-               s->sid = glCreateShader(s->type);
-               const GLchar * pgm = s->shader->str;
-               glShaderSource(s->sid, 1, &pgm, NULL);
-
-               glCompileShader(s->sid);
-
-               GLint status;
-               glGetShaderiv(s->sid, GL_COMPILE_STATUS, &status);
-
-               if (status != GL_FALSE)
-                       continue;
-
-               GLint infoLogLength;
-               glGetShaderiv(s->sid, GL_INFO_LOG_LENGTH, &infoLogLength);
-
-               p->log = str_alloc(infoLogLength);
-               glGetShaderInfoLog(s->sid, infoLogLength, NULL, p->log->str);
-
-               fprintf(stderr, "%s compile %s: %s\n", __func__, s->name->str, p->log->str);
-               break;
-       }
-       if (p->log)
-               return;
-    p->pid = glCreateProgram();
-
-       for (int si = 0; si < p->shaders.count && !p->log; si++) {
-               c3shader_p s = &p->shaders.e[si];
-
-       glAttachShader(p->pid, s->sid);
-       }
-    glLinkProgram(p->pid);
-
-    GLint status;
-    glGetProgramiv (p->pid, GL_LINK_STATUS, &status);
-
-       for (int si = 0; si < p->shaders.count && !p->log; si++) {
-               c3shader_p s = &p->shaders.e[si];
-
-               glDetachShader(p->pid, s->sid);
-               glDeleteShader(s->sid);
-       s->sid = 0;
-       }
-
-    if (status == GL_FALSE) {
-        GLint infoLogLength;
-        glGetProgramiv(p->pid, GL_INFO_LOG_LENGTH, &infoLogLength);
-
-               p->log = str_alloc(infoLogLength);
-
-        glGetProgramInfoLog(p->pid, infoLogLength, NULL, p->log->str);
-               fprintf(stderr, "%s link %s: %s\n", __func__, p->name->str, p->log->str);
-
-               goto error;
-    }
-    for (int pi = 0; pi < p->params.count; pi++) {
-       c3program_param_p pa = &p->params.e[pi];
-       pa->pid = glGetUniformLocation(p->pid, pa->name->str);
-       if (pa->pid == -1) {
-               fprintf(stderr, "%s %s: parameter '%s' not found\n",
-                               __func__, p->name->str, pa->name->str);
-       }
-    }
-
-    c3program_purge(p);
-    return;
-error:
-c3program_purge(p);
-       if (p->pid)
-               glDeleteProgram(p->pid);
-       p->pid = 0;
-}
-
-static void
-_c3_load_pixels(
-               c3pixels_p pix)
-{
-       GLuint mode = pix->normalize ? GL_TEXTURE_2D : GL_TEXTURE_RECTANGLE_ARB;
-       if (!pix->texture) {
-               printf("Creating texture %s %dx%d\n", pix->name ? pix->name->str : "", pix->w, pix->h);
-               pix->dirty = 1;
-               GLuint texID = 0;
-               dumpError("cp_gl_texture_load_argb flush");
-               GLCHECK(glEnable(mode));
-
-               glGenTextures(1, &texID);
-//             glTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE,
-//                             GL_MODULATE); //set texture environment parameters
-//             dumpError("glTexEnvf");
-
-               glPixelStorei(GL_UNPACK_ROW_LENGTH, pix->row / pix->psize);
-               glTexParameteri(mode, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
-               dumpError("GL_TEXTURE_MAG_FILTER");//
-               glTexParameteri(mode, GL_TEXTURE_MIN_FILTER,
-                               pix->normalize ? GL_LINEAR_MIPMAP_LINEAR : GL_LINEAR);
-               dumpError("GL_TEXTURE_MIN_FILTER");
-               glTexParameteri(mode, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
-               dumpError("GL_TEXTURE_WRAP_S");
-               glTexParameteri(mode, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
-               dumpError("GL_TEXTURE_WRAP_T");
-               if (pix->normalize)
-                       GLCHECK(glTexParameteri(mode, GL_GENERATE_MIPMAP, GL_TRUE));
-       #if 1
-               GLfloat fLargest;
-               glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &fLargest);
-               //printf("fLargest = %f\n", fLargest);
-               GLCHECK(glTexParameterf(mode, GL_TEXTURE_MAX_ANISOTROPY_EXT, fLargest));
-       #endif
-               if (pix->normalize)
-                       GLCHECK(glGenerateMipmap(mode));
-
-               pix->texture = texID;
-               pix->dirty = 1;
-       }
-       if (pix->dirty) {
-               pix->dirty = 0;
-               GLCHECK(glBindTexture(mode, pix->texture));
-               glTexImage2D(mode, 0,
-                               pix->format == C3PIXEL_A ? GL_ALPHA16 : GL_RGBA8,
-                               pix->w, pix->h, 0,
-                               pix->format == C3PIXEL_A ? GL_ALPHA : GL_BGRA,
-                               GL_UNSIGNED_BYTE,
-                               pix->base);
-               dumpError("glTexImage2D");
-               if (pix->normalize)
-                       GLCHECK(glGenerateMipmap(mode));
-       }
-}
-
-static void
-_c3_geometry_project(
-               c3context_p c,
-               const struct c3driver_context_t * d,
-               c3geometry_p g,
-               c3mat4p m)
-{
-       if (g->mat.texture) {
-//             printf("_c3_geometry_project xrure %d!\n", g->textures.count);
-               _c3_load_pixels(g->mat.texture);
-       }
-       if (g->mat.program) {
-               _c3_load_program(g->mat.program);
-       }
-
-       switch(g->type.type) {
-               case C3_TRIANGLE_TYPE:
-                       g->type.subtype = GL_TRIANGLES;
-                       break;
-               case C3_TEXTURE_TYPE: {
-               //      c3texture_p t = (c3texture_p)g;
-                       if (g->mat.texture) {
-                               g->type.subtype = GL_TRIANGLE_FAN;
-                       }
-               }       break;
-               case C3_LINES_TYPE:
-                       g->type.subtype = GL_TRIANGLES;
-                       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);
-       dumpError("glColor");
-//     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);
-       dumpError("GL_VERTEX_ARRAY");
-       glDisable(GL_TEXTURE_2D);
-       if (g->mat.texture) {
-               GLuint mode = g->mat.texture->normalize ? GL_TEXTURE_2D : GL_TEXTURE_RECTANGLE_ARB;
-               glEnable(mode);
-               if (g->mat.texture->trace)
-                       printf("%s uses texture %s (%d tex)\n",
-                                       __func__, g->mat.texture->name->str, g->textures.count);
-       //      printf("tex mode %d texture %d\n", g->mat.mode, g->mat.texture);
-               dumpError("glEnable texture");
-               glBindTexture(mode, g->mat.texture->texture);
-               dumpError("glBindTexture");
-               glTexCoordPointer(2, GL_FLOAT, 0, g->textures.e);
-               glEnableClientState(GL_TEXTURE_COORD_ARRAY);
-               dumpError("GL_TEXTURE_COORD_ARRAY");
-       }
-       if (g->mat.program) {
-               glUseProgram(g->mat.program->pid);
-               dumpError("glUseProgram program_postproc");
-       }
-       if (g->normals.count) {
-               glNormalPointer(GL_FLOAT, 0, g->normals.e);
-               glEnableClientState(GL_NORMAL_ARRAY);
-       }
-       glDrawArrays(g->type.subtype, 0,
-                       g->projected.count ? g->projected.count : g->vertice.count);
-       glDisableClientState(GL_VERTEX_ARRAY);
-       glDisableClientState(GL_TEXTURE_COORD_ARRAY);
-       glDisableClientState(GL_NORMAL_ARRAY);
-       if (g->mat.texture)
-               glDisable(g->mat.texture->normalize ? GL_TEXTURE_2D : GL_TEXTURE_RECTANGLE_ARB);
-       if (g->mat.program)
-               glUseProgram(0);
-}
-
-const c3driver_context_t c3context_driver = {
-               .geometry_project = _c3_geometry_project,
-               .geometry_draw = _c3_geometry_draw,
-};
-
-#define FBO 1
-
 static void
 _gl_display_cb(void)           /* function called whenever redisplay needed */
 {
-#if FBO
-       /*
-        * Draw in FBO object
-        */
-       glBindFramebuffer(GL_FRAMEBUFFER, fbo);
-       // draw (without glutSwapBuffers)
-       dumpError("glBindFramebuffer fbo");
-       glViewport(0, 0, _w, _h);
+       int drawIndexes[] = { 1, 0 };
+       int drawViewStart = c3->root->dirty ? 0 : 1;
 
-#else
-       glBindFramebuffer(GL_FRAMEBUFFER, 0);
-#endif
-
-       c3context_view_set(c3, 0);
        c3vec3 headp = c3vec3f(
                        stepper_get_position_mm(&reprap.step_x),
                        stepper_get_position_mm(&reprap.step_y),
@@ -444,79 +163,106 @@ _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 head %.2f,%.2f,%.2f\n", headp.x, headp.y,headp.z);
-               c3context_project(c3);
-       }
-       float z_min = c3context_view_get(c3)->z.min,
-                       z_max = c3context_view_get(c3)->z.max;
-       if (z_min < 0)
-               z_min = 10;
-       z_min = 10;
-       if (z_max < z_min || z_max > 1000)
-               z_max = 1000;
-
-       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(50, (float)_w / (float)_h, z_min, z_max);
-#if 0
-       glCullFace(GL_BACK);
-       glEnable(GL_CULL_FACE);
-#endif
-       glDepthMask(GL_TRUE);
-       glDepthFunc(GL_LEQUAL);
-       glEnable(GL_DEPTH_TEST);
-       glEnable(GL_LIGHTING);
-//     glPolygonMode( GL_FRONT_AND_BACK, GL_LINE );
-
-       glEnable(GL_ALPHA_TEST);
-       glAlphaFunc(GL_GREATER, 1.0f / 255.0f);
-       glEnable(GL_BLEND); // Enable Blending
-       glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); // Type Of Blending To Use
-
-       glMatrixMode(GL_MODELVIEW);
-       glLoadIdentity();
+       for (int vi = drawViewStart; vi < 2; vi++) {
+               c3context_view_set(c3, drawIndexes[vi]);
 
-       glMultMatrixf(c3context_view_get(c3)->cam.mtx.n);
-       glTranslatef(-c3context_view_get(c3)->cam.eye.n[VX],
-                       -c3context_view_get(c3)->cam.eye.n[VY],
-                       -c3context_view_get(c3)->cam.eye.n[VZ]);
+               /*
+                * 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);
 
-       dumpError("flush");
+               c3context_project(c3);
 
-       c3context_draw(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);
+       }
 
-#if FBO
        /*
         * 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);
-#endif
+
        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
-       glLoadIdentity(); // Start with an identity matrix
 
-       if (hud)
-               c3context_draw(hud);
+       if (hud->root->dirty) {
+       //      printf("reproject head %.2f,%.2f,%.2f\n", headp.x, headp.y,headp.z);
+               c3context_project(hud);
+       }
+       c3context_draw(hud);
 
     glutSwapBuffers();
 }
@@ -605,6 +351,8 @@ _gl_timer_cb(
        glutPostRedisplay();
 }
 
+const c3driver_context_t * c3_driver_list[3] = { NULL, NULL };
+
 int
 gl_init(
                int argc,
@@ -626,40 +374,26 @@ gl_init(
 
        glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
        glHint(GL_GENERATE_MIPMAP_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);
-        */
+
        // enable color tracking
        glEnable(GL_COLOR_MATERIAL);
        // set material properties which will be assigned by glColor
        glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE);
 
        /* setup some lights */
-       glShadeModel(GL_SMOOTH);
-       glEnable(GL_LIGHTING);
        GLfloat global_ambient[] = { 0.5f, 0.5f, 0.5f, 1.0f };
        glLightModelfv(GL_LIGHT_MODEL_AMBIENT, global_ambient);
 
-       {
-               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);
-       }
-       {
+       if (0) {
                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);
+               glLightfv(GL_LIGHT1, GL_SPECULAR, specular);
+               glLightfv(GL_LIGHT1, GL_POSITION, position);
+               glEnable(GL_LIGHT1);
        }
 
        /*
-        * Extract the GLSL version as a nuneric value for later
+        * Extract the GLSL version as a numeric value for later
         */
        const char * glsl = (const char *)glGetString(GL_SHADING_LANGUAGE_VERSION);
        {
@@ -670,16 +404,57 @@ gl_init(
        }
        printf("GL_SHADING_LANGUAGE_VERSION %s = %d\n", glsl, glsl_version);
 
-       gl_offscreenInit(_w, _h);
-       //gl_ppProgram();
+       c3gl_fbo_create(&fbo, c3vec2f(_w, _h), (1 << C3GL_FBO_COLOR)|(1 << C3GL_FBO_DEPTH));
+       // shadow buffer
+
+       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";
@@ -693,11 +468,29 @@ gl_init(
                        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";
@@ -749,7 +542,7 @@ gl_init(
        }
 #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",
@@ -757,6 +550,7 @@ gl_init(
        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);
     {
@@ -790,10 +584,11 @@ gl_init(
 
     }
     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
@@ -805,12 +600,12 @@ gl_init(
 
 
     hud = c3context_new(_w, _h);
-    hud->driver = list;
+    hud->driver = c3_driver_list;
 
     /*
      * This is the offscreen framebuffer where the 3D scene is drawn
      */
-    if (FBO) {
+    {
        /*
         * need to insert a header since there is nothing to detect the version number
         * reliably without it, and __VERSION__ returns idiocy
@@ -818,7 +613,8 @@ gl_init(
        char head[128];
        sprintf(head, "#version %d\n#define GLSL_VERSION %d\n", glsl_version, glsl_version);
 
-        fxaa = c3program_new("fxaa");
+       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);
@@ -829,7 +625,7 @@ gl_init(
 
        c3pixels_p dst = c3pixels_new(_w, _h, 4, _w * 4, NULL);
                dst->name = str_new("fbo");
-               dst->texture = fbo_texture;
+               dst->texture = fbo.buffers[C3GL_FBO_COLOR].bid;
                dst->normalize = 1;
                dst->dirty = 0;
        //      dst->trace = 1;
@@ -840,6 +636,38 @@ gl_init(
                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),
@@ -857,6 +685,8 @@ void
 gl_dispose()
 {
        c3context_dispose(c3);
+       c3context_dispose(hud);
+       c3gl_fbo_dispose(&fbo);
 }
 
 int