ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/common/mesh.c
Revision: 2.11
Committed: Thu Jul 10 03:47:00 2003 UTC (20 years, 9 months ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 2.10: +5 -3 lines
Log Message:
Fixed serious bug in ranimate where mesh instances were not being freed

File Contents

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