Commit 8afc0af666a8ca83db318c132a44e57afc40b50a
authorMichel Pollet <buserror@gmail.com>
Sun, 3 Jun 2012 14:11:49 +0000 (15:11 +0100)
committerMichel Pollet <buserror@gmail.com>
Sun, 3 Jun 2012 14:11:49 +0000 (15:11 +0100)
c3context can have several viewpoints
c3context has a list of c3programs
c3camera got renamed with standard type names
c3context/c3geometry driver got a dispose callback

gl code has a new generic glsl program loader

Signed-off-by: Michel Pollet <buserror@gmail.com>
8 files changed:
examples/board_reprap/src/reprap_gl.c
examples/shared/libc3/src/c3camera.c
examples/shared/libc3/src/c3camera.h
examples/shared/libc3/src/c3context.c
examples/shared/libc3/src/c3context.h
examples/shared/libc3/src/c3driver_context.h
examples/shared/libc3/src/c3geometry.c
examples/shared/libc3/src/c3geometry.h

index 48e43ca23d28fc62454acb404027f58c3302d33b..12a6cdcd22e36adb08606da5495fd5eb01593d17 100644 (file)
@@ -42,6 +42,7 @@
 #include "c3driver_context.h"
 #include "c3stl.h"
 #include "c3lines.h"
+#include "c3program.h"
 
 #include <cairo/cairo.h>
 
@@ -53,6 +54,7 @@ c3context_p c3;
 c3context_p hud;
 c3object_p head;
 c3texture_p fbo_c3;
+c3program_p fxaa = NULL;
 
 int glsl_version = 110;
 
@@ -71,26 +73,6 @@ static int dumpError(const char * what)
 
 #define GLCHECK(_w) {_w; dumpError(#_w);}
 
-void print_log(GLuint obj)
-{
-       int infologLength = 0;
-       int maxLength;
-
-       if(glIsShader(obj))
-               glGetShaderiv(obj,GL_INFO_LOG_LENGTH,&maxLength);
-       else
-               glGetProgramiv(obj,GL_INFO_LOG_LENGTH,&maxLength);
-
-       char infoLog[maxLength];
-
-       if (glIsShader(obj))
-               glGetShaderInfoLog(obj, maxLength, &infologLength, infoLog);
-       else
-               glGetProgramInfoLog(obj, maxLength, &infologLength, infoLog);
-
-       if (infologLength > 0)
-               printf("%s\n",infoLog);
-}
 /* Global */
 GLuint fbo, fbo_texture, rbo_depth;
 //GLuint vbo_fbo_vertices;
@@ -159,10 +141,6 @@ gl_offscreenReshape(
        glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, screen_width,
                screen_height);
        glBindRenderbuffer(GL_RENDERBUFFER, 0);
-
-//     glBindFramebuffer(GL_FRAMEBUFFER, fbo);
-//    glViewport(0, 0, screen_width, screen_height);
-//     glBindFramebuffer(GL_FRAMEBUFFER, 0);
 }
 
 void gl_offscreenFree()
@@ -171,93 +149,6 @@ void gl_offscreenFree()
        glDeleteRenderbuffers(1, &rbo_depth);
        glDeleteTextures(1, &fbo_texture);
        glDeleteFramebuffers(1, &fbo);
-//       glDeleteBuffers(1, &vbo_fbo_vertices);
-}
-
-GLuint program_postproc = 0, uniform_fbo_texture;
-
-static GLuint create_shader(const char * fname, GLuint pid)
-{
-       const GLchar * buf;
-
-       FILE *f = fopen(fname, "r");
-       if (!f) {
-               perror(fname);
-               return 0;
-       }
-       fseek(f, 0, SEEK_END);
-       long fs = ftell(f);
-       fseek(f, 0, SEEK_SET);
-       /*
-        * 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 int header = strlen(head);
-       buf = malloc(header + fs + 1);
-       memcpy((void*)buf, head, header);
-       fread((void*)buf + header, 1, fs, f);
-       ((char*)buf)[header + fs] = 0;
-       fclose(f);
-
-       GLuint vs = glCreateShader(pid);
-       glShaderSource(vs, 1, &buf, NULL);
-       glCompileShader(vs);
-       dumpError("glCompileShader");
-       print_log(vs);
-       free((void*)buf);
-       return vs;
-}
-
-
-int gl_ppProgram()
-{
-       int vs, fs;
-       int link_ok, validate_ok;
-       /* init_resources */
-       /* Post-processing */
-       if ((vs = create_shader("gfx/postproc.vs", GL_VERTEX_SHADER)) == 0)
-               return 0;
-       if ((fs = create_shader("gfx/postproc.fs", GL_FRAGMENT_SHADER)) == 0)
-               return 0;
-
-       program_postproc = glCreateProgram();
-       glAttachShader(program_postproc, vs);
-       glAttachShader(program_postproc, fs);
-       glLinkProgram(program_postproc);
-       glGetProgramiv(program_postproc, GL_LINK_STATUS, &link_ok);
-       if (!link_ok) {
-               fprintf(stderr, "glLinkProgram:");
-               goto error;
-       }
-       glValidateProgram(program_postproc);
-       glGetProgramiv(program_postproc, GL_VALIDATE_STATUS, &validate_ok);
-       if (!validate_ok) {
-               fprintf(stderr, "glValidateProgram:");
-               goto error;
-       }
-
-       char * uniform_name = "m_Texture";
-       uniform_fbo_texture = glGetUniformLocation(program_postproc, uniform_name);
-       if (uniform_fbo_texture == -1) {
-               fprintf(stderr, "Could not bind uniform %s\n", uniform_name);
-               goto error;
-       }
-       return 0;
-error:
-       print_log(program_postproc);
-       glDeleteProgram(program_postproc);
-       program_postproc = 0;
-       return -1;
-}
-
-void
-gl_ppFree()
-{
-       if (program_postproc)
-               glDeleteProgram(program_postproc);
-       program_postproc = 0;
 }
 
 static void
