view3d

annotate src/scene.c @ 8:5562a637e5aa

load multiple files and concatenate them
author John Tsiombikas <nuclear@member.fsf.org>
date Mon, 23 Jan 2012 08:51:59 +0200
parents 75e4377f3cdc
children d0896caa3e5b
rev   line source
nuclear@1 1 #include <stdio.h>
nuclear@1 2 #include <stdlib.h>
nuclear@1 3 #include <float.h>
nuclear@1 4
nuclear@1 5 #include <GL/glew.h>
nuclear@1 6
nuclear@1 7 #include <assimp/assimp.h>
nuclear@1 8 #include <assimp/aiScene.h>
nuclear@1 9 #include <assimp/aiPostProcess.h>
nuclear@1 10
nuclear@1 11 #include <imago2.h>
nuclear@1 12
nuclear@1 13 #include "scene.h"
nuclear@1 14
nuclear@3 15 static void setup_light(struct light *lt);
nuclear@1 16 static void color(float *dest, float r, float g, float b);
nuclear@1 17 static struct mesh *create_mesh(const struct aiScene *aiscn, struct aiMesh *aim);
nuclear@1 18 static unsigned int create_buffer(unsigned int type, void *data, size_t sz);
nuclear@1 19 static unsigned int load_texture(const char *fname);
nuclear@1 20
nuclear@3 21 extern int verbose;
nuclear@1 22
nuclear@8 23 int init_scene(struct scene *scn)
nuclear@8 24 {
nuclear@8 25 scn->meshes = 0;
nuclear@8 26 scn->lights = 0;
nuclear@8 27
nuclear@8 28 scn->bbox.min[0] = scn->bbox.min[1] = scn->bbox.min[2] = FLT_MAX;
nuclear@8 29 scn->bbox.max[0] = scn->bbox.max[1] = scn->bbox.max[2] = -FLT_MAX;
nuclear@8 30 return 0;
nuclear@8 31 }
nuclear@8 32
nuclear@1 33 int load_scene(struct scene *scn, const char *fname)
nuclear@1 34 {
nuclear@1 35 int i, j;
nuclear@1 36 const struct aiScene *aiscn;
nuclear@1 37 unsigned int proc_flags = aiProcess_JoinIdenticalVertices |
nuclear@1 38 aiProcess_PreTransformVertices | aiProcess_Triangulate |
nuclear@5 39 aiProcess_GenNormals | aiProcess_SortByPType | aiProcess_FlipUVs;
nuclear@1 40
nuclear@1 41 if(!(aiscn = aiImportFile(fname, proc_flags))) {
nuclear@1 42 fprintf(stderr, "failed to load: %s\n", fname);
nuclear@1 43 return -1;
nuclear@1 44 }
nuclear@1 45
nuclear@4 46 if(verbose) {
nuclear@4 47 printf("scene: %s (%d meshes, %d lights)\n", fname, aiscn->mNumMeshes, aiscn->mNumLights);
nuclear@4 48 }
nuclear@4 49
nuclear@3 50 for(i=0; i<aiscn->mNumLights; i++) {
nuclear@3 51 struct light *lt;
nuclear@3 52 struct aiLight *ailt = aiscn->mLights[i];
nuclear@3 53
nuclear@3 54 if(!(lt = malloc(sizeof *lt))) {
nuclear@3 55 perror("failed to allocate light");
nuclear@3 56 return -1;
nuclear@3 57 }
nuclear@3 58
nuclear@3 59 if(verbose) {
nuclear@3 60 printf("- light(%s) ", ailt->mName.data);
nuclear@3 61 }
nuclear@3 62
nuclear@3 63 switch(ailt->mType) {
nuclear@3 64 case aiLightSource_POINT:
nuclear@3 65 lt->pos[0] = ailt->mPosition.x;
nuclear@3 66 lt->pos[1] = ailt->mPosition.y;
nuclear@3 67 lt->pos[2] = ailt->mPosition.z;
nuclear@3 68 lt->pos[3] = 1.0f;
nuclear@3 69 if(verbose) {
nuclear@3 70 printf("pos(%.2f %.2f %.2f) ", lt->pos[0], lt->pos[1], lt->pos[2]);
nuclear@3 71 }
nuclear@3 72 break;
nuclear@3 73
nuclear@3 74 case aiLightSource_DIRECTIONAL:
nuclear@3 75 lt->pos[0] = ailt->mDirection.x;
nuclear@3 76 lt->pos[1] = ailt->mDirection.y;
nuclear@3 77 lt->pos[2] = ailt->mDirection.z;
nuclear@3 78 lt->pos[3] = 0.0f;
nuclear@3 79 if(verbose) {
nuclear@3 80 printf("dir(%.2f %.2f %.2f) ", lt->pos[0], lt->pos[1], lt->pos[2]);
nuclear@3 81 }
nuclear@3 82 break;
nuclear@3 83
nuclear@3 84 default:
nuclear@3 85 fprintf(stderr, "error loading light: %s, unsupported type\n", ailt->mName.data);
nuclear@3 86 continue;
nuclear@3 87 }
nuclear@3 88 color(lt->color, ailt->mColorDiffuse.r, ailt->mColorDiffuse.g, ailt->mColorDiffuse.b);
nuclear@3 89 if(verbose) {
nuclear@3 90 printf("col(%.2f %.2f %.2f) ", lt->color[0], lt->color[1], lt->color[2]);
nuclear@3 91 }
nuclear@3 92
nuclear@3 93 lt->cone_inner = ailt->mAngleInnerCone;
nuclear@3 94 lt->cone_outer = ailt->mAngleOuterCone;
nuclear@3 95
nuclear@3 96 lt->att[0] = ailt->mAttenuationConstant;
nuclear@3 97 lt->att[1] = ailt->mAttenuationLinear;
nuclear@3 98 lt->att[2] = ailt->mAttenuationQuadratic;
nuclear@3 99 if(verbose) {
nuclear@3 100 printf("att(%.2f %.2f %.2f)\n", lt->att[0], lt->att[1], lt->att[2]);
nuclear@3 101 }
nuclear@3 102
nuclear@3 103 lt->next = scn->lights;
nuclear@3 104 scn->lights = lt;
nuclear@3 105 }
nuclear@3 106
nuclear@8 107 /* load meshes and calculate bounding box */
nuclear@1 108 for(i=0; i<aiscn->mNumMeshes; i++) {
nuclear@1 109 struct mesh *m;
nuclear@1 110
nuclear@1 111 if(!(m = create_mesh(aiscn, aiscn->mMeshes[i]))) {
nuclear@1 112 return -1;
nuclear@1 113 }
nuclear@1 114
nuclear@1 115 for(j=0; j<3; j++) {
nuclear@1 116 if(m->bbox.min[j] < scn->bbox.min[j]) {
nuclear@1 117 scn->bbox.min[j] = m->bbox.min[j];
nuclear@1 118 }
nuclear@1 119 if(m->bbox.max[j] > scn->bbox.max[j]) {
nuclear@1 120 scn->bbox.max[j] = m->bbox.max[j];
nuclear@1 121 }
nuclear@1 122 }
nuclear@1 123
nuclear@1 124 m->next = scn->meshes;
nuclear@1 125 scn->meshes = m;
nuclear@1 126 }
nuclear@1 127
nuclear@1 128 aiReleaseImport(aiscn);
nuclear@1 129 return 0;
nuclear@1 130 }
nuclear@1 131
nuclear@1 132 static void color(float *dest, float r, float g, float b)
nuclear@1 133 {
nuclear@1 134 dest[0] = r;
nuclear@1 135 dest[1] = g;
nuclear@1 136 dest[2] = b;
nuclear@1 137 dest[3] = 1.0;
nuclear@1 138 }
nuclear@1 139
nuclear@1 140 static struct mesh *create_mesh(const struct aiScene *aiscn, struct aiMesh *aim)
nuclear@1 141 {
nuclear@1 142 int i, j;
nuclear@1 143 struct mesh *m;
nuclear@1 144 struct aiMaterial *mat = aiscn->mMaterials[aim->mMaterialIndex];
nuclear@1 145 float sstr = 1.0;
nuclear@1 146 unsigned int sz, *idxarr, *dptr;
nuclear@1 147 struct aiVector3D *vptr;
nuclear@1 148 struct aiString tex_name;
nuclear@1 149
nuclear@1 150 if(!(m = calloc(1, sizeof *m))) {
nuclear@1 151 perror("failed to allocate mesh");
nuclear@1 152 return 0;
nuclear@1 153 }
nuclear@1 154
nuclear@3 155 if(verbose) {
nuclear@3 156 printf("- mesh(%s) v:%d f:%d\n", aim->mName.data, aim->mNumVertices, aim->mNumFaces);
nuclear@3 157 }
nuclear@3 158
nuclear@1 159 /* default material */
nuclear@1 160 color(m->mat.kd, 1, 1, 1);
nuclear@1 161 color(m->mat.ks, 0, 0, 0);
nuclear@1 162 m->mat.shin = 60.0;
nuclear@1 163
nuclear@1 164 aiGetMaterialColor(mat, AI_MATKEY_COLOR_DIFFUSE, (void*)m->mat.kd);
nuclear@1 165 aiGetMaterialColor(mat, AI_MATKEY_COLOR_SPECULAR, (void*)m->mat.ks);
nuclear@1 166 sz = 1;
nuclear@1 167 aiGetMaterialFloatArray(mat, AI_MATKEY_SHININESS, &m->mat.shin, &sz);
nuclear@1 168 sz = 1;
nuclear@1 169 aiGetMaterialFloatArray(mat, AI_MATKEY_SHININESS_STRENGTH, &sstr, &sz);
nuclear@1 170 color(m->mat.ks, m->mat.ks[0] * sstr, m->mat.ks[1] * sstr, m->mat.ks[2] * sstr);
nuclear@1 171
nuclear@1 172 if(aiGetMaterialString(mat, AI_MATKEY_TEXTURE(aiTextureType_DIFFUSE, 0), &tex_name) == 0) {
nuclear@1 173 m->mat.tex = load_texture(tex_name.data);
nuclear@1 174 }
nuclear@1 175
nuclear@1 176 m->num_verts = aim->mNumVertices;
nuclear@1 177 m->num_faces = aim->mNumFaces;
nuclear@1 178
nuclear@1 179 m->bbox.min[0] = m->bbox.min[1] = m->bbox.min[2] = FLT_MAX;
nuclear@1 180 m->bbox.max[0] = m->bbox.max[1] = m->bbox.max[2] = -FLT_MAX;
nuclear@1 181
nuclear@1 182 vptr = aim->mVertices;
nuclear@1 183 for(i=0; i<m->num_verts; i++) {
nuclear@1 184 if(vptr->x < m->bbox.min[0]) m->bbox.min[0] = vptr->x;
nuclear@1 185 if(vptr->y < m->bbox.min[1]) m->bbox.min[1] = vptr->y;
nuclear@1 186 if(vptr->z < m->bbox.min[2]) m->bbox.min[2] = vptr->z;
nuclear@1 187 if(vptr->x > m->bbox.max[0]) m->bbox.max[0] = vptr->x;
nuclear@1 188 if(vptr->y > m->bbox.max[1]) m->bbox.max[1] = vptr->y;
nuclear@1 189 if(vptr->z > m->bbox.max[2]) m->bbox.max[2] = vptr->z;
nuclear@1 190 vptr++;
nuclear@1 191 }
nuclear@1 192
nuclear@1 193 m->vert_buf = create_buffer(GL_ARRAY_BUFFER, aim->mVertices, m->num_verts * sizeof *aim->mVertices);
nuclear@1 194 if(aim->mNormals) {
nuclear@1 195 m->norm_buf = create_buffer(GL_ARRAY_BUFFER, aim->mNormals, m->num_verts * sizeof *aim->mNormals);
nuclear@1 196 }
nuclear@1 197 if(aim->mTextureCoords) {
nuclear@2 198 m->tex_buf = create_buffer(GL_ARRAY_BUFFER, aim->mTextureCoords[0], m->num_verts * sizeof *aim->mTextureCoords[0]);
nuclear@1 199 }
nuclear@1 200
nuclear@1 201 /* indices are scattered all over the fucking place... map the buffer and collect them there directly */
nuclear@1 202 m->idx_buf = create_buffer(GL_ELEMENT_ARRAY_BUFFER, 0, m->num_faces * 3 * sizeof *aim->mFaces[0].mIndices);
nuclear@1 203 dptr = idxarr = glMapBuffer(GL_ELEMENT_ARRAY_BUFFER, GL_WRITE_ONLY);
nuclear@1 204
nuclear@1 205 for(i=0; i<m->num_faces; i++) {
nuclear@1 206 for(j=0; j<3; j++) {
nuclear@1 207 *dptr++ = aim->mFaces[i].mIndices[j];
nuclear@1 208 }
nuclear@1 209 }
nuclear@1 210 glUnmapBuffer(GL_ELEMENT_ARRAY_BUFFER);
nuclear@1 211 return m;
nuclear@1 212 }
nuclear@1 213
nuclear@1 214 static unsigned int create_buffer(unsigned int type, void *data, size_t sz)
nuclear@1 215 {
nuclear@1 216 unsigned int vbo;
nuclear@1 217 glGenBuffers(1, &vbo);
nuclear@1 218 glBindBuffer(type, vbo);
nuclear@1 219 glBufferData(type, sz, data, GL_STATIC_DRAW);
nuclear@1 220 return vbo;
nuclear@1 221 }
nuclear@1 222
nuclear@1 223 static unsigned int load_texture(const char *fname)
nuclear@1 224 {
nuclear@1 225 unsigned int tex;
nuclear@1 226 void *pixels;
nuclear@1 227 int xsz, ysz;
nuclear@1 228
nuclear@1 229 if(!(pixels = img_load_pixels(fname, &xsz, &ysz, IMG_FMT_RGBA32))) {
nuclear@1 230 fprintf(stderr, "failed to load image: %s\n", fname);
nuclear@1 231 return 0;
nuclear@1 232 }
nuclear@1 233
nuclear@3 234 if(verbose) {
nuclear@3 235 printf(" - texture: %s (%dx%d)\n", fname, xsz, ysz);
nuclear@3 236 }
nuclear@3 237
nuclear@1 238 glGenTextures(1, &tex);
nuclear@1 239 glBindTexture(GL_TEXTURE_2D, tex);
nuclear@1 240 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
nuclear@1 241 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
nuclear@1 242 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
nuclear@1 243 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
nuclear@1 244 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, xsz, ysz, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
nuclear@1 245
nuclear@1 246 img_free_pixels(pixels);
nuclear@1 247 return tex;
nuclear@1 248 }
nuclear@1 249
nuclear@1 250 void render_scene(struct scene *scn)
nuclear@1 251 {
nuclear@3 252 struct light *lt = scn->lights;
nuclear@3 253 int pass = 0;
nuclear@3 254
nuclear@4 255 glEnable(GL_BLEND);
nuclear@4 256 glDepthFunc(GL_LEQUAL);
nuclear@4 257
nuclear@3 258 while(lt || pass == 0) {
nuclear@3 259 struct mesh *m;
nuclear@3 260
nuclear@3 261 setup_light(lt);
nuclear@3 262
nuclear@4 263 if(pass == 0) {
nuclear@4 264 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
nuclear@4 265 } else {
nuclear@3 266 glBlendFunc(GL_SRC_ALPHA, GL_ONE);
nuclear@3 267 glDepthMask(0);
nuclear@3 268 }
nuclear@3 269
nuclear@3 270 m = scn->meshes;
nuclear@3 271 while(m) {
nuclear@3 272 render_mesh(m, pass);
nuclear@3 273 m = m->next;
nuclear@3 274 }
nuclear@3 275 pass++;
nuclear@6 276 if(lt) {
nuclear@6 277 lt = lt->next;
nuclear@6 278 }
nuclear@1 279 }
nuclear@4 280
nuclear@4 281 glDisable(GL_BLEND);
nuclear@4 282 glDepthMask(1);
nuclear@1 283 }
nuclear@1 284
nuclear@3 285 static void setup_light(struct light *lt)
nuclear@1 286 {
nuclear@3 287 if(!lt)
nuclear@3 288 return;
nuclear@3 289 glLightfv(GL_LIGHT0, GL_POSITION, lt->pos);
nuclear@3 290 glLightfv(GL_LIGHT0, GL_DIFFUSE, lt->color);
nuclear@7 291 glLightfv(GL_LIGHT0, GL_SPECULAR, lt->color);
nuclear@3 292 glLightf(GL_LIGHT0, GL_CONSTANT_ATTENUATION, lt->att[0]);
nuclear@3 293 glLightf(GL_LIGHT0, GL_LINEAR_ATTENUATION, lt->att[1]);
nuclear@3 294 glLightf(GL_LIGHT0, GL_QUADRATIC_ATTENUATION, lt->att[2]);
nuclear@3 295 glEnable(GL_LIGHT0);
nuclear@3 296 }
nuclear@3 297
nuclear@3 298 void render_mesh(struct mesh *m, int pass)
nuclear@3 299 {
nuclear@3 300 if(pass > 0) {
nuclear@3 301 float black[] = {0, 0, 0, 0};
nuclear@3 302 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, black);
nuclear@3 303 } else {
nuclear@3 304 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, m->mat.kd);
nuclear@3 305 }
nuclear@3 306 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, m->mat.kd);
nuclear@1 307 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, m->mat.ks);
nuclear@1 308 glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, m->mat.shin);
nuclear@1 309
nuclear@1 310 if(m->mat.tex) {
nuclear@1 311 glEnable(GL_TEXTURE_2D);
nuclear@1 312 glBindTexture(GL_TEXTURE_2D, m->mat.tex);
nuclear@1 313 }
nuclear@1 314
nuclear@1 315 glBindBuffer(GL_ARRAY_BUFFER, m->vert_buf);
nuclear@1 316 glVertexPointer(3, GL_FLOAT, 0, 0);
nuclear@1 317 glEnableClientState(GL_VERTEX_ARRAY);
nuclear@1 318
nuclear@1 319 if(m->norm_buf) {
nuclear@1 320 glBindBuffer(GL_ARRAY_BUFFER, m->norm_buf);
nuclear@1 321 glNormalPointer(GL_FLOAT, 0, 0);
nuclear@1 322 glEnableClientState(GL_NORMAL_ARRAY);
nuclear@1 323 }
nuclear@1 324 if(m->tex_buf) {
nuclear@1 325 glBindBuffer(GL_ARRAY_BUFFER, m->tex_buf);
nuclear@1 326 glTexCoordPointer(3, GL_FLOAT, 0, 0);
nuclear@1 327 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
nuclear@1 328 }
nuclear@1 329
nuclear@1 330 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m->idx_buf);
nuclear@1 331 glDrawElements(GL_TRIANGLES, m->num_faces * 3, GL_UNSIGNED_INT, 0);
nuclear@1 332
nuclear@1 333 glDisableClientState(GL_VERTEX_ARRAY);
nuclear@1 334 glDisableClientState(GL_NORMAL_ARRAY);
nuclear@1 335 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
nuclear@1 336
nuclear@1 337 if(m->mat.tex) {
nuclear@1 338 glDisable(GL_TEXTURE_2D);
nuclear@1 339 }
nuclear@1 340 }