Back to index

radiance  4R0+20100331
mesh.c
Go to the documentation of this file.
00001 #ifndef lint
00002 static const char RCSid[] = "$Id: mesh.c,v 2.20 2004/05/25 22:04:13 greg Exp $";
00003 #endif
00004 /*
00005  * Mesh support routines
00006  */
00007 
00008 #include <string.h>
00009 
00010 #include "rtio.h"
00011 #include "rtmath.h"
00012 #include "rterror.h"
00013 #include "paths.h"
00014 #include "octree.h"
00015 #include "object.h"
00016 #include "otypes.h"
00017 #include "mesh.h"
00018 
00019 /* An encoded mesh vertex */
00020 typedef struct {
00021        int           fl;
00022        uint32        xyz[3];
00023        int32         norm;
00024        uint32        uv[2];
00025 } MCVERT;
00026 
00027 #define  MPATCHBLKSIZ       128           /* patch allocation block size */
00028 
00029 #define  IO_LEGAL    (IO_BOUNDS|IO_TREE|IO_SCENE)
00030 
00031 static MESH   *mlist = NULL;              /* list of loaded meshes */
00032 
00033 static lut_keycmpf_t cvcmp;
00034 static lut_hashf_t cvhash;
00035 
00036 
00037 static unsigned long
00038 cvhash(p)                          /* hash an encoded vertex */
00039 //MCVERT      *cvp;
00040 const void    *p;
00041 {
00042        const MCVERT  *cvp = (const MCVERT *)p;
00043        unsigned long hval;
00044        
00045        if (!(cvp->fl & MT_V))
00046               return(0);
00047        hval = cvp->xyz[0] ^ cvp->xyz[1] << 11 ^ cvp->xyz[2] << 22;
00048        if (cvp->fl & MT_N)
00049               hval ^= cvp->norm;
00050        if (cvp->fl & MT_UV)
00051               hval ^= cvp->uv[0] ^ cvp->uv[1] << 16;
00052        return(hval);
00053 }
00054 
00055 
00056 static int
00057 cvcmp(vv1, vv2)                           /* compare encoded vertices */
00058 //register MCVERT    *v1, *v2;
00059 const void    *vv1, *vv2;
00060 {
00061        const MCVERT  *v1 = vv1, *v2 = vv2;
00062        if (v1->fl != v2->fl)
00063               return(1);
00064        if (v1->xyz[0] != v2->xyz[0])
00065               return(1);
00066        if (v1->xyz[1] != v2->xyz[1])
00067               return(1);
00068        if (v1->xyz[2] != v2->xyz[2])
00069               return(1);
00070        if (v1->fl & MT_N && v1->norm != v2->norm)
00071               return(1);
00072        if (v1->fl & MT_UV) {
00073               if (v1->uv[0] != v2->uv[0])
00074                      return(1);
00075               if (v1->uv[1] != v2->uv[1])
00076                      return(1);
00077        }
00078        return(0);
00079 }
00080 
00081 
00082 MESH *
00083 getmesh(mname, flags)                     /* get new mesh data reference */
00084 char   *mname;
00085 int    flags;
00086 {
00087        char  *pathname;
00088        register MESH  *ms;
00089 
00090        flags &= IO_LEGAL;
00091        for (ms = mlist; ms != NULL; ms = ms->next)
00092               if (!strcmp(mname, ms->name)) {
00093                      ms->nref++;   /* increase reference count */
00094                      break;
00095               }
00096        if (ms == NULL) {           /* load first time */
00097               ms = (MESH *)calloc(1, sizeof(MESH));
00098               if (ms == NULL)
00099                      error(SYSTEM, "out of memory in getmesh");
00100               ms->name = savestr(mname);
00101               ms->nref = 1;
00102               ms->mcube.cutree = EMPTY;
00103               ms->next = mlist;
00104               mlist = ms;
00105        }
00106        if ((pathname = getpath(mname, getrlibpath(), R_OK)) == NULL) {
00107               sprintf(errmsg, "cannot find mesh file \"%s\"", mname);
00108               error(USER, errmsg);
00109        }
00110        flags &= ~ms->ldflags;
00111        if (flags)
00112               readmesh(ms, pathname, flags);
00113        return(ms);
00114 }
00115 
00116 
00117 MESHINST *
00118 getmeshinst(o, flags)                     /* create mesh instance */
00119 OBJREC *o;
00120 int    flags;
00121 {
00122        register MESHINST  *ins;
00123 
00124        flags &= IO_LEGAL;
00125        if ((ins = (MESHINST *)o->os) == NULL) {
00126               if ((ins = (MESHINST *)malloc(sizeof(MESHINST))) == NULL)
00127                      error(SYSTEM, "out of memory in getmeshinst");
00128               if (o->oargs.nsargs < 1)
00129                      objerror(o, USER, "bad # of arguments");
00130               if (fullxf(&ins->x, o->oargs.nsargs-1,
00131                             o->oargs.sarg+1) != o->oargs.nsargs-1)
00132                      objerror(o, USER, "bad transform");
00133               if (ins->x.f.sca < 0.0) {
00134                      ins->x.f.sca = -ins->x.f.sca;
00135                      ins->x.b.sca = -ins->x.b.sca;
00136               }
00137               ins->msh = NULL;
00138               o->os = (char *)ins;
00139        }
00140        if (ins->msh == NULL)
00141               ins->msh = getmesh(o->oargs.sarg[0], flags);
00142        else if ((flags &= ~ins->msh->ldflags))
00143               readmesh(ins->msh,
00144                      getpath(o->oargs.sarg[0], getrlibpath(), R_OK),
00145                             flags);
00146        return(ins);
00147 }
00148 
00149 
00150 int
00151 getmeshtrivid(tvid, mo, mp, ti)           /* get triangle vertex ID's */
00152 int32  tvid[3];
00153 OBJECT *mo;
00154 MESH   *mp;
00155 OBJECT ti;
00156 {
00157        int           pn = ti >> 10;
00158        MESHPATCH     *pp;
00159 
00160        if (pn >= mp->npatches)
00161               return(0);
00162        pp = &mp->patch[pn];
00163        ti &= 0x3ff;
00164        if (!(ti & 0x200)) {        /* local triangle */
00165               struct PTri   *tp;
00166               if (ti >= pp->ntris)
00167                      return(0);
00168               tp = &pp->tri[ti];
00169               tvid[0] = tvid[1] = tvid[2] = pn << 8;
00170               tvid[0] |= tp->v1;
00171               tvid[1] |= tp->v2;
00172               tvid[2] |= tp->v3;
00173               if (pp->trimat != NULL)
00174                      *mo = pp->trimat[ti];
00175               else
00176                      *mo = pp->solemat;
00177               if (*mo != OVOID)
00178                      *mo += mp->mat0;
00179               return(1);
00180        }
00181        ti &= ~0x200;
00182        if (!(ti & 0x100)) {        /* single link vertex */
00183               struct PJoin1 *tp1;
00184               if (ti >= pp->nj1tris)
00185                      return(0);
00186               tp1 = &pp->j1tri[ti];
00187               tvid[0] = tp1->v1j;
00188               tvid[1] = tvid[2] = pn << 8;
00189               tvid[1] |= tp1->v2;
00190               tvid[2] |= tp1->v3;
00191               if ((*mo = tp1->mat) != OVOID)
00192                      *mo += mp->mat0;
00193               return(1);
00194        }
00195        ti &= ~0x100;
00196        {                           /* double link vertex */
00197               struct PJoin2 *tp2;
00198               if (ti >= pp->nj2tris)
00199                      return(0);
00200               tp2 = &pp->j2tri[ti];
00201               tvid[0] = tp2->v1j;
00202               tvid[1] = tp2->v2j;
00203               tvid[2] = pn << 8 | tp2->v3;
00204               if ((*mo = tp2->mat) != OVOID)
00205                      *mo += mp->mat0;
00206        }
00207        return(1);
00208 }
00209 
00210 
00211 int
00212 getmeshvert(vp, mp, vid, what)     /* get triangle vertex from ID */
00213 MESHVERT      *vp;
00214 MESH          *mp;
00215 int32         vid;
00216 int           what;
00217 {
00218        int           pn = vid >> 8;
00219        MESHPATCH     *pp;
00220        double        vres;
00221        register int  i;
00222        
00223        vp->fl = 0;
00224        if (pn >= mp->npatches)
00225               return(0);
00226        pp = &mp->patch[pn];
00227        vid &= 0xff;
00228        if (vid >= pp->nverts)
00229               return(0);
00230                                    /* get location */
00231        if (what & MT_V) {
00232               vres = (1./4294967296.)*mp->mcube.cusize;
00233               for (i = 0; i < 3; i++)
00234                      vp->v[i] = mp->mcube.cuorg[i] +
00235                                    (pp->xyz[vid][i] + .5)*vres;
00236               vp->fl |= MT_V;
00237        }
00238                                    /* get normal */
00239        if (what & MT_N && pp->norm != NULL && pp->norm[vid]) {
00240               decodedir(vp->n, pp->norm[vid]);
00241               vp->fl |= MT_N;
00242        }
00243                                    /* get (u,v) */
00244        if (what & MT_UV && pp->uv != NULL && pp->uv[vid][0]) {
00245               for (i = 0; i < 2; i++)
00246                      vp->uv[i] = mp->uvlim[0][i] +
00247                             (mp->uvlim[1][i] - mp->uvlim[0][i])*
00248                             (pp->uv[vid][i] + .5)*(1./4294967296.);
00249               vp->fl |= MT_UV;
00250        }
00251        return(vp->fl);
00252 }
00253 
00254 
00255 OBJREC *
00256 getmeshpseudo(mp, mo)              /* get mesh pseudo object for material */
00257 MESH   *mp;
00258 OBJECT mo;
00259 {
00260        if (mo < mp->mat0 || mo >= mp->mat0 + mp->nmats)
00261               error(INTERNAL, "modifier out of range in getmeshpseudo");
00262        if (mp->pseudo == NULL) {
00263               register int  i;
00264               mp->pseudo = (OBJREC *)calloc(mp->nmats, sizeof(OBJREC));
00265               if (mp->pseudo == NULL)
00266                      error(SYSTEM, "out of memory in getmeshpseudo");
00267               for (i = mp->nmats; i--; ) {
00268                      mp->pseudo[i].omod = mp->mat0 + i;
00269                      mp->pseudo[i].otype = OBJ_FACE;
00270                      mp->pseudo[i].oname = "M-Tri";
00271               }
00272        }
00273        return(&mp->pseudo[mo - mp->mat0]);
00274 }
00275 
00276 
00277 int
00278 getmeshtri(tv, mo, mp, ti, wha)    /* get triangle vertices */
00279 MESHVERT      tv[3];
00280 OBJECT        *mo;
00281 MESH          *mp;
00282 OBJECT        ti;
00283 int           wha;
00284 {
00285        int32  tvid[3];
00286 
00287        if (!getmeshtrivid(tvid, mo, mp, ti))
00288               return(0);
00289 
00290        getmeshvert(&tv[0], mp, tvid[0], wha);
00291        getmeshvert(&tv[1], mp, tvid[1], wha);
00292        getmeshvert(&tv[2], mp, tvid[2], wha);
00293 
00294        return(tv[0].fl & tv[1].fl & tv[2].fl);
00295 }
00296 
00297 
00298 int32
00299 addmeshvert(mp, vp)         /* find/add a mesh vertex */
00300 register MESH *mp;
00301 MESHVERT      *vp;
00302 {
00303        LUENT         *lvp;
00304        MCVERT        cv;
00305        register int  i;
00306 
00307        if (!(vp->fl & MT_V))
00308               return(-1);
00309                                    /* encode vertex */
00310        for (i = 0; i < 3; i++) {
00311               if (vp->v[i] < mp->mcube.cuorg[i])
00312                      return(-1);
00313               if (vp->v[i] >= mp->mcube.cuorg[i] + mp->mcube.cusize)
00314                      return(-1);
00315               cv.xyz[i] = (uint32)(4294967296. *
00316                             (vp->v[i] - mp->mcube.cuorg[i]) /
00317                             mp->mcube.cusize);
00318        }
00319        if (vp->fl & MT_N)          /* assumes normalized! */
00320               cv.norm = encodedir(vp->n);
00321        if (vp->fl & MT_UV)
00322               for (i = 0; i < 2; i++) {
00323                      if (vp->uv[i] <= mp->uvlim[0][i])
00324                             return(-1);
00325                      if (vp->uv[i] >= mp->uvlim[1][i])
00326                             return(-1);
00327                      cv.uv[i] = (uint32)(4294967296. *
00328                                    (vp->uv[i] - mp->uvlim[0][i]) /
00329                                    (mp->uvlim[1][i] - mp->uvlim[0][i]));
00330               }
00331        cv.fl = vp->fl;
00332        if (mp->lut.tsiz == 0) {
00333               mp->lut.hashf = cvhash;
00334               mp->lut.keycmp = cvcmp;
00335               mp->lut.freek = free;
00336               if (!lu_init(&mp->lut, 50000))
00337                      goto nomem;
00338        }
00339                                    /* find entry */
00340        lvp = lu_find(&mp->lut, (char *)&cv);
00341        if (lvp == NULL)
00342               goto nomem;
00343        if (lvp->key == NULL) {
00344               lvp->key = (char *)malloc(sizeof(MCVERT)+sizeof(int32));
00345               memcpy((void *)lvp->key, (void *)&cv, sizeof(MCVERT));
00346        }
00347        if (lvp->data == NULL) {    /* new vertex */
00348               register MESHPATCH   *pp;
00349               if (mp->npatches <= 0) {
00350                      mp->patch = (MESHPATCH *)calloc(MPATCHBLKSIZ,
00351                                    sizeof(MESHPATCH));
00352                      if (mp->patch == NULL)
00353                             goto nomem;
00354                      mp->npatches = 1;
00355               } else if (mp->patch[mp->npatches-1].nverts >= 256) {
00356                      if (mp->npatches % MPATCHBLKSIZ == 0) {
00357                             mp->patch = (MESHPATCH *)realloc(
00358                                           (void *)mp->patch,
00359                                    (mp->npatches + MPATCHBLKSIZ)*
00360                                           sizeof(MESHPATCH));
00361                             memset((void *)(mp->patch + mp->npatches), '\0',
00362                                    MPATCHBLKSIZ*sizeof(MESHPATCH));
00363                      }
00364                      if (mp->npatches++ >= 1L<<22)
00365                             error(INTERNAL, "too many mesh patches");
00366               }
00367               pp = &mp->patch[mp->npatches-1];
00368               if (pp->xyz == NULL) {
00369                      pp->xyz = (uint32 (*)[3])calloc(256, 3*sizeof(int32));
00370                      if (pp->xyz == NULL)
00371                             goto nomem;
00372               }
00373               for (i = 0; i < 3; i++)
00374                      pp->xyz[pp->nverts][i] = cv.xyz[i];
00375               if (cv.fl & MT_N) {
00376                      if (pp->norm == NULL) {
00377                             pp->norm = (int32 *)calloc(256, sizeof(int32));
00378                             if (pp->norm == NULL)
00379                                    goto nomem;
00380                      }
00381                      pp->norm[pp->nverts] = cv.norm;
00382               }
00383               if (cv.fl & MT_UV) {
00384                      if (pp->uv == NULL) {
00385                             pp->uv = (uint32 (*)[2])calloc(256,
00386                                           2*sizeof(uint32));
00387                             if (pp->uv == NULL)
00388                                    goto nomem;
00389                      }
00390                      for (i = 0; i < 2; i++)
00391                             pp->uv[pp->nverts][i] = cv.uv[i];
00392               }
00393               pp->nverts++;
00394               lvp->data = lvp->key + sizeof(MCVERT);
00395               *(int32 *)lvp->data = (mp->npatches-1) << 8 | (pp->nverts-1);
00396        }
00397        return(*(int32 *)lvp->data);
00398 nomem:
00399        error(SYSTEM, "out of memory in addmeshvert");
00400        return(-1);
00401 }
00402 
00403 
00404 OBJECT
00405 addmeshtri(mp, tv, mo)             /* add a new mesh triangle */
00406 MESH          *mp;
00407 MESHVERT      tv[3];
00408 OBJECT        mo;
00409 {
00410        int32                vid[3], t;
00411        int                  pn[3], i;
00412        register MESHPATCH   *pp;
00413 
00414        if (!(tv[0].fl & tv[1].fl & tv[2].fl & MT_V))
00415               return(OVOID);
00416                             /* find/allocate patch vertices */
00417        for (i = 0; i < 3; i++) {
00418               if ((vid[i] = addmeshvert(mp, &tv[i])) < 0)
00419                      return(OVOID);
00420               pn[i] = vid[i] >> 8;
00421        }
00422                             /* normalize material index */
00423        if (mo != OVOID) {
00424               if ((mo -= mp->mat0) >= mp->nmats)
00425                      mp->nmats = mo+1;
00426               else if (mo < 0)
00427                      error(INTERNAL, "modifier range error in addmeshtri");
00428        }
00429                             /* assign triangle */
00430        if (pn[0] == pn[1] && pn[1] == pn[2]) {   /* local case */
00431               pp = &mp->patch[pn[0]];
00432               if (pp->tri == NULL) {
00433                      pp->tri = (struct PTri *)malloc(
00434                                    512*sizeof(struct PTri));
00435                      if (pp->tri == NULL)
00436                             goto nomem;
00437               }
00438               if (pp->ntris < 512) {
00439                      pp->tri[pp->ntris].v1 = vid[0] & 0xff;
00440                      pp->tri[pp->ntris].v2 = vid[1] & 0xff;
00441                      pp->tri[pp->ntris].v3 = vid[2] & 0xff;
00442                      if (pp->ntris == 0)
00443                             pp->solemat = mo;
00444                      else if (pp->trimat == NULL && mo != pp->solemat) {
00445                             pp->trimat = (int16 *)malloc(
00446                                           512*sizeof(int16));
00447                             if (pp->trimat == NULL)
00448                                    goto nomem;
00449                             for (i = pp->ntris; i--; )
00450                                    pp->trimat[i] = pp->solemat;
00451                      }
00452                      if (pp->trimat != NULL)
00453                             pp->trimat[pp->ntris] = mo;
00454                      return(pn[0] << 10 | pp->ntris++);
00455               }
00456        }
00457        if (pn[0] == pn[1]) {
00458               t = vid[2]; vid[2] = vid[1]; vid[1] = vid[0]; vid[0] = t;
00459               i = pn[2]; pn[2] = pn[1]; pn[1] = pn[0]; pn[0] = i;
00460        } else if (pn[0] == pn[2]) {
00461               t = vid[0]; vid[0] = vid[1]; vid[1] = vid[2]; vid[2] = t;
00462               i = pn[0]; pn[0] = pn[1]; pn[1] = pn[2]; pn[2] = i;
00463        }
00464        if (pn[1] == pn[2]) {                     /* single link */
00465               pp = &mp->patch[pn[1]];
00466               if (pp->j1tri == NULL) {
00467                      pp->j1tri = (struct PJoin1 *)malloc(
00468                                    256*sizeof(struct PJoin1));
00469                      if (pp->j1tri == NULL)
00470                             goto nomem;
00471               }
00472               if (pp->nj1tris < 256) {
00473                      pp->j1tri[pp->nj1tris].v1j = vid[0];
00474                      pp->j1tri[pp->nj1tris].v2 = vid[1] & 0xff;
00475                      pp->j1tri[pp->nj1tris].v3 = vid[2] & 0xff;
00476                      pp->j1tri[pp->nj1tris].mat = mo;
00477                      return(pn[1] << 10 | 0x200 | pp->nj1tris++);
00478               }
00479        }
00480                                           /* double link */
00481        pp = &mp->patch[pn[2]];
00482        if (pp->j2tri == NULL) {
00483               pp->j2tri = (struct PJoin2 *)malloc(
00484                                    256*sizeof(struct PJoin2));
00485               if (pp->j2tri == NULL)
00486                      goto nomem;
00487        }
00488        if (pp->nj2tris >= 256)
00489               error(INTERNAL, "too many patch triangles in addmeshtri");
00490        pp->j2tri[pp->nj2tris].v1j = vid[0];
00491        pp->j2tri[pp->nj2tris].v2j = vid[1];
00492        pp->j2tri[pp->nj2tris].v3 = vid[2] & 0xff;
00493        pp->j2tri[pp->nj2tris].mat = mo;
00494        return(pn[2] << 10 | 0x300 | pp->nj2tris++);
00495 nomem:
00496        error(SYSTEM, "out of memory in addmeshtri");
00497        return(OVOID);
00498 }
00499 
00500 
00501 char *
00502 checkmesh(mp)                      /* validate mesh data */
00503 register MESH *mp;
00504 {
00505        static char   embuf[128];
00506        int           nouvbounds = 1;
00507        register int  i;
00508                                    /* basic checks */
00509        if (mp == NULL)
00510               return("NULL mesh pointer");
00511        if (!mp->ldflags)
00512               return("unassigned mesh");
00513        if (mp->name == NULL)
00514               return("missing mesh name");
00515        if (mp->nref <= 0)
00516               return("unreferenced mesh");
00517                                    /* check boundaries */
00518        if (mp->ldflags & IO_BOUNDS) {
00519               if (mp->mcube.cusize <= FTINY)
00520                      return("illegal octree bounds in mesh");
00521               nouvbounds = (mp->uvlim[1][0] - mp->uvlim[0][0] <= FTINY ||
00522                             mp->uvlim[1][1] - mp->uvlim[0][1] <= FTINY);
00523        }
00524                                    /* check octree */
00525        if (mp->ldflags & IO_TREE) {
00526               if (isempty(mp->mcube.cutree))
00527                      error(WARNING, "empty mesh octree");
00528        }
00529                                    /* check scene data */
00530        if (mp->ldflags & IO_SCENE) {
00531               if (!(mp->ldflags & IO_BOUNDS))
00532                      return("unbounded scene in mesh");
00533               if (mp->mat0 < 0 || mp->mat0+mp->nmats > nobjects)
00534                      return("bad mesh modifier range");
00535               for (i = mp->mat0+mp->nmats; i-- > mp->mat0; ) {
00536                      int    otyp = objptr(i)->otype;
00537                      if (!ismodifier(otyp)) {
00538                             sprintf(embuf,
00539                                    "non-modifier in mesh (%s \"%s\")",
00540                                    ofun[otyp].funame, objptr(i)->oname);
00541                             return(embuf);
00542                      }
00543               }
00544               if (mp->npatches <= 0)
00545                      error(WARNING, "no patches in mesh");
00546               for (i = 0; i < mp->npatches; i++) {
00547                      register MESHPATCH   *pp = &mp->patch[i];
00548                      if (pp->nverts <= 0)
00549                             error(WARNING, "no vertices in patch");
00550                      else {
00551                             if (pp->xyz == NULL)
00552                                    return("missing patch vertex list");
00553                             if (nouvbounds && pp->uv != NULL)
00554                                    return("unreferenced uv coordinates");
00555                      }
00556                      if (pp->ntris > 0 && pp->tri == NULL)
00557                             return("missing patch triangle list");
00558                      if (pp->nj1tris > 0 && pp->j1tri == NULL)
00559                             return("missing patch joiner triangle list");
00560                      if (pp->nj2tris > 0 && pp->j2tri == NULL)
00561                             return("missing patch double-joiner list");
00562               }
00563        }
00564        return(NULL);               /* seems OK */
00565 }
00566 
00567 
00568 static void
00569 tallyoctree(ot, ecp, lcp, ocp)     /* tally octree size */
00570 OCTREE ot;
00571 int    *ecp, *lcp, *ocp;
00572 {
00573        int    i;
00574 
00575        if (isempty(ot)) {
00576               (*ecp)++;
00577               return;
00578        }
00579        if (isfull(ot)) {
00580               OBJECT oset[MAXSET+1];
00581               (*lcp)++;
00582               objset(oset, ot);
00583               *ocp += oset[0];
00584               return;
00585        }
00586        for (i = 0; i < 8; i++)
00587               tallyoctree(octkid(ot, i), ecp, lcp, ocp);
00588 }
00589 
00590 
00591 void
00592 printmeshstats(ms, fp)             /* print out mesh statistics */
00593 MESH   *ms;
00594 FILE   *fp;
00595 {
00596        int    lfcnt=0, lecnt=0, locnt=0;
00597        int    vcnt=0, ncnt=0, uvcnt=0;
00598        int    nscnt=0, uvscnt=0;
00599        int    tcnt=0, t1cnt=0, t2cnt=0;
00600        int    i, j;
00601        
00602        tallyoctree(ms->mcube.cutree, &lecnt, &lfcnt, &locnt);
00603        for (i = 0; i < ms->npatches; i++) {
00604               register MESHPATCH   *pp = &ms->patch[i];
00605               vcnt += pp->nverts;
00606               if (pp->norm != NULL) {
00607                      for (j = pp->nverts; j--; )
00608                             if (pp->norm[j])
00609                                    ncnt++;
00610                      nscnt += pp->nverts;
00611               }
00612               if (pp->uv != NULL) {
00613                      for (j = pp->nverts; j--; )
00614                             if (pp->uv[j][0])
00615                                    uvcnt++;
00616                      uvscnt += pp->nverts;
00617               }
00618               tcnt += pp->ntris;
00619               t1cnt += pp->nj1tris;
00620               t2cnt += pp->nj2tris;
00621        }
00622        fprintf(fp, "Mesh statistics:\n");
00623        fprintf(fp, "\t%ld materials\n", ms->nmats);
00624        fprintf(fp, "\t%d patches (%.2f MBytes)\n", ms->npatches,
00625                      (ms->npatches*sizeof(MESHPATCH) +
00626                      vcnt*3*sizeof(uint32) +
00627                      nscnt*sizeof(int32) +
00628                      uvscnt*2*sizeof(uint32) +
00629                      tcnt*sizeof(struct PTri) +
00630                      t1cnt*sizeof(struct PJoin1) +
00631                      t2cnt*sizeof(struct PJoin2))/(1024.*1024.));
00632        fprintf(fp, "\t%d vertices (%.1f%% w/ normals, %.1f%% w/ uv)\n",
00633                      vcnt, 100.*ncnt/vcnt, 100.*uvcnt/vcnt);
00634        fprintf(fp, "\t%d triangles (%.1f%% local, %.1f%% joiner)\n",
00635                      tcnt+t1cnt+t2cnt,
00636                      100.*tcnt/(tcnt+t1cnt+t2cnt),
00637                      100.*t1cnt/(tcnt+t1cnt+t2cnt));
00638        fprintf(fp,
00639        "\t%d leaves in octree (%.1f%% empty, %.2f avg. set size)\n",
00640                      lfcnt+lecnt, 100.*lecnt/(lfcnt+lecnt),
00641                      (double)locnt/lfcnt);
00642 }
00643 
00644 
00645 void
00646 freemesh(ms)                /* free mesh data */
00647 register MESH *ms;
00648 {
00649        MESH   mhead;
00650        MESH   *msp;
00651        
00652        if (ms == NULL)
00653               return;
00654        if (ms->nref <= 0)
00655               error(CONSISTENCY, "unreferenced mesh in freemesh");
00656        ms->nref--;
00657        if (ms->nref)        /* still in use */
00658               return;
00659                             /* else remove from list */
00660        mhead.next = mlist;
00661        for (msp = &mhead; msp->next != NULL; msp = msp->next)
00662               if (msp->next == ms) {
00663                      msp->next = ms->next;
00664                      ms->next = NULL;
00665                      break;
00666               }
00667        if (ms->next != NULL)       /* can't be in list anymore */
00668               error(CONSISTENCY, "unlisted mesh in freemesh");
00669        mlist = mhead.next;
00670                             /* free mesh data */
00671        freestr(ms->name);
00672        octfree(ms->mcube.cutree);
00673        lu_done(&ms->lut);
00674        if (ms->npatches > 0) {
00675               register MESHPATCH   *pp = ms->patch + ms->npatches;
00676               while (pp-- > ms->patch) {
00677                      if (pp->j2tri != NULL)
00678                             free((void *)pp->j2tri);
00679                      if (pp->j1tri != NULL)
00680                             free((void *)pp->j1tri);
00681                      if (pp->tri != NULL)
00682                             free((void *)pp->tri);
00683                      if (pp->uv != NULL)
00684                             free((void *)pp->uv);
00685                      if (pp->norm != NULL)
00686                             free((void *)pp->norm);
00687                      if (pp->xyz != NULL)
00688                             free((void *)pp->xyz);
00689               }
00690               free((void *)ms->patch);
00691        }
00692        if (ms->pseudo != NULL)
00693               free((void *)ms->pseudo);
00694        free((void *)ms);
00695 }
00696 
00697 
00698 void
00699 freemeshinst(o)                    /* free mesh instance */
00700 OBJREC *o;
00701 {
00702        if (o->os == NULL)
00703               return;
00704        freemesh((*(MESHINST *)o->os).msh);
00705        free((void *)o->os);
00706        o->os = NULL;
00707 }