| 1 | #ifndef lint | 
| 2 | static const char       RCSid[] = "$Id$"; | 
| 3 | #endif | 
| 4 | /* | 
| 5 | * Convert a trianglular mesh into a Radiance description. | 
| 6 | * | 
| 7 | * Unlike most other converters, we have defined a file | 
| 8 | * format for the input ourselves.  The format contains eight types, | 
| 9 | * each of which is identified by a single letter.  These are: | 
| 10 | * | 
| 11 | *      # comment               = a comment.  Continues until end of line. | 
| 12 | *      v id Px Py Pz           = a vertex.  The id must be an integer. | 
| 13 | *      n Nx Ny Nz              = a normal.  Corresponds to most recent vertex. | 
| 14 | *      i Iu Iv                 = an index.  Corresponds to most recent vertex. | 
| 15 | *      p picture               = a picture.  Used as a pattern for following. | 
| 16 | *      m material              = a material name.  Used for what follows. | 
| 17 | *      o object                = an object name.  Used for what follows. | 
| 18 | *      t id1 id2 id3           = a triangle. | 
| 19 | * | 
| 20 | * Only the 't' type results in any output.  The others merely set values | 
| 21 | * to be used in generating triangles.  If no picture or "p -" is given, | 
| 22 | * there will be no pattern associated with the geometry.  If no material | 
| 23 | * or "m -" is given, no material will be associated.  (Note that this | 
| 24 | * only makes sense for a mesh which is to be put into an octree for | 
| 25 | * instancing.)  Using a pattern requires that each vertex have an | 
| 26 | * associated index value for generating the colorpict primitive. | 
| 27 | * Likewise, an interpolated surface normal also requires that each | 
| 28 | * vertex of the triangle have an associated normal vector. | 
| 29 | * It is not necessary for the normal vectors to have unit length. | 
| 30 | */ | 
| 31 |  | 
| 32 | #include "standard.h" | 
| 33 |  | 
| 34 | #include "tmesh.h" | 
| 35 |  | 
| 36 | #define VOIDID          "void"          /* this is defined in object.h */ | 
| 37 |  | 
| 38 | #define PATNAME         "T-pat"         /* triangle pattern name (reused) */ | 
| 39 | #define TEXNAME         "T-nor"         /* triangle texture name (reused) */ | 
| 40 |  | 
| 41 | #define V_DEFINED       01              /* this vertex is defined */ | 
| 42 | #define V_HASNORM       02              /* vertex has surface normal */ | 
| 43 | #define V_HASINDX       04              /* vertex has index */ | 
| 44 |  | 
| 45 | typedef struct { | 
| 46 | short   flags;          /* vertex flags, from above */ | 
| 47 | FVECT   pos;            /* location */ | 
| 48 | FVECT   nor;            /* normal */ | 
| 49 | float   ndx[2];         /* picture index */ | 
| 50 | } VERTEX; | 
| 51 |  | 
| 52 | VERTEX  *vlist = NULL;          /* our vertex list */ | 
| 53 | int     nverts = 0;             /* number of vertices in our list */ | 
| 54 |  | 
| 55 | #define novert(i)       ((i)<0|(i)>=nverts || !(vlist[i].flags&V_DEFINED)) | 
| 56 |  | 
| 57 | #define CHUNKSIZ        128     /* vertex allocation chunk size */ | 
| 58 |  | 
| 59 | extern VERTEX   *vnew();        /* allocate a vertex (never freed) */ | 
| 60 |  | 
| 61 | char    *defmat = VOIDID;       /* default (starting) material name */ | 
| 62 | char    *defpat = "";           /* default (starting) picture name */ | 
| 63 | char    *defobj = "T";          /* default (starting) object name */ | 
| 64 |  | 
| 65 |  | 
| 66 | main(argc, argv)                /* read in T-mesh files and convert */ | 
| 67 | int     argc; | 
| 68 | char    *argv[]; | 
| 69 | { | 
| 70 | FILE    *fp; | 
| 71 | int     i; | 
| 72 |  | 
| 73 | for (i = 1; i < argc && argv[i][0] == '-'; i++) | 
| 74 | switch (argv[i][1]) { | 
| 75 | case 'o':               /* object name */ | 
| 76 | defobj = argv[++i]; | 
| 77 | break; | 
| 78 | case 'm':               /* default material */ | 
| 79 | defmat = argv[++i]; | 
| 80 | break; | 
| 81 | case 'p':               /* default picture */ | 
| 82 | defpat = argv[++i]; | 
| 83 | break; | 
| 84 | default: | 
| 85 | fprintf(stderr, | 
| 86 | "Usage: %s [-o obj][-m mat][-p pic] [file ..]\n", | 
| 87 | argv[0]); | 
| 88 | exit(1); | 
| 89 | } | 
| 90 | if (i >= argc) | 
| 91 | convert("<stdin>", stdin); | 
| 92 | else | 
| 93 | for ( ; i < argc; i++) { | 
| 94 | if ((fp = fopen(argv[i], "r")) == NULL) { | 
| 95 | perror(argv[i]); | 
| 96 | exit(1); | 
| 97 | } | 
| 98 | convert(argv[i], fp); | 
| 99 | fclose(fp); | 
| 100 | } | 
| 101 | exit(0); | 
| 102 | } | 
| 103 |  | 
| 104 |  | 
| 105 | convert(fname, fp)              /* convert a T-mesh */ | 
| 106 | char    *fname; | 
| 107 | FILE    *fp; | 
| 108 | { | 
| 109 | char    typ[4]; | 
| 110 | int     id[3]; | 
| 111 | double  vec[3]; | 
| 112 | char    picfile[128]; | 
| 113 | char    matname[64]; | 
| 114 | char    objname[64]; | 
| 115 | register int    i; | 
| 116 | register VERTEX *lastv; | 
| 117 | /* start fresh */ | 
| 118 | i = nverts; | 
| 119 | lastv = vlist; | 
| 120 | while (i--) | 
| 121 | (lastv++)->flags = 0; | 
| 122 | lastv = NULL; | 
| 123 | strcpy(picfile, defpat); | 
| 124 | strcpy(matname, defmat); | 
| 125 | strcpy(objname, defobj); | 
| 126 |  | 
| 127 | printf("\n## T-mesh read from: %s\n", fname); | 
| 128 | /* scan until EOF */ | 
| 129 | while (fscanf(fp, "%1s", typ) == 1) | 
| 130 | switch (typ[0]) { | 
| 131 | case 'v':               /* vertex */ | 
| 132 | if (fscanf(fp, "%d %lf %lf %lf", &id[0], | 
| 133 | &vec[0], &vec[1], &vec[2]) != 4) | 
| 134 | syntax(fname, fp, "Bad vertex"); | 
| 135 | lastv = vnew(id[0], vec[0], vec[1], vec[2]); | 
| 136 | break; | 
| 137 | case 't':               /* triangle */ | 
| 138 | if (fscanf(fp, "%d %d %d", &id[0], &id[1], &id[2]) != 3) | 
| 139 | syntax(fname, fp, "Bad triangle"); | 
| 140 | if (novert(id[0]) | novert(id[1]) | novert(id[2])) | 
| 141 | syntax(fname, fp, "Undefined triangle vertex"); | 
| 142 | triangle(picfile, matname, objname, &vlist[id[0]], | 
| 143 | &vlist[id[1]], &vlist[id[2]]); | 
| 144 | break; | 
| 145 | case 'n':               /* surface normal */ | 
| 146 | if (lastv == NULL) | 
| 147 | syntax(fname, fp, "No vertex for normal"); | 
| 148 | if (fscanf(fp, "%lf %lf %lf", | 
| 149 | &vec[0], &vec[1], &vec[2]) != 3) | 
| 150 | syntax(fname, fp, "Bad vertex normal"); | 
| 151 | lastv->nor[0] = vec[0]; | 
| 152 | lastv->nor[1] = vec[1]; | 
| 153 | lastv->nor[2] = vec[2]; | 
| 154 | if (normalize(lastv->nor) == 0.0) | 
| 155 | syntax(fname, fp, "Zero vertex normal"); | 
| 156 | lastv->flags |= V_HASNORM; | 
| 157 | break; | 
| 158 | case 'i':               /* index position */ | 
| 159 | if (lastv == NULL) | 
| 160 | syntax(fname, fp, "No vertex for index"); | 
| 161 | if (fscanf(fp, "%lf %lf", &vec[0], &vec[1]) != 2) | 
| 162 | syntax(fname, fp, "Bad index"); | 
| 163 | lastv->ndx[0] = vec[0]; | 
| 164 | lastv->ndx[1] = vec[1]; | 
| 165 | lastv->flags |= V_HASINDX; | 
| 166 | break; | 
| 167 | case 'o':               /* object name */ | 
| 168 | if (fscanf(fp, "%s", objname) != 1) | 
| 169 | syntax(fname, fp, "Bad object name"); | 
| 170 | break; | 
| 171 | case 'm':               /* material */ | 
| 172 | if (fscanf(fp, "%s", matname) != 1) | 
| 173 | syntax(fname, fp, "Bad material"); | 
| 174 | if (matname[0] == '-' && !matname[1]) | 
| 175 | strcpy(matname, VOIDID); | 
| 176 | break; | 
| 177 | case 'p':               /* picture */ | 
| 178 | if (fscanf(fp, "%s", picfile) != 1) | 
| 179 | syntax(fname, fp, "Bad pattern"); | 
| 180 | if (picfile[0] == '-' && !picfile[1]) | 
| 181 | picfile[0] = '\0'; | 
| 182 | break; | 
| 183 | case '#':               /* comment */ | 
| 184 | fputs("\n#", stdout); | 
| 185 | while ((i = getc(fp)) != EOF) { | 
| 186 | putchar(i); | 
| 187 | if (i == '\n') | 
| 188 | break; | 
| 189 | } | 
| 190 | break; | 
| 191 | default: | 
| 192 | syntax(fname, fp, "Unknown type"); | 
| 193 | break; | 
| 194 | } | 
| 195 | } | 
| 196 |  | 
| 197 |  | 
| 198 | triangle(pn, mod, obj, v1, v2, v3)      /* put out a triangle */ | 
| 199 | char    *pn, *mod, *obj; | 
| 200 | register VERTEX *v1, *v2, *v3; | 
| 201 | { | 
| 202 | static int      ntri = 0; | 
| 203 | BARYCCM bvecs; | 
| 204 | FLOAT   bvm[3][3]; | 
| 205 | register int    i; | 
| 206 | /* compute barycentric coordinates */ | 
| 207 | if (v1->flags & v2->flags & v3->flags & (V_HASINDX|V_HASNORM)) | 
| 208 | if (comp_baryc(&bvecs, v1->pos, v2->pos, v3->pos) < 0) | 
| 209 | return; | 
| 210 | /* put out texture (if any) */ | 
| 211 | if (v1->flags & v2->flags & v3->flags & V_HASNORM && | 
| 212 | !flat_tri(v1->pos, v2->pos, v3->pos, | 
| 213 | v1->nor, v2->nor, v3->nor)) { | 
| 214 | printf("\n%s texfunc %s\n", mod, TEXNAME); | 
| 215 | mod = TEXNAME; | 
| 216 | printf("4 dx dy dz %s\n", TCALNAME); | 
| 217 | printf("0\n"); | 
| 218 | for (i = 0; i < 3; i++) { | 
| 219 | bvm[i][0] = v1->nor[i]; | 
| 220 | bvm[i][1] = v2->nor[i]; | 
| 221 | bvm[i][2] = v3->nor[i]; | 
| 222 | } | 
| 223 | put_baryc(&bvecs, bvm, 3); | 
| 224 | } | 
| 225 | /* put out pattern (if any) */ | 
| 226 | if (*pn && (v1->flags & v2->flags & v3->flags & V_HASINDX)) { | 
| 227 | printf("\n%s colorpict %s\n", mod, PATNAME); | 
| 228 | mod = PATNAME; | 
| 229 | printf("7 noneg noneg noneg %s %s u v\n", pn, TCALNAME); | 
| 230 | printf("0\n"); | 
| 231 | for (i = 0; i < 2; i++) { | 
| 232 | bvm[i][0] = v1->ndx[i]; | 
| 233 | bvm[i][1] = v2->ndx[i]; | 
| 234 | bvm[i][2] = v3->ndx[i]; | 
| 235 | } | 
| 236 | put_baryc(&bvecs, bvm, 2); | 
| 237 | } | 
| 238 | /* put out triangle */ | 
| 239 | printf("\n%s polygon %s.%d\n", mod, obj, ++ntri); | 
| 240 | printf("0\n0\n9\n"); | 
| 241 | printf("%18.12g %18.12g %18.12g\n", v1->pos[0],v1->pos[1],v1->pos[2]); | 
| 242 | printf("%18.12g %18.12g %18.12g\n", v2->pos[0],v2->pos[1],v2->pos[2]); | 
| 243 | printf("%18.12g %18.12g %18.12g\n", v3->pos[0],v3->pos[1],v3->pos[2]); | 
| 244 | } | 
| 245 |  | 
| 246 |  | 
| 247 | VERTEX * | 
| 248 | vnew(id, x, y, z)                       /* create a new vertex */ | 
| 249 | register int    id; | 
| 250 | double  x, y, z; | 
| 251 | { | 
| 252 | register int    i; | 
| 253 |  | 
| 254 | if (id >= nverts) {             /* get some more */ | 
| 255 | i = nverts; | 
| 256 | nverts = CHUNKSIZ*((id/CHUNKSIZ)+1); | 
| 257 | if (vlist == NULL) | 
| 258 | vlist = (VERTEX *)malloc(nverts*sizeof(VERTEX)); | 
| 259 | else | 
| 260 | vlist = (VERTEX *)realloc((char *)vlist, | 
| 261 | nverts*sizeof(VERTEX)); | 
| 262 | if (vlist == NULL) { | 
| 263 | fprintf(stderr, | 
| 264 | "Out of memory while allocating vertex %d\n", id); | 
| 265 | exit(1); | 
| 266 | } | 
| 267 | while (i < nverts)              /* clear what's new */ | 
| 268 | vlist[i++].flags = 0; | 
| 269 | } | 
| 270 | /* assign new vertex */ | 
| 271 | vlist[id].pos[0] = x; | 
| 272 | vlist[id].pos[1] = y; | 
| 273 | vlist[id].pos[2] = z; | 
| 274 | vlist[id].flags = V_DEFINED; | 
| 275 | /* return it */ | 
| 276 | return(&vlist[id]); | 
| 277 | } | 
| 278 |  | 
| 279 |  | 
| 280 | syntax(fn, fp, er)                      /* report syntax error and exit */ | 
| 281 | char    *fn; | 
| 282 | register FILE   *fp; | 
| 283 | char    *er; | 
| 284 | { | 
| 285 | extern long     ftell(); | 
| 286 | register long   cpos; | 
| 287 | register int    c; | 
| 288 | int     lineno; | 
| 289 |  | 
| 290 | if (fp == stdin) | 
| 291 | fprintf(stderr, "%s: T-mesh format error: %s\n", fn, er); | 
| 292 | else { | 
| 293 | cpos = ftell(fp); | 
| 294 | fseek(fp, 0L, 0); | 
| 295 | lineno = 1; | 
| 296 | while (cpos-- > 0) { | 
| 297 | if ((c = getc(fp)) == EOF) | 
| 298 | break; | 
| 299 | if (c == '\n') | 
| 300 | lineno++; | 
| 301 | } | 
| 302 | fprintf(stderr, "%s: T-mesh format error at line %d: %s\n", | 
| 303 | fn, lineno, er); | 
| 304 | } | 
| 305 | exit(1); | 
| 306 | } |