| 1 | /* Copyright (c) 1990 Regents of the University of California */ | 
| 2 |  | 
| 3 | #ifndef lint | 
| 4 | static char SCCSid[] = "$SunId$ LBL"; | 
| 5 | #endif | 
| 6 |  | 
| 7 | /* | 
| 8 | * Convert Neutral File Format input to Radiance scene description. | 
| 9 | * | 
| 10 | *      12/9/90         Greg Ward | 
| 11 | */ | 
| 12 |  | 
| 13 | /****************************************************************** | 
| 14 |  | 
| 15 | Since Eric Haines wrote such excellent documentation of his | 
| 16 | Neutral File Format, I am just going to reprint it here with | 
| 17 | my added comments in braces {}. | 
| 18 |  | 
| 19 | Neutral File Format (NFF), by Eric Haines | 
| 20 |  | 
| 21 | Draft document #1, 10/3/88 | 
| 22 |  | 
| 23 | The NFF (Neutral File Format) is designed as a minimal scene description | 
| 24 | language.  The language was designed in order to test various rendering | 
| 25 | algorithms and efficiency schemes.  It is meant to describe the geometry and | 
| 26 | basic surface characteristics of objects, the placement of lights, and the | 
| 27 | viewing frustum for the eye.  Some additional information is provided for | 
| 28 | esthetic reasons (such as the color of the objects, which is not strictly | 
| 29 | necessary for testing rendering algorithms). | 
| 30 |  | 
| 31 | Future enhancements include:  circle and torus objects, spline surfaces | 
| 32 | with trimming curves, directional lights, characteristics for positional | 
| 33 | lights, CSG descriptions, and probably more by the time you read this. | 
| 34 | Comments, suggestions, and criticisms are all welcome. | 
| 35 |  | 
| 36 | At present the NFF file format is used in conjunction with the SPD (Standard | 
| 37 | Procedural Database) software, a package designed to create a variety of | 
| 38 | databases for testing rendering schemes.  The SPD package is available | 
| 39 | from Netlib and via ftp from drizzle.cs.uoregon.edu.  For more information | 
| 40 | about SPD see "A Proposal for Standard Graphics Environments," IEEE Computer | 
| 41 | Graphics and Applications, vol. 7, no. 11, November 1987, pp. 3-5. | 
| 42 |  | 
| 43 | By providing a minimal interface, NFF is meant to act as a simple format to | 
| 44 | allow the programmer to quickly write filters to move from NFF to the | 
| 45 | local file format.  Presently the following entities are supported: | 
| 46 | A simple perspective frustum | 
| 47 | A positional (vs. directional) light source description | 
| 48 | A background color description | 
| 49 | A surface properties description | 
| 50 | Polygon, polygonal patch, cylinder/cone, and sphere descriptions | 
| 51 |  | 
| 52 | Files are output as lines of text.  For each entity, the first line | 
| 53 | defines its type.  The rest of the first line and possibly other lines | 
| 54 | contain further information about the entity.  Entities include: | 
| 55 |  | 
| 56 | "v"  - viewing vectors and angles       { optionally creates view file } | 
| 57 | "l"  - positional light location        { it's there, but bad to use } | 
| 58 | "b"  - background color                 { ditto } | 
| 59 | "f"  - object material properties       { this is flakey } | 
| 60 | "c"  - cone or cylinder primitive | 
| 61 | "s"  - sphere primitive | 
| 62 | "p"  - polygon primitive | 
| 63 | "pp" - polygonal patch primitive        { interpreted same as p for now } | 
| 64 |  | 
| 65 | These are explained in depth below:     { see conversion routines } | 
| 66 |  | 
| 67 | ***********************************************************************/ | 
| 68 |  | 
| 69 | #include <stdio.h> | 
| 70 |  | 
| 71 | char    *viewfile = NULL;       /* view parameters file */ | 
| 72 |  | 
| 73 | char    *progname; | 
| 74 |  | 
| 75 |  | 
| 76 | main(argc, argv)                /* convert NFF file to Radiance */ | 
| 77 | int     argc; | 
| 78 | char    *argv[]; | 
| 79 | { | 
| 80 | int     i; | 
| 81 |  | 
| 82 | progname = argv[0]; | 
| 83 | for (i = 1; i < argc; i++) | 
| 84 | if (argc-i > 1 && !strcmp(argv[i], "-vf")) | 
| 85 | viewfile = argv[++i]; | 
| 86 | else | 
| 87 | break; | 
| 88 | if (i-argc > 1) | 
| 89 | goto userr; | 
| 90 | if (i-argc == 1 && freopen(argv[i], "r", stdin) == NULL) { | 
| 91 | perror(argv[i]); | 
| 92 | exit(1); | 
| 93 | } | 
| 94 | init(); | 
| 95 | nff2rad(); | 
| 96 | exit(0); | 
| 97 | userr: | 
| 98 | fprintf(stderr, "Usage: %s [-vf viewfile] [input]\n", progname); | 
| 99 | exit(1); | 
| 100 | } | 
| 101 |  | 
| 102 |  | 
| 103 | init()                  /* spit out initial definitions */ | 
| 104 | { | 
| 105 | printf("# File created by %s\n", progname); | 
| 106 | printf("\nvoid light light\n"); | 
| 107 | printf("0\n0\n3 1 1 1\n"); | 
| 108 | printf("\nvoid plastic fill\n"); | 
| 109 | printf("0\n0\n5 .5 .5 .5 0 0\n"); | 
| 110 | } | 
| 111 |  | 
| 112 |  | 
| 113 | nff2rad()               /* convert NFF on stdin to Radiance on stdout */ | 
| 114 | { | 
| 115 | register int    c; | 
| 116 |  | 
| 117 | while ((c = getchar()) != EOF) | 
| 118 | switch (c) { | 
| 119 | case ' ':                       /* white space */ | 
| 120 | case '\t': | 
| 121 | case '\n': | 
| 122 | case '\f': | 
| 123 | case '\r': | 
| 124 | continue; | 
| 125 | case '#':                       /* comment */ | 
| 126 | comment(); | 
| 127 | break; | 
| 128 | case 'v':                       /* view point */ | 
| 129 | view(); | 
| 130 | break; | 
| 131 | case 'l':                       /* light source */ | 
| 132 | light(); | 
| 133 | break; | 
| 134 | case 'b':                       /* background color */ | 
| 135 | background(); | 
| 136 | break; | 
| 137 | case 'f':                       /* fill material */ | 
| 138 | fill(); | 
| 139 | break; | 
| 140 | case 'c':                       /* cylinder or cone */ | 
| 141 | cone(); | 
| 142 | break; | 
| 143 | case 's':                       /* sphere */ | 
| 144 | sphere(); | 
| 145 | break; | 
| 146 | case 'p':                       /* polygon or patch */ | 
| 147 | poly(); | 
| 148 | break; | 
| 149 | default:                        /* unknown */ | 
| 150 | fprintf(stderr, "%c: unknown NFF primitive\n", c); | 
| 151 | exit(1); | 
| 152 | } | 
| 153 | } | 
| 154 |  | 
| 155 |  | 
| 156 | /******************************************* | 
| 157 |  | 
| 158 | Comment.  Description: | 
| 159 | "#" [ string ] | 
| 160 |  | 
| 161 | Format: | 
| 162 | # [ string ] | 
| 163 |  | 
| 164 | As soon as a "#" character is detected, the rest of the line is considered | 
| 165 | a comment. | 
| 166 |  | 
| 167 | ******************/ | 
| 168 |  | 
| 169 | comment() | 
| 170 | { | 
| 171 | register int    c; | 
| 172 |  | 
| 173 | putchar('#'); | 
| 174 | while ((c = getchar()) != EOF) { | 
| 175 | putchar(c); | 
| 176 | if (c == '\n') | 
| 177 | break; | 
| 178 | } | 
| 179 | } | 
| 180 |  | 
| 181 |  | 
| 182 | /*************************************************** | 
| 183 |  | 
| 184 | Viewpoint location.  Description: | 
| 185 | "v" | 
| 186 | "from" Fx Fy Fz | 
| 187 | "at" Ax Ay Az | 
| 188 | "up" Ux Uy Uz | 
| 189 | "angle" angle | 
| 190 | "hither" hither | 
| 191 | "resolution" xres yres | 
| 192 |  | 
| 193 | Format: | 
| 194 |  | 
| 195 | v | 
| 196 | from %g %g %g | 
| 197 | at %g %g %g | 
| 198 | up %g %g %g | 
| 199 | angle %g | 
| 200 | hither %g | 
| 201 | resolution %d %d | 
| 202 |  | 
| 203 | The parameters are: | 
| 204 |  | 
| 205 | From:  the eye location in XYZ. | 
| 206 | At:    a position to be at the center of the image, in XYZ world | 
| 207 | coordinates.  A.k.a. "lookat". | 
| 208 | Up:    a vector defining which direction is up, as an XYZ vector. | 
| 209 | Angle: in degrees, defined as from the center of top pixel row to | 
| 210 | bottom pixel row and left column to right column. | 
| 211 | Resolution: in pixels, in x and in y. | 
| 212 |  | 
| 213 | Note that no assumptions are made about normalizing the data (e.g. the | 
| 214 | from-at distance does not have to be 1).  Also, vectors are not | 
| 215 | required to be perpendicular to each other. | 
| 216 |  | 
| 217 | For all databases some viewing parameters are always the same: | 
| 218 | Yon is "at infinity." | 
| 219 | Aspect ratio is 1.0. | 
| 220 |  | 
| 221 | A view entity must be defined before any objects are defined (this | 
| 222 | requirement is so that NFF files can be used by hidden surface machines). | 
| 223 |  | 
| 224 | ***************/ | 
| 225 |  | 
| 226 | view() | 
| 227 | { | 
| 228 | static FILE     *fp = NULL; | 
| 229 | float   from[3], at[3], up[3], angle; | 
| 230 |  | 
| 231 | if (scanf(" from %f %f %f", &from[0], &from[1], &from[2]) != 3) | 
| 232 | goto fmterr; | 
| 233 | if (scanf(" at %f %f %f", &at[0], &at[1], &at[2]) != 3) | 
| 234 | goto fmterr; | 
| 235 | if (scanf(" up %f %f %f", &up[0], &up[1], &up[2]) != 3) | 
| 236 | goto fmterr; | 
| 237 | if (scanf(" angle %f", &angle) != 1) | 
| 238 | goto fmterr; | 
| 239 | scanf(" hither %*f"); | 
| 240 | scanf(" resolution %*d %*d"); | 
| 241 | if (viewfile != NULL) { | 
| 242 | if (fp == NULL && (fp = fopen(viewfile, "a")) == NULL) { | 
| 243 | perror(viewfile); | 
| 244 | exit(1); | 
| 245 | } | 
| 246 | fprintf(fp, | 
| 247 | "VIEW= -vp %g %g %g -vd %g %g %g -vu %g %g %g -vh %g -vv %g\n", | 
| 248 | from[0], from[1], from[2], | 
| 249 | at[0]-from[0], at[1]-from[1], at[2]-from[2], | 
| 250 | up[0], up[1], up[2], | 
| 251 | angle, angle); | 
| 252 | } | 
| 253 | return; | 
| 254 | fmterr: | 
| 255 | fprintf(stderr, "%s: view syntax error\n", progname); | 
| 256 | exit(1); | 
| 257 | } | 
| 258 |  | 
| 259 |  | 
| 260 | /******************************** | 
| 261 |  | 
| 262 | Positional light.  A light is defined by XYZ position.  Description: | 
| 263 | "l" X Y Z | 
| 264 |  | 
| 265 | Format: | 
| 266 | l %g %g %g | 
| 267 |  | 
| 268 | All light entities must be defined before any objects are defined (this | 
| 269 | requirement is so that NFF files can be used by hidden surface machines). | 
| 270 | Lights have a non-zero intensity of no particular value [this definition | 
| 271 | may change soon, with the addition of an intensity and/or color]. | 
| 272 |  | 
| 273 | **************************/ | 
| 274 |  | 
| 275 | light() | 
| 276 | { | 
| 277 | static int      nlights = 0; | 
| 278 | register int    c; | 
| 279 | float   x, y, z; | 
| 280 |  | 
| 281 | if (scanf("%f %f %f", &x, &y, &z) != 3) { | 
| 282 | fprintf(stderr, "%s: light source syntax error\n", progname); | 
| 283 | exit(1); | 
| 284 | } | 
| 285 | while ((c = getchar()) != EOF && c != '\n') | 
| 286 | ; | 
| 287 | printf("\nlight sphere l%d ", ++nlights); | 
| 288 | printf("0\n0\n4 %g %g %g 1\n", x, y, z); | 
| 289 | } | 
| 290 |  | 
| 291 |  | 
| 292 | /************************************************** | 
| 293 |  | 
| 294 | Background color.  A color is simply RGB with values between 0 and 1: | 
| 295 | "b" R G B | 
| 296 |  | 
| 297 | Format: | 
| 298 | b %g %g %g | 
| 299 |  | 
| 300 | If no background color is set, assume RGB = {0,0,0}. | 
| 301 |  | 
| 302 | ********************/ | 
| 303 |  | 
| 304 | background() | 
| 305 | { | 
| 306 | float   r, g, b; | 
| 307 |  | 
| 308 | if (scanf("%f %f %f", &r, &g, &b) != 3) { | 
| 309 | fprintf(stderr, "%s: background syntax error\n", progname); | 
| 310 | exit(1); | 
| 311 | } | 
| 312 | printf("\nvoid glow backg_color\n"); | 
| 313 | printf("0\n0\n4 %g %g %g 0\n", r, g, b); | 
| 314 | printf("\nbackg_color source background\n"); | 
| 315 | printf("0\n0\n4 0 0 1 360\n"); | 
| 316 | } | 
| 317 |  | 
| 318 |  | 
| 319 | /**************************************************** | 
| 320 |  | 
| 321 | Fill color and shading parameters.  Description: | 
| 322 | "f" red green blue Kd Ks Shine T index_of_refraction | 
| 323 |  | 
| 324 | Format: | 
| 325 | f %g %g %g %g %g %g %g %g | 
| 326 |  | 
| 327 | RGB is in terms of 0.0 to 1.0. | 
| 328 |  | 
| 329 | Kd is the diffuse component, Ks the specular, Shine is the Phong cosine | 
| 330 | power for highlights, T is transmittance (fraction of light passed per | 
| 331 | unit).  Usually, 0 <= Kd <= 1 and 0 <= Ks <= 1, though it is not required | 
| 332 | that Kd + Ks == 1.  Note that transmitting objects ( T > 0 ) are considered | 
| 333 | to have two sides for algorithms that need these (normally objects have | 
| 334 | one side). | 
| 335 |  | 
| 336 | The fill color is used to color the objects following it until a new color | 
| 337 | is assigned. | 
| 338 |  | 
| 339 | *********************/ | 
| 340 |  | 
| 341 | fill() | 
| 342 | { | 
| 343 | float   r, g, b, d, s, p, t, n; | 
| 344 |  | 
| 345 | if (scanf("%f %f %f %f %f %f %f %f", &r, &g, &b, | 
| 346 | &d, &s, &p, &t, &n) != 8) { | 
| 347 | fprintf(stderr, "%s: fill material syntax error\n", progname); | 
| 348 | exit(1); | 
| 349 | } | 
| 350 | d /= 1.-s-t; | 
| 351 | r *= d; | 
| 352 | g *= d; | 
| 353 | b *= d; | 
| 354 | if (p > 1.) | 
| 355 | p = 1./p; | 
| 356 | if (t > .001) {         /* has transmission */ | 
| 357 | printf("\nvoid trans fill\n"); | 
| 358 | printf("0\n0\n7 %g %g %g %g 0 %g 1\n", r, g, b, s, t); | 
| 359 | } else {                /* no transmission */ | 
| 360 | printf("\nvoid plastic fill\n"); | 
| 361 | printf("0\n0\n5 %g %g %g %g %g\n", r, g, b, s, p); | 
| 362 | } | 
| 363 | } | 
| 364 |  | 
| 365 |  | 
| 366 | /***************************************************** | 
| 367 |  | 
| 368 | Cylinder or cone.  A cylinder is defined as having a radius and an axis | 
| 369 | defined by two points, which also define the top and bottom edge of the | 
| 370 | cylinder.  A cone is defined similarly, the difference being that the apex | 
| 371 | and base radii are different.  The apex radius is defined as being smaller | 
| 372 | than the base radius.  Note that the surface exists without endcaps.  The | 
| 373 | cone or cylinder description: | 
| 374 |  | 
| 375 | "c" | 
| 376 | base.x base.y base.z base_radius | 
| 377 | apex.x apex.y apex.z apex_radius | 
| 378 |  | 
| 379 | Format: | 
| 380 | c | 
| 381 | %g %g %g %g | 
| 382 | %g %g %g %g | 
| 383 |  | 
| 384 | A negative value for both radii means that only the inside of the object is | 
| 385 | visible (objects are normally considered one sided, with the outside | 
| 386 | visible).  Note that the base and apex cannot be coincident for a cylinder | 
| 387 | or cone. | 
| 388 |  | 
| 389 | ************************/ | 
| 390 |  | 
| 391 | cone() | 
| 392 | { | 
| 393 | static int      ncs = 0; | 
| 394 | int     invert; | 
| 395 | float   x0, y0, z0, x1, y1, z1, r0, r1; | 
| 396 |  | 
| 397 | if (scanf("%f %f %f %f %f %f %f %f", &x0, &y0, &z0, &r0, | 
| 398 | &x1, &y1, &z1, &r1) != 8) { | 
| 399 | fprintf(stderr, "%s: cylinder or cone syntax error\n", | 
| 400 | progname); | 
| 401 | exit(1); | 
| 402 | } | 
| 403 | if (invert = r0 < 0.) { | 
| 404 | r0 = -r0; | 
| 405 | r1 = -r1; | 
| 406 | } | 
| 407 | if (r0-r1 < .001 && r1-r0 < .001) {     /* cylinder */ | 
| 408 | printf("\nfill %s c%d ", invert?"tube":"cylinder", ++ncs); | 
| 409 | printf("0\n0\n7\n"); | 
| 410 | printf("\t%g\t%g\t%g\n", x0, y0, z0); | 
| 411 | printf("\t%g\t%g\t%g\n", x1, y1, z1); | 
| 412 | printf("\t%g\n", r0); | 
| 413 | } else {                                /* cone */ | 
| 414 | printf("\nfill %s c%d ", invert?"cup":"cone", ++ncs); | 
| 415 | printf("0\n0\n8\n"); | 
| 416 | printf("\t%g\t%g\t%g\n", x0, y0, z0); | 
| 417 | printf("\t%g\t%g\t%g\n", x1, y1, z1); | 
| 418 | printf("\t%g\t%g\n", r0, r1); | 
| 419 | } | 
| 420 | } | 
| 421 |  | 
| 422 |  | 
| 423 | /***************************************** | 
| 424 |  | 
| 425 | Sphere.  A sphere is defined by a radius and center position: | 
| 426 | "s" center.x center.y center.z radius | 
| 427 |  | 
| 428 | Format: | 
| 429 | s %g %g %g %g | 
| 430 |  | 
| 431 | If the radius is negative, then only the sphere's inside is visible | 
| 432 | (objects are normally considered one sided, with the outside visible). | 
| 433 |  | 
| 434 | ******************/ | 
| 435 |  | 
| 436 | sphere() | 
| 437 | { | 
| 438 | static int      nspheres = 0; | 
| 439 | float   x, y, z, r; | 
| 440 |  | 
| 441 | if (scanf("%f %f %f %f", &x, &y, &z, &r) != 4) { | 
| 442 | fprintf(stderr, "%s: sphere syntax error\n", progname); | 
| 443 | exit(1); | 
| 444 | } | 
| 445 | if (r < 0.) { | 
| 446 | printf("\nfill bubble s%d ", ++nspheres); | 
| 447 | printf("0\n0\n4 %g %g %g %g\n", x, y, z, -r); | 
| 448 | } else { | 
| 449 | printf("\nfill sphere s%d ", ++nspheres); | 
| 450 | printf("0\n0\n4 %g %g %g %g\n", x, y, z, r); | 
| 451 | } | 
| 452 | } | 
| 453 |  | 
| 454 |  | 
| 455 | /********************************************* | 
| 456 |  | 
| 457 | Polygon.  A polygon is defined by a set of vertices.  With these databases, | 
| 458 | a polygon is defined to have all points coplanar.  A polygon has only | 
| 459 | one side, with the order of the vertices being counterclockwise as you | 
| 460 | face the polygon (right-handed coordinate system).  The first two edges | 
| 461 | must form a non-zero convex angle, so that the normal and side visibility | 
| 462 | can be determined.  Description: | 
| 463 |  | 
| 464 | "p" total_vertices | 
| 465 | vert1.x vert1.y vert1.z | 
| 466 | [etc. for total_vertices vertices] | 
| 467 |  | 
| 468 | Format: | 
| 469 | p %d | 
| 470 | [ %g %g %g ] <-- for total_vertices vertices | 
| 471 |  | 
| 472 | -------- | 
| 473 |  | 
| 474 | Polygonal patch.  A patch is defined by a set of vertices and their normals. | 
| 475 | With these databases, a patch is defined to have all points coplanar. | 
| 476 | A patch has only one side, with the order of the vertices being | 
| 477 | counterclockwise as you face the patch (right-handed coordinate system). | 
| 478 | The first two edges must form a non-zero convex angle, so that the normal | 
| 479 | and side visibility can be determined.  Description: | 
| 480 |  | 
| 481 | "pp" total_vertices | 
| 482 | vert1.x vert1.y vert1.z norm1.x norm1.y norm1.z | 
| 483 | [etc. for total_vertices vertices] | 
| 484 |  | 
| 485 | Format: | 
| 486 | pp %d | 
| 487 | [ %g %g %g %g %g %g ] <-- for total_vertices vertices | 
| 488 |  | 
| 489 | *******************/ | 
| 490 |  | 
| 491 | poly() | 
| 492 | { | 
| 493 | static int      npolys = 0; | 
| 494 | int     ispatch; | 
| 495 | int     nverts; | 
| 496 | float   x, y, z; | 
| 497 |  | 
| 498 | ispatch = getchar(); | 
| 499 | if (ispatch != 'p') { | 
| 500 | ungetc(ispatch, stdin); | 
| 501 | ispatch = 0; | 
| 502 | } | 
| 503 | if (scanf("%d", &nverts) != 1) | 
| 504 | goto fmterr; | 
| 505 | printf("\nfill polygon p%d ", ++npolys); | 
| 506 | printf("0\n0\n%d\n", 3*nverts); | 
| 507 | while (nverts-- > 0) { | 
| 508 | if (scanf("%f %f %f", &x, &y, &z) != 3) | 
| 509 | goto fmterr; | 
| 510 | if (ispatch) | 
| 511 | scanf("%*f %*f %*f"); | 
| 512 | printf("\t%g\t%g\t%g\n", x, y, z); | 
| 513 | } | 
| 514 | return; | 
| 515 | fmterr: | 
| 516 | fprintf(stderr, "%s: polygon or patch syntax error\n", progname); | 
| 517 | exit(1); | 
| 518 | } |