ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/common/mesh.c
Revision: 2.26
Committed: Tue Nov 6 17:12:35 2012 UTC (11 years, 5 months ago) by greg
Content type: text/plain
Branch: MAIN
CVS Tags: rad4R2P2, rad5R0, rad4R2, rad4R2P1
Changes since 2.25: +5 -19 lines
Log Message:
Simplified nextmeshtri() logic considerably

File Contents

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