| 10 |  | */ | 
| 11 |  |  | 
| 12 |  | #include "paths.h" | 
| 13 | + | #include "fvect.h" | 
| 14 | + | #include "tmesh.h" | 
| 15 |  | #include "rterror.h" | 
| 16 |  | #include "objutil.h" | 
| 17 |  |  | 
| 18 | + | #define TEXNAME         "T-nor" | 
| 19 | + |  | 
| 20 | + | static int      fcnt = 0;                       /* face output counter */ | 
| 21 | + |  | 
| 22 | + | /* Callback for face smoothing detection */ | 
| 23 | + | static int | 
| 24 | + | checksmooth(Scene *sc, Face *f, void *ptr) | 
| 25 | + | { | 
| 26 | + | int     nrev = 0; | 
| 27 | + | Normal  fnrm; | 
| 28 | + | int     i; | 
| 29 | + |  | 
| 30 | + | f->flags &= ~FACE_RESERVED;             /* using reserved flag */ | 
| 31 | + |  | 
| 32 | + | for (i = f->nv; i--; ) | 
| 33 | + | if (f->v[i].nid < 0) | 
| 34 | + | return(0);              /* missing normal */ | 
| 35 | + |  | 
| 36 | + | if (faceArea(sc, f, fnrm) == 0)         /* degenerate?? */ | 
| 37 | + | return(0); | 
| 38 | + | /* check each normal */ | 
| 39 | + | for (i = f->nv; i--; ) { | 
| 40 | + | float   *tnrm = sc->norm[f->v[i].nid]; | 
| 41 | + | double  dprod = DOT(tnrm, fnrm); | 
| 42 | + | if (dprod >= COSTOL)            /* this one agrees? */ | 
| 43 | + | continue; | 
| 44 | + | if (dprod > -COSTOL)            /* active smoothing? */ | 
| 45 | + | break; | 
| 46 | + | ++nrev;                         /* count opposite face normal */ | 
| 47 | + | } | 
| 48 | + | if ((i < 0) & !nrev)                    /* all normals agree w/ face? */ | 
| 49 | + | return(0); | 
| 50 | + | if (nrev == f->nv) {                    /* all reversed? */ | 
| 51 | + | for (i = f->nv; i--; )          /* remove normal indices */ | 
| 52 | + | f->v[i].nid = -1; | 
| 53 | + | for (i = f->nv/2; i--; ) {      /* and swap others around */ | 
| 54 | + | int     j = f->nv-1 - i; | 
| 55 | + | int     vi = f->v[i].vid; | 
| 56 | + | int     ti = f->v[i].tid; | 
| 57 | + | f->v[i].vid = f->v[j].vid; | 
| 58 | + | f->v[i].tid = f->v[j].tid; | 
| 59 | + | f->v[j].vid = vi; | 
| 60 | + | f->v[j].tid = ti; | 
| 61 | + | } | 
| 62 | + | return(0); | 
| 63 | + | } | 
| 64 | + | f->flags |= FACE_RESERVED;              /* else we got one to smooth */ | 
| 65 | + | return(1); | 
| 66 | + | } | 
| 67 | + |  | 
| 68 | + | /* Callback to write out smoothed Radiance triangle */ | 
| 69 | + | static int | 
| 70 | + | trismooth(Scene *sc, Face *f, void *ptr) | 
| 71 | + | { | 
| 72 | + | FILE            *fp = (FILE *)ptr; | 
| 73 | + | BARYCCM         bcm; | 
| 74 | + | RREAL           ncoor[3][3]; | 
| 75 | + | int             i; | 
| 76 | + |  | 
| 77 | + | if (f->nv != 3) | 
| 78 | + | return(0);                      /* should never happen */ | 
| 79 | + | if (sizeof(sc->vert[0].p) != sizeof(FVECT)) | 
| 80 | + | error(INTERNAL, "Code error in trismooth()"); | 
| 81 | + | if (comp_baryc(&bcm, sc->vert[f->v[0].vid].p, sc->vert[f->v[1].vid].p, | 
| 82 | + | sc->vert[f->v[2].vid].p) < 0) | 
| 83 | + | return(0);                      /* degenerate?? */ | 
| 84 | + |  | 
| 85 | + | for (i = 3; i--; ) {                    /* assign BC normals */ | 
| 86 | + | float   *tnrm = sc->norm[f->v[i].nid]; | 
| 87 | + | ncoor[0][i] = tnrm[0]; | 
| 88 | + | ncoor[1][i] = tnrm[1]; | 
| 89 | + | ncoor[2][i] = tnrm[2]; | 
| 90 | + | }                                       /* print texture */ | 
| 91 | + | fprintf(fp, "\n%s texfunc %s\n4 dx dy dz %s\n0\n", | 
| 92 | + | sc->matname[f->mat], TEXNAME, TCALNAME); | 
| 93 | + | fput_baryc(&bcm, ncoor, 3, fp);         /* with BC normals */ | 
| 94 | + | fprintf(fp, "\n%s polygon %s.%d\n0\n0\n9\n", | 
| 95 | + | TEXNAME, sc->grpname[f->grp], ++fcnt); | 
| 96 | + | for (i = 0; i < 3; i++) {               /* then triangle */ | 
| 97 | + | double  *v = sc->vert[f->v[i].vid].p; | 
| 98 | + | fprintf(fp, "\t%18.12g %18.12g %18.12g\n", v[0], v[1], v[2]); | 
| 99 | + | } | 
| 100 | + | return(1); | 
| 101 | + | } | 
| 102 | + |  | 
| 103 |  | /* Callback to convert face to Radiance */ | 
| 104 |  | static int | 
| 105 |  | radface(Scene *sc, Face *f, void *ptr) | 
| 106 |  | { | 
| 20 | – | static int      fcnt = 0; | 
| 107 |  | FILE            *fp = (FILE *)ptr; | 
| 108 |  | int             i; | 
| 109 |  |  | 
| 24 | – | if (f->flags & FACE_DEGENERATE) | 
| 25 | – | return(0); | 
| 110 |  | fprintf(fp, "\n%s polygon %s.%d\n0\n0\n%d\n", sc->matname[f->mat], | 
| 111 |  | sc->grpname[f->grp], ++fcnt, 3*f->nv); | 
| 112 |  | for (i = 0; i < f->nv; i++) { | 
| 125 |  |  | 
| 126 |  | if (sc == NULL || sc->nfaces <= 0 || fp == NULL) | 
| 127 |  | return(0); | 
| 128 | + | /* not passing empties */ | 
| 129 | + | flexc |= FACE_DEGENERATE; | 
| 130 | + | /* reset counter if not stdout */ | 
| 131 | + | fcnt *= (fp == stdout); | 
| 132 |  | /* write comments */ | 
| 133 |  | for (n = 0; n < sc->ndescr; n++) | 
| 134 |  | fprintf(fp, "# %s\n", sc->descr[n]); | 
| 135 | < | /* write faces */ | 
| 136 | < | n = foreachFace(sc, radface, flreq, flexc, (void *)fp); | 
| 135 | > | /* flag faces to smooth */ | 
| 136 | > | n = foreachFace(sc, checksmooth, flreq, flexc, NULL); | 
| 137 | > | if (n > 0) {                            /* write smooth faces */ | 
| 138 | > | Scene   *smoothies = dupScene(sc, flreq|FACE_RESERVED, flexc); | 
| 139 | > | if (!smoothies) | 
| 140 | > | return(-1); | 
| 141 | > | n = triangulateScene(smoothies); | 
| 142 | > | if (n >= 0) | 
| 143 | > | n = foreachFace(smoothies, trismooth, 0, 0, fp); | 
| 144 | > | freeScene(smoothies); | 
| 145 | > | } | 
| 146 | > | if (n < 0) | 
| 147 | > | return(-1); | 
| 148 | > | /* write flat faces */ | 
| 149 | > | n += foreachFace(sc, radface, flreq, flexc|FACE_RESERVED, fp); | 
| 150 | > |  | 
| 151 |  | if (fflush(fp) < 0) { | 
| 152 | < | error(SYSTEM, "Error flushing Radiance scene data"); | 
| 152 | > | error(SYSTEM, "Error writing Radiance scene data"); | 
| 153 |  | return(-1); | 
| 154 |  | } | 
| 155 |  | return(n); | 
| 170 |  | if ((fp = popen(fspec+1, "w")) == NULL) { | 
| 171 |  | sprintf(errmsg, "%s: cannot execute", fspec); | 
| 172 |  | error(SYSTEM, errmsg); | 
| 173 | < | return(0); | 
| 173 | > | return(-1); | 
| 174 |  | } | 
| 175 |  | } else | 
| 176 |  | #endif | 
| 177 |  | if ((fp = fopen(fspec, "w")) == NULL) { | 
| 178 |  | sprintf(errmsg, "%s: cannot open for writing", fspec); | 
| 179 |  | error(SYSTEM, errmsg); | 
| 180 | < | return(0); | 
| 180 | > | return(-1); | 
| 181 |  | } | 
| 182 |  | /* start off header */ | 
| 183 |  | fprintf(fp, "# Radiance scene file converted from .OBJ by %s\n#\n", | 
| 184 |  | progname); | 
| 185 |  | n = toRadiance(sc, fp, flreq, flexc);   /* write file */ | 
| 186 |  | #if POPEN_SUPPORT | 
| 187 | < | if (fspec[0] == '!') | 
| 188 | < | pclose(fp); | 
| 189 | < | else | 
| 187 | > | if (fspec[0] == '!') { | 
| 188 | > | if (pclose(fp)) { | 
| 189 | > | sprintf(errmsg, "%s: error writing to command\n", fspec); | 
| 190 | > | error(SYSTEM, errmsg); | 
| 191 | > | return(-1); | 
| 192 | > | } | 
| 193 | > | } else | 
| 194 |  | #endif | 
| 195 | < | fclose(fp);                             /* close file */ | 
| 195 | > | fclose(fp);                             /* close it (already flushed) */ | 
| 196 |  | return(n); | 
| 197 |  | } |