ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/common/mesh.c
Revision: 2.25
Committed: Tue Nov 6 01:56:37 2012 UTC (11 years, 5 months ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 2.24: +27 -27 lines
Log Message:
Fixed potential bugs in new routine -- still untested

File Contents

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