Back to index

radiance  4R0+20100331
cvmesh.c
Go to the documentation of this file.
00001 #ifndef lint
00002 static const char RCSid[] = "$Id: cvmesh.c,v 2.10 2004/11/25 14:45:38 greg Exp $";
00003 #endif
00004 /*
00005  *  Radiance triangle mesh conversion routines
00006  */
00007 
00008 #include "copyright.h"
00009 #include "standard.h"
00010 #include "cvmesh.h"
00011 #include "otypes.h"
00012 #include "face.h"
00013 #include "tmesh.h"
00014 
00015 /*
00016  * We need to divide faces into triangles and record auxiliary information
00017  * if given (surface normal and uv coordinates).  We do this by extending
00018  * the face structure linked to the OBJREC os member and putting our
00019  * auxiliary after it -- a bit sly, but it works.
00020  */
00021 
00022 /* Auxiliary data for triangle */
00023 typedef struct {
00024        int           fl;           /* flags of what we're storing */
00025        OBJECT        obj;          /* mesh triangle ID */
00026        FVECT         vn[3];        /* normals */
00027        RREAL         vc[3][2];     /* uv coords. */
00028 } TRIDATA;
00029 
00030 #define tdsize(fl)   ((fl)&MT_UV ? sizeof(TRIDATA) : \
00031                             (fl)&MT_N ? sizeof(TRIDATA)-6*sizeof(RREAL) : \
00032                             sizeof(int)+sizeof(OBJECT))
00033 
00034 #define        OMARGIN      (10*FTINY)    /* margin around global cube */
00035 
00036 MESH   *ourmesh = NULL;            /* our global mesh data structure */
00037 
00038 FVECT  meshbounds[2];                     /* mesh bounding box */
00039 
00040 static void add2bounds(FVECT vp, RREAL vc[2]);
00041 static OBJECT cvmeshtri(OBJECT obj);
00042 static OCTREE cvmeshoct(OCTREE ot);
00043 
00044 
00045 
00046 MESH *
00047 cvinit(                     /* initialize empty mesh */
00048        char   *nm
00049 )
00050 {
00051                             /* free old mesh, first */
00052        if (ourmesh != NULL) {
00053               freemesh(ourmesh);
00054               ourmesh = NULL;
00055               freeobjects(0, nobjects);
00056               donesets();
00057        }
00058        if (nm == NULL)
00059               return(NULL);
00060        ourmesh = (MESH *)calloc(1, sizeof(MESH));
00061        if (ourmesh == NULL)
00062               goto nomem;
00063        ourmesh->name = savestr(nm);
00064        ourmesh->nref = 1;
00065        ourmesh->ldflags = 0;
00066        ourmesh->mcube.cutree = EMPTY;
00067        ourmesh->uvlim[0][0] = ourmesh->uvlim[0][1] = FHUGE;
00068        ourmesh->uvlim[1][0] = ourmesh->uvlim[1][1] = -FHUGE;
00069        meshbounds[0][0] = meshbounds[0][1] = meshbounds[0][2] = FHUGE;
00070        meshbounds[1][0] = meshbounds[1][1] = meshbounds[1][2] = -FHUGE;
00071        return(ourmesh);
00072 nomem:
00073        error(SYSTEM, "out of memory in cvinit");
00074        return(NULL);
00075 }
00076 
00077 
00078 int
00079 cvpoly(       /* convert a polygon to extended triangles */
00080        OBJECT mo,
00081        int    n,
00082        FVECT  *vp,
00083        FVECT  *vn,
00084        RREAL  (*vc)[2]
00085 )
00086 {
00087        int    tcnt = 0;
00088        int    flags;
00089        RREAL  *tn[3], *tc[3];
00090        int    *ord;
00091        int    i, j;
00092 
00093        if (n < 3)           /* degenerate face */
00094               return(0);
00095        flags = MT_V;
00096        if (vn != NULL) {
00097               tn[0] = vn[0]; tn[1] = vn[1]; tn[2] = vn[2];
00098               flags |= MT_N;
00099        } else {
00100               tn[0] = tn[1] = tn[2] = NULL;
00101        }
00102        if (vc != NULL) {
00103               tc[0] = vc[0]; tc[1] = vc[1]; tc[2] = vc[2];
00104               flags |= MT_UV;
00105        } else {
00106               tc[0] = tc[1] = tc[2] = NULL;
00107        }
00108        if (n == 3)          /* output single triangle */
00109               return(cvtri(mo, vp[0], vp[1], vp[2],
00110                             tn[0], tn[1], tn[2],
00111                             tc[0], tc[1], tc[2]));
00112 
00113                             /* decimate polygon (assumes convex) */
00114        ord = (int *)malloc(n*sizeof(int));
00115        if (ord == NULL)
00116               error(SYSTEM, "out of memory in cvpoly");
00117        for (i = n; i--; )
00118               ord[i] = i;
00119        while (n >= 3) {
00120               if (flags & MT_N)
00121                      for (i = 3; i--; )
00122                             tn[i] = vn[ord[i]];
00123               if (flags & MT_UV)
00124                      for (i = 3; i--; )
00125                             tc[i] = vc[ord[i]];
00126               tcnt += cvtri(mo, vp[ord[0]], vp[ord[1]], vp[ord[2]],
00127                             tn[0], tn[1], tn[2],
00128                             tc[0], tc[1], tc[2]);
00129                      /* remove vertex and rotate */
00130               n--;
00131               j = ord[0];
00132               for (i = 0; i < n-1; i++)
00133                      ord[i] = ord[i+2];
00134               ord[i] = j;
00135        }
00136        free((void *)ord);
00137        return(tcnt);
00138 }
00139 
00140 
00141 static void
00142 add2bounds(          /* add point and uv coordinate to bounds */
00143        FVECT  vp,
00144        RREAL  vc[2]
00145 )
00146 {
00147        register int  j;
00148 
00149        for (j = 3; j--; ) {
00150               if (vp[j] < meshbounds[0][j])
00151                      meshbounds[0][j] = vp[j];
00152               if (vp[j] > meshbounds[1][j])
00153                      meshbounds[1][j] = vp[j];
00154        }
00155        if (vc == NULL)
00156               return;
00157        for (j = 2; j--; ) {
00158               if (vc[j] < ourmesh->uvlim[0][j])
00159                      ourmesh->uvlim[0][j] = vc[j];
00160               if (vc[j] > ourmesh->uvlim[1][j])
00161                      ourmesh->uvlim[1][j] = vc[j];
00162        }
00163 }
00164 
00165 
00166 int                         /* create an extended triangle */
00167 cvtri(
00168        OBJECT mo,
00169        FVECT  vp1,
00170        FVECT  vp2,
00171        FVECT  vp3,
00172        FVECT  vn1,
00173        FVECT  vn2,
00174        FVECT  vn3,
00175        RREAL  vc1[2],
00176        RREAL  vc2[2],
00177        RREAL  vc3[2]
00178 )
00179 {
00180        static OBJECT fobj = OVOID;
00181        char          buf[32];
00182        int           flags;
00183        TRIDATA              *ts;
00184        FACE          *f;
00185        OBJREC        *fop;
00186        int           j;
00187        
00188        flags = MT_V;        /* check what we have */
00189        if (vn1 != NULL && vn2 != NULL && vn3 != NULL) {
00190               RREAL  *rp;
00191               switch (flat_tri(vp1, vp2, vp3, vn1, vn2, vn3)) {
00192               case ISBENT:
00193                      flags |= MT_N;
00194                      /* fall through */
00195               case ISFLAT:
00196                      break;
00197               case RVBENT:
00198                      flags |= MT_N;
00199                      rp = vn1; vn1 = vn3; vn3 = rp;
00200                      /* fall through */
00201               case RVFLAT:
00202                      rp = vp1; vp1 = vp3; vp3 = rp;
00203                      rp = vc1; vc1 = vc3; vc3 = rp;
00204                      break;
00205               case DEGEN:
00206                      error(WARNING, "degenerate triangle");
00207                      return(0);
00208               default:
00209                      error(INTERNAL, "bad return from flat_tri()");
00210               }
00211        }
00212        if (vc1 != NULL && vc2 != NULL && vc3 != NULL)
00213               flags |= MT_UV;
00214        if (fobj == OVOID) { /* create new triangle object */
00215               fobj = newobject();
00216               if (fobj == OVOID)
00217                      goto nomem;
00218               fop = objptr(fobj);
00219               fop->omod = mo;
00220               fop->otype = OBJ_FACE;
00221               sprintf(buf, "t%ld", fobj);
00222               fop->oname = savqstr(buf);
00223               fop->oargs.nfargs = 9;
00224               fop->oargs.farg = (RREAL *)malloc(9*sizeof(RREAL));
00225               if (fop->oargs.farg == NULL)
00226                      goto nomem;
00227        } else {             /* else reuse failed one */
00228               fop = objptr(fobj);
00229               if (fop->otype != OBJ_FACE || fop->oargs.nfargs != 9)
00230                      error(CONSISTENCY, "code error 1 in cvtri");
00231        }
00232        for (j = 3; j--; ) {
00233               fop->oargs.farg[j] = vp1[j];
00234               fop->oargs.farg[3+j] = vp2[j];
00235               fop->oargs.farg[6+j] = vp3[j];
00236        }
00237                             /* create face record */
00238        f = getface(fop);
00239        if (f->area == 0.) {
00240               free_os(fop);
00241               return(0);
00242        }
00243        if (fop->os != (char *)f)
00244               error(CONSISTENCY, "code error 2 in cvtri");
00245                             /* follow with auxliary data */
00246        f = (FACE *)realloc((void *)f, sizeof(FACE)+tdsize(flags));
00247        if (f == NULL)
00248               goto nomem;
00249        fop->os = (char *)f;
00250        ts = (TRIDATA *)(f+1);
00251        ts->fl = flags;
00252        ts->obj = OVOID;
00253        if (flags & MT_N)
00254               for (j = 3; j--; ) {
00255                      ts->vn[0][j] = vn1[j];
00256                      ts->vn[1][j] = vn2[j];
00257                      ts->vn[2][j] = vn3[j];
00258               }
00259        if (flags & MT_UV)
00260               for (j = 2; j--; ) {
00261                      ts->vc[0][j] = vc1[j];
00262                      ts->vc[1][j] = vc2[j];
00263                      ts->vc[2][j] = vc3[j];
00264               }
00265        else
00266               vc1 = vc2 = vc3 = NULL;
00267                             /* update bounds */
00268        add2bounds(vp1, vc1);
00269        add2bounds(vp2, vc2);
00270        add2bounds(vp3, vc3);
00271        fobj = OVOID;        /* we used this one */
00272        return(1);
00273 nomem:
00274        error(SYSTEM, "out of memory in cvtri");
00275        return(0);
00276 }
00277 
00278 
00279 static OBJECT
00280 cvmeshtri(                  /* add an extended triangle to our mesh */
00281        OBJECT obj
00282 )
00283 {
00284        OBJREC        *o = objptr(obj);
00285        TRIDATA              *ts;
00286        MESHVERT      vert[3];
00287        int           i, j;
00288        
00289        if (o->otype != OBJ_FACE)
00290               error(CONSISTENCY, "non-face in mesh");
00291        if (o->oargs.nfargs != 9)
00292               error(CONSISTENCY, "non-triangle in mesh");
00293        if (o->os == NULL)
00294               error(CONSISTENCY, "missing face record in cvmeshtri");
00295        ts = (TRIDATA *)((FACE *)o->os + 1);
00296        if (ts->obj != OVOID)       /* already added? */
00297               return(ts->obj);
00298        vert[0].fl = vert[1].fl = vert[2].fl = ts->fl;
00299        for (i = 3; i--; )
00300               for (j = 3; j--; )
00301                      vert[i].v[j] = o->oargs.farg[3*i+j];
00302        if (ts->fl & MT_N)
00303               for (i = 3; i--; )
00304                      for (j = 3; j--; )
00305                             vert[i].n[j] = ts->vn[i][j];
00306        if (ts->fl & MT_UV)
00307               for (i = 3; i--; )
00308                      for (j = 2; j--; )
00309                             vert[i].uv[j] = ts->vc[i][j];
00310        ts->obj = addmeshtri(ourmesh, vert, o->omod);
00311        if (ts->obj == OVOID)
00312               error(INTERNAL, "addmeshtri failed");
00313        return(ts->obj);
00314 }
00315 
00316 
00317 void
00318 cvmeshbounds(void)                 /* set mesh boundaries */
00319 {
00320        int    i;
00321 
00322        if (ourmesh == NULL)
00323               return;
00324                             /* fix coordinate bounds */
00325        for (i = 0; i < 3; i++) {
00326               if (meshbounds[0][i] > meshbounds[1][i])
00327                      error(USER, "no polygons in mesh");
00328               meshbounds[0][i] -= OMARGIN;
00329               meshbounds[1][i] += OMARGIN;
00330               if (meshbounds[1][i]-meshbounds[0][i] > ourmesh->mcube.cusize)
00331                      ourmesh->mcube.cusize = meshbounds[1][i] -
00332                                           meshbounds[0][i];
00333        }
00334        for (i = 0; i < 3; i++)
00335               ourmesh->mcube.cuorg[i] = (meshbounds[1][i]+meshbounds[0][i] -
00336                                           ourmesh->mcube.cusize)*.5;
00337        if (ourmesh->uvlim[0][0] > ourmesh->uvlim[1][0]) {
00338               ourmesh->uvlim[0][0] = ourmesh->uvlim[0][1] = 0.;
00339               ourmesh->uvlim[1][0] = ourmesh->uvlim[1][1] = 0.;
00340        } else {
00341               for (i = 0; i < 2; i++) {
00342                      double marg;         /* expand past endpoints */
00343                      marg = (2./(1L<<(8*sizeof(uint16)))) *
00344                                    (ourmesh->uvlim[1][i] -
00345                                     ourmesh->uvlim[0][i]) + FTINY;
00346                      ourmesh->uvlim[0][i] -= marg;
00347                      ourmesh->uvlim[1][i] += marg;
00348               }
00349        }
00350        ourmesh->ldflags |= IO_BOUNDS;
00351 }
00352 
00353 
00354 static OCTREE
00355 cvmeshoct(                  /* convert triangles in subtree */
00356        OCTREE ot
00357 )
00358 {
00359        int    i;
00360 
00361        if (isempty(ot))
00362               return(EMPTY);
00363 
00364        if (isfull(ot)) {
00365               OBJECT oset1[MAXSET+1];
00366               OBJECT oset2[MAXSET+1];
00367               objset(oset1, ot);
00368               oset2[0] = 0;
00369               for (i = oset1[0]; i > 0; i--)
00370                      insertelem(oset2, cvmeshtri(oset1[i]));
00371               return(fullnode(oset2));
00372        }
00373 
00374        for (i = 8; i--; )
00375               octkid(ot, i) = cvmeshoct(octkid(ot, i));
00376        return(ot);
00377 }
00378 
00379 
00380 MESH *
00381 cvmesh(void)                /* convert mesh and octree leaf nodes */
00382 {
00383        if (ourmesh == NULL)
00384               return(NULL);
00385                             /* convert triangles in octree nodes */
00386        ourmesh->mcube.cutree = cvmeshoct(ourmesh->mcube.cutree);
00387        ourmesh->ldflags |= IO_SCENE|IO_TREE;
00388 
00389        return(ourmesh);
00390 }