ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/common/mesh.c
Revision: 2.17
Committed: Thu Feb 12 18:55:50 2004 UTC (20 years, 2 months ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 2.16: +2 -1 lines
Log Message:
Moved paths.h out of rtio.h and included it manually where R_OK was needed

File Contents

# User Rev Content
1 greg 2.1 #ifndef lint
2 greg 2.17 static const char RCSid[] = "$Id: mesh.c,v 2.16 2004/01/30 00:08:31 greg Exp $";
3 greg 2.1 #endif
4     /*
5     * Mesh support routines
6     */
7    
8 schorsch 2.9 #include <string.h>
9    
10 schorsch 2.15 #include "rtio.h"
11     #include "rtmath.h"
12     #include "rterror.h"
13 greg 2.17 #include "paths.h"
14 greg 2.1 #include "octree.h"
15     #include "object.h"
16 greg 2.4 #include "otypes.h"
17 greg 2.1 #include "mesh.h"
18    
19     /* An encoded mesh vertex */
20     typedef struct {
21     int fl;
22 greg 2.8 uint32 xyz[3];
23     int32 norm;
24 greg 2.16 uint32 uv[2];
25 greg 2.1 } 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 greg 2.10 getmesh(mname, flags) /* get new mesh data reference */
77 greg 2.1 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 greg 2.11 if (!strcmp(mname, ms->name)) {
86     ms->nref++; /* increase reference count */
87 greg 2.10 break;
88 greg 2.11 }
89 greg 2.10 if (ms == NULL) { /* load first time */
90 greg 2.1 ms = (MESH *)calloc(1, sizeof(MESH));
91     if (ms == NULL)
92     error(SYSTEM, "out of memory in getmesh");
93     ms->name = savestr(mname);
94 greg 2.11 ms->nref = 1;
95 greg 2.1 ms->mcube.cutree = EMPTY;
96     ms->next = mlist;
97     mlist = ms;
98     }
99 greg 2.7 if ((pathname = getpath(mname, getrlibpath(), R_OK)) == NULL) {
100 greg 2.1 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 greg 2.10 if (ins->msh == NULL)
134 greg 2.1 ins->msh = getmesh(o->oargs.sarg[0], flags);
135 greg 2.10 else if ((flags &= ~ins->msh->ldflags))
136     readmesh(ins->msh,
137     getpath(o->oargs.sarg[0], getrlibpath(), R_OK),
138     flags);
139 greg 2.1 return(ins);
140     }
141    
142    
143     int
144 greg 2.4 getmeshtrivid(tvid, mo, mp, ti) /* get triangle vertex ID's */
145 greg 2.8 int32 tvid[3];
146 greg 2.4 OBJECT *mo;
147     MESH *mp;
148     OBJECT ti;
149 greg 2.1 {
150     int pn = ti >> 10;
151 greg 2.4 MESHPATCH *pp;
152 greg 2.1
153     if (pn >= mp->npatches)
154     return(0);
155 greg 2.4 pp = &mp->patch[pn];
156 greg 2.1 ti &= 0x3ff;
157     if (!(ti & 0x200)) { /* local triangle */
158     struct PTri *tp;
159 greg 2.4 if (ti >= pp->ntris)
160 greg 2.1 return(0);
161 greg 2.4 tp = &pp->tri[ti];
162 greg 2.1 tvid[0] = tvid[1] = tvid[2] = pn << 8;
163     tvid[0] |= tp->v1;
164     tvid[1] |= tp->v2;
165     tvid[2] |= tp->v3;
166 greg 2.4 if (pp->trimat != NULL)
167     *mo = pp->trimat[ti];
168     else
169     *mo = pp->solemat;
170     if (*mo != OVOID)
171     *mo += mp->mat0;
172 greg 2.1 return(1);
173     }
174     ti &= ~0x200;
175     if (!(ti & 0x100)) { /* single link vertex */
176     struct PJoin1 *tp1;
177 greg 2.4 if (ti >= pp->nj1tris)
178 greg 2.1 return(0);
179 greg 2.4 tp1 = &pp->j1tri[ti];
180 greg 2.1 tvid[0] = tp1->v1j;
181     tvid[1] = tvid[2] = pn << 8;
182     tvid[1] |= tp1->v2;
183     tvid[2] |= tp1->v3;
184 greg 2.4 if ((*mo = tp1->mat) != OVOID)
185     *mo += mp->mat0;
186 greg 2.1 return(1);
187     }
188     ti &= ~0x100;
189     { /* double link vertex */
190     struct PJoin2 *tp2;
191 greg 2.4 if (ti >= pp->nj2tris)
192 greg 2.1 return(0);
193 greg 2.4 tp2 = &pp->j2tri[ti];
194 greg 2.1 tvid[0] = tp2->v1j;
195     tvid[1] = tp2->v2j;
196     tvid[2] = pn << 8 | tp2->v3;
197 greg 2.4 if ((*mo = tp2->mat) != OVOID)
198     *mo += mp->mat0;
199 greg 2.1 }
200     return(1);
201     }
202    
203    
204     int
205     getmeshvert(vp, mp, vid, what) /* get triangle vertex from ID */
206 greg 2.6 MESHVERT *vp;
207     MESH *mp;
208 greg 2.8 int32 vid;
209 greg 2.6 int what;
210 greg 2.1 {
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 greg 2.2 vp->uv[i] = mp->uvlim[0][i] +
240     (mp->uvlim[1][i] - mp->uvlim[0][i])*
241 greg 2.16 (pp->uv[vid][i] + .5)*(1./4294967296.);
242 greg 2.1 vp->fl |= MT_UV;
243     }
244     return(vp->fl);
245     }
246    
247    
248 greg 2.4 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 greg 2.1 int
271 greg 2.4 getmeshtri(tv, mo, mp, ti, wha) /* get triangle vertices */
272 greg 2.1 MESHVERT tv[3];
273 greg 2.4 OBJECT *mo;
274 greg 2.1 MESH *mp;
275     OBJECT ti;
276 greg 2.4 int wha;
277 greg 2.1 {
278 greg 2.8 int32 tvid[3];
279 greg 2.1
280 greg 2.4 if (!getmeshtrivid(tvid, mo, mp, ti))
281 greg 2.1 return(0);
282    
283 greg 2.4 getmeshvert(&tv[0], mp, tvid[0], wha);
284     getmeshvert(&tv[1], mp, tvid[1], wha);
285     getmeshvert(&tv[2], mp, tvid[2], wha);
286 greg 2.1
287     return(tv[0].fl & tv[1].fl & tv[2].fl);
288     }
289    
290    
291 greg 2.8 int32
292 greg 2.1 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 greg 2.8 cv.xyz[i] = (uint32)(4294967296. *
309 greg 2.1 (vp->v[i] - mp->mcube.cuorg[i]) /
310     mp->mcube.cusize);
311     }
312 greg 2.16 if (vp->fl & MT_N) /* assumes normalized! */
313 greg 2.1 cv.norm = encodedir(vp->n);
314     if (vp->fl & MT_UV)
315     for (i = 0; i < 2; i++) {
316 greg 2.2 if (vp->uv[i] <= mp->uvlim[0][i])
317 greg 2.1 return(-1);
318 greg 2.2 if (vp->uv[i] >= mp->uvlim[1][i])
319 greg 2.1 return(-1);
320 greg 2.16 cv.uv[i] = (uint32)(4294967296. *
321 greg 2.2 (vp->uv[i] - mp->uvlim[0][i]) /
322     (mp->uvlim[1][i] - mp->uvlim[0][i]));
323 greg 2.1 }
324     cv.fl = vp->fl;
325 greg 2.4 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 greg 2.1 goto nomem;
331     }
332     /* find entry */
333 greg 2.4 lvp = lu_find(&mp->lut, (char *)&cv);
334 greg 2.1 if (lvp == NULL)
335     goto nomem;
336     if (lvp->key == NULL) {
337 greg 2.8 lvp->key = (char *)malloc(sizeof(MCVERT)+sizeof(int32));
338 schorsch 2.9 memcpy((void *)lvp->key, (void *)&cv, sizeof(MCVERT));
339 greg 2.1 }
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 schorsch 2.9 memset((void *)(mp->patch + mp->npatches), '\0',
355 greg 2.1 MPATCHBLKSIZ*sizeof(MESHPATCH));
356     }
357 greg 2.2 if (mp->npatches++ >= 1L<<22)
358 greg 2.1 error(INTERNAL, "too many mesh patches");
359     }
360     pp = &mp->patch[mp->npatches-1];
361     if (pp->xyz == NULL) {
362 greg 2.8 pp->xyz = (uint32 (*)[3])calloc(256, 3*sizeof(int32));
363 greg 2.1 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 greg 2.8 pp->norm = (int32 *)calloc(256, sizeof(int32));
371 greg 2.1 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 greg 2.16 pp->uv = (uint32 (*)[2])calloc(256,
379     2*sizeof(uint32));
380 greg 2.1 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 greg 2.8 *(int32 *)lvp->data = (mp->npatches-1) << 8 | (pp->nverts-1);
389 greg 2.1 }
390 greg 2.8 return(*(int32 *)lvp->data);
391 greg 2.1 nomem:
392     error(SYSTEM, "out of memory in addmeshvert");
393     return(-1);
394     }
395    
396    
397     OBJECT
398 greg 2.4 addmeshtri(mp, tv, mo) /* add a new mesh triangle */
399 greg 2.1 MESH *mp;
400     MESHVERT tv[3];
401 greg 2.4 OBJECT mo;
402 greg 2.1 {
403 greg 2.8 int32 vid[3], t;
404 greg 2.1 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 greg 2.4 /* normalize material index */
416 schorsch 2.13 if (mo != OVOID) {
417 greg 2.4 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 schorsch 2.13 }
422 greg 2.1 /* 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 greg 2.2 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 greg 2.4 if (pp->ntris == 0)
436     pp->solemat = mo;
437     else if (pp->trimat == NULL && mo != pp->solemat) {
438 greg 2.8 pp->trimat = (int16 *)malloc(
439     512*sizeof(int16));
440 greg 2.4 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 greg 2.2 return(pn[0] << 10 | pp->ntris++);
448     }
449 greg 2.1 }
450     if (pn[0] == pn[1]) {
451 greg 2.2 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 greg 2.1 } else if (pn[0] == pn[2]) {
454 greg 2.2 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 greg 2.1 }
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 greg 2.2 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 greg 2.4 pp->j1tri[pp->nj1tris].mat = mo;
470 greg 2.2 return(pn[1] << 10 | 0x200 | pp->nj1tris++);
471     }
472 greg 2.1 }
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 greg 2.2 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 greg 2.1 pp->j2tri[pp->nj2tris].v3 = vid[2] & 0xff;
486 greg 2.4 pp->j2tri[pp->nj2tris].mat = mo;
487 greg 2.1 return(pn[2] << 10 | 0x300 | pp->nj2tris++);
488     nomem:
489     error(SYSTEM, "out of memory in addmeshtri");
490     return(OVOID);
491     }
492    
493    
494 greg 2.4 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 greg 2.5 nouvbounds = (mp->uvlim[1][0] - mp->uvlim[0][0] <= FTINY ||
515     mp->uvlim[1][1] - mp->uvlim[0][1] <= FTINY);
516 greg 2.4 }
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 greg 2.1 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 schorsch 2.12 fprintf(fp, "\t%ld materials\n", ms->nmats);
619 greg 2.1 fprintf(fp, "\t%d patches (%.2f MBytes)\n", ms->npatches,
620     (ms->npatches*sizeof(MESHPATCH) +
621 greg 2.8 vcnt*3*sizeof(uint32) +
622     nscnt*sizeof(int32) +
623 greg 2.16 uvscnt*2*sizeof(uint32) +
624 greg 2.1 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 greg 2.4 register MESH *ms;
643 greg 2.1 {
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 greg 2.4 lu_done(&ms->lut);
669 greg 2.1 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 greg 2.4 if (ms->pseudo != NULL)
688     free((void *)ms->pseudo);
689 greg 2.1 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     }