ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/common/mesh.c
Revision: 2.19
Committed: Sun Mar 28 20:33:12 2004 UTC (20 years, 1 month ago) by schorsch
Content type: text/plain
Branch: MAIN
Changes since 2.18: +12 -5 lines
Log Message:
Continued ANSIfication, and other fixes and clarifications.

File Contents

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