ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/common/mesh.c
Revision: 2.6
Committed: Wed Apr 23 00:52:33 2003 UTC (21 years ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 2.5: +4 -4 lines
Log Message:
Added (void *) cast to realloc calls

File Contents

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