ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/common/mesh.c
Revision: 2.31
Committed: Tue Nov 27 06:20:37 2018 UTC (5 years, 5 months ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 2.30: +22 -20 lines
Log Message:
Added missing free() call

File Contents

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