ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/common/mesh.c
Revision: 2.30
Committed: Tue Nov 27 01:04:33 2018 UTC (5 years, 5 months ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 2.29: +3 -3 lines
Log Message:
Realized I didn't need to minimize array size in every patch to avoid overflow

File Contents

# Content
1 #ifndef lint
2 static const char RCSid[] = "$Id: mesh.c,v 2.29 2018/11/27 00:42:26 greg Exp $";
3 #endif
4 /*
5 * Mesh support routines
6 */
7
8 #include <string.h>
9
10 #include "rtio.h"
11 #include "rtmath.h"
12 #include "rterror.h"
13 #include "paths.h"
14 #include "octree.h"
15 #include "object.h"
16 #include "otypes.h"
17 #include "mesh.h"
18
19 /* An encoded mesh vertex */
20 typedef struct {
21 int fl;
22 uint32 xyz[3];
23 int32 norm;
24 uint32 uv[2];
25 } 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 cvhash(const char *p) /* hash an encoded vertex */
36 {
37 const MCVERT *cvp = (const MCVERT *)p;
38 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 cvcmp(const char *vv1, const char *vv2) /* compare encoded vertices */
53 {
54 const MCVERT *v1 = (const MCVERT *)vv1, *v2 = (const MCVERT *)vv2;
55
56 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 getmesh( /* get new mesh data reference */
78 char *mname,
79 int flags
80 )
81 {
82 char *pathname;
83 MESH *ms;
84
85 flags &= IO_LEGAL;
86 for (ms = mlist; ms != NULL; ms = ms->next)
87 if (!strcmp(mname, ms->name)) {
88 ms->nref++; /* increase reference count */
89 break;
90 }
91 if (ms == NULL) { /* load first time */
92 ms = (MESH *)calloc(1, sizeof(MESH));
93 if (ms == NULL)
94 error(SYSTEM, "out of memory in getmesh");
95 ms->name = savestr(mname);
96 ms->nref = 1;
97 ms->mcube.cutree = EMPTY;
98 ms->next = mlist;
99 mlist = ms;
100 }
101 if ((pathname = getpath(mname, getrlibpath(), R_OK)) == NULL) {
102 sprintf(errmsg, "cannot find mesh file \"%s\"", mname);
103 error(SYSTEM, errmsg);
104 }
105 flags &= ~ms->ldflags;
106 if (flags)
107 readmesh(ms, pathname, flags);
108 return(ms);
109 }
110
111
112 MESHINST *
113 getmeshinst( /* create mesh instance */
114 OBJREC *o,
115 int flags
116 )
117 {
118 MESHINST *ins;
119
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 if (ins->msh == NULL)
137 ins->msh = getmesh(o->oargs.sarg[0], flags);
138 else if ((flags &= ~ins->msh->ldflags))
139 readmesh(ins->msh,
140 getpath(o->oargs.sarg[0], getrlibpath(), R_OK),
141 flags);
142 return(ins);
143 }
144
145
146 int
147 nextmeshtri( /* get next triangle ID */
148 OBJECT *tip,
149 MESH *mp
150 )
151 {
152 int pn;
153 MESHPATCH *pp;
154
155 pn = ++(*tip) >> 10; /* next triangle (OVOID init) */
156 while (pn < mp->npatches) {
157 pp = &mp->patch[pn];
158 if (!(*tip & 0x200)) { /* local triangle? */
159 if ((*tip & 0x1ff) < pp->ntris)
160 return(1);
161 *tip &= ~0x1ff; /* move on to single-joiners */
162 *tip |= 0x200;
163 }
164 if (!(*tip & 0x100)) { /* single joiner? */
165 if ((*tip & 0xff) < pp->nj1tris)
166 return(1);
167 *tip &= ~0xff; /* move on to double-joiners */
168 *tip |= 0x100;
169 }
170 if ((*tip & 0xff) < pp->nj2tris)
171 return(1);
172 *tip = ++pn << 10; /* first in next patch */
173 }
174 return(0); /* out of patches */
175 }
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 {
185 int pn = ti >> 10;
186 MESHPATCH *pp;
187
188 if (pn >= mp->npatches)
189 return(0);
190 pp = &mp->patch[pn];
191 ti &= 0x3ff;
192 if (!(ti & 0x200)) { /* local triangle */
193 struct PTri *tp;
194 if (ti >= pp->ntris)
195 return(0);
196 tp = &pp->tri[ti];
197 tvid[0] = tvid[1] = tvid[2] = pn << 8;
198 tvid[0] |= tp->v1;
199 tvid[1] |= tp->v2;
200 tvid[2] |= tp->v3;
201 if (pp->trimat != NULL)
202 *mo = pp->trimat[ti];
203 else
204 *mo = pp->solemat;
205 if (*mo != OVOID)
206 *mo += mp->mat0;
207 return(1);
208 }
209 ti &= ~0x200;
210 if (!(ti & 0x100)) { /* single link vertex */
211 struct PJoin1 *tp1;
212 if (ti >= pp->nj1tris)
213 return(0);
214 tp1 = &pp->j1tri[ti];
215 tvid[0] = tp1->v1j;
216 tvid[1] = tvid[2] = pn << 8;
217 tvid[1] |= tp1->v2;
218 tvid[2] |= tp1->v3;
219 if ((*mo = tp1->mat) != OVOID)
220 *mo += mp->mat0;
221 return(1);
222 }
223 ti &= ~0x100;
224 { /* double link vertex */
225 struct PJoin2 *tp2;
226 if (ti >= pp->nj2tris)
227 return(0);
228 tp2 = &pp->j2tri[ti];
229 tvid[0] = tp2->v1j;
230 tvid[1] = tp2->v2j;
231 tvid[2] = pn << 8 | tp2->v3;
232 if ((*mo = tp2->mat) != OVOID)
233 *mo += mp->mat0;
234 }
235 return(1);
236 }
237
238
239 int
240 getmeshvert( /* get triangle vertex from ID */
241 MESHVERT *vp,
242 MESH *mp,
243 int32 vid,
244 int what
245 )
246 {
247 int pn = vid >> 8;
248 MESHPATCH *pp;
249 double vres;
250 int i;
251
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 vp->uv[i] = mp->uvlim[0][i] +
276 (mp->uvlim[1][i] - mp->uvlim[0][i])*
277 (pp->uv[vid][i] + .5)*(1./4294967296.);
278 vp->fl |= MT_UV;
279 }
280 return(vp->fl);
281 }
282
283
284 OBJREC *
285 getmeshpseudo( /* get mesh pseudo object for material */
286 MESH *mp,
287 OBJECT mo
288 )
289 {
290 if (mo < mp->mat0 || mo >= mp->mat0 + mp->nmats)
291 error(INTERNAL, "modifier out of range in getmeshpseudo");
292 if (mp->pseudo == NULL) {
293 int i;
294 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 int
308 getmeshtri( /* get triangle vertices */
309 MESHVERT tv[3],
310 OBJECT *mo,
311 MESH *mp,
312 OBJECT ti,
313 int wha
314 )
315 {
316 int32 tvid[3];
317
318 if (!getmeshtrivid(tvid, mo, mp, ti))
319 return(0);
320
321 getmeshvert(&tv[0], mp, tvid[0], wha);
322 getmeshvert(&tv[1], mp, tvid[1], wha);
323 getmeshvert(&tv[2], mp, tvid[2], wha);
324
325 return(tv[0].fl & tv[1].fl & tv[2].fl);
326 }
327
328
329 int32
330 addmeshvert( /* find/add a mesh vertex */
331 MESH *mp,
332 MESHVERT *vp
333 )
334 {
335 LUENT *lvp;
336 MCVERT cv;
337 int i;
338
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 cv.xyz[i] = (uint32)(4294967296. *
348 (vp->v[i] - mp->mcube.cuorg[i]) /
349 mp->mcube.cusize);
350 }
351 if (vp->fl & MT_N) /* assumes normalized! */
352 cv.norm = encodedir(vp->n);
353 if (vp->fl & MT_UV)
354 for (i = 0; i < 2; i++) {
355 if (vp->uv[i] <= mp->uvlim[0][i])
356 return(-1);
357 if (vp->uv[i] >= mp->uvlim[1][i])
358 return(-1);
359 cv.uv[i] = (uint32)(4294967296. *
360 (vp->uv[i] - mp->uvlim[0][i]) /
361 (mp->uvlim[1][i] - mp->uvlim[0][i]));
362 }
363 cv.fl = vp->fl;
364 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 goto nomem;
370 }
371 /* find entry */
372 lvp = lu_find(&mp->lut, (char *)&cv);
373 if (lvp == NULL)
374 goto nomem;
375 if (lvp->key == NULL) {
376 lvp->key = (char *)malloc(sizeof(MCVERT)+sizeof(int32));
377 memcpy((void *)lvp->key, (void *)&cv, sizeof(MCVERT));
378 }
379 if (lvp->data == NULL) { /* new vertex */
380 MESHPATCH *pp;
381 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 if (mp->npatches % MPATCHBLKSIZ == 0) {
389 mp->patch = (MESHPATCH *)realloc(
390 (void *)mp->patch,
391 (mp->npatches + MPATCHBLKSIZ)*
392 sizeof(MESHPATCH));
393 memset((void *)(mp->patch + mp->npatches), '\0',
394 MPATCHBLKSIZ*sizeof(MESHPATCH));
395 }
396 if (mp->npatches++ >= 1L<<22)
397 error(INTERNAL, "too many mesh patches");
398 }
399 pp = &mp->patch[mp->npatches-1];
400 if (pp->xyz == NULL) {
401 pp->xyz = (uint32 (*)[3])calloc(256, 3*sizeof(int32));
402 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 pp->norm = (int32 *)calloc(256, sizeof(int32));
410 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 pp->uv = (uint32 (*)[2])calloc(256,
418 2*sizeof(uint32));
419 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 *(int32 *)lvp->data = (mp->npatches-1) << 8 | (pp->nverts-1);
428 }
429 return(*(int32 *)lvp->data);
430 nomem:
431 error(SYSTEM, "out of memory in addmeshvert");
432 return(-1);
433 }
434
435
436 OBJECT
437 addmeshtri( /* add a new mesh triangle */
438 MESH *mp,
439 MESHVERT tv[3],
440 OBJECT mo
441 )
442 {
443 int32 vid[3], t;
444 int pn[3], i;
445 MESHPATCH *pp;
446
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 /* normalize material index */
456 if (mo != OVOID) {
457 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 }
462 /* assign triangle */
463 if ((pn[0] == pn[1]) & (pn[1] == pn[2])) { /* local case */
464 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 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 if (pp->ntris == 0)
476 pp->solemat = mo;
477 else if (pp->trimat == NULL && mo != pp->solemat) {
478 pp->trimat = (int16 *)malloc(
479 512*sizeof(int16));
480 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 return(pn[0] << 10 | pp->ntris++);
488 }
489 } else if (pn[0] == pn[1]) {
490 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 } else if (pn[0] == pn[2]) {
493 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 }
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 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 pp->j1tri[pp->nj1tris].mat = mo;
509 return(pn[1] << 10 | 0x200 | pp->nj1tris++);
510 }
511 }
512 /* double link */
513 pp = &mp->patch[pn[i=0]];
514 if (pp->nj2tris >= 256)
515 pp = &mp->patch[pn[i=1]];
516 if (pp->nj2tris >= 256)
517 pp = &mp->patch[pn[i=2]];
518 if (pp->nj2tris >= 256)
519 error(INTERNAL, "too many patch triangles in addmeshtri");
520 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 pp->j2tri[pp->nj2tris].mat = mo;
527 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 nomem:
545 error(SYSTEM, "out of memory in addmeshtri");
546 return(OVOID);
547 }
548
549
550 char *
551 checkmesh(MESH *mp) /* validate mesh data */
552 {
553 static char embuf[128];
554 int nouvbounds = 1;
555 int i;
556 /* 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 nouvbounds = (mp->uvlim[1][0] - mp->uvlim[0][0] <= FTINY ||
570 mp->uvlim[1][1] - mp->uvlim[0][1] <= FTINY);
571 }
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 MESHPATCH *pp = &mp->patch[i];
596 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 static void
617 tallyoctree( /* tally octree size */
618 OCTREE ot,
619 int *ecp,
620 int *lcp,
621 int *ocp
622 )
623 {
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 printmeshstats( /* print out mesh statistics */
644 MESH *ms,
645 FILE *fp
646 )
647 {
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 MESHPATCH *pp = &ms->patch[i];
657 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 fprintf(fp, "\t%ld materials\n", (long)ms->nmats);
676 fprintf(fp, "\t%d patches (%.2f MBytes)\n", ms->npatches,
677 (ms->npatches*sizeof(MESHPATCH) +
678 vcnt*3*sizeof(uint32) +
679 nscnt*sizeof(int32) +
680 uvscnt*2*sizeof(uint32) +
681 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 freemesh(MESH *ms) /* free mesh data */
699 {
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 lu_done(&ms->lut);
725 if (ms->npatches > 0) {
726 MESHPATCH *pp = ms->patch + ms->npatches;
727 while (pp-- > ms->patch) {
728 if (pp->j2tri != NULL)
729 free((void *)pp->j2tri);
730 if (pp->j1tri != NULL)
731 free((void *)pp->j1tri);
732 if (pp->tri != NULL)
733 free((void *)pp->tri);
734 if (pp->uv != NULL)
735 free((void *)pp->uv);
736 if (pp->norm != NULL)
737 free((void *)pp->norm);
738 if (pp->xyz != NULL)
739 free((void *)pp->xyz);
740 }
741 free((void *)ms->patch);
742 }
743 if (ms->pseudo != NULL)
744 free((void *)ms->pseudo);
745 free((void *)ms);
746 }
747
748
749 void
750 freemeshinst(OBJREC *o) /* free mesh instance */
751 {
752 if (o->os == NULL)
753 return;
754 freemesh((*(MESHINST *)o->os).msh);
755 free((void *)o->os);
756 o->os = NULL;
757 }