@@ -292,15 +183,100 @@ _gl_key_cb(
                //      avr_vcd_stop(&vcd_file);
                        break;
                case '1':
-                       if (fbo_c3->geometry.mat.program.pid)
-                               fbo_c3->geometry.mat.program.pid = 0;
+                       if (fbo_c3->geometry.mat.program)
+                               fbo_c3->geometry.mat.program = NULL;
                        else
-                               fbo_c3->geometry.mat.program.pid = program_postproc;
+                               fbo_c3->geometry.mat.program = fxaa;
                        glutPostRedisplay();
                        break;
        }
 }
 
+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)
@@ -368,6 +344,9 @@ _c3_geometry_project(
 //             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:
@@ -415,8 +394,8 @@ _c3_geometry_draw(
                glEnableClientState(GL_TEXTURE_COORD_ARRAY);
                dumpError("GL_TEXTURE_COORD_ARRAY");
        }
-       if (g->mat.program.pid) {
-               glUseProgram(g->mat.program.pid);
+       if (g->mat.program) {
+               glUseProgram(g->mat.program->pid);
                dumpError("glUseProgram program_postproc");
        }
        if (g->normals.count) {
@@ -430,7 +409,7 @@ _c3_geometry_draw(
        glDisableClientState(GL_NORMAL_ARRAY);
        if (g->mat.texture)
                glDisable(g->mat.texture->normalize ? GL_TEXTURE_2D : GL_TEXTURE_RECTANGLE_ARB);
-       if (g->mat.program.pid)
+       if (g->mat.program)
                glUseProgram(0);
 }
 
@@ -439,39 +418,6 @@ const c3driver_context_t c3context_driver = {
                .geometry_draw = _c3_geometry_draw,
 };
 
-float z_min, z_max;
-/*
- * 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, c3->cam.eye));
-       c3f d2 = c3vec3_length2(c3vec3_sub(c2, c3->cam.eye));
-
-       if (d1 > z_max) z_max = d1;
-       if (d1 < z_min) z_min = d1;
-       if (d2 > z_max) z_max = d2;
-       if (d2 < z_min) z_min = d2;
-       /*
-        * 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;
-}
-
 #define FBO 1
 
 static void
@@ -490,6 +436,7 @@ _gl_display_cb(void)                /* function called whenever redisplay needed */
        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),
@@ -500,22 +447,14 @@ _gl_display_cb(void)              /* function called whenever redisplay needed */
        if (c3->root->dirty) {
        //      printf("reproject head %.2f,%.2f,%.2f\n", headp.x, headp.y,headp.z);
                c3context_project(c3);
-
-               z_min = 1000000000;
-               z_max = -1000000000;
-               qsort(c3->projected.e, c3->projected.count, sizeof(c3->projected.e[0]),
-                       _c3_z_sorter);
-               z_min = sqrt(z_min);
-               z_max = sqrt(z_max);
-               //      printf("z_min %f, z_max %f\n", z_min, z_max);
-               //z_min -= 50;
-               if (z_min < 0)
-                       z_min = 10;
-               z_min = 10;
-               if (z_max < z_min || z_max > 1000)
-                       z_max = 1000;
        }
-
+       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);
@@ -542,8 +481,11 @@ _gl_display_cb(void)               /* function called whenever redisplay needed */
 
        glMatrixMode(GL_MODELVIEW);
        glLoadIdentity();
-       glMultMatrixf(c3->cam.mtx.n);
-       glTranslatef(-c3->cam.eye.n[VX], -c3->cam.eye.n[VY], -c3->cam.eye.n[VZ]);
+
+       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]);
 
        dumpError("flush");
 
