ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/common/mesh.c
Revision: 2.16
Committed: Fri Jan 30 00:08:31 2004 UTC (20 years, 3 months ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 2.15: +8 -9 lines
Log Message:
Returned to 32-bit (x2) uv coordinates, since 16-bits was sometimes inadequate

File Contents

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