X-Git-Url: http://git.mutantstargoat.com/user/nuclear/?a=blobdiff_plain;f=src%2Fmesh.c;fp=src%2Fmesh.c;h=149fbe7a78565ea9bb490a38a54a889a87b1f29b;hb=f3d32774e0c196175d8143c21313097bcc8ff3a2;hp=0000000000000000000000000000000000000000;hpb=fd7b604752c0ba03c347bc2ef3ee5a8c0759bff8;p=vrlugburz diff --git a/src/mesh.c b/src/mesh.c new file mode 100644 index 0000000..149fbe7 --- /dev/null +++ b/src/mesh.c @@ -0,0 +1,337 @@ +#include +#include +#include +#include +#include +#define GL_GLEXT_PROTOTYPES 1 +#include +#include +#include "mesh.h" + +static int update_mesh_vbo(struct mesh *m); +static int update_meshgroup_vbo(struct meshgroup *mg); + +void init_mesh(struct mesh *m) +{ + memset(m, 0, sizeof *m); +} + +void destroy_mesh(struct mesh *m) +{ + free(m->varr); + free(m->iarr); + + if(m->vbo) { + glDeleteBuffers(1, &m->vbo); + } + if(m->ibo) { + glDeleteBuffers(1, &m->ibo); + } +} + +void clear_mesh(struct mesh *m) +{ + free(m->varr); + free(m->iarr); + + m->varr = 0; + m->iarr = 0; + m->num_verts = m->max_verts = m->num_idx = m->max_idx = 0; + m->mtl = 0; + m->bbvalid = m->vbovalid = 0; +} + +void init_meshgroup(struct meshgroup *mg) +{ + memset(mg, 0, sizeof *mg); +} + +void destroy_meshgroup(struct meshgroup *mg) +{ + free(mg->meshes); + + if(mg->vbo) { + glDeleteBuffers(1, &mg->vbo); + } + if(mg->ibo) { + glDeleteBuffers(1, &mg->ibo); + } +} + +void clear_meshgroup(struct meshgroup *mg) +{ + free(mg->meshes); + + mg->meshes = 0; + mg->num_meshes = 0; + mg->num_verts = mg->num_idx = 0; + + mg->bbvalid = mg->vbovalid = 0; +} + +void calc_mesh_bounds(struct mesh *m) +{ + int i; + struct vertex *vptr = m->varr; + + m->bb.vmin.x = m->bb.vmin.y = m->bb.vmin.z = FLT_MAX; + m->bb.vmax.x = m->bb.vmax.y = m->bb.vmax.z = -FLT_MAX; + + for(i=0; inum_verts; i++) { + if(vptr->pos.x < m->bb.vmin.x) m->bb.vmin.x = vptr->pos.x; + if(vptr->pos.y < m->bb.vmin.y) m->bb.vmin.y = vptr->pos.y; + if(vptr->pos.z < m->bb.vmin.z) m->bb.vmin.z = vptr->pos.z; + if(vptr->pos.x > m->bb.vmax.x) m->bb.vmax.x = vptr->pos.x; + if(vptr->pos.y > m->bb.vmax.y) m->bb.vmax.y = vptr->pos.y; + if(vptr->pos.z > m->bb.vmax.z) m->bb.vmax.z = vptr->pos.z; + vptr++; + } + + m->bbvalid = 1; +} + +void calc_meshgroup_bounds(struct meshgroup *mg) +{ + int i; + struct mesh *m; + + mg->bb.vmin.x = mg->bb.vmin.y = mg->bb.vmin.z = FLT_MAX; + mg->bb.vmax.x = mg->bb.vmax.y = mg->bb.vmax.z = -FLT_MAX; + + for(i=0; inum_meshes; i++) { + m = mg->meshes[i]; + if(!m->bbvalid) { + calc_mesh_bounds(m); + } + + if(m->bb.vmin.x < mg->bb.vmin.x) mg->bb.vmin.x = m->bb.vmin.x; + if(m->bb.vmin.y < mg->bb.vmin.y) mg->bb.vmin.y = m->bb.vmin.y; + if(m->bb.vmin.z < mg->bb.vmin.z) mg->bb.vmin.z = m->bb.vmin.z; + if(m->bb.vmax.x > mg->bb.vmax.x) mg->bb.vmax.x = m->bb.vmax.x; + if(m->bb.vmax.y > mg->bb.vmax.y) mg->bb.vmax.y = m->bb.vmax.y; + if(m->bb.vmax.z > mg->bb.vmax.z) mg->bb.vmax.z = m->bb.vmax.z; + } + + mg->bbvalid = 1; +} + +int add_mesh_vertex(struct mesh *m, struct vertex *v) +{ + void *tmp; + int newmax; + + if(m->num_verts >= m->max_verts) { + newmax = m->max_verts ? m->max_verts * 2 : 16; + if(!(tmp = realloc(m->varr, newmax * sizeof *m->varr))) { + return -1; + } + m->varr = tmp; + m->max_verts = newmax; + } + + m->varr[m->num_verts++] = *v; + return 0; +} + +int add_mesh_index(struct mesh *m, int idx) +{ + void *tmp; + int newmax; + + if(m->num_idx >= m->max_idx) { + newmax = m->max_idx ? m->max_idx * 2 : 16; + if(!(tmp = realloc(m->iarr, newmax * sizeof *m->iarr))) { + return -1; + } + m->iarr = tmp; + m->max_idx = newmax; + } + + m->iarr[m->num_idx++] = idx; + return 0; +} + +int add_mesh_face(struct mesh *m, int va, int vb, int vc) +{ + if(add_mesh_index(m, va) == -1) return -1; + if(add_mesh_index(m, vb) == -1) { + m->num_idx--; + return -1; + } + if(add_mesh_index(m, vc) == -1) { + m->num_idx -= 2; + return -1; + } + return 0; +} + +int add_meshgroup_mesh(struct meshgroup *mg, struct mesh *m) +{ + void *tmp; + int newmax; + + if(mg->num_meshes >= mg->max_meshes) { + newmax = mg->max_meshes ? mg->max_meshes * 2 : 16; + if(!(tmp = realloc(mg->meshes, newmax * sizeof *mg->meshes))) { + return -1; + } + mg->meshes = tmp; + mg->max_meshes = newmax; + } + + mg->meshes[mg->num_meshes++] = m; + return 0; +} + +void draw_mesh(struct mesh *m) +{ + if(!m->vbovalid) { + if(update_mesh_vbo(m) == -1) { + return; + } + } + + glEnableVertexAttribArray(MESH_ATTR_VERTEX); + glEnableVertexAttribArray(MESH_ATTR_NORMAL); + glEnableVertexAttribArray(MESH_ATTR_TANGENT); + glEnableVertexAttribArray(MESH_ATTR_TEXCOORD); + + glBindBuffer(GL_ARRAY_BUFFER, m->vbo); + glVertexAttribPointer(MESH_ATTR_VERTEX, 3, GL_FLOAT, 0, sizeof *m->varr, 0); + glVertexAttribPointer(MESH_ATTR_NORMAL, 3, GL_FLOAT, 0, sizeof *m->varr, (void*)offsetof(struct vertex, norm)); + glVertexAttribPointer(MESH_ATTR_TANGENT, 3, GL_FLOAT, 0, sizeof *m->varr, (void*)offsetof(struct vertex, tang)); + glVertexAttribPointer(MESH_ATTR_TEXCOORD, 2, GL_FLOAT, 0, sizeof *m->varr, (void*)offsetof(struct vertex, tex)); + glBindBuffer(GL_ARRAY_BUFFER, 0); + + if(m->ibo) { + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m->ibo); + glDrawElements(GL_TRIANGLES, m->num_idx, GL_UNSIGNED_INT, 0); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); + } else { + glDrawArrays(GL_TRIANGLES, 0, m->num_verts); + } + + glDisableVertexAttribArray(MESH_ATTR_VERTEX); + glDisableVertexAttribArray(MESH_ATTR_NORMAL); + glDisableVertexAttribArray(MESH_ATTR_TANGENT); + glDisableVertexAttribArray(MESH_ATTR_TEXCOORD); +} + +void draw_meshgroup(struct meshgroup *mg) +{ + if(!mg->vbovalid) { + if(update_meshgroup_vbo(mg) == -1) { + return; + } + } + + glEnableVertexAttribArray(MESH_ATTR_VERTEX); + glEnableVertexAttribArray(MESH_ATTR_NORMAL); + glEnableVertexAttribArray(MESH_ATTR_TANGENT); + glEnableVertexAttribArray(MESH_ATTR_TEXCOORD); + + glBindBuffer(GL_ARRAY_BUFFER, mg->vbo); + glVertexAttribPointer(MESH_ATTR_VERTEX, 3, GL_FLOAT, 0, sizeof(struct vertex), 0); + glVertexAttribPointer(MESH_ATTR_NORMAL, 3, GL_FLOAT, 0, sizeof(struct vertex), (void*)offsetof(struct vertex, norm)); + glVertexAttribPointer(MESH_ATTR_TANGENT, 3, GL_FLOAT, 0, sizeof(struct vertex), (void*)offsetof(struct vertex, tang)); + glVertexAttribPointer(MESH_ATTR_TEXCOORD, 2, GL_FLOAT, 0, sizeof(struct vertex), (void*)offsetof(struct vertex, tex)); + glBindBuffer(GL_ARRAY_BUFFER, 0); + + if(mg->ibo) { + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mg->ibo); + glDrawElements(GL_TRIANGLES, mg->num_idx, GL_UNSIGNED_INT, 0); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); + } else { + glDrawArrays(GL_TRIANGLES, 0, mg->num_verts); + } + + glDisableVertexAttribArray(MESH_ATTR_VERTEX); + glDisableVertexAttribArray(MESH_ATTR_NORMAL); + glDisableVertexAttribArray(MESH_ATTR_TANGENT); + glDisableVertexAttribArray(MESH_ATTR_TEXCOORD); +} + +static int update_mesh_vbo(struct mesh *m) +{ + if(m->num_verts <= 0) return -1; + + if(!m->vbo) { + glGenBuffers(1, &m->vbo); + } + glBindBuffer(GL_ARRAY_BUFFER, m->vbo); + glBufferData(GL_ARRAY_BUFFER, m->num_verts * sizeof *m->varr, m->varr, GL_STATIC_DRAW); + glBindBuffer(GL_ARRAY_BUFFER, 0); + + if(m->num_idx > 0) { + if(!m->ibo) { + glGenBuffers(1, &m->ibo); + } + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m->ibo); + glBufferData(GL_ELEMENT_ARRAY_BUFFER, m->num_idx * sizeof *m->iarr, + m->iarr, GL_STATIC_DRAW); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); + } + return 0; +} + +static int update_meshgroup_vbo(struct meshgroup *mg) +{ + int i; + struct vertex *varr, *vptr; + unsigned int *iarr = 0, *iptr; + struct mesh *m; + + mg->num_verts = mg->num_idx = 0; + + for(i=0; inum_meshes; i++) { + mg->num_verts += mg->meshes[i]->num_verts; + mg->num_idx += mg->meshes[i]->num_idx; + } + + if(mg->num_verts <= 0) return -1; + + if(!(varr = malloc(mg->num_verts * sizeof *varr))) { + fprintf(stderr, "update_meshgroup_vbo: failed to allocate vertex array with %d vertices\n", mg->num_verts); + return -1; + } + if(mg->num_idx > 0) { + if(!(iarr = malloc(mg->num_idx * sizeof *iarr))) { + fprintf(stderr, "update_meshgroup_vbo: failed to allocate index array with %d indices\n", mg->num_idx); + free(varr); + return -1; + } + } + + vptr = varr; + iptr = iarr; + + for(i=0; inum_meshes; i++) { + m = mg->meshes[i]; + memcpy(vptr, m->varr, m->num_verts * sizeof *vptr); + vptr += m->num_verts; + + if(iarr) { + memcpy(iptr, m->iarr, m->num_idx * sizeof *iptr); + iptr += m->num_idx; + } + } + + if(!mg->vbo) { + glGenBuffers(1, &mg->vbo); + } + glBindBuffer(GL_ARRAY_BUFFER, mg->vbo); + glBufferData(GL_ARRAY_BUFFER, mg->num_verts * sizeof *varr, varr, GL_STATIC_DRAW); + glBindBuffer(GL_ARRAY_BUFFER, 0); + if(iarr) { + if(!mg->ibo) { + glGenBuffers(1, &mg->ibo); + } + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mg->ibo); + glBufferData(GL_ELEMENT_ARRAY_BUFFER, mg->num_idx * sizeof *iarr, iarr, GL_STATIC_DRAW); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); + } + + free(varr); + free(iarr); + return 0; +}