deepstone
view src/scene.c @ 18:777be77b6432
foo
author | John Tsiombikas <nuclear@member.fsf.org> |
---|---|
date | Wed, 30 Nov 2011 00:06:28 +0200 |
parents | cb676ff89e69 |
children | c10f62b2bd56 |
line source
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <ctype.h>
5 #include <errno.h>
6 #include "scene.h"
7 #include "cvec.h"
8 #include "palman.h"
10 #ifdef USE_GL
11 #include <GL/gl.h>
12 #else
13 #include "mingl.h"
14 #endif
17 struct face {
18 int v[3], n[3], t[3];
19 };
21 static int load_materials(struct scene *scn, const char *fname);
22 static int parse_face(struct face *face, char *buf);
25 /* --- scene --- */
26 int scn_init(struct scene *scn)
27 {
28 memset(scn, 0, sizeof *scn);
29 return 0;
30 }
32 void scn_destroy(struct scene *scn)
33 {
34 while(scn->matlist) {
35 struct material *tmp = scn->matlist;
36 scn->matlist = scn->matlist->next;
38 mtl_destroy(tmp);
39 free(tmp);
40 }
41 while(scn->meshlist) {
42 struct mesh *tmp = scn->meshlist;
43 scn->meshlist = scn->meshlist->next;
45 mesh_destroy(tmp);
46 free(tmp);
47 }
48 }
51 void scn_add_mesh(struct scene *scn, struct mesh *m)
52 {
53 printf("adding mesh: %d faces\n", m->nface);
54 m->next = scn->meshlist;
55 scn->meshlist = m;
56 }
58 void scn_add_material(struct scene *scn, struct material *m)
59 {
60 printf("adding material: %s\n", m->name);
61 m->next = scn->matlist;
62 scn->matlist = m;
63 }
65 struct material *scn_find_material(struct scene *scn, const char *name)
66 {
67 struct material *mtl = scn->matlist;
69 while(mtl) {
70 if(strcmp(mtl->name, name) == 0) {
71 break;
72 }
73 mtl = mtl->next;
74 }
75 return mtl;
76 }
78 #define SEP " \t\n\r"
79 int scn_load(struct scene *scn, const char *fname)
80 {
81 FILE *fp;
82 char buf[256];
83 struct mesh *m;
84 vec3_t *varr, *vnarr;
85 vec2_t *vtarr;
87 if(!(fp = fopen(fname, "rb"))) {
88 fprintf(stderr, "failed to open scene file: %s: %s\n", fname, strerror(errno));
89 return -1;
90 }
92 varr = cvec_alloc(0, sizeof *varr);
93 vnarr = cvec_alloc(0, sizeof *vnarr);
94 vtarr = cvec_alloc(0, sizeof *vtarr);
96 if(!(m = malloc(sizeof *m)) || mesh_init(m) == -1) {
97 fprintf(stderr, "meshed up\n");
98 fclose(fp);
99 return -1;
100 }
102 while(fgets(buf, sizeof buf, fp)) {
103 char *line = buf;
104 char *tok, *rest, *tmp;
106 while(*line && isspace(*line)) {
107 line++;
108 }
109 if(*line == 0 || *line == '#') {
110 continue;
111 }
113 if(!(tok = strtok(line, SEP))) {
114 continue;
115 }
116 rest = tok + strlen(tok) + 1;
118 if((tmp = strchr(rest, '\r')) || (tmp = strchr(rest, '\n'))) {
119 *tmp = 0;
120 }
122 if(strcmp(tok, "mtllib") == 0) {
123 if(!rest) {
124 fprintf(stderr, "invalid mtllib directive\n");
125 continue;
126 }
127 load_materials(scn, rest);
129 } else if(strcmp(tok, "usemtl") == 0) {
130 if(rest) {
131 m->mtl = scn_find_material(scn, rest);
132 }
134 } else if(strcmp(tok, "o") == 0 || strcmp(tok, "g") == 0) {
135 if(cvec_size(m->vert) > 0) {
136 scn_add_mesh(scn, m);
138 if(!(m = malloc(sizeof *m)) || mesh_init(m) == -1) {
139 fprintf(stderr, "meshed up\n");
140 fclose(fp);
141 return -1;
142 }
143 }
145 } else if(strcmp(tok, "v") == 0) {
146 vec3_t v;
148 if(!rest || sscanf(rest, "%f %f %f\n", &v.x, &v.y, &v.z) != 3) {
149 continue;
150 }
151 varr = cvec_append(varr, &v);
153 } else if(strcmp(tok, "vn") == 0) {
154 vec3_t v;
156 if(!rest || sscanf(rest, "%f %f %f\n", &v.x, &v.y, &v.z) != 3) {
157 continue;
158 }
159 vnarr = cvec_append(vnarr, &v);
161 } else if(strcmp(tok, "vt") == 0) {
162 vec3_t v;
164 if(!rest || sscanf(rest, "%f %f %f\n", &v.x, &v.y, &v.z) != 3) {
165 continue;
166 }
167 vtarr = cvec_append(vtarr, &v);
169 } else if(strcmp(tok, "f") == 0) {
170 int i;
171 struct face face;
173 if(!rest || parse_face(&face, rest) == -1) {
174 continue;
175 }
177 for(i=0; i<3; i++) {
178 int vidx = face.v[i];
179 int nidx = face.n[i];
180 int tidx = face.t[i];
182 mesh_add_vertex(m, varr[vidx]);
183 if(nidx >= 0) {
184 mesh_add_normal(m, vnarr[nidx]);
185 }
186 if(tidx >= 0) {
187 mesh_add_texcoord(m, vtarr[tidx]);
188 }
189 m->nface++;
190 }
191 }
193 }
194 fclose(fp);
196 if(cvec_size(m->vert) > 0) {
197 scn_add_mesh(scn, m);
198 }
200 cvec_free(varr);
201 cvec_free(vnarr);
202 cvec_free(vtarr);
204 return 0;
205 }
207 static int load_materials(struct scene *scn, const char *fname)
208 {
209 FILE *fp;
210 struct material *m = 0;
211 char buf[256];
213 if(!(fp = fopen(fname, "r"))) {
214 fprintf(stderr, "failed to load material file: %s: %s\n", fname, strerror(errno));
215 return -1;
216 }
218 while(fgets(buf, sizeof buf, fp)) {
219 char *line = buf;
220 char *tok, *rest, *tmp;
222 while(*line && isspace(*line)) {
223 line++;
224 }
225 if(*line == 0 || *line == '#') {
226 continue;
227 }
229 if(!(tok = strtok(line, SEP))) {
230 continue;
231 }
232 rest = tok + strlen(tok) + 1;
234 if((tmp = strchr(rest, '\r')) || (tmp = strchr(rest, '\n'))) {
235 *tmp = 0;
236 }
238 if(strcmp(tok, "newmtl") == 0) {
239 if(m) {
240 if(!m->tex) {
241 palm_add_color(m->kd[0], m->kd[1], m->kd[2]);
242 }
243 scn_add_material(scn, m);
244 }
245 if(!(m = malloc(sizeof *m)) || mtl_init(m) == -1) {
246 continue;
247 }
248 mtl_set_name(m, rest);
250 } else if(strcmp(tok, "Kd") == 0) {
251 float r, g, b;
252 if(sscanf(rest, "%f %f %f", &r, &g, &b) != 3) {
253 continue;
254 }
255 m->kd[0] = (int)(r * 255.0);
256 m->kd[1] = (int)(g * 255.0);
257 m->kd[2] = (int)(b * 255.0);
259 } else if(strcmp(tok, "map_Kd") == 0) {
260 if(!(m->tex = load_texture(rest))) {
261 fprintf(stderr, "failed to load texture: `%s'\n", rest);
262 }
263 }
264 }
266 if(m) {
267 if(!m->tex) {
268 palm_add_color(m->kd[0], m->kd[1], m->kd[2]);
269 }
270 scn_add_material(scn, m);
271 }
273 fclose(fp);
274 return 0;
275 }
277 static int parse_face(struct face *face, char *buf)
278 {
279 int i, found;
280 char *tok;
282 for(i=0; i<3; i++) {
283 tok = strtok(i > 0 ? 0 : buf, SEP);
284 found = sscanf(tok, "%d/%d/%d", &face->v[i], &face->t[i], &face->n[i]);
286 face->v[i]--;
288 if(found > 1) {
289 face->t[i]--;
290 } else {
291 face->t[i] = -1;
292 }
293 if(found > 2) {
294 face->n[i]--;
295 } else {
296 face->n[i] = -1;
297 }
298 }
299 return 0;
300 }
302 void scn_render(struct scene *scn)
303 {
304 struct mesh *m;
306 if(!scn->ready) {
307 struct material *mtl = scn->matlist;
308 while(mtl) {
309 if(mtl->tex) {
310 get_texture_pixels(mtl->tex);
311 #ifdef USE_GL
312 {
313 int i, npix = mtl->tex->width * mtl->tex->height;
314 int range = palm_color_range();
315 unsigned char *rgb = malloc(npix * 3);
316 struct palm_color *pal = palm_palette();
318 for(i=0; i<npix; i++) {
319 int idx = mtl->tex->pixels[i] + range - 1;
320 rgb[i * 3] = pal[idx].r;
321 rgb[i * 3 + 1] = pal[idx].g;
322 rgb[i * 3 + 2] = pal[idx].b;
323 }
324 free(mtl->tex->pixels);
325 mtl->tex->pixels = rgb;
326 }
327 #endif /* USE_GL */
328 } else {
329 mtl->kd_base = palm_color_base(mtl->kd[0], mtl->kd[1], mtl->kd[2]);
330 }
331 mtl = mtl->next;
332 }
333 scn->ready = 1;
334 }
336 m = scn->meshlist;
337 while(m) {
338 mesh_draw(m);
339 m = m->next;
340 }
341 }
343 /* --- material --- */
344 int mtl_init(struct material *mtl)
345 {
346 memset(mtl, 0, sizeof *mtl);
347 return 0;
348 }
350 void mtl_destroy(struct material *mtl)
351 {
352 free(mtl->name);
354 if(mtl->tex) {
355 free_texture(mtl->tex);
356 }
357 }
360 int mtl_set_name(struct material *mtl, const char *name)
361 {
362 char *tmp;
363 int len = strlen(name);
365 if(!(tmp = malloc(len + 1))) {
366 perror("failed to allocate material name");
367 return -1;
368 }
369 memcpy(tmp, name, len);
370 tmp[len] = 0;
372 free(mtl->name);
373 mtl->name = tmp;
374 return 0;
375 }
378 /* --- mesh --- */
379 int mesh_init(struct mesh *m)
380 {
381 memset(m, 0, sizeof *m);
383 m->vert = cvec_alloc(0, sizeof *m->vert);
384 m->norm = cvec_alloc(0, sizeof *m->norm);
385 m->texcoord = cvec_alloc(0, sizeof *m->texcoord);
387 if(!m->vert || !m->norm || !m->texcoord) {
388 return -1;
389 }
390 return 0;
391 }
393 void mesh_destroy(struct mesh *m)
394 {
395 cvec_free(m->vert);
396 cvec_free(m->norm);
397 cvec_free(m->texcoord);
398 }
400 void mesh_add_vertex(struct mesh *m, vec3_t v)
401 {
402 m->vert = cvec_append(m->vert, &v);
403 }
405 void mesh_add_normal(struct mesh *m, vec3_t n)
406 {
407 m->norm = cvec_append(m->norm, &n);
408 }
410 void mesh_add_texcoord(struct mesh *m, vec2_t tc)
411 {
412 m->texcoord = cvec_append(m->texcoord, &tc);
413 }
415 void mesh_draw(struct mesh *m)
416 {
417 int i, numv;
418 struct material *mtl = m->mtl;
420 numv = cvec_size(m->vert);
422 #ifdef USE_GL
423 if(mtl->tex) {
424 glEnable(GL_TEXTURE_2D);
425 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
426 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
427 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
428 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
430 glTexImage2D(GL_TEXTURE_2D, 0, 3, mtl->tex->width, mtl->tex->height, 0, GL_RGB, GL_UNSIGNED_BYTE, mtl->tex->pixels);
431 }
433 glBegin(GL_TRIANGLES);
434 for(i=0; i<numv; i++) {
435 glNormal3f(m->norm[i].x, m->norm[i].y, m->norm[i].z);
436 glTexCoord2f(m->texcoord[i].x, m->texcoord[i].y);
437 glVertex3f(m->vert[i].x, m->vert[i].y, m->vert[i].z);
438 }
439 glEnd();
441 if(mtl->tex) {
442 glDisable(GL_TEXTURE_2D);
443 }
444 #else
445 if(mtl->tex) {
446 /*mgl_enable(MGL_TEXTURE_2D);*/
447 mgl_teximage(mtl->tex->width, mtl->tex->height, mtl->tex->pixels);
448 } else {
449 mgl_index(mtl->kd_base);
450 }
452 mgl_begin(MGL_TRIANGLES);
454 for(i=0; i<numv; i++) {
455 mgl_normal(m->norm[i].x, m->norm[i].y, m->norm[i].z);
456 mgl_texcoord2f(m->texcoord[i].x, m->texcoord[i].y);
457 mgl_vertex3f(m->vert[i].x, m->vert[i].y, m->vert[i].z);
458 }
459 mgl_end();
461 if(mtl->tex) {
462 mgl_disable(MGL_TEXTURE_2D);
463 }
464 #endif
465 }