ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/common/mesh.c
Revision: 2.15
Committed: Fri Nov 14 17:22:06 2003 UTC (20 years, 5 months ago) by schorsch
Content type: text/plain
Branch: MAIN
Changes since 2.14: +5 -2 lines
Log Message:
Reduced compile warnings, and other compatibility fixes.

File Contents

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