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

# User Rev Content
1 greg 2.1 #ifndef lint
2 greg 2.10 static const char RCSid[] = "$Id: mesh.c,v 2.9 2003/06/30 14:59:11 schorsch 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.10 if (!strcmp(mname, ms->name))
83     break;
84     if (ms == NULL) { /* load first time */
85 greg 2.1 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 greg 2.7 if ((pathname = getpath(mname, getrlibpath(), R_OK)) == NULL) {
94 greg 2.1 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 greg 2.10 ms->nref++; /* increase reference count */
101 greg 2.1 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 greg 2.10 if (ins->msh == NULL)
129 greg 2.1 ins->msh = getmesh(o->oargs.sarg[0], flags);
130 greg 2.10 else if ((flags &= ~ins->msh->ldflags))
131     readmesh(ins->msh,
132     getpath(o->oargs.sarg[0], getrlibpath(), R_OK),
133     flags);
134 greg 2.1 return(ins);
135     }
136    
137    
138     int
139 greg 2.4 getmeshtrivid(tvid, mo, mp, ti) /* get triangle vertex ID's */
140 greg 2.8 int32 tvid[3];
141 greg 2.4 OBJECT *mo;
142     MESH *mp;
143     OBJECT ti;
144 greg 2.1 {
145     int pn = ti >> 10;
146 greg 2.4 MESHPATCH *pp;
147 greg 2.1
148     if (pn >= mp->npatches)
149     return(0);
150 greg 2.4 pp = &mp->patch[pn];
151 greg 2.1 ti &= 0x3ff;
152     if (!(ti & 0x200)) { /* local triangle */
153     struct PTri *tp;
154 greg 2.4 if (ti >= pp->ntris)
155 greg 2.1 return(0);
156 greg 2.4 tp = &pp->tri[ti];
157 greg 2.1 tvid[0] = tvid[1] = tvid[2] = pn << 8;
158     tvid[0] |= tp->v1;
159     tvid[1] |= tp->v2;
160     tvid[2] |= tp->v3;
161 greg 2.4 if (pp->trimat != NULL)
162     *mo = pp->trimat[ti];
163     else
164     *mo = pp->solemat;
165     if (*mo != OVOID)
166     *mo += mp->mat0;
167 greg 2.1 return(1);
168     }
169     ti &= ~0x200;
170     if (!(ti & 0x100)) { /* single link vertex */
171     struct PJoin1 *tp1;
172 greg 2.4 if (ti >= pp->nj1tris)
173 greg 2.1 return(0);
174 greg 2.4 tp1 = &pp->j1tri[ti];
175 greg 2.1 tvid[0] = tp1->v1j;
176     tvid[1] = tvid[2] = pn << 8;
177     tvid[1] |= tp1->v2;
178     tvid[2] |= tp1->v3;
179 greg 2.4 if ((*mo = tp1->mat) != OVOID)
180     *mo += mp->mat0;
181 greg 2.1 return(1);
182     }
183     ti &= ~0x100;
184     { /* double link vertex */
185     struct PJoin2 *tp2;
186 greg 2.4 if (ti >= pp->nj2tris)
187 greg 2.1 return(0);
188 greg 2.4 tp2 = &pp->j2tri[ti];
189 greg 2.1 tvid[0] = tp2->v1j;
190     tvid[1] = tp2->v2j;
191     tvid[2] = pn << 8 | tp2->v3;
192 greg 2.4 if ((*mo = tp2->mat) != OVOID)
193     *mo += mp->mat0;
194 greg 2.1 }
195     return(1);
196     }
197    
198    
199     int
200     getmeshvert(vp, mp, vid, what) /* get triangle vertex from ID */
201 greg 2.6 MESHVERT *vp;
202     MESH *mp;
203 greg 2.8 int32 vid;
204 greg 2.6 int what;
205 greg 2.1 {
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 greg 2.2 vp->uv[i] = mp->uvlim[0][i] +
235     (mp->uvlim[1][i] - mp->uvlim[0][i])*
236 greg 2.1 (pp->uv[vid][i] + .5)*(1./4294967296.);
237     vp->fl |= MT_UV;
238     }
239     return(vp->fl);
240     }
241    
242    
243 greg 2.4 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 greg 2.1 int
266 greg 2.4 getmeshtri(tv, mo, mp, ti, wha) /* get triangle vertices */
267 greg 2.1 MESHVERT tv[3];
268 greg 2.4 OBJECT *mo;
269 greg 2.1 MESH *mp;
270     OBJECT ti;
271 greg 2.4 int wha;
272 greg 2.1 {
273 greg 2.8 int32 tvid[3];
274 greg 2.1
275 greg 2.4 if (!getmeshtrivid(tvid, mo, mp, ti))
276 greg 2.1 return(0);
277    
278 greg 2.4 getmeshvert(&tv[0], mp, tvid[0], wha);
279     getmeshvert(&tv[1], mp, tvid[1], wha);
280     getmeshvert(&tv[2], mp, tvid[2], wha);
281 greg 2.1
282     return(tv[0].fl & tv[1].fl & tv[2].fl);
283     }
284    
285    
286 greg 2.8 int32
287 greg 2.1 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 greg 2.8 cv.xyz[i] = (uint32)(4294967296. *
304 greg 2.1 (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 greg 2.2 if (vp->uv[i] <= mp->uvlim[0][i])
312 greg 2.1 return(-1);
313 greg 2.2 if (vp->uv[i] >= mp->uvlim[1][i])
314 greg 2.1 return(-1);
315 greg 2.8 cv.uv[i] = (uint32)(4294967296. *
316 greg 2.2 (vp->uv[i] - mp->uvlim[0][i]) /
317     (mp->uvlim[1][i] - mp->uvlim[0][i]));
318 greg 2.1 }
319     cv.fl = vp->fl;
320 greg 2.4 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 greg 2.1 goto nomem;
326     }
327     /* find entry */
328 greg 2.4 lvp = lu_find(&mp->lut, (char *)&cv);
329 greg 2.1 if (lvp == NULL)
330     goto nomem;
331     if (lvp->key == NULL) {
332 greg 2.8 lvp->key = (char *)malloc(sizeof(MCVERT)+sizeof(int32));
333 schorsch 2.9 memcpy((void *)lvp->key, (void *)&cv, sizeof(MCVERT));
334 greg 2.1 }
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 schorsch 2.9 memset((void *)(mp->patch + mp->npatches), '\0',
350 greg 2.1 MPATCHBLKSIZ*sizeof(MESHPATCH));
351     }
352 greg 2.2 if (mp->npatches++ >= 1L<<22)
353 greg 2.1 error(INTERNAL, "too many mesh patches");
354     }
355     pp = &mp->patch[mp->npatches-1];
356     if (pp->xyz == NULL) {
357 greg 2.8 pp->xyz = (uint32 (*)[3])calloc(256, 3*sizeof(int32));
358 greg 2.1 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 greg 2.8 pp->norm = (int32 *)calloc(256, sizeof(int32));
366 greg 2.1 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 greg 2.8 pp->uv = (uint32 (*)[2])calloc(256,
374     2*sizeof(uint32));
375 greg 2.1 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 greg 2.8 *(int32 *)lvp->data = (mp->npatches-1) << 8 | (pp->nverts-1);
384 greg 2.1 }
385 greg 2.8 return(*(int32 *)lvp->data);
386 greg 2.1 nomem:
387     error(SYSTEM, "out of memory in addmeshvert");
388     return(-1);
389     }
390    
391    
392     OBJECT
393 greg 2.4 addmeshtri(mp, tv, mo) /* add a new mesh triangle */
394 greg 2.1 MESH *mp;
395     MESHVERT tv[3];
396 greg 2.4 OBJECT mo;
397 greg 2.1 {
398 greg 2.8 int32 vid[3], t;
399 greg 2.1 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 greg 2.4 /* 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 greg 2.1 /* 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 greg 2.2 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 greg 2.4 if (pp->ntris == 0)
430     pp->solemat = mo;
431     else if (pp->trimat == NULL && mo != pp->solemat) {
432 greg 2.8 pp->trimat = (int16 *)malloc(
433     512*sizeof(int16));
434 greg 2.4 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 greg 2.2 return(pn[0] << 10 | pp->ntris++);
442     }
443 greg 2.1 }
444     if (pn[0] == pn[1]) {
445 greg 2.2 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 greg 2.1 } else if (pn[0] == pn[2]) {
448 greg 2.2 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 greg 2.1 }
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 greg 2.2 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 greg 2.4 pp->j1tri[pp->nj1tris].mat = mo;
464 greg 2.2 return(pn[1] << 10 | 0x200 | pp->nj1tris++);
465     }
466 greg 2.1 }
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 greg 2.2 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 greg 2.1 pp->j2tri[pp->nj2tris].v3 = vid[2] & 0xff;
480 greg 2.4 pp->j2tri[pp->nj2tris].mat = mo;
481 greg 2.1 return(pn[2] << 10 | 0x300 | pp->nj2tris++);
482     nomem:
483     error(SYSTEM, "out of memory in addmeshtri");
484     return(OVOID);
485     }
486    
487    
488 greg 2.4 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 greg 2.5 nouvbounds = (mp->uvlim[1][0] - mp->uvlim[0][0] <= FTINY ||
509     mp->uvlim[1][1] - mp->uvlim[0][1] <= FTINY);
510 greg 2.4 }
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 greg 2.1 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 greg 2.4 fprintf(fp, "\t%d materials\n", ms->nmats);
613 greg 2.1 fprintf(fp, "\t%d patches (%.2f MBytes)\n", ms->npatches,
614     (ms->npatches*sizeof(MESHPATCH) +
615 greg 2.8 vcnt*3*sizeof(uint32) +
616     nscnt*sizeof(int32) +
617     uvscnt*2*sizeof(uint32) +
618 greg 2.1 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 greg 2.4 register MESH *ms;
637 greg 2.1 {
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 greg 2.4 lu_done(&ms->lut);
663 greg 2.1 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 greg 2.4 if (ms->pseudo != NULL)
682     free((void *)ms->pseudo);
683 greg 2.1 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     }