1 |
#ifndef lint |
2 |
static const char RCSid[] = "$Id$"; |
3 |
#endif |
4 |
/* |
5 |
* Basic .OBJ scene handling routines. |
6 |
* |
7 |
* Created by Greg Ward on Wed Feb 11 2004. |
8 |
*/ |
9 |
|
10 |
#include <stdlib.h> |
11 |
#include "rtio.h" |
12 |
#include "rtmath.h" |
13 |
#include "rterror.h" |
14 |
#include "lookup.h" |
15 |
#include "objutil.h" |
16 |
|
17 |
/* Find an existing name in a list of names */ |
18 |
int |
19 |
findName(const char *nm, const char **nmlist, int n) |
20 |
{ |
21 |
register int i; |
22 |
|
23 |
for (i = n; i-- > 0; ) |
24 |
if (!strcmp(nmlist[i], nm)) |
25 |
break; |
26 |
return(i); |
27 |
} |
28 |
|
29 |
/* Clear face selection */ |
30 |
void |
31 |
clearSelection(Scene *sc, int set) |
32 |
{ |
33 |
Face *f; |
34 |
|
35 |
for (f = sc->flist; f != NULL; f = f->next) |
36 |
if (set) |
37 |
f->flags |= FACE_SELECTED; |
38 |
else |
39 |
f->flags &= ~FACE_SELECTED; |
40 |
} |
41 |
|
42 |
/* Select faces by object name (modifies current) */ |
43 |
void |
44 |
selectGroup(Scene *sc, const char *gname, int invert) |
45 |
{ |
46 |
int gid = findName(gname, (const char **)sc->grpname, sc->ngrps); |
47 |
Face *f; |
48 |
|
49 |
if (gid < 0) |
50 |
return; |
51 |
for (f = sc->flist; f != NULL; f = f->next) |
52 |
if (f->grp == gid) { |
53 |
if (invert) |
54 |
f->flags &= ~FACE_SELECTED; |
55 |
else |
56 |
f->flags |= FACE_SELECTED; |
57 |
} |
58 |
} |
59 |
|
60 |
/* Select faces by material name (modifies current) */ |
61 |
void |
62 |
selectMaterial(Scene *sc, const char *mname, int invert) |
63 |
{ |
64 |
int mid = findName(mname, (const char **)sc->matname, sc->nmats); |
65 |
Face *f; |
66 |
|
67 |
if (mid < 0) |
68 |
return; |
69 |
for (f = sc->flist; f != NULL; f = f->next) |
70 |
if (f->mat == mid) { |
71 |
if (invert) |
72 |
f->flags &= ~FACE_SELECTED; |
73 |
else |
74 |
f->flags |= FACE_SELECTED; |
75 |
} |
76 |
} |
77 |
|
78 |
/* Invert face selection */ |
79 |
void |
80 |
invertSelection(Scene *sc) |
81 |
{ |
82 |
Face *f; |
83 |
|
84 |
for (f = sc->flist; f != NULL; f = f->next) |
85 |
f->flags ^= FACE_SELECTED; |
86 |
} |
87 |
|
88 |
/* Count selected faces */ |
89 |
int |
90 |
numberSelected(Scene *sc) |
91 |
{ |
92 |
int nsel = 0; |
93 |
Face *f; |
94 |
|
95 |
for (f = sc->flist; f != NULL; f = f->next) |
96 |
nsel += ((f->flags & FACE_SELECTED) != 0); |
97 |
return(nsel); |
98 |
} |
99 |
|
100 |
/* Execute callback on indicated faces */ |
101 |
int |
102 |
foreachFace(Scene *sc, int (*cb)(Scene *, Face *, void *), |
103 |
int flreq, int flexc, void *c_data) |
104 |
{ |
105 |
int fltest = flreq | flexc; |
106 |
int sum = 0; |
107 |
Face *f; |
108 |
|
109 |
if ((sc == NULL) | (cb == NULL)) |
110 |
return(0); |
111 |
for (f = sc->flist; f != NULL; f = f->next) |
112 |
if ((f->flags & fltest) == flreq) { |
113 |
int res = (*cb)(sc, f, c_data); |
114 |
if (res < 0) |
115 |
return(res); |
116 |
sum += res; |
117 |
} |
118 |
return(sum); |
119 |
} |
120 |
|
121 |
/* Callback for removeTexture() */ |
122 |
static int |
123 |
remFaceTexture(Scene *sc, Face *f, void *dummy) |
124 |
{ |
125 |
int hadTexture = 0; |
126 |
int i; |
127 |
|
128 |
for (i = f->nv; i-- > 0; ) { |
129 |
if (f->v[i].tid < 0) |
130 |
continue; |
131 |
f->v[i].tid = -1; |
132 |
hadTexture = 1; |
133 |
} |
134 |
return(hadTexture); |
135 |
} |
136 |
|
137 |
/* Remove texture coordinates from the indicated faces */ |
138 |
int |
139 |
removeTexture(Scene *sc, int flreq, int flexc) |
140 |
{ |
141 |
return(foreachFace(sc, remFaceTexture, flreq, flexc, NULL)); |
142 |
} |
143 |
|
144 |
/* Callback for removeNormals() */ |
145 |
static int |
146 |
remFaceNormal(Scene *sc, Face *f, void *dummy) |
147 |
{ |
148 |
int hadNormal = 0; |
149 |
int i; |
150 |
|
151 |
for (i = f->nv; i-- > 0; ) { |
152 |
if (f->v[i].nid < 0) |
153 |
continue; |
154 |
f->v[i].nid = -1; |
155 |
hadNormal = 1; |
156 |
} |
157 |
return(hadNormal); |
158 |
} |
159 |
|
160 |
/* Remove surface normals from the indicated faces */ |
161 |
int |
162 |
removeNormals(Scene *sc, int flreq, int flexc) |
163 |
{ |
164 |
return(foreachFace(sc, remFaceNormal, flreq, flexc, NULL)); |
165 |
} |
166 |
|
167 |
/* Callback for changeGroup() */ |
168 |
static int |
169 |
chngFaceGroup(Scene *sc, Face *f, void *ptr) |
170 |
{ |
171 |
int grp = *(int *)ptr; |
172 |
if (f->grp == grp) |
173 |
return(0); |
174 |
f->grp = grp; |
175 |
return(1); |
176 |
} |
177 |
|
178 |
/* Change group for the indicated faces */ |
179 |
int |
180 |
changeGroup(Scene *sc, const char *gname, int flreq, int flexc) |
181 |
{ |
182 |
int grp = findName(gname, (const char **)sc->grpname, sc->ngrps); |
183 |
if (grp < 0) { |
184 |
sc->grpname = chunk_alloc(char *, sc->grpname, sc->ngrps); |
185 |
sc->grpname[grp=sc->ngrps++] = savqstr((char *)gname); |
186 |
} |
187 |
return(foreachFace(sc, chngFaceGroup, flreq, flexc, (void *)&grp)); |
188 |
} |
189 |
|
190 |
/* Callback for changeMaterial() */ |
191 |
static int |
192 |
chngFaceMaterial(Scene *sc, Face *f, void *ptr) |
193 |
{ |
194 |
int mat = *(int *)ptr; |
195 |
if (f->mat == mat) |
196 |
return(0); |
197 |
f->mat = mat; |
198 |
return(1); |
199 |
} |
200 |
|
201 |
/* Change material for the indicated faces */ |
202 |
int |
203 |
changeMaterial(Scene *sc, const char *mname, int flreq, int flexc) |
204 |
{ |
205 |
int mat = findName(mname, (const char **)sc->matname, sc->nmats); |
206 |
if (mat < 0) { |
207 |
sc->matname = chunk_alloc(char *, sc->matname, sc->nmats); |
208 |
sc->matname[mat=sc->nmats++] = savqstr((char *)mname); |
209 |
} |
210 |
return(foreachFace(sc, chngFaceMaterial, flreq, flexc, (void *)&mat)); |
211 |
} |
212 |
|
213 |
/* Compare floating point values for (near) equality */ |
214 |
static int |
215 |
fdiffer(double f1, double f2, double eps) |
216 |
{ |
217 |
if (f2 != .0) |
218 |
f1 = f1/f2 - 1.; |
219 |
return((f1 > eps) | (f1 < -eps)); |
220 |
} |
221 |
|
222 |
/* Compare two texture coordinates for (near) equality */ |
223 |
static int |
224 |
tex_diff(const TexCoord *t1, const TexCoord *t2, double eps) |
225 |
{ |
226 |
if (fdiffer(t1->u, t2->u, eps)) |
227 |
return(1); |
228 |
if (fdiffer(t1->v, t2->v, eps)) |
229 |
return(1); |
230 |
return(0); |
231 |
} |
232 |
|
233 |
/* Compare two surface normals for (near) equality */ |
234 |
static int |
235 |
norm_diff(const Normal n1, const Normal n2, double eps) |
236 |
{ |
237 |
if (fabs(n1[0]-n2[0]) > eps) |
238 |
return(1); |
239 |
if (fabs(n1[1]-n2[1]) > eps) |
240 |
return(1); |
241 |
if (fabs(n1[2]-n2[2]) > eps) |
242 |
return(1); |
243 |
return(0); |
244 |
} |
245 |
|
246 |
/* Replace the given vertex with an equivalent one */ |
247 |
static int |
248 |
replace_vertex(Scene *sc, int prev, int repl, double eps) |
249 |
{ |
250 |
int repl_tex[10]; |
251 |
int repl_norm[10]; |
252 |
Face *f, *flast=NULL; |
253 |
int i, j=0; |
254 |
/* check to see if it's even used */ |
255 |
if (sc->vert[prev].vflist == NULL) |
256 |
return(0); |
257 |
/* get replacement textures */ |
258 |
repl_tex[0] = -1; |
259 |
for (f = sc->vert[repl].vflist; f != NULL; f = f->v[j].fnext) { |
260 |
/* make sure prev isn't in there */ |
261 |
for (j = 0; j < f->nv; j++) |
262 |
if (f->v[j].vid == prev) |
263 |
return(0); |
264 |
for (j = 0; j < f->nv; j++) |
265 |
if (f->v[j].vid == repl) |
266 |
break; |
267 |
if (j >= f->nv) |
268 |
goto linkerr; |
269 |
if (f->v[j].tid < 0) |
270 |
continue; |
271 |
/* see if it's new */ |
272 |
for (i = 0; repl_tex[i] >= 0; i++) { |
273 |
if (repl_tex[i] == f->v[j].tid) |
274 |
break; |
275 |
if (!tex_diff(&sc->tex[repl_tex[i]], |
276 |
&sc->tex[f->v[j].tid], eps)) { |
277 |
f->v[j].tid = repl_tex[i]; |
278 |
break; /* consolidate */ |
279 |
} |
280 |
} |
281 |
if (repl_tex[i] >= 0) |
282 |
continue; /* have this one already */ |
283 |
/* else add it */ |
284 |
repl_tex[i++] = f->v[j].tid; |
285 |
repl_tex[i] = -1; |
286 |
if (i >= 9) |
287 |
break; /* that's all we have room for */ |
288 |
} |
289 |
/* get replacement normals */ |
290 |
repl_norm[0] = -1; |
291 |
for (f = sc->vert[repl].vflist; f != NULL; f = f->v[j].fnext) { |
292 |
for (j = 0; j < f->nv; j++) |
293 |
if (f->v[j].vid == repl) |
294 |
break; |
295 |
if (f->v[j].nid < 0) |
296 |
continue; |
297 |
/* see if it's new */ |
298 |
for (i = 0; repl_norm[i] >= 0; i++) { |
299 |
if (repl_norm[i] == f->v[j].nid) |
300 |
break; |
301 |
if (!norm_diff(sc->norm[repl_norm[i]], |
302 |
sc->norm[f->v[j].nid], eps)) { |
303 |
f->v[j].nid = repl_norm[i]; |
304 |
break; /* consolidate */ |
305 |
} |
306 |
} |
307 |
if (repl_norm[i] >= 0) |
308 |
continue; /* have this one already */ |
309 |
/* else add it */ |
310 |
repl_norm[i++] = f->v[j].nid; |
311 |
repl_norm[i] = -1; |
312 |
if (i >= 9) |
313 |
break; /* that's all we have room for */ |
314 |
} |
315 |
/* replace occurrences of vertex */ |
316 |
for (f = sc->vert[prev].vflist; f != NULL; f = f->v[j].fnext) { |
317 |
for (j = 0; j < f->nv; j++) |
318 |
if (f->v[j].vid == prev) |
319 |
break; |
320 |
if (j >= f->nv) |
321 |
goto linkerr; |
322 |
/* XXX doesn't allow for multiple references to prev in face */ |
323 |
f->v[j].vid = repl; /* replace vertex itself */ |
324 |
if (faceArea(sc, f, NULL) <= FTINY) |
325 |
f->flags |= FACE_DEGENERATE; |
326 |
if (f->v[j].tid >= 0) /* replace texture if appropriate */ |
327 |
for (i = 0; repl_tex[i] >= 0; i++) { |
328 |
if (repl_tex[i] == f->v[j].tid) |
329 |
break; |
330 |
if (!tex_diff(&sc->tex[repl_tex[i]], |
331 |
&sc->tex[f->v[j].tid], eps)) { |
332 |
f->v[j].tid = repl_tex[i]; |
333 |
break; |
334 |
} |
335 |
} |
336 |
if (f->v[j].nid >= 0) /* replace normal if appropriate */ |
337 |
for (i = 0; repl_norm[i] >= 0; i++) { |
338 |
if (repl_norm[i] == f->v[j].nid) |
339 |
break; |
340 |
if (!norm_diff(sc->norm[repl_norm[i]], |
341 |
sc->norm[f->v[j].nid], eps)) { |
342 |
f->v[j].nid = repl_norm[i]; |
343 |
break; |
344 |
} |
345 |
} |
346 |
flast = f; |
347 |
} |
348 |
/* transfer face list */ |
349 |
flast->v[j].fnext = sc->vert[repl].vflist; |
350 |
sc->vert[repl].vflist = sc->vert[prev].vflist; |
351 |
sc->vert[prev].vflist = NULL; |
352 |
return(1); |
353 |
linkerr: |
354 |
error(CONSISTENCY, "Link error in replace_vertex()"); |
355 |
return(0); /* shouldn't return */ |
356 |
} |
357 |
|
358 |
/* Eliminate duplicate vertices, return # joined */ |
359 |
int |
360 |
coalesceVertices(Scene *sc, double eps) |
361 |
{ |
362 |
int nelim = 0; |
363 |
LUTAB myLookup; |
364 |
LUENT *le; |
365 |
char vertfmt[32], vertbuf[64]; |
366 |
double d; |
367 |
int i; |
368 |
|
369 |
if (eps >= 1.) |
370 |
return(0); |
371 |
if (sc->nverts <= 3) |
372 |
return(0); |
373 |
/* create hash table */ |
374 |
myLookup.hashf = lu_shash; |
375 |
myLookup.keycmp = (lut_keycmpf_t *)strcmp; |
376 |
myLookup.freek = (lut_free_t *)freeqstr; |
377 |
myLookup.freed = NULL; |
378 |
if (!lu_init(&myLookup, sc->nverts)) |
379 |
return(0); |
380 |
if (eps <= 5e-15) |
381 |
strcpy(vertfmt, "%.15e %.15e %.15e"); |
382 |
else { |
383 |
int nsigdig = 0; |
384 |
for (d = eps; d < 0.5; d *= 10.) |
385 |
++nsigdig; |
386 |
sprintf(vertfmt, "%%.%de %%.%de %%.%de", |
387 |
nsigdig, nsigdig, nsigdig); |
388 |
} |
389 |
/* find coicident vertices */ |
390 |
for (i = 0; i < sc->nverts; i++) { |
391 |
if (verbose && !((i+1) & 0x3fff)) |
392 |
fprintf(stderr, "%3d%% complete\r", 100*i/sc->nverts); |
393 |
/* check for match */ |
394 |
sprintf(vertbuf, vertfmt, sc->vert[i].p[0], |
395 |
sc->vert[i].p[1], sc->vert[i].p[2]); |
396 |
le = lu_find(&myLookup, vertbuf); |
397 |
if (le->data != NULL) { /* coincident vertex */ |
398 |
nelim += replace_vertex(sc, i, |
399 |
(Vertex *)le->data - sc->vert, eps); |
400 |
continue; |
401 |
} |
402 |
if (le->key == NULL) /* else create new entry */ |
403 |
le->key = savqstr(vertbuf); |
404 |
le->data = (char *)&sc->vert[i]; |
405 |
} |
406 |
lu_done(&myLookup); /* clean up */ |
407 |
return(nelim); |
408 |
} |
409 |
|
410 |
/* Identify duplicate faces */ |
411 |
int |
412 |
findDuplicateFaces(Scene *sc) |
413 |
{ |
414 |
int nchecked = 0; |
415 |
int nfound = 0; |
416 |
Face *f, *f1; |
417 |
int vid; |
418 |
int i, j; |
419 |
/* start fresh */ |
420 |
for (f = sc->flist; f != NULL; f = f->next) |
421 |
f->flags &= ~FACE_DUPLICATE; |
422 |
/* check each face */ |
423 |
for (f = sc->flist; f != NULL; f = f->next) { |
424 |
nchecked++; |
425 |
if (verbose && !(nchecked & 0x3fff)) |
426 |
fprintf(stderr, "%3d%% complete\r", |
427 |
100*nchecked/sc->nfaces); |
428 |
if (f->flags & FACE_DUPLICATE) |
429 |
continue; /* already identified */ |
430 |
vid = f->v[0].vid; |
431 |
/* look for duplicates */ |
432 |
for (f1 = sc->vert[vid].vflist; f1 != NULL; |
433 |
f1 = f1->v[j].fnext) { |
434 |
for (j = 0; j < f1->nv; j++) |
435 |
if (f1->v[j].vid == vid) |
436 |
break; |
437 |
if (j >= f1->nv) |
438 |
break; /* missing link! */ |
439 |
if (f1 == f) |
440 |
continue; /* shouldn't happen */ |
441 |
if (f1->flags & FACE_DUPLICATE) |
442 |
continue; /* already marked */ |
443 |
if (f1->nv != f->nv) |
444 |
continue; /* couldn't be dup. */ |
445 |
for (i = f->nv; --i > 0; ) |
446 |
if (f->v[i].vid != f1->v[(j+i)%f1->nv].vid) |
447 |
break; /* vertex mismatch */ |
448 |
if (i) { |
449 |
#if DUP_CHECK_REVERSE /* check reverse direction */ |
450 |
for (i = f->nv; --i > 0; ) |
451 |
if (f1->v[(j+f1->nv-i)%f1->nv].vid |
452 |
!= f->v[i].vid) |
453 |
break; |
454 |
if (i) /* no match */ |
455 |
#endif |
456 |
continue; |
457 |
} |
458 |
f1->flags |= FACE_DUPLICATE; |
459 |
++nfound; |
460 |
} |
461 |
} |
462 |
return(nfound); |
463 |
} |
464 |
|
465 |
/* Delete indicated faces */ |
466 |
int |
467 |
deleteFaces(Scene *sc, int flreq, int flexc) |
468 |
{ |
469 |
int fltest = flreq | flexc; |
470 |
int orig_nfaces = sc->nfaces; |
471 |
Face fhead; |
472 |
Face *f, *ftst; |
473 |
|
474 |
fhead.next = sc->flist; |
475 |
f = &fhead; |
476 |
while ((ftst = f->next) != NULL) |
477 |
if ((ftst->flags & fltest) == flreq) { |
478 |
Face *vf; /* remove from vertex lists */ |
479 |
int vid, i, j; |
480 |
for (i = 0; i < ftst->nv; i++) { |
481 |
vid = ftst->v[i].vid; |
482 |
vf = sc->vert[vid].vflist; |
483 |
if (vf == ftst) { |
484 |
sc->vert[vid].vflist = ftst->v[i].fnext; |
485 |
continue; |
486 |
} |
487 |
while (vf != NULL) { |
488 |
for (j = 0; j < vf->nv; j++) |
489 |
if (vf->v[j].vid == vid) |
490 |
break; |
491 |
if (j >= vf->nv) |
492 |
break; /* error */ |
493 |
if (vf->v[j].fnext == ftst) { |
494 |
vf->v[j].fnext = |
495 |
ftst->v[i].fnext; |
496 |
break; |
497 |
} |
498 |
vf = vf->v[j].fnext; |
499 |
} |
500 |
} |
501 |
f->next = ftst->next; /* remove from scene list */ |
502 |
efree((char *)ftst); |
503 |
sc->nfaces--; |
504 |
} else |
505 |
f = f->next; |
506 |
sc->flist = fhead.next; |
507 |
return(orig_nfaces - sc->nfaces); |
508 |
} |
509 |
|
510 |
/* Compute face area (and normal) */ |
511 |
double |
512 |
faceArea(const Scene *sc, const Face *f, Normal nrm) |
513 |
{ |
514 |
FVECT fnrm; |
515 |
double area; |
516 |
FVECT v1, v2, v3; |
517 |
double *p0; |
518 |
int i; |
519 |
|
520 |
if (f->flags & FACE_DEGENERATE) |
521 |
return(.0); /* should we check this? */ |
522 |
fnrm[0] = fnrm[1] = fnrm[2] = .0; |
523 |
p0 = sc->vert[f->v[0].vid].p; |
524 |
VSUB(v1, sc->vert[f->v[1].vid].p, p0); |
525 |
for (i = 2; i < f->nv; i++) { |
526 |
VSUB(v2, sc->vert[f->v[i].vid].p, p0); |
527 |
fcross(v3, v1, v2); |
528 |
VADD(fnrm, fnrm, v3); |
529 |
VCOPY(v1, v2); |
530 |
} |
531 |
area = 0.5*normalize(fnrm); |
532 |
if (nrm != NULL) { |
533 |
if (area != 0.) |
534 |
VCOPY(nrm, fnrm); |
535 |
else |
536 |
nrm[0] = nrm[1] = nrm[2] = 0.; |
537 |
} |
538 |
return(area); |
539 |
} |
540 |
|
541 |
/* Add a descriptive comment */ |
542 |
void |
543 |
addComment(Scene *sc, const char *comment) |
544 |
{ |
545 |
sc->descr = chunk_alloc(char *, sc->descr, sc->ndescr); |
546 |
sc->descr[sc->ndescr++] = savqstr((char *)comment); |
547 |
} |
548 |
|
549 |
/* Clear comments */ |
550 |
void |
551 |
clearComments(Scene *sc) |
552 |
{ |
553 |
while (sc->ndescr > 0) |
554 |
freeqstr(sc->descr[--sc->ndescr]); |
555 |
efree((char *)sc->descr); |
556 |
sc->ndescr = 0; |
557 |
} |
558 |
|
559 |
/* Add a face to a vertex face list */ |
560 |
static void |
561 |
add2facelist(Scene *sc, Face *f, int i) |
562 |
{ |
563 |
int vid = f->v[i].vid; |
564 |
Face *fp = sc->vert[vid].vflist; |
565 |
int j; |
566 |
|
567 |
f->v[i].fnext = NULL; /* will put at end */ |
568 |
if (fp == NULL) { /* new list */ |
569 |
sc->vert[vid].vflist = f; |
570 |
return; |
571 |
} |
572 |
for ( ; ; ) { /* else find position */ |
573 |
if (fp == f) |
574 |
return; /* already in list */ |
575 |
for (j = 0; j < fp->nv; j++) |
576 |
if (fp->v[j].vid == vid) |
577 |
break; |
578 |
if (j >= fp->nv) |
579 |
error(CONSISTENCY, "Link error in add2facelist()"); |
580 |
if (fp->v[j].fnext == NULL) |
581 |
break; /* reached the end */ |
582 |
fp = fp->v[j].fnext; |
583 |
} |
584 |
fp->v[j].fnext = f; /* append new face */ |
585 |
} |
586 |
|
587 |
/* Allocate an empty scene */ |
588 |
Scene * |
589 |
newScene(void) |
590 |
{ |
591 |
Scene *sc = (Scene *)ecalloc(1, sizeof(Scene)); |
592 |
/* default group & material */ |
593 |
sc->grpname = chunk_alloc(char *, sc->grpname, sc->ngrps); |
594 |
sc->grpname[sc->ngrps++] = savqstr("DEFAULT_GROUP"); |
595 |
sc->matname = chunk_alloc(char *, sc->matname, sc->nmats); |
596 |
sc->matname[sc->nmats++] = savqstr("DEFAULT_MATERIAL"); |
597 |
|
598 |
return(sc); |
599 |
} |
600 |
|
601 |
/* Duplicate a scene */ |
602 |
Scene * |
603 |
dupScene(const Scene *osc) |
604 |
{ |
605 |
Scene *sc; |
606 |
const Face *fo; |
607 |
Face *f; |
608 |
int i; |
609 |
|
610 |
if (osc == NULL) |
611 |
return(NULL); |
612 |
sc = newScene(); |
613 |
for (i = 0; i < osc->ndescr; i++) |
614 |
addComment(sc, osc->descr[i]); |
615 |
if (osc->ngrps) { |
616 |
sc->grpname = (char **)emalloc(sizeof(char *) * |
617 |
(osc->ngrps+(CHUNKSIZ-1))); |
618 |
for (i = 0; i < osc->ngrps; i++) |
619 |
sc->grpname[i] = savqstr(osc->grpname[i]); |
620 |
sc->ngrps = osc->ngrps; |
621 |
} |
622 |
if (osc->nmats) { |
623 |
sc->matname = (char **)emalloc(sizeof(char *) * |
624 |
(osc->nmats+(CHUNKSIZ-1))); |
625 |
for (i = 0; i < osc->nmats; i++) |
626 |
sc->matname[i] = savqstr(osc->matname[i]); |
627 |
sc->nmats = osc->nmats; |
628 |
} |
629 |
if (osc->nverts) { |
630 |
sc->vert = (Vertex *)emalloc(sizeof(Vertex) * |
631 |
(osc->nverts+(CHUNKSIZ-1))); |
632 |
memcpy((void *)sc->vert, (const void *)osc->vert, |
633 |
sizeof(Vertex)*osc->nverts); |
634 |
sc->nverts = osc->nverts; |
635 |
for (i = 0; i < sc->nverts; i++) |
636 |
sc->vert[i].vflist = NULL; |
637 |
} |
638 |
if (osc->ntex) { |
639 |
sc->tex = (TexCoord *)emalloc(sizeof(TexCoord) * |
640 |
(osc->ntex+(CHUNKSIZ-1))); |
641 |
memcpy((void *)sc->tex, (const void *)osc->tex, |
642 |
sizeof(TexCoord)*osc->ntex); |
643 |
sc->ntex = osc->ntex; |
644 |
} |
645 |
if (osc->nnorms) { |
646 |
sc->norm = (Normal *)emalloc(sizeof(Normal) * |
647 |
(osc->nnorms+CHUNKSIZ)); |
648 |
memcpy((void *)sc->norm, (const void *)osc->norm, |
649 |
sizeof(Normal)*osc->nnorms); |
650 |
sc->nnorms = osc->nnorms; |
651 |
} |
652 |
for (fo = osc->flist; fo != NULL; fo = fo->next) { |
653 |
f = (Face *)emalloc(sizeof(Face) + |
654 |
sizeof(VertEnt)*(fo->nv-3)); |
655 |
memcpy((void *)f, (const void *)fo, sizeof(Face) + |
656 |
sizeof(VertEnt)*(fo->nv-3)); |
657 |
for (i = 0; i < f->nv; i++) |
658 |
add2facelist(sc, f, i); |
659 |
f->next = sc->flist; |
660 |
sc->flist = f; |
661 |
sc->nfaces++; |
662 |
} |
663 |
return(sc); |
664 |
} |
665 |
|
666 |
/* Free a scene */ |
667 |
void |
668 |
freeScene(Scene *sc) |
669 |
{ |
670 |
int i; |
671 |
Face *f; |
672 |
|
673 |
if (sc == NULL) |
674 |
return; |
675 |
clearComments(sc); |
676 |
for (i = sc->ngrps; i-- > 0; ) |
677 |
freeqstr(sc->grpname[i]); |
678 |
efree((char *)sc->grpname); |
679 |
for (i = sc->nmats; i-- > 0; ) |
680 |
freeqstr(sc->matname[i]); |
681 |
efree((char *)sc->matname); |
682 |
efree((char *)sc->vert); |
683 |
efree((char *)sc->tex); |
684 |
efree((char *)sc->norm); |
685 |
while ((f = sc->flist) != NULL) { |
686 |
sc->flist = f->next; |
687 |
efree((char *)f); |
688 |
} |
689 |
efree((char *)sc); |
690 |
} |