dos3d
view src/scene.c @ 16:cb676ff89e69
added missing cvec and scene files
author | John Tsiombikas <nuclear@member.fsf.org> |
---|---|
date | Tue, 29 Nov 2011 07:23:57 +0200 |
parents | |
children | 1e9f0b3616fa |
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 "mingl.h"
11 struct face {
12 int v[3], n[3], t[3];
13 };
15 static int load_materials(struct scene *scn, const char *fname);
16 static int parse_face(struct face *face, char *buf);
19 /* --- scene --- */
20 int scn_init(struct scene *scn)
21 {
22 memset(scn, 0, sizeof *scn);
23 return 0;
24 }
26 void scn_destroy(struct scene *scn)
27 {
28 while(scn->matlist) {
29 struct material *tmp = scn->matlist;
30 scn->matlist = scn->matlist->next;
32 mtl_destroy(tmp);
33 free(tmp);
34 }
35 while(scn->meshlist) {
36 struct mesh *tmp = scn->meshlist;
37 scn->meshlist = scn->meshlist->next;
39 mesh_destroy(tmp);
40 free(tmp);
41 }
42 }
45 void scn_add_mesh(struct scene *scn, struct mesh *m)
46 {
47 printf("adding mesh: %d faces\n", m->nface);
48 m->next = scn->meshlist;
49 scn->meshlist = m;
50 }
52 void scn_add_material(struct scene *scn, struct material *m)
53 {
54 printf("adding material: %s\n", m->name);
55 m->next = scn->matlist;
56 scn->matlist = m;
57 }
59 struct material *scn_find_material(struct scene *scn, const char *name)
60 {
61 struct material *mtl = scn->matlist;
63 while(mtl) {
64 if(strcmp(mtl->name, name) == 0) {
65 break;
66 }
67 mtl = mtl->next;
68 }
69 return mtl;
70 }
72 #define SEP " \t\n\r"
73 int scn_load(struct scene *scn, const char *fname)
74 {
75 FILE *fp;
76 char buf[256];
77 struct mesh *m;
78 vec3_t *varr, *vnarr;
79 vec2_t *vtarr;
81 if(!(fp = fopen(fname, "rb"))) {
82 fprintf(stderr, "failed to open scene file: %s: %s\n", fname, strerror(errno));
83 return -1;
84 }
86 varr = cvec_alloc(0, sizeof *varr);
87 vnarr = cvec_alloc(0, sizeof *vnarr);
88 vtarr = cvec_alloc(0, sizeof *vtarr);
90 if(!(m = malloc(sizeof *m)) || mesh_init(m) == -1) {
91 fprintf(stderr, "meshed up\n");
92 fclose(fp);
93 return -1;
94 }
96 while(fgets(buf, sizeof buf, fp)) {
97 char *line = buf;
98 char *tok, *rest, *tmp;
100 while(*line && isspace(*line)) {
101 line++;
102 }
103 if(*line == 0 || *line == '#') {
104 continue;
105 }
107 if(!(tok = strtok(line, SEP))) {
108 continue;
109 }
110 rest = tok + strlen(tok) + 1;
112 if((tmp = strchr(rest, '\r')) || (tmp = strchr(rest, '\n'))) {
113 *tmp = 0;
114 }
116 if(strcmp(tok, "mtllib") == 0) {
117 if(!rest) {
118 fprintf(stderr, "invalid mtllib directive\n");
119 continue;
120 }
121 load_materials(scn, rest);
123 } else if(strcmp(tok, "usemtl") == 0) {
124 if(rest) {
125 m->mtl = scn_find_material(scn, rest);
126 }
128 } else if(strcmp(tok, "o") == 0 || strcmp(tok, "g") == 0) {
129 if(cvec_size(m->vert) > 0) {
130 scn_add_mesh(scn, m);
132 if(!(m = malloc(sizeof *m)) || mesh_init(m) == -1) {
133 fprintf(stderr, "meshed up\n");
134 fclose(fp);
135 return -1;
136 }
137 }
139 } else if(strcmp(tok, "v") == 0) {
140 vec3_t v;
142 if(!rest || sscanf(rest, "%f %f %f\n", &v.x, &v.y, &v.z) != 3) {
143 continue;
144 }
145 varr = cvec_append(varr, &v);
147 } else if(strcmp(tok, "vn") == 0) {
148 vec3_t v;
150 if(!rest || sscanf(rest, "%f %f %f\n", &v.x, &v.y, &v.z) != 3) {
151 continue;
152 }
153 vnarr = cvec_append(vnarr, &v);
155 } else if(strcmp(tok, "vt") == 0) {
156 vec3_t v;
158 if(!rest || sscanf(rest, "%f %f %f\n", &v.x, &v.y, &v.z) != 3) {
159 continue;
160 }
161 vtarr = cvec_append(vtarr, &v);
163 } else if(strcmp(tok, "f") == 0) {
164 int i;
165 struct face face;
167 if(!rest || parse_face(&face, rest) == -1) {
168 continue;
169 }
171 for(i=0; i<3; i++) {
172 int vidx = face.v[i];
173 int nidx = face.n[i];
174 int tidx = face.t[i];
176 mesh_add_vertex(m, varr[vidx]);
177 if(nidx >= 0) {
178 mesh_add_normal(m, vnarr[nidx]);
179 }
180 if(tidx >= 0) {
181 mesh_add_texcoord(m, vtarr[tidx]);
182 }
183 m->nface++;
184 }
185 }
187 }
188 fclose(fp);
190 if(cvec_size(m->vert) > 0) {
191 scn_add_mesh(scn, m);
192 }
194 cvec_free(varr);
195 cvec_free(vnarr);
196 cvec_free(vtarr);
198 return 0;
199 }
201 static int load_materials(struct scene *scn, const char *fname)
202 {
203 FILE *fp;
204 struct material *m = 0;
205 char buf[256];
207 if(!(fp = fopen(fname, "r"))) {
208 fprintf(stderr, "failed to load material file: %s: %s\n", fname, strerror(errno));
209 return -1;
210 }
212 while(fgets(buf, sizeof buf, fp)) {
213 char *line = buf;
214 char *tok, *rest, *tmp;
216 while(*line && isspace(*line)) {
217 line++;
218 }
219 if(*line == 0 || *line == '#') {
220 continue;
221 }
223 if(!(tok = strtok(line, SEP))) {
224 continue;
225 }
226 rest = tok + strlen(tok) + 1;
228 if((tmp = strchr(rest, '\r')) || (tmp = strchr(rest, '\n'))) {
229 *tmp = 0;
230 }
232 if(strcmp(tok, "newmtl") == 0) {
233 if(m) {
234 scn_add_material(scn, m);
235 }
236 if(!(m = malloc(sizeof *m)) || mtl_init(m) == -1) {
237 continue;
238 }
239 mtl_set_name(m, rest);
241 } else if(strcmp(tok, "Kd") == 0) {
242 if(sscanf(rest, "%f %f %f", &m->kd.x, &m->kd.y, &m->kd.z) != 3) {
243 continue;
244 }
245 } else if(strcmp(tok, "map_Kd") == 0) {
246 printf("ignoring texture: `%s'\n", rest);
247 }
248 }
250 if(m) {
251 scn_add_material(scn, m);
252 }
254 fclose(fp);
255 return 0;
256 }
258 static int parse_face(struct face *face, char *buf)
259 {
260 int i, found;
261 char *tok;
263 for(i=0; i<3; i++) {
264 tok = strtok(i > 0 ? 0 : buf, SEP);
265 found = sscanf(tok, "%d/%d/%d", &face->v[i], &face->t[i], &face->n[i]);
267 face->v[i]--;
269 if(found > 1) {
270 face->t[i]--;
271 } else {
272 face->t[i] = -1;
273 }
274 if(found > 2) {
275 face->n[i]--;
276 } else {
277 face->n[i] = -1;
278 }
279 }
280 return 0;
281 }
283 void scn_render(struct scene *scn)
284 {
285 struct mesh *m = scn->meshlist;
287 while(m) {
288 mesh_draw(m);
289 m = m->next;
290 }
291 }
293 /* --- material --- */
294 int mtl_init(struct material *mtl)
295 {
296 memset(mtl, 0, sizeof *mtl);
297 return 0;
298 }
300 void mtl_destroy(struct material *mtl)
301 {
302 free(mtl->name);
304 if(mtl->tex) {
305 free_texture(mtl->tex);
306 }
307 }
310 int mtl_set_name(struct material *mtl, const char *name)
311 {
312 char *tmp;
313 int len = strlen(name);
315 if(!(tmp = malloc(len + 1))) {
316 perror("failed to allocate material name");
317 return -1;
318 }
319 memcpy(tmp, name, len);
320 tmp[len] = 0;
322 free(mtl->name);
323 mtl->name = tmp;
324 return 0;
325 }
328 /* --- mesh --- */
329 int mesh_init(struct mesh *m)
330 {
331 memset(m, 0, sizeof *m);
333 m->vert = cvec_alloc(0, sizeof *m->vert);
334 m->norm = cvec_alloc(0, sizeof *m->norm);
335 m->texcoord = cvec_alloc(0, sizeof *m->texcoord);
337 if(!m->vert || !m->norm || !m->texcoord) {
338 return -1;
339 }
340 return 0;
341 }
343 void mesh_destroy(struct mesh *m)
344 {
345 cvec_free(m->vert);
346 cvec_free(m->norm);
347 cvec_free(m->texcoord);
348 }
350 void mesh_add_vertex(struct mesh *m, vec3_t v)
351 {
352 m->vert = cvec_append(m->vert, &v);
353 }
355 void mesh_add_normal(struct mesh *m, vec3_t n)
356 {
357 m->norm = cvec_append(m->norm, &n);
358 }
360 void mesh_add_texcoord(struct mesh *m, vec2_t tc)
361 {
362 m->texcoord = cvec_append(m->texcoord, &tc);
363 }
365 void mesh_draw(struct mesh *m)
366 {
367 int i, numv;
369 mgl_begin(MGL_TRIANGLES);
371 numv = cvec_size(m->vert);
372 for(i=0; i<numv; i++) {
373 mgl_normal(m->norm[i].x, m->norm[i].y, m->norm[i].z);
374 mgl_texcoord2f(m->texcoord[i].x, m->texcoord[i].y);
375 mgl_vertex3f(m->vert[i].x, m->vert[i].y, m->vert[i].z);
376 }
378 mgl_end();
379 }