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