ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/common/mesh.c
Revision: 2.13
Committed: Mon Jul 21 22:30:17 2003 UTC (20 years, 9 months ago) by schorsch
Content type: text/plain
Branch: MAIN
Changes since 2.12: +3 -2 lines
Log Message:
Eliminated copystruct() macro, which is unnecessary in ANSI.
Reduced ambiguity warnings for nested if/if/else clauses.

File Contents

# Content
1 #ifndef lint
2 static const char RCSid[] = "$Id: mesh.c,v 2.12 2003/07/17 09:21:29 schorsch Exp $";
3 #endif
4 /*
5 * Mesh support routines
6 */
7
8 #include <string.h>
9
10 #include "standard.h"
11 #include "octree.h"
12 #include "object.h"
13 #include "otypes.h"
14 #include "mesh.h"
15
16 /* An encoded mesh vertex */
17 typedef struct {
18 int fl;
19 uint32 xyz[3];
20 int32 norm;
21 uint32 uv[2];
22 } MCVERT;
23
24 #define MPATCHBLKSIZ 128 /* patch allocation block size */
25
26 #define IO_LEGAL (IO_BOUNDS|IO_TREE|IO_SCENE)
27
28 static MESH *mlist = NULL; /* list of loaded meshes */
29
30
31 static unsigned long
32 cvhash(cvp) /* hash an encoded vertex */
33 MCVERT *cvp;
34 {
35 unsigned long hval;
36
37 if (!(cvp->fl & MT_V))
38 return(0);
39 hval = cvp->xyz[0] ^ cvp->xyz[1] << 11 ^ cvp->xyz[2] << 22;
40 if (cvp->fl & MT_N)
41 hval ^= cvp->norm;
42 if (cvp->fl & MT_UV)
43 hval ^= cvp->uv[0] ^ cvp->uv[1] << 16;
44 return(hval);
45 }
46
47
48 static int
49 cvcmp(v1, v2) /* compare encoded vertices */
50 register MCVERT *v1, *v2;
51 {
52 if (v1->fl != v2->fl)
53 return(1);
54 if (v1->xyz[0] != v2->xyz[0])
55 return(1);
56 if (v1->xyz[1] != v2->xyz[1])
57 return(1);
58 if (v1->xyz[2] != v2->xyz[2])
59 return(1);
60 if (v1->fl & MT_N && v1->norm != v2->norm)
61 return(1);
62 if (v1->fl & MT_UV) {
63 if (v1->uv[0] != v2->uv[0])
64 return(1);
65 if (v1->uv[1] != v2->uv[1])
66 return(1);
67 }
68 return(0);
69 }
70
71
72 MESH *
73 getmesh(mname, flags) /* get new mesh data reference */
74 char *mname;
75 int flags;
76 {
77 char *pathname;
78 register MESH *ms;
79
80 flags &= IO_LEGAL;
81 for (ms = mlist; ms != NULL; ms = ms->next)
82 if (!strcmp(mname, ms->name)) {
83 ms->nref++; /* increase reference count */
84 break;
85 }
86 if (ms == NULL) { /* load first time */
87 ms = (MESH *)calloc(1, sizeof(MESH));
88 if (ms == NULL)
89 error(SYSTEM, "out of memory in getmesh");
90 ms->name = savestr(mname);
91 ms->nref = 1;
92 ms->mcube.cutree = EMPTY;
93 ms->next = mlist;
94 mlist = ms;
95 }
96 if ((pathname = getpath(mname, getrlibpath(), R_OK)) == NULL) {
97 sprintf(errmsg, "cannot find mesh file \"%s\"", mname);
98 error(USER, errmsg);
99 }
100 flags &= ~ms->ldflags;
101 if (flags)
102 readmesh(ms, pathname, flags);
103 return(ms);
104 }
105
106
107 MESHINST *
108 getmeshinst(o, flags) /* create mesh instance */
109 OBJREC *o;
110 int flags;
111 {
112 register MESHINST *ins;
113
114 flags &= IO_LEGAL;
115 if ((ins = (MESHINST *)o->os) == NULL) {
116 if ((ins = (MESHINST *)malloc(sizeof(MESHINST))) == NULL)
117 error(SYSTEM, "out of memory in getmeshinst");
118 if (o->oargs.nsargs < 1)
119 objerror(o, USER, "bad # of arguments");
120 if (fullxf(&ins->x, o->oargs.nsargs-1,
121 o->oargs.sarg+1) != o->oargs.nsargs-1)
122 objerror(o, USER, "bad transform");
123 if (ins->x.f.sca < 0.0) {
124 ins->x.f.sca = -ins->x.f.sca;
125 ins->x.b.sca = -ins->x.b.sca;
126 }
127 ins->msh = NULL;
128 o->os = (char *)ins;
129 }
130 if (ins->msh == NULL)
131 ins->msh = getmesh(o->oargs.sarg[0], flags);
132 else if ((flags &= ~ins->msh->ldflags))
133 readmesh(ins->msh,
134 getpath(o->oargs.sarg[0], getrlibpath(), R_OK),
135 flags);
136 return(ins);
137 }
138
139
140 int
141 getmeshtrivid(tvid, mo, mp, ti) /* get triangle vertex ID's */
142 int32 tvid[3];
143 OBJECT *mo;
144 MESH *mp;
145 OBJECT ti;
146 {
147 int pn = ti >> 10;
148 MESHPATCH *pp;
149
150 if (pn >= mp->npatches)
151 return(0);
152 pp = &mp->patch[pn];
153 ti &= 0x3ff;
154 if (!(ti & 0x200)) { /* local triangle */
155 struct PTri *tp;
156 if (ti >= pp->ntris)
157 return(0);
158 tp = &pp->tri[ti];
159 tvid[0] = tvid[1] = tvid[2] = pn << 8;
160 tvid[0] |= tp->v1;
161 tvid[1] |= tp->v2;
162 tvid[2] |= tp->v3;
163 if (pp->trimat != NULL)
164 *mo = pp->trimat[ti];
165 else
166 *mo = pp->solemat;
167 if (*mo != OVOID)
168 *mo += mp->mat0;
169 return(1);
170 }
171 ti &= ~0x200;
172 if (!(ti & 0x100)) { /* single link vertex */
173 struct PJoin1 *tp1;
174 if (ti >= pp->nj1tris)
175 return(0);
176 tp1 = &pp->j1tri[ti];
177 tvid[0] = tp1->v1j;
178 tvid[1] = tvid[2] = pn << 8;
179 tvid[1] |= tp1->v2;
180 tvid[2] |= tp1->v3;
181 if ((*mo = tp1->mat) != OVOID)
182 *mo += mp->mat0;
183 return(1);
184 }
185 ti &= ~0x100;
186 { /* double link vertex */
187 struct PJoin2 *tp2;
188 if (ti >= pp->nj2tris)
189 return(0);
190 tp2 = &pp->j2tri[ti];
191 tvid[0] = tp2->v1j;
192 tvid[1] = tp2->v2j;
193 tvid[2] = pn << 8 | tp2->v3;
194 if ((*mo = tp2->mat) != OVOID)
195 *mo += mp->mat0;
196 }
197 return(1);
198 }
199
200
201 int
202 getmeshvert(vp, mp, vid, what) /* get triangle vertex from ID */
203 MESHVERT *vp;
204 MESH *mp;
205 int32 vid;
206 int what;
207 {
208 int pn = vid >> 8;
209 MESHPATCH *pp;
210 double vres;
211 register int i;
212
213 vp->fl = 0;
214 if (pn >= mp->npatches)
215 return(0);
216 pp = &mp->patch[pn];
217 vid &= 0xff;
218 if (vid >= pp->nverts)
219 return(0);
220 /* get location */
221 if (what & MT_V) {
222 vres = (1./4294967296.)*mp->mcube.cusize;
223 for (i = 0; i < 3; i++)
224 vp->v[i] = mp->mcube.cuorg[i] +
225 (pp->xyz[vid][i] + .5)*vres;
226 vp->fl |= MT_V;
227 }
228 /* get normal */
229 if (what & MT_N && pp->norm != NULL && pp->norm[vid]) {
230 decodedir(vp->n, pp->norm[vid]);
231 vp->fl |= MT_N;
232 }
233 /* get (u,v) */
234 if (what & MT_UV && pp->uv != NULL && pp->uv[vid][0]) {
235 for (i = 0; i < 2; i++)
236 vp->uv[i] = mp->uvlim[0][i] +
237 (mp->uvlim[1][i] - mp->uvlim[0][i])*
238 (pp->uv[vid][i] + .5)*(1./4294967296.);
239 vp->fl |= MT_UV;
240 }
241 return(vp->fl);
242 }
243
244
245 OBJREC *
246 getmeshpseudo(mp, mo) /* get mesh pseudo object for material */
247 MESH *mp;
248 OBJECT mo;
249 {
250 if (mo < mp->mat0 || mo >= mp->mat0 + mp->nmats)
251 error(INTERNAL, "modifier out of range in getmeshpseudo");
252 if (mp->pseudo == NULL) {
253 register int i;
254 mp->pseudo = (OBJREC *)calloc(mp->nmats, sizeof(OBJREC));
255 if (mp->pseudo == NULL)
256 error(SYSTEM, "out of memory in getmeshpseudo");
257 for (i = mp->nmats; i--; ) {
258 mp->pseudo[i].omod = mp->mat0 + i;
259 mp->pseudo[i].otype = OBJ_FACE;
260 mp->pseudo[i].oname = "M-Tri";
261 }
262 }
263 return(&mp->pseudo[mo - mp->mat0]);
264 }
265
266
267 int
268 getmeshtri(tv, mo, mp, ti, wha) /* get triangle vertices */
269 MESHVERT tv[3];
270 OBJECT *mo;
271 MESH *mp;
272 OBJECT ti;
273 int wha;
274 {
275 int32 tvid[3];
276
277 if (!getmeshtrivid(tvid, mo, mp, ti))
278 return(0);
279
280 getmeshvert(&tv[0], mp, tvid[0], wha);
281 getmeshvert(&tv[1], mp, tvid[1], wha);
282 getmeshvert(&tv[2], mp, tvid[2], wha);
283
284 return(tv[0].fl & tv[1].fl & tv[2].fl);
285 }
286
287
288 int32
289 addmeshvert(mp, vp) /* find/add a mesh vertex */
290 register MESH *mp;
291 MESHVERT *vp;
292 {
293 LUENT *lvp;
294 MCVERT cv;
295 register int i;
296
297 if (!(vp->fl & MT_V))
298 return(-1);
299 /* encode vertex */
300 for (i = 0; i < 3; i++) {
301 if (vp->v[i] < mp->mcube.cuorg[i])
302 return(-1);
303 if (vp->v[i] >= mp->mcube.cuorg[i] + mp->mcube.cusize)
304 return(-1);
305 cv.xyz[i] = (uint32)(4294967296. *
306 (vp->v[i] - mp->mcube.cuorg[i]) /
307 mp->mcube.cusize);
308 }
309 if (vp->fl & MT_N)
310 cv.norm = encodedir(vp->n);
311 if (vp->fl & MT_UV)
312 for (i = 0; i < 2; i++) {
313 if (vp->uv[i] <= mp->uvlim[0][i])
314 return(-1);
315 if (vp->uv[i] >= mp->uvlim[1][i])
316 return(-1);
317 cv.uv[i] = (uint32)(4294967296. *
318 (vp->uv[i] - mp->uvlim[0][i]) /
319 (mp->uvlim[1][i] - mp->uvlim[0][i]));
320 }
321 cv.fl = vp->fl;
322 if (mp->lut.tsiz == 0) {
323 mp->lut.hashf = cvhash;
324 mp->lut.keycmp = cvcmp;
325 mp->lut.freek = free;
326 if (!lu_init(&mp->lut, 50000))
327 goto nomem;
328 }
329 /* find entry */
330 lvp = lu_find(&mp->lut, (char *)&cv);
331 if (lvp == NULL)
332 goto nomem;
333 if (lvp->key == NULL) {
334 lvp->key = (char *)malloc(sizeof(MCVERT)+sizeof(int32));
335 memcpy((void *)lvp->key, (void *)&cv, sizeof(MCVERT));
336 }
337 if (lvp->data == NULL) { /* new vertex */
338 register MESHPATCH *pp;
339 if (mp->npatches <= 0) {
340 mp->patch = (MESHPATCH *)calloc(MPATCHBLKSIZ,
341 sizeof(MESHPATCH));
342 if (mp->patch == NULL)
343 goto nomem;
344 mp->npatches = 1;
345 } else if (mp->patch[mp->npatches-1].nverts >= 256) {
346 if (mp->npatches % MPATCHBLKSIZ == 0) {
347 mp->patch = (MESHPATCH *)realloc(
348 (void *)mp->patch,
349 (mp->npatches + MPATCHBLKSIZ)*
350 sizeof(MESHPATCH));
351 memset((void *)(mp->patch + mp->npatches), '\0',
352 MPATCHBLKSIZ*sizeof(MESHPATCH));
353 }
354 if (mp->npatches++ >= 1L<<22)
355 error(INTERNAL, "too many mesh patches");
356 }
357 pp = &mp->patch[mp->npatches-1];
358 if (pp->xyz == NULL) {
359 pp->xyz = (uint32 (*)[3])calloc(256, 3*sizeof(int32));
360 if (pp->xyz == NULL)
361 goto nomem;
362 }
363 for (i = 0; i < 3; i++)
364 pp->xyz[pp->nverts][i] = cv.xyz[i];
365 if (cv.fl & MT_N) {
366 if (pp->norm == NULL) {
367 pp->norm = (int32 *)calloc(256, sizeof(int32));
368 if (pp->norm == NULL)
369 goto nomem;
370 }
371 pp->norm[pp->nverts] = cv.norm;
372 }
373 if (cv.fl & MT_UV) {
374 if (pp->uv == NULL) {
375 pp->uv = (uint32 (*)[2])calloc(256,
376 2*sizeof(uint32));
377 if (pp->uv == NULL)
378 goto nomem;
379 }
380 for (i = 0; i < 2; i++)
381 pp->uv[pp->nverts][i] = cv.uv[i];
382 }
383 pp->nverts++;
384 lvp->data = lvp->key + sizeof(MCVERT);
385 *(int32 *)lvp->data = (mp->npatches-1) << 8 | (pp->nverts-1);
386 }
387 return(*(int32 *)lvp->data);
388 nomem:
389 error(SYSTEM, "out of memory in addmeshvert");
390 return(-1);
391 }
392
393
394 OBJECT
395 addmeshtri(mp, tv, mo) /* add a new mesh triangle */
396 MESH *mp;
397 MESHVERT tv[3];
398 OBJECT mo;
399 {
400 int32 vid[3], t;
401 int pn[3], i;
402 register MESHPATCH *pp;
403
404 if (!(tv[0].fl & tv[1].fl & tv[2].fl & MT_V))
405 return(OVOID);
406 /* find/allocate patch vertices */
407 for (i = 0; i < 3; i++) {
408 if ((vid[i] = addmeshvert(mp, &tv[i])) < 0)
409 return(OVOID);
410 pn[i] = vid[i] >> 8;
411 }
412 /* normalize material index */
413 if (mo != OVOID) {
414 if ((mo -= mp->mat0) >= mp->nmats)
415 mp->nmats = mo+1;
416 else if (mo < 0)
417 error(INTERNAL, "modifier range error in addmeshtri");
418 }
419 /* assign triangle */
420 if (pn[0] == pn[1] && pn[1] == pn[2]) { /* local case */
421 pp = &mp->patch[pn[0]];
422 if (pp->tri == NULL) {
423 pp->tri = (struct PTri *)malloc(
424 512*sizeof(struct PTri));
425 if (pp->tri == NULL)
426 goto nomem;
427 }
428 if (pp->ntris < 512) {
429 pp->tri[pp->ntris].v1 = vid[0] & 0xff;
430 pp->tri[pp->ntris].v2 = vid[1] & 0xff;
431 pp->tri[pp->ntris].v3 = vid[2] & 0xff;
432 if (pp->ntris == 0)
433 pp->solemat = mo;
434 else if (pp->trimat == NULL && mo != pp->solemat) {
435 pp->trimat = (int16 *)malloc(
436 512*sizeof(int16));
437 if (pp->trimat == NULL)
438 goto nomem;
439 for (i = pp->ntris; i--; )
440 pp->trimat[i] = pp->solemat;
441 }
442 if (pp->trimat != NULL)
443 pp->trimat[pp->ntris] = mo;
444 return(pn[0] << 10 | pp->ntris++);
445 }
446 }
447 if (pn[0] == pn[1]) {
448 t = vid[2]; vid[2] = vid[1]; vid[1] = vid[0]; vid[0] = t;
449 i = pn[2]; pn[2] = pn[1]; pn[1] = pn[0]; pn[0] = i;
450 } else if (pn[0] == pn[2]) {
451 t = vid[0]; vid[0] = vid[1]; vid[1] = vid[2]; vid[2] = t;
452 i = pn[0]; pn[0] = pn[1]; pn[1] = pn[2]; pn[2] = i;
453 }
454 if (pn[1] == pn[2]) { /* single link */
455 pp = &mp->patch[pn[1]];
456 if (pp->j1tri == NULL) {
457 pp->j1tri = (struct PJoin1 *)malloc(
458 256*sizeof(struct PJoin1));
459 if (pp->j1tri == NULL)
460 goto nomem;
461 }
462 if (pp->nj1tris < 256) {
463 pp->j1tri[pp->nj1tris].v1j = vid[0];
464 pp->j1tri[pp->nj1tris].v2 = vid[1] & 0xff;
465 pp->j1tri[pp->nj1tris].v3 = vid[2] & 0xff;
466 pp->j1tri[pp->nj1tris].mat = mo;
467 return(pn[1] << 10 | 0x200 | pp->nj1tris++);
468 }
469 }
470 /* double link */
471 pp = &mp->patch[pn[2]];
472 if (pp->j2tri == NULL) {
473 pp->j2tri = (struct PJoin2 *)malloc(
474 256*sizeof(struct PJoin2));
475 if (pp->j2tri == NULL)
476 goto nomem;
477 }
478 if (pp->nj2tris >= 256)
479 error(INTERNAL, "too many patch triangles in addmeshtri");
480 pp->j2tri[pp->nj2tris].v1j = vid[0];
481 pp->j2tri[pp->nj2tris].v2j = vid[1];
482 pp->j2tri[pp->nj2tris].v3 = vid[2] & 0xff;
483 pp->j2tri[pp->nj2tris].mat = mo;
484 return(pn[2] << 10 | 0x300 | pp->nj2tris++);
485 nomem:
486 error(SYSTEM, "out of memory in addmeshtri");
487 return(OVOID);
488 }
489
490
491 char *
492 checkmesh(mp) /* validate mesh data */
493 register MESH *mp;
494 {
495 static char embuf[128];
496 int nouvbounds = 1;
497 register int i;
498 /* basic checks */
499 if (mp == NULL)
500 return("NULL mesh pointer");
501 if (!mp->ldflags)
502 return("unassigned mesh");
503 if (mp->name == NULL)
504 return("missing mesh name");
505 if (mp->nref <= 0)
506 return("unreferenced mesh");
507 /* check boundaries */
508 if (mp->ldflags & IO_BOUNDS) {
509 if (mp->mcube.cusize <= FTINY)
510 return("illegal octree bounds in mesh");
511 nouvbounds = (mp->uvlim[1][0] - mp->uvlim[0][0] <= FTINY ||
512 mp->uvlim[1][1] - mp->uvlim[0][1] <= FTINY);
513 }
514 /* check octree */
515 if (mp->ldflags & IO_TREE) {
516 if (isempty(mp->mcube.cutree))
517 error(WARNING, "empty mesh octree");
518 }
519 /* check scene data */
520 if (mp->ldflags & IO_SCENE) {
521 if (!(mp->ldflags & IO_BOUNDS))
522 return("unbounded scene in mesh");
523 if (mp->mat0 < 0 || mp->mat0+mp->nmats > nobjects)
524 return("bad mesh modifier range");
525 for (i = mp->mat0+mp->nmats; i-- > mp->mat0; ) {
526 int otyp = objptr(i)->otype;
527 if (!ismodifier(otyp)) {
528 sprintf(embuf,
529 "non-modifier in mesh (%s \"%s\")",
530 ofun[otyp].funame, objptr(i)->oname);
531 return(embuf);
532 }
533 }
534 if (mp->npatches <= 0)
535 error(WARNING, "no patches in mesh");
536 for (i = 0; i < mp->npatches; i++) {
537 register MESHPATCH *pp = &mp->patch[i];
538 if (pp->nverts <= 0)
539 error(WARNING, "no vertices in patch");
540 else {
541 if (pp->xyz == NULL)
542 return("missing patch vertex list");
543 if (nouvbounds && pp->uv != NULL)
544 return("unreferenced uv coordinates");
545 }
546 if (pp->ntris + pp->nj1tris + pp->nj2tris <= 0)
547 error(WARNING, "no triangles in patch");
548 if (pp->ntris > 0 && pp->tri == NULL)
549 return("missing patch triangle list");
550 if (pp->nj1tris > 0 && pp->j1tri == NULL)
551 return("missing patch joiner triangle list");
552 if (pp->nj2tris > 0 && pp->j2tri == NULL)
553 return("missing patch double-joiner list");
554 }
555 }
556 return(NULL); /* seems OK */
557 }
558
559
560 static void
561 tallyoctree(ot, ecp, lcp, ocp) /* tally octree size */
562 OCTREE ot;
563 int *ecp, *lcp, *ocp;
564 {
565 int i;
566
567 if (isempty(ot)) {
568 (*ecp)++;
569 return;
570 }
571 if (isfull(ot)) {
572 OBJECT oset[MAXSET+1];
573 (*lcp)++;
574 objset(oset, ot);
575 *ocp += oset[0];
576 return;
577 }
578 for (i = 0; i < 8; i++)
579 tallyoctree(octkid(ot, i), ecp, lcp, ocp);
580 }
581
582
583 void
584 printmeshstats(ms, fp) /* print out mesh statistics */
585 MESH *ms;
586 FILE *fp;
587 {
588 int lfcnt=0, lecnt=0, locnt=0;
589 int vcnt=0, ncnt=0, uvcnt=0;
590 int nscnt=0, uvscnt=0;
591 int tcnt=0, t1cnt=0, t2cnt=0;
592 int i, j;
593
594 tallyoctree(ms->mcube.cutree, &lecnt, &lfcnt, &locnt);
595 for (i = 0; i < ms->npatches; i++) {
596 register MESHPATCH *pp = &ms->patch[i];
597 vcnt += pp->nverts;
598 if (pp->norm != NULL) {
599 for (j = pp->nverts; j--; )
600 if (pp->norm[j])
601 ncnt++;
602 nscnt += pp->nverts;
603 }
604 if (pp->uv != NULL) {
605 for (j = pp->nverts; j--; )
606 if (pp->uv[j][0])
607 uvcnt++;
608 uvscnt += pp->nverts;
609 }
610 tcnt += pp->ntris;
611 t1cnt += pp->nj1tris;
612 t2cnt += pp->nj2tris;
613 }
614 fprintf(fp, "Mesh statistics:\n");
615 fprintf(fp, "\t%ld materials\n", ms->nmats);
616 fprintf(fp, "\t%d patches (%.2f MBytes)\n", ms->npatches,
617 (ms->npatches*sizeof(MESHPATCH) +
618 vcnt*3*sizeof(uint32) +
619 nscnt*sizeof(int32) +
620 uvscnt*2*sizeof(uint32) +
621 tcnt*sizeof(struct PTri) +
622 t1cnt*sizeof(struct PJoin1) +
623 t2cnt*sizeof(struct PJoin2))/(1024.*1024.));
624 fprintf(fp, "\t%d vertices (%.1f%% w/ normals, %.1f%% w/ uv)\n",
625 vcnt, 100.*ncnt/vcnt, 100.*uvcnt/vcnt);
626 fprintf(fp, "\t%d triangles (%.1f%% local, %.1f%% joiner)\n",
627 tcnt+t1cnt+t2cnt,
628 100.*tcnt/(tcnt+t1cnt+t2cnt),
629 100.*t1cnt/(tcnt+t1cnt+t2cnt));
630 fprintf(fp,
631 "\t%d leaves in octree (%.1f%% empty, %.2f avg. set size)\n",
632 lfcnt+lecnt, 100.*lecnt/(lfcnt+lecnt),
633 (double)locnt/lfcnt);
634 }
635
636
637 void
638 freemesh(ms) /* free mesh data */
639 register MESH *ms;
640 {
641 MESH mhead;
642 MESH *msp;
643
644 if (ms == NULL)
645 return;
646 if (ms->nref <= 0)
647 error(CONSISTENCY, "unreferenced mesh in freemesh");
648 ms->nref--;
649 if (ms->nref) /* still in use */
650 return;
651 /* else remove from list */
652 mhead.next = mlist;
653 for (msp = &mhead; msp->next != NULL; msp = msp->next)
654 if (msp->next == ms) {
655 msp->next = ms->next;
656 ms->next = NULL;
657 break;
658 }
659 if (ms->next != NULL) /* can't be in list anymore */
660 error(CONSISTENCY, "unlisted mesh in freemesh");
661 mlist = mhead.next;
662 /* free mesh data */
663 freestr(ms->name);
664 octfree(ms->mcube.cutree);
665 lu_done(&ms->lut);
666 if (ms->npatches > 0) {
667 register MESHPATCH *pp = ms->patch + ms->npatches;
668 while (pp-- > ms->patch) {
669 if (pp->j2tri != NULL)
670 free((void *)pp->j2tri);
671 if (pp->j1tri != NULL)
672 free((void *)pp->j1tri);
673 if (pp->tri != NULL)
674 free((void *)pp->tri);
675 if (pp->uv != NULL)
676 free((void *)pp->uv);
677 if (pp->norm != NULL)
678 free((void *)pp->norm);
679 if (pp->xyz != NULL)
680 free((void *)pp->xyz);
681 }
682 free((void *)ms->patch);
683 }
684 if (ms->pseudo != NULL)
685 free((void *)ms->pseudo);
686 free((void *)ms);
687 }
688
689
690 void
691 freemeshinst(o) /* free mesh instance */
692 OBJREC *o;
693 {
694 if (o->os == NULL)
695 return;
696 freemesh((*(MESHINST *)o->os).msh);
697 free((void *)o->os);
698 o->os = NULL;
699 }