From: Michel Pollet Date: Sun, 3 Jun 2012 14:11:49 +0000 (+0100) Subject: libc3: Few more updates X-Git-Tag: v1.0~100 X-Git-Url: https://git.htl-mechatronik.at/public/?a=commitdiff_plain;h=8afc0af666a8ca83db318c132a44e57afc40b50a;p=sx%2Fsimavr.git libc3: Few more updates 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 --- diff --git a/examples/board_reprap/src/reprap_gl.c b/examples/board_reprap/src/reprap_gl.c index 48e43ca..12a6cdc 100644 --- a/examples/board_reprap/src/reprap_gl.c +++ b/examples/board_reprap/src/reprap_gl.c @@ -42,6 +42,7 @@ #include "c3driver_context.h" #include "c3stl.h" #include "c3lines.h" +#include "c3program.h" #include @@ -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; diff --git a/examples/shared/libc3/src/c3camera.c b/examples/shared/libc3/src/c3camera.c index 8e5fef1..29f9844 100644 --- a/examples/shared/libc3/src/c3camera.c +++ b/examples/shared/libc3/src/c3camera.c @@ -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" ); diff --git a/examples/shared/libc3/src/c3camera.h b/examples/shared/libc3/src/c3camera.h index 1bfc66c..9342e58 100644 --- a/examples/shared/libc3/src/c3camera.h +++ b/examples/shared/libc3/src/c3camera.h @@ -25,12 +25,12 @@ #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 */ diff --git a/examples/shared/libc3/src/c3context.c b/examples/shared/libc3/src/c3context.c index 0ba8367..351e631 100644 --- a/examples/shared/libc3/src/c3context.c +++ b/examples/shared/libc3/src/c3context.c @@ -19,7 +19,7 @@ along with simavr. If not, see . */ - +#include #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); } } diff --git a/examples/shared/libc3/src/c3context.h b/examples/shared/libc3/src/c3context.h index f659cf8..91ea4f1 100644 --- a/examples/shared/libc3/src/c3context.h +++ b/examples/shared/libc3/src/c3context.h @@ -26,8 +26,28 @@ #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 @@ -39,13 +59,13 @@ * 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___ */ diff --git a/examples/shared/libc3/src/c3driver_context.h b/examples/shared/libc3/src/c3driver_context.h index 98f34ab..c3cff59 100644 --- a/examples/shared/libc3/src/c3driver_context.h +++ b/examples/shared/libc3/src/c3driver_context.h @@ -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___ */ diff --git a/examples/shared/libc3/src/c3geometry.c b/examples/shared/libc3/src/c3geometry.c index 3abaacc..8de3ead 100644 --- a/examples/shared/libc3/src/c3geometry.c +++ b/examples/shared/libc3/src/c3geometry.c @@ -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); diff --git a/examples/shared/libc3/src/c3geometry.h b/examples/shared/libc3/src/c3geometry.h index 82b6156..355654f 100644 --- a/examples/shared/libc3/src/c3geometry.h +++ b/examples/shared/libc3/src/c3geometry.h @@ -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?