# HG changeset patch # User John Tsiombikas # Date 1326925069 -7200 # Node ID 7650e941805c26924af72052bab8c2ca23224b62 # Parent 182bfd9f55c7414515d9c8fde7101ad38b2f41c4 forgot two files diff -r 182bfd9f55c7 -r 7650e941805c src/scene.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/scene.c Thu Jan 19 00:17:49 2012 +0200 @@ -0,0 +1,224 @@ +#include +#include +#include + +#include + +#include +#include +#include + +#include + +#include "scene.h" + +static void color(float *dest, float r, float g, float b); +static struct mesh *create_mesh(const struct aiScene *aiscn, struct aiMesh *aim); +static unsigned int create_buffer(unsigned int type, void *data, size_t sz); +static unsigned int load_texture(const char *fname); + + +int load_scene(struct scene *scn, const char *fname) +{ + int i, j; + const struct aiScene *aiscn; + unsigned int proc_flags = aiProcess_JoinIdenticalVertices | + aiProcess_PreTransformVertices | aiProcess_Triangulate | + aiProcess_GenNormals | aiProcess_SortByPType; + + if(!(aiscn = aiImportFile(fname, proc_flags))) { + fprintf(stderr, "failed to load: %s\n", fname); + return -1; + } + + scn->meshes = 0; + scn->lights = 0; + + scn->bbox.min[0] = scn->bbox.min[1] = scn->bbox.min[2] = FLT_MAX; + scn->bbox.max[0] = scn->bbox.max[1] = scn->bbox.max[2] = -FLT_MAX; + + for(i=0; imNumMeshes; i++) { + struct mesh *m; + + if(!(m = create_mesh(aiscn, aiscn->mMeshes[i]))) { + return -1; + } + + for(j=0; j<3; j++) { + if(m->bbox.min[j] < scn->bbox.min[j]) { + scn->bbox.min[j] = m->bbox.min[j]; + } + if(m->bbox.max[j] > scn->bbox.max[j]) { + scn->bbox.max[j] = m->bbox.max[j]; + } + } + + m->next = scn->meshes; + scn->meshes = m; + } + + printf("scene bounds: %.2f %.2f %.2f -> %.2f %.2f %.2f\n", scn->bbox.min[0], scn->bbox.min[1], + scn->bbox.min[2], scn->bbox.max[0], scn->bbox.max[1], scn->bbox.max[2]); + + aiReleaseImport(aiscn); + return 0; +} + +static void color(float *dest, float r, float g, float b) +{ + dest[0] = r; + dest[1] = g; + dest[2] = b; + dest[3] = 1.0; +} + +static struct mesh *create_mesh(const struct aiScene *aiscn, struct aiMesh *aim) +{ + int i, j; + struct mesh *m; + struct aiMaterial *mat = aiscn->mMaterials[aim->mMaterialIndex]; + float sstr = 1.0; + unsigned int sz, *idxarr, *dptr; + struct aiVector3D *vptr; + struct aiString tex_name; + + if(!(m = calloc(1, sizeof *m))) { + perror("failed to allocate mesh"); + return 0; + } + + /* default material */ + color(m->mat.kd, 1, 1, 1); + color(m->mat.ks, 0, 0, 0); + m->mat.shin = 60.0; + + aiGetMaterialColor(mat, AI_MATKEY_COLOR_DIFFUSE, (void*)m->mat.kd); + aiGetMaterialColor(mat, AI_MATKEY_COLOR_SPECULAR, (void*)m->mat.ks); + sz = 1; + aiGetMaterialFloatArray(mat, AI_MATKEY_SHININESS, &m->mat.shin, &sz); + sz = 1; + aiGetMaterialFloatArray(mat, AI_MATKEY_SHININESS_STRENGTH, &sstr, &sz); + color(m->mat.ks, m->mat.ks[0] * sstr, m->mat.ks[1] * sstr, m->mat.ks[2] * sstr); + + if(aiGetMaterialString(mat, AI_MATKEY_TEXTURE(aiTextureType_DIFFUSE, 0), &tex_name) == 0) { + m->mat.tex = load_texture(tex_name.data); + } + + m->num_verts = aim->mNumVertices; + m->num_faces = aim->mNumFaces; + + m->bbox.min[0] = m->bbox.min[1] = m->bbox.min[2] = FLT_MAX; + m->bbox.max[0] = m->bbox.max[1] = m->bbox.max[2] = -FLT_MAX; + + vptr = aim->mVertices; + for(i=0; inum_verts; i++) { + if(vptr->x < m->bbox.min[0]) m->bbox.min[0] = vptr->x; + if(vptr->y < m->bbox.min[1]) m->bbox.min[1] = vptr->y; + if(vptr->z < m->bbox.min[2]) m->bbox.min[2] = vptr->z; + if(vptr->x > m->bbox.max[0]) m->bbox.max[0] = vptr->x; + if(vptr->y > m->bbox.max[1]) m->bbox.max[1] = vptr->y; + if(vptr->z > m->bbox.max[2]) m->bbox.max[2] = vptr->z; + vptr++; + } + + m->vert_buf = create_buffer(GL_ARRAY_BUFFER, aim->mVertices, m->num_verts * sizeof *aim->mVertices); + if(aim->mNormals) { + m->norm_buf = create_buffer(GL_ARRAY_BUFFER, aim->mNormals, m->num_verts * sizeof *aim->mNormals); + } + if(aim->mTextureCoords) { + m->tex_buf = create_buffer(GL_ARRAY_BUFFER, aim->mTextureCoords, m->num_verts * sizeof *aim->mTextureCoords); + } + + /* indices are scattered all over the fucking place... map the buffer and collect them there directly */ + m->idx_buf = create_buffer(GL_ELEMENT_ARRAY_BUFFER, 0, m->num_faces * 3 * sizeof *aim->mFaces[0].mIndices); + dptr = idxarr = glMapBuffer(GL_ELEMENT_ARRAY_BUFFER, GL_WRITE_ONLY); + + for(i=0; inum_faces; i++) { + for(j=0; j<3; j++) { + *dptr++ = aim->mFaces[i].mIndices[j]; + } + } + glUnmapBuffer(GL_ELEMENT_ARRAY_BUFFER); + return m; +} + +static unsigned int create_buffer(unsigned int type, void *data, size_t sz) +{ + unsigned int vbo; + glGenBuffers(1, &vbo); + glBindBuffer(type, vbo); + glBufferData(type, sz, data, GL_STATIC_DRAW); + return vbo; +} + +static unsigned int load_texture(const char *fname) +{ + unsigned int tex; + void *pixels; + int xsz, ysz; + + if(!(pixels = img_load_pixels(fname, &xsz, &ysz, IMG_FMT_RGBA32))) { + fprintf(stderr, "failed to load image: %s\n", fname); + return 0; + } + + glGenTextures(1, &tex); + glBindTexture(GL_TEXTURE_2D, tex); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, xsz, ysz, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels); + + img_free_pixels(pixels); + return tex; +} + +void render_scene(struct scene *scn) +{ + struct mesh *m = scn->meshes; + while(m) { + render_mesh(m); + m = m->next; + } +} + +void render_mesh(struct mesh *m) +{ + glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, m->mat.kd); + glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, m->mat.ks); + glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, m->mat.shin); + + if(m->mat.tex) { + glEnable(GL_TEXTURE_2D); + glBindTexture(GL_TEXTURE_2D, m->mat.tex); + } + + /* TODO texture */ + + glBindBuffer(GL_ARRAY_BUFFER, m->vert_buf); + glVertexPointer(3, GL_FLOAT, 0, 0); + glEnableClientState(GL_VERTEX_ARRAY); + + if(m->norm_buf) { + glBindBuffer(GL_ARRAY_BUFFER, m->norm_buf); + glNormalPointer(GL_FLOAT, 0, 0); + glEnableClientState(GL_NORMAL_ARRAY); + } + if(m->tex_buf) { + glBindBuffer(GL_ARRAY_BUFFER, m->tex_buf); + glTexCoordPointer(3, GL_FLOAT, 0, 0); + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + } + + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m->idx_buf); + glDrawElements(GL_TRIANGLES, m->num_faces * 3, GL_UNSIGNED_INT, 0); + + glDisableClientState(GL_VERTEX_ARRAY); + glDisableClientState(GL_NORMAL_ARRAY); + glDisableClientState(GL_TEXTURE_COORD_ARRAY); + + if(m->mat.tex) { + glDisable(GL_TEXTURE_2D); + } +} diff -r 182bfd9f55c7 -r 7650e941805c src/scene.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/scene.h Thu Jan 19 00:17:49 2012 +0200 @@ -0,0 +1,46 @@ +#ifndef SCENE_H_ +#define SCENE_H_ + +struct aabb { + float min[3], max[3]; +}; + +struct material { + float kd[4]; + float ks[4]; + float shin; + unsigned int tex; +}; + +struct mesh { + unsigned int vert_buf, norm_buf, tex_buf, idx_buf; + int num_verts, num_faces; + + struct material mat; + + struct aabb bbox; + + struct mesh *next; +}; + +struct light { + float pos[4]; + float color[4]; + + struct light *next; +}; + +struct scene { + struct mesh *meshes; + struct light *lights; + + struct aabb bbox; +}; + + +int load_scene(struct scene *scn, const char *fname); + +void render_scene(struct scene *scn); +void render_mesh(struct mesh *m); + +#endif /* SCENE_H_ */