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

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