ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/common/mesh.c
Revision: 2.32
Committed: Sat Dec 28 18:05:14 2019 UTC (4 years, 4 months ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 2.31: +1 -3 lines
Log Message:
Removed redundant include files

File Contents

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