dos3d

annotate src/scene.c @ 19:c10f62b2bd56

foo
author John Tsiombikas <nuclear@member.fsf.org>
date Wed, 30 Nov 2011 07:17:09 +0200
parents 1e9f0b3616fa
children
rev   line source
nuclear@16 1 #include <stdio.h>
nuclear@16 2 #include <stdlib.h>
nuclear@16 3 #include <string.h>
nuclear@16 4 #include <ctype.h>
nuclear@16 5 #include <errno.h>
nuclear@19 6 #include <assert.h>
nuclear@16 7 #include "scene.h"
nuclear@16 8 #include "cvec.h"
nuclear@17 9 #include "palman.h"
nuclear@17 10
nuclear@17 11 #ifdef USE_GL
nuclear@17 12 #include <GL/gl.h>
nuclear@17 13 #else
nuclear@16 14 #include "mingl.h"
nuclear@17 15 #endif
nuclear@16 16
nuclear@16 17
nuclear@16 18 struct face {
nuclear@16 19 int v[3], n[3], t[3];
nuclear@16 20 };
nuclear@16 21
nuclear@16 22 static int load_materials(struct scene *scn, const char *fname);
nuclear@16 23 static int parse_face(struct face *face, char *buf);
nuclear@16 24
nuclear@16 25
nuclear@16 26 /* --- scene --- */
nuclear@16 27 int scn_init(struct scene *scn)
nuclear@16 28 {
nuclear@16 29 memset(scn, 0, sizeof *scn);
nuclear@16 30 return 0;
nuclear@16 31 }
nuclear@16 32
nuclear@16 33 void scn_destroy(struct scene *scn)
nuclear@16 34 {
nuclear@16 35 while(scn->matlist) {
nuclear@16 36 struct material *tmp = scn->matlist;
nuclear@16 37 scn->matlist = scn->matlist->next;
nuclear@16 38
nuclear@16 39 mtl_destroy(tmp);
nuclear@16 40 free(tmp);
nuclear@16 41 }
nuclear@16 42 while(scn->meshlist) {
nuclear@16 43 struct mesh *tmp = scn->meshlist;
nuclear@16 44 scn->meshlist = scn->meshlist->next;
nuclear@16 45
nuclear@16 46 mesh_destroy(tmp);
nuclear@16 47 free(tmp);
nuclear@16 48 }
nuclear@16 49 }
nuclear@16 50
nuclear@16 51
nuclear@16 52 void scn_add_mesh(struct scene *scn, struct mesh *m)
nuclear@16 53 {
nuclear@16 54 printf("adding mesh: %d faces\n", m->nface);
nuclear@16 55 m->next = scn->meshlist;
nuclear@16 56 scn->meshlist = m;
nuclear@16 57 }
nuclear@16 58
nuclear@16 59 void scn_add_material(struct scene *scn, struct material *m)
nuclear@16 60 {
nuclear@16 61 printf("adding material: %s\n", m->name);
nuclear@16 62 m->next = scn->matlist;
nuclear@16 63 scn->matlist = m;
nuclear@16 64 }
nuclear@16 65
nuclear@16 66 struct material *scn_find_material(struct scene *scn, const char *name)
nuclear@16 67 {
nuclear@16 68 struct material *mtl = scn->matlist;
nuclear@16 69
nuclear@16 70 while(mtl) {
nuclear@16 71 if(strcmp(mtl->name, name) == 0) {
nuclear@16 72 break;
nuclear@16 73 }
nuclear@16 74 mtl = mtl->next;
nuclear@16 75 }
nuclear@16 76 return mtl;
nuclear@16 77 }
nuclear@16 78
nuclear@16 79 #define SEP " \t\n\r"
nuclear@16 80 int scn_load(struct scene *scn, const char *fname)
nuclear@16 81 {
nuclear@16 82 FILE *fp;
nuclear@16 83 char buf[256];
nuclear@16 84 struct mesh *m;
nuclear@16 85 vec3_t *varr, *vnarr;
nuclear@16 86 vec2_t *vtarr;
nuclear@16 87
nuclear@16 88 if(!(fp = fopen(fname, "rb"))) {
nuclear@16 89 fprintf(stderr, "failed to open scene file: %s: %s\n", fname, strerror(errno));
nuclear@16 90 return -1;
nuclear@16 91 }
nuclear@16 92
nuclear@16 93 varr = cvec_alloc(0, sizeof *varr);
nuclear@16 94 vnarr = cvec_alloc(0, sizeof *vnarr);
nuclear@16 95 vtarr = cvec_alloc(0, sizeof *vtarr);
nuclear@16 96
nuclear@16 97 if(!(m = malloc(sizeof *m)) || mesh_init(m) == -1) {
nuclear@16 98 fprintf(stderr, "meshed up\n");
nuclear@16 99 fclose(fp);
nuclear@16 100 return -1;
nuclear@16 101 }
nuclear@16 102
nuclear@16 103 while(fgets(buf, sizeof buf, fp)) {
nuclear@16 104 char *line = buf;
nuclear@16 105 char *tok, *rest, *tmp;
nuclear@16 106
nuclear@16 107 while(*line && isspace(*line)) {
nuclear@16 108 line++;
nuclear@16 109 }
nuclear@16 110 if(*line == 0 || *line == '#') {
nuclear@16 111 continue;
nuclear@16 112 }
nuclear@16 113
nuclear@16 114 if(!(tok = strtok(line, SEP))) {
nuclear@16 115 continue;
nuclear@16 116 }
nuclear@16 117 rest = tok + strlen(tok) + 1;
nuclear@16 118
nuclear@16 119 if((tmp = strchr(rest, '\r')) || (tmp = strchr(rest, '\n'))) {
nuclear@16 120 *tmp = 0;
nuclear@16 121 }
nuclear@16 122
nuclear@16 123 if(strcmp(tok, "mtllib") == 0) {
nuclear@16 124 if(!rest) {
nuclear@16 125 fprintf(stderr, "invalid mtllib directive\n");
nuclear@16 126 continue;
nuclear@16 127 }
nuclear@16 128 load_materials(scn, rest);
nuclear@16 129
nuclear@16 130 } else if(strcmp(tok, "usemtl") == 0) {
nuclear@16 131 if(rest) {
nuclear@16 132 m->mtl = scn_find_material(scn, rest);
nuclear@16 133 }
nuclear@16 134
nuclear@16 135 } else if(strcmp(tok, "o") == 0 || strcmp(tok, "g") == 0) {
nuclear@16 136 if(cvec_size(m->vert) > 0) {
nuclear@16 137 scn_add_mesh(scn, m);
nuclear@16 138
nuclear@16 139 if(!(m = malloc(sizeof *m)) || mesh_init(m) == -1) {
nuclear@16 140 fprintf(stderr, "meshed up\n");
nuclear@16 141 fclose(fp);
nuclear@16 142 return -1;
nuclear@16 143 }
nuclear@16 144 }
nuclear@16 145
nuclear@16 146 } else if(strcmp(tok, "v") == 0) {
nuclear@16 147 vec3_t v;
nuclear@16 148
nuclear@16 149 if(!rest || sscanf(rest, "%f %f %f\n", &v.x, &v.y, &v.z) != 3) {
nuclear@16 150 continue;
nuclear@16 151 }
nuclear@16 152 varr = cvec_append(varr, &v);
nuclear@16 153
nuclear@16 154 } else if(strcmp(tok, "vn") == 0) {
nuclear@16 155 vec3_t v;
nuclear@16 156
nuclear@16 157 if(!rest || sscanf(rest, "%f %f %f\n", &v.x, &v.y, &v.z) != 3) {
nuclear@16 158 continue;
nuclear@16 159 }
nuclear@16 160 vnarr = cvec_append(vnarr, &v);
nuclear@16 161
nuclear@16 162 } else if(strcmp(tok, "vt") == 0) {
nuclear@19 163 vec2_t v;
nuclear@16 164
nuclear@19 165 if(!rest || sscanf(rest, "%f %f\n", &v.x, &v.y) != 2) {
nuclear@16 166 continue;
nuclear@16 167 }
nuclear@19 168 v.y = 1.0 - v.y;
nuclear@16 169 vtarr = cvec_append(vtarr, &v);
nuclear@16 170
nuclear@16 171 } else if(strcmp(tok, "f") == 0) {
nuclear@16 172 int i;
nuclear@16 173 struct face face;
nuclear@16 174
nuclear@16 175 if(!rest || parse_face(&face, rest) == -1) {
nuclear@16 176 continue;
nuclear@16 177 }
nuclear@16 178
nuclear@16 179 for(i=0; i<3; i++) {
nuclear@16 180 int vidx = face.v[i];
nuclear@16 181 int nidx = face.n[i];
nuclear@16 182 int tidx = face.t[i];
nuclear@16 183
nuclear@16 184 mesh_add_vertex(m, varr[vidx]);
nuclear@16 185 if(nidx >= 0) {
nuclear@16 186 mesh_add_normal(m, vnarr[nidx]);
nuclear@16 187 }
nuclear@16 188 if(tidx >= 0) {
nuclear@16 189 mesh_add_texcoord(m, vtarr[tidx]);
nuclear@16 190 }
nuclear@16 191 m->nface++;
nuclear@16 192 }
nuclear@16 193 }
nuclear@16 194
nuclear@16 195 }
nuclear@16 196 fclose(fp);
nuclear@16 197
nuclear@16 198 if(cvec_size(m->vert) > 0) {
nuclear@16 199 scn_add_mesh(scn, m);
nuclear@16 200 }
nuclear@16 201
nuclear@16 202 cvec_free(varr);
nuclear@16 203 cvec_free(vnarr);
nuclear@16 204 cvec_free(vtarr);
nuclear@16 205
nuclear@16 206 return 0;
nuclear@16 207 }
nuclear@16 208
nuclear@16 209 static int load_materials(struct scene *scn, const char *fname)
nuclear@16 210 {
nuclear@16 211 FILE *fp;
nuclear@16 212 struct material *m = 0;
nuclear@16 213 char buf[256];
nuclear@16 214
nuclear@16 215 if(!(fp = fopen(fname, "r"))) {
nuclear@16 216 fprintf(stderr, "failed to load material file: %s: %s\n", fname, strerror(errno));
nuclear@16 217 return -1;
nuclear@16 218 }
nuclear@16 219
nuclear@16 220 while(fgets(buf, sizeof buf, fp)) {
nuclear@16 221 char *line = buf;
nuclear@16 222 char *tok, *rest, *tmp;
nuclear@16 223
nuclear@16 224 while(*line && isspace(*line)) {
nuclear@16 225 line++;
nuclear@16 226 }
nuclear@16 227 if(*line == 0 || *line == '#') {
nuclear@16 228 continue;
nuclear@16 229 }
nuclear@16 230
nuclear@16 231 if(!(tok = strtok(line, SEP))) {
nuclear@16 232 continue;
nuclear@16 233 }
nuclear@16 234 rest = tok + strlen(tok) + 1;
nuclear@16 235
nuclear@16 236 if((tmp = strchr(rest, '\r')) || (tmp = strchr(rest, '\n'))) {
nuclear@16 237 *tmp = 0;
nuclear@16 238 }
nuclear@16 239
nuclear@16 240 if(strcmp(tok, "newmtl") == 0) {
nuclear@16 241 if(m) {
nuclear@17 242 if(!m->tex) {
nuclear@17 243 palm_add_color(m->kd[0], m->kd[1], m->kd[2]);
nuclear@17 244 }
nuclear@16 245 scn_add_material(scn, m);
nuclear@16 246 }
nuclear@16 247 if(!(m = malloc(sizeof *m)) || mtl_init(m) == -1) {
nuclear@16 248 continue;
nuclear@16 249 }
nuclear@16 250 mtl_set_name(m, rest);
nuclear@16 251
nuclear@16 252 } else if(strcmp(tok, "Kd") == 0) {
nuclear@17 253 float r, g, b;
nuclear@17 254 if(sscanf(rest, "%f %f %f", &r, &g, &b) != 3) {
nuclear@16 255 continue;
nuclear@16 256 }
nuclear@17 257 m->kd[0] = (int)(r * 255.0);
nuclear@17 258 m->kd[1] = (int)(g * 255.0);
nuclear@17 259 m->kd[2] = (int)(b * 255.0);
nuclear@17 260
nuclear@16 261 } else if(strcmp(tok, "map_Kd") == 0) {
nuclear@17 262 if(!(m->tex = load_texture(rest))) {
nuclear@17 263 fprintf(stderr, "failed to load texture: `%s'\n", rest);
nuclear@17 264 }
nuclear@16 265 }
nuclear@16 266 }
nuclear@16 267
nuclear@16 268 if(m) {
nuclear@17 269 if(!m->tex) {
nuclear@17 270 palm_add_color(m->kd[0], m->kd[1], m->kd[2]);
nuclear@17 271 }
nuclear@16 272 scn_add_material(scn, m);
nuclear@16 273 }
nuclear@16 274
nuclear@16 275 fclose(fp);
nuclear@16 276 return 0;
nuclear@16 277 }
nuclear@16 278
nuclear@16 279 static int parse_face(struct face *face, char *buf)
nuclear@16 280 {
nuclear@16 281 int i, found;
nuclear@16 282 char *tok;
nuclear@16 283
nuclear@16 284 for(i=0; i<3; i++) {
nuclear@16 285 tok = strtok(i > 0 ? 0 : buf, SEP);
nuclear@16 286 found = sscanf(tok, "%d/%d/%d", &face->v[i], &face->t[i], &face->n[i]);
nuclear@16 287
nuclear@16 288 face->v[i]--;
nuclear@16 289
nuclear@16 290 if(found > 1) {
nuclear@16 291 face->t[i]--;
nuclear@16 292 } else {
nuclear@16 293 face->t[i] = -1;
nuclear@16 294 }
nuclear@16 295 if(found > 2) {
nuclear@16 296 face->n[i]--;
nuclear@16 297 } else {
nuclear@16 298 face->n[i] = -1;
nuclear@16 299 }
nuclear@16 300 }
nuclear@16 301 return 0;
nuclear@16 302 }
nuclear@16 303
nuclear@16 304 void scn_render(struct scene *scn)
nuclear@16 305 {
nuclear@17 306 struct mesh *m;
nuclear@16 307
nuclear@17 308 if(!scn->ready) {
nuclear@17 309 struct material *mtl = scn->matlist;
nuclear@17 310 while(mtl) {
nuclear@17 311 if(mtl->tex) {
nuclear@17 312 get_texture_pixels(mtl->tex);
nuclear@17 313 #ifdef USE_GL
nuclear@17 314 {
nuclear@17 315 int i, npix = mtl->tex->width * mtl->tex->height;
nuclear@17 316 int range = palm_color_range();
nuclear@17 317 unsigned char *rgb = malloc(npix * 3);
nuclear@17 318 struct palm_color *pal = palm_palette();
nuclear@17 319
nuclear@17 320 for(i=0; i<npix; i++) {
nuclear@17 321 int idx = mtl->tex->pixels[i] + range - 1;
nuclear@17 322 rgb[i * 3] = pal[idx].r;
nuclear@17 323 rgb[i * 3 + 1] = pal[idx].g;
nuclear@17 324 rgb[i * 3 + 2] = pal[idx].b;
nuclear@17 325 }
nuclear@17 326 free(mtl->tex->pixels);
nuclear@17 327 mtl->tex->pixels = rgb;
nuclear@17 328 }
nuclear@17 329 #endif /* USE_GL */
nuclear@17 330 } else {
nuclear@17 331 mtl->kd_base = palm_color_base(mtl->kd[0], mtl->kd[1], mtl->kd[2]);
nuclear@17 332 }
nuclear@17 333 mtl = mtl->next;
nuclear@17 334 }
nuclear@17 335 scn->ready = 1;
nuclear@17 336 }
nuclear@17 337
nuclear@17 338 m = scn->meshlist;
nuclear@16 339 while(m) {
nuclear@16 340 mesh_draw(m);
nuclear@16 341 m = m->next;
nuclear@16 342 }
nuclear@19 343
nuclear@19 344 #if 0
nuclear@19 345 {
nuclear@19 346 int i;
nuclear@19 347 struct palm_color *pal = palm_palette();
nuclear@19 348 float dx = 1.8 / 256;
nuclear@19 349 struct material *mtl = scn->matlist;
nuclear@19 350
nuclear@19 351 glMatrixMode(GL_MODELVIEW);
nuclear@19 352 glPushMatrix();
nuclear@19 353 glLoadIdentity();
nuclear@19 354 glMatrixMode(GL_PROJECTION);
nuclear@19 355 glPushMatrix();
nuclear@19 356 glLoadIdentity();
nuclear@19 357
nuclear@19 358 glPushAttrib(GL_ENABLE_BIT);
nuclear@19 359 glDisable(GL_LIGHTING);
nuclear@19 360 glDisable(GL_DEPTH_TEST);
nuclear@19 361
nuclear@19 362 glBegin(GL_QUADS);
nuclear@19 363 for(i=0; i<255; i++) {
nuclear@19 364 float x = i * dx - 0.9;
nuclear@19 365 glColor3ub(pal[i].r, pal[i].g, pal[i].b);
nuclear@19 366 glVertex2f(x, 0.98);
nuclear@19 367 glVertex2f(x, 0.9);
nuclear@19 368 glColor3ub(pal[i + 1].r, pal[i + 1].g, pal[i + 1].b);
nuclear@19 369 glVertex2f(x + dx, 0.9);
nuclear@19 370 glVertex2f(x + dx, 0.98);
nuclear@19 371 }
nuclear@19 372 glEnd();
nuclear@19 373
nuclear@19 374 glPopAttrib();
nuclear@19 375
nuclear@19 376 glMatrixMode(GL_PROJECTION);
nuclear@19 377 glPopMatrix();
nuclear@19 378 glMatrixMode(GL_MODELVIEW);
nuclear@19 379 glPopMatrix();
nuclear@19 380 }
nuclear@19 381 #endif
nuclear@16 382 }
nuclear@16 383
nuclear@16 384 /* --- material --- */
nuclear@16 385 int mtl_init(struct material *mtl)
nuclear@16 386 {
nuclear@16 387 memset(mtl, 0, sizeof *mtl);
nuclear@16 388 return 0;
nuclear@16 389 }
nuclear@16 390
nuclear@16 391 void mtl_destroy(struct material *mtl)
nuclear@16 392 {
nuclear@16 393 free(mtl->name);
nuclear@16 394
nuclear@16 395 if(mtl->tex) {
nuclear@16 396 free_texture(mtl->tex);
nuclear@16 397 }
nuclear@16 398 }
nuclear@16 399
nuclear@16 400
nuclear@16 401 int mtl_set_name(struct material *mtl, const char *name)
nuclear@16 402 {
nuclear@16 403 char *tmp;
nuclear@16 404 int len = strlen(name);
nuclear@16 405
nuclear@16 406 if(!(tmp = malloc(len + 1))) {
nuclear@16 407 perror("failed to allocate material name");
nuclear@16 408 return -1;
nuclear@16 409 }
nuclear@16 410 memcpy(tmp, name, len);
nuclear@16 411 tmp[len] = 0;
nuclear@16 412
nuclear@16 413 free(mtl->name);
nuclear@16 414 mtl->name = tmp;
nuclear@16 415 return 0;
nuclear@16 416 }
nuclear@16 417
nuclear@16 418
nuclear@16 419 /* --- mesh --- */
nuclear@16 420 int mesh_init(struct mesh *m)
nuclear@16 421 {
nuclear@16 422 memset(m, 0, sizeof *m);
nuclear@16 423
nuclear@16 424 m->vert = cvec_alloc(0, sizeof *m->vert);
nuclear@16 425 m->norm = cvec_alloc(0, sizeof *m->norm);
nuclear@16 426 m->texcoord = cvec_alloc(0, sizeof *m->texcoord);
nuclear@16 427
nuclear@16 428 if(!m->vert || !m->norm || !m->texcoord) {
nuclear@16 429 return -1;
nuclear@16 430 }
nuclear@16 431 return 0;
nuclear@16 432 }
nuclear@16 433
nuclear@16 434 void mesh_destroy(struct mesh *m)
nuclear@16 435 {
nuclear@16 436 cvec_free(m->vert);
nuclear@16 437 cvec_free(m->norm);
nuclear@16 438 cvec_free(m->texcoord);
nuclear@16 439 }
nuclear@16 440
nuclear@16 441 void mesh_add_vertex(struct mesh *m, vec3_t v)
nuclear@16 442 {
nuclear@16 443 m->vert = cvec_append(m->vert, &v);
nuclear@16 444 }
nuclear@16 445
nuclear@16 446 void mesh_add_normal(struct mesh *m, vec3_t n)
nuclear@16 447 {
nuclear@16 448 m->norm = cvec_append(m->norm, &n);
nuclear@16 449 }
nuclear@16 450
nuclear@16 451 void mesh_add_texcoord(struct mesh *m, vec2_t tc)
nuclear@16 452 {
nuclear@16 453 m->texcoord = cvec_append(m->texcoord, &tc);
nuclear@16 454 }
nuclear@16 455
nuclear@16 456 void mesh_draw(struct mesh *m)
nuclear@16 457 {
nuclear@16 458 int i, numv;
nuclear@17 459 struct material *mtl = m->mtl;
nuclear@17 460
nuclear@17 461 numv = cvec_size(m->vert);
nuclear@17 462
nuclear@17 463 #ifdef USE_GL
nuclear@17 464 if(mtl->tex) {
nuclear@19 465 assert(mtl->tex->pixels);
nuclear@17 466 glEnable(GL_TEXTURE_2D);
nuclear@17 467 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
nuclear@17 468 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
nuclear@17 469 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
nuclear@17 470 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
nuclear@17 471
nuclear@17 472 glTexImage2D(GL_TEXTURE_2D, 0, 3, mtl->tex->width, mtl->tex->height, 0, GL_RGB, GL_UNSIGNED_BYTE, mtl->tex->pixels);
nuclear@17 473 }
nuclear@17 474
nuclear@17 475 glBegin(GL_TRIANGLES);
nuclear@17 476 for(i=0; i<numv; i++) {
nuclear@17 477 glNormal3f(m->norm[i].x, m->norm[i].y, m->norm[i].z);
nuclear@17 478 glTexCoord2f(m->texcoord[i].x, m->texcoord[i].y);
nuclear@17 479 glVertex3f(m->vert[i].x, m->vert[i].y, m->vert[i].z);
nuclear@17 480 }
nuclear@17 481 glEnd();
nuclear@17 482
nuclear@17 483 if(mtl->tex) {
nuclear@17 484 glDisable(GL_TEXTURE_2D);
nuclear@17 485 }
nuclear@17 486 #else
nuclear@17 487 if(mtl->tex) {
nuclear@19 488 mgl_enable(MGL_TEXTURE_2D);
nuclear@17 489 mgl_teximage(mtl->tex->width, mtl->tex->height, mtl->tex->pixels);
nuclear@17 490 } else {
nuclear@17 491 mgl_index(mtl->kd_base);
nuclear@17 492 }
nuclear@16 493
nuclear@16 494 mgl_begin(MGL_TRIANGLES);
nuclear@16 495
nuclear@16 496 for(i=0; i<numv; i++) {
nuclear@16 497 mgl_normal(m->norm[i].x, m->norm[i].y, m->norm[i].z);
nuclear@16 498 mgl_texcoord2f(m->texcoord[i].x, m->texcoord[i].y);
nuclear@16 499 mgl_vertex3f(m->vert[i].x, m->vert[i].y, m->vert[i].z);
nuclear@16 500 }
nuclear@17 501 mgl_end();
nuclear@16 502
nuclear@17 503 if(mtl->tex) {
nuclear@17 504 mgl_disable(MGL_TEXTURE_2D);
nuclear@17 505 }
nuclear@17 506 #endif
nuclear@16 507 }