/** # Vertex buffers They are used to store the vertex coordinates, normals and colors computed by the the OpenGL commands typically used by [draw.h](). These vertex buffers are the minimal information required to render the objects. In combination with the [tiny implementation](gl/fb_tiny.c) this allows to generate geometries using OpenGL commands but without any OpenGL library. */ struct { // public Array * position, * normal, * color, * index; float modelview[16]; int type; // type = 0 -> lines, type = 1 -> mesh int dim; int vertex, nvertex; bool visible; // visible = true > only traverse visible vertices // private int line_loop, lines, line_strip ; int quads, polygon, fan; int state; } VertexBuffer = { .visible = false, // traverse all vertices by default .modelview = { 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1 } }; static void vertex_buffer_push_index (unsigned int i) { i -= VertexBuffer.vertex; array_append (VertexBuffer.index, &i, sizeof(unsigned int)); } void vertex_buffer_setup() { VertexBuffer.nvertex = 0; VertexBuffer.type = -1; VertexBuffer.dim = -1; VertexBuffer.position = array_new(); VertexBuffer.normal = array_new(); VertexBuffer.color = array_new(); VertexBuffer.index = array_new(); } void vertex_buffer_free() { array_free (VertexBuffer.position); VertexBuffer.position = NULL; array_free (VertexBuffer.normal); VertexBuffer.normal = NULL; array_free (VertexBuffer.color); VertexBuffer.color = NULL; array_free (VertexBuffer.index); VertexBuffer.index = NULL; } static void vertex_buffer_glBegin (unsigned int state) { if (VertexBuffer.index) { glGetFloatv (GL_MODELVIEW_MATRIX, VertexBuffer.modelview); bview * view = get_view(); float q[16] = { 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, - view->tx, - view->ty, 3, 1 }; matrix_multiply (q, VertexBuffer.modelview); for (int i = 0; i < 16; i++) VertexBuffer.modelview[i] = q[i]; gl_build_rotmatrix ((float (*)[4])q, view->quat); swap (float, q[1], q[4]); swap (float, q[2], q[8]); swap (float, q[6], q[9]); matrix_multiply (q, VertexBuffer.modelview); for (int i = 0; i < 16; i++) VertexBuffer.modelview[i] = q[i]; VertexBuffer.state = state; switch (state) { case GL_LINE_LOOP: VertexBuffer.line_loop = VertexBuffer.nvertex; break; case GL_LINES: VertexBuffer.lines = VertexBuffer.nvertex; break; case GL_LINE_STRIP: VertexBuffer.line_strip = VertexBuffer.nvertex; break; case GL_QUADS: VertexBuffer.quads = VertexBuffer.nvertex; break; case GL_POLYGON: VertexBuffer.polygon = VertexBuffer.nvertex; break; case GL_TRIANGLE_FAN: VertexBuffer.fan = VertexBuffer.nvertex; break; default: fprintf (stderr, "glBegin (%d) not implemented yet\n", state); break; } } else glBegin (state); } static void vertex_buffer_glEnd() { if (VertexBuffer.index) { int type = -1; switch (VertexBuffer.state) { case GL_LINE_LOOP: for (int i = VertexBuffer.line_loop; i < VertexBuffer.nvertex - 1; i++) { vertex_buffer_push_index (i); vertex_buffer_push_index (i + 1); } vertex_buffer_push_index (VertexBuffer.nvertex - 1); vertex_buffer_push_index (VertexBuffer.line_loop); type = 0; break; case GL_LINES: for (int i = VertexBuffer.lines; i < VertexBuffer.nvertex; i += 2) { vertex_buffer_push_index (i); vertex_buffer_push_index (i + 1); } type = 0; break; case GL_LINE_STRIP: for (int i = VertexBuffer.line_strip; i < VertexBuffer.nvertex - 1; i++) { vertex_buffer_push_index (i); vertex_buffer_push_index (i + 1); } type = 0; break; case GL_QUADS: for (int i = VertexBuffer.quads; i < VertexBuffer.nvertex; i += 4) for (int j = 1; j <= 2; j++) { vertex_buffer_push_index (i); vertex_buffer_push_index (i + j); vertex_buffer_push_index (i + j + 1); } type = 1; break; case GL_POLYGON: for (int j = 1; j <= VertexBuffer.nvertex - VertexBuffer.polygon - 2; j++) { vertex_buffer_push_index (VertexBuffer.polygon); vertex_buffer_push_index (VertexBuffer.polygon + j); vertex_buffer_push_index (VertexBuffer.polygon + j + 1); } type = 1; break; case GL_TRIANGLE_FAN: for (int i = VertexBuffer.fan + 1; i < VertexBuffer.nvertex - 1; i++) { vertex_buffer_push_index (VertexBuffer.fan); vertex_buffer_push_index (i); vertex_buffer_push_index (i + 1); } type = 1; break; default: break; } VertexBuffer.state = 0; if (VertexBuffer.type >= 0 && type >= 0) { // cannot mix lines and surfaces primitives assert (VertexBuffer.type == type); } else VertexBuffer.type = type; } else glEnd(); } static void vertex_buffer_glColor3f (float r, float g, float b) { if (VertexBuffer.color) { struct { float x, y, z; } color = {r, g, b}; // fixme: use r,g,b directly array_append (VertexBuffer.color, &color, 3*sizeof(float)); } else glColor3f (r, g, b); } static void vertex_buffer_glNormal3d (double nx, double ny, double nz) { if (VertexBuffer.normal) { struct { float x, y, z; } normal = {nx, ny, nz}; array_append (VertexBuffer.normal, &normal, 3*sizeof(float)); } else glNormal3d (nx, ny, nz); } static void vertex_buffer_glVertex3d (double x, double y, double z) { if (VertexBuffer.position) { if (VertexBuffer.dim < 3) VertexBuffer.dim = 3; float v[4] = {x, y, z, 1.}; vector_multiply (v, VertexBuffer.modelview); array_append (VertexBuffer.position, v, 3*sizeof(float)); VertexBuffer.nvertex++; } else glVertex3d (x, y, z); } static void vertex_buffer_glVertex2d (double x, double y) { if (VertexBuffer.position) { if (VertexBuffer.dim < 2) VertexBuffer.dim = 2; float v[4] = {x, y, 0, 1.}; vector_multiply (v, VertexBuffer.modelview); array_append (VertexBuffer.position, v, 3*sizeof(float)); VertexBuffer.nvertex++; } else glVertex3d (x, y, 0.); } /** Here we overload the default OpenGL commands, in order to call the corresponding vertex buffer operations defined above. */ #define glBegin vertex_buffer_glBegin #define glEnd vertex_buffer_glEnd #define glVertex2d vertex_buffer_glVertex2d #define glVertex2f vertex_buffer_glVertex2d #define glVertex3d vertex_buffer_glVertex3d #define glColor3f vertex_buffer_glColor3f #define glNormal3d vertex_buffer_glNormal3d