ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/common/mesh.c
Revision: 2.9
Committed: Mon Jun 30 14:59:11 2003 UTC (20 years, 10 months ago) by schorsch
Content type: text/plain
Branch: MAIN
Changes since 2.8: +5 -3 lines
Log Message:
Replaced most outdated BSD function calls with their posix equivalents, and cleaned up a few other platform dependencies.

File Contents

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