@@ -597,6 +539,7 @@ void _gl_button_cb(
 {
        button = s == GLUT_DOWN ? b : 0;
        move = c3vec2f(x, y);
+       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:
@@ -604,11 +547,12 @@ void _gl_button_cb(
                        break;
                case GLUT_WHEEL_UP:
                case GLUT_WHEEL_DOWN:
-                       if (c3->cam.distance > 10) {
+                       if (view->cam.distance > 10) {
                                const float d = 0.004;
-                               c3cam_set_distance(&c3->cam, c3->cam.distance * ((b == GLUT_WHEEL_DOWN) ? (1.0+d) : (1.0-d)));
-                               c3cam_update_matrix(&c3->cam);
-                               c3->root->dirty = 1;    // resort the array
+                               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;
        }
@@ -621,29 +565,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 delta %.1f,%.1f\n",
 //                     __func__, button, move.n[0], move.n[1], x, y, delta.x, delta.y);
 
        switch (button) {
                case GLUT_LEFT_BUTTON: {
-                       c3mat4 rotx = rotation3D(c3->cam.side, 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(&c3->cam, &rotx);
+                       c3cam_rot_about_lookat(&view->cam, &rotx);
+                       c3cam_update_matrix(&view->cam);
 
-                   c3cam_update_matrix(&c3->cam);
-                   c3->root->dirty = 1;        // resort the array
+                       view->dirty = 1;        // resort the array
                }       break;
                case GLUT_RIGHT_BUTTON: {
                        // offset both points, but following the plane
-                       c3vec3 f = c3vec3_mulf(c3vec3f(-c3->cam.side.y, c3->cam.side.x, 0), -delta.n[1] / 4);
-                       c3->cam.eye = c3vec3_add(c3->cam.eye, f);
-                       c3->cam.lookat = c3vec3_add(c3->cam.lookat, f);
-                       c3cam_movef(&c3->cam, delta.n[0] / 8, 0, 0);
-
-                   c3cam_update_matrix(&c3->cam);
-                   c3->root->dirty = 1;        // resort the array
+                       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;
@@ -724,15 +671,15 @@ gl_init(
        printf("GL_SHADING_LANGUAGE_VERSION %s = %d\n", glsl, glsl_version);
 
        gl_offscreenInit(_w, _h);
-       gl_ppProgram();
+       //gl_ppProgram();
 
     c3 = c3context_new(_w, _h);
     static const c3driver_context_t * list[] = { &c3context_driver, NULL };
     c3->driver = list;
 
-       c3->cam.lookat = c3vec3f(100.0, 100.0, 0.0);
-       c3->cam.eye = c3vec3f(100.0, -100.0, 100.0);
-    c3cam_update_matrix(&c3->cam);
+    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);
 
     {
        const char *path = "gfx/hb.png";
@@ -859,11 +806,26 @@ gl_init(
 
     hud = c3context_new(_w, _h);
     hud->driver = list;
+
     /*
      * This is the offscreen framebuffer where the 3D scene is drawn
      */
     if (FBO) {
-       c3texture_p b = c3texture_new(hud->root);
+       /*
+        * 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);
+
+        fxaa = c3program_new("fxaa");
+        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");
@@ -872,7 +834,7 @@ gl_init(
                dst->dirty = 0;
        //      dst->trace = 1;
        b->geometry.mat.texture = dst;
-       b->geometry.mat.program.pid = program_postproc;
+       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;
index 8e5fef1ec061076138ba15044a0e91e52ac902ad..29f98444591a94a27d7da232f258c6a8863e4786 100644 (file)
@@ -26,7 +26,7 @@
 
 void
 c3cam_set_distance(
-               c3camp c,
+               c3cam_p c,
                const c3f new_distance)
 {
     if ( new_distance <= 0.0 )  /* Distance has to be positive */
@@ -46,7 +46,7 @@ c3cam_set_distance(
 
 void
 c3cam_set_upv(
-               c3camp c,
+               c3cam_p c,
                const c3vec3 new_up)
 {
     c->up = new_up;
@@ -55,7 +55,7 @@ c3cam_set_upv(
 
 void
 c3cam_set_upf(
-               c3camp c,
+               c3cam_p c,
                const c3f x,
                const c3f y,
                const c3f z)
@@ -65,7 +65,7 @@ c3cam_set_upf(
 
 void
 c3cam_set_eyev(
-               c3camp c,
+               c3cam_p c,
                const c3vec3 new_eye)
 {
     c->eye = new_eye;
@@ -74,7 +74,7 @@ c3cam_set_eyev(
 
 void
 c3cam_set_eyef(
-               c3camp c,
+               c3cam_p c,
                const c3f x,
                const c3f y,
                const c3f z)
@@ -84,7 +84,7 @@ c3cam_set_eyef(
 
 void
 c3cam_set_lookatv(
-               c3camp c,
+               c3cam_p c,
                const c3vec3 new_lookat)
 {
     c->lookat = new_lookat;
@@ -93,7 +93,7 @@ c3cam_set_lookatv(
 
 void
 c3cam_set_lookatf(
-               c3camp c,
+               c3cam_p c,
                const c3f x,
                const c3f y,
                const c3f z)
@@ -104,7 +104,7 @@ c3cam_set_lookatf(
 
 void
 c3cam_roll(
-               c3camp c,
+               c3cam_p c,
                const c3f angle)
 {
     c3mat4 rot = rotation3D(c->forward, angle );
@@ -114,7 +114,7 @@ c3cam_roll(
 
 void
 c3cam_eye_yaw(
-               c3camp c,
+               c3cam_p c,
                const c3f angle)
 {
     c3vec3 eye_pt = c3vec3_sub(c->eye, c->lookat); /* eye w/lookat at center */
@@ -128,7 +128,7 @@ c3cam_eye_yaw(
 
 void
 c3cam_eye_yaw_abs(
-               c3camp c,
+               c3cam_p c,
                const c3f angle,
                const c3vec3 axis)
 {
@@ -146,7 +146,7 @@ c3cam_eye_yaw_abs(
 
 void
 c3cam_eye_pitch(
-               c3camp c,
+               c3cam_p c,
                const c3f angle)
 {
     c3vec3 eye_pt = c3vec3_sub(c->eye, c->lookat); /* eye w/lookat at center */
@@ -162,7 +162,7 @@ c3cam_eye_pitch(
 
 void
 c3cam_lookat_yaw(
-               c3camp c,
+               c3cam_p c,
                const c3f angle)
 {
     c3vec3 lookat_pt = c3vec3_sub(c->lookat, c->eye); /* lookat w/eye at center */
@@ -176,7 +176,7 @@ c3cam_lookat_yaw(
 
 void
 c3cam_lookat_pitch(
-               c3camp c,
+               c3cam_p c,
                const c3f angle)
 {
     c3vec3 lookat_pt = c3vec3_sub(c->lookat, c->eye); /* lookat w/eye at center */
@@ -192,7 +192,7 @@ c3cam_lookat_pitch(
 
 void
 c3cam_reset_up_axis(
-               c3camp c,
+               c3cam_p c,
                const int axis_num)
 {
     c3vec3 eye_pt = c3vec3_sub(c->lookat, c->eye); /* eye w/lookat at center */
@@ -213,14 +213,14 @@ c3cam_reset_up_axis(
 
 void
 c3cam_reset_up(
-               c3camp c)
+               c3cam_p c)
 {
        c3cam_reset_up_axis(c, VY ); /* Resets to the Y axis */
 }
 
 void
 c3cam_movef(
-               c3camp c,
+               c3cam_p c,
                const c3f side_move,
                const c3f up_move,
                const c3f forw_move)
@@ -236,7 +236,7 @@ c3cam_movef(
 
 void
 c3cam_movev(
-               c3camp c,
+               c3cam_p c,
                const c3vec3 v) /* A vector version of the above command */
 {
        c3cam_movef(c, v.n[VX], v.n[VY], v.n[VZ] );
@@ -244,7 +244,7 @@ c3cam_movev(
 
 void
 c3cam_move_by_eye(
-               c3camp c,
+               c3cam_p c,
                const c3vec3 new_eye)
 {
     c3vec3 diff = c3vec3_sub(new_eye, c->eye);
@@ -257,7 +257,7 @@ c3cam_move_by_eye(
 
 void
 c3cam_move_by_lookat(
-               c3camp c,
+               c3cam_p c,
                const c3vec3 new_lookat)
 {
     c3vec3 diff = c3vec3_sub(new_lookat, c->lookat);
@@ -270,7 +270,7 @@ c3cam_move_by_lookat(
 
 void
 c3cam_move_abs(
-               c3camp c,
+               c3cam_p c,
                const c3vec3 v)
 {
     c->lookat = c3vec3_add(c->lookat, v);
@@ -281,7 +281,7 @@ c3cam_move_abs(
 
 void
 c3cam_rot_about_eye(
-               c3camp c,
+               c3cam_p c,
                const c3mat4p rot)
 {
     c3vec3  view = c3vec3_sub(c->lookat, c->eye);
@@ -296,7 +296,7 @@ c3cam_rot_about_eye(
 
 void
 c3cam_rot_about_lookat(
-               c3camp c,
+               c3cam_p c,
                const c3mat4p rot)
 {
     // NOT QUITE RIGHT YET
@@ -313,7 +313,7 @@ c3cam_rot_about_lookat(
 
 void
 c3cam_update_matrix(
-               c3camp c)
+               c3cam_p c)
 {
     c3cam_update(c);
 
@@ -325,7 +325,7 @@ c3cam_update_matrix(
 }
 #if 0
 void
-c3cam_load_to_openGL(c3camp c)
+c3cam_load_to_openGL(c3cam_p c)
 {
     c3mat4  m;
 
@@ -338,7 +338,7 @@ c3cam_load_to_openGL(c3camp c)
 }
 
 void
-c3cam_load_to_openGL_noident(c3camp c)
+c3cam_load_to_openGL_noident(c3cam_p c)
 {
     c3mat4  m;
 
@@ -352,8 +352,9 @@ c3cam_load_to_openGL_noident(c3camp c)
 
 void
 c3cam_reset(
-               c3camp c)
+               c3cam_p c)
 {
+       memset(c, 0, sizeof(*c));
     c->up = c3vec3f( 0.0, 1.0, 0.0 );
     c->eye = c3vec3f(0.0, 0.0, 10.0);
     c->lookat = c3vec3f(0.0,0.0,0.0);
@@ -363,17 +364,24 @@ c3cam_reset(
     c3cam_update(c);
 }
 
-c3cam
+c3cam_t
 c3cam_new()
 {
-       c3cam c;
+       c3cam_t c;
        c3cam_reset(&c);
        return c;
 }
 
+void
+c3cam_init(
+               c3cam_p c)
+{
+       c3cam_reset(&c);
+}
+
 void
 c3cam_update(
-               c3camp c)
+               c3cam_p c)
 {
        /* get proper side and forward vectors, and distance  */
        c->forward = c3vec3_minus(c3vec3_sub(c->lookat, c->eye));
@@ -390,7 +398,7 @@ c3cam_update(
 
 # if 0
 void
-c3cam_dump(c3camp c, FILE *output) const
+c3cam_dump(c3cam_p c, FILE *output) const
 {
     fprintf( output, "Viewmodel: \n" );
     eye.print(    output, "  eye"    );
index 1bfc66ccd5e7231551f6c8b2922a2d2a536d483f..9342e586c517db4dcd7cbc848eaf77023a4e30bf 100644 (file)
 
 #include "c3algebra.h"
 
-typedef struct c3cam {
+typedef struct c3cam_t {
        c3vec3 eye, lookat;
        c3vec3 up, side, forward;
        c3mat4 mtx;
        c3f distance;
-} c3cam, *c3camp;
+} c3cam_t, *c3cam_p;
 
 /******************************* set_distance() ***********/
 /* This readjusts the distance from the eye to the lookat */
@@ -38,17 +38,17 @@ typedef struct c3cam {
 /* The lookat point is unaffected                         */
 void
 c3cam_set_distance(
-               c3camp c,
+               c3cam_p c,
                const c3f new_distance);
 
 /******************************* set_up() ***************/
 void
 c3cam_set_upv(
-               c3camp c,
+               c3cam_p c,
                const c3vec3 new_up);
 void
 c3cam_set_upf(
-               c3camp c,
+               c3cam_p c,
                const c3f x,
                const c3f y,
                const c3f z);
@@ -56,11 +56,11 @@ c3cam_set_upf(
 /******************************* set_eye() ***************/
 void
 c3cam_set_eyev(
-               c3camp c,
+               c3cam_p c,
                const c3vec3 new_eye);
 void
 c3cam_set_eyef(
-               c3camp c,
+               c3cam_p c,
                const c3f x,
                const c3f y,
                const c3f z);
@@ -68,11 +68,11 @@ c3cam_set_eyef(
 /******************************* set_lookat() ***************/
 void
 c3cam_set_lookatv(
-               c3camp c,
+               c3cam_p c,
                const c3vec3 new_lookat);
 void
 c3cam_set_lookatf(
-               c3camp c,
+               c3cam_p c,
                const c3f x,
                const c3f y,
                const c3f z);
@@ -82,7 +82,7 @@ c3cam_set_lookatf(
 /* eye and lookat remain unchanged                      */
 void
 c3cam_roll(
-               c3camp c,
+               c3cam_p c,
                const c3f angle);
 
 /******************************* eye_yaw() *********************/
@@ -90,7 +90,7 @@ c3cam_roll(
 /* Lookat is unaffected                                        */
 void
 c3cam_eye_yaw(
-               c3camp c,
+               c3cam_p c,
                const c3f angle);
 
 /******************************* eye_yaw_abs() ******************/
@@ -98,7 +98,7 @@ c3cam_eye_yaw(
 /* Lookat is unaffected                                         */
 void
 c3cam_eye_yaw_abs(
-               c3camp c,
+               c3cam_p c,
                const c3f angle,
                const c3vec3 axis);
 
@@ -107,7 +107,7 @@ c3cam_eye_yaw_abs(
 /* Lookat is unaffected                                 */
 void
 c3cam_eye_pitch(
-               c3camp c,
+               c3cam_p c,
                const c3f angle);
 
 /******************************* lookat_yaw()************/
@@ -116,7 +116,7 @@ c3cam_eye_pitch(
 /* Eye point is unaffected                              */
 void
 c3cam_lookat_yaw(
-               c3camp c,
+               c3cam_p c,
                const c3f angle);
 
 /******************************* lookat_pitch() *********/
@@ -125,7 +125,7 @@ c3cam_lookat_yaw(
 /* Eye point is unaffected                              */
 void
 c3cam_lookat_pitch(
-               c3camp c,
+               c3cam_p c,
                const c3f angle);
 
 /******************************* reset_up() ******************/
@@ -134,11 +134,11 @@ c3cam_lookat_pitch(
 /* along the specified axis                                  */
 void
 c3cam_reset_up_axis(
-               c3camp c,
+               c3cam_p c,
                const int axis_num);
 void
 c3cam_reset_up(
-               c3camp c);
+               c3cam_p c);
 
 /******************************* move() ********************/
 /* Moves a specified distance in the forward, side, and up */
@@ -147,13 +147,13 @@ c3cam_reset_up(
 /* function.                                               */
 void
 c3cam_movef(
-               c3camp c,
+               c3cam_p c,
                const c3f side_move,
                const c3f up_move,
                const c3f forw_move);
 void
 c3cam_movev(
-               c3camp c,
+               c3cam_p c,
                const c3vec3 v); /* A vector version of the above command */
 
 /******************************* move_by_eye() ***********/
@@ -161,7 +161,7 @@ c3cam_movev(
 /* same amount as the eye is moved.                      */
 void
 c3cam_move_by_eye(
-               c3camp c,
+               c3cam_p c,
                const c3vec3 new_eye);
 
 /******************************* move_by_lookat() *********/
@@ -169,14 +169,14 @@ c3cam_move_by_eye(
 /* same amount as the lookat is moved.                    */
 void
 c3cam_move_by_lookat(
-               c3camp c,
+               c3cam_p c,
                const c3vec3 new_lookat);
 
 /******************************* move_abs() *****************/
 /* Move the eye and lookat in world coordinates             */
 void
 c3cam_move_abs(
-               c3camp c,
+               c3cam_p c,
                const c3vec3 v);
 
 /****************************** rot_about_eye() ************/
@@ -184,7 +184,7 @@ c3cam_move_abs(
 /* (pure) rotation matrix                                  */
 void
 c3cam_rot_about_eye(
-               c3camp c,
+               c3cam_p c,
                const c3mat4p rot);
 
 /****************************** rot_about_lookat() ************/
@@ -192,14 +192,14 @@ c3cam_rot_about_eye(
 /* (pure) rotation matrix                                  */
 void
 c3cam_rot_about_lookat(
-               c3camp c,
+               c3cam_p c,
                const c3mat4p rot);
 
 /******************************* make_mtx() *************/
 /* Constructs a 4x4 matrix - used by load_to_openGL()   */
 void
 c3cam_update_matrix(
-               c3camp c);
+               c3cam_p c);
 
 /******************************* load_to_openGL() ********/
 /* Sets the OpenGL modelview matrix based on the current */
@@ -216,17 +216,21 @@ c3cam_update_matrix(
 /* Resets the parameters of this class                  */
 void
 c3cam_reset(
-               c3camp c);
+               c3cam_p c);
 
-/******************************* ViewModel() ************/
+/******************************* c3cam_t() ************/
 /* Constructor                                          */
-c3cam c3cam_new();
+c3cam_t
+c3cam_new();
 
+void
+c3cam_init(
+               c3cam_p c);
 /******************************* update() ****************/
 /* updates the view params.  Call this after making      */
 /* direct changes to the vectors or points of this class */
 void c3cam_update(
-               c3camp c);
+               c3cam_p c);
 
 /******************************* dump() *******************/
 /* Prints the contents of this class to a file, typically */
index 0ba83674318659074c8e0fd48c71c87ff23ed160..351e63118e2d69779d4259f5829e4710e4664117 100644 (file)
@@ -19,7 +19,7 @@
        along with simavr.  If not, see <http://www.gnu.org/licenses/>.
  */
 
-
+#include <math.h>
 #include "c3context.h"
 #include "c3object.h"
 #include "c3driver_context.h"
@@ -40,13 +40,17 @@ c3context_init(
                int h)
 {
        memset(c, 0, sizeof(*c));
-       c->size.x = w;
-       c->size.y = h;
+
+       c3context_view_t v = {
+                       .type = C3_CONTEXT_VIEW_EYE,
+                       .size = c3vec2f(w, h),
+                       .cam = c3cam_new(),
+                       .dirty = 1,
+       };
+       c3context_view_array_add(&c->views, v);
        c->root = c3object_new(NULL);
        c->root->context = c;
 
-       c->cam = c3cam_new();
-
        return c;
 }
 
@@ -55,21 +59,87 @@ c3context_dispose(
                c3context_p c)
 {
        c3object_dispose(c->root);
-       c3geometry_array_free(&c->projected);
+       for (int i = 0; i < c->views.count; i++)
+               c3geometry_array_free(&c->views.e[i].projected);
        free(c);
 }
 
+static c3context_view_p qsort_view;
+
+/*
+ * Computes the distance from the 'eye' of the camera, 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));
+
+       c3cam_p cam = &qsort_view->cam;
+       c3f d1 = c3vec3_length2(c3vec3_sub(c1, cam->eye));
+       c3f d2 = c3vec3_length2(c3vec3_sub(c2, cam->eye));
+
+       if (d1 > qsort_view->z.max) qsort_view->z.max = d1;
+       if (d1 < qsort_view->z.min) qsort_view->z.min = d1;
+       if (d2 > qsort_view->z.max) qsort_view->z.max = d2;
+       if (d2 < qsort_view->z.min) qsort_view->z.min = d2;
+       /*
+        * 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;
+}
+
 void
 c3context_project(
                c3context_p c)
 {
-       if (!c->root || !c->root->dirty)
+       if (!c->root)
                return;
 
-       c3mat4 m = identity3D();
-       c3object_project(c->root, &m);
-       c3geometry_array_clear(&c->projected);
-       c3object_get_geometry(c->root, &c->projected);
+       /*
+        * if the root object is dirty, all the views are also
+        * dirty since the geometry has changed
+        */
+       if (c->root->dirty) {
+               for (int ci = 0; ci < c->views.count; ci++)
+                       c->views.e[ci].dirty = 1;
+               c3mat4 m = identity3D();
+               c3object_project(c->root, &m);
+       }
+
+       /*
+        * if the current view is dirty, gather all the geometry
+        * and Z sort it in a basic way
+        */
+       c3context_view_p v = qsort_view = c3context_view_get(c);
+       if (v->dirty) {
+           c3cam_update_matrix(&v->cam);
+
+               c3geometry_array_p  array = &c3context_view_get(c)->projected;
+               c3geometry_array_clear(array);
+               c3object_get_geometry(c->root, array);
+
+               v->z.min = 1000000000;
+               v->z.max = -1000000000;
+
+               qsort(v->projected.e,
+                               v->projected.count, sizeof(v->projected.e[0]),
+                       _c3_z_sorter);
+               v->z.min = sqrt(v->z.min);
+               v->z.max = sqrt(v->z.max);
+
+               v->dirty = 0;
+       }
 }
 
 void
@@ -77,8 +147,10 @@ c3context_draw(
                c3context_p c)
 {
        c3context_project(c);
-       for (int gi = 0; gi < c->projected.count; gi++) {
-               c3geometry_p g = c->projected.e[gi];
+
+       c3geometry_array_p  array = &c3context_view_get(c)->projected;
+       for (int gi = 0; gi < array->count; gi++) {
+               c3geometry_p g = array->e[gi];
                c3geometry_draw(g);
        }
 }
index f659cf8d86e003b42497fe350b0c9e840f8d2adf..91ea4f16ae2420a5de9eed18e5d5af5c3379f88f 100644 (file)
 #include "c3algebra.h"
 #include "c3geometry.h"
 #include "c3pixels.h"
+#include "c3program.h"
 #include "c3camera.h"
 
+enum {
+       C3_CONTEXT_VIEW_EYE = 0,
+       C3_CONTEXT_VIEW_LIGHT
+};
+
+typedef struct c3context_view_t {
+       int                     type : 4,       // C3_CONTEXT_VIEW_EYE...
+                               dirty : 1;
+       c3vec2          size;                                   // in pixels. for fbo/textures/window
+       c3cam_t         cam;
+
+       c3geometry_array_t      projected;
+       struct {
+               c3f min, max;
+       } z;
+} c3context_view_t, *c3context_view_p;
+
+DECLARE_C_ARRAY(c3context_view_t, c3context_view_array, 4);
+
 //! c3context_t is a container for a 'scene' to be drawn
 /*!
  * A c3context_t holds a root object, a list of already cached projected
  * TODO: Add the camera/eye/arcball control there
  */
 typedef struct c3context_t {
-       c3vec2          size;
-       c3cam           cam;
+       int     current;
+       c3context_view_array_t  views;
 
        struct c3object_t * root;       // root object
-       c3pixels_array_t        pixels; // pixels, textures...
 
-       c3geometry_array_t      projected;
+       c3pixels_array_t        pixels; // pixels, textures...
+       c3program_array_t       programs;       // fragment, vertex, geometry shaders
 
        const struct c3driver_context_t ** driver;
 } c3context_t, *c3context_p;
@@ -77,4 +97,37 @@ void
 c3context_draw(
                c3context_p c);
 
+IMPLEMENT_C_ARRAY(c3context_view_array);
+
+/*
+ * Set and get the current view, this is done
+ * before projecting and drawing
+ */
+static inline c3context_view_p
+c3context_view_get(
+               c3context_p c )
+{
+       return &c->views.e[c->current];
+}
+
+static inline c3context_view_p
+c3context_view_get_at(
+               c3context_p c,
+               int view)
+{
+       if (view < c->views.count)
+               return &c->views.e[view];
+       return NULL;
+}
+
+static inline void
+c3context_view_set(
+               c3context_p c,
+               int view)
+{
+       if (view < c->views.count)
+               c->current = view;
+}
+
+
 #endif /* __C3CONTEXT_H___ */
index 98f34abce15d41853836e0ad88c9766b0ec6ccc6..c3cff597c19ceb5021ad329dda5f95089f3a5945 100644 (file)
@@ -30,15 +30,31 @@ struct c3driver_context_t;
 struct c3geometry_t;
 
 typedef struct c3driver_context_t {
+       /*
+        * Called when a geometry projection had changed in world view
+        * can also be used to prepare resources like textures and so on
+        */
        void (*geometry_project)(
                        struct c3context_t * c,
                        const struct c3driver_context_t *d,
                        struct c3geometry_t * g,
                        union c3mat4 * mat);
+       /*
+        * Called to draw a geometry
+        */
        void (*geometry_draw)(
                        struct c3context_t * c,
                        const struct c3driver_context_t *d,
                        struct c3geometry_t * g);
+
+       /*
+        * called when a geometry is disposed of, let the application
+        * delete resources like textures etc
+        */
+       void (*geometry_dispose)(
+               struct c3context_t * c,
+               const struct c3driver_context_t *d,
+               struct c3geometry_t * g);
 } c3driver_context_t, *c3driver_context_p;
 
 #endif /* __C3DRIVER_CONTEXT_H___ */
index 3abaacc02a07d411e73165ee113849ef4b593601..8de3eadaaf8570724746f18a5a81ba763b96a3c7 100644 (file)
@@ -42,6 +42,9 @@ _c3geometry_dispose(
                        }
                g->object = NULL;
        }
+       /* let the context driver have a chance to clear it's own stuff */
+       if (g->object && g->object->context)
+               C3_DRIVER(g->object->context, geometry_dispose, g);
        str_free(g->name);
        c3vertex_array_free(&g->vertice);
        c3vertex_array_free(&g->projected);
index 82b615610a3e54ee55f6da2684af0ebeb6b256c0..355654fd8b8e9f552383c965ddf20f39a32fd231 100644 (file)
@@ -38,22 +38,20 @@ typedef c3vec2 c3tex, *c3tex_p;
 
 struct c3object_t;
 struct c3pixels_t;
+struct c3program_t;
 
-DECLARE_C_ARRAY(c3vertex, c3vertex_array, 16);
-DECLARE_C_ARRAY(c3tex, c3tex_array, 16);
-DECLARE_C_ARRAY(c3colorf, c3colorf_array, 16);
+DECLARE_C_ARRAY(c3vertex, c3vertex_array, 16, uint32_t bid);
+DECLARE_C_ARRAY(c3tex, c3tex_array, 16, uint32_t bid);
+DECLARE_C_ARRAY(c3colorf, c3colorf_array, 16, uint32_t bid);
 
 //! Geometry material. TODO: Beef up. Add vertex/fragment programs..
 typedef struct c3material_t {
        c3colorf        color;
        struct c3pixels_t * texture;
-//     uint32_t        texmode;
+       struct c3program_t * program;
        struct {
                uint32_t src, dst;
        } blend;
-       struct {
-               uint32_t pid;
-       } program;
 } c3material_t;
 
 //! Bounding box. TODO: Move to a separate file?