ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/common/mesh.c
Revision: 2.10
Committed: Thu Jul 10 03:30:11 2003 UTC (20 years, 9 months ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 2.9: +11 -12 lines
Log Message:
Fixed potential bug in reference counting of mesh'es and instance's

File Contents

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